github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/optbuilder/testdata/fk-on-update-cascade (about)

     1  exec-ddl
     2  CREATE TABLE parent (p INT PRIMARY KEY)
     3  ----
     4  
     5  exec-ddl
     6  CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p) ON UPDATE CASCADE)
     7  ----
     8  
     9  build-cascades
    10  UPDATE parent SET p = p * 10 WHERE p > 1
    11  ----
    12  root
    13   ├── update parent
    14   │    ├── columns: <none>
    15   │    ├── fetch columns: p:2
    16   │    ├── update-mapping:
    17   │    │    └── p_new:3 => p:1
    18   │    ├── input binding: &1
    19   │    ├── cascades
    20   │    │    └── fk_p_ref_parent
    21   │    └── project
    22   │         ├── columns: p_new:3!null p:2!null
    23   │         ├── select
    24   │         │    ├── columns: p:2!null
    25   │         │    ├── scan parent
    26   │         │    │    └── columns: p:2!null
    27   │         │    └── filters
    28   │         │         └── p:2 > 1
    29   │         └── projections
    30   │              └── p:2 * 10 [as=p_new:3]
    31   └── cascade
    32        └── update child
    33             ├── columns: <none>
    34             ├── fetch columns: c:6 child.p:7
    35             ├── update-mapping:
    36             │    └── p_new:9 => child.p:5
    37             ├── input binding: &2
    38             ├── inner-join (hash)
    39             │    ├── columns: c:6!null child.p:7!null p:8!null p_new:9!null
    40             │    ├── scan child
    41             │    │    └── columns: c:6!null child.p:7!null
    42             │    ├── select
    43             │    │    ├── columns: p:8!null p_new:9!null
    44             │    │    ├── with-scan &1
    45             │    │    │    ├── columns: p:8!null p_new:9!null
    46             │    │    │    └── mapping:
    47             │    │    │         ├──  parent.p:2 => p:8
    48             │    │    │         └──  p_new:3 => p_new:9
    49             │    │    └── filters
    50             │    │         └── p:8 IS DISTINCT FROM p_new:9
    51             │    └── filters
    52             │         └── child.p:7 = p:8
    53             └── f-k-checks
    54                  └── f-k-checks-item: child(p) -> parent(p)
    55                       └── anti-join (hash)
    56                            ├── columns: p_new:10!null
    57                            ├── with-scan &2
    58                            │    ├── columns: p_new:10!null
    59                            │    └── mapping:
    60                            │         └──  p_new:9 => p_new:10
    61                            ├── scan parent
    62                            │    └── columns: parent.p:11!null
    63                            └── filters
    64                                 └── p_new:10 = parent.p:11
    65  
    66  exec-ddl
    67  CREATE TABLE parent_multi (
    68    pk INT PRIMARY KEY,
    69    p INT, q INT,
    70    UNIQUE (p, q),
    71    FAMILY (pk),
    72    FAMILY (p),
    73    FAMILY (q)
    74  )
    75  ----
    76  
    77  exec-ddl
    78  CREATE TABLE child_multi (
    79    c INT PRIMARY KEY,
    80    p INT, q INT,
    81    UNIQUE (c, q),
    82    CONSTRAINT fk FOREIGN KEY (p, q) REFERENCES parent_multi(p, q) ON UPDATE CASCADE 
    83  )
    84  ----
    85  
    86  build-cascades
    87  UPDATE parent_multi SET p = p * 10, q = q + 1 WHERE pk > 1
    88  ----
    89  root
    90   ├── update parent_multi
    91   │    ├── columns: <none>
    92   │    ├── fetch columns: pk:4 p:5 q:6
    93   │    ├── update-mapping:
    94   │    │    ├── p_new:7 => p:2
    95   │    │    └── q_new:8 => q:3
    96   │    ├── input binding: &1
    97   │    ├── cascades
    98   │    │    └── fk
    99   │    └── project
   100   │         ├── columns: p_new:7 q_new:8 pk:4!null p:5 q:6
   101   │         ├── select
   102   │         │    ├── columns: pk:4!null p:5 q:6
   103   │         │    ├── scan parent_multi
   104   │         │    │    └── columns: pk:4!null p:5 q:6
   105   │         │    └── filters
   106   │         │         └── pk:4 > 1
   107   │         └── projections
   108   │              ├── p:5 * 10 [as=p_new:7]
   109   │              └── q:6 + 1 [as=q_new:8]
   110   └── cascade
   111        └── update child_multi
   112             ├── columns: <none>
   113             ├── fetch columns: c:12 child_multi.p:13 child_multi.q:14
   114             ├── update-mapping:
   115             │    ├── p_new:17 => child_multi.p:10
   116             │    └── q_new:18 => child_multi.q:11
   117             ├── input binding: &2
   118             ├── inner-join (hash)
   119             │    ├── columns: c:12!null child_multi.p:13!null child_multi.q:14!null p:15!null q:16!null p_new:17 q_new:18
   120             │    ├── scan child_multi
   121             │    │    └── columns: c:12!null child_multi.p:13 child_multi.q:14
   122             │    ├── select
   123             │    │    ├── columns: p:15 q:16 p_new:17 q_new:18
   124             │    │    ├── with-scan &1
   125             │    │    │    ├── columns: p:15 q:16 p_new:17 q_new:18
   126             │    │    │    └── mapping:
   127             │    │    │         ├──  parent_multi.p:5 => p:15
   128             │    │    │         ├──  parent_multi.q:6 => q:16
   129             │    │    │         ├──  p_new:7 => p_new:17
   130             │    │    │         └──  q_new:8 => q_new:18
   131             │    │    └── filters
   132             │    │         └── (p:15 IS DISTINCT FROM p_new:17) OR (q:16 IS DISTINCT FROM q_new:18)
   133             │    └── filters
   134             │         ├── child_multi.p:13 = p:15
   135             │         └── child_multi.q:14 = q:16
   136             └── f-k-checks
   137                  └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q)
   138                       └── anti-join (hash)
   139                            ├── columns: p_new:19!null q_new:20!null
   140                            ├── select
   141                            │    ├── columns: p_new:19!null q_new:20!null
   142                            │    ├── with-scan &2
   143                            │    │    ├── columns: p_new:19 q_new:20
   144                            │    │    └── mapping:
   145                            │    │         ├──  p_new:17 => p_new:19
   146                            │    │         └──  q_new:18 => q_new:20
   147                            │    └── filters
   148                            │         ├── p_new:19 IS NOT NULL
   149                            │         └── q_new:20 IS NOT NULL
   150                            ├── scan parent_multi
   151                            │    └── columns: parent_multi.p:22 parent_multi.q:23
   152                            └── filters
   153                                 ├── p_new:19 = parent_multi.p:22
   154                                 └── q_new:20 = parent_multi.q:23
   155  
   156  # Update only one of the two FK columns. The "before" and "after" values of q
   157  # come from the same column in the mutation input.
   158  build-cascades
   159  UPDATE parent_multi SET p = p * 10 WHERE p > 1
   160  ----
   161  root
   162   ├── update parent_multi
   163   │    ├── columns: <none>
   164   │    ├── fetch columns: pk:4 p:5 q:6
   165   │    ├── update-mapping:
   166   │    │    └── p_new:7 => p:2
   167   │    ├── input binding: &1
   168   │    ├── cascades
   169   │    │    └── fk
   170   │    └── project
   171   │         ├── columns: p_new:7!null pk:4!null p:5!null q:6
   172   │         ├── select
   173   │         │    ├── columns: pk:4!null p:5!null q:6
   174   │         │    ├── scan parent_multi
   175   │         │    │    └── columns: pk:4!null p:5 q:6
   176   │         │    └── filters
   177   │         │         └── p:5 > 1
   178   │         └── projections
   179   │              └── p:5 * 10 [as=p_new:7]
   180   └── cascade
   181        └── update child_multi
   182             ├── columns: <none>
   183             ├── fetch columns: c:11 child_multi.p:12 child_multi.q:13
   184             ├── update-mapping:
   185             │    ├── p_new:16 => child_multi.p:9
   186             │    └── q:17 => child_multi.q:10
   187             ├── input binding: &2
   188             ├── inner-join (hash)
   189             │    ├── columns: c:11!null child_multi.p:12!null child_multi.q:13!null p:14!null q:15!null p_new:16!null q:17
   190             │    ├── scan child_multi
   191             │    │    └── columns: c:11!null child_multi.p:12 child_multi.q:13
   192             │    ├── select
   193             │    │    ├── columns: p:14!null q:15 p_new:16!null q:17
   194             │    │    ├── with-scan &1
   195             │    │    │    ├── columns: p:14!null q:15 p_new:16!null q:17
   196             │    │    │    └── mapping:
   197             │    │    │         ├──  parent_multi.p:5 => p:14
   198             │    │    │         ├──  parent_multi.q:6 => q:15
   199             │    │    │         ├──  p_new:7 => p_new:16
   200             │    │    │         └──  parent_multi.q:6 => q:17
   201             │    │    └── filters
   202             │    │         └── (p:14 IS DISTINCT FROM p_new:16) OR (q:15 IS DISTINCT FROM q:17)
   203             │    └── filters
   204             │         ├── child_multi.p:12 = p:14
   205             │         └── child_multi.q:13 = q:15
   206             └── f-k-checks
   207                  └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q)
   208                       └── anti-join (hash)
   209                            ├── columns: p_new:18!null q:19!null
   210                            ├── select
   211                            │    ├── columns: p_new:18!null q:19!null
   212                            │    ├── with-scan &2
   213                            │    │    ├── columns: p_new:18!null q:19
   214                            │    │    └── mapping:
   215                            │    │         ├──  p_new:16 => p_new:18
   216                            │    │         └──  q:17 => q:19
   217                            │    └── filters
   218                            │         └── q:19 IS NOT NULL
   219                            ├── scan parent_multi
   220                            │    └── columns: parent_multi.p:21 parent_multi.q:22
   221                            └── filters
   222                                 ├── p_new:18 = parent_multi.p:21
   223                                 └── q:19 = parent_multi.q:22
   224  
   225  # Test a two-level cascade.
   226  exec-ddl
   227  CREATE TABLE grandchild (
   228    g INT PRIMARY KEY,
   229    c INT, q INT,
   230    CONSTRAINT fk2 FOREIGN KEY (c, q) REFERENCES child_multi(c, q) ON UPDATE CASCADE
   231  )
   232  ----
   233  
   234  build-cascades
   235  UPDATE parent_multi SET q = q * 10 WHERE p > 1
   236  ----
   237  root
   238   ├── update parent_multi
   239   │    ├── columns: <none>
   240   │    ├── fetch columns: pk:4 p:5 q:6
   241   │    ├── update-mapping:
   242   │    │    └── q_new:7 => q:3
   243   │    ├── input binding: &1
   244   │    ├── cascades
   245   │    │    └── fk
   246   │    └── project
   247   │         ├── columns: q_new:7 pk:4!null p:5!null q:6
   248   │         ├── select
   249   │         │    ├── columns: pk:4!null p:5!null q:6
   250   │         │    ├── scan parent_multi
   251   │         │    │    └── columns: pk:4!null p:5 q:6
   252   │         │    └── filters
   253   │         │         └── p:5 > 1
   254   │         └── projections
   255   │              └── q:6 * 10 [as=q_new:7]
   256   └── cascade
   257        ├── update child_multi
   258        │    ├── columns: <none>
   259        │    ├── fetch columns: c:11 child_multi.p:12 child_multi.q:13
   260        │    ├── update-mapping:
   261        │    │    ├── p:16 => child_multi.p:9
   262        │    │    └── q_new:17 => child_multi.q:10
   263        │    ├── input binding: &2
   264        │    ├── cascades
   265        │    │    └── fk2
   266        │    ├── inner-join (hash)
   267        │    │    ├── columns: c:11!null child_multi.p:12!null child_multi.q:13!null p:14!null q:15!null p:16!null q_new:17
   268        │    │    ├── scan child_multi
   269        │    │    │    └── columns: c:11!null child_multi.p:12 child_multi.q:13
   270        │    │    ├── select
   271        │    │    │    ├── columns: p:14!null q:15 p:16!null q_new:17
   272        │    │    │    ├── with-scan &1
   273        │    │    │    │    ├── columns: p:14!null q:15 p:16!null q_new:17
   274        │    │    │    │    └── mapping:
   275        │    │    │    │         ├──  parent_multi.p:5 => p:14
   276        │    │    │    │         ├──  parent_multi.q:6 => q:15
   277        │    │    │    │         ├──  parent_multi.p:5 => p:16
   278        │    │    │    │         └──  q_new:7 => q_new:17
   279        │    │    │    └── filters
   280        │    │    │         └── (p:14 IS DISTINCT FROM p:16) OR (q:15 IS DISTINCT FROM q_new:17)
   281        │    │    └── filters
   282        │    │         ├── child_multi.p:12 = p:14
   283        │    │         └── child_multi.q:13 = q:15
   284        │    └── f-k-checks
   285        │         └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q)
   286        │              └── anti-join (hash)
   287        │                   ├── columns: p:18!null q_new:19!null
   288        │                   ├── select
   289        │                   │    ├── columns: p:18!null q_new:19!null
   290        │                   │    ├── with-scan &2
   291        │                   │    │    ├── columns: p:18!null q_new:19
   292        │                   │    │    └── mapping:
   293        │                   │    │         ├──  p:16 => p:18
   294        │                   │    │         └──  q_new:17 => q_new:19
   295        │                   │    └── filters
   296        │                   │         └── q_new:19 IS NOT NULL
   297        │                   ├── scan parent_multi
   298        │                   │    └── columns: parent_multi.p:21 parent_multi.q:22
   299        │                   └── filters
   300        │                        ├── p:18 = parent_multi.p:21
   301        │                        └── q_new:19 = parent_multi.q:22
   302        └── cascade
   303             └── update grandchild
   304                  ├── columns: <none>
   305                  ├── fetch columns: g:26 grandchild.c:27 grandchild.q:28
   306                  ├── update-mapping:
   307                  │    ├── c:31 => grandchild.c:24
   308                  │    └── q_new:32 => grandchild.q:25
   309                  ├── input binding: &3
   310                  ├── inner-join (hash)
   311                  │    ├── columns: g:26!null grandchild.c:27!null grandchild.q:28!null c:29!null q:30!null c:31!null q_new:32
   312                  │    ├── scan grandchild
   313                  │    │    └── columns: g:26!null grandchild.c:27 grandchild.q:28
   314                  │    ├── select
   315                  │    │    ├── columns: c:29!null q:30!null c:31!null q_new:32
   316                  │    │    ├── with-scan &2
   317                  │    │    │    ├── columns: c:29!null q:30!null c:31!null q_new:32
   318                  │    │    │    └── mapping:
   319                  │    │    │         ├──  child_multi.c:11 => c:29
   320                  │    │    │         ├──  child_multi.q:13 => q:30
   321                  │    │    │         ├──  child_multi.c:11 => c:31
   322                  │    │    │         └──  q_new:17 => q_new:32
   323                  │    │    └── filters
   324                  │    │         └── (c:29 IS DISTINCT FROM c:31) OR (q:30 IS DISTINCT FROM q_new:32)
   325                  │    └── filters
   326                  │         ├── grandchild.c:27 = c:29
   327                  │         └── grandchild.q:28 = q:30
   328                  └── f-k-checks
   329                       └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q)
   330                            └── anti-join (hash)
   331                                 ├── columns: c:33!null q_new:34!null
   332                                 ├── select
   333                                 │    ├── columns: c:33!null q_new:34!null
   334                                 │    ├── with-scan &3
   335                                 │    │    ├── columns: c:33!null q_new:34
   336                                 │    │    └── mapping:
   337                                 │    │         ├──  c:31 => c:33
   338                                 │    │         └──  q_new:32 => q_new:34
   339                                 │    └── filters
   340                                 │         └── q_new:34 IS NOT NULL
   341                                 ├── scan child_multi
   342                                 │    └── columns: child_multi.c:35!null child_multi.q:37
   343                                 └── filters
   344                                      ├── c:33 = child_multi.c:35
   345                                      └── q_new:34 = child_multi.q:37