1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge tag 'mariadb-5.5.45' into 5.5-galera

This commit is contained in:
Nirbhay Choubey
2015-08-07 17:02:51 -04:00
95 changed files with 3002 additions and 378 deletions

View File

@@ -1,4 +1,4 @@
MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MAJOR=5
MYSQL_VERSION_MINOR=5 MYSQL_VERSION_MINOR=5
MYSQL_VERSION_PATCH=44 MYSQL_VERSION_PATCH=45
MYSQL_VERSION_EXTRA= MYSQL_VERSION_EXTRA=

View File

@@ -1066,7 +1066,7 @@ int main(int argc, char **argv)
printf("This installation of MySQL is already upgraded to %s, " printf("This installation of MySQL is already upgraded to %s, "
"use --force if you still need to run mysql_upgrade\n", "use --force if you still need to run mysql_upgrade\n",
MYSQL_SERVER_VERSION); MYSQL_SERVER_VERSION);
die(NULL); goto end;
} }
if (opt_version_check && check_version_match()) if (opt_version_check && check_version_match())
@@ -1089,6 +1089,7 @@ int main(int argc, char **argv)
/* Create a file indicating upgrade has been performed */ /* Create a file indicating upgrade has been performed */
create_mysql_upgrade_info_file(); create_mysql_upgrade_info_file();
end:
free_used_memory(); free_used_memory();
my_end(my_end_arg); my_end(my_end_arg);
exit(0); exit(0);

View File

@@ -66,6 +66,7 @@ ulong server_id = 0;
ulong bytes_sent = 0L, bytes_received = 0L; ulong bytes_sent = 0L, bytes_received = 0L;
ulong mysqld_net_retry_count = 10L; ulong mysqld_net_retry_count = 10L;
ulong open_files_limit; ulong open_files_limit;
ulong opt_binlog_rows_event_max_size;
uint test_flags = 0; uint test_flags = 0;
static uint opt_protocol= 0; static uint opt_protocol= 0;
static FILE *result_file; static FILE *result_file;
@@ -1432,6 +1433,12 @@ that may lead to an endless loop.",
"Used to reserve file descriptors for use by this program.", "Used to reserve file descriptors for use by this program.",
&open_files_limit, &open_files_limit, 0, GET_ULONG, &open_files_limit, &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
{"binlog-row-event-max-size", 0,
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"This value must be a multiple of 256.",
&opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, 0,
GET_ULONG, REQUIRED_ARG, UINT_MAX, 256, ULONG_MAX, 0, 256, 0},
{"verify-binlog-checksum", 'c', "Verify checksum binlog events.", {"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
(uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},

View File

@@ -1,5 +1,6 @@
/* /*
Copyright (c) 2005, 2012, Oracle and/or its affiliates. Copyright (c) 2005, 2015, Oracle and/or its affiliates.
Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -244,7 +245,7 @@ void print_conclusions_csv(conclusions *con);
void generate_stats(conclusions *con, option_string *eng, stats *sptr); void generate_stats(conclusions *con, option_string *eng, stats *sptr);
uint parse_comma(const char *string, uint **range); uint parse_comma(const char *string, uint **range);
uint parse_delimiter(const char *script, statement **stmt, char delm); uint parse_delimiter(const char *script, statement **stmt, char delm);
uint parse_option(const char *origin, option_string **stmt, char delm); int parse_option(const char *origin, option_string **stmt, char delm);
static int drop_schema(MYSQL *mysql, const char *db); static int drop_schema(MYSQL *mysql, const char *db);
uint get_random_string(char *buf); uint get_random_string(char *buf);
static statement *build_table_string(void); static statement *build_table_string(void);
@@ -1259,7 +1260,13 @@ get_options(int *argc,char ***argv)
if (num_int_cols_opt) if (num_int_cols_opt)
{ {
option_string *str; option_string *str;
parse_option(num_int_cols_opt, &str, ','); if(parse_option(num_int_cols_opt, &str, ',') == -1)
{
fprintf(stderr, "Invalid value specified for the option "
"'number-int-cols'\n");
option_cleanup(str);
return 1;
}
num_int_cols= atoi(str->string); num_int_cols= atoi(str->string);
if (str->option) if (str->option)
num_int_cols_index= atoi(str->option); num_int_cols_index= atoi(str->option);
@@ -1270,7 +1277,13 @@ get_options(int *argc,char ***argv)
if (num_char_cols_opt) if (num_char_cols_opt)
{ {
option_string *str; option_string *str;
parse_option(num_char_cols_opt, &str, ','); if(parse_option(num_char_cols_opt, &str, ',') == -1)
{
fprintf(stderr, "Invalid value specified for the option "
"'number-char-cols'\n");
option_cleanup(str);
return 1;
}
num_char_cols= atoi(str->string); num_char_cols= atoi(str->string);
if (str->option) if (str->option)
num_char_cols_index= atoi(str->option); num_char_cols_index= atoi(str->option);
@@ -1507,7 +1520,13 @@ get_options(int *argc,char ***argv)
printf("Parsing engines to use.\n"); printf("Parsing engines to use.\n");
if (default_engine) if (default_engine)
parse_option(default_engine, &engine_options, ','); {
if(parse_option(default_engine, &engine_options, ',') == -1)
{
fprintf(stderr, "Invalid value specified for the option 'engine'\n");
return 1;
}
}
if (tty_password) if (tty_password)
opt_password= get_tty_password(NullS); opt_password= get_tty_password(NullS);
@@ -1984,7 +2003,7 @@ end:
DBUG_RETURN(0); DBUG_RETURN(0);
} }
uint int
parse_option(const char *origin, option_string **stmt, char delm) parse_option(const char *origin, option_string **stmt, char delm)
{ {
char *retstr; char *retstr;
@@ -2009,6 +2028,13 @@ parse_option(const char *origin, option_string **stmt, char delm)
char buffer[HUGE_STRING_LENGTH]= ""; char buffer[HUGE_STRING_LENGTH]= "";
char *buffer_ptr; char *buffer_ptr;
/*
Return an error if the length of the any of the comma seprated value
exceeds HUGE_STRING_LENGTH.
*/
if ((size_t)(retstr - ptr) > HUGE_STRING_LENGTH)
return -1;
count++; count++;
strncpy(buffer, ptr, (size_t)(retstr - ptr)); strncpy(buffer, ptr, (size_t)(retstr - ptr));
/* /*
@@ -2048,6 +2074,13 @@ parse_option(const char *origin, option_string **stmt, char delm)
{ {
char *origin_ptr; char *origin_ptr;
/*
Return an error if the length of the any of the comma seprated value
exceeds HUGE_STRING_LENGTH.
*/
if (strlen(ptr) > HUGE_STRING_LENGTH)
return -1;
if ((origin_ptr= strchr(ptr, ':'))) if ((origin_ptr= strchr(ptr, ':')))
{ {
char *option_ptr; char *option_ptr;
@@ -2058,13 +2091,13 @@ parse_option(const char *origin, option_string **stmt, char delm)
option_ptr= (char *)ptr + 1 + tmp->length; option_ptr= (char *)ptr + 1 + tmp->length;
/* Move past the : and the first string */ /* Move past the : and the first string */
tmp->option_length= (size_t)((ptr + length) - option_ptr); tmp->option_length= strlen(option_ptr);
tmp->option= my_strndup(option_ptr, tmp->option_length, tmp->option= my_strndup(option_ptr, tmp->option_length,
MYF(MY_FAE)); MYF(MY_FAE));
} }
else else
{ {
tmp->length= (size_t)((ptr + length) - ptr); tmp->length= strlen(ptr);
tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE)); tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
} }

View File

@@ -228,7 +228,7 @@ rollback;
create table t0 (n int); create table t0 (n int);
insert t0 select * from t1; insert t0 select * from t1;
set autocommit=1; set autocommit=1;
insert into t0 select GET_LOCK("lock1",null); insert into t0 select GET_LOCK("lock1",0);
set autocommit=0; set autocommit=0;
create table t2 (n int) engine=innodb; create table t2 (n int) engine=innodb;
insert into t2 values (3); insert into t2 values (3);

View File

@@ -4810,6 +4810,7 @@ sub extract_warning_lines ($$) {
qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|, qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|,
qr|Failed to setup SSL|, qr|Failed to setup SSL|,
qr|SSL error: Failed to set ciphers to use|, qr|SSL error: Failed to set ciphers to use|,
qr/Plugin 'InnoDB' will be forced to shutdown/,
); );
my $matched_lines= []; my $matched_lines= [];

View File

@@ -1103,3 +1103,19 @@ ORDER BY field;
field field
c,c c,c
drop table t3, t2, t1; drop table t3, t2, t1;
#
# MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd
# execution of PS
#
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(1),(2);
PREPARE stmt FROM "SELECT GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) FROM t1 AS t1a, t1 AS t1b GROUP BY t1a.a";
EXECUTE stmt;
GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0)
1,1
2,2
EXECUTE stmt;
GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0)
1,1
2,2
DROP TABLE t1;

View File

@@ -361,5 +361,18 @@ set optimizer_switch=@optimizer_switch_save;
drop view v_merge, vm; drop view v_merge, vm;
drop table t1,tv; drop table t1,tv;
# #
# MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior
#
SELECT GET_LOCK('ul1', NULL);
GET_LOCK('ul1', NULL)
NULL
Warnings:
Warning 1411 Incorrect timeout value: 'NULL' for function get_lock
SELECT GET_LOCK('ul1', -1);
GET_LOCK('ul1', -1)
NULL
Warnings:
Warning 1411 Incorrect timeout value: '-1' for function get_lock
#
# End of 5.5 tests # End of 5.5 tests
# #

View File

@@ -18,3 +18,5 @@ mysqld-bin.000001 # Query # # use `test`; insert t1 values (2)
mysqld-bin.000001 # Query # # COMMIT mysqld-bin.000001 # Query # # COMMIT
drop table t1; drop table t1;
uninstall plugin innodb; uninstall plugin innodb;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown

View File

@@ -1,5 +1,7 @@
# #
# Test of MyISAM MRG tables with corrupted children. # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted
# children..
#
# Run with --myisam-recover=force option. # Run with --myisam-recover=force option.
# #
# Preparation: we need to make sure that the merge parent # Preparation: we need to make sure that the merge parent
@@ -101,3 +103,48 @@ execute stmt;
deallocate prepare stmt; deallocate prepare stmt;
set @@global.table_definition_cache=default; set @@global.table_definition_cache=default;
set @@global.table_open_cache=default; set @@global.table_open_cache=default;
#
# 18075170 - sql node restart required to avoid deadlock after
# restore
#
# Check that auto-repair for MyISAM tables can now happen in the
# middle of transaction, without aborting it.
create table t1 (a int, key(a)) engine=myisam;
create table t2 (a int);
insert into t2 values (1);
# Create a table with a corrupted index file:
# save an old index file, insert more rows,
# overwrite the new index file with the old one.
insert into t1 (a) values (1);
flush table t1;
insert into t1 (a) values (4);
flush table t1;
# Check table is needed to mark the table as crashed.
check table t1;
Table Op Msg_type Msg_text
test.t1 check warning Size of datafile is: 14 Should be: 7
test.t1 check error Record-count is not ok; is 2 Should be: 1
test.t1 check warning Found 2 key parts. Should be: 1
test.t1 check error Corrupt
# At this point we have a corrupt t1
set autocommit = 0;
select * from t2;
a
1
# Without fix select from t1 will break the transaction. After the fix
# transaction should be active and should hold lock on table t2. Alter
# table from con2 will wait only if the transaction is not broken.
select * from t1;
a
1
4
Warnings:
Error 145 Table 't1' is marked as crashed and should be repaired
Error 1194 Table 't1' is marked as crashed and should be repaired
Error 1034 Number of rows changed from 1 to 2
ALTER TABLE t2 ADD val INT;
# With fix we should have alter table waiting for t2 lock here.
ROLLBACK;
SET autocommit = 1;
# Cleanup
drop table t1, t2;

View File

@@ -0,0 +1,156 @@
drop table if exists t1;
Warnings:
Note 1051 Unknown table 't1'
drop view if exists view_t1;
Warnings:
Note 1051 Unknown table 'test.view_t1'
SET sql_mode=ONLY_FULL_GROUP_BY;
CREATE TABLE t1 (
pk INT,
f0 INT, f1 INT, f2 INT, f3 INT, f4 INT,
f5 INT, f6 INT, f7 INT, f8 INT, f9 INT,
PRIMARY KEY (pk)
);
CREATE VIEW view_t1 AS SELECT * FROM t1;
CREATE PROCEDURE s1()
SELECT * FROM (
INFORMATION_SCHEMA.`INNODB_BUFFER_PAGE_LRU` AS table1
LEFT JOIN test.view_t1 AS table2
ON ( table2.`f6` = table1.FREE_PAGE_CLOCK)
)
ORDER BY table1.NUMBER_RECORDS
LIMIT 0
;
CALL s1;
POOL_ID LRU_POSITION SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE COMPRESSED IO_FIX IS_OLD FREE_PAGE_CLOCK pk f0 f1 f2 f3 f4 f5 f6 f7 f8 f9
CALL s1;
POOL_ID LRU_POSITION SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE COMPRESSED IO_FIX IS_OLD FREE_PAGE_CLOCK pk f0 f1 f2 f3 f4 f5 f6 f7 f8 f9
drop table t1;
drop view view_t1;
drop procedure s1;
CREATE TABLE A (
pk INTEGER AUTO_INCREMENT,
col_int_key INTEGER,
col_varchar_key VARCHAR(1),
PRIMARY KEY (pk)
) ENGINE=MyISAM;
CREATE VIEW view_A AS SELECT * FROM A;
CREATE TABLE C (
pk INTEGER AUTO_INCREMENT,
col_int_nokey INTEGER,
col_int_key INTEGER,
col_date_key DATE,
col_date_nokey DATE,
col_time_key TIME,
col_time_nokey TIME,
col_datetime_key DATETIME,
col_datetime_nokey DATETIME,
col_varchar_key VARCHAR(1),
col_varchar_nokey VARCHAR(1),
PRIMARY KEY (pk)
) ENGINE=MyISAM;
CREATE VIEW view_C AS SELECT * FROM C;
CREATE TABLE AA (
pk INTEGER AUTO_INCREMENT,
col_int_nokey INTEGER,
col_int_key INTEGER,
col_date_key DATE,
col_date_nokey DATE,
col_time_key TIME,
col_time_nokey TIME,
col_datetime_key DATETIME,
col_datetime_nokey DATETIME,
col_varchar_key VARCHAR(1),
col_varchar_nokey VARCHAR(1),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key)
) ENGINE=MyISAM;
CREATE VIEW view_AA AS SELECT * FROM AA;
CREATE TABLE BB (
pk INTEGER AUTO_INCREMENT,
col_int_key INTEGER,
col_varchar_key VARCHAR(1),
col_varchar_nokey VARCHAR(1),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key)
) ENGINE=MyISAM;
CREATE VIEW view_BB AS SELECT * FROM BB;
CREATE TABLE DD (
pk INTEGER AUTO_INCREMENT,
col_int_key INTEGER,
col_date_key DATE,
col_time_key TIME,
col_datetime_key DATETIME,
col_varchar_key VARCHAR(1),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key)
) ENGINE=MyISAM;
CREATE VIEW view_DD AS SELECT * FROM DD;
CREATE TRIGGER k BEFORE INSERT ON `DD` FOR EACH ROW INSERT INTO `view_BB` SELECT * FROM `view_A` LIMIT 0 ;
CREATE TRIGGER r BEFORE INSERT ON `A` FOR EACH ROW INSERT INTO `view_AA` SELECT * FROM `view_C` LIMIT 0 ;
ALTER TABLE `DD` DROP PRIMARY KEY;
ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key
INSERT INTO `view_A` ( `pk` ) VALUES (NULL);
INSERT INTO `DD` ( `pk` ) VALUES (NULL);
INSERT INTO `A` ( `pk` ) VALUES (NULL);
INSERT INTO `view_DD` ( `pk` ) VALUES (NULL);
drop trigger r;
drop trigger k;
drop view view_A,view_AA,view_C,view_BB,view_DD;
drop table A,C,AA,BB,DD;
CREATE TABLE A (
i INT,
i1 INT,
i2 INT,
d1 DATE,
d2 DATE,
col_time_nokey1 TIME,
col_time_nokey2 TIME,
col_datetime_nokey1 DATETIME,
col_datetime_nokey2 DATETIME,
col_varchar_nokey1 VARCHAR(1),
col_varchar_nokey2 VARCHAR(1)
) ENGINE=MyISAM;
CREATE VIEW view_A AS SELECT * FROM A;
CREATE TABLE B (
col_varchar_nokey VARCHAR(1)
) ENGINE=MyISAM;
CREATE TABLE AA (
i INT,
i1 INT,
i2 INT,
d1 DATE,
d2 DATE,
col_time_nokey1 TIME,
col_time_nokey2 TIME,
col_datetime_nokey1 DATETIME,
col_datetime_nokey2 DATETIME,
col_varchar_nokey1 VARCHAR(1),
col_varchar_nokey2 VARCHAR(1)
) ENGINE=MyISAM;
CREATE VIEW view_AA AS SELECT * FROM AA;
CREATE TABLE DD (
i INT,
i1 INT,
i2 INT,
d1 DATE,
d2 DATE,
col_time_nokey1 TIME,
col_time_nokey2 TIME,
col_datetime_nokey1 DATETIME,
col_datetime_nokey2 DATETIME,
col_varchar_nokey1 VARCHAR(1),
col_varchar_nokey2 VARCHAR(1)
) ENGINE=MyISAM;
CREATE VIEW view_DD AS SELECT * FROM DD;
CREATE TRIGGER tr1 BEFORE INSERT ON `AA` FOR EACH ROW INSERT INTO `view_A` SELECT * FROM `view_AA` LIMIT 0 ;
CREATE TRIGGER tr2 BEFORE INSERT ON `B` FOR EACH ROW INSERT INTO `D` SELECT * FROM `A` LIMIT 0 ;
INSERT INTO `view_AA` ( `i` ) VALUES (1);
INSERT INTO `AA` ( `i` ) VALUES (2);
DELETE FROM `B`;
INSERT INTO `view_DD` ( `i` ) VALUES (1);
INSERT INTO `view_AA` ( `i` ) VALUES (3);
drop trigger tr1;
drop trigger tr2;
drop view view_A, view_AA,view_DD;
drop table A,B,AA,DD;

View File

@@ -2145,6 +2145,24 @@ drop database mysqltest1;
drop database mysqltest2; drop database mysqltest2;
drop database mysqltest3; drop database mysqltest3;
drop database mysqltest4; drop database mysqltest4;
#
# MDEV-7810 Wrong result on execution of a query as a PS
# (both 1st and further executions)
CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM;
INSERT INTO t1 VALUES (0),(8);
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2));
a
0
PREPARE stmt FROM "
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2))
";
execute stmt;
a
0
execute stmt;
a
0
drop table t1;
# End of 5.5 tests # End of 5.5 tests
set @subselect_mat_test_optimizer_switch_value=null; set @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';

View File

@@ -2185,4 +2185,22 @@ drop database mysqltest1;
drop database mysqltest2; drop database mysqltest2;
drop database mysqltest3; drop database mysqltest3;
drop database mysqltest4; drop database mysqltest4;
#
# MDEV-7810 Wrong result on execution of a query as a PS
# (both 1st and further executions)
CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM;
INSERT INTO t1 VALUES (0),(8);
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2));
a
0
PREPARE stmt FROM "
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2))
";
execute stmt;
a
0
execute stmt;
a
0
drop table t1;
# End of 5.5 tests # End of 5.5 tests

View File

@@ -5429,6 +5429,21 @@ View Create View character_set_client collation_connection
v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` latin1 latin1_swedish_ci v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` latin1 latin1_swedish_ci
drop view v2; drop view v2;
drop table t1; drop table t1;
#
# MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update
#
CREATE TABLE t1 (a INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (b INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (3),(4);
CREATE TABLE t3 (c INT) ENGINE=MyISAM;
INSERT INTO t3 VALUES (5),(6);
CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3;
PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )';
UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 );
EXECUTE stmt;
DROP TABLE t1, t2, t3;
DROP VIEW v3;
# ----------------------------------------------------------------- # -----------------------------------------------------------------
# -- End of 5.5 tests. # -- End of 5.5 tests.
# ----------------------------------------------------------------- # -----------------------------------------------------------------

View File

@@ -258,7 +258,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
create table t0 (n int); create table t0 (n int);
insert t0 select * from t1; insert t0 select * from t1;
set autocommit=1; set autocommit=1;
insert into t0 select GET_LOCK("lock1",null); insert into t0 select GET_LOCK("lock1",0);
set autocommit=0; set autocommit=0;
create table t2 (n int) engine=innodb; create table t2 (n int) engine=innodb;
insert into t2 values (3); insert into t2 values (3);

View File

