github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/exec/execbuilder/testdata/fk_opt (about) 1 # LogicTest: local 2 3 statement ok 4 SET optimizer_foreign_keys = true 5 6 # We will test the fast path later. 7 statement ok 8 SET enable_insert_fast_path = false 9 10 # -- Tests with INSERT -- 11 12 statement ok 13 CREATE TABLE parent (p INT PRIMARY KEY, other INT UNIQUE, FAMILY (p, other)) 14 15 statement ok 16 CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p), FAMILY (c, p)) 17 18 query TTT 19 EXPLAIN INSERT INTO child VALUES (1,1), (2,2) 20 ---- 21 · distributed false 22 · vectorized false 23 root · · 24 ├── count · · 25 │ └── insert · · 26 │ │ into child(c, p) 27 │ │ strategy inserter 28 │ └── buffer node · · 29 │ │ label buffer 1 30 │ └── values · · 31 │ size 2 columns, 2 rows 32 └── fk-check · · 33 └── error if rows · · 34 └── lookup-join · · 35 │ table parent@primary 36 │ type anti 37 │ equality (column2) = (p) 38 │ equality cols are key · 39 │ parallel · 40 └── render · · 41 └── scan buffer node · · 42 · label buffer 1 43 44 # Use data from a different table as input. 45 statement ok 46 CREATE TABLE xy (x INT, y INT) 47 48 query TTT 49 EXPLAIN INSERT INTO child SELECT x,y FROM xy 50 ---- 51 · distributed false 52 · vectorized false 53 root · · 54 ├── count · · 55 │ └── insert · · 56 │ │ into child(c, p) 57 │ │ strategy inserter 58 │ └── buffer node · · 59 │ │ label buffer 1 60 │ └── scan · · 61 │ table xy@primary 62 │ spans FULL SCAN 63 └── fk-check · · 64 └── error if rows · · 65 └── hash-join · · 66 │ type anti 67 │ equality (y) = (p) 68 │ right cols are key · 69 ├── render · · 70 │ └── scan buffer node · · 71 │ label buffer 1 72 └── scan · · 73 · table parent@primary 74 · spans FULL SCAN 75 76 statement ok 77 CREATE TABLE child_nullable (c INT PRIMARY KEY, p INT REFERENCES parent(p)); 78 79 # Because the input column can be NULL (in which case it requires no FK match), 80 # we have to add an extra filter. 81 query TTT 82 EXPLAIN INSERT INTO child_nullable VALUES (100, 1), (200, NULL) 83 ---- 84 · distributed false 85 · vectorized false 86 root · · 87 ├── count · · 88 │ └── insert · · 89 │ │ into child_nullable(c, p) 90 │ │ strategy inserter 91 │ └── buffer node · · 92 │ │ label buffer 1 93 │ └── values · · 94 │ size 2 columns, 2 rows 95 └── fk-check · · 96 └── error if rows · · 97 └── lookup-join · · 98 │ table parent@primary 99 │ type anti 100 │ equality (column2) = (p) 101 │ equality cols are key · 102 │ parallel · 103 └── filter · · 104 │ filter column2 IS NOT NULL 105 └── render · · 106 └── scan buffer node · · 107 · label buffer 1 108 109 # Tests with multicolumn FKs. 110 statement ok 111 CREATE TABLE multi_col_parent (p INT, q INT, r INT, other INT, PRIMARY KEY (p, q, r)) 112 113 statement ok 114 CREATE TABLE multi_col_child ( 115 c INT PRIMARY KEY, 116 p INT, q INT, r INT, 117 CONSTRAINT fk FOREIGN KEY (p,q,r) REFERENCES multi_col_parent(p,q,r) MATCH SIMPLE 118 ) 119 120 # Only p and q are nullable. 121 query TTT 122 EXPLAIN INSERT INTO multi_col_child VALUES (2, NULL, 20, 20), (3, 20, NULL, 20) 123 ---- 124 · distributed false 125 · vectorized false 126 root · · 127 ├── count · · 128 │ └── insert · · 129 │ │ into multi_col_child(c, p, q, r) 130 │ │ strategy inserter 131 │ └── buffer node · · 132 │ │ label buffer 1 133 │ └── values · · 134 │ size 4 columns, 2 rows 135 └── fk-check · · 136 └── error if rows · · 137 └── lookup-join · · 138 │ table multi_col_parent@primary 139 │ type anti 140 │ equality (column2, column3, column4) = (p, q, r) 141 │ equality cols are key · 142 │ parallel · 143 └── filter · · 144 │ filter (column2 IS NOT NULL) AND (column3 IS NOT NULL) 145 └── render · · 146 └── scan buffer node · · 147 · label buffer 1 148 149 statement ok 150 CREATE TABLE multi_ref_parent_a (a INT PRIMARY KEY, other INT) 151 152 statement ok 153 CREATE TABLE multi_ref_parent_bc (b INT, c INT, PRIMARY KEY (b,c), other INT) 154 155 statement ok 156 CREATE TABLE multi_ref_child ( 157 k INT PRIMARY KEY, 158 a INT, 159 b INT, 160 c INT, 161 CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES multi_ref_parent_a(a), 162 CONSTRAINT fk2 FOREIGN KEY (b,c) REFERENCES multi_ref_parent_bc(b,c) 163 ) 164 165 query TTT 166 EXPLAIN INSERT INTO multi_ref_child VALUES (1, NULL, NULL, NULL), (2, 3, 4, 5) 167 ---- 168 · distributed false 169 · vectorized false 170 root · · 171 ├── count · · 172 │ └── insert · · 173 │ │ into multi_ref_child(k, a, b, c) 174 │ │ strategy inserter 175 │ └── buffer node · · 176 │ │ label buffer 1 177 │ └── values · · 178 │ size 4 columns, 2 rows 179 ├── fk-check · · 180 │ └── error if rows · · 181 │ └── lookup-join · · 182 │ │ table multi_ref_parent_a@primary 183 │ │ type anti 184 │ │ equality (column2) = (a) 185 │ │ equality cols are key · 186 │ │ parallel · 187 │ └── filter · · 188 │ │ filter column2 IS NOT NULL 189 │ └── render · · 190 │ └── scan buffer node · · 191 │ label buffer 1 192 └── fk-check · · 193 └── error if rows · · 194 └── lookup-join · · 195 │ table multi_ref_parent_bc@primary 196 │ type anti 197 │ equality (column3, column4) = (b, c) 198 │ equality cols are key · 199 │ parallel · 200 └── filter · · 201 │ filter (column3 IS NOT NULL) AND (column4 IS NOT NULL) 202 └── render · · 203 └── scan buffer node · · 204 · label buffer 1 205 206 # FK check can be omitted when we are inserting only NULLs. 207 query TTT 208 EXPLAIN INSERT INTO multi_ref_child VALUES (1, NULL, NULL, NULL) 209 ---- 210 · distributed false 211 · vectorized false 212 count · · 213 └── insert · · 214 │ into multi_ref_child(k, a, b, c) 215 │ strategy inserter 216 │ auto commit · 217 └── values · · 218 · size 4 columns, 1 row 219 220 # -- Tests with DELETE -- 221 222 query TTT 223 EXPLAIN DELETE FROM parent WHERE p = 3 224 ---- 225 · distributed false 226 · vectorized false 227 root · · 228 ├── count · · 229 │ └── delete · · 230 │ │ from parent 231 │ │ strategy deleter 232 │ └── buffer node · · 233 │ │ label buffer 1 234 │ └── scan · · 235 │ table parent@primary 236 │ spans /3-/3/# 237 ├── fk-check · · 238 │ └── error if rows · · 239 │ └── lookup-join · · 240 │ │ table child@child_auto_index_fk_p_ref_parent 241 │ │ type semi 242 │ │ equality (p) = (p) 243 │ └── render · · 244 │ └── scan buffer node · · 245 │ label buffer 1 246 └── fk-check · · 247 └── error if rows · · 248 └── lookup-join · · 249 │ table child_nullable@child_nullable_auto_index_fk_p_ref_parent 250 │ type semi 251 │ equality (p) = (p) 252 └── render · · 253 └── scan buffer node · · 254 · label buffer 1 255 256 statement ok 257 CREATE TABLE child2 (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(other)) 258 259 query TTT 260 EXPLAIN DELETE FROM parent WHERE p = 3 261 ---- 262 · distributed false 263 · vectorized false 264 root · · 265 ├── count · · 266 │ └── delete · · 267 │ │ from parent 268 │ │ strategy deleter 269 │ └── buffer node · · 270 │ │ label buffer 1 271 │ └── scan · · 272 │ table parent@primary 273 │ spans /3-/3/# 274 ├── fk-check · · 275 │ └── error if rows · · 276 │ └── lookup-join · · 277 │ │ table child@child_auto_index_fk_p_ref_parent 278 │ │ type semi 279 │ │ equality (p) = (p) 280 │ └── render · · 281 │ └── scan buffer node · · 282 │ label buffer 1 283 ├── fk-check · · 284 │ └── error if rows · · 285 │ └── lookup-join · · 286 │ │ table child_nullable@child_nullable_auto_index_fk_p_ref_parent 287 │ │ type semi 288 │ │ equality (p) = (p) 289 │ └── render · · 290 │ └── scan buffer node · · 291 │ label buffer 1 292 └── fk-check · · 293 └── error if rows · · 294 └── lookup-join · · 295 │ table child2@child2_auto_index_fk_p_ref_parent 296 │ type semi 297 │ equality (other) = (p) 298 └── render · · 299 └── scan buffer node · · 300 · label buffer 1 301 302 statement ok 303 CREATE TABLE doubleparent (p1 INT, p2 INT, other INT, PRIMARY KEY (p1, p2)) 304 305 statement ok 306 CREATE TABLE doublechild ( 307 c INT8 PRIMARY KEY, 308 p1 INT8, 309 p2 INT8, 310 FOREIGN KEY (p1, p2) REFERENCES doubleparent (p1, p2) 311 ) 312 313 query TTT 314 EXPLAIN DELETE FROM doubleparent WHERE p1 = 10 315 ---- 316 · distributed false 317 · vectorized false 318 root · · 319 ├── count · · 320 │ └── delete · · 321 │ │ from doubleparent 322 │ │ strategy deleter 323 │ └── buffer node · · 324 │ │ label buffer 1 325 │ └── scan · · 326 │ table doubleparent@primary 327 │ spans /10-/11 328 └── fk-check · · 329 └── error if rows · · 330 └── lookup-join · · 331 │ table doublechild@doublechild_auto_index_fk_p1_ref_doubleparent 332 │ type semi 333 │ equality (p1, p2) = (p1, p2) 334 └── scan buffer node · · 335 · label buffer 1 336 337 # -- Tests with UPDATE -- 338 339 query TTT 340 EXPLAIN UPDATE child SET p = 4 341 ---- 342 · distributed false 343 · vectorized false 344 root · · 345 ├── count · · 346 │ └── update · · 347 │ │ table child 348 │ │ set p 349 │ │ strategy updater 350 │ └── buffer node · · 351 │ │ label buffer 1 352 │ └── render · · 353 │ └── scan · · 354 │ table child@primary 355 │ spans FULL SCAN 356 │ locking strength for update 357 └── fk-check · · 358 └── error if rows · · 359 └── hash-join · · 360 │ type anti 361 │ equality (p_new) = (p) 362 │ right cols are key · 363 ├── render · · 364 │ └── scan buffer node · · 365 │ label buffer 1 366 └── scan · · 367 · table parent@primary 368 · spans FULL SCAN 369 370 query TTT 371 EXPLAIN UPDATE child SET p = 4 WHERE c = 10 372 ---- 373 · distributed false 374 · vectorized false 375 root · · 376 ├── count · · 377 │ └── update · · 378 │ │ table child 379 │ │ set p 380 │ │ strategy updater 381 │ └── buffer node · · 382 │ │ label buffer 1 383 │ └── render · · 384 │ └── scan · · 385 │ table child@primary 386 │ spans /10-/10/# 387 │ locking strength for update 388 └── fk-check · · 389 └── error if rows · · 390 └── lookup-join · · 391 │ table parent@primary 392 │ type anti 393 │ equality (p_new) = (p) 394 │ equality cols are key · 395 │ parallel · 396 └── render · · 397 └── scan buffer node · · 398 · label buffer 1 399 400 query TTT 401 EXPLAIN UPDATE parent SET p = p+1 402 ---- 403 · distributed false 404 · vectorized false 405 root · · 406 ├── count · · 407 │ └── update · · 408 │ │ table parent 409 │ │ set p 410 │ │ strategy updater 411 │ └── buffer node · · 412 │ │ label buffer 1 413 │ └── render · · 414 │ └── scan · · 415 │ table parent@primary 416 │ spans FULL SCAN 417 │ locking strength for update 418 ├── fk-check · · 419 │ └── error if rows · · 420 │ └── render · · 421 │ └── hash-join · · 422 │ │ type inner 423 │ │ equality (p) = (p) 424 │ │ left cols are key · 425 │ │ right cols are key · 426 │ ├── union · · 427 │ │ ├── render · · 428 │ │ │ └── scan buffer node · · 429 │ │ │ label buffer 1 430 │ │ └── render · · 431 │ │ └── scan buffer node · · 432 │ │ label buffer 1 433 │ └── distinct · · 434 │ │ distinct on p 435 │ │ order key p 436 │ └── scan · · 437 │ table child@child_auto_index_fk_p_ref_parent 438 │ spans FULL SCAN 439 └── fk-check · · 440 └── error if rows · · 441 └── render · · 442 └── hash-join · · 443 │ type inner 444 │ equality (p) = (p) 445 │ left cols are key · 446 │ right cols are key · 447 ├── union · · 448 │ ├── render · · 449 │ │ └── scan buffer node · · 450 │ │ label buffer 1 451 │ └── render · · 452 │ └── scan buffer node · · 453 │ label buffer 1 454 └── distinct · · 455 │ distinct on p 456 │ order key p 457 └── scan · · 458 · table child_nullable@child_nullable_auto_index_fk_p_ref_parent 459 · spans FULL SCAN 460 461 query TTT 462 EXPLAIN UPDATE parent SET p = p+1 WHERE other = 10 463 ---- 464 · distributed false 465 · vectorized false 466 root · · 467 ├── count · · 468 │ └── update · · 469 │ │ table parent 470 │ │ set p 471 │ │ strategy updater 472 │ └── buffer node · · 473 │ │ label buffer 1 474 │ └── render · · 475 │ └── scan · · 476 │ table parent@parent_other_key 477 │ spans /10-/11 478 │ locking strength for update 479 ├── fk-check · · 480 │ └── error if rows · · 481 │ └── lookup-join · · 482 │ │ table child@child_auto_index_fk_p_ref_parent 483 │ │ type semi 484 │ │ equality (p) = (p) 485 │ └── union · · 486 │ ├── render · · 487 │ │ └── scan buffer node · · 488 │ │ label buffer 1 489 │ └── render · · 490 │ └── scan buffer node · · 491 │ label buffer 1 492 └── fk-check · · 493 └── error if rows · · 494 └── lookup-join · · 495 │ table child_nullable@child_nullable_auto_index_fk_p_ref_parent 496 │ type semi 497 │ equality (p) = (p) 498 └── union · · 499 ├── render · · 500 │ └── scan buffer node · · 501 │ label buffer 1 502 └── render · · 503 └── scan buffer node · · 504 · label buffer 1 505 506 statement ok 507 CREATE TABLE grandchild (g INT PRIMARY KEY, c INT NOT NULL REFERENCES child(c)) 508 509 query TTT 510 EXPLAIN UPDATE child SET c = 4 511 ---- 512 · distributed false 513 · vectorized false 514 root · · 515 ├── count · · 516 │ └── update · · 517 │ │ table child 518 │ │ set c 519 │ │ strategy updater 520 │ └── buffer node · · 521 │ │ label buffer 1 522 │ └── render · · 523 │ └── scan · · 524 │ table child@primary 525 │ spans FULL SCAN 526 │ locking strength for update 527 └── fk-check · · 528 └── error if rows · · 529 └── render · · 530 └── hash-join · · 531 │ type inner 532 │ equality (c) = (c) 533 │ left cols are key · 534 │ right cols are key · 535 ├── union · · 536 │ ├── render · · 537 │ │ └── scan buffer node · · 538 │ │ label buffer 1 539 │ └── render · · 540 │ └── scan buffer node · · 541 │ label buffer 1 542 └── distinct · · 543 │ distinct on c 544 │ order key c 545 └── scan · · 546 · table grandchild@grandchild_auto_index_fk_c_ref_child 547 · spans FULL SCAN 548 549 # This update shouldn't emit checks for c, since it's unchanged. 550 query TTT 551 EXPLAIN UPDATE child SET p = 4 552 ---- 553 · distributed false 554 · vectorized false 555 root · · 556 ├── count · · 557 │ └── update · · 558 │ │ table child 559 │ │ set p 560 │ │ strategy updater 561 │ └── buffer node · · 562 │ │ label buffer 1 563 │ └── render · · 564 │ └── scan · · 565 │ table child@primary 566 │ spans FULL SCAN 567 │ locking strength for update 568 └── fk-check · · 569 └── error if rows · · 570 └── hash-join · · 571 │ type anti 572 │ equality (p_new) = (p) 573 │ right cols are key · 574 ├── render · · 575 │ └── scan buffer node · · 576 │ label buffer 1 577 └── scan · · 578 · table parent@primary 579 · spans FULL SCAN 580 581 query TTT 582 EXPLAIN UPDATE child SET p = p 583 ---- 584 · distributed false 585 · vectorized false 586 root · · 587 ├── count · · 588 │ └── update · · 589 │ │ table child 590 │ │ set p 591 │ │ strategy updater 592 │ └── buffer node · · 593 │ │ label buffer 1 594 │ └── render · · 595 │ └── scan · · 596 │ table child@primary 597 │ spans FULL SCAN 598 │ locking strength for update 599 └── fk-check · · 600 └── error if rows · · 601 └── hash-join · · 602 │ type anti 603 │ equality (p) = (p) 604 │ right cols are key · 605 ├── render · · 606 │ └── scan buffer node · · 607 │ label buffer 1 608 └── scan · · 609 · table parent@primary 610 · spans FULL SCAN 611 612 query TTT 613 EXPLAIN UPDATE child SET p = p+1, c = c+1 614 ---- 615 · distributed false 616 · vectorized false 617 root · · 618 ├── count · · 619 │ └── update · · 620 │ │ table child 621 │ │ set c, p 622 │ │ strategy updater 623 │ └── buffer node · · 624 │ │ label buffer 1 625 │ └── render · · 626 │ └── scan · · 627 │ table child@primary 628 │ spans FULL SCAN 629 │ locking strength for update 630 ├── fk-check · · 631 │ └── error if rows · · 632 │ └── hash-join · · 633 │ │ type anti 634 │ │ equality (p_new) = (p) 635 │ │ right cols are key · 636 │ ├── render · · 637 │ │ └── scan buffer node · · 638 │ │ label buffer 1 639 │ └── scan · · 640 │ table parent@primary 641 │ spans FULL SCAN 642 └── fk-check · · 643 └── error if rows · · 644 └── render · · 645 └── hash-join · · 646 │ type inner 647 │ equality (c) = (c) 648 │ left cols are key · 649 │ right cols are key · 650 ├── union · · 651 │ ├── render · · 652 │ │ └── scan buffer node · · 653 │ │ label buffer 1 654 │ └── render · · 655 │ └── scan buffer node · · 656 │ label buffer 1 657 └── distinct · · 658 │ distinct on c 659 │ order key c 660 └── scan · · 661 · table grandchild@grandchild_auto_index_fk_c_ref_child 662 · spans FULL SCAN 663 664 # Multiple grandchild tables 665 statement ok 666 CREATE TABLE grandchild2 (g INT PRIMARY KEY, c INT NOT NULL REFERENCES child(c)) 667 668 query TTT 669 EXPLAIN UPDATE child SET p = 4 670 ---- 671 · distributed false 672 · vectorized false 673 root · · 674 ├── count · · 675 │ └── update · · 676 │ │ table child 677 │ │ set p 678 │ │ strategy updater 679 │ └── buffer node · · 680 │ │ label buffer 1 681 │ └── render · · 682 │ └── scan · · 683 │ table child@primary 684 │ spans FULL SCAN 685 │ locking strength for update 686 └── fk-check · · 687 └── error if rows · · 688 └── hash-join · · 689 │ type anti 690 │ equality (p_new) = (p) 691 │ right cols are key · 692 ├── render · · 693 │ └── scan buffer node · · 694 │ label buffer 1 695 └── scan · · 696 · table parent@primary 697 · spans FULL SCAN 698 699 statement ok 700 CREATE TABLE self (x INT PRIMARY KEY, y INT NOT NULL REFERENCES self(x)) 701 702 query TTT 703 EXPLAIN UPDATE self SET y = 3 704 ---- 705 · distributed false 706 · vectorized false 707 root · · 708 ├── count · · 709 │ └── update · · 710 │ │ table self 711 │ │ set y 712 │ │ strategy updater 713 │ └── buffer node · · 714 │ │ label buffer 1 715 │ └── render · · 716 │ └── scan · · 717 │ table self@primary 718 │ spans FULL SCAN 719 │ locking strength for update 720 └── fk-check · · 721 └── error if rows · · 722 └── hash-join · · 723 │ type anti 724 │ equality (y_new) = (x) 725 │ right cols are key · 726 ├── render · · 727 │ └── scan buffer node · · 728 │ label buffer 1 729 └── scan · · 730 · table self@primary 731 · spans FULL SCAN 732 733 query TTT 734 EXPLAIN UPDATE self SET x = 3 735 ---- 736 · distributed false 737 · vectorized false 738 root · · 739 ├── count · · 740 │ └── update · · 741 │ │ table self 742 │ │ set x 743 │ │ strategy updater 744 │ └── buffer node · · 745 │ │ label buffer 1 746 │ └── render · · 747 │ └── scan · · 748 │ table self@primary 749 │ spans FULL SCAN 750 │ locking strength for update 751 └── fk-check · · 752 └── error if rows · · 753 └── render · · 754 └── hash-join · · 755 │ type inner 756 │ equality (x) = (y) 757 │ left cols are key · 758 │ right cols are key · 759 ├── union · · 760 │ ├── render · · 761 │ │ └── scan buffer node · · 762 │ │ label buffer 1 763 │ └── render · · 764 │ └── scan buffer node · · 765 │ label buffer 1 766 └── distinct · · 767 │ distinct on y 768 │ order key y 769 └── scan · · 770 · table self@self_auto_index_fk_y_ref_self 771 · spans FULL SCAN 772 773 # Tests for the insert fast path. 774 statement ok 775 SET enable_insert_fast_path = true 776 777 # Simple insert with VALUES should use the fast path. 778 query TTTTT 779 EXPLAIN (VERBOSE) INSERT INTO child VALUES (1,1), (2,2) 780 ---- 781 · distributed false · · 782 · vectorized false · · 783 count · · () · 784 └── insert-fast-path · · () · 785 · into child(c, p) · · 786 · strategy inserter · · 787 · auto commit · · · 788 · FK check parent@primary · · 789 · size 2 columns, 2 rows · · 790 · row 0, expr 0 1 · · 791 · row 0, expr 1 1 · · 792 · row 1, expr 0 2 · · 793 · row 1, expr 1 2 · · 794 795 # We shouldn't use the fast path if the VALUES columns are not in order. 796 query B 797 SELECT count(*) > 0 FROM [ 798 EXPLAIN INSERT INTO child (SELECT b, a FROM (VALUES (1,2)) AS v(a,b)) 799 ] WHERE tree LIKE '%insert-fast-path' 800 ---- 801 false 802 803 # Multiple mutations shouldn't use the fast-path. 804 query B 805 SELECT count(*) > 0 FROM [ 806 EXPLAIN WITH cte AS (INSERT INTO child VALUES (1, 1) RETURNING p) 807 INSERT INTO parent VALUES (2, 3) 808 ] WHERE tree LIKE '%insert-fast-path' 809 ---- 810 false 811 812 # Self-referencing FKs should not use the fast-path. 813 query B 814 SELECT count(*) > 0 FROM [ 815 EXPLAIN INSERT INTO self VALUES (1, 1) 816 ] WHERE tree LIKE '%insert-fast-path' 817 ---- 818 false 819 820 # We should not use the fast path If the best FK check plan is not a lookup 821 # join. We do this by adding statistics that make a hash join more desirable. 822 statement ok 823 ALTER TABLE parent INJECT STATISTICS '[ 824 { 825 "columns": ["p"], 826 "created_at": "2018-01-01 1:00:00.00000+00:00", 827 "row_count": 1, 828 "distinct_count": 1 829 } 830 ]' 831 832 query B 833 SELECT count(*) > 0 FROM [ 834 EXPLAIN (VERBOSE) INSERT INTO child VALUES (1,1), (2,2), (3,3), (4,4) 835 ] WHERE tree LIKE '%insert-fast-path' 836 ---- 837 false 838 839 # Test FK check that is using a non-unique index (#43969). In this case the 840 # index on k2 is preferred because it doesn't contain unnecessary column v. 841 statement ok 842 CREATE TABLE nonunique_idx_parent ( 843 k1 INT, 844 k2 INT, 845 v INT, 846 CONSTRAINT "primary" PRIMARY KEY (k1, k2), 847 INDEX (k2) 848 ) 849 850 statement ok 851 CREATE TABLE nonunique_idx_child ( 852 k INT PRIMARY KEY, 853 ref1 INT, 854 ref2 INT, 855 CONSTRAINT "fk" FOREIGN KEY (ref1, ref2) REFERENCES nonunique_idx_parent (k1, k2) 856 ) 857 858 query TTT 859 EXPLAIN INSERT INTO nonunique_idx_child VALUES (0, 1, 10) 860 ---- 861 · distributed false 862 · vectorized false 863 count · · 864 └── insert-fast-path · · 865 · into nonunique_idx_child(k, ref1, ref2) 866 · strategy inserter 867 · auto commit · 868 · FK check nonunique_idx_parent@nonunique_idx_parent_k2_idx 869 · size 3 columns, 1 row 870 871 # Regression test for #46397: upserter was looking at the incorrect ordinal for 872 # the check because of an extra input column used by the FK check. 873 statement ok 874 CREATE TABLE t46397_parent(p INT PRIMARY KEY) 875 876 statement ok 877 CREATE TABLE t46397_child ( 878 c INT PRIMARY KEY, 879 p INT DEFAULT 0 REFERENCES t46397_parent (p), 880 CONSTRAINT foo CHECK (c != 1) 881 ) 882 883 statement error failed to satisfy CHECK constraint 884 UPSERT INTO t46397_child(c) VALUES (1) 885 886 statement error upsert on table "t46397_child" violates foreign key constraint "fk_p_ref_t46397_parent" 887 UPSERT INTO t46397_child(c) VALUES (2) 888 889 statement ok 890 INSERT INTO t46397_parent VALUES (0) 891 892 statement ok 893 UPSERT INTO t46397_child(c) VALUES (2) 894 895 896 # Verify that cascade information shows up in EXPLAIN. 897 statement ok 898 SET experimental_optimizer_foreign_key_cascades = true 899 900 statement ok 901 CREATE TABLE cascadeparent (p INT PRIMARY KEY); 902 CREATE TABLE cascadechild ( 903 c INT PRIMARY KEY, 904 p INT NOT NULL REFERENCES cascadeparent(p) ON DELETE CASCADE 905 ) 906 907 query TTTTT 908 EXPLAIN (VERBOSE) DELETE FROM cascadeparent WHERE p > 1 909 ---- 910 · distributed false · · 911 · vectorized false · · 912 root · · () · 913 ├── count · · () · 914 │ └── delete · · () · 915 │ │ from cascadeparent · · 916 │ │ strategy deleter · · 917 │ └── buffer node · · (p) · 918 │ │ label buffer 1 · · 919 │ └── scan · · (p) · 920 │ table cascadeparent@primary · · 921 │ spans /2- · · 922 └── fk-cascade · · · · 923 · fk fk_p_ref_cascadeparent · · 924 · input buffer 1 · ·