From 1def5764aec99b9921c1f80a3018808fb24ecdd7 Mon Sep 17 00:00:00 2001 From: Axel Svensson Date: Fri, 23 Feb 2024 15:26:07 +0100 Subject: [PATCH 1/3] [RONDB-620] Minimal test case --- mysql-test/suite/ndb/r/bug_rondb-620.result | 26 +++++++++++ mysql-test/suite/ndb/t/bug_rondb-620.cnf | 3 ++ mysql-test/suite/ndb/t/bug_rondb-620.test | 52 +++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 mysql-test/suite/ndb/r/bug_rondb-620.result create mode 100644 mysql-test/suite/ndb/t/bug_rondb-620.cnf create mode 100644 mysql-test/suite/ndb/t/bug_rondb-620.test diff --git a/mysql-test/suite/ndb/r/bug_rondb-620.result b/mysql-test/suite/ndb/r/bug_rondb-620.result new file mode 100644 index 000000000000..caf43d227b2f --- /dev/null +++ b/mysql-test/suite/ndb/r/bug_rondb-620.result @@ -0,0 +1,26 @@ +use test; +create table t1 ( +a int not null, +b varchar(8) not null, +primary key (a,b) +) engine=ndbcluster; +create table t2 ( +b varchar(8) not null, +a int not null, +primary key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (66051, "ABCD"); +insert into t2 (b, a) values ("ABCD", 66051); +insert into t2 (b, a) values ("DCBA", 15066); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk1` FOREIGN KEY (`b`,`a`) REFERENCES `t1` (`b`,`a`) ON DELETE NO ACTION ON UPDATE NO ACTION) +Backing up data +Restoring data +insert into t2 (b, a) values ("DCBA", 15066); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk1` FOREIGN KEY (`b`,`a`) REFERENCES `t1` (`b`,`a`) ON DELETE NO ACTION ON UPDATE NO ACTION) +select * from t1; +a b +66051 ABCD +select * from t2; +b a +ABCD 66051 diff --git a/mysql-test/suite/ndb/t/bug_rondb-620.cnf b/mysql-test/suite/ndb/t/bug_rondb-620.cnf new file mode 100644 index 000000000000..4070340a8502 --- /dev/null +++ b/mysql-test/suite/ndb/t/bug_rondb-620.cnf @@ -0,0 +1,3 @@ +!include suite/ndb/my.cnf +[cluster_config] +ThreadConfig=ldm={count=2} diff --git a/mysql-test/suite/ndb/t/bug_rondb-620.test b/mysql-test/suite/ndb/t/bug_rondb-620.test new file mode 100644 index 000000000000..60a877caf11a --- /dev/null +++ b/mysql-test/suite/ndb/t/bug_rondb-620.test @@ -0,0 +1,52 @@ +-- source include/have_ndb.inc +-- source suite/ndb/include/backup_restore_setup.inc + +use test; + +create table t1 ( + a int not null, + b varchar(8) not null, + primary key (a,b) +) engine=ndbcluster; + +create table t2 ( + b varchar(8) not null, + a int not null, + primary key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; + +insert into t1 (a, b) values (66051, "ABCD"); + +insert into t2 (b, a) values ("ABCD", 66051); + +--error 1452 +insert into t2 (b, a) values ("DCBA", 15066); + +--echo Backing up data +--source include/ndb_backup.inc +disable_query_log; drop table t2; drop table t1; enable_query_log; + +--let $restore= $NDB_RESTORE -b $the_backup_id +--let $backup= $NDB_BACKUPS-$the_backup_id +--let $trash= $NDB_TOOLS_OUTPUT + +--echo Restoring data + +--exec $restore -n 1 --restore-meta --disable-indexes $backup >> $trash +--exec $restore -n 1 --restore-data $backup >> $trash +--exec $restore -n 2 --restore-data $backup >> $trash +--exec $restore -n 2 --rebuild-indexes $backup >> $trash + +--error 1452 +insert into t2 (b, a) values ("DCBA", 15066); + +select * from t1; +select * from t2; + +# Cleanup + +disable_query_log; drop table t2; drop table t1; enable_query_log; + +--remove_file $trash +--source suite/ndb/include/backup_restore_cleanup.inc From 021adf6c437419b91339fe42162880069e68e75c Mon Sep 17 00:00:00 2001 From: Axel Svensson Date: Sat, 24 Feb 2024 16:29:46 +0100 Subject: [PATCH 2/3] [RONDB-620] More test cases --- mysql-test/suite/ndb/r/bug_rondb-620.result | 224 +++++++++++++++++- mysql-test/suite/ndb/t/bug_rondb-620.test | 189 +++++++++++++-- .../suite/ndb/t/bug_rondb-620_helper.inc | 25 ++ 3 files changed, 403 insertions(+), 35 deletions(-) create mode 100644 mysql-test/suite/ndb/t/bug_rondb-620_helper.inc diff --git a/mysql-test/suite/ndb/r/bug_rondb-620.result b/mysql-test/suite/ndb/r/bug_rondb-620.result index caf43d227b2f..987d45cef362 100644 --- a/mysql-test/suite/ndb/r/bug_rondb-620.result +++ b/mysql-test/suite/ndb/r/bug_rondb-620.result @@ -1,26 +1,230 @@ use test; +Case: (a,b) P<-P (b,a) create table t1 ( a int not null, -b varchar(8) not null, +b int not null, primary key (a,b) ) engine=ndbcluster; create table t2 ( -b varchar(8) not null, +b int not null, a int not null, primary key (b,a), constraint fk1 foreign key (b, a) references t1 (b, a) ) engine=ndbcluster; -insert into t1 (a, b) values (66051, "ABCD"); -insert into t2 (b, a) values ("ABCD", 66051); -insert into t2 (b, a) values ("DCBA", 15066); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk1` FOREIGN KEY (`b`,`a`) REFERENCES `t1` (`b`,`a`) ON DELETE NO ACTION ON UPDATE NO ACTION) +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +Backing up data +Restoring data +select * from t1; +a b +1 2 +select * from t2; +b a +2 1 +Case: (a,b) <-P (b,a) +create table t1 ( +a int not null, +b int not null, +primary key (b), +unique key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +a int not null, +primary key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +Backing up data +Restoring data +select * from t1; +a b +1 2 +select * from t2; +b a +2 1 +b a +2 1 +Case: (a,b) <- (b,a) +create table t1 ( +a int not null, +b int not null, +primary key (b), +unique key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +a int not null, +primary key (a), +unique key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); Backing up data Restoring data -insert into t2 (b, a) values ("DCBA", 15066); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk1` FOREIGN KEY (`b`,`a`) REFERENCES `t1` (`b`,`a`) ON DELETE NO ACTION ON UPDATE NO ACTION) select * from t1; a b -66051 ABCD +1 2 select * from t2; b a -ABCD 66051 +2 1 +b a +2 1 +Case: (a,b) P<- (b,a) +create table t1 ( +a int not null, +b int not null, +primary key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +a int not null, +primary key (a), +unique key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +Backing up data +Restoring data +select * from t1; +a b +1 2 +select * from t2; +b a +2 1 +b a +2 1 +Case: (a,_c,b) P<-P (b,a) +create table t1 ( +a int not null, +_c int not null, +b int not null, +primary key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +a int not null, +primary key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b, _c) values (1, 2, 3); +insert into t2 (b, a) values (2, 1); +Backing up data +Restoring data +select * from t1; +a _c b +1 3 2 +select * from t2; +b a +2 1 +b a +2 1 +Case: (a,b) P<-P (b,_c,a) +create table t1 ( +a int not null, +b int not null, +primary key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +_c int not null, +a int not null, +primary key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a, _c) values (2, 1, 3); +Backing up data +Restoring data +select * from t1; +a b +1 2 +select * from t2; +b _c a +2 3 1 +b _c a +2 3 1 +Case: (_c,a,b) P<-P (b,a,_c) +create table t1 ( +_c int not null, +a int not null, +b int not null, +primary key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +a int not null, +_c int not null, +primary key (b,a), +constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b, _c) values (1, 2, 3); +insert into t2 (b, a, _c) values (2, 1, 3); +Backing up data +Restoring data +select * from t1; +_c a b +3 1 2 +select * from t2; +b a _c +2 1 3 +b a _c +2 1 3 +Case: (a,b) P<-P (b,a) +create table t1 ( +a int not null, +b int not null, +primary key (a,b) +) engine=ndbcluster; +create table t2 ( +b int not null, +a int not null, +primary key (b,a), +constraint fk1 foreign key (a, b) references t1 (a, b) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +Backing up data +Restoring data +select * from t1; +a b +1 2 +select * from t2; +b a +2 1 +b a +2 1 +Case: (a,b,_c,d,e) P<- (a,_c,e,d,b) +create table t1 ( +a int not null, +b varchar(8) not null, +_c int not null, +d int not null, +e int not null, +primary key (a,b,d,e) +) engine=ndbcluster; +create table t2 ( +a int not null, +_c int not null, +e int not null, +d int not null, +b varchar(8) not null, +primary key (a), +unique key (a,e,d,b), +constraint fk1 foreign key (b, e, d, a) references t1 (b, e, d, a) +) engine=ndbcluster; +insert into t1 (a, b, _c, d, e) values (1, "ABCD", 3, 4, 5); +insert into t2 (a, _c, e, d, b) values (1, 9, 5, 4, "ABCD"); +Backing up data +Restoring data +select * from t1; +a b _c d e +1 ABCD 3 4 5 +select * from t2; +a _c e d b +1 9 5 4 ABCD +a _c e d b +1 9 5 4 ABCD diff --git a/mysql-test/suite/ndb/t/bug_rondb-620.test b/mysql-test/suite/ndb/t/bug_rondb-620.test index 60a877caf11a..0e1bb699558f 100644 --- a/mysql-test/suite/ndb/t/bug_rondb-620.test +++ b/mysql-test/suite/ndb/t/bug_rondb-620.test @@ -1,52 +1,191 @@ -- source include/have_ndb.inc -- source suite/ndb/include/backup_restore_setup.inc - +--let $trash= $NDB_TOOLS_OUTPUT use test; +# Vary primary/unique key + +--echo Case: (a,b) P<-P (b,a) create table t1 ( a int not null, - b varchar(8) not null, + b int not null, primary key (a,b) ) engine=ndbcluster; +create table t2 ( + b int not null, + a int not null, + primary key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +--let forbidden_insert= insert into t2 (b, a) values (102, 101); +--let where_clause= b=2 and a=7 +--source bug_rondb-620_helper.inc +--echo Case: (a,b) <-P (b,a) +create table t1 ( + a int not null, + b int not null, + primary key (b), + unique key (a,b) +) engine=ndbcluster; create table t2 ( - b varchar(8) not null, + b int not null, a int not null, primary key (b,a), constraint fk1 foreign key (b, a) references t1 (b, a) ) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +--let forbidden_insert= insert into t2 (b, a) values (102, 101); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc -insert into t1 (a, b) values (66051, "ABCD"); +--echo Case: (a,b) <- (b,a) +create table t1 ( + a int not null, + b int not null, + primary key (b), + unique key (a,b) +) engine=ndbcluster; +create table t2 ( + b int not null, + a int not null, + primary key (a), + unique key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +--let forbidden_insert= insert into t2 (b, a) values (102, 101); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc -insert into t2 (b, a) values ("ABCD", 66051); +--echo Case: (a,b) P<- (b,a) +create table t1 ( + a int not null, + b int not null, + primary key (a,b) +) engine=ndbcluster; +create table t2 ( + b int not null, + a int not null, + primary key (a), + unique key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +--let forbidden_insert= insert into t2 (b, a) values (102, 101); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc ---error 1452 -insert into t2 (b, a) values ("DCBA", 15066); +# Vary presence of other column ---echo Backing up data ---source include/ndb_backup.inc -disable_query_log; drop table t2; drop table t1; enable_query_log; +--echo Case: (a,_c,b) P<-P (b,a) +create table t1 ( + a int not null, + _c int not null, + b int not null, + primary key (a,b) +) engine=ndbcluster; +create table t2 ( + b int not null, + a int not null, + primary key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b, _c) values (1, 2, 3); +insert into t2 (b, a) values (2, 1); +--let forbidden_insert= insert into t2 (b, a) values (102, 101); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc ---let $restore= $NDB_RESTORE -b $the_backup_id ---let $backup= $NDB_BACKUPS-$the_backup_id ---let $trash= $NDB_TOOLS_OUTPUT +--echo Case: (a,b) P<-P (b,_c,a) +create table t1 ( + a int not null, + b int not null, + primary key (a,b) +) engine=ndbcluster; +create table t2 ( + b int not null, + _c int not null, + a int not null, + primary key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a, _c) values (2, 1, 3); +--let forbidden_insert= insert into t2 (b, a, _c) values (102, 101, 103); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc ---echo Restoring data +--echo Case: (_c,a,b) P<-P (b,a,_c) +create table t1 ( + _c int not null, + a int not null, + b int not null, + primary key (a,b) +) engine=ndbcluster; +create table t2 ( + b int not null, + a int not null, + _c int not null, + primary key (b,a), + constraint fk1 foreign key (b, a) references t1 (b, a) +) engine=ndbcluster; +insert into t1 (a, b, _c) values (1, 2, 3); +insert into t2 (b, a, _c) values (2, 1, 3); +--let forbidden_insert= insert into t2 (b, a, _c) values (102, 101, 103); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc ---exec $restore -n 1 --restore-meta --disable-indexes $backup >> $trash ---exec $restore -n 1 --restore-data $backup >> $trash ---exec $restore -n 2 --restore-data $backup >> $trash ---exec $restore -n 2 --rebuild-indexes $backup >> $trash +# Vary FK order ---error 1452 -insert into t2 (b, a) values ("DCBA", 15066); +--echo Case: (a,b) P<-P (b,a) +create table t1 ( + a int not null, + b int not null, + primary key (a,b) +) engine=ndbcluster; +create table t2 ( + b int not null, + a int not null, + primary key (b,a), + constraint fk1 foreign key (a, b) references t1 (a, b) +) engine=ndbcluster; +insert into t1 (a, b) values (1, 2); +insert into t2 (b, a) values (2, 1); +--let forbidden_insert= insert into t2 (b, a) values (102, 101); +--let where_clause= b=2 and a=1 +--source bug_rondb-620_helper.inc -select * from t1; -select * from t2; +--echo Case: (a,b,_c,d,e) P<- (a,_c,e,d,b) +create table t1 ( + a int not null, + b varchar(8) not null, + _c int not null, + d int not null, + e int not null, + primary key (a,b,d,e) +) engine=ndbcluster; +create table t2 ( + a int not null, + _c int not null, + e int not null, + d int not null, + b varchar(8) not null, + primary key (a), + unique key (a,e,d,b), + constraint fk1 foreign key (b, e, d, a) references t1 (b, e, d, a) +) engine=ndbcluster; +insert into t1 (a, b, _c, d, e) values (1, "ABCD", 3, 4, 5); +insert into t2 (a, _c, e, d, b) values (1, 9, 5, 4, "ABCD"); +--let forbidden_insert= insert into t2 (a, _c, e, d, b) values (1, 9, 5, 4, 'DCBA'); +--let where_clause= a=1 and b='ABCD' and d=4 and e=5 +--source bug_rondb-620_helper.inc # Cleanup - -disable_query_log; drop table t2; drop table t1; enable_query_log; - --remove_file $trash --source suite/ndb/include/backup_restore_cleanup.inc diff --git a/mysql-test/suite/ndb/t/bug_rondb-620_helper.inc b/mysql-test/suite/ndb/t/bug_rondb-620_helper.inc new file mode 100644 index 000000000000..13c29aaedfe9 --- /dev/null +++ b/mysql-test/suite/ndb/t/bug_rondb-620_helper.inc @@ -0,0 +1,25 @@ +--error 1 +--exec $MYSQL -e "use test; $forbidden_insert" + +--echo Backing up data +--source include/ndb_backup.inc +disable_query_log; drop table t2; drop table t1; enable_query_log; + +--let $restore= $NDB_RESTORE -b $the_backup_id +--let $backup= $NDB_BACKUPS-$the_backup_id + +--echo Restoring data + +--exec $restore -n 1 --restore-meta --disable-indexes $backup >> $trash +--exec $restore -n 1 --restore-data $backup >> $trash +--exec $restore -n 2 --restore-data $backup >> $trash +--exec $restore -n 2 --rebuild-indexes $backup >> $trash + +select * from t1; +select * from t2; +--exec $MYSQL -e "use test; select * from t2 where $where_clause;" + +#--error 1 +#--exec $MYSQL -e "use test; $forbidden_insert" + +disable_query_log; drop table t2; drop table t1; enable_query_log; From d9ae7afed384df60c904b4dc34785d02b0fb600c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Ronstr=C3=B6m?= Date: Sat, 24 Feb 2024 14:27:13 +0100 Subject: [PATCH 3/3] [RONDB-620] Fix column ordering in Dbdict::buildFK_prepare --- .../ndb/src/kernel/blocks/dbdict/Dbdict.cpp | 109 +++++++++++------- .../ndb/src/kernel/blocks/dbdict/Dbdict.hpp | 2 + 2 files changed, 71 insertions(+), 40 deletions(-) diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 36cc8649a770..0b59a9ae3d26 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -1,5 +1,6 @@ /* Copyright (c) 2003, 2023, Oracle and/or its affiliates. + Copyright (c) 2021, 2024, Hopsworks and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -25035,6 +25036,56 @@ void Dbdict::createFK_prepare(Signal *signal, SchemaOpPtr op_ptr) { writeTableFile(signal, op_ptr, impl_req->fkId, sec, &cb); } +void +Dbdict::map_fk_columns(Ptr fk_ptr, + Uint32 *parent_to_child, + Uint32 *child_to_parent) +{ + if ((fk_ptr.p->m_bits & CreateFKImplReq::FK_CHILD_OI) == 0) + { + jam(); + Uint32 tmp[MAX_ATTRIBUTES_IN_INDEX]; + memcpy(tmp, fk_ptr.p->m_childColumns, 4*fk_ptr.p->m_columnCount); + qsort(tmp, fk_ptr.p->m_columnCount, sizeof(Uint32), cmp_uint); + for (Uint32 i = 0; i < fk_ptr.p->m_columnCount; i++) + { + Uint32 col = tmp[i]; + for (Uint32 j = 0; j < fk_ptr.p->m_columnCount; j++) + { + if (fk_ptr.p->m_childColumns[j] == col) + { + parent_to_child[i] = fk_ptr.p->m_parentColumns[j]; + break; + } + } + } + } + + if ((fk_ptr.p->m_bits & CreateFKImplReq::FK_PARENT_OI) == 0) + { + jam(); + /** + * PK/UI are stored in attribute id order...so sort child columns + * in parent order... + */ + Uint32 tmp[MAX_ATTRIBUTES_IN_INDEX]; + memcpy(tmp, fk_ptr.p->m_parentColumns, 4*fk_ptr.p->m_columnCount); + qsort(tmp, fk_ptr.p->m_columnCount, sizeof(Uint32), cmp_uint); + for (Uint32 i = 0; i < fk_ptr.p->m_columnCount; i++) + { + Uint32 col = tmp[i]; + for (Uint32 j = 0; j < fk_ptr.p->m_columnCount; j++) + { + if (fk_ptr.p->m_parentColumns[j] == col) + { + child_to_parent[i] = fk_ptr.p->m_childColumns[j]; + break; + } + } + } + } +} + void Dbdict::createFK_writeTableConf(Signal *signal, Uint32 op_key, Uint32 ret) { D("createFK_writeTableConf"); @@ -25086,46 +25137,10 @@ void Dbdict::createFK_writeTableConf(Signal *signal, Uint32 op_key, * into access on a child row */ Uint32 parent_to_child[MAX_ATTRIBUTES_IN_INDEX]; - memcpy(parent_to_child, fk_ptr.p->m_parentColumns, - 4 * fk_ptr.p->m_columnCount); - if ((fk_ptr.p->m_bits & CreateFKImplReq::FK_CHILD_OI) == 0) { - jam(); - Uint32 tmp[MAX_ATTRIBUTES_IN_INDEX]; - memcpy(tmp, fk_ptr.p->m_childColumns, 4 * fk_ptr.p->m_columnCount); - qsort(tmp, fk_ptr.p->m_columnCount, sizeof(Uint32), cmp_uint); - for (Uint32 i = 0; i < fk_ptr.p->m_columnCount; i++) { - Uint32 col = tmp[i]; - for (Uint32 j = 0; j < fk_ptr.p->m_columnCount; j++) { - if (fk_ptr.p->m_childColumns[j] == col) { - parent_to_child[i] = fk_ptr.p->m_parentColumns[j]; - break; - } - } - } - } - Uint32 child_to_parent[MAX_ATTRIBUTES_IN_INDEX]; - memcpy(child_to_parent, fk_ptr.p->m_childColumns, - 4 * fk_ptr.p->m_columnCount); - if ((fk_ptr.p->m_bits & CreateFKImplReq::FK_PARENT_OI) == 0) { - jam(); - /** - * PK/UI are stored in attribute id order...so sort child columns - * in parent order... - */ - Uint32 tmp[MAX_ATTRIBUTES_IN_INDEX]; - memcpy(tmp, fk_ptr.p->m_parentColumns, 4 * fk_ptr.p->m_columnCount); - qsort(tmp, fk_ptr.p->m_columnCount, sizeof(Uint32), cmp_uint); - for (Uint32 i = 0; i < fk_ptr.p->m_columnCount; i++) { - Uint32 col = tmp[i]; - for (Uint32 j = 0; j < fk_ptr.p->m_columnCount; j++) { - if (fk_ptr.p->m_parentColumns[j] == col) { - child_to_parent[i] = fk_ptr.p->m_childColumns[j]; - break; - } - } - } - } + memcpy(parent_to_child, fk_ptr.p->m_parentColumns, 4*fk_ptr.p->m_columnCount); + memcpy(child_to_parent, fk_ptr.p->m_childColumns, 4*fk_ptr.p->m_columnCount); + map_fk_columns(fk_ptr, &parent_to_child[0], &child_to_parent[0]); BlockReference ref = DBTC_REF; LinearSectionPtr ptr[3]; @@ -25457,10 +25472,24 @@ void Dbdict::buildFK_prepare(Signal *signal, SchemaOpPtr op_ptr) { for (Uint32 i = 0; i < parentColumns.sz; i++) parentColumns.id[i] = i; } + /** + * RONDB-620: + * If the user has defined the FOREIGN KEY CONSTRAINT with multiple + * columns and in different order to the parent tables primary key + * definition we could read the key from the child table with key + * columns in wrong order, thus creating a PK which has the columns + * in wrong order. + */ + Uint32 parent_to_child[MAX_ATTRIBUTES_IN_INDEX]; + Uint32 child_to_parent[MAX_ATTRIBUTES_IN_INDEX]; + memcpy(parent_to_child, fk_ptr.p->m_parentColumns, 4*fk_ptr.p->m_columnCount); + memcpy(child_to_parent, fk_ptr.p->m_childColumns, 4*fk_ptr.p->m_columnCount); + map_fk_columns(fk_ptr, &parent_to_child[0], &child_to_parent[0]); + LinearSectionPtr ptr[3]; ptr[0].p = parentColumns.id; ptr[0].sz = parentColumns.sz; - ptr[1].p = fk_ptr.p->m_childColumns; + ptr[1].p = child_to_parent; ptr[1].sz = fk_ptr.p->m_columnCount; sendSignal(TRIX_REF, GSN_BUILD_FK_IMPL_REQ, signal, diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index b060bb7183d4..163f9d71ddcc 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -1,5 +1,6 @@ /* Copyright (c) 2003, 2023, Oracle and/or its affiliates. + Copyright (c) 2021, 2024, Hopsworks and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -4501,6 +4502,7 @@ class Dbdict : public SimulatedBlock { void sendSchemaComplete(Signal *, Uint32 callbackData, Uint32); + void map_fk_columns(Ptr, Uint32*, Uint32*); public: void send_drop_file(Signal *, Uint32, Uint32, DropFileImplReq::RequestInfo); void send_drop_fg(Signal *, Uint32, Uint32,