@@ -242,7 +242,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
create table t0 (n int); create table t0 (n int);
insert t0 select * from t1; insert t0 select * from t1;
set autocommit=1; set autocommit=1;
insert into t0 select GET_LOCK("lock1",null); insert into t0 select GET_LOCK("lock1",0);
Warnings: Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave.
set autocommit=0; set autocommit=0;
@@ -288,7 +288,7 @@ master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert t0 select * from t1 master-bin.000001 # Query # # use `test`; insert t0 select * from t1
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t0 select GET_LOCK("lock1",null) master-bin.000001 # Query # # use `test`; insert into t0 select GET_LOCK("lock1",0)
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb
master-bin.000001 # Query # # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `t1`,`ti` master-bin.000001 # Query # # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `t1`,`ti`

View File

@@ -0,0 +1,13 @@
#
# Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE
#
create table t1(a int, b int, key(a),key(b))engine=innodb;
create table t2(a int, b int, key(a),key(b))engine=innodb;
alter table t2 add constraint b foreign key (b) references t1(a);
alter table t1 add constraint b1 foreign key (b) references t2(a);
alter table t2 add constraint b1 foreign key (b) references t1(a);
ERROR HY000: Can't create table '#sql-temporary' (errno: 121)
alter table t2 drop foreign key b;
alter table t1 drop foreign key b1;
drop table t2;
drop table t1;

View File

@@ -0,0 +1,105 @@
CREATE TABLE t1 (
id int(11) NOT NULL PRIMARY KEY,
a int(11) NOT NULL,
b int(11) NOT NULL,
c int not null,
CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE t2 (
id int(11) NOT NULL PRIMARY KEY,
a int(11) NOT NULL,
b int(11) NOT NULL,
c int not null,
CONSTRAINT mytest FOREIGN KEY (c) REFERENCES t1(id),
CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ERROR HY000: Can't create table 'test.t2' (errno: 121)
show warnings;
Level Code Message
Warning 121 Create or Alter table `test`.`t2` with foreign key constraint failed. Foreign key constraint `test/test` already exists on data dictionary. Foreign key constraint names need to be unique in database. Error in foreign key definition: CONSTRAINT `test` FOREIGN KEY (`b`) REFERENCES `test`.`t2` (`id`).
Error 1005 Can't create table 'test.t2' (errno: 121)
drop table t1;
create table t1(a int) engine=innodb;
create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=innodb;
ERROR HY000: Can't create table 'test.t2' (errno: 150)
show warnings;
Level Code Message
Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key a (a) references t1(a)) engine=innodb.
Error 1005 Can't create table 'test.t2' (errno: 150)
drop table t1;
create table t1(a int not null primary key, b int) engine=innodb;
create table t2(a int, b int, constraint a foreign key a (a) references t1(a),
constraint a foreign key a (a) references t1(b)) engine=innodb;
ERROR HY000: Can't create table 'test.t2' (errno: 150)
show warnings;
Level Code Message
Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key a (a) references t1(b)) engine=innodb.
Error 1005 Can't create table 'test.t2' (errno: 150)
create table t2(a int, b int, constraint a foreign key a (a) references t1(a)) engine=innodb;
alter table t2 add constraint b foreign key (b) references t2(b);
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings;
Level Code Message
Warning 150 Alter table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key (b) references t2(b).
Error 1005 Can't create table '#sql-temporary' (errno: 150)
drop table t2, t1;
create table t1 (f1 integer primary key) engine=innodb;
alter table t1 add constraint c1 foreign key (f1) references t11(f1);
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings;
Level Code Message
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Referenced table `test`.`t11` not found in the data dictionary close to foreign key (f1) references t11(f1).
Error 1005 Can't create table '#sql-temporary' (errno: 150)
drop table t1;
create temporary table t1(a int not null primary key, b int, key(b)) engine=innodb;
create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb;
ERROR HY000: Can't create table 'test.t2' (errno: 150)
show warnings;
Level Code Message
Warning 150 Create table `mysqld.1`.`t2` with foreign key constraint failed. Referenced table `mysqld.1`.`t1` not found in the data dictionary close to foreign key(a) references t1(a)) engine=innodb.
Error 1005 Can't create table 'test.t2' (errno: 150)
alter table t1 add foreign key(b) references t1(a);
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings;
Level Code Message
Warning 150 Alter table `mysqld.1`.`t1` with foreign key constraint failed. Referenced table `mysqld.1`.`t1` not found in the data dictionary close to foreign key(b) references t1(a).
Error 1005 Can't create table '#sql-temporary' (errno: 150)
drop table t1;
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
alter table t1 add foreign key(a,b) references t1(a);
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings;
Level Code Message
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Foreign key constraint parse error in foreign key(a,b) references t1(a) close to ). Too few referenced columns, you have 1 when you should have 2.
Error 1005 Can't create table '#sql-temporary' (errno: 150)
drop table t1;
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
alter table t1 add foreign key(a) references t1(a,b);
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings;
Level Code Message
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Foreign key constraint parse error in foreign key(a) references t1(a,b) close to ). Too few referenced columns, you have 2 when you should have 1.
Error 1005 Can't create table '#sql-temporary' (errno: 150)
drop table t1;
create table t1 (f1 integer not null primary key) engine=innodb;
alter table t1 add constraint c1 foreign key (f1) references t1(f1) on update set null;
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings;
Level Code Message
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. You have defined a SET NULL condition but column f1 is defined as NOT NULL in foreign key (f1) references t1(f1) on update set null close to on update set null.
Error 1005 Can't create table '#sql-temporary' (errno: 150)
create table t2(a int not null, foreign key(a) references t1(f1) on delete set null) engine=innodb;
ERROR HY000: Can't create table 'test.t2' (errno: 150)
show warnings;
Level Code Message
Warning 150 Create table `test`.`t2` with foreign key constraint failed. You have defined a SET NULL condition but column a is defined as NOT NULL in foreign key(a) references t1(f1) on delete set null) engine=innodb close to on delete set null) engine=innodb.
Error 1005 Can't create table 'test.t2' (errno: 150)
drop table t1;
create table t1 (id int not null primary key, f1 int, f2 int, key(f1)) engine=innodb;
create table t2(a char(20), key(a), foreign key(a) references t1(f1)) engine=innodb;
ERROR HY000: Can't create table 'test.t2' (errno: 150)
show warnings;
Level Code Message
Warning 150 Create table `test`.`t2` with foreign key constraint failed. Field type or character set for column a does not mach referenced column f1 close to foreign key(a) references t1(f1)) engine=innodb
Error 1005 Can't create table 'test.t2' (errno: 150)
drop table t1;

View File

@@ -50,6 +50,8 @@ CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE
ERROR HY000: Can't create table 'test.t2' (errno: 150) ERROR HY000: Can't create table 'test.t2' (errno: 150)
show warnings; show warnings;
Level Code Message Level Code Message
Warning 150 Create table `test`.`t2` with foreign key constraint failed. Referenced table `test`.`t3` not found in the data dictionary close to FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE
) ENGINE=InnoDB.
Error 1005 Can't create table 'test.t2' (errno: 150) Error 1005 Can't create table 'test.t2' (errno: 150)
CREATE TABLE t2 ( CREATE TABLE t2 (
id int(11) NOT NULL AUTO_INCREMENT, id int(11) NOT NULL AUTO_INCREMENT,
@@ -62,6 +64,7 @@ ALTER TABLE t2 ADD CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE
ERROR HY000: Can't create table '#sql-temporary' (errno: 150) ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
show warnings; show warnings;
Level Code Message Level Code Message
Warning 150 Alter table `test`.`t2` with foreign key constraint failed. Referenced table `test`.`t3` not found in the data dictionary close to FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE.
Error 1005 Can't create table '#sql-temporary' (errno: 150) Error 1005 Can't create table '#sql-temporary' (errno: 150)
drop table t2; drop table t2;
drop table t1; drop table t1;

View File

@@ -0,0 +1,22 @@
install plugin innodb soname 'ha_innodb';
create table t1(a int not null primary key) engine=innodb;
begin;
insert into t1 values(1);
flush tables;
uninstall plugin innodb;
select sleep(1);
sleep(1)
0
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
drop table t1;
install plugin innodb soname 'ha_innodb';
create table t2(a int not null primary key) engine=innodb;
insert into t2 values(1);
drop table t2;
uninstall plugin innodb;
select sleep(1);
sleep(1)
0
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown

View File

@@ -0,0 +1,21 @@
--source include/have_innodb.inc
--echo #
--echo # Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE
--echo #
create table t1(a int, b int, key(a),key(b))engine=innodb;
create table t2(a int, b int, key(a),key(b))engine=innodb;
alter table t2 add constraint b foreign key (b) references t1(a);
alter table t1 add constraint b1 foreign key (b) references t2(a);
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
alter table t2 add constraint b1 foreign key (b) references t1(a);
alter table t2 drop foreign key b;
alter table t1 drop foreign key b1;
drop table t2;
drop table t1;

View File

@@ -0,0 +1,130 @@
--source include/have_innodb.inc
#
# MDEV-8524: Improve error messaging when there is duplicate key or foreign key names
#
CREATE TABLE t1 (
id int(11) NOT NULL PRIMARY KEY,
a int(11) NOT NULL,
b int(11) NOT NULL,
c int not null,
CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
#
# Below create table fails because constraint name test
# is reserved for above table.
#
--error 1005
CREATE TABLE t2 (
id int(11) NOT NULL PRIMARY KEY,
a int(11) NOT NULL,
b int(11) NOT NULL,
c int not null,
CONSTRAINT mytest FOREIGN KEY (c) REFERENCES t1(id),
CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
show warnings;
drop table t1;
#
# MDEV-6697: Improve foreign keys warnings/errors
#
#
# No index for referenced columns
#
create table t1(a int) engine=innodb;
--error 1005
create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=innodb;
show warnings;
drop table t1;
create table t1(a int not null primary key, b int) engine=innodb;
--error 1005
create table t2(a int, b int, constraint a foreign key a (a) references t1(a),
constraint a foreign key a (a) references t1(b)) engine=innodb;
show warnings;
create table t2(a int, b int, constraint a foreign key a (a) references t1(a)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
alter table t2 add constraint b foreign key (b) references t2(b);
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t2, t1;
#
# Referenced table does not exists
#
create table t1 (f1 integer primary key) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
alter table t1 add constraint c1 foreign key (f1) references t11(f1);
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t1;
#
# Foreign key on temporal tables
#
create temporary table t1(a int not null primary key, b int, key(b)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
alter table t1 add foreign key(b) references t1(a);
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t1;
#
# Column numbers do not match
#
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
alter table t1 add foreign key(a,b) references t1(a);
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t1;
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
alter table t1 add foreign key(a) references t1(a,b);
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t1;
#
# ON UPDATE/DELETE SET NULL on NOT NULL column
#
create table t1 (f1 integer not null primary key) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
alter table t1 add constraint c1 foreign key (f1) references t1(f1) on update set null;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
create table t2(a int not null, foreign key(a) references t1(f1) on delete set null) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t1;
#
# Incorrect types
#
create table t1 (id int not null primary key, f1 int, f2 int, key(f1)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error 1005
create table t2(a char(20), key(a), foreign key(a) references t1(f1)) engine=innodb;
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
show warnings;
drop table t1;

View File

@@ -0,0 +1,3 @@
--ignore-builtin-innodb
--loose-innodb

View File

@@ -0,0 +1,58 @@
--source include/not_embedded.inc
--source include/not_windows.inc
if (!$HA_INNODB_SO) {
--skip Need InnoDB plugin
}
#
# MDEV-8474: InnoDB sets per-connection data unsafely
# Below test caused hang
#
install plugin innodb soname 'ha_innodb';
create table t1(a int not null primary key) engine=innodb;
connect (con1, localhost, root);
connection con1;
begin;
insert into t1 values(1);
connection default;
flush tables;
send uninstall plugin innodb;
connection con1;
select sleep(1);
disconnect con1;
connection default;
reap;
--source include/restart_mysqld.inc
drop table t1;
#
# Another test that caused hang.
#
connect (con1, localhost, root);
connection con1;
install plugin innodb soname 'ha_innodb';
create table t2(a int not null primary key) engine=innodb;
insert into t2 values(1);
drop table t2;
connection default;
send uninstall plugin innodb;
connection con1;
select sleep(1);
disconnect con1;
connection default;
reap;
--source include/restart_mysqld.inc

View File

@@ -0,0 +1,33 @@
#
# 18075170 - sql node restart required to avoid deadlock after
# restore
#
CREATE TABLE t1 (id INT) ENGINE=NDBCluster;
CREATE TABLE t2 (id INT) ENGINE=NDBCluster;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
DROP TABLE t1;
DROP TABLE t2;
SET autocommit = 0;
SELECT * FROM t1;
id
1
SELECT * FROM t2;
id
1
ROLLBACK;
SET autocommit = 1;
drop table t1;
drop table t2;
SET autocommit = 0;
SELECT * FROM t1;
id
1
SELECT * FROM t2;
id
1
ALTER TABLE t1 ADD val INT;
ROLLBACK;
SET autocommit = 1;
drop table t1;
drop table t2;

View File

@@ -0,0 +1,70 @@
-- source include/have_ndb.inc
-- source include/count_sessions.inc
--echo #
--echo # 18075170 - sql node restart required to avoid deadlock after
--echo # restore
--echo #
# Test Auto Discover option within a transaction
# and make sure the transaction is not broken.
CREATE TABLE t1 (id INT) ENGINE=NDBCluster;
CREATE TABLE t2 (id INT) ENGINE=NDBCluster;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
-- source include/ndb_backup.inc
DROP TABLE t1;
DROP TABLE t2;
-- source include/ndb_restore_master.inc
SET autocommit = 0;
SELECT * FROM t1;
# Without fix below select was resulting in DEADLOCK error. With fix select
# should succeed.
SELECT * FROM t2;
ROLLBACK;
SET autocommit = 1;
drop table t1;
drop table t2;
#
# Checking lock preservation in transaction
#
# Using existing backup to create the scenario. Tables are deleted as part of
# above test cleanup. Thus restoring the backup will bring the system to
# required state.
-- source include/ndb_restore_master.inc
SET autocommit = 0;
SELECT * FROM t1;
SELECT * FROM t2;
connect(con2, localhost, root);
--SEND ALTER TABLE t1 ADD val INT
connection default;
# Alter from con2 will be in waiting state as there is a lock on t1 from
# default connection due to active transaction. We check for this condition
# then releasing the lock by rollbacking active transaction.
let $wait_condition=
SELECT count(*) = 1 FROM information_schema.processlist WHERE state
LIKE "Waiting%" AND info = "ALTER TABLE t1 ADD val INT";
--source include/wait_condition.inc
ROLLBACK;
SET autocommit = 1;
connection con2;
--REAP
disconnect con2;
connection default;
drop table t1;
drop table t2;
# Wait till all disconnects are completed
-- source include/wait_until_count_sessions.inc

View File

@@ -14,4 +14,109 @@ select * from mysqltest.t3;
n n
45 45
drop database mysqltest; drop database mysqltest;
use test;
#
# Test bug where ALTER TABLE MODIFY didn't replicate properly
#
create table t1 (a int unsigned primary key, b int);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(10) unsigned NOT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 (a) values (1),((1<<32)-1);
select * from t1;
a b
1 NULL
4294967295 NULL
alter table t1 modify a bigint;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
a b
1 NULL
4294967295 NULL
alter table t1 modify a int unsigned;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(10) unsigned NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
a b
1 NULL
4294967295 NULL
alter table t1 modify a bigint unsigned;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) unsigned NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
a b
1 NULL
4294967295 NULL
use test;
select * from t1;
a b
1 NULL
4294967295 NULL
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) unsigned NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
create table t2 (a int unsigned auto_increment primary key, b int);
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
alter table t2 modify a bigint;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` bigint(20) NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
alter table t2 modify a bigint auto_increment;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` bigint(20) NOT NULL AUTO_INCREMENT,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1,t2;
#
# MDEV-8432: Slave cannot replicate signed integer-type values
# with high bit set to 1
# Test replication when we have int on master and bigint on slave
#
create table t1 (a int unsigned primary key, b int);
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
alter table t1 modify a bigint unsigned;
insert into t1 (a) values (1),((1<<32)-1);
select * from t1;
a b
1 NULL
4294967295 NULL
SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
drop table t1;
include/rpl_end.inc include/rpl_end.inc

View File

@@ -15,4 +15,57 @@ drop database mysqltest;
sync_slave_with_master; sync_slave_with_master;
# End of 4.1 tests # End of 4.1 tests
connection master;
use test;
--echo #
--echo # Test bug where ALTER TABLE MODIFY didn't replicate properly
--echo #
create table t1 (a int unsigned primary key, b int);
show create table t1;
insert into t1 (a) values (1),((1<<32)-1);
select * from t1;
alter table t1 modify a bigint;
show create table t1;
select * from t1;
alter table t1 modify a int unsigned;
show create table t1;
select * from t1;
alter table t1 modify a bigint unsigned;
show create table t1;
select * from t1;
sync_slave_with_master;
use test;
select * from t1;
show create table t1;
connection master;
#
create table t2 (a int unsigned auto_increment primary key, b int);
show create table t2;
alter table t2 modify a bigint;
show create table t2;
alter table t2 modify a bigint auto_increment;
show create table t2;
drop table t1,t2;
--echo #
--echo # MDEV-8432: Slave cannot replicate signed integer-type values
--echo # with high bit set to 1
--echo # Test replication when we have int on master and bigint on slave
--echo #
create table t1 (a int unsigned primary key, b int);
sync_slave_with_master;
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
alter table t1 modify a bigint unsigned;
connection master;
insert into t1 (a) values (1),((1<<32)-1);
sync_slave_with_master;
select * from t1;
SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
connection master;
drop table t1;
--source include/rpl_end.inc --source include/rpl_end.inc

View File

@@ -821,3 +821,14 @@ FROM ( SELECT * FROM t2 ) AS sq2, t3
ORDER BY field; ORDER BY field;
drop table t3, t2, t1; drop table t3, t2, t1;
--echo #
--echo # MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd
--echo # execution of PS
--echo #
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(1),(2);
PREPARE stmt FROM "SELECT GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) FROM t1 AS t1a, t1 AS t1b GROUP BY t1a.a";
EXECUTE stmt;
EXECUTE stmt;
DROP TABLE t1;

View File

@@ -391,6 +391,11 @@ set optimizer_switch=@optimizer_switch_save;
drop view v_merge, vm; drop view v_merge, vm;
drop table t1,tv; drop table t1,tv;
--echo #
--echo # MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior
--echo #
SELECT GET_LOCK('ul1', NULL);
SELECT GET_LOCK('ul1', -1);
--echo # --echo #
--echo # End of 5.5 tests --echo # End of 5.5 tests

View File

@@ -17,3 +17,6 @@ commit;
--source include/show_binlog_events.inc --source include/show_binlog_events.inc
drop table t1; drop table t1;
uninstall plugin innodb; uninstall plugin innodb;
--source include/restart_mysqld.inc

View File

@@ -1,5 +1,9 @@
--source include/count_sessions.inc
--echo #
--echo # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted
--echo # children..
--echo # --echo #
--echo # Test of MyISAM MRG tables with corrupted children.
--echo # Run with --myisam-recover=force option. --echo # Run with --myisam-recover=force option.
--echo # --echo #
--echo # Preparation: we need to make sure that the merge parent --echo # Preparation: we need to make sure that the merge parent
@@ -111,3 +115,66 @@ set @@global.table_open_cache=default;
disconnect con1; disconnect con1;
connection default; connection default;
--enable_ps_protocol --enable_ps_protocol
--echo #
--echo # 18075170 - sql node restart required to avoid deadlock after
--echo # restore
--echo #
--echo # Check that auto-repair for MyISAM tables can now happen in the
--echo # middle of transaction, without aborting it.
--enable_prepare_warnings
connection default;
create table t1 (a int, key(a)) engine=myisam;
create table t2 (a int);
insert into t2 values (1);
--echo # Create a table with a corrupted index file:
--echo # save an old index file, insert more rows,
--echo # overwrite the new index file with the old one.
insert into t1 (a) values (1);
flush table t1;
--copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI
insert into t1 (a) values (4);
flush table t1;
--remove_file $MYSQLD_DATADIR/test/t1.MYI
--copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI
--remove_file $MYSQLD_DATADIR/test/t1_copy.MYI
--echo # Check table is needed to mark the table as crashed.
check table t1;
--echo # At this point we have a corrupt t1
set autocommit = 0;
select * from t2;
--echo # Without fix select from t1 will break the transaction. After the fix
--echo # transaction should be active and should hold lock on table t2. Alter
--echo # table from con2 will wait only if the transaction is not broken.
--replace_regex /'.*[\/\\]/'/
select * from t1;
connect(con2, localhost, root);
--SEND ALTER TABLE t2 ADD val INT
connection default;
--echo # With fix we should have alter table waiting for t2 lock here.
let $wait_condition=
SELECT count(*) = 1 FROM information_schema.processlist WHERE state
LIKE "Waiting%" AND info = "ALTER TABLE t2 ADD val INT";
--source include/wait_condition.inc
ROLLBACK;
SET autocommit = 1;
connection con2;
--REAP
connection default;
disconnect con2;
--echo # Cleanup
drop table t1, t2;
# Wait till all disconnects are completed
-- source include/wait_until_count_sessions.inc

View File

@@ -14,7 +14,6 @@ file_exists $MYSQLD_DATADIR/mysql_upgrade_info;
--echo Run it again - should say already completed --echo Run it again - should say already completed
--replace_result $MYSQL_SERVER_VERSION VERSION --replace_result $MYSQL_SERVER_VERSION VERSION
--error 1
--exec $MYSQL_UPGRADE 2>&1 --exec $MYSQL_UPGRADE 2>&1
# It should have created a file in the MySQL Servers datadir # It should have created a file in the MySQL Servers datadir

187
mysql-test/t/sp-group.test Normal file
View File

@@ -0,0 +1,187 @@
--source include/have_innodb.inc
drop table if exists t1;
drop view if exists view_t1;
#
# Test case for MDEV 7601, MDEV-7594 and MDEV-7555
# Server crashes in functions related to stored procedures
# Server crashes in different ways while executing concurrent
# flow involving views and non-empty sql_mode with ONLY_FULL_GROUP_BY
#
SET sql_mode=ONLY_FULL_GROUP_BY;
CREATE TABLE t1 (
pk INT,
f0 INT, f1 INT, f2 INT, f3 INT, f4 INT,
f5 INT, f6 INT, f7 INT, f8 INT, f9 INT,
PRIMARY KEY (pk)
);
CREATE VIEW view_t1 AS SELECT * FROM t1;
CREATE PROCEDURE s1()
SELECT * FROM (
INFORMATION_SCHEMA.`INNODB_BUFFER_PAGE_LRU` AS table1
LEFT JOIN test.view_t1 AS table2
ON ( table2.`f6` = table1.FREE_PAGE_CLOCK)
)
ORDER BY table1.NUMBER_RECORDS
LIMIT 0
;
CALL s1;
CALL s1;
drop table t1;
drop view view_t1;
drop procedure s1;
#
# MDEV-7590
# Server crashes in st_select_lex_unit::cleanup on executing a trigger
#
CREATE TABLE A (
pk INTEGER AUTO_INCREMENT,
col_int_key INTEGER,
col_varchar_key VARCHAR(1),
PRIMARY KEY (pk)
) ENGINE=MyISAM;
CREATE VIEW view_A AS SELECT * FROM A;
CREATE TABLE C (
pk INTEGER AUTO_INCREMENT,
col_int_nokey INTEGER,
col_int_key INTEGER,
col_date_key DATE,
col_date_nokey DATE,
col_time_key TIME,
col_time_nokey TIME,
col_datetime_key DATETIME,
col_datetime_nokey DATETIME,
col_varchar_key VARCHAR(1),
col_varchar_nokey VARCHAR(1),
PRIMARY KEY (pk)
) ENGINE=MyISAM;
CREATE VIEW view_C AS SELECT * FROM C;
CREATE TABLE AA (
pk INTEGER AUTO_INCREMENT,
col_int_nokey INTEGER,
col_int_key INTEGER,
col_date_key DATE,
col_date_nokey DATE,
col_time_key TIME,
col_time_nokey TIME,
col_datetime_key DATETIME,
col_datetime_nokey DATETIME,
col_varchar_key VARCHAR(1),
col_varchar_nokey VARCHAR(1),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key)
) ENGINE=MyISAM;
CREATE VIEW view_AA AS SELECT * FROM AA;
CREATE TABLE BB (
pk INTEGER AUTO_INCREMENT,
col_int_key INTEGER,
col_varchar_key VARCHAR(1),
col_varchar_nokey VARCHAR(1),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key)
) ENGINE=MyISAM;
CREATE VIEW view_BB AS SELECT * FROM BB;
CREATE TABLE DD (
pk INTEGER AUTO_INCREMENT,
col_int_key INTEGER,
col_date_key DATE,
col_time_key TIME,
col_datetime_key DATETIME,
col_varchar_key VARCHAR(1),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key)
) ENGINE=MyISAM;
CREATE VIEW view_DD AS SELECT * FROM DD;
CREATE TRIGGER k BEFORE INSERT ON `DD` FOR EACH ROW INSERT INTO `view_BB` SELECT * FROM `view_A` LIMIT 0 ;
CREATE TRIGGER r BEFORE INSERT ON `A` FOR EACH ROW INSERT INTO `view_AA` SELECT * FROM `view_C` LIMIT 0 ;
--error ER_WRONG_AUTO_KEY
ALTER TABLE `DD` DROP PRIMARY KEY;
INSERT INTO `view_A` ( `pk` ) VALUES (NULL);
--error 0,ER_WRONG_VALUE_COUNT_ON_ROW
INSERT INTO `DD` ( `pk` ) VALUES (NULL);
INSERT INTO `A` ( `pk` ) VALUES (NULL);
--error 0,ER_WRONG_VALUE_COUNT_ON_ROW
INSERT INTO `view_DD` ( `pk` ) VALUES (NULL);
drop trigger r;
drop trigger k;
drop view view_A,view_AA,view_C,view_BB,view_DD;
drop table A,C,AA,BB,DD;
#
# MDEV-7581
# Server crashes in st_select_lex_unit::cleanup after a sequence of statements
#
CREATE TABLE A (
i INT,
i1 INT,
i2 INT,
d1 DATE,
d2 DATE,
col_time_nokey1 TIME,
col_time_nokey2 TIME,
col_datetime_nokey1 DATETIME,
col_datetime_nokey2 DATETIME,
col_varchar_nokey1 VARCHAR(1),
col_varchar_nokey2 VARCHAR(1)
) ENGINE=MyISAM;
CREATE VIEW view_A AS SELECT * FROM A;
CREATE TABLE B (
col_varchar_nokey VARCHAR(1)
) ENGINE=MyISAM;
CREATE TABLE AA (
i INT,
i1 INT,
i2 INT,
d1 DATE,
d2 DATE,
col_time_nokey1 TIME,
col_time_nokey2 TIME,
col_datetime_nokey1 DATETIME,
col_datetime_nokey2 DATETIME,
col_varchar_nokey1 VARCHAR(1),
col_varchar_nokey2 VARCHAR(1)
) ENGINE=MyISAM;
CREATE VIEW view_AA AS SELECT * FROM AA;
CREATE TABLE DD (
i INT,
i1 INT,
i2 INT,
d1 DATE,
d2 DATE,
col_time_nokey1 TIME,
col_time_nokey2 TIME,
col_datetime_nokey1 DATETIME,
col_datetime_nokey2 DATETIME,
col_varchar_nokey1 VARCHAR(1),
col_varchar_nokey2 VARCHAR(1)
) ENGINE=MyISAM;
CREATE VIEW view_DD AS SELECT * FROM DD;
CREATE TRIGGER tr1 BEFORE INSERT ON `AA` FOR EACH ROW INSERT INTO `view_A` SELECT * FROM `view_AA` LIMIT 0 ;
CREATE TRIGGER tr2 BEFORE INSERT ON `B` FOR EACH ROW INSERT INTO `D` SELECT * FROM `A` LIMIT 0 ;
INSERT INTO `view_AA` ( `i` ) VALUES (1);
INSERT INTO `AA` ( `i` ) VALUES (2);
DELETE FROM `B`;
INSERT INTO `view_DD` ( `i` ) VALUES (1);
INSERT INTO `view_AA` ( `i` ) VALUES (3);
drop trigger tr1;
drop trigger tr2;
drop view view_A, view_AA,view_DD;
drop table A,B,AA,DD;

View File

@@ -1841,5 +1841,20 @@ drop database mysqltest2;
drop database mysqltest3; drop database mysqltest3;
drop database mysqltest4; drop database mysqltest4;
--echo # End of 5.5 tests --echo #
--echo # MDEV-7810 Wrong result on execution of a query as a PS
--echo # (both 1st and further executions)
CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM;
INSERT INTO t1 VALUES (0),(8);
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2));
PREPARE stmt FROM "
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2))
";
execute stmt;
execute stmt;
drop table t1;
--echo # End of 5.5 tests

