You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bug#36345882 Contribution: [RONDB-620] Fix column ordering in Dbdict::buildFK_prepare
Contributed by Axel Svensson.
If one have a table with data adding a multicolumn foreign key
constraint could fail even if the data satisifies the constraint. Namely
if the order columns are mentioned in the references clause do not match
the order the columns are defined for the table.
Example#1, alter table add constraint foreign key:
mysql> create table prnt (pk1 int, pk2 int, primary key(pk2,pk1)
-> ) engine=ndbcluster;
mysql> create table chld (pk int primary key, col1 int, col2 int
-> ) engine=ndbcluster;
mysql> insert into prnt values (1,2);
mysql> insert into chld values (0,1,2);
mysql> alter table chld add
-> constraint fk foreign key(col2,col1)
-> references prnt(pk2,pk1);
mysql> \W
Show warnings enabled.
mysql> alter table chld
-> add constraint fk foreign key(col2,col1)
-> references prnt(pk2,pk1);
ERROR 1215 (HY000): Cannot add foreign key constraint
Warning (Code 1296): Got error 21033 'Create foreign key failed in NDB - No parent row found' from NDB
Error (Code 1215): Cannot add foreign key constraint
Example#2, ndb_restore --rebuild-indexes:
mysql> create table prnt (pk1 int, pk2 int, primary key(pk2,pk1)
-> ) engine=ndbcluster;
mysql> create table chld (pk int primary key, col1 int, col2 int,
-> constraint fk foreign key(col2,col1)
-> references prnt(pk2,pk1)
-> ) engine=ndbcluster;
mysql> insert into prnt values (1,2);
mysql> insert into chld values (0,1,2);
ndb_mgm> start backup
...
Node 1: Backup 1 started from node 3 completed
mysql> drop table chld, prnt;
$ ndb_restore -b 1 -n 1 -m --disable-indexes BACKUP/BACKUP-1
$ ndb_restore -b 1 -n 1 -r --disable-indexes BACKUP/BACKUP-1
$ ndb_restore -b 1 -n 2 -r --disable-indexes BACKUP/BACKUP-1
$ ndb_restore -b 1 -n 1 --rebuild-indexes BACKUP/BACKUP-1
...
Failed to create foreign key fk parent test.prnt.PK child test.chld.fk : 21033: Create foreign key failed in NDB - No parent row found
Problem:
When checking the existing data for a pending foreign key constraint
with multi column key, columns from referencing table were matches with
the columns in the referenced table in wrong order.
In the examples above, the columns (col2,col1) from referencing table is
matches against columns (pk1,pk2) in referenced table resulting in col2
is matched against pk1 and col1 against pk2 instead of the intention to
match col2 against pk2 and col1 against pk1.
The checking code expected the index in parent table to use the same
column order as specified in the references clause of constraint
definition. But unique indexes in NDB always uses the column order as
they appear in table definition.
In example above:
- PRIMARY KEY(pk1,pk2)
- PRIMARY KEY(pk2,pk1)
- UNIQUE KEY(pk1,pk2)
- UNIQUE KEY(pk2,pk1)
all would use key with column order as (pk1,pk2) since that is the
order in table definition
create table prnt (pk1 int, pk2 int)
Also note that the ordered index in the child table must have the
columns in the order specified in the constraint.
Note that the code maintaining the foreign key constraint did handle
multicolumn keys correctly.
Fix:
When Dbdict sends GSN_BUILD_FK_IMPL_REQ to TRIX it now sends the child
columns to fetch matching the parent index order.
Change-Id: I3bd57d3d2c36628c1dc03e1f590a2d5bcb9b04de
b1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
617
+
c1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
618
+
a1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
619
+
b2 Int NOT NULL AT=FIXED ST=MEMORY
620
+
c2 Int NOT NULL AT=FIXED ST=MEMORY
621
+
a2 Int NOT NULL AT=FIXED ST=MEMORY
622
+
a Int NULL AT=FIXED ST=MEMORY DEFAULT 0
623
+
b Int NULL AT=FIXED ST=MEMORY DEFAULT 0
624
+
c Int NULL AT=FIXED ST=MEMORY DEFAULT 0
625
+
-- Indexes --
626
+
PRIMARY KEY(b1, c1, a1) - UniqueHashIndex
627
+
uk2$unique(b2, c2, a2) - UniqueHashIndex
628
+
-- t2 --
629
+
Version: Any
630
+
Fragment type: HashMapPartition
631
+
K Value: 6
632
+
Min load factor: 78
633
+
Max load factor: 80
634
+
Temporary table: no
635
+
Number of attributes: 15
636
+
Number of primary keys: 3
637
+
Length of frm data: XXX
638
+
Max Rows: 0
639
+
Row Checksum: 1
640
+
Row GCI: 1
641
+
SingleUserMode: 0
642
+
ForceVarPart: 1
643
+
PartitionCount: 8
644
+
FragmentCount: 8
645
+
PartitionBalance: FOR_RP_BY_LDM
646
+
ExtraRowGciBits: 0
647
+
ExtraRowAuthorBits: 0
648
+
TableStatus: Retrieved
649
+
Table options: readbackup
650
+
HashMap: DEFAULT-HASHMAP-3840-8
651
+
-- Attributes --
652
+
a Int NULL AT=FIXED ST=MEMORY DEFAULT 0
653
+
b Int NULL AT=FIXED ST=MEMORY DEFAULT 0
654
+
c Int NULL AT=FIXED ST=MEMORY DEFAULT 0
655
+
d Int NULL AT=FIXED ST=MEMORY DEFAULT 0
656
+
e Int NULL AT=FIXED ST=MEMORY DEFAULT 0
657
+
f Int NULL AT=FIXED ST=MEMORY DEFAULT 0
658
+
b1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
659
+
c1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
660
+
a1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
661
+
b2 Int NOT NULL AT=FIXED ST=MEMORY
662
+
c2 Int NOT NULL AT=FIXED ST=MEMORY
663
+
a2 Int NOT NULL AT=FIXED ST=MEMORY
664
+
b3 Int NOT NULL AT=FIXED ST=MEMORY
665
+
c3 Int NOT NULL AT=FIXED ST=MEMORY
666
+
a3 Int NOT NULL AT=FIXED ST=MEMORY
667
+
-- Indexes --
668
+
PRIMARY KEY(b1, c1, a1) - UniqueHashIndex
669
+
uk2$unique(b2, c2, a2) - UniqueHashIndex
670
+
ok3def(c3, b3, a3, d, e, f) - OrderedIndex
671
+
-- ForeignKeys --
672
+
XX/XX/fk11 PRIMARY KEY (c1, b1, a1) REFERENCES test.t1/PRIMARY KEY () on update noaction on delete noaction
673
+
XX/XX/fk21 uk2$unique (c2, b2, a2) REFERENCES test.t1/PRIMARY KEY () on update noaction on delete noaction
674
+
XX/XX/fk31 ok3def (c3, b3, a3) REFERENCES test.t1/PRIMARY KEY () on update noaction on delete noaction
675
+
XX/XX/fk12 PRIMARY KEY (c1, b1, a1) REFERENCES test.t1/uk2$unique () on update noaction on delete noaction
676
+
XX/XX/fk22 uk2$unique (c2, b2, a2) REFERENCES test.t1/uk2$unique () on update noaction on delete noaction
677
+
XX/XX/fk32 ok3def (c3, b3, a3) REFERENCES test.t1/uk2$unique () on update noaction on delete noaction
678
+
insert into t1 (a, b, c) values (11, 12, 13);
679
+
insert into t2 (a, b, c) values (11, 12, 13);
680
+
insert into t2 (a,b,c) values (101, 102, 103);
681
+
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk11` FOREIGN KEY (`c1`,`b1`,`a1`) REFERENCES `t1` (`c1`,`b1`,`a1`) ON DELETE NO ACTION ON UPDATE NO ACTION)
682
+
# show meta
683
+
show create table t2;
684
+
Table Create Table
685
+
t2 CREATE TABLE `t2` (
686
+
`a` int DEFAULT '0',
687
+
`b` int DEFAULT '0',
688
+
`c` int DEFAULT '0',
689
+
`d` int DEFAULT '0',
690
+
`e` int DEFAULT '0',
691
+
`f` int DEFAULT '0',
692
+
`b1` int GENERATED ALWAYS AS (`b`) STORED NOT NULL,
693
+
`c1` int GENERATED ALWAYS AS (`c`) STORED NOT NULL,
694
+
`a1` int GENERATED ALWAYS AS (`a`) STORED NOT NULL,
695
+
`b2` int GENERATED ALWAYS AS (`b`) STORED NOT NULL,
696
+
`c2` int GENERATED ALWAYS AS (`c`) STORED NOT NULL,
697
+
`a2` int GENERATED ALWAYS AS (`a`) STORED NOT NULL,
698
+
`b3` int GENERATED ALWAYS AS (`b`) STORED NOT NULL,
699
+
`c3` int GENERATED ALWAYS AS (`c`) STORED NOT NULL,
700
+
`a3` int GENERATED ALWAYS AS (`a`) STORED NOT NULL,
0 commit comments