github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/optbuilder/testdata/fk-on-update-set-null (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 SET NULL) 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:10 => child.p:5 37 └── project 38 ├── columns: p_new:10 c:6!null child.p:7!null p:8!null p_new:9!null 39 ├── inner-join (hash) 40 │ ├── columns: c:6!null child.p:7!null p:8!null p_new:9!null 41 │ ├── scan child 42 │ │ └── columns: c:6!null child.p:7!null 43 │ ├── select 44 │ │ ├── columns: p:8!null p_new:9!null 45 │ │ ├── with-scan &1 46 │ │ │ ├── columns: p:8!null p_new:9!null 47 │ │ │ └── mapping: 48 │ │ │ ├── parent.p:2 => p:8 49 │ │ │ └── p_new:3 => p_new:9 50 │ │ └── filters 51 │ │ └── p:8 IS DISTINCT FROM p_new:9 52 │ └── filters 53 │ └── child.p:7 = p:8 54 └── projections 55 └── NULL::INT8 [as=p_new:10] 56 57 exec-ddl 58 CREATE TABLE parent_multi ( 59 pk INT PRIMARY KEY, 60 p INT, q INT, 61 UNIQUE (p, q), 62 FAMILY (pk), 63 FAMILY (p), 64 FAMILY (q) 65 ) 66 ---- 67 68 exec-ddl 69 CREATE TABLE child_multi ( 70 c INT PRIMARY KEY, 71 p INT, q INT, 72 UNIQUE (c, q), 73 CONSTRAINT fk FOREIGN KEY (p, q) REFERENCES parent_multi(p, q) ON UPDATE SET NULL 74 ) 75 ---- 76 77 build-cascades 78 UPDATE parent_multi SET p = p * 10, q = q + 1 WHERE pk > 1 79 ---- 80 root 81 ├── update parent_multi 82 │ ├── columns: <none> 83 │ ├── fetch columns: pk:4 p:5 q:6 84 │ ├── update-mapping: 85 │ │ ├── p_new:7 => p:2 86 │ │ └── q_new:8 => q:3 87 │ ├── input binding: &1 88 │ ├── cascades 89 │ │ └── fk 90 │ └── project 91 │ ├── columns: p_new:7 q_new:8 pk:4!null p:5 q:6 92 │ ├── select 93 │ │ ├── columns: pk:4!null p:5 q:6 94 │ │ ├── scan parent_multi 95 │ │ │ └── columns: pk:4!null p:5 q:6 96 │ │ └── filters 97 │ │ └── pk:4 > 1 98 │ └── projections 99 │ ├── p:5 * 10 [as=p_new:7] 100 │ └── q:6 + 1 [as=q_new:8] 101 └── cascade 102 └── update child_multi 103 ├── columns: <none> 104 ├── fetch columns: c:12 child_multi.p:13 child_multi.q:14 105 ├── update-mapping: 106 │ ├── p_new:19 => child_multi.p:10 107 │ └── p_new:19 => child_multi.q:11 108 └── project 109 ├── columns: p_new:19 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 110 ├── inner-join (hash) 111 │ ├── 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 112 │ ├── scan child_multi 113 │ │ └── columns: c:12!null child_multi.p:13 child_multi.q:14 114 │ ├── select 115 │ │ ├── columns: p:15 q:16 p_new:17 q_new:18 116 │ │ ├── with-scan &1 117 │ │ │ ├── columns: p:15 q:16 p_new:17 q_new:18 118 │ │ │ └── mapping: 119 │ │ │ ├── parent_multi.p:5 => p:15 120 │ │ │ ├── parent_multi.q:6 => q:16 121 │ │ │ ├── p_new:7 => p_new:17 122 │ │ │ └── q_new:8 => q_new:18 123 │ │ └── filters 124 │ │ └── (p:15 IS DISTINCT FROM p_new:17) OR (q:16 IS DISTINCT FROM q_new:18) 125 │ └── filters 126 │ ├── child_multi.p:13 = p:15 127 │ └── child_multi.q:14 = q:16 128 └── projections 129 └── NULL::INT8 [as=p_new:19] 130 131 # Update only one of the two FK columns. 132 build-cascades 133 UPDATE parent_multi SET p = p * 10 WHERE p > 1 134 ---- 135 root 136 ├── update parent_multi 137 │ ├── columns: <none> 138 │ ├── fetch columns: pk:4 p:5 q:6 139 │ ├── update-mapping: 140 │ │ └── p_new:7 => p:2 141 │ ├── input binding: &1 142 │ ├── cascades 143 │ │ └── fk 144 │ └── project 145 │ ├── columns: p_new:7!null pk:4!null p:5!null q:6 146 │ ├── select 147 │ │ ├── columns: pk:4!null p:5!null q:6 148 │ │ ├── scan parent_multi 149 │ │ │ └── columns: pk:4!null p:5 q:6 150 │ │ └── filters 151 │ │ └── p:5 > 1 152 │ └── projections 153 │ └── p:5 * 10 [as=p_new:7] 154 └── cascade 155 └── update child_multi 156 ├── columns: <none> 157 ├── fetch columns: c:11 child_multi.p:12 child_multi.q:13 158 ├── update-mapping: 159 │ ├── p_new:18 => child_multi.p:9 160 │ └── p_new:18 => child_multi.q:10 161 └── project 162 ├── columns: p_new:18 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 163 ├── inner-join (hash) 164 │ ├── 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 165 │ ├── scan child_multi 166 │ │ └── columns: c:11!null child_multi.p:12 child_multi.q:13 167 │ ├── select 168 │ │ ├── columns: p:14!null q:15 p_new:16!null q:17 169 │ │ ├── with-scan &1 170 │ │ │ ├── columns: p:14!null q:15 p_new:16!null q:17 171 │ │ │ └── mapping: 172 │ │ │ ├── parent_multi.p:5 => p:14 173 │ │ │ ├── parent_multi.q:6 => q:15 174 │ │ │ ├── p_new:7 => p_new:16 175 │ │ │ └── parent_multi.q:6 => q:17 176 │ │ └── filters 177 │ │ └── (p:14 IS DISTINCT FROM p_new:16) OR (q:15 IS DISTINCT FROM q:17) 178 │ └── filters 179 │ ├── child_multi.p:12 = p:14 180 │ └── child_multi.q:13 = q:15 181 └── projections 182 └── NULL::INT8 [as=p_new:18] 183 184 # Test a two-level cascade. 185 exec-ddl 186 CREATE TABLE grandchild ( 187 g INT PRIMARY KEY, 188 c INT, q INT, 189 CONSTRAINT fk2 FOREIGN KEY (c, q) REFERENCES child_multi(c, q) ON UPDATE SET NULL 190 ) 191 ---- 192 193 build-cascades 194 UPDATE parent_multi SET q = q * 10 WHERE p > 1 195 ---- 196 root 197 ├── update parent_multi 198 │ ├── columns: <none> 199 │ ├── fetch columns: pk:4 p:5 q:6 200 │ ├── update-mapping: 201 │ │ └── q_new:7 => q:3 202 │ ├── input binding: &1 203 │ ├── cascades 204 │ │ └── fk 205 │ └── project 206 │ ├── columns: q_new:7 pk:4!null p:5!null q:6 207 │ ├── select 208 │ │ ├── columns: pk:4!null p:5!null q:6 209 │ │ ├── scan parent_multi 210 │ │ │ └── columns: pk:4!null p:5 q:6 211 │ │ └── filters 212 │ │ └── p:5 > 1 213 │ └── projections 214 │ └── q:6 * 10 [as=q_new:7] 215 └── cascade 216 ├── update child_multi 217 │ ├── columns: <none> 218 │ ├── fetch columns: c:11 child_multi.p:12 child_multi.q:13 219 │ ├── update-mapping: 220 │ │ ├── p_new:18 => child_multi.p:9 221 │ │ └── p_new:18 => child_multi.q:10 222 │ ├── input binding: &2 223 │ ├── cascades 224 │ │ └── fk2 225 │ └── project 226 │ ├── columns: p_new:18 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 227 │ ├── inner-join (hash) 228 │ │ ├── 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 229 │ │ ├── scan child_multi 230 │ │ │ └── columns: c:11!null child_multi.p:12 child_multi.q:13 231 │ │ ├── select 232 │ │ │ ├── columns: p:14!null q:15 p:16!null q_new:17 233 │ │ │ ├── with-scan &1 234 │ │ │ │ ├── columns: p:14!null q:15 p:16!null q_new:17 235 │ │ │ │ └── mapping: 236 │ │ │ │ ├── parent_multi.p:5 => p:14 237 │ │ │ │ ├── parent_multi.q:6 => q:15 238 │ │ │ │ ├── parent_multi.p:5 => p:16 239 │ │ │ │ └── q_new:7 => q_new:17 240 │ │ │ └── filters 241 │ │ │ └── (p:14 IS DISTINCT FROM p:16) OR (q:15 IS DISTINCT FROM q_new:17) 242 │ │ └── filters 243 │ │ ├── child_multi.p:12 = p:14 244 │ │ └── child_multi.q:13 = q:15 245 │ └── projections 246 │ └── NULL::INT8 [as=p_new:18] 247 └── cascade 248 └── update grandchild 249 ├── columns: <none> 250 ├── fetch columns: g:22 grandchild.c:23 grandchild.q:24 251 ├── update-mapping: 252 │ ├── c_new:29 => grandchild.c:20 253 │ └── c_new:29 => grandchild.q:21 254 └── project 255 ├── columns: c_new:29 g:22!null grandchild.c:23!null grandchild.q:24!null c:25!null q:26!null c:27!null p_new:28 256 ├── inner-join (hash) 257 │ ├── columns: g:22!null grandchild.c:23!null grandchild.q:24!null c:25!null q:26!null c:27!null p_new:28 258 │ ├── scan grandchild 259 │ │ └── columns: g:22!null grandchild.c:23 grandchild.q:24 260 │ ├── select 261 │ │ ├── columns: c:25!null q:26!null c:27!null p_new:28 262 │ │ ├── with-scan &2 263 │ │ │ ├── columns: c:25!null q:26!null c:27!null p_new:28 264 │ │ │ └── mapping: 265 │ │ │ ├── child_multi.c:11 => c:25 266 │ │ │ ├── child_multi.q:13 => q:26 267 │ │ │ ├── child_multi.c:11 => c:27 268 │ │ │ └── p_new:18 => p_new:28 269 │ │ └── filters 270 │ │ └── (c:25 IS DISTINCT FROM c:27) OR (q:26 IS DISTINCT FROM p_new:28) 271 │ └── filters 272 │ ├── grandchild.c:23 = c:25 273 │ └── grandchild.q:24 = q:26 274 └── projections 275 └── NULL::INT8 [as=c_new:29]