View File

@@ -5380,6 +5380,27 @@ show create view v2;
drop view v2; drop view v2;
drop table t1; drop table t1;
--echo #
--echo # MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update
--echo #
CREATE TABLE t1 (a INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1),(2); # Not necessary, the table can be empty
CREATE TABLE t2 (b INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (3),(4); # Not necessary, the table can be empty
CREATE TABLE t3 (c INT) ENGINE=MyISAM;
INSERT INTO t3 VALUES (5),(6); # Not necessary, the table can be empty
CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3;
PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )';
UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 );
EXECUTE stmt;
DROP TABLE t1, t2, t3;
DROP VIEW v3;
--echo # ----------------------------------------------------------------- --echo # -----------------------------------------------------------------
--echo # -- End of 5.5 tests. --echo # -- End of 5.5 tests.
--echo # ----------------------------------------------------------------- --echo # -----------------------------------------------------------------

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -91,6 +91,7 @@ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
reg3 int length= *compare_length; reg3 int length= *compare_length;
reg1 uchar *first,*last; reg1 uchar *first,*last;
DBUG_ASSERT(length > 0);
first= *a; last= *b; first= *a; last= *b;
while (--length) while (--length)
{ {

View File

@@ -1,3 +1,11 @@
/* Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved.
See file COPYRIGHT for details.
This file was modified by Oracle on 2015-05-18 for 32-bit compatibility.
Modifications copyright (c) 2015, Oracle and/or its affiliates. All rights
reserved. */
#include <my_global.h> #include <my_global.h>
#include <m_string.h> #include <m_string.h>
#include <m_ctype.h> #include <m_ctype.h>
@@ -133,12 +141,26 @@ CHARSET_INFO *charset;
} else } else
len = strlen((char *)pattern); len = strlen((char *)pattern);
/*
Find the maximum len we can safely process
without a rollover and a mis-malloc.
p->ssize is a sopno is a long (32+ bit signed);
size_t is 16+ bit unsigned.
*/
{
size_t new_ssize = len / (size_t)2 * (size_t)3 + (size_t)1; /* ugh */
if ((new_ssize < len) || /* size_t rolled over */
((SIZE_T_MAX / sizeof(sop)) < new_ssize) || /* malloc arg */
(new_ssize > LONG_MAX)) /* won't fit in ssize */
return(REG_ESPACE); /* MY_REG_ESPACE or MY_REG_INVARG */
p->ssize = new_ssize;
}
/* do the mallocs early so failure handling is easy */ /* do the mallocs early so failure handling is easy */
g = (struct re_guts *)malloc(sizeof(struct re_guts) + g = (struct re_guts *)malloc(sizeof(struct re_guts) +
(NC-1)*sizeof(cat_t)); (NC-1)*sizeof(cat_t));
if (g == NULL) if (g == NULL)
return(REG_ESPACE); return(REG_ESPACE);
p->ssize = (long) (len/(size_t)2*(size_t)3 + (size_t)1); /* ugh */
p->strip = (sop *)malloc(p->ssize * sizeof(sop)); p->strip = (sop *)malloc(p->ssize * sizeof(sop));
p->slen = 0; p->slen = 0;
if (p->strip == NULL) { if (p->strip == NULL) {

View File

@@ -7612,7 +7612,8 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
} }
Field_blob::store_length(length); Field_blob::store_length(length);
if (table->copy_blobs || length <= MAX_FIELD_WIDTH) if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
from != value.ptr())
{ // Must make a copy { // Must make a copy
value.copy(from, length, cs); value.copy(from, length, cs);
from= value.ptr(); from= value.ptr();

View File

@@ -1146,18 +1146,24 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
because Item_singlerow_subselect later calls Item_cache-specific methods, because Item_singlerow_subselect later calls Item_cache-specific methods,
e.g. row[i]->store() and row[i]->cache_value(). e.g. row[i]->store() and row[i]->cache_value().
Let's wrap Item_func_conv_charset to a new Item_cache, Let's wrap Item_func_conv_charset in a new Item_cache,
so the Item_cache-specific methods can still be used for so the Item_cache-specific methods can still be used for
Item_singlerow_subselect::row[i] safely. Item_singlerow_subselect::row[i] safely.
As a bonus we cache the converted value, instead of converting every time
TODO: we should eventually check all other use cases of change_item_tree(). TODO: we should eventually check all other use cases of change_item_tree().
Perhaps some more potentially dangerous substitution examples exist. Perhaps some more potentially dangerous substitution examples exist.
*/ */
Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs) Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs)
{ {
Item_func_conv_charset *conv= new Item_func_conv_charset(example, tocs, 1); if (!example)
return Item::safe_charset_converter(tocs);
Item *conv= example->safe_charset_converter(tocs);
if (conv == example)
return this;
Item_cache *cache; Item_cache *cache;
if (!conv || !conv->safe || !(cache= new Item_cache_str(conv))) if (!conv || !(cache= new Item_cache_str(conv)))
return NULL; // Safe conversion is not possible, or OEM return NULL; // Safe conversion is not possible, or OEM
cache->setup(conv); cache->setup(conv);
cache->fixed= false; // Make Item::fix_fields() happy cache->fixed= false; // Make Item::fix_fields() happy
@@ -4408,19 +4414,24 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *resolved_item, Item_ident *resolved_item,
Item_ident *mark_item) Item_ident *mark_item)
{
DBUG_ENTER("mark_as_dependent");
/* store pointer on SELECT_LEX from which item is dependent */
if (mark_item && mark_item->can_be_depended)
{
DBUG_PRINT("info", ("mark_item: %p lex: %p", mark_item, last));
mark_item->depended_from= last;
}
if (current->mark_as_dependent(thd, last,
/** resolved_item psergey-thu **/ mark_item))
DBUG_RETURN(TRUE);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{ {
const char *db_name= (resolved_item->db_name ? const char *db_name= (resolved_item->db_name ?
resolved_item->db_name : ""); resolved_item->db_name : "");
const char *table_name= (resolved_item->table_name ? const char *table_name= (resolved_item->table_name ?
resolved_item->table_name : ""); resolved_item->table_name : "");
/* store pointer on SELECT_LEX from which item is dependent */
if (mark_item && mark_item->can_be_depended)
mark_item->depended_from= last;
if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu
**/mark_item))
return TRUE;
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED), ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED),
db_name, (db_name[0] ? "." : ""), db_name, (db_name[0] ? "." : ""),
@@ -4428,7 +4439,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
resolved_item->field_name, resolved_item->field_name,
current->select_number, last->select_number); current->select_number, last->select_number);
} }
return FALSE; DBUG_RETURN(FALSE);
} }
@@ -4877,7 +4888,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
non aggregated fields of the outer select. non aggregated fields of the outer select.
*/ */
marker= select->cur_pos_in_select_list; marker= select->cur_pos_in_select_list;
select->non_agg_fields.push_back(this); select->join->non_agg_fields.push_back(this);
} }
if (*from_field != view_ref_found) if (*from_field != view_ref_found)
{ {
@@ -5293,9 +5304,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
fixed= 1; fixed= 1;
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
!outer_fixed && !thd->lex->in_sum_func && !outer_fixed && !thd->lex->in_sum_func &&
thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS) thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS &&
thd->lex->current_select->join)
{ {
thd->lex->current_select->non_agg_fields.push_back(this); thd->lex->current_select->join->non_agg_fields.push_back(this);
marker= thd->lex->current_select->cur_pos_in_select_list; marker= thd->lex->current_select->cur_pos_in_select_list;
} }
mark_non_agg_field: mark_non_agg_field:
@@ -6742,7 +6754,7 @@ Item_ref::Item_ref(Name_resolution_context *context_arg,
/* /*
This constructor used to create some internals references over fixed items This constructor used to create some internals references over fixed items
*/ */
if (ref && *ref && (*ref)->fixed) if ((set_properties_only= (ref && *ref && (*ref)->fixed)))
set_properties(); set_properties();
} }
@@ -6786,7 +6798,7 @@ Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item,
/* /*
This constructor is used to create some internal references over fixed items This constructor is used to create some internal references over fixed items
*/ */
if (ref && *ref && (*ref)->fixed) if ((set_properties_only= (ref && *ref && (*ref)->fixed)))
set_properties(); set_properties();
} }
@@ -6861,7 +6873,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
SELECT_LEX *current_sel= thd->lex->current_select; SELECT_LEX *current_sel= thd->lex->current_select;
if (!ref || ref == not_found_item) if (set_properties_only)
{
/* do nothing */
}
else if (!ref || ref == not_found_item)
{ {
DBUG_ASSERT(reference_trough_name != 0); DBUG_ASSERT(reference_trough_name != 0);
if (!(ref= resolve_ref_in_select_and_group(thd, this, if (!(ref= resolve_ref_in_select_and_group(thd, this,
@@ -6879,7 +6895,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
{ {
/* The current reference cannot be resolved in this query. */ /* The current reference cannot be resolved in this query. */
my_error(ER_BAD_FIELD_ERROR,MYF(0), my_error(ER_BAD_FIELD_ERROR,MYF(0),
this->full_name(), current_thd->where); this->full_name(), thd->where);
goto error; goto error;
} }
@@ -7014,7 +7030,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error; goto error;
thd->change_item_tree(reference, fld); thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex, mark_as_dependent(thd, last_checked_context->select_lex,
thd->lex->current_select, fld, fld); current_sel, fld, fld);
/* /*
A reference is resolved to a nest level that's outer or the same as A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of the nest level of the enclosing set function : adjust the value of
@@ -7031,7 +7047,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
{ {
/* The item was not a table field and not a reference */ /* The item was not a table field and not a reference */
my_error(ER_BAD_FIELD_ERROR, MYF(0), my_error(ER_BAD_FIELD_ERROR, MYF(0),
this->full_name(), current_thd->where); this->full_name(), thd->where);
goto error; goto error;
} }
/* Should be checked in resolve_ref_in_select_and_group(). */ /* Should be checked in resolve_ref_in_select_and_group(). */

View File

@@ -631,7 +631,7 @@ public:
*/ */
uint name_length; /* Length of name */ uint name_length; /* Length of name */
uint decimals; uint decimals;
int8 marker; int marker;
bool maybe_null; /* If item may be null */ bool maybe_null; /* If item may be null */
bool in_rollup; /* If used in GROUP BY list bool in_rollup; /* If used in GROUP BY list
of a query with ROLLUP */ of a query with ROLLUP */
@@ -2946,6 +2946,7 @@ class Item_ref :public Item_ident
{ {
protected: protected:
void set_properties(); void set_properties();
bool set_properties_only; // the item doesn't need full fix_fields
public: public:
enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF }; enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF };
Field *result_field; /* Save result here */ Field *result_field; /* Save result here */
@@ -2955,7 +2956,7 @@ public:
const char *db_arg, const char *table_name_arg, const char *db_arg, const char *table_name_arg,
const char *field_name_arg) const char *field_name_arg)
:Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg),
result_field(0), ref(0), reference_trough_name(1) {} set_properties_only(0), result_field(0), ref(0), reference_trough_name(1) {}
/* /*
This constructor is used in two scenarios: This constructor is used in two scenarios:
A) *item = NULL A) *item = NULL
@@ -2978,7 +2979,7 @@ public:
/* Constructor need to process subselect with temporary tables (see Item) */ /* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item) Item_ref(THD *thd, Item_ref *item)
:Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} :Item_ident(thd, item), set_properties_only(0), result_field(item->result_field), ref(item->ref) {}
enum Type type() const { return REF_ITEM; } enum Type type() const { return REF_ITEM; }
enum Type real_type() const { return ref ? (*ref)->type() : enum Type real_type() const { return ref ? (*ref)->type() :
REF_ITEM; } REF_ITEM; }

View File

@@ -4196,7 +4196,25 @@ longlong Item_func_get_lock::val_int()
it's not guaranteed to be same as on master. it's not guaranteed to be same as on master.
*/ */
if (thd->slave_thread) if (thd->slave_thread)
{
null_value= 0;
DBUG_RETURN(1); DBUG_RETURN(1);
}
if (args[1]->null_value ||
(!args[1]->unsigned_flag && ((longlong) timeout < 0)))
{
char buf[22];
if (args[1]->null_value)
strmov(buf, "NULL");
else
llstr(((longlong) timeout), buf);
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
"timeout", buf, "get_lock");
null_value= 1;
DBUG_RETURN(0);
}
mysql_mutex_lock(&LOCK_user_locks); mysql_mutex_lock(&LOCK_user_locks);

View File

@@ -464,6 +464,7 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
{ {
List_iterator<Ref_to_outside> it(upper_refs); List_iterator<Ref_to_outside> it(upper_refs);
Ref_to_outside *upper; Ref_to_outside *upper;
DBUG_ENTER("recalc_used_tables");
used_tables_cache= 0; used_tables_cache= 0;
while ((upper= it++)) while ((upper= it++))
@@ -523,6 +524,8 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
he has done const table detection, and that will be our chance to update he has done const table detection, and that will be our chance to update
const_tables_cache. const_tables_cache.
*/ */
DBUG_PRINT("exit", ("used_tables_cache: %llx", used_tables_cache));
DBUG_VOID_RETURN;
} }
@@ -1999,7 +2002,6 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN * join,
during JOIN::optimize: this->tmp_having= this->having; this->having= 0; during JOIN::optimize: this->tmp_having= this->having; this->having= 0;
*/ */
Item* join_having= join->having ? join->having : join->tmp_having; Item* join_having= join->having ? join->having : join->tmp_having;
DBUG_ENTER("Item_in_subselect::create_single_in_to_exists_cond"); DBUG_ENTER("Item_in_subselect::create_single_in_to_exists_cond");
*where_item= NULL; *where_item= NULL;

View File

@@ -3514,9 +3514,17 @@ bool Item_func_group_concat::setup(THD *thd)
"all_fields". The resulting field list is used as input to create "all_fields". The resulting field list is used as input to create
tmp table columns. tmp table columns.
*/ */
if (arg_count_order && if (arg_count_order)
setup_order(thd, args, context->table_list, list, all_fields, *order)) {
uint n_elems= arg_count_order + all_fields.elements;
ref_pointer_array= static_cast<Item**>(thd->alloc(sizeof(Item*) * n_elems));
if (!ref_pointer_array)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
memcpy(ref_pointer_array, args, arg_count * sizeof(Item*));
if (setup_order(thd, ref_pointer_array, context->table_list, list,
all_fields, *order))
DBUG_RETURN(TRUE);
}
count_field_types(select_lex, tmp_table_param, all_fields, 0); count_field_types(select_lex, tmp_table_param, all_fields, 0);
tmp_table_param->force_copy_fields= force_copy_fields; tmp_table_param->force_copy_fields= force_copy_fields;

View File

@@ -1394,6 +1394,7 @@ class Item_func_group_concat : public Item_sum
String *separator; String *separator;
TREE tree_base; TREE tree_base;
TREE *tree; TREE *tree;
Item **ref_pointer_array;
/** /**
If DISTINCT is used with this GROUP_CONCAT, this member is used to filter If DISTINCT is used with this GROUP_CONCAT, this member is used to filter

View File

@@ -3778,6 +3778,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
{ {
int error; int error;
char *to_purge_if_included= NULL; char *to_purge_if_included= NULL;
ulonglong log_space_reclaimed= 0;
DBUG_ENTER("purge_first_log"); DBUG_ENTER("purge_first_log");
DBUG_ASSERT(is_open()); DBUG_ASSERT(is_open());
@@ -3826,17 +3827,13 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE();); DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
mysql_mutex_lock(&rli->log_space_lock);
rli->relay_log.purge_logs(to_purge_if_included, included, rli->relay_log.purge_logs(to_purge_if_included, included,
0, 0, &rli->log_space_total); 0, 0, &log_space_reclaimed);
mysql_mutex_unlock(&rli->log_space_lock);
/* mysql_mutex_lock(&rli->log_space_lock);
Ok to broadcast after the critical region as there is no risk of rli->log_space_total-= log_space_reclaimed;
the mutex being destroyed by this thread later - this helps save
context switches
*/
mysql_cond_broadcast(&rli->log_space_cond); mysql_cond_broadcast(&rli->log_space_cond);
mysql_mutex_unlock(&rli->log_space_lock);
/* /*
* Need to update the log pos because purge logs has been called * Need to update the log pos because purge logs has been called
@@ -3885,7 +3882,7 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads
@param need_mutex @param need_mutex
@param need_update_threads If we want to update the log coordinates of @param need_update_threads If we want to update the log coordinates of
all threads. False for relay logs, true otherwise. all threads. False for relay logs, true otherwise.
@param freed_log_space If not null, decrement this variable of @param reclaimeed_log_space If not null, increment this variable to
the amount of log space freed the amount of log space freed
@note @note
@@ -3905,7 +3902,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
bool included, bool included,
bool need_mutex, bool need_mutex,
bool need_update_threads, bool need_update_threads,
ulonglong *decrease_log_space) ulonglong *reclaimed_space)
{ {
int error= 0; int error= 0;
bool exit_loop= 0; bool exit_loop= 0;
@@ -3970,7 +3967,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
err: err:
/* Read each entry from purge_index_file and delete the file. */ /* Read each entry from purge_index_file and delete the file. */
if (is_inited_purge_index_file() && if (is_inited_purge_index_file() &&
(error= purge_index_entry(thd, decrease_log_space, FALSE))) (error= purge_index_entry(thd, reclaimed_space, FALSE)))
sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files" sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
" that would be purged."); " that would be purged.");
close_purge_index_file(); close_purge_index_file();
@@ -4075,7 +4072,7 @@ int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
DBUG_RETURN(register_purge_index_entry(entry)); DBUG_RETURN(register_purge_index_entry(entry));
} }
int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space,
bool need_mutex) bool need_mutex)
{ {
DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry"); DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
@@ -4195,8 +4192,8 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
DBUG_PRINT("info",("purging %s",log_info.log_file_name)); DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0))) if (!my_delete(log_info.log_file_name, MYF(0)))
{ {
if (decrease_log_space) if (reclaimed_space)
*decrease_log_space-= s.st_size; *reclaimed_space+= s.st_size;
} }
else else
{ {

View File

@@ -1252,9 +1252,10 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
} }
data_len= uint4korr(buf + EVENT_LEN_OFFSET); data_len= uint4korr(buf + EVENT_LEN_OFFSET);
if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN || if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
data_len > current_thd->variables.max_allowed_packet) data_len > max(current_thd->variables.max_allowed_packet,
opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
{ {
DBUG_PRINT("error",("data_len: %ld", data_len)); DBUG_PRINT("error",("data_len: %lu", data_len));
result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS : result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
LOG_READ_TOO_LARGE); LOG_READ_TOO_LARGE);
goto end; goto end;
@@ -1375,7 +1376,7 @@ failed my_b_read"));
*/ */
DBUG_RETURN(0); DBUG_RETURN(0);
} }
uint data_len = uint4korr(head + EVENT_LEN_OFFSET); ulong data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= 0; char *buf= 0;
const char *error= 0; const char *error= 0;
Log_event *res= 0; Log_event *res= 0;
@@ -1384,7 +1385,8 @@ failed my_b_read"));
uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0; uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0;
#endif #endif
if (data_len > max_allowed_packet) if (data_len > max(max_allowed_packet,
opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
{ {
error = "Event too big"; error = "Event too big";
goto err; goto err;
@@ -1418,7 +1420,7 @@ err:
{ {
DBUG_ASSERT(error != 0); DBUG_ASSERT(error != 0);
sql_print_error("Error in Log_event::read_log_event(): " sql_print_error("Error in Log_event::read_log_event(): "
"'%s', data_len: %d, event_type: %d", "'%s', data_len: %lu, event_type: %d",
error,data_len,head[EVENT_TYPE_OFFSET]); error,data_len,head[EVENT_TYPE_OFFSET]);
my_free(buf); my_free(buf);
/* /*

View File

@@ -2644,7 +2644,6 @@ void unlink_thd(THD *thd)
thd->add_status_to_global(); thd->add_status_to_global();
mysql_mutex_lock(&LOCK_thread_count); mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
thd->unlink(); thd->unlink();
/* /*
Used by binlog_reset_master. It would be cleaner to use Used by binlog_reset_master. It would be cleaner to use
@@ -2652,6 +2651,16 @@ void unlink_thd(THD *thd)
sync feature has been shut down at this point. sync feature has been shut down at this point.
*/ */
DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5);); DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5););
if (unlikely(abort_loop))
{
/*
During shutdown, we have to delete thd inside the mutex
to not refer to mutexes that may be deleted during shutdown
*/
delete thd;
thd= 0;
}
thread_count--;
mysql_mutex_unlock(&LOCK_thread_count); mysql_mutex_unlock(&LOCK_thread_count);
delete thd; delete thd;

View File

@@ -38,8 +38,6 @@ typedef struct Trans_binlog_info {
char log_file[FN_REFLEN]; char log_file[FN_REFLEN];
} Trans_binlog_info; } Trans_binlog_info;
static pthread_key(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
int get_user_var_int(const char *name, int get_user_var_int(const char *name,
long long int *value, int *null_value) long long int *value, int *null_value)
{ {
@@ -143,13 +141,6 @@ int delegates_init()
} }
#endif #endif
if (pthread_key_create(&RPL_TRANS_BINLOG_INFO, NULL))
{
sql_print_error("Error while creating pthread specific data key for replication. "
"Please report a bug.");
return 1;
}
return 0; return 0;
} }
@@ -195,27 +186,27 @@ void delegates_destroy()
int Trans_delegate::after_commit(THD *thd, bool all) int Trans_delegate::after_commit(THD *thd, bool all)
{ {
Trans_param param; Trans_param param;
Trans_binlog_info *log_info;
bool is_real_trans= (all || thd->transaction.all.ha_list == 0); bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
int ret= 0;
param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
Trans_binlog_info *log_info= log_info= thd->semisync_info;
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
param.log_file= log_info ? log_info->log_file : 0; param.log_file= log_info && log_info->log_file[0] ? log_info->log_file : 0;
param.log_pos= log_info ? log_info->log_pos : 0; param.log_pos= log_info ? log_info->log_pos : 0;
int ret= 0;
FOREACH_OBSERVER(ret, after_commit, false, (&param)); FOREACH_OBSERVER(ret, after_commit, false, (&param));
/* /*
This is the end of a real transaction or autocommit statement, we This is the end of a real transaction or autocommit statement, we
can free the memory allocated for binlog file and position. can mark the memory unused.
*/ */
if (is_real_trans && log_info) if (is_real_trans && log_info)
{ {
my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); log_info->log_file[0]= 0;
my_free(log_info); log_info->log_pos= 0;
} }
return ret; return ret;
} }
@@ -223,27 +214,27 @@ int Trans_delegate::after_commit(THD *thd, bool all)
int Trans_delegate::after_rollback(THD *thd, bool all) int Trans_delegate::after_rollback(THD *thd, bool all)
{ {
Trans_param param; Trans_param param;
Trans_binlog_info *log_info;
bool is_real_trans= (all || thd->transaction.all.ha_list == 0); bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
int ret= 0;
param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
Trans_binlog_info *log_info= log_info= thd->semisync_info;
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
param.log_file= log_info ? log_info->log_file : 0; param.log_file= log_info && log_info->log_file[0] ? log_info->log_file : 0;
param.log_pos= log_info ? log_info->log_pos : 0; param.log_pos= log_info ? log_info->log_pos : 0;
int ret= 0;
FOREACH_OBSERVER(ret, after_rollback, false, (&param)); FOREACH_OBSERVER(ret, after_rollback, false, (&param));
/* /*
This is the end of a real transaction or autocommit statement, we This is the end of a real transaction or autocommit statement, we
can free the memory allocated for binlog file and position. can mark the memory unused.
*/ */
if (is_real_trans && log_info) if (is_real_trans && log_info)
{ {
my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); log_info->log_file[0]= 0;
my_free(log_info); log_info->log_pos= 0;
} }
return ret; return ret;
} }
@@ -254,25 +245,24 @@ int Binlog_storage_delegate::after_flush(THD *thd,
bool synced) bool synced)
{ {
Binlog_storage_param param; Binlog_storage_param param;
Trans_binlog_info *log_info;
uint32 flags=0; uint32 flags=0;
int ret= 0;
if (synced) if (synced)
flags |= BINLOG_STORAGE_IS_SYNCED; flags |= BINLOG_STORAGE_IS_SYNCED;
Trans_binlog_info *log_info= if (!(log_info= thd->semisync_info))
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
if (!log_info)
{ {
if(!(log_info= if(!(log_info=
(Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0)))) (Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0))))
return 1; return 1;
my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, log_info); thd->semisync_info= log_info;
} }
strcpy(log_info->log_file, log_file+dirname_length(log_file)); strcpy(log_info->log_file, log_file+dirname_length(log_file));
log_info->log_pos = log_pos; log_info->log_pos = log_pos;
int ret= 0;
FOREACH_OBSERVER(ret, after_flush, false, FOREACH_OBSERVER(ret, after_flush, false,
(&param, log_info->log_file, log_info->log_pos, flags)); (&param, log_info->log_file, log_info->log_pos, flags));
return ret; return ret;

