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