diff options
64 files changed, 2520 insertions, 305 deletions
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index ce441695d6f..db120896bda 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1095,7 +1095,7 @@ int main(int argc, char **argv) printf("This installation of MySQL is already upgraded to %s, " "use --force if you still need to run mysql_upgrade\n", MYSQL_SERVER_VERSION); - die(NULL); + goto end; } if (opt_version_check && check_version_match()) @@ -1124,6 +1124,7 @@ int main(int argc, char **argv) DBUG_ASSERT(phase == phases_total); +end: free_used_memory(); my_end(my_end_arg); exit(0); diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test index 48e922d2e67..74fbe6b482a 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -228,7 +228,7 @@ rollback; create table t0 (n int); insert t0 select * from t1; set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); +insert into t0 select GET_LOCK("lock1",0); set autocommit=0; create table t2 (n int) engine=innodb; insert into t2 values (3); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 46bc64a6fcc..d902f8645eb 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -4862,6 +4862,7 @@ sub extract_warning_lines ($$) { qr|InnoDB: Setting thread \d+ nice to \d+ failed, current nice \d+, errno 13|, # setpriority() fails under valgrind qr|Failed to setup SSL|, qr|SSL error: Failed to set ciphers to use|, + qr/Plugin 'InnoDB' will be forced to shutdown/, ); my $matched_lines= []; diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index f12a0c1127a..0bc31a5e85b 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -1103,3 +1103,19 @@ ORDER BY field; field c,c 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; diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 5ae9ae1f0e8..d42d1fac411 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -361,7 +361,18 @@ set optimizer_switch=@optimizer_switch_save; drop view v_merge, vm; drop table t1,tv; # -# GET_LOCK, RELEASE_LOCK, IS_USED_LOCK functions test +# 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 # # IS_USED_LOCK, IS_FREE_LOCK: the lock is not acquired # Note: IS_USED_LOCK returns NULL if the lock is unused diff --git a/mysql-test/r/innodb_load_xa.result b/mysql-test/r/innodb_load_xa.result index 85e6d52c098..017bc7450bd 100644 --- a/mysql-test/r/innodb_load_xa.result +++ b/mysql-test/r/innodb_load_xa.result @@ -19,3 +19,5 @@ mysqld-bin.000001 # Query # # use `test`; insert t1 values (2) mysqld-bin.000001 # Query # # COMMIT drop table t1; uninstall plugin innodb; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown diff --git a/mysql-test/r/sp-group.result b/mysql-test/r/sp-group.result new file mode 100644 index 00000000000..9744bbee6b6 --- /dev/null +++ b/mysql-test/r/sp-group.result @@ -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; diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 7b421c624bf..9a72e4d12ba 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2145,6 +2145,24 @@ drop database mysqltest1; drop database mysqltest2; drop database mysqltest3; 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 # # MDEV-7220: Materialization strategy is not used for REPLACE ... SELECT diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 55b54ea4eb2..1484a111ff2 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2185,6 +2185,24 @@ drop database mysqltest1; drop database mysqltest2; drop database mysqltest3; 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 # # MDEV-7220: Materialization strategy is not used for REPLACE ... SELECT diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 22434790686..35607ea7f95 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -259,7 +259,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back create table t0 (n int); insert t0 select * from t1; set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); +insert into t0 select GET_LOCK("lock1",0); set autocommit=0; create table t2 (n int) engine=innodb; insert into t2 values (3); diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 10f3f5ddf2a..0ac4716f383 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -243,7 +243,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back create table t0 (n int); insert t0 select * from t1; set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); +insert into t0 select GET_LOCK("lock1",0); 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. set autocommit=0; @@ -293,7 +293,7 @@ master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Query # # use `test`; insert t0 select * from t1 master-bin.000001 # Query # # COMMIT master-bin.000001 # Gtid # # BEGIN GTID #-#-# -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 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb diff --git a/mysql-test/suite/innodb/r/innodb-fk-warnings.result b/mysql-test/suite/innodb/r/innodb-fk-warnings.result new file mode 100644 index 00000000000..a022f07936c --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-fk-warnings.result @@ -0,0 +1,112 @@ +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 "Duplicate key on write or update") +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 "Duplicate key on write or update") +Warning 1022 Can't write; duplicate key in table 't2' +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 "Foreign key constraint is incorrectly formed") +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 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 "Foreign key constraint is incorrectly formed") +show warnings; +Level Code Message +Error 1005 Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 "Foreign key constraint is incorrectly formed") +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 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +alter table t1 add foreign key(b) references t1(a); +ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 42000: Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match +show warnings; +Level Code Message +Error 1239 Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match +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 42000: Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match +show warnings; +Level Code Message +Error 1239 Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 "Foreign key constraint is incorrectly formed") +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 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +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 "Foreign key constraint is incorrectly formed") +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 "Foreign key constraint is incorrectly formed") +Warning 1215 Cannot add foreign key constraint +drop table t1; diff --git a/mysql-test/suite/innodb/r/innodb-fk.result b/mysql-test/suite/innodb/r/innodb-fk.result index 956dbce58ed..dee20d282f7 100644 --- a/mysql-test/suite/innodb/r/innodb-fk.result +++ b/mysql-test/suite/innodb/r/innodb-fk.result @@ -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 "Foreign key constraint is incorrectly formed") show warnings; 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 "Foreign key constraint is incorrectly formed") Warning 1215 Cannot add foreign key constraint CREATE TABLE t2 ( @@ -63,6 +65,7 @@ ALTER TABLE t2 ADD CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") show warnings; 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 `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed") Warning 1215 Cannot add foreign key constraint drop table t2; diff --git a/mysql-test/suite/innodb/r/innodb_uninstall.result b/mysql-test/suite/innodb/r/innodb_uninstall.result new file mode 100644 index 00000000000..2064269a02e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_uninstall.result @@ -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 diff --git a/mysql-test/suite/innodb/t/innodb-fk-warnings.test b/mysql-test/suite/innodb/t/innodb-fk-warnings.test new file mode 100644 index 00000000000..8de5e672c4a --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-fk-warnings.test @@ -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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +--error 1005 +alter table t2 add constraint b foreign key (b) references t2(b); +--replace_regex /#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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +--error 1005 +alter table t1 add constraint c1 foreign key (f1) references t11(f1); +--replace_regex /#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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +--error 1005 +create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb; +--replace_regex /#sql-[0-9a-f_]*`/#sql-temporary`/ +show warnings; +--replace_regex /#sql-[0-9a-f_]*`/#sql-temporary`/ +--error 1005 +alter table t1 add foreign key(b) references t1(a); +--replace_regex /#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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +--error 1239 +alter table t1 add foreign key(a,b) references t1(a); +--replace_regex /#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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +--error 1239 +alter table t1 add foreign key(a) references t1(a,b); +--replace_regex /#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 /#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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +show warnings; +--replace_regex /#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 /#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 /#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 /#sql-[0-9a-f_]*`/#sql-temporary`/ +show warnings; +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb_uninstall.opt b/mysql-test/suite/innodb/t/innodb_uninstall.opt new file mode 100644 index 00000000000..918855a7b01 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_uninstall.opt @@ -0,0 +1,3 @@ +--ignore-builtin-innodb +--loose-innodb + diff --git a/mysql-test/suite/innodb/t/innodb_uninstall.test b/mysql-test/suite/innodb/t/innodb_uninstall.test new file mode 100644 index 00000000000..34fc8345a02 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_uninstall.test @@ -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 + + diff --git a/mysql-test/suite/rpl/r/rpl_alter.result b/mysql-test/suite/rpl/r/rpl_alter.result index 2cffa70d778..7be3bc576f3 100644 --- a/mysql-test/suite/rpl/r/rpl_alter.result +++ b/mysql-test/suite/rpl/r/rpl_alter.result @@ -14,4 +14,109 @@ select * from mysqltest.t3; n 45 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 diff --git a/mysql-test/suite/rpl/t/rpl_alter.test b/mysql-test/suite/rpl/t/rpl_alter.test index 630197f8637..8b8bcfb3d26 100644 --- a/mysql-test/suite/rpl/t/rpl_alter.test +++ b/mysql-test/suite/rpl/t/rpl_alter.test @@ -15,4 +15,57 @@ drop database mysqltest; sync_slave_with_master; # 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 diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 42a30760a86..5550eebf1a3 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -821,3 +821,14 @@ FROM ( SELECT * FROM t2 ) AS sq2, t3 ORDER BY field; 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; diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 8b1f0ca108e..916a952fa3a 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -391,6 +391,11 @@ set optimizer_switch=@optimizer_switch_save; drop view v_merge, vm; 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 # GET_LOCK, RELEASE_LOCK, IS_USED_LOCK functions test diff --git a/mysql-test/t/innodb_load_xa.test b/mysql-test/t/innodb_load_xa.test index 52862151b22..9ecddde5d13 100644 --- a/mysql-test/t/innodb_load_xa.test +++ b/mysql-test/t/innodb_load_xa.test @@ -16,3 +16,6 @@ commit; --source include/show_binlog_events.inc drop table t1; uninstall plugin innodb; + +--source include/restart_mysqld.inc + diff --git a/mysql-test/t/mysql_upgrade.test b/mysql-test/t/mysql_upgrade.test index 8c641428353..a24ba0de2d9 100644 --- a/mysql-test/t/mysql_upgrade.test +++ b/mysql-test/t/mysql_upgrade.test @@ -15,7 +15,6 @@ file_exists $MYSQLD_DATADIR/mysql_upgrade_info; --echo Run it again - should say already completed --replace_result $MYSQL_SERVER_VERSION VERSION ---error 1 --exec $MYSQL_UPGRADE 2>&1 # It should have created a file in the MySQL Servers datadir diff --git a/mysql-test/t/sp-group.test b/mysql-test/t/sp-group.test new file mode 100644 index 00000000000..2083ac97595 --- /dev/null +++ b/mysql-test/t/sp-group.test @@ -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; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index c34c805f90c..cb4b5ea927f 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1841,8 +1841,23 @@ drop database mysqltest2; drop database mysqltest3; 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 --echo # --echo # MDEV-7220: Materialization strategy is not used for REPLACE ... SELECT --echo # diff --git a/sql/item.cc b/sql/item.cc index bffa7e2990d..934846c4815 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4363,18 +4363,23 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, Item_ident *resolved_item, Item_ident *mark_item) { - const char *db_name= (resolved_item->db_name ? - resolved_item->db_name : ""); - const char *table_name= (resolved_item->table_name ? - resolved_item->table_name : ""); + 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)) - return TRUE; + } + 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 ? + resolved_item->db_name : ""); + const char *table_name= (resolved_item->table_name ? + resolved_item->table_name : ""); push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED), db_name, (db_name[0] ? "." : ""), @@ -4382,7 +4387,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, resolved_item->field_name, current->select_number, last->select_number); } - return FALSE; + DBUG_RETURN(FALSE); } @@ -4831,7 +4836,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) non aggregated fields of the outer select. */ 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) { @@ -5247,9 +5252,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference) fixed= 1; if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !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; } mark_non_agg_field: @@ -6730,7 +6736,7 @@ Item_ref::Item_ref(Name_resolution_context *context_arg, /* 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(); } @@ -6774,7 +6780,7 @@ Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item, /* 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(); } @@ -6849,7 +6855,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(fixed == 0); 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); if (!(ref= resolve_ref_in_select_and_group(thd, this, @@ -6867,7 +6877,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { /* The current reference cannot be resolved in this query. */ my_error(ER_BAD_FIELD_ERROR,MYF(0), - this->full_name(), current_thd->where); + this->full_name(), thd->where); goto error; } @@ -7002,7 +7012,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; thd->change_item_tree(reference, fld); 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 the nest level of the enclosing set function : adjust the value of @@ -7019,7 +7029,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { /* The item was not a table field and not a reference */ my_error(ER_BAD_FIELD_ERROR, MYF(0), - this->full_name(), current_thd->where); + this->full_name(), thd->where); goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ diff --git a/sql/item.h b/sql/item.h index 171bdb05310..353c9e0f6bc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -657,7 +657,7 @@ public: */ uint name_length; /* Length of name */ uint decimals; - int8 marker; + int marker; bool maybe_null; /* If item may be null */ bool in_rollup; /* If used in GROUP BY list of a query with ROLLUP */ @@ -3356,6 +3356,7 @@ class Item_ref :public Item_ident { protected: void set_properties(); + bool set_properties_only; // the item doesn't need full fix_fields public: enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF }; Field *result_field; /* Save result here */ @@ -3365,7 +3366,7 @@ public: const char *db_arg, const char *table_name_arg, const char *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: A) *item = NULL @@ -3388,7 +3389,7 @@ public: /* Constructor need to process subselect with temporary tables (see 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 real_type() const { return ref ? (*ref)->type() : REF_ITEM; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 0dabd06d423..4d7e10b6577 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4268,6 +4268,24 @@ longlong Item_func_get_lock::val_int() if (thd->slave_thread) { null_value= 0; + } + + 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, Sql_condition::WARN_LEVEL_WARN, + ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE), + "timeout", buf, "get_lock"); + null_value= 1; + DBUG_RETURN(0); + } + { + null_value= 0; DBUG_RETURN(1); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a0fca36452c..fe2352f3008 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -477,6 +477,7 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent, { List_iterator_fast<Ref_to_outside> it(upper_refs); Ref_to_outside *upper; + DBUG_ENTER("recalc_used_tables"); used_tables_cache= 0; while ((upper= it++)) @@ -536,6 +537,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 const_tables_cache. */ + DBUG_PRINT("exit", ("used_tables_cache: %llx", used_tables_cache)); + DBUG_VOID_RETURN; } @@ -2002,7 +2005,7 @@ bool Item_allany_subselect::is_maxmin_applicable(JOIN *join) */ bool -Item_in_subselect::create_single_in_to_exists_cond(JOIN * join, +Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, Item **where_item, Item **having_item) { @@ -2012,7 +2015,6 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN * join, during JOIN::optimize: this->tmp_having= this->having; this->having= 0; */ Item* join_having= join->having ? join->having : join->tmp_having; - DBUG_ENTER("Item_in_subselect::create_single_in_to_exists_cond"); *where_item= NULL; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 1c5682417a5..29dc94eb5af 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3527,9 +3527,16 @@ bool Item_func_group_concat::setup(THD *thd) "all_fields". The resulting field list is used as input to create tmp table columns. */ - if (arg_count_order && - setup_order(thd, args, context->table_list, list, all_fields, *order)) - DBUG_RETURN(TRUE); + if (arg_count_order) + { + uint n_elems= arg_count_order + all_fields.elements; + ref_pointer_array= static_cast<Item**>(thd->alloc(sizeof(Item*) * n_elems)); + memcpy(ref_pointer_array, args, arg_count * sizeof(Item*)); + if (!ref_pointer_array || + 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); tmp_table_param->force_copy_fields= force_copy_fields; diff --git a/sql/item_sum.h b/sql/item_sum.h index d28c654c438..09a20487226 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1394,6 +1394,7 @@ class Item_func_group_concat : public Item_sum String *separator; TREE tree_base; TREE *tree; + Item **ref_pointer_array; /** If DISTINCT is used with this GROUP_CONCAT, this member is used to filter diff --git a/sql/log.cc b/sql/log.cc index 50c036ef650..d22333a0f49 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4129,6 +4129,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) int error; char *to_purge_if_included= NULL; inuse_relaylog *ir; + ulonglong log_space_reclaimed= 0; DBUG_ENTER("purge_first_log"); DBUG_ASSERT(is_open()); @@ -4200,17 +4201,13 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) 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, - 0, 0, &rli->log_space_total); - mysql_mutex_unlock(&rli->log_space_lock); + 0, 0, &log_space_reclaimed); - /* - Ok to broadcast after the critical region as there is no risk of - the mutex being destroyed by this thread later - this helps save - context switches - */ + mysql_mutex_lock(&rli->log_space_lock); + rli->log_space_total-= log_space_reclaimed; 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 @@ -4259,8 +4256,8 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads @param need_mutex @param need_update_threads If we want to update the log coordinates of all threads. False for relay logs, true otherwise. - @param freed_log_space If not null, decrement this variable of - the amount of log space freed + @param reclaimeed_log_space If not null, increment this variable to + the amount of log space freed @note If any of the logs before the deleted one is in use, @@ -4276,10 +4273,10 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads */ int MYSQL_BIN_LOG::purge_logs(const char *to_log, - bool included, - bool need_mutex, - bool need_update_threads, - ulonglong *decrease_log_space) + bool included, + bool need_mutex, + bool need_update_threads, + ulonglong *reclaimed_space) { int error= 0; bool exit_loop= 0; @@ -4343,7 +4340,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, err: /* Read each entry from purge_index_file and delete the 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" " that would be purged."); close_purge_index_file(); @@ -4448,7 +4445,7 @@ int MYSQL_BIN_LOG::register_create_index_entry(const char *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) { DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry"); @@ -4568,8 +4565,8 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, DBUG_PRINT("info",("purging %s",log_info.log_file_name)); if (!my_delete(log_info.log_file_name, MYF(0))) { - if (decrease_log_space) - *decrease_log_space-= s.st_size; + if (reclaimed_space) + *reclaimed_space+= s.st_size; } else { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c9682e15eae..7cb3072e7c4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2768,6 +2768,16 @@ void unlink_thd(THD *thd) sync feature has been shut down at this point. */ 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); delete thd; diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index 09e221e9bd5..917a9d11b5a 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -39,8 +39,6 @@ typedef struct Trans_binlog_info { char log_file[FN_REFLEN]; } Trans_binlog_info; -static pthread_key(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); - int get_user_var_int(const char *name, long long int *value, int *null_value) { @@ -144,13 +142,6 @@ int delegates_init() } #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; } @@ -196,27 +187,27 @@ void delegates_destroy() int Trans_delegate::after_commit(THD *thd, bool all) { Trans_param param; + Trans_binlog_info *log_info; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); + int ret= 0; param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; - Trans_binlog_info *log_info= - my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); + log_info= thd->semisync_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; - int ret= 0; FOREACH_OBSERVER(ret, after_commit, false, (¶m)); /* 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) { - my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); - my_free(log_info); + log_info->log_file[0]= 0; + log_info->log_pos= 0; } return ret; } @@ -224,27 +215,27 @@ int Trans_delegate::after_commit(THD *thd, bool all) int Trans_delegate::after_rollback(THD *thd, bool all) { Trans_param param; + Trans_binlog_info *log_info; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); + int ret= 0; param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; - Trans_binlog_info *log_info= - my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); - - param.log_file= log_info ? log_info->log_file : 0; + log_info= thd->semisync_info; + + 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; - int ret= 0; FOREACH_OBSERVER(ret, after_rollback, false, (¶m)); /* 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) { - my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); - my_free(log_info); + log_info->log_file[0]= 0; + log_info->log_pos= 0; } return ret; } @@ -255,25 +246,24 @@ int Binlog_storage_delegate::after_flush(THD *thd, bool synced) { Binlog_storage_param param; + Trans_binlog_info *log_info; uint32 flags=0; + int ret= 0; + if (synced) flags |= BINLOG_STORAGE_IS_SYNCED; - Trans_binlog_info *log_info= - my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); - - if (!log_info) + if (!(log_info= thd->semisync_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; - 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)); log_info->log_pos = log_pos; - int ret= 0; FOREACH_OBSERVER(ret, after_flush, false, (¶m, log_info->log_file, log_info->log_pos, flags)); return ret; diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 6a8dee229bb..27a7a0478b6 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -947,6 +947,7 @@ TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, { Create_field *field_def= (Create_field*) alloc_root(thd->mem_root, sizeof(Create_field)); + bool unsigned_flag= 0; if (field_list.push_back(field_def)) DBUG_RETURN(NULL); @@ -956,8 +957,7 @@ TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, uint32 max_length= max_display_length_for_field(type(col), field_metadata(col)); - switch(type(col)) - { + switch(type(col)) { int precision; case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: @@ -996,6 +996,18 @@ TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, pack_length= field_metadata(col) & 0x00ff; 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: break; } @@ -1003,12 +1015,13 @@ TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," " maybe_null: %d, unsigned_flag: %d, pack_length: %u", binlog_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), max_length, decimals, TRUE, // maybe_null - FALSE, // unsigned_flag + unsigned_flag, pack_length); field_def->charset= target_table->field[col]->charset(); field_def->interval= interval; diff --git a/sql/slave.cc b/sql/slave.cc index dde57bc16fb..0243272c443 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4523,9 +4523,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->parallel.reset(); //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; - mysql_mutex_unlock(&rli->log_space_lock); serial_rgi->gtid_sub_id= 0; serial_rgi->gtid_pending= false; @@ -6626,14 +6624,8 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size) 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_mutex_unlock(&rli->log_space_lock); // Note that wait_for_update_relay_log unlocks lock_log ! rli->relay_log.wait_for_update_relay_log(rli->sql_driver_thd); // re-acquire data lock since we released it earlier diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 13b8625ebe6..643ad4b41cb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6583,6 +6583,7 @@ find_field_in_tables(THD *thd, Item_ident *item, if (item->cached_table) { + DBUG_PRINT("info", ("using cached table")); /* This shortcut is used by prepared statements. We assume that TABLE_LIST *first_table is not changed during query execution (which diff --git a/sql/sql_class.cc b/sql/sql_class.cc index cf0c4a1b84f..d2221d210e0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -960,6 +960,7 @@ THD::THD() file_id = 0; query_id= 0; query_name_consts= 0; + semisync_info= 0; db_charset= global_system_variables.collation_database; bzero(ha_data, sizeof(ha_data)); mysys_var=0; @@ -1395,6 +1396,7 @@ void THD::init(void) bzero((char *) &org_status_var, sizeof(org_status_var)); start_bytes_received= 0; last_commit_gtid.seq_no= 0; + status_in_global= 0; if (variables.sql_log_bin) variables.option_bits|= OPTION_BIN_LOG; @@ -1500,6 +1502,7 @@ void THD::change_user(void) cleanup(); reset_killed(); cleanup_done= 0; + status_in_global= 0; init(); stmt_map.reset(); my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, @@ -1630,6 +1633,7 @@ THD::~THD() mysql_audit_free_thd(this); if (rgi_slave) rgi_slave->cleanup_after_session(); + my_free(semisync_info); #endif free_root(&main_mem_root, MYF(0)); diff --git a/sql/sql_class.h b/sql/sql_class.h index a8d8444571e..f577935f545 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -64,7 +64,6 @@ class Reprepare_observer; class Relay_log_info; struct rpl_group_info; class Rpl_filter; - class Query_log_event; class Load_log_event; class Slave_log_event; @@ -75,6 +74,7 @@ class Parser_state; class Rows_log_event; class Sroutine_hash_entry; class user_var_entry; +struct Trans_binlog_info; class rpl_io_thread_info; class rpl_sql_thread_info; @@ -1959,6 +1959,9 @@ public: */ const char *where; + /* Needed by MariaDB semi sync replication */ + Trans_binlog_info *semisync_info; + ulong client_capabilities; /* What the client supports */ ulong max_client_packet_length; @@ -2027,11 +2030,11 @@ public: /* Do not set socket timeouts for wait_timeout (used with threadpool) */ bool skip_wait_timeout; - /* container for handler's private per-connection data */ - Ha_data ha_data[MAX_HA]; - 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 derived table or a view. @@ -2040,6 +2043,9 @@ public: bool save_prep_leaf_list; + /* container for handler's private per-connection data */ + Ha_data ha_data[MAX_HA]; + #ifndef MYSQL_CLIENT binlog_cache_mngr * binlog_setup_trx_data(); @@ -3687,6 +3693,8 @@ public: { mysql_mutex_lock(&LOCK_status); 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); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2026d5f5059..3f3bc40ad59 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1910,7 +1910,6 @@ void st_select_lex::init_select() with_sum_func= 0; is_correlated= 0; cur_pos_in_select_list= UNDEF_POS; - non_agg_fields.empty(); cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); insert_tables= 0; @@ -1918,6 +1917,7 @@ void st_select_lex::init_select() m_non_agg_field_used= false; m_agg_func_used= false; name_visibility_map= 0; + join= 0; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index dcd8ddfce91..3d008723f66 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -823,8 +823,6 @@ public: bool no_wrap_view_item; /* exclude this select from check of unique_table() */ 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 */ int cur_pos_in_select_list; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e0f560f0b3a..aa9a3f2da0e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5185,6 +5185,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, KEY_FIELD *key_fields, *end, *field; uint sz; uint m= MY_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; sel->cond_count= 0; @@ -5231,7 +5233,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, sz= MY_MAX(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))* ((sel->cond_count*2 + sel->between_count)*m+1); if (!(key_fields=(KEY_FIELD*) thd->alloc(sz))) - return TRUE; /* purecov: inspected */ + DBUG_RETURN(TRUE); /* purecov: inspected */ and_level= 0; field= end= key_fields; *sargables= (SARGABLE_PARAM *) key_fields + @@ -5241,7 +5243,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64, MYF(MY_THREAD_SPECIFIC))) - return TRUE; + DBUG_RETURN(TRUE); if (cond) { @@ -5291,16 +5293,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, for ( ; field != end ; field++) { if (add_key_part(keyuse,field)) - return TRUE; + DBUG_RETURN(TRUE); } if (select_lex->ftfunc_list->elements) { if (add_ft_keys(keyuse,join_tab,cond,normal_tables)) - return TRUE; + DBUG_RETURN(TRUE); } - return FALSE; + DBUG_RETURN(FALSE); } @@ -21544,7 +21546,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Item_field *field; int cur_pos_in_select_list= 0; 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++; while (field && (item=li++)) diff --git a/sql/sql_select.h b/sql/sql_select.h index 5aa29715dc3..61157130f50 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -934,6 +934,9 @@ public: Item *pre_sort_idx_pushed_cond; 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 either: @@ -1326,6 +1329,7 @@ public: all_fields= fields_arg; if (&fields_list != &fields_arg) /* Avoid valgrind-warning */ fields_list= fields_arg; + non_agg_fields.empty(); bzero((char*) &keyuse,sizeof(keyuse)); tmp_table_param.init(); tmp_table_param.end_write_records= HA_POS_ERROR; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2413cb5ba53..103d39e7fd0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3512,7 +3512,10 @@ void calc_sum_of_all_status(STATUS_VAR *to) /* Add to this status from existing threads */ while ((tmp= it++)) - add_to_status(to, &tmp->status_var); + { + if (!tmp->status_in_global) + add_to_status(to, &tmp->status_var); + } mysql_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 82abc861ec4..d73b6db830e 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -222,7 +222,7 @@ TEST_join(JOIN *join) #define FT_KEYPART (MAX_FIELDS+10) -void print_keyuse(KEYUSE *keyuse) +static void print_keyuse(KEYUSE *keyuse) { char buff[256]; char buf2[64]; @@ -240,14 +240,11 @@ void print_keyuse(KEYUSE *keyuse) else fieldname= key_info->key_part[keyuse->keypart].field->field_name; ll2str(keyuse->used_tables, buf2, 16, 0); - DBUG_LOCK_FILE; fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s " "ref_table_rows: %lu keypart_map: %0lx\n", keyuse->table->alias.c_ptr(), fieldname, str.ptr(), (uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows, (ulong) keyuse->keypart_map); - DBUG_UNLOCK_FILE; - //key_part_map keypart_map; --?? there can be several? } @@ -256,9 +253,9 @@ void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array) { DBUG_LOCK_FILE; fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements); - DBUG_UNLOCK_FILE; for(uint i=0; i < keyuse_array->elements; i++) print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i)); + DBUG_UNLOCK_FILE; } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 77a3b1eec8f..a316fbad726 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1029,7 +1029,6 @@ bool st_select_lex::cleanup() { error= (bool) ((uint) error | (uint) lex_unit->cleanup()); } - non_agg_fields.empty(); inner_refs_list.empty(); exclude_from_table_unique_test= FALSE; DBUG_RETURN(error); @@ -1040,6 +1039,7 @@ void st_select_lex::cleanup_all_joins(bool full) { SELECT_LEX_UNIT *unit; SELECT_LEX *sl; + DBUG_ENTER("st_select_lex::cleanup_all_joins"); if (join) join->cleanup(full); @@ -1047,6 +1047,7 @@ void st_select_lex::cleanup_all_joins(bool full) for (unit= first_inner_unit(); unit; unit= unit->next_unit()) for (sl= unit->first_select(); sl; sl= sl->next_select()) sl->cleanup_all_joins(full); + DBUG_VOID_RETURN; } diff --git a/sql/table.cc b/sql/table.cc index 053269ab435..cdc7b4381cd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5271,7 +5271,7 @@ Item *Field_iterator_table::create_item(THD *thd) if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !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; select->set_non_agg_field_used(true); } diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 30523ff2af4..ed6eeb79a04 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1562,12 +1562,111 @@ dict_create_add_foreign_field_to_dictionary( } /********************************************************************//** +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 = (char *)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 = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + char* fieldbuf2 = (char *)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 foreign key definition to the data dictionary tables. @return error code or DB_SUCCESS */ UNIV_INTERN dberr_t dict_create_add_foreign_to_dictionary( /*==================================*/ + dict_table_t* table, /*!< in: table */ const char* name, /*!< in: table name */ const dict_foreign_t* foreign,/*!< in: foreign key */ trx_t* trx) /*!< in/out: dictionary transaction */ @@ -1595,6 +1694,29 @@ dict_create_add_foreign_to_dictionary( 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((dict_foreign_t*)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); } @@ -1603,6 +1725,26 @@ dict_create_add_foreign_to_dictionary( i, name, foreign, trx); 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((dict_foreign_t*)foreign, trx); + dict_foreign_def_get_fields((dict_foreign_t*)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); } @@ -1649,7 +1791,7 @@ dict_create_add_foreigns_to_dictionary( foreign = *it; ut_ad(foreign->id != NULL); - error = dict_create_add_foreign_to_dictionary(table->name, + error = dict_create_add_foreign_to_dictionary((dict_table_t*)table, table->name, foreign, trx); if (error != DB_SUCCESS) { diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index b866f44cc54..c7ffe071e99 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -3259,6 +3259,11 @@ dict_index_build_internal_fts( } /*====================== FOREIGN KEY PROCESSING ========================*/ +#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 + /*********************************************************************//** Checks if a table is referenced by foreign keys. @return TRUE if table is referenced by a foreign key */ @@ -3413,15 +3418,26 @@ dict_foreign_find_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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; ut_ad(mutex_own(&dict_sys->mutex)); + if (error) { + *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND; + } + index = dict_table_get_first_index(table); while (index != NULL) { @@ -3431,7 +3447,12 @@ dict_foreign_find_index( && dict_foreign_qualify_index( table, col_names, columns, n_cols, index, types_idx, - check_charsets, check_null)) { + check_charsets, check_null, + error, err_col_no,err_index)) { + if (error) { + *error = DB_SUCCESS; + } + return(index); } @@ -3536,11 +3557,15 @@ dict_foreign_add_to_cache( } if (ref_table && !for_in_cache->referenced_table) { + ulint index_error; + ulint err_col; + dict_index_t *err_index=NULL; + index = dict_foreign_find_index( ref_table, NULL, for_in_cache->referenced_col_names, 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 && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -3572,6 +3597,10 @@ dict_foreign_add_to_cache( } if (for_table && !for_in_cache->foreign_table) { + ulint index_error; + ulint err_col; + dict_index_t *err_index=NULL; + index = dict_foreign_find_index( for_table, col_names, for_in_cache->foreign_col_names, @@ -3579,7 +3608,8 @@ dict_foreign_add_to_cache( for_in_cache->referenced_index, check_charsets, for_in_cache->type & (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 && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -4239,6 +4269,8 @@ static void 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* start_of_latest_foreign, /*!< in: start of the foreign key clause @@ -4251,12 +4283,102 @@ dict_foreign_report_syntax_err( mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nSyntax error close to:\n%s\n", - start_of_latest_foreign, ptr); + fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr); 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 key constraints declared in the string. This function should be called after the indexes for a table have been created. Each foreign key constraint must @@ -4284,16 +4406,21 @@ dict_create_foreign_constraints_low( DB_CANNOT_ADD_CONSTRAINT if any foreign keys are found. */ { - dict_table_t* table; - dict_table_t* referenced_table; - dict_table_t* table_to_alter; + dict_table_t* table = NULL; + dict_table_t* referenced_table = NULL; + dict_table_t* table_to_alter = NULL; + dict_table_t* table_to_create = NULL; ulint highest_id_so_far = 0; ulint number = 1; - dict_index_t* index; - dict_foreign_t* foreign; + dict_index_t* index = NULL; + dict_foreign_t* foreign = NULL; const char* ptr = sql_string; const char* start_of_latest_foreign = sql_string; + const char* start_of_latest_set = NULL; FILE* ef = dict_foreign_err_file; + ulint index_error = DB_SUCCESS; + dict_index_t* err_index = NULL; + ulint err_col; const char* constraint_name; ibool success; dberr_t error; @@ -4306,37 +4433,80 @@ dict_create_foreign_constraints_low( ulint n_on_updates; const dict_col_t*columns[500]; const char* column_names[500]; + const char* ref_column_names[500]; const char* referenced_table_name; dict_foreign_set local_fk_set; dict_foreign_set_free local_fk_set_free(local_fk_set); + const char* create_table_name; + const char* orig; + char create_name[MAX_TABLE_NAME_LEN + 1]; + char operation[8]; ut_ad(!srv_read_only_mode); ut_ad(mutex_own(&(dict_sys->mutex))); table = dict_table_get_low(name); + /* First check if we are actually doing an ALTER TABLE, and in that + case look for the table being altered */ + orig = ptr; + 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) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, - "Cannot find the table in the internal" - " data dictionary of InnoDB.\n" - "Create table statement:\n%s\n", sql_string); + dict_foreign_error_report_low(ef, create_name); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%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, start_of_latest_foreign); 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); } - /* 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); - + /* If not alter table jump to loop */ if (!success) { goto loop; } + orig = ptr; ptr = dict_accept(cs, ptr, "TABLE", &success); if (!success) { @@ -4346,13 +4516,40 @@ dict_create_foreign_constraints_low( /* 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, &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) { - fprintf(stderr, - "InnoDB: Error: could not find" - " the table being ALTERED in:\n%s\n", - sql_string); + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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); } @@ -4389,6 +4586,7 @@ loop: of the constraint to system tables. */ ptr = ptr1; + orig = ptr; ptr = dict_accept(cs, ptr, "CONSTRAINT", &success); ut_a(success); @@ -4419,6 +4617,19 @@ loop: if so, immediately reject the command if the table is a temporary one. For now, this kludge will work. */ if (reject_fks && !local_fk_set.empty()) { + 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); } @@ -4444,6 +4655,7 @@ loop: start_of_latest_foreign = ptr; + orig = ptr; ptr = dict_accept(cs, ptr, "FOREIGN", &success); if (!success) { @@ -4454,6 +4666,7 @@ loop: goto loop; } + orig = ptr; ptr = dict_accept(cs, ptr, "KEY", &success); if (!success) { @@ -4479,6 +4692,7 @@ loop: } } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { @@ -4488,8 +4702,17 @@ loop: ptr = dict_skip_word(cs, ptr, &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); - return(DB_CANNOT_ADD_CONSTRAINT); + "%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); } } else { @@ -4516,15 +4739,26 @@ loop: /* Scan the columns in the first list */ col_loop1: ut_a(i < (sizeof column_names) / sizeof *column_names); + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, table, columns + i, heap, column_names + i); if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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); + 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); } @@ -4536,11 +4770,22 @@ col_loop1: goto col_loop1; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success) { 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); } @@ -4551,27 +4796,41 @@ col_loop1: set to 0 */ index = dict_foreign_find_index( - table, NULL, column_names, i, NULL, TRUE, FALSE); + table, NULL, column_names, i, + NULL, TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { 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); - ut_print_name(ef, NULL, TRUE, name); + ut_print_name(ef, NULL, TRUE, create_name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" "See " REFMAN "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, table, ef); - return(DB_CHILD_NO_INDEX); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } + + orig = ptr; ptr = dict_accept(cs, ptr, "REFERENCES", &success); if (!success || !my_isspace(cs, *ptr)) { 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); } @@ -4640,21 +4899,46 @@ col_loop1: checking of foreign key constraints! */ 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); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve table name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.\n", + operation, create_name, buf, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } @@ -4662,34 +4946,54 @@ col_loop1: i = 0; col_loop2: + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, - heap, column_names + i); + heap, ref_column_names + i); i++; if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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); + 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); } + orig = ptr; ptr = dict_accept(cs, ptr, ",", &success); if (success) { goto col_loop2; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success || foreign->n_fields != i) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } @@ -4699,6 +5003,7 @@ col_loop2: scan_on_conditions: /* Loop here as long as we can find ON ... conditions */ + start_of_latest_set = ptr; ptr = dict_accept(cs, ptr, "ON", &success); if (!success) { @@ -4706,15 +5011,27 @@ scan_on_conditions: goto try_find_index; } + orig = ptr; ptr = dict_accept(cs, ptr, "DELETE", &success); if (!success) { + orig = ptr; ptr = dict_accept(cs, ptr, "UPDATE", &success); if (!success) { 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); } @@ -4725,12 +5042,14 @@ scan_on_conditions: n_on_deletes++; } + orig = ptr; ptr = dict_accept(cs, ptr, "RESTRICT", &success); if (success) { goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "CASCADE", &success); if (success) { @@ -4743,14 +5062,25 @@ scan_on_conditions: goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "NO", &success); if (success) { + orig = ptr; ptr = dict_accept(cs, ptr, "ACTION", &success); if (!success) { 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); } @@ -4764,38 +5094,69 @@ scan_on_conditions: goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "SET", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } + orig = ptr; ptr = dict_accept(cs, ptr, "NULL", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } for (j = 0; j < foreign->n_fields; j++) { if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) & 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 if the column is not allowed to be NULL! */ mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have defined a SET NULL condition" - " though some of the\n" - "columns are defined as NOT NULL.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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.\n", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); 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); + return(DB_CANNOT_ADD_CONSTRAINT); } } @@ -4813,11 +5174,20 @@ try_find_index: /* It is an error to define more than 1 action */ mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have twice an ON DELETE clause" - " or twice an ON UPDATE clause.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " 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. 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); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -4829,12 +5199,12 @@ try_find_index: if (referenced_table) { index = dict_foreign_find_index(referenced_table, NULL, - column_names, i, + ref_column_names, i, foreign->foreign_index, - TRUE, FALSE); + TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { 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" "Cannot find an index in the" " referenced table where the\n" @@ -4852,9 +5222,13 @@ try_find_index: "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", 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); - return(DB_PARENT_NO_INDEX); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { ut_a(trx->check_foreigns == FALSE); @@ -4873,11 +5247,12 @@ try_find_index: for (i = 0; i < foreign->n_fields; i++) { foreign->referenced_col_names[i] - = mem_heap_strdup(foreign->heap, column_names[i]); + = mem_heap_strdup(foreign->heap, ref_column_names[i]); } goto loop; } + /************************************************************************** Determines whether a string starts with the specified keyword. @return TRUE if str starts with keyword */ @@ -6029,7 +6404,8 @@ dict_foreign_replace_index( foreign->foreign_table, col_names, foreign->foreign_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); if (new_index) { ut_ad(new_index->table == index->table); ut_ad(!new_index->to_be_dropped); @@ -6053,7 +6429,8 @@ dict_foreign_replace_index( foreign->referenced_table, NULL, foreign->referenced_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); /* There must exist an alternative index, since this must have been checked earlier. */ if (new_index) { @@ -6622,10 +6999,17 @@ dict_foreign_qualify_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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 */ { if (dict_index_get_n_fields(index) < n_cols) { return(false); @@ -6642,11 +7026,21 @@ dict_foreign_qualify_index( if (field->prefix_len != 0) { /* We do not accept column prefix indexes here */ + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } return(false); } if (check_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 = (dict_index_t*)index; + } return(false); } @@ -6662,6 +7056,12 @@ dict_foreign_qualify_index( dict_index_get_nth_col(index, i), dict_index_get_nth_col(types_idx, i), check_charsets)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } + return(false); } } diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index e830a8430b7..12f9516b938 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -417,7 +417,8 @@ dict_mem_table_col_rename_low( dict_index_t* new_index = dict_foreign_find_index( foreign->foreign_table, NULL, foreign->foreign_col_names, - foreign->n_fields, NULL, true, false); + foreign->n_fields, NULL, true, false, + NULL, NULL, NULL); /* There must be an equivalent index in this case. */ ut_ad(new_index != NULL); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7b57f072493..4239aaf30b0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2125,6 +2125,7 @@ check_trx_exists( if (trx == NULL) { trx = innobase_trx_allocate(thd); + thd_set_ha_data(thd, innodb_hton_ptr, trx); } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { mem_analyze_corruption(trx); ut_error; @@ -17633,3 +17634,29 @@ ib_warn_row_too_big(const dict_table_t* table) " ROW_FORMAT=COMPRESSED ": "" , prefix ? DICT_MAX_FIXED_COL_LEN : 0); } + +/********************************************************************//** +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 */ + ...) +{ + 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, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); +} diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 63bd70e89a3..7c79ea9cd35 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -824,7 +824,8 @@ innobase_find_fk_index( if (!(index->type & DICT_FTS) && dict_foreign_qualify_index( table, col_names, columns, n_cols, - index, NULL, true, 0)) { + index, NULL, true, 0, + NULL, NULL, NULL)) { for (ulint i = 0; i < n_drop_index; i++) { if (index == drop_index[i]) { /* Skip to-be-dropped indexes. */ @@ -1014,7 +1015,8 @@ innobase_get_foreign_key_info( referenced_table, 0, referenced_column_names, i, index, - TRUE, FALSE); + TRUE, FALSE, + NULL, NULL, NULL); DBUG_EXECUTE_IF( "innodb_test_no_reference_idx", @@ -3317,7 +3319,8 @@ innobase_check_foreign_key_index( foreign->referenced_col_names, foreign->n_fields, index, /*check_charsets=*/TRUE, - /*check_null=*/FALSE) + /*check_null=*/FALSE, + NULL, NULL, NULL) && !innobase_find_equiv_index( foreign->referenced_col_names, foreign->n_fields, @@ -3345,7 +3348,8 @@ innobase_check_foreign_key_index( foreign->foreign_col_names, foreign->n_fields, index, /*check_charsets=*/TRUE, - /*check_null=*/FALSE) + /*check_null=*/FALSE, + NULL, NULL, NULL) && !innobase_find_equiv_index( foreign->foreign_col_names, foreign->n_fields, @@ -4789,7 +4793,8 @@ innobase_update_foreign_try( fk->n_fields, fk->referenced_index, TRUE, fk->type & (DICT_FOREIGN_ON_DELETE_SET_NULL - | DICT_FOREIGN_ON_UPDATE_SET_NULL)); + | DICT_FOREIGN_ON_UPDATE_SET_NULL), + NULL, NULL, NULL); if (!fk->foreign_index) { my_error(ER_FK_INCORRECT_OPTION, MYF(0), table_name, fk->id); @@ -4801,7 +4806,7 @@ innobase_update_foreign_try( names, while the columns in ctx->old_table have not been renamed yet. */ error = dict_create_add_foreign_to_dictionary( - ctx->old_table->name, fk, trx); + (dict_table_t*)ctx->old_table,ctx->old_table->name, fk, trx); DBUG_EXECUTE_IF( "innodb_test_cannot_add_fk_system", diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index 67eab9058da..5628af6eb4d 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -110,6 +110,17 @@ UNIV_INTERN dberr_t 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 */ + /********************************************************************//** Generate a foreign key constraint name when it was not named by the user. A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER, @@ -174,11 +185,22 @@ UNIV_INTERN dberr_t dict_create_add_foreign_to_dictionary( /*==================================*/ + dict_table_t* table, /*!< in: table */ const char* name, /*!< in: table name */ const dict_foreign_t* foreign,/*!< in: foreign key */ trx_t* trx) /*!< in/out: dictionary transaction */ __attribute__((nonnull, warn_unused_result)); +/********************************************************************//** +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 */ + /* Table create node structure */ struct tab_node_t{ que_common_t common; /*!< node type: QUE_NODE_TABLE_CREATE */ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 9e007809471..ef7b6580134 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -580,10 +580,18 @@ dict_foreign_find_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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 */ + __attribute__((nonnull(1,3), warn_unused_result)); /**********************************************************************//** Returns a column's name. @@ -675,10 +683,17 @@ dict_foreign_qualify_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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 */ __attribute__((nonnull(1,3), warn_unused_result)); #ifdef UNIV_DEBUG /********************************************************************//** diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 20409f85e0c..eef36110999 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -615,5 +615,14 @@ innobase_convert_to_filename_charset( const char* from, /* in: identifier to convert */ 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 /* HA_INNODB_PROTOTYPES_H */ diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc index 30523ff2af4..1947786c8e3 100644 --- a/storage/xtradb/dict/dict0crea.cc +++ b/storage/xtradb/dict/dict0crea.cc @@ -1562,12 +1562,111 @@ dict_create_add_foreign_field_to_dictionary( } /********************************************************************//** +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 = (char *)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 = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + char* fieldbuf2 = (char *)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 foreign key definition to the data dictionary tables. @return error code or DB_SUCCESS */ UNIV_INTERN dberr_t dict_create_add_foreign_to_dictionary( /*==================================*/ + dict_table_t* table, const char* name, /*!< in: table name */ const dict_foreign_t* foreign,/*!< in: foreign key */ trx_t* trx) /*!< in/out: dictionary transaction */ @@ -1594,6 +1693,28 @@ dict_create_add_foreign_to_dictionary( , name, foreign->id, trx); 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((dict_foreign_t*)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); } @@ -1603,6 +1724,26 @@ dict_create_add_foreign_to_dictionary( i, name, foreign, trx); 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((dict_foreign_t*)foreign, trx); + dict_foreign_def_get_fields((dict_foreign_t*)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); } @@ -1649,7 +1790,7 @@ dict_create_add_foreigns_to_dictionary( foreign = *it; ut_ad(foreign->id != NULL); - error = dict_create_add_foreign_to_dictionary(table->name, + error = dict_create_add_foreign_to_dictionary((dict_table_t*)table, table->name, foreign, trx); if (error != DB_SUCCESS) { diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index 8d8347ca726..5791890056d 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -3263,6 +3263,11 @@ dict_index_build_internal_fts( } /*====================== FOREIGN KEY PROCESSING ========================*/ +#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 + /*********************************************************************//** Checks if a table is referenced by foreign keys. @return TRUE if table is referenced by a foreign key */ @@ -3417,15 +3422,26 @@ dict_foreign_find_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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; ut_ad(mutex_own(&dict_sys->mutex)); + if (error) { + *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND; + } + index = dict_table_get_first_index(table); while (index != NULL) { @@ -3435,7 +3451,8 @@ dict_foreign_find_index( && dict_foreign_qualify_index( table, col_names, columns, n_cols, index, types_idx, - check_charsets, check_null)) { + check_charsets, check_null, + error, err_col_no,err_index)) { return(index); } @@ -3544,7 +3561,7 @@ dict_foreign_add_to_cache( ref_table, NULL, for_in_cache->referenced_col_names, for_in_cache->n_fields, for_in_cache->foreign_index, - check_charsets, false); + check_charsets, false, NULL, NULL, NULL); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -3576,6 +3593,10 @@ dict_foreign_add_to_cache( } if (for_table && !for_in_cache->foreign_table) { + ulint index_error; + ulint err_col; + dict_index_t *err_index=NULL; + index = dict_foreign_find_index( for_table, col_names, for_in_cache->foreign_col_names, @@ -3583,7 +3604,8 @@ dict_foreign_add_to_cache( for_in_cache->referenced_index, check_charsets, for_in_cache->type & (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 && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -4243,6 +4265,8 @@ static void 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* start_of_latest_foreign, /*!< in: start of the foreign key clause @@ -4255,12 +4279,102 @@ dict_foreign_report_syntax_err( mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nSyntax error close to:\n%s\n", - start_of_latest_foreign, ptr); + fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr); 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 key constraints declared in the string. This function should be called after the indexes for a table have been created. Each foreign key constraint must @@ -4288,16 +4402,21 @@ dict_create_foreign_constraints_low( DB_CANNOT_ADD_CONSTRAINT if any foreign keys are found. */ { - dict_table_t* table; - dict_table_t* referenced_table; - dict_table_t* table_to_alter; + dict_table_t* table = NULL; + dict_table_t* referenced_table = NULL; + dict_table_t* table_to_alter = NULL; + dict_table_t* table_to_create = NULL; ulint highest_id_so_far = 0; ulint number = 1; - dict_index_t* index; - dict_foreign_t* foreign; + dict_index_t* index = NULL; + dict_foreign_t* foreign = NULL; const char* ptr = sql_string; const char* start_of_latest_foreign = sql_string; + const char* start_of_latest_set = NULL; FILE* ef = dict_foreign_err_file; + ulint index_error = DB_SUCCESS; + dict_index_t* err_index = NULL; + ulint err_col; const char* constraint_name; ibool success; dberr_t error; @@ -4310,37 +4429,80 @@ dict_create_foreign_constraints_low( ulint n_on_updates; const dict_col_t*columns[500]; const char* column_names[500]; + const char* ref_column_names[500]; const char* referenced_table_name; dict_foreign_set local_fk_set; dict_foreign_set_free local_fk_set_free(local_fk_set); + const char* create_table_name; + const char* orig; + char create_name[MAX_TABLE_NAME_LEN + 1]; + char operation[8]; ut_ad(!srv_read_only_mode); ut_ad(mutex_own(&(dict_sys->mutex))); table = dict_table_get_low(name); + /* First check if we are actually doing an ALTER TABLE, and in that + case look for the table being altered */ + orig = ptr; + 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) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, - "Cannot find the table in the internal" - " data dictionary of InnoDB.\n" - "Create table statement:\n%s\n", sql_string); + dict_foreign_error_report_low(ef, create_name); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%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, start_of_latest_foreign); 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); } - /* 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); - + /* If not alter table jump to loop */ if (!success) { goto loop; } + orig = ptr; ptr = dict_accept(cs, ptr, "TABLE", &success); if (!success) { @@ -4350,13 +4512,40 @@ dict_create_foreign_constraints_low( /* 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, &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) { - fprintf(stderr, - "InnoDB: Error: could not find" - " the table being ALTERED in:\n%s\n", - sql_string); + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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); } @@ -4393,6 +4582,7 @@ loop: of the constraint to system tables. */ ptr = ptr1; + orig = ptr; ptr = dict_accept(cs, ptr, "CONSTRAINT", &success); ut_a(success); @@ -4423,6 +4613,19 @@ loop: if so, immediately reject the command if the table is a temporary one. For now, this kludge will work. */ if (reject_fks && !local_fk_set.empty()) { + 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); } @@ -4448,6 +4651,7 @@ loop: start_of_latest_foreign = ptr; + orig = ptr; ptr = dict_accept(cs, ptr, "FOREIGN", &success); if (!success) { @@ -4458,6 +4662,7 @@ loop: goto loop; } + orig = ptr; ptr = dict_accept(cs, ptr, "KEY", &success); if (!success) { @@ -4483,6 +4688,7 @@ loop: } } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { @@ -4492,8 +4698,17 @@ loop: ptr = dict_skip_word(cs, ptr, &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); - return(DB_CANNOT_ADD_CONSTRAINT); + "%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); } } else { @@ -4520,15 +4735,26 @@ loop: /* Scan the columns in the first list */ col_loop1: ut_a(i < (sizeof column_names) / sizeof *column_names); + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, table, columns + i, heap, column_names + i); if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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); + 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); } @@ -4540,11 +4766,22 @@ col_loop1: goto col_loop1; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success) { 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); } @@ -4555,27 +4792,41 @@ col_loop1: set to 0 */ index = dict_foreign_find_index( - table, NULL, column_names, i, NULL, TRUE, FALSE); + table, NULL, column_names, i, + NULL, TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { 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); - ut_print_name(ef, NULL, TRUE, name); + ut_print_name(ef, NULL, TRUE, create_name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" "See " REFMAN "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, table, ef); - return(DB_CHILD_NO_INDEX); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } + + orig = ptr; ptr = dict_accept(cs, ptr, "REFERENCES", &success); if (!success || !my_isspace(cs, *ptr)) { 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); } @@ -4644,21 +4895,46 @@ col_loop1: checking of foreign key constraints! */ 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); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve table name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.\n", + operation, create_name, buf, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } @@ -4666,34 +4942,54 @@ col_loop1: i = 0; col_loop2: + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, - heap, column_names + i); + heap, ref_column_names + i); i++; if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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); + 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); } + orig = ptr; ptr = dict_accept(cs, ptr, ",", &success); if (success) { goto col_loop2; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success || foreign->n_fields != i) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } @@ -4703,6 +4999,7 @@ col_loop2: scan_on_conditions: /* Loop here as long as we can find ON ... conditions */ + start_of_latest_set = ptr; ptr = dict_accept(cs, ptr, "ON", &success); if (!success) { @@ -4710,15 +5007,27 @@ scan_on_conditions: goto try_find_index; } + orig = ptr; ptr = dict_accept(cs, ptr, "DELETE", &success); if (!success) { + orig = ptr; ptr = dict_accept(cs, ptr, "UPDATE", &success); if (!success) { 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); } @@ -4729,12 +5038,14 @@ scan_on_conditions: n_on_deletes++; } + orig = ptr; ptr = dict_accept(cs, ptr, "RESTRICT", &success); if (success) { goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "CASCADE", &success); if (success) { @@ -4747,14 +5058,25 @@ scan_on_conditions: goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "NO", &success); if (success) { + orig = ptr; ptr = dict_accept(cs, ptr, "ACTION", &success); if (!success) { 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); } @@ -4768,38 +5090,69 @@ scan_on_conditions: goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "SET", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } + orig = ptr; ptr = dict_accept(cs, ptr, "NULL", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%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); } for (j = 0; j < foreign->n_fields; j++) { if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) & 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 if the column is not allowed to be NULL! */ mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have defined a SET NULL condition" - " though some of the\n" - "columns are defined as NOT NULL.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%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.\n", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); 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); + return(DB_CANNOT_ADD_CONSTRAINT); } } @@ -4817,11 +5170,20 @@ try_find_index: /* It is an error to define more than 1 action */ mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have twice an ON DELETE clause" - " or twice an ON UPDATE clause.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " 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. 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); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -4833,12 +5195,12 @@ try_find_index: if (referenced_table) { index = dict_foreign_find_index(referenced_table, NULL, - column_names, i, + ref_column_names, i, foreign->foreign_index, - TRUE, FALSE); + TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { 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" "Cannot find an index in the" " referenced table where the\n" @@ -4856,9 +5218,13 @@ try_find_index: "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", 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); - return(DB_PARENT_NO_INDEX); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { ut_a(trx->check_foreigns == FALSE); @@ -4877,11 +5243,12 @@ try_find_index: for (i = 0; i < foreign->n_fields; i++) { foreign->referenced_col_names[i] - = mem_heap_strdup(foreign->heap, column_names[i]); + = mem_heap_strdup(foreign->heap, ref_column_names[i]); } goto loop; } + /************************************************************************** Determines whether a string starts with the specified keyword. @return TRUE if str starts with keyword */ @@ -6071,7 +6438,8 @@ dict_foreign_replace_index( foreign->foreign_table, col_names, foreign->foreign_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); if (new_index) { ut_ad(new_index->table == index->table); ut_ad(!new_index->to_be_dropped); @@ -6095,7 +6463,8 @@ dict_foreign_replace_index( foreign->referenced_table, NULL, foreign->referenced_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); /* There must exist an alternative index, since this must have been checked earlier. */ if (new_index) { @@ -6656,10 +7025,15 @@ dict_foreign_qualify_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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 */ { if (dict_index_get_n_fields(index) < n_cols) { return(false); @@ -6676,11 +7050,21 @@ dict_foreign_qualify_index( if (field->prefix_len != 0) { /* We do not accept column prefix indexes here */ + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } return(false); } if (check_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 = (dict_index_t*)index; + } return(false); } @@ -6696,6 +7080,12 @@ dict_foreign_qualify_index( dict_index_get_nth_col(index, i), dict_index_get_nth_col(types_idx, i), check_charsets)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } + return(false); } } diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc index c23a3637632..42dc856dd22 100644 --- a/storage/xtradb/dict/dict0mem.cc +++ b/storage/xtradb/dict/dict0mem.cc @@ -420,7 +420,8 @@ dict_mem_table_col_rename_low( dict_index_t* new_index = dict_foreign_find_index( foreign->foreign_table, NULL, foreign->foreign_col_names, - foreign->n_fields, NULL, true, false); + foreign->n_fields, NULL, true, false, + NULL, NULL, NULL); /* There must be an equivalent index in this case. */ ut_ad(new_index != NULL); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 0bb72ada5af..fba50ea52f1 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -2413,6 +2413,7 @@ check_trx_exists( if (trx == NULL) { trx = innobase_trx_allocate(thd); + thd_set_ha_data(thd, innodb_hton_ptr, trx); } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { mem_analyze_corruption(trx); ut_error; @@ -18958,3 +18959,28 @@ ib_warn_row_too_big(const dict_table_t* table) " ROW_FORMAT=COMPRESSED ": "" , prefix ? DICT_MAX_FIXED_COL_LEN : 0); } +/********************************************************************//** +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 */ + ...) +{ + 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, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); +} diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index e6e4f13a73e..d8cadfb6891 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -825,7 +825,7 @@ innobase_find_fk_index( if (!(index->type & DICT_FTS) && dict_foreign_qualify_index( table, col_names, columns, n_cols, - index, NULL, true, 0)) { + index, NULL, true, 0, NULL, NULL, NULL)) { for (ulint i = 0; i < n_drop_index; i++) { if (index == drop_index[i]) { /* Skip to-be-dropped indexes. */ @@ -1015,7 +1015,7 @@ innobase_get_foreign_key_info( referenced_table, 0, referenced_column_names, i, index, - TRUE, FALSE); + TRUE, FALSE, NULL, NULL, NULL); DBUG_EXECUTE_IF( "innodb_test_no_reference_idx", @@ -3330,7 +3330,7 @@ innobase_check_foreign_key_index( foreign->referenced_col_names, foreign->n_fields, index, /*check_charsets=*/TRUE, - /*check_null=*/FALSE) + /*check_null=*/FALSE, NULL, NULL, NULL) && !innobase_find_equiv_index( foreign->referenced_col_names, foreign->n_fields, @@ -3358,7 +3358,7 @@ innobase_check_foreign_key_index( foreign->foreign_col_names, foreign->n_fields, index, /*check_charsets=*/TRUE, - /*check_null=*/FALSE) + /*check_null=*/FALSE, NULL,NULL, NULL) && !innobase_find_equiv_index( foreign->foreign_col_names, foreign->n_fields, @@ -4806,7 +4806,8 @@ innobase_update_foreign_try( fk->n_fields, fk->referenced_index, TRUE, fk->type & (DICT_FOREIGN_ON_DELETE_SET_NULL - | DICT_FOREIGN_ON_UPDATE_SET_NULL)); + | DICT_FOREIGN_ON_UPDATE_SET_NULL), + NULL, NULL, NULL); if (!fk->foreign_index) { my_error(ER_FK_INCORRECT_OPTION, MYF(0), table_name, fk->id); @@ -4818,7 +4819,7 @@ innobase_update_foreign_try( names, while the columns in ctx->old_table have not been renamed yet. */ error = dict_create_add_foreign_to_dictionary( - ctx->old_table->name, fk, trx); + (dict_table_t*)ctx->old_table, ctx->old_table->name, fk, trx); DBUG_EXECUTE_IF( "innodb_test_cannot_add_fk_system", diff --git a/storage/xtradb/include/dict0crea.h b/storage/xtradb/include/dict0crea.h index 67eab9058da..cc5eb10bb90 100644 --- a/storage/xtradb/include/dict0crea.h +++ b/storage/xtradb/include/dict0crea.h @@ -110,6 +110,17 @@ UNIV_INTERN dberr_t 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 */ + /********************************************************************//** Generate a foreign key constraint name when it was not named by the user. A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER, @@ -174,6 +185,7 @@ UNIV_INTERN dberr_t dict_create_add_foreign_to_dictionary( /*==================================*/ + dict_table_t* table, /*!< in: table */ const char* name, /*!< in: table name */ const dict_foreign_t* foreign,/*!< in: foreign key */ trx_t* trx) /*!< in/out: dictionary transaction */ diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h index def7b246ead..ce70e936e6e 100644 --- a/storage/xtradb/include/dict0dict.h +++ b/storage/xtradb/include/dict0dict.h @@ -580,10 +580,17 @@ dict_foreign_find_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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 */ __attribute__((nonnull(1,3), warn_unused_result)); /**********************************************************************//** Returns a column's name. @@ -675,10 +682,18 @@ dict_foreign_qualify_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must 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 */ + __attribute__((nonnull(1,3), warn_unused_result)); #ifdef UNIV_DEBUG /********************************************************************//** diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 3c14828989b..6fb16c2c8b0 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -611,5 +611,14 @@ innobase_convert_to_filename_charset( const char* from, /* in: identifier to convert */ 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 /* HA_INNODB_PROTOTYPES_H */ diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 9a476eace71..96275b95f68 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -21,31 +21,42 @@ static my_bool ssl_algorithms_added = 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 -DH *get_dh1024() +DH *get_dh2048() { - static unsigned char dh1024_p[]={ - 0xEC,0x46,0x7E,0xF9,0x4E,0x10,0x29,0xDC,0x44,0x97,0x71,0xFD, - 0x71,0xC6,0x9F,0x0D,0xD1,0x09,0xF6,0x58,0x6F,0xAD,0xCA,0xF4, - 0x37,0xD5,0xC3,0xBD,0xC3,0x9A,0x51,0x66,0x2C,0x58,0xBD,0x02, - 0xBD,0xBA,0xBA,0xFC,0xE7,0x0E,0x5A,0xE5,0x97,0x81,0xC3,0xF3, - 0x28,0x2D,0xAD,0x00,0x91,0xEF,0xF8,0xF0,0x5D,0xE9,0xE7,0x18, - 0xE2,0xAD,0xC4,0x70,0xC5,0x3C,0x12,0x8A,0x80,0x6A,0x9F,0x3B, - 0x00,0xA2,0x8F,0xA9,0x26,0xB0,0x0E,0x7F,0xED,0xF6,0xC2,0x03, - 0x81,0xB5,0xC5,0x41,0xD0,0x00,0x2B,0x21,0xD4,0x4B,0x74,0xA6, - 0xD7,0x1A,0x0E,0x82,0xC8,0xEE,0xD4,0xB1,0x6F,0xB4,0x79,0x01, - 0x8A,0xF1,0x12,0xD7,0x3C,0xFD,0xCB,0x9B,0xAE,0x1C,0xA9,0x0F, - 0x3D,0x0F,0xF8,0xD6,0x7D,0xDE,0xD6,0x0B, + static unsigned char dh2048_p[]={ + 0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8, + 0x15,0xFC,0x3B,0xBA,0xAB,0x9F,0xDF,0x68,0xC4,0x79,0x78,0x0D, + 0xC1,0x12,0x64,0xE4,0x15,0xC9,0x66,0xDB,0xF6,0xCB,0xB3,0x39, + 0x02,0x5B,0x78,0x62,0xFB,0x09,0xAE,0x09,0x6B,0xDD,0xD4,0x5D, + 0x97,0xBC,0xDC,0x7F,0xE6,0xD6,0xF1,0xCB,0xF5,0xEB,0xDA,0xA7, + 0x2E,0x5A,0x43,0x2B,0xE9,0x40,0xE2,0x85,0x00,0x1C,0xC0,0x0A, + 0x98,0x77,0xA9,0x31,0xDE,0x0B,0x75,0x4D,0x1E,0x1F,0x16,0x83, + 0xCA,0xDE,0xBD,0x21,0xFC,0xC1,0x82,0x37,0x36,0x33,0x0B,0x66, + 0x06,0x3C,0xF3,0xAF,0x21,0x57,0x57,0x80,0xF6,0x94,0x1B,0xA9, + 0xD4,0xF6,0x8F,0x18,0x62,0x0E,0xC4,0x22,0xF9,0x5B,0x62,0xCC, + 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, }; DH *dh; if ((dh=DH_new()) == NULL) return(NULL); - dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); - dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); + dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); + dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return(NULL); } return(dh); @@ -248,7 +259,7 @@ new_VioSSLFd(const char *key_file, const char *cert_file, } /* DH stuff */ - dh=get_dh1024(); + dh=get_dh2048(); if (!SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh)) { *error= SSL_INITERR_DH; |