View File

@@ -876,6 +876,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
{ {
Create_field *field_def= Create_field *field_def=
(Create_field*) alloc_root(thd->mem_root, sizeof(Create_field)); (Create_field*) alloc_root(thd->mem_root, sizeof(Create_field));
bool unsigned_flag= 0;
if (field_list.push_back(field_def)) if (field_list.push_back(field_def))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
@@ -885,8 +886,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
uint32 max_length= uint32 max_length=
max_display_length_for_field(type(col), field_metadata(col)); max_display_length_for_field(type(col), field_metadata(col));
switch(type(col)) switch(type(col)) {
{
int precision; int precision;
case MYSQL_TYPE_ENUM: case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET: case MYSQL_TYPE_SET:
@@ -925,6 +925,18 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
pack_length= field_metadata(col) & 0x00ff; pack_length= field_metadata(col) & 0x00ff;
break; break;
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
/*
As we don't know if the integer was signed or not on the master,
assume we have same sign on master and slave. This is true when not
using conversions so it should be true also when using conversions.
*/
unsigned_flag= ((Field_num*) target_table->field[col])->unsigned_flag;
break;
default: default:
break; break;
} }
@@ -932,12 +944,13 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
" maybe_null: %d, unsigned_flag: %d, pack_length: %u", " maybe_null: %d, unsigned_flag: %d, pack_length: %u",
type(col), target_table->field[col]->field_name, type(col), target_table->field[col]->field_name,
max_length, decimals, TRUE, FALSE, pack_length)); max_length, decimals, TRUE, unsigned_flag,
pack_length));
field_def->init_for_tmp_table(type(col), field_def->init_for_tmp_table(type(col),
max_length, max_length,
decimals, decimals,
TRUE, // maybe_null TRUE, // maybe_null
FALSE, // unsigned_flag unsigned_flag,
pack_length); pack_length);
field_def->charset= target_table->field[col]->charset(); field_def->charset= target_table->field[col]->charset();
field_def->interval= interval; field_def->interval= interval;

View File

@@ -3531,9 +3531,7 @@ pthread_handler_t handle_slave_sql(void *arg)
rli->clear_error(); rli->clear_error();
//tell the I/O thread to take relay_log_space_limit into account from now on //tell the I/O thread to take relay_log_space_limit into account from now on
mysql_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0; rli->ignore_log_space_limit= 0;
mysql_mutex_unlock(&rli->log_space_lock);
rli->trans_retries= 0; // start from "no error" rli->trans_retries= 0; // start from "no error"
DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries)); DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries));
@@ -5235,14 +5233,8 @@ static Log_event* next_event(Relay_log_info* rli)
rli->ignore_log_space_limit= true; rli->ignore_log_space_limit= true;
} }
/*
If the I/O thread is blocked, unblock it. Ok to broadcast
after unlock, because the mutex is only destroyed in
~Relay_log_info(), i.e. when rli is destroyed, and rli will
not be destroyed before we exit the present function.
*/
mysql_mutex_unlock(&rli->log_space_lock);
mysql_cond_broadcast(&rli->log_space_cond); mysql_cond_broadcast(&rli->log_space_cond);
mysql_mutex_unlock(&rli->log_space_lock);
// Note that wait_for_update_relay_log unlocks lock_log ! // Note that wait_for_update_relay_log unlocks lock_log !
rli->relay_log.wait_for_update_relay_log(rli->sql_thd); rli->relay_log.wait_for_update_relay_log(rli->sql_thd);
// re-acquire data lock since we released it earlier // re-acquire data lock since we released it earlier

View File

@@ -4067,10 +4067,11 @@ request_backoff_action(enum_open_table_action action_arg,
* We met a broken table that needs repair, or a table that * We met a broken table that needs repair, or a table that
is not present on this MySQL server and needs re-discovery. is not present on this MySQL server and needs re-discovery.
To perform the action, we need an exclusive metadata lock on To perform the action, we need an exclusive metadata lock on
the table. Acquiring an X lock while holding other shared the table. Acquiring X lock while holding other shared
locks is very deadlock-prone. If this is a multi- statement locks can easily lead to deadlocks. We rely on MDL deadlock
transaction that holds metadata locks for completed detector to discover them. If this is a multi-statement
statements, we don't do it, and report an error instead. transaction that holds metadata locks for completed statements,
we should keep these locks after discovery/repair.
The action type in this case is OT_DISCOVER or OT_REPAIR. The action type in this case is OT_DISCOVER or OT_REPAIR.
* Our attempt to acquire an MDL lock lead to a deadlock, * Our attempt to acquire an MDL lock lead to a deadlock,
detected by the MDL deadlock detector. The current detected by the MDL deadlock detector. The current
@@ -4111,7 +4112,7 @@ request_backoff_action(enum_open_table_action action_arg,
keep tables open between statements and a livelock keep tables open between statements and a livelock
is not possible. is not possible.
*/ */
if (action_arg != OT_REOPEN_TABLES && m_has_locks) if (action_arg == OT_BACKOFF_AND_RETRY && m_has_locks)
{ {
my_error(ER_LOCK_DEADLOCK, MYF(0)); my_error(ER_LOCK_DEADLOCK, MYF(0));
m_thd->mark_transaction_to_rollback(true); m_thd->mark_transaction_to_rollback(true);
@@ -4138,6 +4139,32 @@ request_backoff_action(enum_open_table_action action_arg,
} }
/**
An error handler to mark transaction to rollback on DEADLOCK error
during DISCOVER / REPAIR.
*/
class MDL_deadlock_discovery_repair_handler : public Internal_error_handler
{
public:
virtual bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg,
MYSQL_ERROR ** cond_hdl)
{
if (sql_errno == ER_LOCK_DEADLOCK)
{
thd->mark_transaction_to_rollback(true);
}
/*
We have marked this transaction to rollback. Return false to allow
error to be reported or handled by other handlers.
*/
return false;
}
};
/** /**
Recover from failed attempt of open table by performing requested action. Recover from failed attempt of open table by performing requested action.
@@ -4153,6 +4180,12 @@ Open_table_context::
recover_from_failed_open() recover_from_failed_open()
{ {
bool result= FALSE; bool result= FALSE;
MDL_deadlock_discovery_repair_handler handler;
/*
Install error handler to mark transaction to rollback on DEADLOCK error.
*/
m_thd->push_internal_handler(&handler);
/* Execute the action. */ /* Execute the action. */
switch (m_action) switch (m_action)
{ {
@@ -4174,7 +4207,12 @@ recover_from_failed_open()
m_thd->warning_info->clear_warning_info(m_thd->query_id); m_thd->warning_info->clear_warning_info(m_thd->query_id);
m_thd->clear_error(); // Clear error message m_thd->clear_error(); // Clear error message
m_thd->mdl_context.release_transactional_locks(); /*
Rollback to start of the current statement to release exclusive lock
on table which was discovered but preserve locks from previous statements
in current transaction.
*/
m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp());
break; break;
} }
case OT_REPAIR: case OT_REPAIR:
@@ -4188,12 +4226,18 @@ recover_from_failed_open()
m_failed_table->table_name, FALSE); m_failed_table->table_name, FALSE);
result= auto_repair_table(m_thd, m_failed_table); result= auto_repair_table(m_thd, m_failed_table);
m_thd->mdl_context.release_transactional_locks(); /*
Rollback to start of the current statement to release exclusive lock
on table which was discovered but preserve locks from previous statements
in current transaction.
*/
m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp());
break; break;
} }
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
m_thd->pop_internal_handler();
/* /*
Reset the pointers to conflicting MDL request and the Reset the pointers to conflicting MDL request and the
TABLE_LIST element, set when we need auto-discovery or repair, TABLE_LIST element, set when we need auto-discovery or repair,
@@ -6879,6 +6923,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
if (item->cached_table) if (item->cached_table)
{ {
DBUG_PRINT("info", ("using cached table"));
/* /*
This shortcut is used by prepared statements. We assume that This shortcut is used by prepared statements. We assume that
TABLE_LIST *first_table is not changed during query execution (which TABLE_LIST *first_table is not changed during query execution (which

View File

@@ -1058,6 +1058,7 @@ THD::THD()
file_id = 0; file_id = 0;
query_id= 0; query_id= 0;
query_name_consts= 0; query_name_consts= 0;
semisync_info= 0;
db_charset= global_system_variables.collation_database; db_charset= global_system_variables.collation_database;
bzero(ha_data, sizeof(ha_data)); bzero(ha_data, sizeof(ha_data));
mysys_var=0; mysys_var=0;
@@ -1467,6 +1468,8 @@ void THD::init(void)
bzero((char *) &status_var, sizeof(status_var)); bzero((char *) &status_var, sizeof(status_var));
bzero((char *) &org_status_var, sizeof(org_status_var)); bzero((char *) &org_status_var, sizeof(org_status_var));
start_bytes_received= 0; start_bytes_received= 0;
status_in_global= 0;
#ifdef WITH_WSREP #ifdef WITH_WSREP
wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE; wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE;
wsrep_conflict_state= NO_CONFLICT; wsrep_conflict_state= NO_CONFLICT;
@@ -1491,8 +1494,8 @@ void THD::init(void)
*/ */
if (variables.wsrep_causal_reads) if (variables.wsrep_causal_reads)
variables.wsrep_sync_wait|= WSREP_SYNC_WAIT_BEFORE_READ; variables.wsrep_sync_wait|= WSREP_SYNC_WAIT_BEFORE_READ;
#endif /* WITH_WSREP */
#endif
if (variables.sql_log_bin) if (variables.sql_log_bin)
variables.option_bits|= OPTION_BIN_LOG; variables.option_bits|= OPTION_BIN_LOG;
else else
@@ -1595,6 +1598,7 @@ void THD::change_user(void)
cleanup(); cleanup();
reset_killed(); reset_killed();
cleanup_done= 0; cleanup_done= 0;
status_in_global= 0;
init(); init();
stmt_map.reset(); stmt_map.reset();
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
@@ -1727,6 +1731,7 @@ THD::~THD()
mysql_audit_free_thd(this); mysql_audit_free_thd(this);
if (rli_slave) if (rli_slave)
rli_slave->cleanup_after_session(); rli_slave->cleanup_after_session();
my_free(semisync_info);
#endif #endif
free_root(&main_mem_root, MYF(0)); free_root(&main_mem_root, MYF(0));

View File

@@ -59,7 +59,6 @@ struct wsrep_thd_shadow {
#endif #endif
class Reprepare_observer; class Reprepare_observer;
class Relay_log_info; class Relay_log_info;
class Query_log_event; class Query_log_event;
class Load_log_event; class Load_log_event;
class Slave_log_event; class Slave_log_event;
@@ -71,6 +70,7 @@ class Rows_log_event;
class Sroutine_hash_entry; class Sroutine_hash_entry;
class User_level_lock; class User_level_lock;
class user_var_entry; class user_var_entry;
struct Trans_binlog_info;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
@@ -1689,6 +1689,9 @@ public:
*/ */
const char *where; const char *where;
/* Needed by MariaDB semi sync replication */
Trans_binlog_info *semisync_info;
ulong client_capabilities; /* What the client supports */ ulong client_capabilities; /* What the client supports */
ulong max_client_packet_length; ulong max_client_packet_length;
@@ -1752,11 +1755,11 @@ public:
/* Do not set socket timeouts for wait_timeout (used with threadpool) */ /* Do not set socket timeouts for wait_timeout (used with threadpool) */
bool skip_wait_timeout; bool skip_wait_timeout;
/* container for handler's private per-connection data */
Ha_data ha_data[MAX_HA];
bool prepare_derived_at_open; bool prepare_derived_at_open;
/* Set to 1 if status of this THD is already in global status */
bool status_in_global;
/* /*
To signal that the tmp table to be created is created for materialized To signal that the tmp table to be created is created for materialized
derived table or a view. derived table or a view.
@@ -1765,6 +1768,9 @@ public:
bool save_prep_leaf_list; bool save_prep_leaf_list;
/* container for handler's private per-connection data */
Ha_data ha_data[MAX_HA];
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
binlog_cache_mngr * binlog_setup_trx_data(); binlog_cache_mngr * binlog_setup_trx_data();
@@ -3175,6 +3181,8 @@ public:
{ {
mysql_mutex_lock(&LOCK_status); mysql_mutex_lock(&LOCK_status);
add_to_status(&global_status_var, &status_var); add_to_status(&global_status_var, &status_var);
/* Mark that this THD status has already been added in global status */
status_in_global= 1;
mysql_mutex_unlock(&LOCK_status); mysql_mutex_unlock(&LOCK_status);
} }

View File

@@ -1928,7 +1928,6 @@ void st_select_lex::init_select()
with_sum_func= 0; with_sum_func= 0;
is_correlated= 0; is_correlated= 0;
cur_pos_in_select_list= UNDEF_POS; cur_pos_in_select_list= UNDEF_POS;
non_agg_fields.empty();
cond_value= having_value= Item::COND_UNDEF; cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty(); inner_refs_list.empty();
insert_tables= 0; insert_tables= 0;
@@ -1936,6 +1935,7 @@ void st_select_lex::init_select()
m_non_agg_field_used= false; m_non_agg_field_used= false;
m_agg_func_used= false; m_agg_func_used= false;
name_visibility_map= 0; name_visibility_map= 0;
join= 0;
} }
/* /*

View File

@@ -877,8 +877,6 @@ public:
bool no_wrap_view_item; bool no_wrap_view_item;
/* exclude this select from check of unique_table() */ /* exclude this select from check of unique_table() */
bool exclude_from_table_unique_test; bool exclude_from_table_unique_test;
/* List of fields that aren't under an aggregate function */
List<Item_field> non_agg_fields;
/* index in the select list of the expression currently being fixed */ /* index in the select list of the expression currently being fixed */
int cur_pos_in_select_list; int cur_pos_in_select_list;

View File

@@ -6175,6 +6175,8 @@ void THD::reset_for_next_command()
thd->reset_current_stmt_binlog_format_row(); thd->reset_current_stmt_binlog_format_row();
thd->binlog_unsafe_warning_flags= 0; thd->binlog_unsafe_warning_flags= 0;
thd->save_prep_leaf_list= false;
DBUG_PRINT("debug", DBUG_PRINT("debug",
("is_current_stmt_binlog_format_row(): %d", ("is_current_stmt_binlog_format_row(): %d",
thd->is_current_stmt_binlog_format_row())); thd->is_current_stmt_binlog_format_row()));

View File

@@ -4904,6 +4904,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
KEY_FIELD *key_fields, *end, *field; KEY_FIELD *key_fields, *end, *field;
uint sz; uint sz;
uint m= max(select_lex->max_equal_elems,1); uint m= max(select_lex->max_equal_elems,1);
DBUG_ENTER("update_ref_and_keys");
DBUG_PRINT("enter", ("normal_tables: %llx", normal_tables));
SELECT_LEX *sel=thd->lex->current_select; SELECT_LEX *sel=thd->lex->current_select;
sel->cond_count= 0; sel->cond_count= 0;
@@ -4950,7 +4952,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))* sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
((sel->cond_count*2 + sel->between_count)*m+1); ((sel->cond_count*2 + sel->between_count)*m+1);
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz))) if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
return TRUE; /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
and_level= 0; and_level= 0;
field= end= key_fields; field= end= key_fields;
*sargables= (SARGABLE_PARAM *) key_fields + *sargables= (SARGABLE_PARAM *) key_fields +
@@ -4959,7 +4961,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
(*sargables)[0].field= 0; (*sargables)[0].field= 0;
if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64)) if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
return TRUE; DBUG_RETURN(TRUE);
if (cond) if (cond)
{ {
@@ -5009,16 +5011,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
for ( ; field != end ; field++) for ( ; field != end ; field++)
{ {
if (add_key_part(keyuse,field)) if (add_key_part(keyuse,field))
return TRUE; DBUG_RETURN(TRUE);
} }
if (select_lex->ftfunc_list->elements) if (select_lex->ftfunc_list->elements)
{ {
if (add_ft_keys(keyuse,join_tab,cond,normal_tables)) if (add_ft_keys(keyuse,join_tab,cond,normal_tables))
return TRUE; DBUG_RETURN(TRUE);
} }
return FALSE; DBUG_RETURN(FALSE);
} }
@@ -20705,7 +20707,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item_field *field; Item_field *field;
int cur_pos_in_select_list= 0; int cur_pos_in_select_list= 0;
List_iterator<Item> li(fields); List_iterator<Item> li(fields);
List_iterator<Item_field> naf_it(thd->lex->current_select->non_agg_fields); List_iterator<Item_field> naf_it(thd->lex->current_select->join->non_agg_fields);
field= naf_it++; field= naf_it++;
while (field && (item=li++)) while (field && (item=li++))

View File

@@ -922,6 +922,9 @@ public:
Item *pre_sort_idx_pushed_cond; Item *pre_sort_idx_pushed_cond;
void clean_pre_sort_join_tab(); void clean_pre_sort_join_tab();
/* List of fields that aren't under an aggregate function */
List<Item_field> non_agg_fields;
/* /*
For "Using temporary+Using filesort" queries, JOIN::join_tab can point to For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
either: either:
@@ -1301,6 +1304,7 @@ public:
all_fields= fields_arg; all_fields= fields_arg;
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */ if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
fields_list= fields_arg; fields_list= fields_arg;
non_agg_fields.empty();
bzero((char*) &keyuse,sizeof(keyuse)); bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.init(); tmp_table_param.init();
tmp_table_param.end_write_records= HA_POS_ERROR; tmp_table_param.end_write_records= HA_POS_ERROR;

View File

@@ -3126,7 +3126,10 @@ void calc_sum_of_all_status(STATUS_VAR *to)
/* Add to this status from existing threads */ /* Add to this status from existing threads */
while ((tmp= it++)) while ((tmp= it++))
{
if (!tmp->status_in_global)
add_to_status(to, &tmp->status_var); add_to_status(to, &tmp->status_var);
}
mysql_mutex_unlock(&LOCK_thread_count); mysql_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;

View File

@@ -248,7 +248,7 @@ TEST_join(JOIN *join)
#define FT_KEYPART (MAX_REF_PARTS+10) #define FT_KEYPART (MAX_REF_PARTS+10)
void print_keyuse(KEYUSE *keyuse) static void print_keyuse(KEYUSE *keyuse)
{ {
char buff[256]; char buff[256];
char buf2[64]; char buf2[64];
@@ -266,14 +266,11 @@ void print_keyuse(KEYUSE *keyuse)
else else
fieldname= key_info->key_part[keyuse->keypart].field->field_name; fieldname= key_info->key_part[keyuse->keypart].field->field_name;
ll2str(keyuse->used_tables, buf2, 16, 0); ll2str(keyuse->used_tables, buf2, 16, 0);
DBUG_LOCK_FILE;
fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s " fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s "
"ref_table_rows: %lu keypart_map: %0lx\n", "ref_table_rows: %lu keypart_map: %0lx\n",
keyuse->table->alias.c_ptr(), fieldname, str.ptr(), keyuse->table->alias.c_ptr(), fieldname, str.ptr(),
(uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows, (uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows,
(ulong) keyuse->keypart_map); (ulong) keyuse->keypart_map);
DBUG_UNLOCK_FILE;
//key_part_map keypart_map; --?? there can be several?
} }
@@ -282,9 +279,9 @@ void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array)
{ {
DBUG_LOCK_FILE; DBUG_LOCK_FILE;
fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements); fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements);
DBUG_UNLOCK_FILE;
for(uint i=0; i < keyuse_array->elements; i++) for(uint i=0; i < keyuse_array->elements; i++)
print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i)); print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i));
DBUG_UNLOCK_FILE;
} }

View File

@@ -1021,7 +1021,6 @@ bool st_select_lex::cleanup()
{ {
error= (bool) ((uint) error | (uint) lex_unit->cleanup()); error= (bool) ((uint) error | (uint) lex_unit->cleanup());
} }
non_agg_fields.empty();
inner_refs_list.empty(); inner_refs_list.empty();
exclude_from_table_unique_test= FALSE; exclude_from_table_unique_test= FALSE;
DBUG_RETURN(error); DBUG_RETURN(error);
@@ -1032,6 +1031,7 @@ void st_select_lex::cleanup_all_joins(bool full)
{ {
SELECT_LEX_UNIT *unit; SELECT_LEX_UNIT *unit;
SELECT_LEX *sl; SELECT_LEX *sl;
DBUG_ENTER("st_select_lex::cleanup_all_joins");
if (join) if (join)
join->cleanup(full); join->cleanup(full);
@@ -1039,6 +1039,7 @@ void st_select_lex::cleanup_all_joins(bool full)
for (unit= first_inner_unit(); unit; unit= unit->next_unit()) for (unit= first_inner_unit(); unit; unit= unit->next_unit())
for (sl= unit->first_select(); sl; sl= sl->next_select()) for (sl= unit->first_select(); sl; sl= sl->next_select())
sl->cleanup_all_joins(full); sl->cleanup_all_joins(full);
DBUG_VOID_RETURN;
} }

View File

@@ -5203,7 +5203,7 @@ Item *Field_iterator_table::create_item(THD *thd)
if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
!thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS) !thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS)
{ {
select->non_agg_fields.push_back(item); select->join->non_agg_fields.push_back(item);
item->marker= select->cur_pos_in_select_list; item->marker= select->cur_pos_in_select_list;
select->set_non_agg_field_used(true); select->set_non_agg_field_used(true);
} }

View File

@@ -1419,6 +1419,104 @@ dict_create_add_foreign_field_to_dictionary(
table, foreign, trx)); table, foreign, trx));
} }
/********************************************************************//**
Construct foreign key constraint defintion from data dictionary information.
*/
UNIV_INTERN
char*
dict_foreign_def_get(
/*=================*/
dict_foreign_t* foreign,/*!< in: foreign */
trx_t* trx) /*!< in: trx */
{
char* fk_def = mem_heap_alloc(foreign->heap, 4*1024);
const char* tbname;
char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
int i;
char* bufend;
tbname = dict_remove_db_name(foreign->id);
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
tbname, strlen(tbname), trx->mysql_thd, FALSE);
tablebuf[bufend - tablebuf] = '\0';
sprintf(fk_def,
(char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
for(i = 0; i < foreign->n_fields; i++) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->foreign_col_names[i],
strlen(foreign->foreign_col_names[i]),
trx->mysql_thd, FALSE);
strcat(fk_def, buf);
if (i < foreign->n_fields-1) {
strcat(fk_def, (char *)",");
}
}
strcat(fk_def,(char *)") REFERENCES ");
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
foreign->referenced_table_name,
strlen(foreign->referenced_table_name),
trx->mysql_thd, TRUE);
tablebuf[bufend - tablebuf] = '\0';
strcat(fk_def, tablebuf);
strcat(fk_def, " (");
for(i = 0; i < foreign->n_fields; i++) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->referenced_col_names[i],
strlen(foreign->referenced_col_names[i]),
trx->mysql_thd, FALSE);
buf[bufend - buf] = '\0';
strcat(fk_def, buf);
if (i < foreign->n_fields-1) {
strcat(fk_def, (char *)",");
}
}
strcat(fk_def, (char *)")");
return fk_def;
}
/********************************************************************//**
Convert foreign key column names from data dictionary to SQL-layer.
*/
static
void
dict_foreign_def_get_fields(
/*========================*/
dict_foreign_t* foreign,/*!< in: foreign */
trx_t* trx, /*!< in: trx */
char** field, /*!< out: foreign column */
char** field2, /*!< out: referenced column */
int col_no) /*!< in: column number */
{
char* bufend;
char* fieldbuf = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
char* fieldbuf2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
foreign->foreign_col_names[col_no],
strlen(foreign->foreign_col_names[col_no]),
trx->mysql_thd, FALSE);
fieldbuf[bufend - fieldbuf] = '\0';
bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
foreign->referenced_col_names[col_no],
strlen(foreign->referenced_col_names[col_no]),
trx->mysql_thd, FALSE);
fieldbuf2[bufend - fieldbuf2] = '\0';
*field = fieldbuf;
*field2 = fieldbuf2;
}
/********************************************************************//** /********************************************************************//**
Add a single foreign key definition to the data dictionary tables in the Add a single foreign key definition to the data dictionary tables in the
database. We also generate names to constraints that were not named by the database. We also generate names to constraints that were not named by the
@@ -1501,6 +1599,29 @@ dict_create_add_foreign_to_dictionary(
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
if (error == DB_DUPLICATE_KEY) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
char* fk_def;
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
table->name, strlen(table->name),
trx->mysql_thd, TRUE);
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
fk_def = dict_foreign_def_get(foreign, trx);
ib_push_warning(trx, error,
"Create or Alter table %s with foreign key constraint"
" failed. Foreign key constraint %s"
" already exists on data dictionary."
" Foreign key constraint names need to be unique in database."
" Error in foreign key definition: %s.",
tablename, buf, fk_def);
}
return(error); return(error);
} }
@@ -1509,6 +1630,26 @@ dict_create_add_foreign_to_dictionary(
i, table, foreign, trx); i, table, foreign, trx);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
char* field=NULL;
char* field2=NULL;
char* fk_def;
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
table->name, strlen(table->name),
trx->mysql_thd, TRUE);
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
fk_def = dict_foreign_def_get(foreign, trx);
dict_foreign_def_get_fields(foreign, trx, &field, &field2, i);
ib_push_warning(trx, error,
"Create or Alter table %s with foreign key constraint"
" failed. Error adding foreign key constraint name %s"
" fields %s or %s to the dictionary."
" Error in foreign key definition: %s.",
tablename, buf, i+1, fk_def);
return(error); return(error);
} }

View File

@@ -2534,8 +2534,9 @@ dict_foreign_remove_from_cache(
const ib_rbt_node_t* node const ib_rbt_node_t* node
= rbt_lookup(rbt, foreign->id); = rbt_lookup(rbt, foreign->id);
if (node) { if (node != NULL) {
dict_foreign_t* val = *(dict_foreign_t**) node->value; dict_foreign_t* val
= *(dict_foreign_t**) node->value;
if (val == foreign) { if (val == foreign) {
rbt_delete(rbt, foreign->id); rbt_delete(rbt, foreign->id);
@@ -2555,9 +2556,10 @@ dict_foreign_remove_from_cache(
if (rbt != NULL && foreign->id != NULL) { if (rbt != NULL && foreign->id != NULL) {
const ib_rbt_node_t* node const ib_rbt_node_t* node
= rbt_lookup(rbt, foreign->id); = rbt_lookup(rbt, foreign->id);
if (node) {
dict_foreign_t* val = *(dict_foreign_t**) node->value; if (node != NULL) {
dict_foreign_t* val
= *(dict_foreign_t**) node->value;
if (val == foreign) { if (val == foreign) {
rbt_delete(rbt, foreign->id); rbt_delete(rbt, foreign->id);
@@ -2614,6 +2616,11 @@ dict_foreign_find(
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
} }
#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
#define DB_FOREIGN_KEY_COL_NOT_NULL 201
#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
/*********************************************************************//** /*********************************************************************//**
Tries to find an index whose first fields are the columns in the array, Tries to find an index whose first fields are the columns in the array,
in the same order and is not marked for deletion and is not the same in the same order and is not marked for deletion and is not the same
@@ -2631,12 +2638,21 @@ dict_foreign_find_index(
ibool check_charsets, ibool check_charsets,
/*!< in: whether to check charsets. /*!< in: whether to check charsets.
only has an effect if types_idx != NULL */ only has an effect if types_idx != NULL */
ulint check_null) ulint check_null,
/*!< in: nonzero if none of the columns must /*!< in: nonzero if none of the columns must
be declared NOT NULL */ be declared NOT NULL */
ulint* error, /*!< out: error code */
ulint* err_col_no,
/*!< out: column number where error happened */
dict_index_t** err_index)
/*!< out: index where error happened */
{ {
dict_index_t* index; dict_index_t* index;
if (error) {
*error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
}
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
while (index != NULL) { while (index != NULL) {
@@ -2662,6 +2678,12 @@ dict_foreign_find_index(
/* We do not accept column prefix /* We do not accept column prefix
indexes here */ indexes here */
if (error && err_col_no && err_index) {
*error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
*err_col_no = i;
*err_index = index;
}
break; break;
} }
@@ -2673,6 +2695,11 @@ dict_foreign_find_index(
if (check_null if (check_null
&& (field->col->prtype & DATA_NOT_NULL)) { && (field->col->prtype & DATA_NOT_NULL)) {
if (error && err_col_no && err_index) {
*error = DB_FOREIGN_KEY_COL_NOT_NULL;
*err_col_no = i;
*err_index = index;
}
return(NULL); return(NULL);
} }
@@ -2682,6 +2709,12 @@ dict_foreign_find_index(
i), i),
check_charsets)) { check_charsets)) {
if (error && err_col_no && err_index) {
*error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
*err_col_no = i;
*err_index = index;
}
break; break;
} }
} }
@@ -2689,6 +2722,10 @@ dict_foreign_find_index(
if (i == n_cols) { if (i == n_cols) {
/* We found a matching index */ /* We found a matching index */
if (error) {
*error = DB_SUCCESS;
}
return(index); return(index);
} }
} }
@@ -2715,8 +2752,9 @@ wsrep_dict_foreign_find_index(
/*!< in: nonzero if none of the columns must /*!< in: nonzero if none of the columns must
be declared NOT NULL */ be declared NOT NULL */
{ {
return dict_foreign_find_index( return dict_foreign_find_index(table, columns, n_cols, types_idx,
table, columns, n_cols, types_idx, check_charsets, check_null); check_charsets, check_null,
NULL, NULL, NULL);
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/**********************************************************************//** /**********************************************************************//**
@@ -2739,7 +2777,7 @@ dict_foreign_find_equiv_index(
foreign->foreign_table, foreign->foreign_table,
foreign->foreign_col_names, foreign->n_fields, foreign->foreign_col_names, foreign->n_fields,
foreign->foreign_index, TRUE, /* check types */ foreign->foreign_index, TRUE, /* check types */
FALSE/* allow columns to be NULL */)); FALSE/* allow columns to be NULL */, NULL, NULL, NULL));
} }
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
@@ -2902,11 +2940,15 @@ dict_foreign_add_to_cache(
} }
if (for_in_cache->referenced_table == NULL && ref_table) { if (for_in_cache->referenced_table == NULL && ref_table) {
ulint index_error;
ulint err_col;
dict_index_t *err_index=NULL;
index = dict_foreign_find_index( index = dict_foreign_find_index(
ref_table, ref_table,
for_in_cache->referenced_col_names, for_in_cache->referenced_col_names,
for_in_cache->n_fields, for_in_cache->foreign_index, for_in_cache->n_fields, for_in_cache->foreign_index,
check_charsets, FALSE); check_charsets, FALSE, &index_error, &err_col, &err_index);
if (index == NULL if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -2938,6 +2980,9 @@ dict_foreign_add_to_cache(
} }
if (for_in_cache->foreign_table == NULL && for_table) { if (for_in_cache->foreign_table == NULL && for_table) {
ulint index_error;
ulint err_col;
dict_index_t* err_index=NULL;
index = dict_foreign_find_index( index = dict_foreign_find_index(
for_table, for_table,
@@ -2946,7 +2991,8 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_index, check_charsets, for_in_cache->referenced_index, check_charsets,
for_in_cache->type for_in_cache->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL & (DICT_FOREIGN_ON_DELETE_SET_NULL
| DICT_FOREIGN_ON_UPDATE_SET_NULL)); | DICT_FOREIGN_ON_UPDATE_SET_NULL),
&index_error, &err_col, &err_index);
if (index == NULL if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3557,6 +3603,8 @@ static
void void
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
/*===========================*/ /*===========================*/
const char* fmt, /*!< in: syntax err msg */
const char* oper, /*!< in: operation */
const char* name, /*!< in: table name */ const char* name, /*!< in: table name */
const char* start_of_latest_foreign, const char* start_of_latest_foreign,
/*!< in: start of the foreign key clause /*!< in: start of the foreign key clause
@@ -3567,11 +3615,101 @@ dict_foreign_report_syntax_err(
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, name);
fprintf(ef, "%s:\nSyntax error close to:\n%s\n", fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr);
start_of_latest_foreign, ptr);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
} }
/*********************************************************************//**
Push warning message to SQL-layer based on foreign key constraint
index match error. */
static
void
dict_foreign_push_index_error(
/*==========================*/
trx_t* trx, /*!< in: trx */
const char* operation, /*!< in: operation create or alter
*/
const char* create_name, /*!< in: table name in create or
alter table */
const char* latest_foreign, /*!< in: start of latest foreign key
constraint name */
const char** columns, /*!< in: foreign key columns */
ulint index_error, /*!< in: error code */
ulint err_col, /*!< in: column where error happened
*/
dict_index_t* err_index, /*!< in: index where error happened
*/
dict_table_t* table, /*!< in: table */
FILE* ef) /*!< in: output stream */
{
switch (index_error) {
case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
fprintf(ef,
"%s table '%s' with foreign key constraint"
" failed. There is no index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.\n",
operation, create_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table '%s' with foreign key constraint"
" failed. There is no index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.",
operation, create_name, latest_foreign);
break;
}
case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
fprintf(ef,
"%s table '%s' with foreign key constraint"
" failed. There is only prefix index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.\n",
operation, create_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table '%s' with foreign key constraint"
" failed. There is only prefix index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.",
operation, create_name, latest_foreign);
break;
}
case DB_FOREIGN_KEY_COL_NOT_NULL: {
fprintf(ef,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but "
"field %s on index is defined as NOT NULL close to %s\n",
operation, create_name, columns[err_col], latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but "
"field %s on index is defined as NOT NULL close to %s",
operation, create_name, columns[err_col], latest_foreign);
break;
}
case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
dict_field_t* field;
const char* col_name;
field = dict_index_get_nth_field(err_index, err_col);
col_name = dict_table_get_col_name(
table, dict_col_get_no(field->col));
fprintf(ef,
"%s table %s with foreign key constraint"
" failed. Field type or character set for column %s "
"does not mach referenced column %s close to %s\n",
operation, create_name, columns[err_col], col_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Field type or character set for column %s "
"does not mach referenced column %s close to %s",
operation, create_name, columns[err_col], col_name, latest_foreign);
break;
}
default:
ut_error;
}
}
/*********************************************************************//** /*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary the foreign Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after key constraints declared in the string. This function should be called after
@@ -3600,15 +3738,20 @@ dict_create_foreign_constraints_low(
DB_CANNOT_ADD_CONSTRAINT if any foreign DB_CANNOT_ADD_CONSTRAINT if any foreign
keys are found. */ keys are found. */
{ {
dict_table_t* table; dict_table_t* table = NULL;
dict_table_t* referenced_table; dict_table_t* referenced_table = NULL;
dict_table_t* table_to_alter; dict_table_t* table_to_alter = NULL;
dict_table_t* table_to_create = NULL;
ulint highest_id_so_far = 0; ulint highest_id_so_far = 0;
dict_index_t* index; dict_index_t* index = NULL;
dict_foreign_t* foreign; dict_foreign_t* foreign = NULL;
const char* ptr = sql_string; const char* ptr = sql_string;
const char* start_of_latest_foreign = sql_string; const char* start_of_latest_foreign = sql_string;
const char* start_of_latest_set = NULL;
FILE* ef = dict_foreign_err_file; FILE* ef = dict_foreign_err_file;
ulint index_error = DB_SUCCESS;
dict_index_t* err_index = NULL;
ulint err_col;
const char* constraint_name; const char* constraint_name;
ibool success; ibool success;
ulint error; ulint error;
@@ -3621,29 +3764,68 @@ dict_create_foreign_constraints_low(
ulint n_on_updates; ulint n_on_updates;
const dict_col_t*columns[500]; const dict_col_t*columns[500];
const char* column_names[500]; const char* column_names[500];
const char* ref_column_names[500];
const char* referenced_table_name; const char* referenced_table_name;
const char* create_table_name;
const char* orig;
char create_name[MAX_TABLE_NAME_LEN + 1];
const char operation[8];
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE); table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE);
/* First check if we are actually doing an ALTER TABLE, and in that
case look for the table being altered */
ptr = dict_accept(cs, ptr, "ALTER", &success);
strcpy((char *)operation, success ? "Alter " : "Create ");
if (!success) {
orig = ptr;
ptr = dict_scan_to(ptr, "CREATE");
ptr = dict_scan_to(ptr, "TABLE");
ptr = dict_accept(cs, ptr, "TABLE", &success);
if (success) {
ptr = dict_scan_table_name(cs, ptr, &table_to_create, name,
&success, heap, &create_table_name);
}
if (success) {
char *bufend;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
create_table_name, strlen(create_table_name),
trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
ptr = orig;
} else {
char *bufend;
ptr = orig;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
name, strlen(name), trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
}
goto loop;
}
if (table == NULL) { if (table == NULL) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, fprintf(ef, "%s table %s with foreign key constraint"
"Cannot find the table in the internal" " failed. Table %s not found from data dictionary."
" data dictionary of InnoDB.\n" " Error close to %s.\n",
"Create table statement:\n%s\n", sql_string); operation, create_name, create_name, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_ERROR,
"%s table %s with foreign key constraint"
" failed. Table %s not found from data dictionary."
" Error close to %s.",
operation, create_name, create_name, start_of_latest_foreign);
return(DB_ERROR); return(DB_ERROR);
} }
/* First check if we are actually doing an ALTER TABLE, and in that /* If not alter table jump to loop */
case look for the table being altered */
ptr = dict_accept(cs, ptr, "ALTER", &success);
if (!success) { if (!success) {
goto loop; goto loop;
@@ -3658,13 +3840,40 @@ dict_create_foreign_constraints_low(
/* We are doing an ALTER TABLE: scan the table name we are altering */ /* We are doing an ALTER TABLE: scan the table name we are altering */
orig = ptr;
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name, ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
&success, heap, &referenced_table_name); &success, heap, &referenced_table_name);
if (table_to_alter) {
char *bufend;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
table_to_alter->name, strlen(table_to_alter->name),
trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
} else {
char *bufend;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
referenced_table_name, strlen(referenced_table_name),
trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
}
if (!success) { if (!success) {
fprintf(stderr, mutex_enter(&dict_foreign_err_mutex);
"InnoDB: Error: could not find" dict_foreign_error_report_low(ef, create_name);
" the table being ALTERED in:\n%s\n", fprintf(ef,
sql_string); "%s table %s with foreign key constraint"
" failed. Table %s not found from data dictionary."
" Error close to %s.\n",
operation, create_name, create_name, orig);
mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_ERROR,
"%s table %s with foreign key constraint"
" failed. Table %s not found from data dictionary."
" Error close to %s.",
operation, create_name, create_name, orig);
return(DB_ERROR); return(DB_ERROR);
} }
@@ -3730,7 +3939,19 @@ loop:
if so, immediately reject the command if the table is a if so, immediately reject the command if the table is a
temporary one. For now, this kludge will work. */ temporary one. For now, this kludge will work. */
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) { if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s table %s with foreign key constraint"
" failed. Temporary tables can't have foreign key constraints."
" Error close to %s.\n",
operation, create_name, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Temporary tables can't have foreign key constraints."
" Error close to %s.",
operation, create_name, start_of_latest_foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3766,11 +3987,21 @@ loop:
if (!success) { if (!success) {
/* MySQL allows also an index id before the '('; we /* MySQL allows also an index id before the '('; we
skip it */ skip it */
orig = ptr;
ptr = dict_skip_word(cs, ptr, &success); ptr = dict_skip_word(cs, ptr, &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3790,15 +4021,26 @@ loop:
/* Scan the columns in the first list */ /* Scan the columns in the first list */
col_loop1: col_loop1:
ut_a(i < (sizeof column_names) / sizeof *column_names); ut_a(i < (sizeof column_names) / sizeof *column_names);
orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, table, columns + i, ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
heap, column_names + i); heap, column_names + i);
if (!success) { if (!success) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", fprintf(ef,
start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3810,11 +4052,22 @@ col_loop1:
goto col_loop1; goto col_loop1;
} }
orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success); ptr = dict_accept(cs, ptr, ")", &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3822,27 +4075,41 @@ col_loop1:
as the first fields and in the right order */ as the first fields and in the right order */
index = dict_foreign_find_index(table, column_names, i, index = dict_foreign_find_index(table, column_names, i,
NULL, TRUE, FALSE); NULL, TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) { if (!index) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fputs("There is no index in table ", ef); fputs("There is no index in table ", ef);
ut_print_name(ef, NULL, TRUE, name); ut_print_name(ef, NULL, TRUE, create_name);
fprintf(ef, " where the columns appear\n" fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n" "as the first columns. Constraint:\n%s\n"
"See " REFMAN "innodb-foreign-key-constraints.html\n" "See " REFMAN "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n", "for correct foreign key definition.\n",
start_of_latest_foreign); start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CHILD_NO_INDEX); dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
column_names, index_error, err_col, err_index, table, ef);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT);
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "REFERENCES", &success); ptr = dict_accept(cs, ptr, "REFERENCES", &success);
if (!success || !my_isspace(cs, *ptr)) { if (!success || !my_isspace(cs, *ptr)) {
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3891,24 +4158,50 @@ col_loop1:
checking of foreign key constraints! */ checking of foreign key constraints! */
if (!success || (!referenced_table && trx->check_foreigns)) { if (!success || (!referenced_table && trx->check_foreigns)) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char* bufend;
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
referenced_table_name, strlen(referenced_table_name),
trx->mysql_thd, TRUE);
buf[bufend - buf] = '\0';
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
"close to %s.",
operation, create_name, buf, start_of_latest_foreign);
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\nCannot resolve table name close to:\n" fprintf(ef,
"%s\n", "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
start_of_latest_foreign, ptr); "close to %s.\n",
operation, create_name, buf, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success); ptr = dict_accept(cs, ptr, "(", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3916,20 +4209,29 @@ col_loop1:
i = 0; i = 0;
col_loop2: col_loop2:
orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
heap, column_names + i); heap, ref_column_names + i);
i++; i++;
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\nCannot resolve column name close to:\n" fprintf(ef,
"%s\n", "%s table %s with foreign key constraint"
start_of_latest_foreign, ptr); " failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3939,13 +4241,23 @@ col_loop2:
goto col_loop2; goto col_loop2;
} }
orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success); ptr = dict_accept(cs, ptr, ")", &success);
if (!success || foreign->n_fields != i) { if (!success || foreign->n_fields != i) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s. Too few referenced columns.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s. Too few referenced columns, you have %d when you should have %d.",
operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3955,6 +4267,7 @@ col_loop2:
scan_on_conditions: scan_on_conditions:
/* Loop here as long as we can find ON ... conditions */ /* Loop here as long as we can find ON ... conditions */
start_of_latest_set = ptr;
ptr = dict_accept(cs, ptr, "ON", &success); ptr = dict_accept(cs, ptr, "ON", &success);
if (!success) { if (!success) {
@@ -3965,13 +4278,24 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "DELETE", &success); ptr = dict_accept(cs, ptr, "DELETE", &success);
if (!success) { if (!success) {
orig = ptr;
ptr = dict_accept(cs, ptr, "UPDATE", &success); ptr = dict_accept(cs, ptr, "UPDATE", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4003,12 +4327,22 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "NO", &success); ptr = dict_accept(cs, ptr, "NO", &success);
if (success) { if (success) {
orig = ptr;
ptr = dict_accept(cs, ptr, "ACTION", &success); ptr = dict_accept(cs, ptr, "ACTION", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4022,42 +4356,73 @@ scan_on_conditions:
goto scan_on_conditions; goto scan_on_conditions;
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "SET", &success); ptr = dict_accept(cs, ptr, "SET", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "NULL", &success); ptr = dict_accept(cs, ptr, "NULL", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
for (j = 0; j < foreign->n_fields; j++) { for (j = 0; j < foreign->n_fields; j++) {
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
& DATA_NOT_NULL) { & DATA_NOT_NULL) {
const dict_col_t* col
= dict_index_get_nth_col(foreign->foreign_index, j);
const char* col_name = dict_table_get_col_name(foreign->foreign_index->table,
dict_col_get_no(col));
/* It is not sensible to define SET NULL /* It is not sensible to define SET NULL
if the column is not allowed to be NULL! */ if the column is not allowed to be NULL! */
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n" fprintf(ef,
"You have defined a SET NULL condition" "%s table %s with foreign key constraint"
" though some of the\n" " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
"columns are defined as NOT NULL.\n", " in %s close to %s.\n",
start_of_latest_foreign); operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
" in %s close to %s.",
operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
} }
@@ -4074,16 +4439,22 @@ try_find_index:
if (n_on_deletes > 1 || n_on_updates > 1) { if (n_on_deletes > 1 || n_on_updates > 1) {
/* It is an error to define more than 1 action */ /* It is an error to define more than 1 action */
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n" fprintf(ef,
"You have twice an ON DELETE clause" "%s table %s with foreign key constraint"
" or twice an ON UPDATE clause.\n", " failed. You have more than one on delete or on update clause"
start_of_latest_foreign); " in %s close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. You have more than one on delete or on update clause"
" in %s close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4093,13 +4464,13 @@ try_find_index:
if (referenced_table) { if (referenced_table) {
index = dict_foreign_find_index(referenced_table, index = dict_foreign_find_index(referenced_table,
column_names, i, ref_column_names, i,
foreign->foreign_index, foreign->foreign_index,
TRUE, FALSE); TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) { if (!index) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n" fprintf(ef, "%s:\n"
"Cannot find an index in the" "Cannot find an index in the"
" referenced table where the\n" " referenced table where the\n"
@@ -4117,9 +4488,13 @@ try_find_index:
"innodb-foreign-key-constraints.html\n" "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n", "for correct foreign key definition.\n",
start_of_latest_foreign); start_of_latest_foreign);
dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
column_names, index_error, err_col, err_index, referenced_table, ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
return(DB_PARENT_NO_INDEX); return(DB_CANNOT_ADD_CONSTRAINT);
} }
} else { } else {
ut_a(trx->check_foreigns == FALSE); ut_a(trx->check_foreigns == FALSE);
@@ -4137,7 +4512,7 @@ try_find_index:
i * sizeof(void*)); i * sizeof(void*));
for (i = 0; i < foreign->n_fields; i++) { for (i = 0; i < foreign->n_fields; i++) {
foreign->referenced_col_names[i] foreign->referenced_col_names[i]
= mem_heap_strdup(foreign->heap, column_names[i]); = mem_heap_strdup(foreign->heap, ref_column_names[i]);
} }
/* We found an ok constraint definition: add to the lists */ /* We found an ok constraint definition: add to the lists */
@@ -5270,7 +5645,8 @@ dict_table_replace_index_in_foreign_list(
foreign->referenced_table, foreign->referenced_table,
foreign->referenced_col_names, foreign->referenced_col_names,
foreign->n_fields, index, foreign->n_fields, index,
/*check_charsets=*/TRUE, /*check_null=*/FALSE); /*check_charsets=*/TRUE, /*check_null=*/FALSE,
NULL, NULL, NULL);
ut_ad(new_index || !trx->check_foreigns); ut_ad(new_index || !trx->check_foreigns);
ut_ad(!new_index || new_index->table == index->table); ut_ad(!new_index || new_index->table == index->table);

View File

@@ -1654,6 +1654,7 @@ check_trx_exists(
if (trx == NULL) { if (trx == NULL) {
trx = innobase_trx_allocate(thd); trx = innobase_trx_allocate(thd);
thd_set_ha_data(thd, innodb_hton_ptr, trx);
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
mem_analyze_corruption(trx); mem_analyze_corruption(trx);
ut_error; ut_error;
@@ -13711,3 +13712,29 @@ ib_warn_row_too_big(const dict_table_t* table)
" ROW_FORMAT=COMPRESSED ": "" " ROW_FORMAT=COMPRESSED ": ""
, prefix ? DICT_MAX_FIXED_COL_LEN : 0); , prefix ? DICT_MAX_FIXED_COL_LEN : 0);
} }
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
extern "C" UNIV_INTERN
void
ib_push_warning(
trx_t* trx, /*!< in: trx */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...)
{
va_list args;
THD *thd = (THD *)trx->mysql_thd;
char *buf;
#define MAX_BUF_SIZE 4*1024
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
convert_error_code_to_mysql(error, 0, thd),
buf);
my_free(buf);
va_end(args);
}

View File

@@ -106,6 +106,17 @@ UNIV_INTERN
ulint ulint
dict_create_or_check_foreign_constraint_tables(void); dict_create_or_check_foreign_constraint_tables(void);
/*================================================*/ /*================================================*/
/********************************************************************//**
Construct foreign key constraint defintion from data dictionary information.
*/
UNIV_INTERN
char*
dict_foreign_def_get(
/*=================*/
dict_foreign_t* foreign,/*!< in: foreign */
trx_t* trx); /*!< in: trx */
/********************************************************************//** /********************************************************************//**
Adds foreign key definitions to data dictionary tables in the database. We Adds foreign key definitions to data dictionary tables in the database. We
look at table->foreign_list, and also generate names to constraints that were look at table->foreign_list, and also generate names to constraints that were

View File

@@ -339,5 +339,14 @@ innobase_convert_to_filename_charset(
const char* from, /* in: identifier to convert */ const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */ ulint len); /* in: length of 'to', in bytes */
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
trx_t* trx, /*!< in: trx */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...);
#endif #endif

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@@ -111,6 +111,17 @@ struct purge_node_struct{
purge of a row */ purge of a row */
}; };
#ifdef UNIV_DEBUG
/***********************************************************//**
Validate the persisent cursor in the purge node. The purge node has two
references to the clustered index record - one via the ref member, and the
other via the persistent cursor. These two references must match each
other if the found_clust flag is set.
@return true if the persistent cursor is consistent with the ref member.*/
ibool
row_purge_validate_pcur(purge_node_t* node);
#endif /* UNIV_DEBUG */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "row0purge.ic" #include "row0purge.ic"
#endif #endif

View File

@@ -1,6 +1,6 @@
/*********************************************************************** /***********************************************************************
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Percona Inc. Copyright (c) 2009, Percona Inc.
Portions of this file contain modifications contributed and copyrighted Portions of this file contain modifications contributed and copyrighted
@@ -1287,18 +1287,21 @@ os_file_create_simple_no_error_handling_func(
#else /* __WIN__ */ #else /* __WIN__ */
os_file_t file; os_file_t file;
int create_flag; int create_flag;
const char* mode_str = NULL;
ut_a(name); ut_a(name);
if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW) if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
WAIT_ALLOW_WRITES(); WAIT_ALLOW_WRITES();
if (create_mode == OS_FILE_OPEN) { if (create_mode == OS_FILE_OPEN) {
mode_str = "OPEN";
if (access_type == OS_FILE_READ_ONLY) { if (access_type == OS_FILE_READ_ONLY) {
create_flag = O_RDONLY; create_flag = O_RDONLY;
} else { } else {
create_flag = O_RDWR; create_flag = O_RDWR;
} }
} else if (create_mode == OS_FILE_CREATE) { } else if (create_mode == OS_FILE_CREATE) {
mode_str = "CREATE";
create_flag = O_RDWR | O_CREAT | O_EXCL; create_flag = O_RDWR | O_CREAT | O_EXCL;
} else { } else {
create_flag = 0; create_flag = 0;
@@ -1323,6 +1326,14 @@ os_file_create_simple_no_error_handling_func(
#endif #endif
} else { } else {
*success = TRUE; *success = TRUE;
/* This function is always called for data files, we should
disable OS caching (O_DIRECT) here as we do in
os_file_create_func(), so we open the same file in the same
mode, see man page of open(2). */
if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
os_file_set_nocache(file, name, mode_str);
}
} }
return(file); return(file);

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@@ -43,6 +43,7 @@ Created 3/14/1997 Heikki Tuuri
#include "row0vers.h" #include "row0vers.h"
#include "row0mysql.h" #include "row0mysql.h"
#include "log0log.h" #include "log0log.h"
#include "rem0cmp.h"
/************************************************************************* /*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there IMPORTANT NOTE: Any operation that generates redo MUST check that there
@@ -80,7 +81,7 @@ row_purge_node_create(
/***********************************************************//** /***********************************************************//**
Repositions the pcur in the purge node on the clustered index record, Repositions the pcur in the purge node on the clustered index record,
if found. if found. If the record is not found, close pcur.
@return TRUE if the record was found */ @return TRUE if the record was found */
static static
ibool ibool
@@ -90,23 +91,28 @@ row_purge_reposition_pcur(
purge_node_t* node, /*!< in: row purge node */ purge_node_t* node, /*!< in: row purge node */
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in: mtr */
{ {
ibool found; if (node->found_clust) {
ut_ad(row_purge_validate_pcur(node));
node->found_clust = btr_pcur_restore_position(
mode, &(node->pcur), mtr);
} else {
node->found_clust = row_search_on_row_ref(
&(node->pcur), mode, node->table, node->ref, mtr);
if (node->found_clust) { if (node->found_clust) {
found = btr_pcur_restore_position(mode, &(node->pcur), mtr);
return(found);
}
found = row_search_on_row_ref(&(node->pcur), mode, node->table,
node->ref, mtr);
node->found_clust = found;
if (found) {
btr_pcur_store_position(&(node->pcur), mtr); btr_pcur_store_position(&(node->pcur), mtr);
} }
}
return(found); /* Close the current cursor if we fail to position it correctly. */
if (!node->found_clust) {
btr_pcur_close(&node->pcur);
}
return(node->found_clust);
} }
/***********************************************************//** /***********************************************************//**
@@ -143,8 +149,8 @@ row_purge_remove_clust_if_poss_low(
if (!success) { if (!success) {
/* The record is already removed */ /* The record is already removed */
/* Persistent cursor is closed if reposition fails. */
btr_pcur_commit_specify_mtr(pcur, &mtr); mtr_commit(&mtr);
return(TRUE); return(TRUE);
} }
@@ -258,7 +264,12 @@ row_purge_poss_sec(
btr_pcur_get_rec(&node->pcur), btr_pcur_get_rec(&node->pcur),
&mtr, index, entry); &mtr, index, entry);
/* Persistent cursor is closed if reposition fails. */
if (node->found_clust) {
btr_pcur_commit_specify_mtr(&node->pcur, &mtr); btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
} else {
mtr_commit(&mtr);
}
return(can_delete); return(can_delete);
} }
@@ -806,3 +817,53 @@ row_purge_step(
return(thr); return(thr);
} }
#ifdef UNIV_DEBUG
/***********************************************************//**
Validate the persisent cursor in the purge node. The purge node has two
references to the clustered index record - one via the ref member, and the
other via the persistent cursor. These two references must match each
other if the found_clust flag is set.
@return true if the stored copy of persistent cursor is consistent
with the ref member.*/
ibool
row_purge_validate_pcur(
purge_node_t* node)
{
dict_index_t* clust_index;
ulint* offsets;
int st;
if (!node->found_clust) {
return(TRUE);
}
if (node->index == NULL) {
return(TRUE);
}
if (node->pcur.old_stored != BTR_PCUR_OLD_STORED) {
return(TRUE);
}
clust_index = node->pcur.btr_cur.index;
offsets = rec_get_offsets(node->pcur.old_rec, clust_index, NULL,
node->pcur.old_n_fields, &node->heap);
/* Here we are comparing the purge ref record and the stored initial
part in persistent cursor. Both cases we store n_uniq fields of the
cluster index and so it is fine to do the comparison. We note this
dependency here as pcur and ref belong to different modules. */
st = cmp_dtuple_rec(node->ref, node->pcur.old_rec, offsets);
if (st != 0) {
fprintf(stderr, "Purge node pcur validation failed\n");
dtuple_print(stderr, node->ref);
rec_print(stderr, node->pcur.old_rec, clust_index);
return(FALSE);
}
return(TRUE);
}
#endif /* UNIV_DEBUG */

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc. Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by Portions of this file contain modifications contributed and copyrighted by
@@ -1666,6 +1666,10 @@ buf_pool_watch_set(
/* buf_pool->watch is protected by zip_mutex for now */ /* buf_pool->watch is protected by zip_mutex for now */
mutex_enter(&buf_pool->zip_mutex); mutex_enter(&buf_pool->zip_mutex);
/* The maximum number of purge threads should never exceed
BUF_POOL_WATCH_SIZE. So there is no way for purge thread
instance to hold a watch when setting another watch. */
for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) { for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) {
bpage = &buf_pool->watch[i]; bpage = &buf_pool->watch[i];

View File

@@ -1626,6 +1626,104 @@ dict_create_add_foreign_field_to_dictionary(
table, foreign, trx)); table, foreign, trx));
} }
/********************************************************************//**
Construct foreign key constraint defintion from data dictionary information.
*/
UNIV_INTERN
char*
dict_foreign_def_get(
/*=================*/
dict_foreign_t* foreign,/*!< in: foreign */
trx_t* trx) /*!< in: trx */
{
char* fk_def = mem_heap_alloc(foreign->heap, 4*1024);
const char* tbname;
char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
int i;
char* bufend;
tbname = dict_remove_db_name(foreign->id);
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
tbname, strlen(tbname), trx->mysql_thd, FALSE);
tablebuf[bufend - tablebuf] = '\0';
sprintf(fk_def,
(char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
for(i = 0; i < foreign->n_fields; i++) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->foreign_col_names[i],
strlen(foreign->foreign_col_names[i]),
trx->mysql_thd, FALSE);
strcat(fk_def, buf);
if (i < foreign->n_fields-1) {
strcat(fk_def, (char *)",");
}
}
strcat(fk_def,(char *)") REFERENCES ");
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
foreign->referenced_table_name,
strlen(foreign->referenced_table_name),
trx->mysql_thd, TRUE);
tablebuf[bufend - tablebuf] = '\0';
strcat(fk_def, tablebuf);
strcat(fk_def, " (");
for(i = 0; i < foreign->n_fields; i++) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->referenced_col_names[i],
strlen(foreign->referenced_col_names[i]),
trx->mysql_thd, FALSE);
buf[bufend - buf] = '\0';
strcat(fk_def, buf);
if (i < foreign->n_fields-1) {
strcat(fk_def, (char *)",");
}
}
strcat(fk_def, (char *)")");
return fk_def;
}
/********************************************************************//**
Convert foreign key column names from data dictionary to SQL-layer.
*/
static
void
dict_foreign_def_get_fields(
/*========================*/
dict_foreign_t* foreign,/*!< in: foreign */
trx_t* trx, /*!< in: trx */
char** field, /*!< out: foreign column */
char** field2, /*!< out: referenced column */
int col_no) /*!< in: column number */
{
char* bufend;
char* fieldbuf = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
char* fieldbuf2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
foreign->foreign_col_names[col_no],
strlen(foreign->foreign_col_names[col_no]),
trx->mysql_thd, FALSE);
fieldbuf[bufend - fieldbuf] = '\0';
bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
foreign->referenced_col_names[col_no],
strlen(foreign->referenced_col_names[col_no]),
trx->mysql_thd, FALSE);
fieldbuf2[bufend - fieldbuf2] = '\0';
*field = fieldbuf;
*field2 = fieldbuf2;
}
/********************************************************************//** /********************************************************************//**
Add a single foreign key definition to the data dictionary tables in the Add a single foreign key definition to the data dictionary tables in the
database. We also generate names to constraints that were not named by the database. We also generate names to constraints that were not named by the
@@ -1708,6 +1806,29 @@ dict_create_add_foreign_to_dictionary(
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
if (error == DB_DUPLICATE_KEY) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
char* fk_def;
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
table->name, strlen(table->name),
trx->mysql_thd, TRUE);
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
fk_def = dict_foreign_def_get(foreign, trx);
ib_push_warning(trx, error,
"Create or Alter table %s with foreign key constraint"
" failed. Foreign key constraint %s"
" already exists on data dictionary."
" Foreign key constraint names need to be unique in database."
" Error in foreign key definition: %s.",
tablename, buf, fk_def);
}
return(error); return(error);
} }
@@ -1716,6 +1837,26 @@ dict_create_add_foreign_to_dictionary(
i, table, foreign, trx); i, table, foreign, trx);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
char* field=NULL;
char* field2=NULL;
char* fk_def;
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
table->name, strlen(table->name),
trx->mysql_thd, TRUE);
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
fk_def = dict_foreign_def_get(foreign, trx);
dict_foreign_def_get_fields(foreign, trx, &field, &field2, i);
ib_push_warning(trx, error,
"Create or Alter table %s with foreign key constraint"
" failed. Error adding foreign key constraint name %s"
" fields %s or %s to the dictionary."
" Error in foreign key definition: %s.",
tablename, buf, i+1, fk_def);
return(error); return(error);
} }

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@@ -2663,6 +2663,7 @@ dict_foreign_remove_from_cache(
foreign); foreign);
rbt = foreign->referenced_table->referenced_rbt; rbt = foreign->referenced_table->referenced_rbt;
if (rbt != NULL && foreign->id != NULL) { if (rbt != NULL && foreign->id != NULL) {
const ib_rbt_node_t* node const ib_rbt_node_t* node
= rbt_lookup(rbt, foreign->id); = rbt_lookup(rbt, foreign->id);
@@ -2747,6 +2748,11 @@ dict_foreign_find(
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
} }
#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
#define DB_FOREIGN_KEY_COL_NOT_NULL 201
#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
/*********************************************************************//** /*********************************************************************//**
Tries to find an index whose first fields are the columns in the array, Tries to find an index whose first fields are the columns in the array,
in the same order and is not marked for deletion and is not the same in the same order and is not marked for deletion and is not the same
@@ -2764,12 +2770,21 @@ dict_foreign_find_index(
ibool check_charsets, ibool check_charsets,
/*!< in: whether to check charsets. /*!< in: whether to check charsets.
only has an effect if types_idx != NULL */ only has an effect if types_idx != NULL */
ulint check_null) ulint check_null,
/*!< in: nonzero if none of the columns must /*!< in: nonzero if none of the columns must
be declared NOT NULL */ be declared NOT NULL */
ulint* error, /*!< out: error code */
ulint* err_col_no,
/*!< out: column number where error happened */
dict_index_t** err_index)
/*!< out: index where error happened */
{ {
dict_index_t* index; dict_index_t* index;
if (error) {
*error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
}
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
while (index != NULL) { while (index != NULL) {
@@ -2795,6 +2810,12 @@ dict_foreign_find_index(
/* We do not accept column prefix /* We do not accept column prefix
indexes here */ indexes here */
if (error && err_col_no && err_index) {
*error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
*err_col_no = i;
*err_index = index;
}
break; break;
} }
@@ -2806,6 +2827,11 @@ dict_foreign_find_index(
if (check_null if (check_null
&& (field->col->prtype & DATA_NOT_NULL)) { && (field->col->prtype & DATA_NOT_NULL)) {
if (error && err_col_no && err_index) {
*error = DB_FOREIGN_KEY_COL_NOT_NULL;
*err_col_no = i;
*err_index = index;
}
return(NULL); return(NULL);
} }
@@ -2815,6 +2841,12 @@ dict_foreign_find_index(
i), i),
check_charsets)) { check_charsets)) {
if (error && err_col_no && err_index) {
*error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
*err_col_no = i;
*err_index = index;
}
break; break;
} }
} }
@@ -2822,6 +2854,10 @@ dict_foreign_find_index(
if (i == n_cols) { if (i == n_cols) {
/* We found a matching index */ /* We found a matching index */
if (error) {
*error = DB_SUCCESS;
}
return(index); return(index);
} }
} }
@@ -2848,8 +2884,9 @@ wsrep_dict_foreign_find_index(
/*!< in: nonzero if none of the columns must /*!< in: nonzero if none of the columns must
be declared NOT NULL */ be declared NOT NULL */
{ {
return dict_foreign_find_index( return dict_foreign_find_index(table, columns, n_cols, types_idx,
table, columns, n_cols, types_idx, check_charsets, check_null); check_charsets, check_null,
NULL, NULL, NULL);
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/**********************************************************************//** /**********************************************************************//**
@@ -2872,7 +2909,7 @@ dict_foreign_find_equiv_index(
foreign->foreign_table, foreign->foreign_table,
foreign->foreign_col_names, foreign->n_fields, foreign->foreign_col_names, foreign->n_fields,
foreign->foreign_index, TRUE, /* check types */ foreign->foreign_index, TRUE, /* check types */
FALSE/* allow columns to be NULL */)); FALSE/* allow columns to be NULL */, NULL, NULL, NULL));
} }
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
@@ -3035,11 +3072,15 @@ dict_foreign_add_to_cache(
} }
if (for_in_cache->referenced_table == NULL && ref_table) { if (for_in_cache->referenced_table == NULL && ref_table) {
ulint index_error;
ulint err_col;
dict_index_t *err_index=NULL;
index = dict_foreign_find_index( index = dict_foreign_find_index(
ref_table, ref_table,
for_in_cache->referenced_col_names, for_in_cache->referenced_col_names,
for_in_cache->n_fields, for_in_cache->foreign_index, for_in_cache->n_fields, for_in_cache->foreign_index,
check_charsets, FALSE); check_charsets, FALSE, &index_error, &err_col, &err_index);
if (index == NULL if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3071,6 +3112,9 @@ dict_foreign_add_to_cache(
} }
if (for_in_cache->foreign_table == NULL && for_table) { if (for_in_cache->foreign_table == NULL && for_table) {
ulint index_error;
ulint err_col;
dict_index_t* err_index=NULL;
index = dict_foreign_find_index( index = dict_foreign_find_index(
for_table, for_table,
@@ -3079,7 +3123,8 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_index, check_charsets, for_in_cache->referenced_index, check_charsets,
for_in_cache->type for_in_cache->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL & (DICT_FOREIGN_ON_DELETE_SET_NULL
| DICT_FOREIGN_ON_UPDATE_SET_NULL)); | DICT_FOREIGN_ON_UPDATE_SET_NULL),
&index_error, &err_col, &err_index);
if (index == NULL if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3690,6 +3735,8 @@ static
void void
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
/*===========================*/ /*===========================*/
const char* fmt, /*!< in: syntax err msg */
const char* oper, /*!< in: operation */
const char* name, /*!< in: table name */ const char* name, /*!< in: table name */
const char* start_of_latest_foreign, const char* start_of_latest_foreign,
/*!< in: start of the foreign key clause /*!< in: start of the foreign key clause
@@ -3700,11 +3747,101 @@ dict_foreign_report_syntax_err(
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, name);
fprintf(ef, "%s:\nSyntax error close to:\n%s\n", fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr);
start_of_latest_foreign, ptr);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
} }
/*********************************************************************//**
Push warning message to SQL-layer based on foreign key constraint
index match error. */
static
void
dict_foreign_push_index_error(
/*==========================*/
trx_t* trx, /*!< in: trx */
const char* operation, /*!< in: operation create or alter
*/
const char* create_name, /*!< in: table name in create or
alter table */
const char* latest_foreign, /*!< in: start of latest foreign key
constraint name */
const char** columns, /*!< in: foreign key columns */
ulint index_error, /*!< in: error code */
ulint err_col, /*!< in: column where error happened
*/
dict_index_t* err_index, /*!< in: index where error happened
*/
dict_table_t* table, /*!< in: table */
FILE* ef) /*!< in: output stream */
{
switch (index_error) {
case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
fprintf(ef,
"%s table '%s' with foreign key constraint"
" failed. There is no index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.\n",
operation, create_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table '%s' with foreign key constraint"
" failed. There is no index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.",
operation, create_name, latest_foreign);
break;
}
case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
fprintf(ef,
"%s table '%s' with foreign key constraint"
" failed. There is only prefix index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.\n",
operation, create_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table '%s' with foreign key constraint"
" failed. There is only prefix index in the referenced"
" table where the referenced columns appear"
" as the first columns. Error close to %s.",
operation, create_name, latest_foreign);
break;
}
case DB_FOREIGN_KEY_COL_NOT_NULL: {
fprintf(ef,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but "
"field %s on index is defined as NOT NULL close to %s\n",
operation, create_name, columns[err_col], latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but "
"field %s on index is defined as NOT NULL close to %s",
operation, create_name, columns[err_col], latest_foreign);
break;
}
case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
dict_field_t* field;
const char* col_name;
field = dict_index_get_nth_field(err_index, err_col);
col_name = dict_table_get_col_name(
table, dict_col_get_no(field->col));
fprintf(ef,
"%s table %s with foreign key constraint"
" failed. Field type or character set for column %s "
"does not mach referenced column %s close to %s\n",
operation, create_name, columns[err_col], col_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Field type or character set for column %s "
"does not mach referenced column %s close to %s",
operation, create_name, columns[err_col], col_name, latest_foreign);
break;
}
default:
ut_error;
}
}
/*********************************************************************//** /*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary the foreign Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after key constraints declared in the string. This function should be called after
@@ -3733,15 +3870,20 @@ dict_create_foreign_constraints_low(
DB_CANNOT_ADD_CONSTRAINT if any foreign DB_CANNOT_ADD_CONSTRAINT if any foreign
keys are found. */ keys are found. */
{ {
dict_table_t* table; dict_table_t* table = NULL;
dict_table_t* referenced_table; dict_table_t* referenced_table = NULL;
dict_table_t* table_to_alter; dict_table_t* table_to_alter = NULL;
dict_table_t* table_to_create = NULL;
ulint highest_id_so_far = 0; ulint highest_id_so_far = 0;
dict_index_t* index; dict_index_t* index = NULL;
dict_foreign_t* foreign; dict_foreign_t* foreign = NULL;
const char* ptr = sql_string; const char* ptr = sql_string;
const char* start_of_latest_foreign = sql_string; const char* start_of_latest_foreign = sql_string;
const char* start_of_latest_set = NULL;
FILE* ef = dict_foreign_err_file; FILE* ef = dict_foreign_err_file;
ulint index_error = DB_SUCCESS;
dict_index_t* err_index = NULL;
ulint err_col;
const char* constraint_name; const char* constraint_name;
ibool success; ibool success;
ulint error; ulint error;
@@ -3754,29 +3896,68 @@ dict_create_foreign_constraints_low(
ulint n_on_updates; ulint n_on_updates;
const dict_col_t*columns[500]; const dict_col_t*columns[500];
const char* column_names[500]; const char* column_names[500];
const char* ref_column_names[500];
const char* referenced_table_name; const char* referenced_table_name;
const char* create_table_name;
const char* orig;
char create_name[MAX_TABLE_NAME_LEN + 1];
const char operation[8];
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE); table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE);
/* First check if we are actually doing an ALTER TABLE, and in that
case look for the table being altered */
ptr = dict_accept(cs, ptr, "ALTER", &success);
strcpy((char *)operation, success ? "Alter " : "Create ");
if (!success) {
orig = ptr;
ptr = dict_scan_to(ptr, "CREATE");
ptr = dict_scan_to(ptr, "TABLE");
ptr = dict_accept(cs, ptr, "TABLE", &success);
if (success) {
ptr = dict_scan_table_name(cs, ptr, &table_to_create, name,
&success, heap, &create_table_name);
}
if (success) {
char *bufend;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
create_table_name, strlen(create_table_name),
trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
ptr = orig;
} else {
char *bufend;
ptr = orig;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
name, strlen(name), trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
}
goto loop;
}
if (table == NULL) { if (table == NULL) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, fprintf(ef, "%s table %s with foreign key constraint"
"Cannot find the table in the internal" " failed. Table %s not found from data dictionary."
" data dictionary of InnoDB.\n" " Error close to %s.\n",
"Create table statement:\n%s\n", sql_string); operation, create_name, create_name, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_ERROR,
"%s table %s with foreign key constraint"
" failed. Table %s not found from data dictionary."
" Error close to %s.",
operation, create_name, create_name, start_of_latest_foreign);
return(DB_ERROR); return(DB_ERROR);
} }
/* First check if we are actually doing an ALTER TABLE, and in that /* If not alter table jump to loop */
case look for the table being altered */
ptr = dict_accept(cs, ptr, "ALTER", &success);
if (!success) { if (!success) {
goto loop; goto loop;
@@ -3791,13 +3972,40 @@ dict_create_foreign_constraints_low(
/* We are doing an ALTER TABLE: scan the table name we are altering */ /* We are doing an ALTER TABLE: scan the table name we are altering */
orig = ptr;
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name, ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
&success, heap, &referenced_table_name); &success, heap, &referenced_table_name);
if (table_to_alter) {
char *bufend;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
table_to_alter->name, strlen(table_to_alter->name),
trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
} else {
char *bufend;
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
referenced_table_name, strlen(referenced_table_name),
trx->mysql_thd, TRUE);
create_name[bufend-create_name]='\0';
}
if (!success) { if (!success) {
fprintf(stderr, mutex_enter(&dict_foreign_err_mutex);
"InnoDB: Error: could not find" dict_foreign_error_report_low(ef, create_name);
" the table being ALTERED in:\n%s\n", fprintf(ef,
sql_string); "%s table %s with foreign key constraint"
" failed. Table %s not found from data dictionary."
" Error close to %s.\n",
operation, create_name, create_name, orig);
mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_ERROR,
"%s table %s with foreign key constraint"
" failed. Table %s not found from data dictionary."
" Error close to %s.",
operation, create_name, create_name, orig);
return(DB_ERROR); return(DB_ERROR);
} }
@@ -3863,7 +4071,19 @@ loop:
if so, immediately reject the command if the table is a if so, immediately reject the command if the table is a
temporary one. For now, this kludge will work. */ temporary one. For now, this kludge will work. */
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) { if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s table %s with foreign key constraint"
" failed. Temporary tables can't have foreign key constraints."
" Error close to %s.\n",
operation, create_name, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Temporary tables can't have foreign key constraints."
" Error close to %s.",
operation, create_name, start_of_latest_foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3899,11 +4119,21 @@ loop:
if (!success) { if (!success) {
/* MySQL allows also an index id before the '('; we /* MySQL allows also an index id before the '('; we
skip it */ skip it */
orig = ptr;
ptr = dict_skip_word(cs, ptr, &success); ptr = dict_skip_word(cs, ptr, &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3923,15 +4153,26 @@ loop:
/* Scan the columns in the first list */ /* Scan the columns in the first list */
col_loop1: col_loop1:
ut_a(i < (sizeof column_names) / sizeof *column_names); ut_a(i < (sizeof column_names) / sizeof *column_names);
orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, table, columns + i, ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
heap, column_names + i); heap, column_names + i);
if (!success) { if (!success) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", fprintf(ef,
start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3943,11 +4184,22 @@ col_loop1:
goto col_loop1; goto col_loop1;
} }
orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success); ptr = dict_accept(cs, ptr, ")", &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -3955,27 +4207,41 @@ col_loop1:
as the first fields and in the right order */ as the first fields and in the right order */
index = dict_foreign_find_index(table, column_names, i, index = dict_foreign_find_index(table, column_names, i,
NULL, TRUE, FALSE); NULL, TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) { if (!index) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fputs("There is no index in table ", ef); fputs("There is no index in table ", ef);
ut_print_name(ef, NULL, TRUE, name); ut_print_name(ef, NULL, TRUE, create_name);
fprintf(ef, " where the columns appear\n" fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n" "as the first columns. Constraint:\n%s\n"
"See " REFMAN "innodb-foreign-key-constraints.html\n" "See " REFMAN "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n", "for correct foreign key definition.\n",
start_of_latest_foreign); start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CHILD_NO_INDEX); dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
column_names, index_error, err_col, err_index, table, ef);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT);
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "REFERENCES", &success); ptr = dict_accept(cs, ptr, "REFERENCES", &success);
if (!success || !my_isspace(cs, *ptr)) { if (!success || !my_isspace(cs, *ptr)) {
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4024,24 +4290,50 @@ col_loop1:
checking of foreign key constraints! */ checking of foreign key constraints! */
if (!success || (!referenced_table && trx->check_foreigns)) { if (!success || (!referenced_table && trx->check_foreigns)) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char* bufend;
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
referenced_table_name, strlen(referenced_table_name),
trx->mysql_thd, TRUE);
buf[bufend - buf] = '\0';
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
"close to %s.",
operation, create_name, buf, start_of_latest_foreign);
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\nCannot resolve table name close to:\n" fprintf(ef,
"%s\n", "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
start_of_latest_foreign, ptr); "close to %s.\n",
operation, create_name, buf, start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success); ptr = dict_accept(cs, ptr, "(", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4049,20 +4341,29 @@ col_loop1:
i = 0; i = 0;
col_loop2: col_loop2:
orig = ptr;
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
heap, column_names + i); heap, ref_column_names + i);
i++; i++;
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\nCannot resolve column name close to:\n" fprintf(ef,
"%s\n", "%s table %s with foreign key constraint"
start_of_latest_foreign, ptr); " failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, orig);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, orig);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4072,13 +4373,23 @@ col_loop2:
goto col_loop2; goto col_loop2;
} }
orig = ptr;
ptr = dict_accept(cs, ptr, ")", &success); ptr = dict_accept(cs, ptr, ")", &success);
if (!success || foreign->n_fields != i) { if (!success || foreign->n_fields != i) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s. Too few referenced columns\n",
operation, create_name, start_of_latest_foreign, orig);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s. Too few referenced columns, you have %d when you should have %d.",
operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4088,6 +4399,7 @@ col_loop2:
scan_on_conditions: scan_on_conditions:
/* Loop here as long as we can find ON ... conditions */ /* Loop here as long as we can find ON ... conditions */
start_of_latest_set = ptr;
ptr = dict_accept(cs, ptr, "ON", &success); ptr = dict_accept(cs, ptr, "ON", &success);
if (!success) { if (!success) {
@@ -4098,13 +4410,24 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "DELETE", &success); ptr = dict_accept(cs, ptr, "DELETE", &success);
if (!success) { if (!success) {
orig = ptr;
ptr = dict_accept(cs, ptr, "UPDATE", &success); ptr = dict_accept(cs, ptr, "UPDATE", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4136,12 +4459,22 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "NO", &success); ptr = dict_accept(cs, ptr, "NO", &success);
if (success) { if (success) {
orig = ptr;
ptr = dict_accept(cs, ptr, "ACTION", &success); ptr = dict_accept(cs, ptr, "ACTION", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err( dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4155,42 +4488,73 @@ scan_on_conditions:
goto scan_on_conditions; goto scan_on_conditions;
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "SET", &success); ptr = dict_accept(cs, ptr, "SET", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
orig = ptr;
ptr = dict_accept(cs, ptr, "NULL", &success); ptr = dict_accept(cs, ptr, "NULL", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(
ptr); "%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. Foreign key constraint parse error in %s"
" close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
for (j = 0; j < foreign->n_fields; j++) { for (j = 0; j < foreign->n_fields; j++) {
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
& DATA_NOT_NULL) { & DATA_NOT_NULL) {
const dict_col_t* col
= dict_index_get_nth_col(foreign->foreign_index, j);
const char* col_name = dict_table_get_col_name(foreign->foreign_index->table,
dict_col_get_no(col));
/* It is not sensible to define SET NULL /* It is not sensible to define SET NULL
if the column is not allowed to be NULL! */ if the column is not allowed to be NULL! */
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n" fprintf(ef,
"You have defined a SET NULL condition" "%s table %s with foreign key constraint"
" though some of the\n" " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
"columns are defined as NOT NULL.\n", " in %s close to %s.\n",
start_of_latest_foreign); operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
" in %s close to %s.",
operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
} }
@@ -4207,16 +4571,22 @@ try_find_index:
if (n_on_deletes > 1 || n_on_updates > 1) { if (n_on_deletes > 1 || n_on_updates > 1) {
/* It is an error to define more than 1 action */ /* It is an error to define more than 1 action */
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n" fprintf(ef,
"You have twice an ON DELETE clause" "%s table %s with foreign key constraint"
" or twice an ON UPDATE clause.\n", " failed. You have more than one on delete or on update clause"
start_of_latest_foreign); " in %s close to %s.\n",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
"%s table %s with foreign key constraint"
" failed. You have more than one on delete or on update clause"
" in %s close to %s.",
operation, create_name, start_of_latest_foreign, start_of_latest_set);
dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
@@ -4226,13 +4596,13 @@ try_find_index:
if (referenced_table) { if (referenced_table) {
index = dict_foreign_find_index(referenced_table, index = dict_foreign_find_index(referenced_table,
column_names, i, ref_column_names, i,
foreign->foreign_index, foreign->foreign_index,
TRUE, FALSE); TRUE, FALSE, &index_error, &err_col, &err_index);
if (!index) { if (!index) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, create_name);
fprintf(ef, "%s:\n" fprintf(ef, "%s:\n"
"Cannot find an index in the" "Cannot find an index in the"
" referenced table where the\n" " referenced table where the\n"
@@ -4250,9 +4620,13 @@ try_find_index:
"innodb-foreign-key-constraints.html\n" "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n", "for correct foreign key definition.\n",
start_of_latest_foreign); start_of_latest_foreign);
dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
column_names, index_error, err_col, err_index, referenced_table, ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
return(DB_PARENT_NO_INDEX); return(DB_CANNOT_ADD_CONSTRAINT);
} }
} else { } else {
ut_a(trx->check_foreigns == FALSE); ut_a(trx->check_foreigns == FALSE);
@@ -4270,7 +4644,7 @@ try_find_index:
i * sizeof(void*)); i * sizeof(void*));
for (i = 0; i < foreign->n_fields; i++) { for (i = 0; i < foreign->n_fields; i++) {
foreign->referenced_col_names[i] foreign->referenced_col_names[i]
= mem_heap_strdup(foreign->heap, column_names[i]); = mem_heap_strdup(foreign->heap, ref_column_names[i]);
} }
/* We found an ok constraint definition: add to the lists */ /* We found an ok constraint definition: add to the lists */
@@ -5815,7 +6189,8 @@ dict_table_replace_index_in_foreign_list(
foreign->referenced_table, foreign->referenced_table,
foreign->referenced_col_names, foreign->referenced_col_names,
foreign->n_fields, index, foreign->n_fields, index,
/*check_charsets=*/TRUE, /*check_null=*/FALSE); /*check_charsets=*/TRUE, /*check_null=*/FALSE,
NULL, NULL, NULL);
ut_ad(new_index || !trx->check_foreigns); ut_ad(new_index || !trx->check_foreigns);
ut_ad(!new_index || new_index->table == index->table); ut_ad(!new_index || new_index->table == index->table);

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc. Copyright (c) 2009, Percona Inc.
@@ -1910,6 +1910,7 @@ check_trx_exists(
if (trx == NULL) { if (trx == NULL) {
trx = innobase_trx_allocate(thd); trx = innobase_trx_allocate(thd);
thd_set_ha_data(thd, innodb_hton_ptr, trx);
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
mem_analyze_corruption(trx); mem_analyze_corruption(trx);
ut_error; ut_error;
@@ -10169,6 +10170,13 @@ ha_innobase::estimate_rows_upper_bound(void)
estimate = 2 * local_data_file_length / estimate = 2 * local_data_file_length /
dict_index_calc_min_rec_len(index); dict_index_calc_min_rec_len(index);
/* Set num_rows less than MERGEBUFF to simulate the case where we do
not have enough space to merge the externally sorted file blocks. */
DBUG_EXECUTE_IF("set_num_rows_lt_MERGEBUFF",
estimate = 2;
DBUG_SET("-d,set_num_rows_lt_MERGEBUFF");
);
prebuilt->trx->op_info = (char*)""; prebuilt->trx->op_info = (char*)"";
DBUG_RETURN((ha_rows) estimate); DBUG_RETURN((ha_rows) estimate);
@@ -10448,17 +10456,6 @@ ha_innobase::info_low(
prebuilt->trx->op_info = "returning various info to MySQL"; prebuilt->trx->op_info = "returning various info to MySQL";
} }
my_snprintf(path, sizeof(path), "%s/%s%s",
mysql_data_home, ib_table->name, reg_ext);
unpack_filename(path,path);
/* Note that we do not know the access time of the table,
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
if (os_file_get_status(path,&stat_info)) {
stats.create_time = (ulong) stat_info.ctime;
}
} }
if (flag & HA_STATUS_VARIABLE) { if (flag & HA_STATUS_VARIABLE) {
@@ -10702,6 +10699,20 @@ ha_innobase::info_low(
} }
dict_table_stats_unlock(ib_table, RW_S_LATCH); dict_table_stats_unlock(ib_table, RW_S_LATCH);
my_snprintf(path, sizeof(path), "%s/%s%s",
mysql_data_home,
table->s->normalized_path.str,
reg_ext);
unpack_filename(path,path);
/* Note that we do not know the access time of the table,
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
if (os_file_get_status(path,&stat_info)) {
stats.create_time = (ulong) stat_info.ctime;
}
} }
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
@@ -15514,3 +15525,28 @@ ha_innobase::idx_cond_push(
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
} }
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
extern "C" UNIV_INTERN
void
ib_push_warning(
trx_t* trx, /*!< in: trx */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...)
{
va_list args;
THD *thd = (THD *)trx->mysql_thd;
char *buf;
#define MAX_BUF_SIZE 4*1024
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
convert_error_code_to_mysql(error, 0, thd),
buf);
my_free(buf);
va_end(args);
}

View File

@@ -121,6 +121,17 @@ UNIV_INTERN
ulint ulint
dict_create_or_check_foreign_constraint_tables(void); dict_create_or_check_foreign_constraint_tables(void);
/*================================================*/ /*================================================*/
/********************************************************************//**
Construct foreign key constraint defintion from data dictionary information.
*/
UNIV_INTERN
char*
dict_foreign_def_get(
/*=================*/
dict_foreign_t* foreign,/*!< in: foreign */
trx_t* trx); /*!< in: trx */
/********************************************************************//** /********************************************************************//**
Adds foreign key definitions to data dictionary tables in the database. We Adds foreign key definitions to data dictionary tables in the database. We
look at table->foreign_list, and also generate names to constraints that were look at table->foreign_list, and also generate names to constraints that were

View File

@@ -366,5 +366,14 @@ innobase_convert_to_filename_charset(
const char* from, /* in: identifier to convert */ const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */ ulint len); /* in: length of 'to', in bytes */
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
trx_t* trx, /*!< in: trx */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...);
#endif #endif

View File

@@ -64,10 +64,10 @@ component, i.e. we show M.N.P as M.N */
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR) (INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
#ifndef PERCONA_INNODB_VERSION #ifndef PERCONA_INNODB_VERSION
#define PERCONA_INNODB_VERSION 37.2 #define PERCONA_INNODB_VERSION 37.3
#endif #endif
#define INNODB_VERSION_STR "5.5.43-MariaDB-" IB_TO_STR(PERCONA_INNODB_VERSION) #define INNODB_VERSION_STR "5.5.44-MariaDB-" IB_TO_STR(PERCONA_INNODB_VERSION)
#define REFMAN "http://dev.mysql.com/doc/refman/" \ #define REFMAN "http://dev.mysql.com/doc/refman/" \
IB_TO_STR(MYSQL_MAJOR_VERSION) "." \ IB_TO_STR(MYSQL_MAJOR_VERSION) "." \

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, Google Inc. Copyright (c) 2008, Google Inc.
Copyright (c) 2009, Percona Inc. Copyright (c) 2009, Percona Inc.
@@ -2511,9 +2511,9 @@ innobase_shutdown_for_mysql(void)
ibuf_close(); ibuf_close();
log_shutdown(); log_shutdown();
lock_sys_close();
trx_sys_file_format_close(); trx_sys_file_format_close();
trx_sys_close(); trx_sys_close();
lock_sys_close();
mutex_free(&srv_monitor_file_mutex); mutex_free(&srv_monitor_file_mutex);
mutex_free(&srv_dict_tmpfile_mutex); mutex_free(&srv_dict_tmpfile_mutex);

View File

@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc. Copyright (c) 2008, Google Inc.
Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved. Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
@@ -1114,8 +1114,9 @@ sync_array_output_info(
os_thread_id_t r; os_thread_id_t r;
fprintf(file, fprintf(file,
"OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n", "OS WAIT ARRAY INFO: reservation count " ULINTPF
(long) arr->res_count, (long) arr->sg_count); ", signal count " ULINTPF "\n",
arr->res_count, arr->sg_count);
i = 0; i = 0;
count = 0; count = 0;

View File

@@ -771,9 +771,9 @@ trx_lists_init_at_db_start(void)
" anyway.\n"); " anyway.\n");
trx->state = TRX_ACTIVE; trx->state = TRX_ACTIVE;
trx_reserve_descriptor(
trx);
} }
trx_reserve_descriptor(trx);
} else { } else {
trx->state trx->state
= TRX_COMMITTED_IN_MEMORY; = TRX_COMMITTED_IN_MEMORY;

View File

@@ -21,31 +21,42 @@
static my_bool ssl_algorithms_added = FALSE; static my_bool ssl_algorithms_added = FALSE;
static my_bool ssl_error_strings_loaded= FALSE; static my_bool ssl_error_strings_loaded= FALSE;
/* the function below was generated with "openssl dhparam -2 -C 1024" */ /* the function below was generated with "openssl dhparam -2 -C 2048" */
static static
DH *get_dh1024() DH *get_dh2048()
{ {
static unsigned char dh1024_p[]={ static unsigned char dh2048_p[]={
0xEC,0x46,0x7E,0xF9,0x4E,0x10,0x29,0xDC,0x44,0x97,0x71,0xFD, 0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8,
0x71,0xC6,0x9F,0x0D,0xD1,0x09,0xF6,0x58,0x6F,0xAD,0xCA,0xF4, 0x15,0xFC,0x3B,0xBA,0xAB,0x9F,0xDF,0x68,0xC4,0x79,0x78,0x0D,
0x37,0xD5,0xC3,0xBD,0xC3,0x9A,0x51,0x66,0x2C,0x58,0xBD,0x02, 0xC1,0x12,0x64,0xE4,0x15,0xC9,0x66,0xDB,0xF6,0xCB,0xB3,0x39,
0xBD,0xBA,0xBA,0xFC,0xE7,0x0E,0x5A,0xE5,0x97,0x81,0xC3,0xF3, 0x02,0x5B,0x78,0x62,0xFB,0x09,0xAE,0x09,0x6B,0xDD,0xD4,0x5D,
0x28,0x2D,0xAD,0x00,0x91,0xEF,0xF8,0xF0,0x5D,0xE9,0xE7,0x18, 0x97,0xBC,0xDC,0x7F,0xE6,0xD6,0xF1,0xCB,0xF5,0xEB,0xDA,0xA7,
0xE2,0xAD,0xC4,0x70,0xC5,0x3C,0x12,0x8A,0x80,0x6A,0x9F,0x3B, 0x2E,0x5A,0x43,0x2B,0xE9,0x40,0xE2,0x85,0x00,0x1C,0xC0,0x0A,
0x00,0xA2,0x8F,0xA9,0x26,0xB0,0x0E,0x7F,0xED,0xF6,0xC2,0x03, 0x98,0x77,0xA9,0x31,0xDE,0x0B,0x75,0x4D,0x1E,0x1F,0x16,0x83,
0x81,0xB5,0xC5,0x41,0xD0,0x00,0x2B,0x21,0xD4,0x4B,0x74,0xA6, 0xCA,0xDE,0xBD,0x21,0xFC,0xC1,0x82,0x37,0x36,0x33,0x0B,0x66,
0xD7,0x1A,0x0E,0x82,0xC8,0xEE,0xD4,0xB1,0x6F,0xB4,0x79,0x01, 0x06,0x3C,0xF3,0xAF,0x21,0x57,0x57,0x80,0xF6,0x94,0x1B,0xA9,
0x8A,0xF1,0x12,0xD7,0x3C,0xFD,0xCB,0x9B,0xAE,0x1C,0xA9,0x0F, 0xD4,0xF6,0x8F,0x18,0x62,0x0E,0xC4,0x22,0xF9,0x5B,0x62,0xCC,
0x3D,0x0F,0xF8,0xD6,0x7D,0xDE,0xD6,0x0B, 0x3F,0x19,0x95,0xCF,0x4B,0x00,0xA6,0x6C,0x0B,0xAF,0x9F,0xD5,
0xFA,0x3D,0x6D,0xDA,0x30,0x83,0x07,0x91,0xAC,0x15,0xFF,0x8F,
0x59,0x54,0xEA,0x25,0xBC,0x4E,0xEB,0x6A,0x54,0xDF,0x75,0x09,
0x72,0x0F,0xEF,0x23,0x70,0xE0,0xA8,0x04,0xEA,0xFF,0x90,0x54,
0xCD,0x84,0x18,0xC0,0x75,0x91,0x99,0x0F,0xA1,0x78,0x0C,0x07,
0xB7,0xC5,0xDE,0x55,0x06,0x7B,0x95,0x68,0x2C,0x33,0x39,0xBC,
0x2C,0xD0,0x6D,0xDD,0xFA,0xDC,0xB5,0x8F,0x82,0x39,0xF8,0x67,
0x44,0xF1,0xD8,0xF7,0x78,0x11,0x9A,0x77,0x9B,0x53,0x47,0xD6,
0x2B,0x5D,0x67,0xB8,0xB7,0xBC,0xC1,0xD7,0x79,0x62,0x15,0xC2,
0xC5,0x83,0x97,0xA7,0xF8,0xB4,0x9C,0xF6,0x8F,0x9A,0xC7,0xDA,
0x1B,0xBB,0x87,0x07,0xA7,0x71,0xAD,0xB2,0x8A,0x50,0xF8,0x26,
0x12,0xB7,0x3E,0x0B,
}; };
static unsigned char dh1024_g[]={ static unsigned char dh2048_g[]={
0x02, 0x02,
}; };
DH *dh; DH *dh;
if ((dh=DH_new()) == NULL) return(NULL); if ((dh=DH_new()) == NULL) return(NULL);
dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL)) if ((dh->p == NULL) || (dh->g == NULL))
{ DH_free(dh); return(NULL); } { DH_free(dh); return(NULL); }
return(dh); return(dh);
@@ -259,7 +270,7 @@ new_VioSSLFd(const char *key_file, const char *cert_file,
} }
/* DH stuff */ /* DH stuff */
dh=get_dh1024(); dh=get_dh2048();
SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh); SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh);
DH_free(dh); DH_free(dh);