From 675e964cf24c372385e900f9b24bf62ce0cd5636 Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Wed, 10 Feb 2021 16:40:01 -0800 Subject: [PATCH 1/2] optbuilder: return scope from mutationBuilder.buildCheckInputScan This commit updates `mutationBuilder.buildCheckInputScan` to build a scope containing the constructed WithScan expression and the scope columns output by the expression. Also, the WithScan output column names are now the names of the columns in the underlying table, rather than the names of the input columns. Access to a scope for the WithScan expression will be required to support partial `UNIQUE WITHOUT INDEX` constraints. For uniqueness checks, a filter on the WithScan columns must be added to the semi-join filters. The WithScan scope will be required in order to build the filter expression. Additionally, the names of the WithScan output columns must match the names of the columns in the underlying table in order to build partial predicate expressions that refer to the table's columns. Release note: None --- pkg/sql/opt/norm/testdata/rules/prune_cols | 160 +-- pkg/sql/opt/norm/testdata/rules/with | 8 +- pkg/sql/opt/optbuilder/mutation_builder.go | 41 +- pkg/sql/opt/optbuilder/mutation_builder_fk.go | 52 +- .../opt/optbuilder/mutation_builder_unique.go | 19 +- pkg/sql/opt/optbuilder/scope.go | 12 +- .../opt/optbuilder/testdata/fk-checks-insert | 230 ++-- .../opt/optbuilder/testdata/fk-checks-update | 132 +-- .../opt/optbuilder/testdata/fk-checks-upsert | 628 +++++----- .../testdata/fk-on-delete-set-default | 56 +- .../optbuilder/testdata/fk-on-update-cascade | 138 +-- .../testdata/fk-on-update-set-default | 136 +-- .../optbuilder/testdata/unique-checks-insert | 496 ++++---- .../optbuilder/testdata/unique-checks-update | 272 ++--- .../optbuilder/testdata/unique-checks-upsert | 1044 ++++++++--------- pkg/sql/opt/xform/testdata/coster/join | 18 +- pkg/sql/opt/xform/testdata/external/tpcc | 88 +- .../xform/testdata/external/tpcc-later-stats | 88 +- .../opt/xform/testdata/external/tpcc-no-stats | 88 +- pkg/sql/opt/xform/testdata/external/tpce | 312 ++--- .../opt/xform/testdata/external/tpce-no-stats | 318 ++--- pkg/sql/opt/xform/testdata/external/trading | 30 +- .../xform/testdata/external/trading-mutation | 30 +- pkg/sql/opt/xform/testdata/rules/scan | 6 +- 24 files changed, 2213 insertions(+), 2189 deletions(-) diff --git a/pkg/sql/opt/norm/testdata/rules/prune_cols b/pkg/sql/opt/norm/testdata/rules/prune_cols index 49d6f4990edd..aee982723767 100644 --- a/pkg/sql/opt/norm/testdata/rules/prune_cols +++ b/pkg/sql/opt/norm/testdata/rules/prune_cols @@ -3583,25 +3583,25 @@ UPDATE uniq SET w = 1, x = 2 WHERE k = 3 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:8 w:10 x:11 + ├── fetch columns: uniq.k:8 uniq.w:10 uniq.x:11 ├── update-mapping: - │ ├── w_new:15 => w:3 - │ └── x_new:16 => x:4 + │ ├── w_new:15 => uniq.w:3 + │ └── x_new:16 => uniq.x:4 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: w_new:15!null x_new:16!null uniq.k:8!null w:10 x:11 uniq.y:12 + │ ├── columns: w_new:15!null x_new:16!null uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8,10-12,15,16) │ ├── select - │ │ ├── columns: uniq.k:8!null w:10 x:11 uniq.y:12 + │ │ ├── columns: uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 │ │ ├── cardinality: [0 - 1] │ │ ├── key: () │ │ ├── fd: ()-->(8,10-12) │ │ ├── scan uniq - │ │ │ ├── columns: uniq.k:8!null w:10 x:11 uniq.y:12 + │ │ │ ├── columns: uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 │ │ │ ├── key: (8) │ │ │ └── fd: (8)-->(10-12) │ │ └── filters @@ -3612,46 +3612,46 @@ update uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w_new:17!null k:18!null + │ ├── columns: w:17!null k:18!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17,18) │ ├── with-scan &1 - │ │ ├── columns: w_new:17!null k:18!null + │ │ ├── columns: w:17!null k:18!null │ │ ├── mapping: - │ │ │ ├── w_new:15 => w_new:17 + │ │ │ ├── w_new:15 => w:17 │ │ │ └── uniq.k:8 => k:18 │ │ ├── cardinality: [0 - 1] │ │ ├── key: () │ │ └── fd: ()-->(17,18) │ ├── scan uniq - │ │ ├── columns: uniq.k:19!null w:21 + │ │ ├── columns: uniq.k:19!null uniq.w:21 │ │ ├── key: (19) │ │ └── fd: (19)-->(21) │ └── filters - │ ├── w_new:17 = w:21 [outer=(17,21), constraints=(/17: (/NULL - ]; /21: (/NULL - ]), fd=(17)==(21), (21)==(17)] + │ ├── w:17 = uniq.w:21 [outer=(17,21), constraints=(/17: (/NULL - ]; /21: (/NULL - ]), fd=(17)==(21), (21)==(17)] │ └── k:18 != uniq.k:19 [outer=(18,19), constraints=(/18: (/NULL - ]; /19: (/NULL - ])] └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x_new:26!null y:27 k:28!null + ├── columns: x:26!null y:27 k:28!null ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(26-28) ├── with-scan &1 - │ ├── columns: x_new:26!null y:27 k:28!null + │ ├── columns: x:26!null y:27 k:28!null │ ├── mapping: - │ │ ├── x_new:16 => x_new:26 + │ │ ├── x_new:16 => x:26 │ │ ├── uniq.y:12 => y:27 │ │ └── uniq.k:8 => k:28 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(26-28) ├── scan uniq - │ ├── columns: uniq.k:29!null x:32 uniq.y:33 + │ ├── columns: uniq.k:29!null uniq.x:32 uniq.y:33 │ ├── key: (29) │ └── fd: (29)-->(32,33) └── filters - ├── x_new:26 = x:32 [outer=(26,32), constraints=(/26: (/NULL - ]; /32: (/NULL - ]), fd=(26)==(32), (32)==(26)] + ├── x:26 = uniq.x:32 [outer=(26,32), constraints=(/26: (/NULL - ]; /32: (/NULL - ]), fd=(26)==(32), (32)==(26)] ├── y:27 = uniq.y:33 [outer=(27,33), constraints=(/27: (/NULL - ]; /33: (/NULL - ]), fd=(27)==(33), (33)==(27)] └── k:28 != uniq.k:29 [outer=(28,29), constraints=(/28: (/NULL - ]; /29: (/NULL - ])] @@ -3662,28 +3662,28 @@ INSERT INTO uniq_fk_parent VALUES (2, 1) ON CONFLICT (k) DO UPDATE SET c = 1 upsert uniq_fk_parent ├── columns: ├── arbiter indexes: primary - ├── canary column: k:10 - ├── fetch columns: k:10 b:12 c:13 + ├── canary column: uniq_fk_parent.k:10 + ├── fetch columns: uniq_fk_parent.k:10 uniq_fk_parent.b:12 uniq_fk_parent.c:13 ├── insert-mapping: - │ ├── column1:7 => k:1 - │ ├── column2:8 => a:2 - │ ├── column9:9 => b:3 - │ ├── column9:9 => c:4 + │ ├── column1:7 => uniq_fk_parent.k:1 + │ ├── column2:8 => uniq_fk_parent.a:2 + │ ├── column9:9 => uniq_fk_parent.b:3 + │ ├── column9:9 => uniq_fk_parent.c:4 │ └── column9:9 => d:5 ├── update-mapping: - │ └── upsert_c:20 => c:4 + │ └── upsert_c:20 => uniq_fk_parent.c:4 ├── input binding: &1 ├── cascades │ └── fk_b_ref_uniq_fk_parent ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: upsert_k:17 upsert_a:18 upsert_b:19 upsert_c:20 column1:7!null column2:8!null column9:9 k:10 b:12 c:13 + │ ├── columns: upsert_k:17 upsert_a:18 upsert_b:19 upsert_c:20 column1:7!null column2:8!null column9:9 uniq_fk_parent.k:10 uniq_fk_parent.b:12 uniq_fk_parent.c:13 │ ├── cardinality: [1 - 1] │ ├── key: () │ ├── fd: ()-->(7-10,12,13,17-20) │ ├── left-join (cross) - │ │ ├── columns: column1:7!null column2:8!null column9:9 k:10 a:11 b:12 c:13 + │ │ ├── columns: column1:7!null column2:8!null column9:9 uniq_fk_parent.k:10 uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 │ │ ├── cardinality: [1 - 1] │ │ ├── multiplicity: left-rows(exactly-one), right-rows(exactly-one) │ │ ├── key: () @@ -3695,67 +3695,67 @@ upsert uniq_fk_parent │ │ │ ├── fd: ()-->(7-9) │ │ │ └── (2, 1, NULL) │ │ ├── select - │ │ │ ├── columns: k:10!null a:11 b:12 c:13 + │ │ │ ├── columns: uniq_fk_parent.k:10!null uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 │ │ │ ├── cardinality: [0 - 1] │ │ │ ├── key: () │ │ │ ├── fd: ()-->(10-13) │ │ │ ├── scan uniq_fk_parent - │ │ │ │ ├── columns: k:10!null a:11 b:12 c:13 + │ │ │ │ ├── columns: uniq_fk_parent.k:10!null uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 │ │ │ │ ├── key: (10) │ │ │ │ └── fd: (10)-->(11-13) │ │ │ └── filters - │ │ │ └── k:10 = 2 [outer=(10), constraints=(/10: [/2 - /2]; tight), fd=()-->(10)] + │ │ │ └── uniq_fk_parent.k:10 = 2 [outer=(10), constraints=(/10: [/2 - /2]; tight), fd=()-->(10)] │ │ └── filters (true) │ └── projections - │ ├── CASE WHEN k:10 IS NULL THEN column1:7 ELSE k:10 END [as=upsert_k:17, outer=(7,10)] - │ ├── CASE WHEN k:10 IS NULL THEN column2:8 ELSE a:11 END [as=upsert_a:18, outer=(8,10,11)] - │ ├── CASE WHEN k:10 IS NULL THEN column9:9 ELSE b:12 END [as=upsert_b:19, outer=(9,10,12)] - │ └── CASE WHEN k:10 IS NULL THEN column9:9 ELSE 1 END [as=upsert_c:20, outer=(9,10)] + │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column1:7 ELSE uniq_fk_parent.k:10 END [as=upsert_k:17, outer=(7,10)] + │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column2:8 ELSE uniq_fk_parent.a:11 END [as=upsert_a:18, outer=(8,10,11)] + │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column9:9 ELSE uniq_fk_parent.b:12 END [as=upsert_b:19, outer=(9,10,12)] + │ └── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column9:9 ELSE 1 END [as=upsert_c:20, outer=(9,10)] └── unique-checks ├── unique-checks-item: uniq_fk_parent(a) │ └── semi-join (hash) - │ ├── columns: upsert_a:22 upsert_k:23 + │ ├── columns: a:22 k:23 │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(22,23) │ ├── with-scan &1 - │ │ ├── columns: upsert_a:22 upsert_k:23 + │ │ ├── columns: a:22 k:23 │ │ ├── mapping: - │ │ │ ├── upsert_a:18 => upsert_a:22 - │ │ │ └── upsert_k:17 => upsert_k:23 + │ │ │ ├── upsert_a:18 => a:22 + │ │ │ └── upsert_k:17 => k:23 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(22,23) │ ├── scan uniq_fk_parent - │ │ ├── columns: k:24!null a:25 + │ │ ├── columns: uniq_fk_parent.k:24!null uniq_fk_parent.a:25 │ │ ├── key: (24) │ │ └── fd: (24)-->(25) │ └── filters - │ ├── upsert_a:22 = a:25 [outer=(22,25), constraints=(/22: (/NULL - ]; /25: (/NULL - ]), fd=(22)==(25), (25)==(22)] - │ └── upsert_k:23 != k:24 [outer=(23,24), constraints=(/23: (/NULL - ]; /24: (/NULL - ])] + │ ├── a:22 = uniq_fk_parent.a:25 [outer=(22,25), constraints=(/22: (/NULL - ]; /25: (/NULL - ]), fd=(22)==(25), (25)==(22)] + │ └── k:23 != uniq_fk_parent.k:24 [outer=(23,24), constraints=(/23: (/NULL - ]; /24: (/NULL - ])] └── unique-checks-item: uniq_fk_parent(b,c) └── semi-join (hash) - ├── columns: upsert_b:30 upsert_c:31 upsert_k:32 + ├── columns: b:30 c:31 k:32 ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(30-32) ├── with-scan &1 - │ ├── columns: upsert_b:30 upsert_c:31 upsert_k:32 + │ ├── columns: b:30 c:31 k:32 │ ├── mapping: - │ │ ├── upsert_b:19 => upsert_b:30 - │ │ ├── upsert_c:20 => upsert_c:31 - │ │ └── upsert_k:17 => upsert_k:32 + │ │ ├── upsert_b:19 => b:30 + │ │ ├── upsert_c:20 => c:31 + │ │ └── upsert_k:17 => k:32 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(30-32) ├── scan uniq_fk_parent - │ ├── columns: k:33!null b:35 c:36 + │ ├── columns: uniq_fk_parent.k:33!null uniq_fk_parent.b:35 uniq_fk_parent.c:36 │ ├── key: (33) │ └── fd: (33)-->(35,36) └── filters - ├── upsert_b:30 = b:35 [outer=(30,35), constraints=(/30: (/NULL - ]; /35: (/NULL - ]), fd=(30)==(35), (35)==(30)] - ├── upsert_c:31 = c:36 [outer=(31,36), constraints=(/31: (/NULL - ]; /36: (/NULL - ]), fd=(31)==(36), (36)==(31)] - └── upsert_k:32 != k:33 [outer=(32,33), constraints=(/32: (/NULL - ]; /33: (/NULL - ])] + ├── b:30 = uniq_fk_parent.b:35 [outer=(30,35), constraints=(/30: (/NULL - ]; /35: (/NULL - ]), fd=(30)==(35), (35)==(30)] + ├── c:31 = uniq_fk_parent.c:36 [outer=(31,36), constraints=(/31: (/NULL - ]; /36: (/NULL - ]), fd=(31)==(36), (36)==(31)] + └── k:32 != uniq_fk_parent.k:33 [outer=(32,33), constraints=(/32: (/NULL - ]; /33: (/NULL - ])] # Prune inbound foreign key columns when they are not updated. norm expect=PruneMutationInputCols @@ -3764,13 +3764,13 @@ INSERT INTO uniq_fk_parent VALUES (1) ON CONFLICT (k) DO UPDATE SET d = 1 upsert uniq_fk_parent ├── columns: ├── arbiter indexes: primary - ├── canary column: k:9 - ├── fetch columns: k:9 d:13 + ├── canary column: uniq_fk_parent.k:9 + ├── fetch columns: uniq_fk_parent.k:9 d:13 ├── insert-mapping: - │ ├── column1:7 => k:1 - │ ├── column8:8 => a:2 - │ ├── column8:8 => b:3 - │ ├── column8:8 => c:4 + │ ├── column1:7 => uniq_fk_parent.k:1 + │ ├── column8:8 => uniq_fk_parent.a:2 + │ ├── column8:8 => uniq_fk_parent.b:3 + │ ├── column8:8 => uniq_fk_parent.c:4 │ └── column8:8 => d:5 ├── update-mapping: │ └── upsert_d:20 => d:5 @@ -3778,12 +3778,12 @@ upsert uniq_fk_parent ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: upsert_k:16 upsert_a:17 upsert_b:18 upsert_c:19 upsert_d:20 column1:7!null column8:8 k:9 d:13 + │ ├── columns: upsert_k:16 upsert_a:17 upsert_b:18 upsert_c:19 upsert_d:20 column1:7!null column8:8 uniq_fk_parent.k:9 d:13 │ ├── cardinality: [1 - 1] │ ├── key: () │ ├── fd: ()-->(7-9,13,16-20) │ ├── left-join (cross) - │ │ ├── columns: column1:7!null column8:8 k:9 a:10 b:11 c:12 d:13 + │ │ ├── columns: column1:7!null column8:8 uniq_fk_parent.k:9 uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 d:13 │ │ ├── cardinality: [1 - 1] │ │ ├── multiplicity: left-rows(exactly-one), right-rows(exactly-one) │ │ ├── key: () @@ -3795,68 +3795,68 @@ upsert uniq_fk_parent │ │ │ ├── fd: ()-->(7,8) │ │ │ └── (1, NULL) │ │ ├── select - │ │ │ ├── columns: k:9!null a:10 b:11 c:12 d:13 + │ │ │ ├── columns: uniq_fk_parent.k:9!null uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 d:13 │ │ │ ├── cardinality: [0 - 1] │ │ │ ├── key: () │ │ │ ├── fd: ()-->(9-13) │ │ │ ├── scan uniq_fk_parent - │ │ │ │ ├── columns: k:9!null a:10 b:11 c:12 d:13 + │ │ │ │ ├── columns: uniq_fk_parent.k:9!null uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 d:13 │ │ │ │ ├── key: (9) │ │ │ │ └── fd: (9)-->(10-13) │ │ │ └── filters - │ │ │ └── k:9 = 1 [outer=(9), constraints=(/9: [/1 - /1]; tight), fd=()-->(9)] + │ │ │ └── uniq_fk_parent.k:9 = 1 [outer=(9), constraints=(/9: [/1 - /1]; tight), fd=()-->(9)] │ │ └── filters (true) │ └── projections - │ ├── CASE WHEN k:9 IS NULL THEN column1:7 ELSE k:9 END [as=upsert_k:16, outer=(7,9)] - │ ├── CASE WHEN k:9 IS NULL THEN column8:8 ELSE a:10 END [as=upsert_a:17, outer=(8-10)] - │ ├── CASE WHEN k:9 IS NULL THEN column8:8 ELSE b:11 END [as=upsert_b:18, outer=(8,9,11)] - │ ├── CASE WHEN k:9 IS NULL THEN column8:8 ELSE c:12 END [as=upsert_c:19, outer=(8,9,12)] - │ └── CASE WHEN k:9 IS NULL THEN column8:8 ELSE 1 END [as=upsert_d:20, outer=(8,9)] + │ ├── CASE WHEN uniq_fk_parent.k:9 IS NULL THEN column1:7 ELSE uniq_fk_parent.k:9 END [as=upsert_k:16, outer=(7,9)] + │ ├── CASE WHEN uniq_fk_parent.k:9 IS NULL THEN column8:8 ELSE uniq_fk_parent.a:10 END [as=upsert_a:17, outer=(8-10)] + │ ├── CASE WHEN uniq_fk_parent.k:9 IS NULL THEN column8:8 ELSE uniq_fk_parent.b:11 END [as=upsert_b:18, outer=(8,9,11)] + │ ├── CASE WHEN uniq_fk_parent.k:9 IS NULL THEN column8:8 ELSE uniq_fk_parent.c:12 END [as=upsert_c:19, outer=(8,9,12)] + │ └── CASE WHEN uniq_fk_parent.k:9 IS NULL THEN column8:8 ELSE 1 END [as=upsert_d:20, outer=(8,9)] └── unique-checks ├── unique-checks-item: uniq_fk_parent(a) │ └── semi-join (hash) - │ ├── columns: upsert_a:21 upsert_k:22 + │ ├── columns: a:21 k:22 │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(21,22) │ ├── with-scan &1 - │ │ ├── columns: upsert_a:21 upsert_k:22 + │ │ ├── columns: a:21 k:22 │ │ ├── mapping: - │ │ │ ├── upsert_a:17 => upsert_a:21 - │ │ │ └── upsert_k:16 => upsert_k:22 + │ │ │ ├── upsert_a:17 => a:21 + │ │ │ └── upsert_k:16 => k:22 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(21,22) │ ├── scan uniq_fk_parent - │ │ ├── columns: k:23!null a:24 + │ │ ├── columns: uniq_fk_parent.k:23!null uniq_fk_parent.a:24 │ │ ├── key: (23) │ │ └── fd: (23)-->(24) │ └── filters - │ ├── upsert_a:21 = a:24 [outer=(21,24), constraints=(/21: (/NULL - ]; /24: (/NULL - ]), fd=(21)==(24), (24)==(21)] - │ └── upsert_k:22 != k:23 [outer=(22,23), constraints=(/22: (/NULL - ]; /23: (/NULL - ])] + │ ├── a:21 = uniq_fk_parent.a:24 [outer=(21,24), constraints=(/21: (/NULL - ]; /24: (/NULL - ]), fd=(21)==(24), (24)==(21)] + │ └── k:22 != uniq_fk_parent.k:23 [outer=(22,23), constraints=(/22: (/NULL - ]; /23: (/NULL - ])] └── unique-checks-item: uniq_fk_parent(b,c) └── semi-join (hash) - ├── columns: upsert_b:29 upsert_c:30 upsert_k:31 + ├── columns: b:29 c:30 k:31 ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(29-31) ├── with-scan &1 - │ ├── columns: upsert_b:29 upsert_c:30 upsert_k:31 + │ ├── columns: b:29 c:30 k:31 │ ├── mapping: - │ │ ├── upsert_b:18 => upsert_b:29 - │ │ ├── upsert_c:19 => upsert_c:30 - │ │ └── upsert_k:16 => upsert_k:31 + │ │ ├── upsert_b:18 => b:29 + │ │ ├── upsert_c:19 => c:30 + │ │ └── upsert_k:16 => k:31 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(29-31) ├── scan uniq_fk_parent - │ ├── columns: k:32!null b:34 c:35 + │ ├── columns: uniq_fk_parent.k:32!null uniq_fk_parent.b:34 uniq_fk_parent.c:35 │ ├── key: (32) │ └── fd: (32)-->(34,35) └── filters - ├── upsert_b:29 = b:34 [outer=(29,34), constraints=(/29: (/NULL - ]; /34: (/NULL - ]), fd=(29)==(34), (34)==(29)] - ├── upsert_c:30 = c:35 [outer=(30,35), constraints=(/30: (/NULL - ]; /35: (/NULL - ]), fd=(30)==(35), (35)==(30)] - └── upsert_k:31 != k:32 [outer=(31,32), constraints=(/31: (/NULL - ]; /32: (/NULL - ])] + ├── b:29 = uniq_fk_parent.b:34 [outer=(29,34), constraints=(/29: (/NULL - ]; /34: (/NULL - ]), fd=(29)==(34), (34)==(29)] + ├── c:30 = uniq_fk_parent.c:35 [outer=(30,35), constraints=(/30: (/NULL - ]; /35: (/NULL - ]), fd=(30)==(35), (35)==(30)] + └── k:31 != uniq_fk_parent.k:32 [outer=(31,32), constraints=(/31: (/NULL - ]; /32: (/NULL - ])] # Do not prune columns that are needed for foreign key checks or cascades. norm expect=PruneMutationInputCols diff --git a/pkg/sql/opt/norm/testdata/rules/with b/pkg/sql/opt/norm/testdata/rules/with index f1949c03d14e..d0b849063f2e 100644 --- a/pkg/sql/opt/norm/testdata/rules/with +++ b/pkg/sql/opt/norm/testdata/rules/with @@ -579,7 +579,7 @@ with &2 (cte) │ └── f-k-checks │ └── f-k-checks-item: child(p) -> parent(p) │ └── anti-join (hash) - │ ├── columns: column2:6(int!null) + │ ├── columns: p:6(int!null) │ ├── cardinality: [0 - 1] │ ├── stats: [rows=1e-10] │ ├── cost: 1036.5775 @@ -588,9 +588,9 @@ with &2 (cte) │ ├── cte-uses │ │ └── &1: count=1 used-columns=(5) │ ├── with-scan &1 - │ │ ├── columns: column2:6(int!null) + │ │ ├── columns: p:6(int!null) │ │ ├── mapping: - │ │ │ └── column2:5(int) => column2:6(int) + │ │ │ └── column2:5(int) => p:6(int) │ │ ├── cardinality: [1 - 1] │ │ ├── stats: [rows=1, distinct(6)=1, null(6)=0] │ │ ├── cost: 0.01 @@ -609,7 +609,7 @@ with &2 (cte) │ │ └── unfiltered-cols: (7,8) │ └── filters │ └── eq [type=bool, outer=(6,7), constraints=(/6: (/NULL - ]; /7: (/NULL - ]), fd=(6)==(7), (7)==(6)] - │ ├── variable: column2:6 [type=int] + │ ├── variable: p:6 [type=int] │ └── variable: t.public.parent.p:7 [type=int] └── union ├── columns: c:12(int!null) diff --git a/pkg/sql/opt/optbuilder/mutation_builder.go b/pkg/sql/opt/optbuilder/mutation_builder.go index 6b92d126fcdd..ad4c6320ae17 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder.go +++ b/pkg/sql/opt/optbuilder/mutation_builder.go @@ -1281,25 +1281,28 @@ const ( checkInputScanFetchedVals ) -// makeCheckInputScan constructs a WithScan that iterates over the input to the +// buildCheckInputScan constructs a WithScan that iterates over the input to the // mutation operator. Used in expressions that generate rows for checking for FK // and uniqueness violations. // // The WithScan expression will scan either the new values or the fetched values // for the given table ordinals (which correspond to FK or unique columns). // -// Returns the output columns from the WithScan, which map 1-to-1 to -// tabOrdinals. Also returns the subset of these columns that can be assumed -// to be not null (either because they are not null in the mutation input or -// because they are non-nullable table columns). +// Returns a scope containing the WithScan expression and the output columns +// from the WithScan. The output columns map 1-to-1 to tabOrdinals. Also returns +// the subset of these columns that can be assumed to be not null (either +// because they are not null in the mutation input or because they are +// non-nullable table columns). // -func (mb *mutationBuilder) makeCheckInputScan( +func (mb *mutationBuilder) buildCheckInputScan( typ checkInputScanType, tabOrdinals []int, -) (scan memo.RelExpr, outCols opt.ColList, notNullOutCols opt.ColSet) { +) (withScanScope *scope, notNullOutCols opt.ColSet) { // inputCols are the column IDs from the mutation input that we are scanning. inputCols := make(opt.ColList, len(tabOrdinals)) - // outCols will store the newly synthesized output columns for WithScan. - outCols = make(opt.ColList, len(inputCols)) + + withScanScope = mb.b.allocScope() + withScanScope.cols = make([]scopeColumn, len(inputCols)) + for i, tabOrd := range tabOrdinals { if typ == checkInputScanNewVals { inputCols[i] = mb.mapToReturnColID(tabOrd) @@ -1310,24 +1313,30 @@ func (mb *mutationBuilder) makeCheckInputScan( panic(errors.AssertionFailedf("no value for check input column (tabOrd=%d)", tabOrd)) } - // Synthesize new column. - c := mb.b.factory.Metadata().ColumnMeta(inputCols[i]) - outCols[i] = mb.md.AddColumn(c.Alias, c.Type) + // Synthesize a new output column for the input column, using the name + // of the column in the underlying table. + tableCol := mb.b.factory.Metadata().Table(mb.tabID).Column(tabOrd) + outCol := mb.md.AddColumn(string(tableCol.ColName()), tableCol.DatumType()) + withScanScope.cols[i] = scopeColumn{ + id: outCol, + name: tableCol.ColName(), + typ: tableCol.DatumType(), + } // If a table column is not nullable, NULLs cannot be inserted (the // mutation will fail). So for the purposes of checks, we can treat // these columns as not null. if mb.outScope.expr.Relational().NotNullCols.Contains(inputCols[i]) || !mb.tab.Column(tabOrd).IsNullable() { - notNullOutCols.Add(outCols[i]) + notNullOutCols.Add(outCol) } } - scan = mb.b.factory.ConstructWithScan(&memo.WithScanPrivate{ + withScanScope.expr = mb.b.factory.ConstructWithScan(&memo.WithScanPrivate{ With: mb.withID, InCols: inputCols, - OutCols: outCols, + OutCols: withScanScope.colList(), ID: mb.b.factory.Metadata().NextUniqueID(), }) - return scan, outCols, notNullOutCols + return withScanScope, notNullOutCols } diff --git a/pkg/sql/opt/optbuilder/mutation_builder_fk.go b/pkg/sql/opt/optbuilder/mutation_builder_fk.go index 97600abe26db..aef77ed582c3 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder_fk.go +++ b/pkg/sql/opt/optbuilder/mutation_builder_fk.go @@ -171,8 +171,8 @@ func (mb *mutationBuilder) buildFKChecksAndCascadesForDelete() { } mb.ensureWithID() - fkInput, withScanCols, _ := mb.makeCheckInputScan(checkInputScanFetchedVals, h.tabOrdinals) - mb.fkChecks = append(mb.fkChecks, h.buildDeletionCheck(fkInput, withScanCols)) + withScanScope, _ := mb.buildCheckInputScan(checkInputScanFetchedVals, h.tabOrdinals) + mb.fkChecks = append(mb.fkChecks, h.buildDeletionCheck(withScanScope.expr, withScanScope.colList())) } telemetry.Inc(sqltelemetry.ForeignKeyChecksUseCounter) } @@ -336,15 +336,17 @@ func (mb *mutationBuilder) buildFKChecksForUpdate() { // performance either: we would be incurring extra cost (more complicated // expressions, scanning the input buffer twice) for a rare case. - oldRows, colsForOldRow, _ := mb.makeCheckInputScan(checkInputScanFetchedVals, h.tabOrdinals) - newRows, colsForNewRow, _ := mb.makeCheckInputScan(checkInputScanNewVals, h.tabOrdinals) + oldRowsScope, _ := mb.buildCheckInputScan(checkInputScanFetchedVals, h.tabOrdinals) + newRowsScope, _ := mb.buildCheckInputScan(checkInputScanNewVals, h.tabOrdinals) + colsForOldRow := oldRowsScope.colList() + colsForNewRow := newRowsScope.colList() // The rows that no longer exist are the ones that were "deleted" by virtue // of being updated _from_, minus the ones that were "added" by virtue of // being updated _to_. deletedRows := mb.b.factory.ConstructExcept( - oldRows, - newRows, + oldRowsScope.expr, + newRowsScope.expr, &memo.SetPrivate{ LeftCols: colsForOldRow, RightCols: colsForNewRow, @@ -439,22 +441,24 @@ func (mb *mutationBuilder) buildFKChecksForUpsert() { // insertions (using a "canaryCol IS NOT NULL" condition). But the rows we // would filter out have all-null fetched values anyway and will never match // in the semi join. - oldRows, colsForOldRow, _ := mb.makeCheckInputScan(checkInputScanFetchedVals, h.tabOrdinals) - newRows, colsForNewRow, _ := mb.makeCheckInputScan(checkInputScanNewVals, h.tabOrdinals) + oldRowsScope, _ := mb.buildCheckInputScan(checkInputScanFetchedVals, h.tabOrdinals) + newRowsScope, _ := mb.buildCheckInputScan(checkInputScanNewVals, h.tabOrdinals) + colsForOldRow := oldRowsScope.colList() + colsForNewRow := newRowsScope.colList() // The rows that no longer exist are the ones that were "deleted" by virtue // of being updated _from_, minus the ones that were "added" by virtue of // being updated _to_. deletedRows := mb.b.factory.ConstructExcept( - oldRows, - newRows, + oldRowsScope.expr, + newRowsScope.expr, &memo.SetPrivate{ LeftCols: colsForOldRow, RightCols: colsForNewRow, OutCols: colsForOldRow, }, ) - mb.fkChecks = append(mb.fkChecks, h.buildDeletionCheck(deletedRows, colsForOldRow)) + mb.fkChecks = append(mb.fkChecks, h.buildDeletionCheck(deletedRows, oldRowsScope.colList())) } telemetry.Inc(sqltelemetry.ForeignKeyChecksUseCounter) } @@ -638,11 +642,11 @@ func (h *fkCheckHelper) allocOrdinals(numCols int) { // The input to the insertion check will be produced from the input to the // mutation operator. func (h *fkCheckHelper) buildInsertionCheck() memo.FKChecksItem { - fkInput, withScanCols, notNullWithScanCols := h.mb.makeCheckInputScan( + withScanScope, notNullWithScanCols := h.mb.buildCheckInputScan( checkInputScanNewVals, h.tabOrdinals, ) - numCols := len(withScanCols) + numCols := len(withScanScope.cols) f := h.mb.b.factory if notNullWithScanCols.Len() < numCols { // The columns we are inserting might have NULLs. These require special @@ -667,17 +671,17 @@ func (h *fkCheckHelper) buildInsertionCheck() memo.FKChecksItem { // Filter out any rows which have a NULL; build filters of the form // (a IS NOT NULL) AND (b IS NOT NULL) ... filters := make(memo.FiltersExpr, 0, numCols-notNullWithScanCols.Len()) - for _, col := range withScanCols { - if !notNullWithScanCols.Contains(col) { + for _, col := range withScanScope.cols { + if !notNullWithScanCols.Contains(col.id) { filters = append(filters, f.ConstructFiltersItem( f.ConstructIsNot( - f.ConstructVariable(col), + f.ConstructVariable(col.id), memo.NullSingleton, ), )) } } - fkInput = f.ConstructSelect(fkInput, filters) + withScanScope.expr = f.ConstructSelect(withScanScope.expr, filters) case tree.MatchFull: // Filter out any rows which have NULLs on all referencing columns. @@ -690,9 +694,9 @@ func (h *fkCheckHelper) buildInsertionCheck() memo.FKChecksItem { // Build a filter of the form // (a IS NOT NULL) OR (b IS NOT NULL) ... var condition opt.ScalarExpr - for _, col := range withScanCols { + for _, col := range withScanScope.cols { is := f.ConstructIsNot( - f.ConstructVariable(col), + f.ConstructVariable(col.id), memo.NullSingleton, ) if condition == nil { @@ -701,8 +705,8 @@ func (h *fkCheckHelper) buildInsertionCheck() memo.FKChecksItem { condition = f.ConstructOr(condition, is) } } - fkInput = f.ConstructSelect( - fkInput, + withScanScope.expr = f.ConstructSelect( + withScanScope.expr, memo.FiltersExpr{f.ConstructFiltersItem(condition)}, ) @@ -722,7 +726,7 @@ func (h *fkCheckHelper) buildInsertionCheck() memo.FKChecksItem { for j := 0; j < numCols; j++ { antiJoinFilters[j] = f.ConstructFiltersItem( f.ConstructEq( - f.ConstructVariable(withScanCols[j]), + f.ConstructVariable(withScanScope.cols[j].id), f.ConstructVariable(scanScope.cols[j].id), ), ) @@ -731,14 +735,14 @@ func (h *fkCheckHelper) buildInsertionCheck() memo.FKChecksItem { if h.mb.b.evalCtx.SessionData.PreferLookupJoinsForFKs { p.Flags = memo.PreferLookupJoinIntoRight } - antiJoin := f.ConstructAntiJoin(fkInput, scanScope.expr, antiJoinFilters, &p) + antiJoin := f.ConstructAntiJoin(withScanScope.expr, scanScope.expr, antiJoinFilters, &p) return f.ConstructFKChecksItem(antiJoin, &memo.FKChecksItemPrivate{ OriginTable: h.mb.tabID, ReferencedTable: refTabMeta.MetaID, FKOutbound: true, FKOrdinal: h.fkOrdinal, - KeyCols: withScanCols, + KeyCols: withScanScope.colList(), OpName: h.mb.opName, }) } diff --git a/pkg/sql/opt/optbuilder/mutation_builder_unique.go b/pkg/sql/opt/optbuilder/mutation_builder_unique.go index c3256216ae97..cc30ee2bdc42 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder_unique.go +++ b/pkg/sql/opt/optbuilder/mutation_builder_unique.go @@ -189,11 +189,11 @@ func (h *uniqueCheckHelper) init(mb *mutationBuilder, uniqueOrdinal int) bool { // table. The input to the insertion check will be produced from the input to // the mutation operator. func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { - checkInput, withScanCols, _ := h.mb.makeCheckInputScan( + withScanScope, _ := h.mb.buildCheckInputScan( checkInputScanNewVals, h.uniqueAndPrimaryKeyOrdinals, ) - numCols := len(withScanCols) + numCols := len(withScanScope.cols) f := h.mb.b.factory // Build a self semi-join, with the new values on the left and the @@ -211,7 +211,7 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { for i := 0; i < len(h.uniqueOrdinals); i++ { semiJoinFilters = append(semiJoinFilters, f.ConstructFiltersItem( f.ConstructEq( - f.ConstructVariable(withScanCols[i]), + f.ConstructVariable(withScanScope.cols[i].id), f.ConstructVariable(scanScope.cols[i].id), ), )) @@ -224,7 +224,7 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { var pkFilter opt.ScalarExpr for i := len(h.uniqueOrdinals); i < numCols; i++ { pkFilterLocal := f.ConstructNe( - f.ConstructVariable(withScanCols[i]), + f.ConstructVariable(withScanScope.cols[i].id), f.ConstructVariable(scanScope.cols[i].id), ) if pkFilter == nil { @@ -235,15 +235,16 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { } semiJoinFilters = append(semiJoinFilters, f.ConstructFiltersItem(pkFilter)) - semiJoin := f.ConstructSemiJoin(checkInput, scanScope.expr, semiJoinFilters, memo.EmptyJoinPrivate) + semiJoin := f.ConstructSemiJoin(withScanScope.expr, scanScope.expr, semiJoinFilters, memo.EmptyJoinPrivate) return f.ConstructUniqueChecksItem(semiJoin, &memo.UniqueChecksItemPrivate{ Table: h.mb.tabID, CheckOrdinal: h.uniqueOrdinal, - // uniqueOrdinals is always a prefix of uniqueAndPrimaryKeyOrdinals, which - // maps 1-to-1 to the columns in withScanCols. The remaining columns are - // primary key columns and should not be included in the KeyCols. - KeyCols: withScanCols[:len(h.uniqueOrdinals)], + // uniqueOrdinals is always a prefix of uniqueAndPrimaryKeyOrdinals, + // which maps 1-to-1 to the columns in withScanScope.cols. The remaining + // columns are primary key columns and should not be included in the + // KeyCols. + KeyCols: withScanScope.colList()[:len(h.uniqueOrdinals)], OpName: h.mb.opName, }) } diff --git a/pkg/sql/opt/optbuilder/scope.go b/pkg/sql/opt/optbuilder/scope.go index 0fc94d0266d4..542ef1f79cdf 100644 --- a/pkg/sql/opt/optbuilder/scope.go +++ b/pkg/sql/opt/optbuilder/scope.go @@ -507,7 +507,7 @@ func (s *scope) isOuterColumn(id opt.ColumnID) bool { } // colSet returns a ColSet of all the columns in this scope, -// excluding orderByCols. +// excluding extraCols. func (s *scope) colSet() opt.ColSet { var colSet opt.ColSet for i := range s.cols { @@ -526,6 +526,16 @@ func (s *scope) colSetWithExtraCols() opt.ColSet { return colSet } +// colList returns a ColList of all the columns in this scope, +// excluding extraCols. +func (s *scope) colList() opt.ColList { + colList := make(opt.ColList, len(s.cols)) + for i := range s.cols { + colList[i] = s.cols[i].id + } + return colList +} + // hasSameColumns returns true if this scope has the same columns // as the other scope. // diff --git a/pkg/sql/opt/optbuilder/testdata/fk-checks-insert b/pkg/sql/opt/optbuilder/testdata/fk-checks-insert index 33f2ff951dd7..b2d2488b7337 100644 --- a/pkg/sql/opt/optbuilder/testdata/fk-checks-insert +++ b/pkg/sql/opt/optbuilder/testdata/fk-checks-insert @@ -22,15 +22,15 @@ insert child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: p:6!null ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ └── mapping: - │ └── column2:5 => column2:6 + │ └── column2:5 => p:6 ├── scan parent │ └── columns: parent.p:7!null └── filters - └── column2:6 = parent.p:7 + └── p:6 = parent.p:7 build INSERT INTO child VALUES (100, 1), (200, 1) ON CONFLICT DO NOTHING @@ -61,15 +61,15 @@ insert child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: column2:9!null + ├── columns: p:9!null ├── with-scan &1 - │ ├── columns: column2:9!null + │ ├── columns: p:9!null │ └── mapping: - │ └── column2:5 => column2:9 + │ └── column2:5 => p:9 ├── scan parent │ └── columns: parent.p:10!null └── filters - └── column2:9 = parent.p:10 + └── p:9 = parent.p:10 # Use a non-constant input. exec-ddl @@ -83,24 +83,24 @@ insert child ├── columns: ├── insert-mapping: │ ├── x:4 => c:1 - │ └── xy.y:5 => child.p:2 + │ └── y:5 => child.p:2 ├── input binding: &1 ├── project - │ ├── columns: x:4 xy.y:5 + │ ├── columns: x:4 y:5 │ └── scan xy - │ └── columns: x:4 xy.y:5 rowid:6!null xy.crdb_internal_mvcc_timestamp:7 + │ └── columns: x:4 y:5 rowid:6!null xy.crdb_internal_mvcc_timestamp:7 └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: y:8 + ├── columns: p:8 ├── with-scan &1 - │ ├── columns: y:8 + │ ├── columns: p:8 │ └── mapping: - │ └── xy.y:5 => y:8 + │ └── y:5 => p:8 ├── scan parent │ └── columns: parent.p:9!null └── filters - └── y:8 = parent.p:9 + └── p:8 = parent.p:9 exec-ddl CREATE TABLE child_nullable (c INT PRIMARY KEY, p INT REFERENCES parent(p)); @@ -124,19 +124,19 @@ insert child_nullable └── f-k-checks └── f-k-checks-item: child_nullable(p) -> parent(p) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: p:6!null ├── select - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ ├── with-scan &1 - │ │ ├── columns: column2:6 + │ │ ├── columns: p:6 │ │ └── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => p:6 │ └── filters - │ └── column2:6 IS NOT NULL + │ └── p:6 IS NOT NULL ├── scan parent │ └── columns: parent.p:7!null └── filters - └── column2:6 = parent.p:7 + └── p:6 = parent.p:7 # The column is nullable but we know that the input is not null, so we don't # need to plan the filter. @@ -156,15 +156,15 @@ insert child_nullable └── f-k-checks └── f-k-checks-item: child_nullable(p) -> parent(p) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: p:6!null ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ └── mapping: - │ └── column2:5 => column2:6 + │ └── column2:5 => p:6 ├── scan parent │ └── columns: parent.p:7!null └── filters - └── column2:6 = parent.p:7 + └── p:6 = parent.p:7 # In this case, we know that we are inserting *only* NULL values, so we don't # need to check any FKs. @@ -221,19 +221,19 @@ insert child_nullable_full └── f-k-checks └── f-k-checks-item: child_nullable_full(p) -> parent(p) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: p:6!null ├── select - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ ├── with-scan &1 - │ │ ├── columns: column2:6 + │ │ ├── columns: p:6 │ │ └── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => p:6 │ └── filters - │ └── column2:6 IS NOT NULL + │ └── p:6 IS NOT NULL ├── scan parent │ └── columns: parent.p:7!null └── filters - └── column2:6 = parent.p:7 + └── p:6 = parent.p:7 # No FK check needed. build @@ -285,25 +285,25 @@ insert multi_col_child └── f-k-checks └── f-k-checks-item: multi_col_child(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10!null column3:11!null column4:12!null + ├── columns: p:10!null q:11!null r:12!null ├── select - │ ├── columns: column2:10!null column3:11!null column4:12!null + │ ├── columns: p:10!null q:11!null r:12!null │ ├── with-scan &1 - │ │ ├── columns: column2:10 column3:11 column4:12 + │ │ ├── columns: p:10 q:11 r:12 │ │ └── mapping: - │ │ ├── column2:7 => column2:10 - │ │ ├── column3:8 => column3:11 - │ │ └── column4:9 => column4:12 + │ │ ├── column2:7 => p:10 + │ │ ├── column3:8 => q:11 + │ │ └── column4:9 => r:12 │ └── filters - │ ├── column2:10 IS NOT NULL - │ ├── column3:11 IS NOT NULL - │ └── column4:12 IS NOT NULL + │ ├── p:10 IS NOT NULL + │ ├── q:11 IS NOT NULL + │ └── r:12 IS NOT NULL ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 # Only p and q are nullable. build @@ -324,24 +324,24 @@ insert multi_col_child └── f-k-checks └── f-k-checks-item: multi_col_child(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10!null column3:11!null column4:12!null + ├── columns: p:10!null q:11!null r:12!null ├── select - │ ├── columns: column2:10!null column3:11!null column4:12!null + │ ├── columns: p:10!null q:11!null r:12!null │ ├── with-scan &1 - │ │ ├── columns: column2:10 column3:11 column4:12!null + │ │ ├── columns: p:10 q:11 r:12!null │ │ └── mapping: - │ │ ├── column2:7 => column2:10 - │ │ ├── column3:8 => column3:11 - │ │ └── column4:9 => column4:12 + │ │ ├── column2:7 => p:10 + │ │ ├── column3:8 => q:11 + │ │ └── column4:9 => r:12 │ └── filters - │ ├── column2:10 IS NOT NULL - │ └── column3:11 IS NOT NULL + │ ├── p:10 IS NOT NULL + │ └── q:11 IS NOT NULL ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 # All the FK columns are not-null; no filter necessary. build @@ -361,19 +361,19 @@ insert multi_col_child └── f-k-checks └── f-k-checks-item: multi_col_child(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10!null column3:11!null column4:12!null + ├── columns: p:10!null q:11!null r:12!null ├── with-scan &1 - │ ├── columns: column2:10!null column3:11!null column4:12!null + │ ├── columns: p:10!null q:11!null r:12!null │ └── mapping: - │ ├── column2:7 => column2:10 - │ ├── column3:8 => column3:11 - │ └── column4:9 => column4:12 + │ ├── column2:7 => p:10 + │ ├── column3:8 => q:11 + │ └── column4:9 => r:12 ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 # No FK check needed - we have only NULL values for a FK column. build @@ -417,23 +417,23 @@ insert multi_col_child_full └── f-k-checks └── f-k-checks-item: multi_col_child_full(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10 column3:11 column4:12 + ├── columns: p:10 q:11 r:12 ├── select - │ ├── columns: column2:10 column3:11 column4:12 + │ ├── columns: p:10 q:11 r:12 │ ├── with-scan &1 - │ │ ├── columns: column2:10 column3:11 column4:12 + │ │ ├── columns: p:10 q:11 r:12 │ │ └── mapping: - │ │ ├── column2:7 => column2:10 - │ │ ├── column3:8 => column3:11 - │ │ └── column4:9 => column4:12 + │ │ ├── column2:7 => p:10 + │ │ ├── column3:8 => q:11 + │ │ └── column4:9 => r:12 │ └── filters - │ └── ((column2:10 IS NOT NULL) OR (column3:11 IS NOT NULL)) OR (column4:12 IS NOT NULL) + │ └── ((p:10 IS NOT NULL) OR (q:11 IS NOT NULL)) OR (r:12 IS NOT NULL) ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 # Only p and q are nullable; no filter necessary. build @@ -454,19 +454,19 @@ insert multi_col_child_full └── f-k-checks └── f-k-checks-item: multi_col_child_full(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10 column3:11 column4:12!null + ├── columns: p:10 q:11 r:12!null ├── with-scan &1 - │ ├── columns: column2:10 column3:11 column4:12!null + │ ├── columns: p:10 q:11 r:12!null │ └── mapping: - │ ├── column2:7 => column2:10 - │ ├── column3:8 => column3:11 - │ └── column4:9 => column4:12 + │ ├── column2:7 => p:10 + │ ├── column3:8 => q:11 + │ └── column4:9 => r:12 ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 # All the FK columns are not-null; no filter necessary. build @@ -486,19 +486,19 @@ insert multi_col_child_full └── f-k-checks └── f-k-checks-item: multi_col_child_full(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10!null column3:11!null column4:12!null + ├── columns: p:10!null q:11!null r:12!null ├── with-scan &1 - │ ├── columns: column2:10!null column3:11!null column4:12!null + │ ├── columns: p:10!null q:11!null r:12!null │ └── mapping: - │ ├── column2:7 => column2:10 - │ ├── column3:8 => column3:11 - │ └── column4:9 => column4:12 + │ ├── column2:7 => p:10 + │ ├── column3:8 => q:11 + │ └── column4:9 => r:12 ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 # No FK check needed when all FK columns only have NULL values. build @@ -534,19 +534,19 @@ insert multi_col_child_full └── f-k-checks └── f-k-checks-item: multi_col_child_full(p,q,r) -> multi_col_parent(p,q,r) └── anti-join (hash) - ├── columns: column2:10 column3:11!null column4:12 + ├── columns: p:10 q:11!null r:12 ├── with-scan &1 - │ ├── columns: column2:10 column3:11!null column4:12 + │ ├── columns: p:10 q:11!null r:12 │ └── mapping: - │ ├── column2:7 => column2:10 - │ ├── column3:8 => column3:11 - │ └── column4:9 => column4:12 + │ ├── column2:7 => p:10 + │ ├── column3:8 => q:11 + │ └── column4:9 => r:12 ├── scan multi_col_parent │ └── columns: multi_col_parent.p:13!null multi_col_parent.q:14!null multi_col_parent.r:15!null └── filters - ├── column2:10 = multi_col_parent.p:13 - ├── column3:11 = multi_col_parent.q:14 - └── column4:12 = multi_col_parent.r:15 + ├── p:10 = multi_col_parent.p:13 + ├── q:11 = multi_col_parent.q:14 + └── r:12 = multi_col_parent.r:15 exec-ddl CREATE TABLE multi_ref_parent_a (a INT PRIMARY KEY, other INT) @@ -586,37 +586,37 @@ insert multi_ref_child └── f-k-checks ├── f-k-checks-item: multi_ref_child(a) -> multi_ref_parent_a(a) │ └── anti-join (hash) - │ ├── columns: column2:10!null + │ ├── columns: a:10!null │ ├── select - │ │ ├── columns: column2:10!null + │ │ ├── columns: a:10!null │ │ ├── with-scan &1 - │ │ │ ├── columns: column2:10 + │ │ │ ├── columns: a:10 │ │ │ └── mapping: - │ │ │ └── column2:7 => column2:10 + │ │ │ └── column2:7 => a:10 │ │ └── filters - │ │ └── column2:10 IS NOT NULL + │ │ └── a:10 IS NOT NULL │ ├── scan multi_ref_parent_a │ │ └── columns: multi_ref_parent_a.a:11!null │ └── filters - │ └── column2:10 = multi_ref_parent_a.a:11 + │ └── a:10 = multi_ref_parent_a.a:11 └── f-k-checks-item: multi_ref_child(b,c) -> multi_ref_parent_bc(b,c) └── anti-join (hash) - ├── columns: column3:14!null column4:15!null + ├── columns: b:14!null c:15!null ├── select - │ ├── columns: column3:14!null column4:15!null + │ ├── columns: b:14!null c:15!null │ ├── with-scan &1 - │ │ ├── columns: column3:14 column4:15 + │ │ ├── columns: b:14 c:15 │ │ └── mapping: - │ │ ├── column3:8 => column3:14 - │ │ └── column4:9 => column4:15 + │ │ ├── column3:8 => b:14 + │ │ └── column4:9 => c:15 │ └── filters - │ ├── column3:14 IS NOT NULL - │ └── column4:15 IS NOT NULL + │ ├── b:14 IS NOT NULL + │ └── c:15 IS NOT NULL ├── scan multi_ref_parent_bc │ └── columns: multi_ref_parent_bc.b:16!null multi_ref_parent_bc.c:17!null └── filters - ├── column3:14 = multi_ref_parent_bc.b:16 - └── column4:15 = multi_ref_parent_bc.c:17 + ├── b:14 = multi_ref_parent_bc.b:16 + └── c:15 = multi_ref_parent_bc.c:17 build INSERT INTO multi_ref_child VALUES (1, NULL, NULL, NULL) @@ -649,13 +649,13 @@ insert child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: p:6!null ├── flags: prefer lookup join (into right side) ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ └── mapping: - │ └── column2:5 => column2:6 + │ └── column2:5 => p:6 ├── scan parent │ └── columns: parent.p:7!null └── filters - └── column2:6 = parent.p:7 + └── p:6 = parent.p:7 diff --git a/pkg/sql/opt/optbuilder/testdata/fk-checks-update b/pkg/sql/opt/optbuilder/testdata/fk-checks-update index d3a8cdf2cdc2..c75ea422a5f0 100644 --- a/pkg/sql/opt/optbuilder/testdata/fk-checks-update +++ b/pkg/sql/opt/optbuilder/testdata/fk-checks-update @@ -24,15 +24,15 @@ update child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:8!null + ├── columns: p:8!null ├── with-scan &1 - │ ├── columns: p_new:8!null + │ ├── columns: p:8!null │ └── mapping: - │ └── p_new:7 => p_new:8 + │ └── p_new:7 => p:8 ├── scan parent │ └── columns: parent.p:10!null └── filters - └── p_new:8 = parent.p:10 + └── p:8 = parent.p:10 build UPDATE parent SET p = p+1 @@ -56,15 +56,15 @@ update parent ├── except │ ├── columns: p:10!null │ ├── left columns: p:10!null - │ ├── right columns: p_new:11 + │ ├── right columns: p:11 │ ├── with-scan &1 │ │ ├── columns: p:10!null │ │ └── mapping: │ │ └── parent.p:6 => p:10 │ └── with-scan &1 - │ ├── columns: p_new:11!null + │ ├── columns: p:11!null │ └── mapping: - │ └── p_new:9 => p_new:11 + │ └── p_new:9 => p:11 ├── scan child │ └── columns: child.p:13!null └── filters @@ -96,15 +96,15 @@ update child ├── except │ ├── columns: c:8!null │ ├── left columns: c:8!null - │ ├── right columns: c_new:9 + │ ├── right columns: c:9 │ ├── with-scan &1 │ │ ├── columns: c:8!null │ │ └── mapping: │ │ └── child.c:4 => c:8 │ └── with-scan &1 - │ ├── columns: c_new:9!null + │ ├── columns: c:9!null │ └── mapping: - │ └── c_new:7 => c_new:9 + │ └── c_new:7 => c:9 ├── scan grandchild │ └── columns: grandchild.c:11!null └── filters @@ -129,15 +129,15 @@ update child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:8!null + ├── columns: p:8!null ├── with-scan &1 - │ ├── columns: p_new:8!null + │ ├── columns: p:8!null │ └── mapping: - │ └── p_new:7 => p_new:8 + │ └── p_new:7 => p:8 ├── scan parent │ └── columns: parent.p:10!null └── filters - └── p_new:8 = parent.p:10 + └── p:8 = parent.p:10 build UPDATE child SET p = p @@ -183,30 +183,30 @@ update child └── f-k-checks ├── f-k-checks-item: child(p) -> parent(p) │ └── anti-join (hash) - │ ├── columns: p_new:9!null + │ ├── columns: p:9!null │ ├── with-scan &1 - │ │ ├── columns: p_new:9!null + │ │ ├── columns: p:9!null │ │ └── mapping: - │ │ └── p_new:7 => p_new:9 + │ │ └── p_new:7 => p:9 │ ├── scan parent │ │ └── columns: parent.p:11!null │ └── filters - │ └── p_new:9 = parent.p:11 + │ └── p:9 = parent.p:11 └── f-k-checks-item: grandchild(c) -> child(c) └── semi-join (hash) ├── columns: c:14!null ├── except │ ├── columns: c:14!null │ ├── left columns: c:14!null - │ ├── right columns: c_new:15 + │ ├── right columns: c:15 │ ├── with-scan &1 │ │ ├── columns: c:14!null │ │ └── mapping: │ │ └── child.c:4 => c:14 │ └── with-scan &1 - │ ├── columns: c_new:15!null + │ ├── columns: c:15!null │ └── mapping: - │ └── c_new:8 => c_new:15 + │ └── c_new:8 => c:15 ├── scan grandchild │ └── columns: grandchild.c:17!null └── filters @@ -256,15 +256,15 @@ update child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:8!null + ├── columns: p:8!null ├── with-scan &1 - │ ├── columns: p_new:8!null + │ ├── columns: p:8!null │ └── mapping: - │ └── p_new:7 => p_new:8 + │ └── p_new:7 => p:8 ├── scan parent │ └── columns: parent.p:10!null └── filters - └── p_new:8 = parent.p:10 + └── p:8 = parent.p:10 exec-ddl CREATE TABLE self (x INT PRIMARY KEY, y INT NOT NULL REFERENCES self(x)) @@ -275,28 +275,28 @@ UPDATE self SET y = 3 ---- update self ├── columns: - ├── fetch columns: x:4 y:5 + ├── fetch columns: x:4 self.y:5 ├── update-mapping: - │ └── y_new:7 => y:2 + │ └── y_new:7 => self.y:2 ├── input binding: &1 ├── project - │ ├── columns: y_new:7!null x:4!null y:5!null crdb_internal_mvcc_timestamp:6 + │ ├── columns: y_new:7!null x:4!null self.y:5!null crdb_internal_mvcc_timestamp:6 │ ├── scan self - │ │ └── columns: x:4!null y:5!null crdb_internal_mvcc_timestamp:6 + │ │ └── columns: x:4!null self.y:5!null crdb_internal_mvcc_timestamp:6 │ └── projections │ └── 3 [as=y_new:7] └── f-k-checks └── f-k-checks-item: self(y) -> self(x) └── anti-join (hash) - ├── columns: y_new:8!null + ├── columns: y:8!null ├── with-scan &1 - │ ├── columns: y_new:8!null + │ ├── columns: y:8!null │ └── mapping: - │ └── y_new:7 => y_new:8 + │ └── y_new:7 => y:8 ├── scan self │ └── columns: x:9!null └── filters - └── y_new:8 = x:9 + └── y:8 = x:9 build UPDATE self SET x = 3 @@ -320,15 +320,15 @@ update self ├── except │ ├── columns: x:8!null │ ├── left columns: x:8!null - │ ├── right columns: x_new:9 + │ ├── right columns: x:9 │ ├── with-scan &1 │ │ ├── columns: x:8!null │ │ └── mapping: │ │ └── self.x:4 => x:8 │ └── with-scan &1 - │ ├── columns: x_new:9!null + │ ├── columns: x:9!null │ └── mapping: - │ └── x_new:7 => x_new:9 + │ └── x_new:7 => x:9 ├── scan self │ └── columns: y:11!null └── filters @@ -403,19 +403,19 @@ update child_multicol_full └── f-k-checks └── f-k-checks-item: child_multicol_full(a,b,c) -> parent_multicol(a,b,c) └── anti-join (hash) - ├── columns: a_new:13!null b_new:14 a_new:15!null + ├── columns: a:13!null b:14 c:15!null ├── with-scan &1 - │ ├── columns: a_new:13!null b_new:14 a_new:15!null + │ ├── columns: a:13!null b:14 c:15!null │ └── mapping: - │ ├── a_new:11 => a_new:13 - │ ├── b_new:12 => b_new:14 - │ └── a_new:11 => a_new:15 + │ ├── a_new:11 => a:13 + │ ├── b_new:12 => b:14 + │ └── a_new:11 => c:15 ├── scan parent_multicol │ └── columns: parent_multicol.a:16!null parent_multicol.b:17!null parent_multicol.c:18!null └── filters - ├── a_new:13 = parent_multicol.a:16 - ├── b_new:14 = parent_multicol.b:17 - └── a_new:15 = parent_multicol.c:18 + ├── a:13 = parent_multicol.a:16 + ├── b:14 = parent_multicol.b:17 + └── c:15 = parent_multicol.c:18 build UPDATE child_multicol_full SET a = NULL, b = NULL, c = NULL WHERE k = 1 @@ -464,33 +464,33 @@ UPDATE fam SET c = 3 ---- update fam ├── columns: - ├── fetch columns: fam.a:8 fam.b:9 c:10 rowid:13 + ├── fetch columns: fam.a:8 fam.b:9 fam.c:10 rowid:13 ├── update-mapping: - │ └── c_new:15 => c:3 + │ └── c_new:15 => fam.c:3 ├── input binding: &1 ├── project - │ ├── columns: c_new:15!null fam.a:8 fam.b:9 c:10 fam.d:11 rowid:13!null + │ ├── columns: c_new:15!null fam.a:8 fam.b:9 fam.c:10 fam.d:11 rowid:13!null │ ├── scan fam - │ │ └── columns: fam.a:8 fam.b:9 c:10 fam.d:11 rowid:13!null + │ │ └── columns: fam.a:8 fam.b:9 fam.c:10 fam.d:11 rowid:13!null │ └── projections │ └── 3 [as=c_new:15] └── f-k-checks └── f-k-checks-item: fam(c,d) -> two(a,b) └── anti-join (hash) - ├── columns: c_new:16!null d:17!null + ├── columns: c:16!null d:17!null ├── select - │ ├── columns: c_new:16!null d:17!null + │ ├── columns: c:16!null d:17!null │ ├── with-scan &1 - │ │ ├── columns: c_new:16!null d:17 + │ │ ├── columns: c:16!null d:17 │ │ └── mapping: - │ │ ├── c_new:15 => c_new:16 + │ │ ├── c_new:15 => c:16 │ │ └── fam.d:11 => d:17 │ └── filters │ └── d:17 IS NOT NULL ├── scan two │ └── columns: two.a:18!null two.b:19!null └── filters - ├── c_new:16 = two.a:18 + ├── c:16 = two.a:18 └── d:17 = two.b:19 norm @@ -498,34 +498,34 @@ UPDATE fam SET d = 3 ---- update fam ├── columns: - ├── fetch columns: d:11 e:12 rowid:13 + ├── fetch columns: fam.d:11 e:12 rowid:13 ├── update-mapping: - │ └── d_new:15 => d:4 + │ └── d_new:15 => fam.d:4 ├── input binding: &1 ├── project - │ ├── columns: d_new:15!null fam.c:10 d:11 e:12 rowid:13!null + │ ├── columns: d_new:15!null fam.c:10 fam.d:11 e:12 rowid:13!null │ ├── scan fam - │ │ └── columns: fam.c:10 d:11 e:12 rowid:13!null + │ │ └── columns: fam.c:10 fam.d:11 e:12 rowid:13!null │ └── projections │ └── 3 [as=d_new:15] └── f-k-checks └── f-k-checks-item: fam(c,d) -> two(a,b) └── anti-join (hash) - ├── columns: c:16!null d_new:17!null + ├── columns: c:16!null d:17!null ├── select - │ ├── columns: c:16!null d_new:17!null + │ ├── columns: c:16!null d:17!null │ ├── with-scan &1 - │ │ ├── columns: c:16 d_new:17!null + │ │ ├── columns: c:16 d:17!null │ │ └── mapping: │ │ ├── fam.c:10 => c:16 - │ │ └── d_new:15 => d_new:17 + │ │ └── d_new:15 => d:17 │ └── filters │ └── c:16 IS NOT NULL ├── scan two │ └── columns: two.a:18!null two.b:19!null └── filters ├── c:16 = two.a:18 - └── d_new:17 = two.b:19 + └── d:17 = two.b:19 # Verify that the join hint is set. build prefer-lookup-joins-for-fks @@ -546,13 +546,13 @@ update child └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:8!null + ├── columns: p:8!null ├── flags: prefer lookup join (into right side) ├── with-scan &1 - │ ├── columns: p_new:8!null + │ ├── columns: p:8!null │ └── mapping: - │ └── p_new:7 => p_new:8 + │ └── p_new:7 => p:8 ├── scan parent │ └── columns: parent.p:10!null └── filters - └── p_new:8 = parent.p:10 + └── p:8 = parent.p:10 diff --git a/pkg/sql/opt/optbuilder/testdata/fk-checks-upsert b/pkg/sql/opt/optbuilder/testdata/fk-checks-upsert index 708f0b81b366..b312c9ac00f8 100644 --- a/pkg/sql/opt/optbuilder/testdata/fk-checks-upsert +++ b/pkg/sql/opt/optbuilder/testdata/fk-checks-upsert @@ -51,15 +51,15 @@ upsert c1 └── f-k-checks └── f-k-checks-item: c1(p) -> p(p) └── anti-join (hash) - ├── columns: column2:8!null + ├── columns: p:8!null ├── with-scan &1 - │ ├── columns: column2:8!null + │ ├── columns: p:8!null │ └── mapping: - │ └── column2:6 => column2:8 + │ └── column2:6 => p:8 ├── scan p │ └── columns: p.p:9!null └── filters - └── column2:8 = p.p:9 + └── p:8 = p.p:9 build UPSERT INTO c1(c) VALUES (100), (200) @@ -106,15 +106,15 @@ upsert c1 └── f-k-checks └── f-k-checks-item: c1(p) -> p(p) └── anti-join (hash) - ├── columns: upsert_p:15 + ├── columns: p:15 ├── with-scan &1 - │ ├── columns: upsert_p:15 + │ ├── columns: p:15 │ └── mapping: - │ └── upsert_p:13 => upsert_p:15 + │ └── upsert_p:13 => p:15 ├── scan p │ └── columns: p.p:16!null └── filters - └── upsert_p:15 = p.p:16 + └── p:15 = p.p:16 # Use a non-constant input. build @@ -124,29 +124,29 @@ upsert c1 ├── columns: ├── upsert-mapping: │ ├── x:5 => c:1 - │ ├── xyzw.y:6 => c1.p:2 + │ ├── y:6 => c1.p:2 │ └── column11:11 => i:3 ├── input binding: &1 ├── project - │ ├── columns: column11:11 x:5 xyzw.y:6 + │ ├── columns: column11:11 x:5 y:6 │ ├── project - │ │ ├── columns: x:5 xyzw.y:6 + │ │ ├── columns: x:5 y:6 │ │ └── scan xyzw - │ │ └── columns: x:5 xyzw.y:6 z:7 w:8 rowid:9!null xyzw.crdb_internal_mvcc_timestamp:10 + │ │ └── columns: x:5 y:6 z:7 w:8 rowid:9!null xyzw.crdb_internal_mvcc_timestamp:10 │ └── projections │ └── NULL::INT8 [as=column11:11] └── f-k-checks └── f-k-checks-item: c1(p) -> p(p) └── anti-join (hash) - ├── columns: y:12 + ├── columns: p:12 ├── with-scan &1 - │ ├── columns: y:12 + │ ├── columns: p:12 │ └── mapping: - │ └── xyzw.y:6 => y:12 + │ └── y:6 => p:12 ├── scan p │ └── columns: p.p:13!null └── filters - └── y:12 = p.p:13 + └── p:12 = p.p:13 build INSERT INTO c1 VALUES (100, 1), (200, 1) ON CONFLICT (c) DO UPDATE SET p = excluded.p + 1 @@ -198,15 +198,15 @@ upsert c1 └── f-k-checks └── f-k-checks-item: c1(p) -> p(p) └── anti-join (hash) - ├── columns: upsert_p:16!null + ├── columns: p:16!null ├── with-scan &1 - │ ├── columns: upsert_p:16!null + │ ├── columns: p:16!null │ └── mapping: - │ └── upsert_p:14 => upsert_p:16 + │ └── upsert_p:14 => p:16 ├── scan p │ └── columns: p.p:17!null └── filters - └── upsert_p:16 = p.p:17 + └── p:16 = p.p:17 build INSERT INTO c1 SELECT u, v FROM uv ON CONFLICT (c) DO UPDATE SET i = c1.c + 1 @@ -258,15 +258,15 @@ upsert c1 └── f-k-checks └── f-k-checks-item: c1(p) -> p(p) └── anti-join (hash) - ├── columns: upsert_p:18 + ├── columns: p:18 ├── with-scan &1 - │ ├── columns: upsert_p:18 + │ ├── columns: p:18 │ └── mapping: - │ └── upsert_p:16 => upsert_p:18 + │ └── upsert_p:16 => p:18 ├── scan p │ └── columns: p.p:19!null └── filters - └── upsert_p:18 = p.p:19 + └── p:18 = p.p:19 exec-ddl CREATE TABLE c2 (c INT PRIMARY KEY, FOREIGN KEY (c) REFERENCES p(p)) @@ -278,19 +278,19 @@ INSERT INTO c2 VALUES (1), (2) ON CONFLICT (c) DO UPDATE SET c = 1 upsert c2 ├── columns: ├── arbiter indexes: primary - ├── canary column: c:4 - ├── fetch columns: c:4 + ├── canary column: c2.c:4 + ├── fetch columns: c2.c:4 ├── insert-mapping: - │ └── column1:3 => c:1 + │ └── column1:3 => c2.c:1 ├── update-mapping: - │ └── upsert_c:7 => c:1 + │ └── upsert_c:7 => c2.c:1 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:7!null column1:3!null c:4 c2.crdb_internal_mvcc_timestamp:5 c_new:6!null + │ ├── columns: upsert_c:7!null column1:3!null c2.c:4 c2.crdb_internal_mvcc_timestamp:5 c_new:6!null │ ├── project - │ │ ├── columns: c_new:6!null column1:3!null c:4 c2.crdb_internal_mvcc_timestamp:5 + │ │ ├── columns: c_new:6!null column1:3!null c2.c:4 c2.crdb_internal_mvcc_timestamp:5 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:3!null c:4 c2.crdb_internal_mvcc_timestamp:5 + │ │ │ ├── columns: column1:3!null c2.c:4 c2.crdb_internal_mvcc_timestamp:5 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:3!null │ │ │ │ ├── grouping columns: column1:3!null @@ -299,25 +299,25 @@ upsert c2 │ │ │ │ ├── (1,) │ │ │ │ └── (2,) │ │ │ ├── scan c2 - │ │ │ │ └── columns: c:4!null c2.crdb_internal_mvcc_timestamp:5 + │ │ │ │ └── columns: c2.c:4!null c2.crdb_internal_mvcc_timestamp:5 │ │ │ └── filters - │ │ │ └── column1:3 = c:4 + │ │ │ └── column1:3 = c2.c:4 │ │ └── projections │ │ └── 1 [as=c_new:6] │ └── projections - │ └── CASE WHEN c:4 IS NULL THEN column1:3 ELSE c_new:6 END [as=upsert_c:7] + │ └── CASE WHEN c2.c:4 IS NULL THEN column1:3 ELSE c_new:6 END [as=upsert_c:7] └── f-k-checks └── f-k-checks-item: c2(c) -> p(p) └── anti-join (hash) - ├── columns: upsert_c:8!null + ├── columns: c:8!null ├── with-scan &1 - │ ├── columns: upsert_c:8!null + │ ├── columns: c:8!null │ └── mapping: - │ └── upsert_c:7 => upsert_c:8 + │ └── upsert_c:7 => c:8 ├── scan p │ └── columns: p:9!null └── filters - └── upsert_c:8 = p:9 + └── c:8 = p:9 exec-ddl CREATE TABLE c3 (c INT PRIMARY KEY, p INT REFERENCES p(p)); @@ -341,19 +341,19 @@ upsert c3 └── f-k-checks └── f-k-checks-item: c3(p) -> p(p) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: p:6!null ├── select - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ ├── with-scan &1 - │ │ ├── columns: column2:6 + │ │ ├── columns: p:6 │ │ └── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => p:6 │ └── filters - │ └── column2:6 IS NOT NULL + │ └── p:6 IS NOT NULL ├── scan p │ └── columns: p.p:7!null └── filters - └── column2:6 = p.p:7 + └── p:6 = p.p:7 build UPSERT INTO c3(c) VALUES (100), (200) @@ -395,19 +395,19 @@ upsert c3 └── f-k-checks └── f-k-checks-item: c3(p) -> p(p) └── anti-join (hash) - ├── columns: upsert_p:11!null + ├── columns: p:11!null ├── select - │ ├── columns: upsert_p:11!null + │ ├── columns: p:11!null │ ├── with-scan &1 - │ │ ├── columns: upsert_p:11 + │ │ ├── columns: p:11 │ │ └── mapping: - │ │ └── upsert_p:10 => upsert_p:11 + │ │ └── upsert_p:10 => p:11 │ └── filters - │ └── upsert_p:11 IS NOT NULL + │ └── p:11 IS NOT NULL ├── scan p │ └── columns: p.p:12!null └── filters - └── upsert_p:11 = p.p:12 + └── p:11 = p.p:12 exec-ddl CREATE TABLE c4 (c INT PRIMARY KEY, a INT REFERENCES p(p), other INT, UNIQUE(a)) @@ -420,20 +420,20 @@ upsert c4 ├── columns: ├── arbiter indexes: secondary ├── canary column: c:11 - ├── fetch columns: c:11 a:12 c4.other:13 + ├── fetch columns: c:11 c4.a:12 c4.other:13 ├── insert-mapping: │ ├── x:5 => c:1 - │ ├── y:6 => a:2 + │ ├── y:6 => c4.a:2 │ └── z:7 => c4.other:3 ├── update-mapping: │ └── upsert_other:18 => c4.other:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:16 upsert_a:17 upsert_other:18 x:5 y:6 z:7 c:11 a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 other_new:15!null + │ ├── columns: upsert_c:16 upsert_a:17 upsert_other:18 x:5 y:6 z:7 c:11 c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 other_new:15!null │ ├── project - │ │ ├── columns: other_new:15!null x:5 y:6 z:7 c:11 a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 + │ │ ├── columns: other_new:15!null x:5 y:6 z:7 c:11 c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 │ │ ├── left-join (hash) - │ │ │ ├── columns: x:5 y:6 z:7 c:11 a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 + │ │ │ ├── columns: x:5 y:6 z:7 c:11 c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: x:5 y:6 z:7 │ │ │ │ ├── grouping columns: y:6 @@ -447,31 +447,31 @@ upsert c4 │ │ │ │ └── first-agg [as=z:7] │ │ │ │ └── z:7 │ │ │ ├── scan c4 - │ │ │ │ └── columns: c:11!null a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 + │ │ │ │ └── columns: c:11!null c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 │ │ │ └── filters - │ │ │ └── y:6 = a:12 + │ │ │ └── y:6 = c4.a:12 │ │ └── projections │ │ └── 1 [as=other_new:15] │ └── projections │ ├── CASE WHEN c:11 IS NULL THEN x:5 ELSE c:11 END [as=upsert_c:16] - │ ├── CASE WHEN c:11 IS NULL THEN y:6 ELSE a:12 END [as=upsert_a:17] + │ ├── CASE WHEN c:11 IS NULL THEN y:6 ELSE c4.a:12 END [as=upsert_a:17] │ └── CASE WHEN c:11 IS NULL THEN z:7 ELSE other_new:15 END [as=upsert_other:18] └── f-k-checks └── f-k-checks-item: c4(a) -> p(p) └── anti-join (hash) - ├── columns: upsert_a:19!null + ├── columns: a:19!null ├── select - │ ├── columns: upsert_a:19!null + │ ├── columns: a:19!null │ ├── with-scan &1 - │ │ ├── columns: upsert_a:19 + │ │ ├── columns: a:19 │ │ └── mapping: - │ │ └── upsert_a:17 => upsert_a:19 + │ │ └── upsert_a:17 => a:19 │ └── filters - │ └── upsert_a:19 IS NOT NULL + │ └── a:19 IS NOT NULL ├── scan p │ └── columns: p:20!null └── filters - └── upsert_a:19 = p:20 + └── a:19 = p:20 build INSERT INTO c4 SELECT x, y, z FROM xyzw ON CONFLICT (a) DO UPDATE SET a = 5 @@ -480,20 +480,20 @@ upsert c4 ├── columns: ├── arbiter indexes: secondary ├── canary column: c:11 - ├── fetch columns: c:11 a:12 c4.other:13 + ├── fetch columns: c:11 c4.a:12 c4.other:13 ├── insert-mapping: │ ├── x:5 => c:1 - │ ├── y:6 => a:2 + │ ├── y:6 => c4.a:2 │ └── z:7 => c4.other:3 ├── update-mapping: - │ └── upsert_a:17 => a:2 + │ └── upsert_a:17 => c4.a:2 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:16 upsert_a:17 upsert_other:18 x:5 y:6 z:7 c:11 a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 a_new:15!null + │ ├── columns: upsert_c:16 upsert_a:17 upsert_other:18 x:5 y:6 z:7 c:11 c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 a_new:15!null │ ├── project - │ │ ├── columns: a_new:15!null x:5 y:6 z:7 c:11 a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 + │ │ ├── columns: a_new:15!null x:5 y:6 z:7 c:11 c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 │ │ ├── left-join (hash) - │ │ │ ├── columns: x:5 y:6 z:7 c:11 a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 + │ │ │ ├── columns: x:5 y:6 z:7 c:11 c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: x:5 y:6 z:7 │ │ │ │ ├── grouping columns: y:6 @@ -507,9 +507,9 @@ upsert c4 │ │ │ │ └── first-agg [as=z:7] │ │ │ │ └── z:7 │ │ │ ├── scan c4 - │ │ │ │ └── columns: c:11!null a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 + │ │ │ │ └── columns: c:11!null c4.a:12 c4.other:13 c4.crdb_internal_mvcc_timestamp:14 │ │ │ └── filters - │ │ │ └── y:6 = a:12 + │ │ │ └── y:6 = c4.a:12 │ │ └── projections │ │ └── 5 [as=a_new:15] │ └── projections @@ -519,19 +519,19 @@ upsert c4 └── f-k-checks └── f-k-checks-item: c4(a) -> p(p) └── anti-join (hash) - ├── columns: upsert_a:19!null + ├── columns: a:19!null ├── select - │ ├── columns: upsert_a:19!null + │ ├── columns: a:19!null │ ├── with-scan &1 - │ │ ├── columns: upsert_a:19 + │ │ ├── columns: a:19 │ │ └── mapping: - │ │ └── upsert_a:17 => upsert_a:19 + │ │ └── upsert_a:17 => a:19 │ └── filters - │ └── upsert_a:19 IS NOT NULL + │ └── a:19 IS NOT NULL ├── scan p │ └── columns: p:20!null └── filters - └── upsert_a:19 = p:20 + └── a:19 = p:20 # ------------------------------------------ @@ -577,17 +577,17 @@ upsert cpq └── f-k-checks └── f-k-checks-item: cpq(p,q) -> pq(p,q) └── anti-join (hash) - ├── columns: column2:10!null column3:11!null + ├── columns: p:10!null q:11!null ├── with-scan &1 - │ ├── columns: column2:10!null column3:11!null + │ ├── columns: p:10!null q:11!null │ └── mapping: - │ ├── column2:7 => column2:10 - │ └── column3:8 => column3:11 + │ ├── column2:7 => p:10 + │ └── column3:8 => q:11 ├── scan pq │ └── columns: pq.p:13 pq.q:14 └── filters - ├── column2:10 = pq.p:13 - └── column3:11 = pq.q:14 + ├── p:10 = pq.p:13 + └── q:11 = pq.q:14 # In this case, the input columns can be null. build @@ -597,33 +597,33 @@ upsert cpq ├── columns: ├── upsert-mapping: │ ├── x:6 => c:1 - │ ├── xyzw.y:7 => cpq.p:2 - │ ├── xyzw.z:8 => cpq.q:3 + │ ├── y:7 => cpq.p:2 + │ ├── z:8 => cpq.q:3 │ └── w:9 => cpq.other:4 ├── input binding: &1 ├── project - │ ├── columns: x:6 xyzw.y:7 xyzw.z:8 w:9 + │ ├── columns: x:6 y:7 z:8 w:9 │ └── scan xyzw - │ └── columns: x:6 xyzw.y:7 xyzw.z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 + │ └── columns: x:6 y:7 z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 └── f-k-checks └── f-k-checks-item: cpq(p,q) -> pq(p,q) └── anti-join (hash) - ├── columns: y:12!null z:13!null + ├── columns: p:12!null q:13!null ├── select - │ ├── columns: y:12!null z:13!null + │ ├── columns: p:12!null q:13!null │ ├── with-scan &1 - │ │ ├── columns: y:12 z:13 + │ │ ├── columns: p:12 q:13 │ │ └── mapping: - │ │ ├── xyzw.y:7 => y:12 - │ │ └── xyzw.z:8 => z:13 + │ │ ├── y:7 => p:12 + │ │ └── z:8 => q:13 │ └── filters - │ ├── y:12 IS NOT NULL - │ └── z:13 IS NOT NULL + │ ├── p:12 IS NOT NULL + │ └── q:13 IS NOT NULL ├── scan pq │ └── columns: pq.p:15 pq.q:16 └── filters - ├── y:12 = pq.p:15 - └── z:13 = pq.q:16 + ├── p:12 = pq.p:15 + └── q:13 = pq.q:16 build UPSERT INTO cpq(c,p) SELECT x,y FROM xyzw @@ -635,31 +635,31 @@ upsert cpq ├── fetch columns: c:14 cpq.p:15 cpq.q:16 cpq.other:17 ├── insert-mapping: │ ├── x:6 => c:1 - │ ├── xyzw.y:7 => cpq.p:2 + │ ├── y:7 => cpq.p:2 │ ├── column12:12 => cpq.q:3 │ └── column13:13 => cpq.other:4 ├── update-mapping: - │ └── xyzw.y:7 => cpq.p:2 + │ └── y:7 => cpq.p:2 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:19 upsert_q:20 upsert_other:21 x:6 xyzw.y:7 column12:12!null column13:13 c:14 cpq.p:15 cpq.q:16 cpq.other:17 cpq.crdb_internal_mvcc_timestamp:18 + │ ├── columns: upsert_c:19 upsert_q:20 upsert_other:21 x:6 y:7 column12:12!null column13:13 c:14 cpq.p:15 cpq.q:16 cpq.other:17 cpq.crdb_internal_mvcc_timestamp:18 │ ├── left-join (hash) - │ │ ├── columns: x:6 xyzw.y:7 column12:12!null column13:13 c:14 cpq.p:15 cpq.q:16 cpq.other:17 cpq.crdb_internal_mvcc_timestamp:18 + │ │ ├── columns: x:6 y:7 column12:12!null column13:13 c:14 cpq.p:15 cpq.q:16 cpq.other:17 cpq.crdb_internal_mvcc_timestamp:18 │ │ ├── ensure-upsert-distinct-on - │ │ │ ├── columns: x:6 xyzw.y:7 column12:12!null column13:13 + │ │ │ ├── columns: x:6 y:7 column12:12!null column13:13 │ │ │ ├── grouping columns: x:6 │ │ │ ├── project - │ │ │ │ ├── columns: column12:12!null column13:13 x:6 xyzw.y:7 + │ │ │ │ ├── columns: column12:12!null column13:13 x:6 y:7 │ │ │ │ ├── project - │ │ │ │ │ ├── columns: x:6 xyzw.y:7 + │ │ │ │ │ ├── columns: x:6 y:7 │ │ │ │ │ └── scan xyzw - │ │ │ │ │ └── columns: x:6 xyzw.y:7 z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 + │ │ │ │ │ └── columns: x:6 y:7 z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 │ │ │ │ └── projections │ │ │ │ ├── 8 [as=column12:12] │ │ │ │ └── NULL::INT8 [as=column13:13] │ │ │ └── aggregations - │ │ │ ├── first-agg [as=xyzw.y:7] - │ │ │ │ └── xyzw.y:7 + │ │ │ ├── first-agg [as=y:7] + │ │ │ │ └── y:7 │ │ │ ├── first-agg [as=column12:12] │ │ │ │ └── column12:12 │ │ │ └── first-agg [as=column13:13] @@ -675,22 +675,22 @@ upsert cpq └── f-k-checks └── f-k-checks-item: cpq(p,q) -> pq(p,q) └── anti-join (hash) - ├── columns: y:22!null upsert_q:23!null + ├── columns: p:22!null q:23!null ├── select - │ ├── columns: y:22!null upsert_q:23!null + │ ├── columns: p:22!null q:23!null │ ├── with-scan &1 - │ │ ├── columns: y:22 upsert_q:23 + │ │ ├── columns: p:22 q:23 │ │ └── mapping: - │ │ ├── xyzw.y:7 => y:22 - │ │ └── upsert_q:20 => upsert_q:23 + │ │ ├── y:7 => p:22 + │ │ └── upsert_q:20 => q:23 │ └── filters - │ ├── y:22 IS NOT NULL - │ └── upsert_q:23 IS NOT NULL + │ ├── p:22 IS NOT NULL + │ └── q:23 IS NOT NULL ├── scan pq │ └── columns: pq.p:25 pq.q:26 └── filters - ├── y:22 = pq.p:25 - └── upsert_q:23 = pq.q:26 + ├── p:22 = pq.p:25 + └── q:23 = pq.q:26 build UPSERT INTO cpq(c) SELECT x FROM xyzw @@ -742,22 +742,22 @@ upsert cpq └── f-k-checks └── f-k-checks-item: cpq(p,q) -> pq(p,q) └── anti-join (hash) - ├── columns: upsert_p:24!null upsert_q:25!null + ├── columns: p:24!null q:25!null ├── select - │ ├── columns: upsert_p:24!null upsert_q:25!null + │ ├── columns: p:24!null q:25!null │ ├── with-scan &1 - │ │ ├── columns: upsert_p:24 upsert_q:25 + │ │ ├── columns: p:24 q:25 │ │ └── mapping: - │ │ ├── upsert_p:21 => upsert_p:24 - │ │ └── upsert_q:22 => upsert_q:25 + │ │ ├── upsert_p:21 => p:24 + │ │ └── upsert_q:22 => q:25 │ └── filters - │ ├── upsert_p:24 IS NOT NULL - │ └── upsert_q:25 IS NOT NULL + │ ├── p:24 IS NOT NULL + │ └── q:25 IS NOT NULL ├── scan pq │ └── columns: pq.p:27 pq.q:28 └── filters - ├── upsert_p:24 = pq.p:27 - └── upsert_q:25 = pq.q:28 + ├── p:24 = pq.p:27 + └── q:25 = pq.q:28 # This has different semantics from the UPSERT INTO cpq(c) version - here we # upsert default values for all unspecified columns. @@ -785,17 +785,17 @@ upsert cpq └── f-k-checks └── f-k-checks-item: cpq(p,q) -> pq(p,q) └── anti-join (hash) - ├── columns: column12:15!null column13:16!null + ├── columns: p:15!null q:16!null ├── with-scan &1 - │ ├── columns: column12:15!null column13:16!null + │ ├── columns: p:15!null q:16!null │ └── mapping: - │ ├── column12:12 => column12:15 - │ └── column13:13 => column13:16 + │ ├── column12:12 => p:15 + │ └── column13:13 => q:16 ├── scan pq │ └── columns: pq.p:18 pq.q:19 └── filters - ├── column12:15 = pq.p:18 - └── column13:16 = pq.q:19 + ├── p:15 = pq.p:18 + └── q:16 = pq.q:19 build INSERT INTO cpq VALUES (1), (2) ON CONFLICT (c) DO UPDATE SET p = 10 @@ -853,21 +853,21 @@ upsert cpq └── f-k-checks └── f-k-checks-item: cpq(p,q) -> pq(p,q) └── anti-join (hash) - ├── columns: upsert_p:20!null upsert_q:21!null + ├── columns: p:20!null q:21!null ├── select - │ ├── columns: upsert_p:20!null upsert_q:21!null + │ ├── columns: p:20!null q:21!null │ ├── with-scan &1 - │ │ ├── columns: upsert_p:20!null upsert_q:21 + │ │ ├── columns: p:20!null q:21 │ │ └── mapping: - │ │ ├── upsert_p:17 => upsert_p:20 - │ │ └── upsert_q:18 => upsert_q:21 + │ │ ├── upsert_p:17 => p:20 + │ │ └── upsert_q:18 => q:21 │ └── filters - │ └── upsert_q:21 IS NOT NULL + │ └── q:21 IS NOT NULL ├── scan pq │ └── columns: pq.p:23 pq.q:24 └── filters - ├── upsert_p:20 = pq.p:23 - └── upsert_q:21 = pq.q:24 + ├── p:20 = pq.p:23 + └── q:21 = pq.q:24 # ------------------------------------------ # Multiple outbound FKs @@ -891,40 +891,40 @@ UPSERT INTO cmulti SELECT x,y,z,w FROM xyzw upsert cmulti ├── columns: ├── upsert-mapping: - │ ├── xyzw.x:6 => a:1 - │ ├── xyzw.y:7 => b:2 - │ ├── xyzw.z:8 => c:3 + │ ├── x:6 => cmulti.a:1 + │ ├── y:7 => cmulti.b:2 + │ ├── z:8 => cmulti.c:3 │ └── w:9 => d:4 ├── input binding: &1 ├── project - │ ├── columns: xyzw.x:6 xyzw.y:7 xyzw.z:8 w:9 + │ ├── columns: x:6 y:7 z:8 w:9 │ └── scan xyzw - │ └── columns: xyzw.x:6 xyzw.y:7 xyzw.z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 + │ └── columns: x:6 y:7 z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 └── f-k-checks ├── f-k-checks-item: cmulti(a) -> p(p) │ └── anti-join (hash) - │ ├── columns: x:12 + │ ├── columns: a:12 │ ├── with-scan &1 - │ │ ├── columns: x:12 + │ │ ├── columns: a:12 │ │ └── mapping: - │ │ └── xyzw.x:6 => x:12 + │ │ └── x:6 => a:12 │ ├── scan p │ │ └── columns: p.p:13!null │ └── filters - │ └── x:12 = p.p:13 + │ └── a:12 = p.p:13 └── f-k-checks-item: cmulti(b,c) -> pq(p,q) └── anti-join (hash) - ├── columns: y:16 z:17 + ├── columns: b:16 c:17 ├── with-scan &1 - │ ├── columns: y:16 z:17 + │ ├── columns: b:16 c:17 │ └── mapping: - │ ├── xyzw.y:7 => y:16 - │ └── xyzw.z:8 => z:17 + │ ├── y:7 => b:16 + │ └── z:8 => c:17 ├── scan pq │ └── columns: pq.p:19 q:20 └── filters - ├── y:16 = pq.p:19 - └── z:17 = q:20 + ├── b:16 = pq.p:19 + └── c:17 = q:20 build UPSERT INTO cmulti(a,b,c) SELECT x,y,z FROM xyzw @@ -932,70 +932,70 @@ UPSERT INTO cmulti(a,b,c) SELECT x,y,z FROM xyzw upsert cmulti ├── columns: ├── arbiter indexes: primary - ├── canary column: a:13 - ├── fetch columns: a:13 b:14 c:15 d:16 + ├── canary column: cmulti.a:13 + ├── fetch columns: cmulti.a:13 cmulti.b:14 cmulti.c:15 d:16 ├── insert-mapping: - │ ├── x:6 => a:1 - │ ├── y:7 => b:2 - │ ├── xyzw.z:8 => c:3 + │ ├── x:6 => cmulti.a:1 + │ ├── y:7 => cmulti.b:2 + │ ├── z:8 => cmulti.c:3 │ └── column12:12 => d:4 ├── update-mapping: - │ └── xyzw.z:8 => c:3 + │ └── z:8 => cmulti.c:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_a:18 upsert_b:19 upsert_d:20 x:6 y:7 xyzw.z:8 column12:12!null a:13 b:14 c:15 d:16 cmulti.crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_a:18 upsert_b:19 upsert_d:20 x:6 y:7 z:8 column12:12!null cmulti.a:13 cmulti.b:14 cmulti.c:15 d:16 cmulti.crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: x:6 y:7 xyzw.z:8 column12:12!null a:13 b:14 c:15 d:16 cmulti.crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: x:6 y:7 z:8 column12:12!null cmulti.a:13 cmulti.b:14 cmulti.c:15 d:16 cmulti.crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on - │ │ │ ├── columns: x:6 y:7 xyzw.z:8 column12:12!null + │ │ │ ├── columns: x:6 y:7 z:8 column12:12!null │ │ │ ├── grouping columns: x:6 y:7 │ │ │ ├── project - │ │ │ │ ├── columns: column12:12!null x:6 y:7 xyzw.z:8 + │ │ │ │ ├── columns: column12:12!null x:6 y:7 z:8 │ │ │ │ ├── project - │ │ │ │ │ ├── columns: x:6 y:7 xyzw.z:8 + │ │ │ │ │ ├── columns: x:6 y:7 z:8 │ │ │ │ │ └── scan xyzw - │ │ │ │ │ └── columns: x:6 y:7 xyzw.z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 + │ │ │ │ │ └── columns: x:6 y:7 z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 │ │ │ │ └── projections │ │ │ │ └── 8 [as=column12:12] │ │ │ └── aggregations - │ │ │ ├── first-agg [as=xyzw.z:8] - │ │ │ │ └── xyzw.z:8 + │ │ │ ├── first-agg [as=z:8] + │ │ │ │ └── z:8 │ │ │ └── first-agg [as=column12:12] │ │ │ └── column12:12 │ │ ├── scan cmulti - │ │ │ └── columns: a:13!null b:14!null c:15 d:16 cmulti.crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: cmulti.a:13!null cmulti.b:14!null cmulti.c:15 d:16 cmulti.crdb_internal_mvcc_timestamp:17 │ │ └── filters - │ │ ├── x:6 = a:13 - │ │ └── y:7 = b:14 + │ │ ├── x:6 = cmulti.a:13 + │ │ └── y:7 = cmulti.b:14 │ └── projections - │ ├── CASE WHEN a:13 IS NULL THEN x:6 ELSE a:13 END [as=upsert_a:18] - │ ├── CASE WHEN a:13 IS NULL THEN y:7 ELSE b:14 END [as=upsert_b:19] - │ └── CASE WHEN a:13 IS NULL THEN column12:12 ELSE d:16 END [as=upsert_d:20] + │ ├── CASE WHEN cmulti.a:13 IS NULL THEN x:6 ELSE cmulti.a:13 END [as=upsert_a:18] + │ ├── CASE WHEN cmulti.a:13 IS NULL THEN y:7 ELSE cmulti.b:14 END [as=upsert_b:19] + │ └── CASE WHEN cmulti.a:13 IS NULL THEN column12:12 ELSE d:16 END [as=upsert_d:20] └── f-k-checks ├── f-k-checks-item: cmulti(a) -> p(p) │ └── anti-join (hash) - │ ├── columns: upsert_a:21 + │ ├── columns: a:21 │ ├── with-scan &1 - │ │ ├── columns: upsert_a:21 + │ │ ├── columns: a:21 │ │ └── mapping: - │ │ └── upsert_a:18 => upsert_a:21 + │ │ └── upsert_a:18 => a:21 │ ├── scan p │ │ └── columns: p.p:22!null │ └── filters - │ └── upsert_a:21 = p.p:22 + │ └── a:21 = p.p:22 └── f-k-checks-item: cmulti(b,c) -> pq(p,q) └── anti-join (hash) - ├── columns: upsert_b:25 z:26 + ├── columns: b:25 c:26 ├── with-scan &1 - │ ├── columns: upsert_b:25 z:26 + │ ├── columns: b:25 c:26 │ └── mapping: - │ ├── upsert_b:19 => upsert_b:25 - │ └── xyzw.z:8 => z:26 + │ ├── upsert_b:19 => b:25 + │ └── z:8 => c:26 ├── scan pq │ └── columns: pq.p:28 q:29 └── filters - ├── upsert_b:25 = pq.p:28 - └── z:26 = q:29 + ├── b:25 = pq.p:28 + └── c:26 = q:29 # --------------------------------------- # Inbound FK tests with single FK column @@ -1106,15 +1106,15 @@ upsert p1 ├── except │ ├── columns: p:12 │ ├── left columns: p:12 - │ ├── right columns: upsert_p:13 + │ ├── right columns: p:13 │ ├── with-scan &1 │ │ ├── columns: p:12 │ │ └── mapping: │ │ └── p1.p:6 => p:12 │ └── with-scan &1 - │ ├── columns: upsert_p:13!null + │ ├── columns: p:13!null │ └── mapping: - │ └── upsert_p:10 => upsert_p:13 + │ └── upsert_p:10 => p:13 ├── scan p1c │ └── columns: p1c.p:15!null └── filters @@ -1210,15 +1210,15 @@ upsert p2 ├── except │ ├── columns: fk:10 │ ├── left columns: fk:10 - │ ├── right columns: column2:11 + │ ├── right columns: fk:11 │ ├── with-scan &1 │ │ ├── columns: fk:10 │ │ └── mapping: │ │ └── p2.fk:7 => fk:10 │ └── with-scan &1 - │ ├── columns: column2:11!null + │ ├── columns: fk:11!null │ └── mapping: - │ └── column2:5 => column2:11 + │ └── column2:5 => fk:11 ├── scan p2c │ └── columns: p2c.fk:13 └── filters @@ -1313,15 +1313,15 @@ upsert p2 ├── except │ ├── columns: fk:12 │ ├── left columns: fk:12 - │ ├── right columns: upsert_fk:13 + │ ├── right columns: fk:13 │ ├── with-scan &1 │ │ ├── columns: fk:12 │ │ └── mapping: │ │ └── p2.fk:7 => fk:12 │ └── with-scan &1 - │ ├── columns: upsert_fk:13!null + │ ├── columns: fk:13!null │ └── mapping: - │ └── upsert_fk:11 => upsert_fk:13 + │ └── upsert_fk:11 => fk:13 ├── scan p2c │ └── columns: p2c.fk:15 └── filters @@ -1414,15 +1414,15 @@ upsert p2 ├── except │ ├── columns: fk:12 │ ├── left columns: fk:12 - │ ├── right columns: upsert_fk:13 + │ ├── right columns: fk:13 │ ├── with-scan &1 │ │ ├── columns: fk:12 │ │ └── mapping: │ │ └── p2.fk:7 => fk:12 │ └── with-scan &1 - │ ├── columns: upsert_fk:13!null + │ ├── columns: fk:13!null │ └── mapping: - │ └── upsert_fk:11 => upsert_fk:13 + │ └── upsert_fk:11 => fk:13 ├── scan p2c │ └── columns: p2c.fk:15 └── filters @@ -1520,17 +1520,17 @@ upsert pq │ ├── except │ │ ├── columns: p:16 q:17 │ │ ├── left columns: p:16 q:17 - │ │ ├── right columns: column2:18 column3:19 + │ │ ├── right columns: p:18 q:19 │ │ ├── with-scan &1 │ │ │ ├── columns: p:16 q:17 │ │ │ └── mapping: │ │ │ ├── pq.p:11 => p:16 │ │ │ └── pq.q:12 => q:17 │ │ └── with-scan &1 - │ │ ├── columns: column2:18!null column3:19!null + │ │ ├── columns: p:18!null q:19!null │ │ └── mapping: - │ │ ├── column2:7 => column2:18 - │ │ └── column3:8 => column3:19 + │ │ ├── column2:7 => p:18 + │ │ └── column3:8 => q:19 │ ├── scan cpq │ │ └── columns: cpq.p:21 cpq.q:22 │ └── filters @@ -1542,17 +1542,17 @@ upsert pq ├── except │ ├── columns: p:25 q:26 │ ├── left columns: p:25 q:26 - │ ├── right columns: column2:27 column3:28 + │ ├── right columns: p:27 q:28 │ ├── with-scan &1 │ │ ├── columns: p:25 q:26 │ │ └── mapping: │ │ ├── pq.p:11 => p:25 │ │ └── pq.q:12 => q:26 │ └── with-scan &1 - │ ├── columns: column2:27!null column3:28!null + │ ├── columns: p:27!null q:28!null │ └── mapping: - │ ├── column2:7 => column2:27 - │ └── column3:8 => column3:28 + │ ├── column2:7 => p:27 + │ └── column3:8 => q:28 ├── scan cmulti │ └── columns: b:30!null cmulti.c:31 └── filters @@ -1652,17 +1652,17 @@ upsert pq │ ├── except │ │ ├── columns: p:17 q:18 │ │ ├── left columns: p:17 q:18 - │ │ ├── right columns: upsert_p:19 column2:20 + │ │ ├── right columns: p:19 q:20 │ │ ├── with-scan &1 │ │ │ ├── columns: p:17 q:18 │ │ │ └── mapping: │ │ │ ├── pq.p:10 => p:17 │ │ │ └── pq.q:11 => q:18 │ │ └── with-scan &1 - │ │ ├── columns: upsert_p:19 column2:20!null + │ │ ├── columns: p:19 q:20!null │ │ └── mapping: - │ │ ├── upsert_p:15 => upsert_p:19 - │ │ └── column2:7 => column2:20 + │ │ ├── upsert_p:15 => p:19 + │ │ └── column2:7 => q:20 │ ├── scan cpq │ │ └── columns: cpq.p:22 cpq.q:23 │ └── filters @@ -1674,17 +1674,17 @@ upsert pq ├── except │ ├── columns: p:26 q:27 │ ├── left columns: p:26 q:27 - │ ├── right columns: upsert_p:28 column2:29 + │ ├── right columns: p:28 q:29 │ ├── with-scan &1 │ │ ├── columns: p:26 q:27 │ │ └── mapping: │ │ ├── pq.p:10 => p:26 │ │ └── pq.q:11 => q:27 │ └── with-scan &1 - │ ├── columns: upsert_p:28 column2:29!null + │ ├── columns: p:28 q:29!null │ └── mapping: - │ ├── upsert_p:15 => upsert_p:28 - │ └── column2:7 => column2:29 + │ ├── upsert_p:15 => p:28 + │ └── column2:7 => q:29 ├── scan cmulti │ └── columns: b:31!null cmulti.c:32 └── filters @@ -1791,17 +1791,17 @@ upsert pq │ ├── except │ │ ├── columns: p:20 q:21 │ │ ├── left columns: p:20 q:21 - │ │ ├── right columns: upsert_p:22 upsert_q:23 + │ │ ├── right columns: p:22 q:23 │ │ ├── with-scan &1 │ │ │ ├── columns: p:20 q:21 │ │ │ └── mapping: │ │ │ ├── pq.p:11 => p:20 │ │ │ └── pq.q:12 => q:21 │ │ └── with-scan &1 - │ │ ├── columns: upsert_p:22 upsert_q:23 + │ │ ├── columns: p:22 q:23 │ │ └── mapping: - │ │ ├── upsert_p:17 => upsert_p:22 - │ │ └── upsert_q:18 => upsert_q:23 + │ │ ├── upsert_p:17 => p:22 + │ │ └── upsert_q:18 => q:23 │ ├── scan cpq │ │ └── columns: cpq.p:25 cpq.q:26 │ └── filters @@ -1813,17 +1813,17 @@ upsert pq ├── except │ ├── columns: p:29 q:30 │ ├── left columns: p:29 q:30 - │ ├── right columns: upsert_p:31 upsert_q:32 + │ ├── right columns: p:31 q:32 │ ├── with-scan &1 │ │ ├── columns: p:29 q:30 │ │ └── mapping: │ │ ├── pq.p:11 => p:29 │ │ └── pq.q:12 => q:30 │ └── with-scan &1 - │ ├── columns: upsert_p:31 upsert_q:32 + │ ├── columns: p:31 q:32 │ └── mapping: - │ ├── upsert_p:17 => upsert_p:31 - │ └── upsert_q:18 => upsert_q:32 + │ ├── upsert_p:17 => p:31 + │ └── upsert_q:18 => q:32 ├── scan cmulti │ └── columns: b:34!null cmulti.c:35 └── filters @@ -1932,17 +1932,17 @@ upsert pq │ ├── except │ │ ├── columns: p:20 q:21 │ │ ├── left columns: p:20 q:21 - │ │ ├── right columns: upsert_p:22 upsert_q:23 + │ │ ├── right columns: p:22 q:23 │ │ ├── with-scan &1 │ │ │ ├── columns: p:20 q:21 │ │ │ └── mapping: │ │ │ ├── pq.p:11 => p:20 │ │ │ └── pq.q:12 => q:21 │ │ └── with-scan &1 - │ │ ├── columns: upsert_p:22 upsert_q:23!null + │ │ ├── columns: p:22 q:23!null │ │ └── mapping: - │ │ ├── upsert_p:17 => upsert_p:22 - │ │ └── upsert_q:18 => upsert_q:23 + │ │ ├── upsert_p:17 => p:22 + │ │ └── upsert_q:18 => q:23 │ ├── scan cpq │ │ └── columns: cpq.p:25 cpq.q:26 │ └── filters @@ -1954,17 +1954,17 @@ upsert pq ├── except │ ├── columns: p:29 q:30 │ ├── left columns: p:29 q:30 - │ ├── right columns: upsert_p:31 upsert_q:32 + │ ├── right columns: p:31 q:32 │ ├── with-scan &1 │ │ ├── columns: p:29 q:30 │ │ └── mapping: │ │ ├── pq.p:11 => p:29 │ │ └── pq.q:12 => q:30 │ └── with-scan &1 - │ ├── columns: upsert_p:31 upsert_q:32!null + │ ├── columns: p:31 q:32!null │ └── mapping: - │ ├── upsert_p:17 => upsert_p:31 - │ └── upsert_q:18 => upsert_q:32 + │ ├── upsert_p:17 => p:31 + │ └── upsert_q:18 => q:32 ├── scan cmulti │ └── columns: b:34!null cmulti.c:35 └── filters @@ -2004,19 +2004,19 @@ upsert tab2 ├── columns: ├── arbiter indexes: primary ├── canary column: c:8 - ├── fetch columns: c:8 d:9 tab2.e:10 + ├── fetch columns: c:8 tab2.d:9 tab2.e:10 ├── insert-mapping: │ ├── column1:5 => c:1 - │ ├── column2:6 => d:2 + │ ├── column2:6 => tab2.d:2 │ └── column3:7 => tab2.e:3 ├── update-mapping: - │ ├── column2:6 => d:2 + │ ├── column2:6 => tab2.d:2 │ └── column3:7 => tab2.e:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:12 column1:5!null column2:6 column3:7 c:8 d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ ├── columns: upsert_c:12 column1:5!null column2:6 column3:7 c:8 tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 │ ├── left-join (hash) - │ │ ├── columns: column1:5!null column2:6 column3:7 c:8 d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ ├── columns: column1:5!null column2:6 column3:7 c:8 tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:5!null column2:6 column3:7 │ │ │ ├── grouping columns: column1:5!null @@ -2030,7 +2030,7 @@ upsert tab2 │ │ │ └── first-agg [as=column3:7] │ │ │ └── column3:7 │ │ ├── scan tab2 - │ │ │ └── columns: c:8!null d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ │ └── columns: c:8!null tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ └── filters │ │ └── column1:5 = c:8 │ └── projections @@ -2038,34 +2038,34 @@ upsert tab2 └── f-k-checks ├── f-k-checks-item: tab2(d) -> tab1(b) │ └── anti-join (hash) - │ ├── columns: column2:13!null + │ ├── columns: d:13!null │ ├── select - │ │ ├── columns: column2:13!null + │ │ ├── columns: d:13!null │ │ ├── with-scan &1 - │ │ │ ├── columns: column2:13 + │ │ │ ├── columns: d:13 │ │ │ └── mapping: - │ │ │ └── column2:6 => column2:13 + │ │ │ └── column2:6 => d:13 │ │ └── filters - │ │ └── column2:13 IS NOT NULL + │ │ └── d:13 IS NOT NULL │ ├── scan tab1 │ │ └── columns: b:15 │ └── filters - │ └── column2:13 = b:15 + │ └── d:13 = b:15 └── f-k-checks-item: tab3(g) -> tab2(e) └── semi-join (hash) ├── columns: e:17 ├── except │ ├── columns: e:17 │ ├── left columns: e:17 - │ ├── right columns: column3:18 + │ ├── right columns: e:18 │ ├── with-scan &1 │ │ ├── columns: e:17 │ │ └── mapping: │ │ └── tab2.e:10 => e:17 │ └── with-scan &1 - │ ├── columns: column3:18 + │ ├── columns: e:18 │ └── mapping: - │ └── column3:7 => column3:18 + │ └── column3:7 => e:18 ├── scan tab3 │ └── columns: g:20 └── filters @@ -2078,20 +2078,20 @@ upsert tab2 ├── columns: ├── arbiter indexes: primary ├── canary column: c:8 - ├── fetch columns: c:8 d:9 tab2.e:10 + ├── fetch columns: c:8 tab2.d:9 tab2.e:10 ├── insert-mapping: │ ├── column1:5 => c:1 - │ ├── column2:6 => d:2 + │ ├── column2:6 => tab2.d:2 │ └── column3:7 => tab2.e:3 ├── update-mapping: │ └── upsert_e:15 => tab2.e:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:13 upsert_d:14 upsert_e:15 column1:5!null column2:6!null column3:7!null c:8 d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 e_new:12 + │ ├── columns: upsert_c:13 upsert_d:14 upsert_e:15 column1:5!null column2:6!null column3:7!null c:8 tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 e_new:12 │ ├── project - │ │ ├── columns: e_new:12 column1:5!null column2:6!null column3:7!null c:8 d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ ├── columns: e_new:12 column1:5!null column2:6!null column3:7!null c:8 tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null c:8 d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null c:8 tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null │ │ │ │ ├── grouping columns: column1:5!null @@ -2104,46 +2104,46 @@ upsert tab2 │ │ │ │ └── first-agg [as=column3:7] │ │ │ │ └── column3:7 │ │ │ ├── scan tab2 - │ │ │ │ └── columns: c:8!null d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ │ │ └── columns: c:8!null tab2.d:9 tab2.e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ │ └── filters │ │ │ └── column1:5 = c:8 │ │ └── projections │ │ └── tab2.e:10 + 1 [as=e_new:12] │ └── projections │ ├── CASE WHEN c:8 IS NULL THEN column1:5 ELSE c:8 END [as=upsert_c:13] - │ ├── CASE WHEN c:8 IS NULL THEN column2:6 ELSE d:9 END [as=upsert_d:14] + │ ├── CASE WHEN c:8 IS NULL THEN column2:6 ELSE tab2.d:9 END [as=upsert_d:14] │ └── CASE WHEN c:8 IS NULL THEN column3:7 ELSE e_new:12 END [as=upsert_e:15] └── f-k-checks ├── f-k-checks-item: tab2(d) -> tab1(b) │ └── anti-join (hash) - │ ├── columns: upsert_d:16!null + │ ├── columns: d:16!null │ ├── select - │ │ ├── columns: upsert_d:16!null + │ │ ├── columns: d:16!null │ │ ├── with-scan &1 - │ │ │ ├── columns: upsert_d:16 + │ │ │ ├── columns: d:16 │ │ │ └── mapping: - │ │ │ └── upsert_d:14 => upsert_d:16 + │ │ │ └── upsert_d:14 => d:16 │ │ └── filters - │ │ └── upsert_d:16 IS NOT NULL + │ │ └── d:16 IS NOT NULL │ ├── scan tab1 │ │ └── columns: b:18 │ └── filters - │ └── upsert_d:16 = b:18 + │ └── d:16 = b:18 └── f-k-checks-item: tab3(g) -> tab2(e) └── semi-join (hash) ├── columns: e:20 ├── except │ ├── columns: e:20 │ ├── left columns: e:20 - │ ├── right columns: upsert_e:21 + │ ├── right columns: e:21 │ ├── with-scan &1 │ │ ├── columns: e:20 │ │ └── mapping: │ │ └── tab2.e:10 => e:20 │ └── with-scan &1 - │ ├── columns: upsert_e:21 + │ ├── columns: e:21 │ └── mapping: - │ └── upsert_e:15 => upsert_e:21 + │ └── upsert_e:15 => e:21 ├── scan tab3 │ └── columns: g:23 └── filters @@ -2157,20 +2157,20 @@ upsert tab2 ├── columns: ├── arbiter indexes: tab2_e_key ├── canary column: c:8 - ├── fetch columns: c:8 d:9 e:10 + ├── fetch columns: c:8 tab2.d:9 e:10 ├── insert-mapping: │ ├── column1:5 => c:1 - │ ├── column2:6 => d:2 + │ ├── column2:6 => tab2.d:2 │ └── column3:7 => e:3 ├── update-mapping: - │ └── upsert_d:14 => d:2 + │ └── upsert_d:14 => tab2.d:2 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:13 upsert_d:14 upsert_e:15 column1:5!null column2:6!null column3:7!null c:8 d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 d_new:12 + │ ├── columns: upsert_c:13 upsert_d:14 upsert_e:15 column1:5!null column2:6!null column3:7!null c:8 tab2.d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 d_new:12 │ ├── project - │ │ ├── columns: d_new:12 column1:5!null column2:6!null column3:7!null c:8 d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ ├── columns: d_new:12 column1:5!null column2:6!null column3:7!null c:8 tab2.d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null c:8 d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null c:8 tab2.d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null │ │ │ │ ├── grouping columns: column3:7!null @@ -2183,11 +2183,11 @@ upsert tab2 │ │ │ │ └── first-agg [as=column2:6] │ │ │ │ └── column2:6 │ │ │ ├── scan tab2 - │ │ │ │ └── columns: c:8!null d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 + │ │ │ │ └── columns: c:8!null tab2.d:9 e:10 tab2.crdb_internal_mvcc_timestamp:11 │ │ │ └── filters │ │ │ └── column3:7 = e:10 │ │ └── projections - │ │ └── d:9 + 1 [as=d_new:12] + │ │ └── tab2.d:9 + 1 [as=d_new:12] │ └── projections │ ├── CASE WHEN c:8 IS NULL THEN column1:5 ELSE c:8 END [as=upsert_c:13] │ ├── CASE WHEN c:8 IS NULL THEN column2:6 ELSE d_new:12 END [as=upsert_d:14] @@ -2195,19 +2195,19 @@ upsert tab2 └── f-k-checks └── f-k-checks-item: tab2(d) -> tab1(b) └── anti-join (hash) - ├── columns: upsert_d:16!null + ├── columns: d:16!null ├── select - │ ├── columns: upsert_d:16!null + │ ├── columns: d:16!null │ ├── with-scan &1 - │ │ ├── columns: upsert_d:16 + │ │ ├── columns: d:16 │ │ └── mapping: - │ │ └── upsert_d:14 => upsert_d:16 + │ │ └── upsert_d:14 => d:16 │ └── filters - │ └── upsert_d:16 IS NOT NULL + │ └── d:16 IS NOT NULL ├── scan tab1 │ └── columns: b:18 └── filters - └── upsert_d:16 = b:18 + └── d:16 = b:18 exec-ddl CREATE TABLE self ( @@ -2229,91 +2229,91 @@ UPSERT INTO self SELECT x, y, z, w FROM xyzw upsert self ├── columns: ├── arbiter indexes: primary - ├── canary column: a:12 - ├── fetch columns: a:12 self.b:13 self.c:14 self.d:15 + ├── canary column: self.a:12 + ├── fetch columns: self.a:12 self.b:13 self.c:14 self.d:15 ├── insert-mapping: - │ ├── x:6 => a:1 + │ ├── x:6 => self.a:1 │ ├── y:7 => self.b:2 - │ ├── xyzw.z:8 => self.c:3 - │ └── xyzw.w:9 => self.d:4 + │ ├── z:8 => self.c:3 + │ └── w:9 => self.d:4 ├── update-mapping: - │ ├── xyzw.z:8 => self.c:3 - │ └── xyzw.w:9 => self.d:4 + │ ├── z:8 => self.c:3 + │ └── w:9 => self.d:4 ├── input binding: &1 ├── project - │ ├── columns: upsert_a:17 upsert_b:18 x:6 y:7 xyzw.z:8 xyzw.w:9 a:12 self.b:13 self.c:14 self.d:15 self.crdb_internal_mvcc_timestamp:16 + │ ├── columns: upsert_a:17 upsert_b:18 x:6 y:7 z:8 w:9 self.a:12 self.b:13 self.c:14 self.d:15 self.crdb_internal_mvcc_timestamp:16 │ ├── left-join (hash) - │ │ ├── columns: x:6 y:7 xyzw.z:8 xyzw.w:9 a:12 self.b:13 self.c:14 self.d:15 self.crdb_internal_mvcc_timestamp:16 + │ │ ├── columns: x:6 y:7 z:8 w:9 self.a:12 self.b:13 self.c:14 self.d:15 self.crdb_internal_mvcc_timestamp:16 │ │ ├── ensure-upsert-distinct-on - │ │ │ ├── columns: x:6 y:7 xyzw.z:8 xyzw.w:9 + │ │ │ ├── columns: x:6 y:7 z:8 w:9 │ │ │ ├── grouping columns: x:6 y:7 │ │ │ ├── project - │ │ │ │ ├── columns: x:6 y:7 xyzw.z:8 xyzw.w:9 + │ │ │ │ ├── columns: x:6 y:7 z:8 w:9 │ │ │ │ └── scan xyzw - │ │ │ │ └── columns: x:6 y:7 xyzw.z:8 xyzw.w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 + │ │ │ │ └── columns: x:6 y:7 z:8 w:9 rowid:10!null xyzw.crdb_internal_mvcc_timestamp:11 │ │ │ └── aggregations - │ │ │ ├── first-agg [as=xyzw.z:8] - │ │ │ │ └── xyzw.z:8 - │ │ │ └── first-agg [as=xyzw.w:9] - │ │ │ └── xyzw.w:9 + │ │ │ ├── first-agg [as=z:8] + │ │ │ │ └── z:8 + │ │ │ └── first-agg [as=w:9] + │ │ │ └── w:9 │ │ ├── scan self - │ │ │ └── columns: a:12!null self.b:13!null self.c:14 self.d:15 self.crdb_internal_mvcc_timestamp:16 + │ │ │ └── columns: self.a:12!null self.b:13!null self.c:14 self.d:15 self.crdb_internal_mvcc_timestamp:16 │ │ └── filters - │ │ ├── x:6 = a:12 + │ │ ├── x:6 = self.a:12 │ │ └── y:7 = self.b:13 │ └── projections - │ ├── CASE WHEN a:12 IS NULL THEN x:6 ELSE a:12 END [as=upsert_a:17] - │ └── CASE WHEN a:12 IS NULL THEN y:7 ELSE self.b:13 END [as=upsert_b:18] + │ ├── CASE WHEN self.a:12 IS NULL THEN x:6 ELSE self.a:12 END [as=upsert_a:17] + │ └── CASE WHEN self.a:12 IS NULL THEN y:7 ELSE self.b:13 END [as=upsert_b:18] └── f-k-checks ├── f-k-checks-item: self(a,b) -> self(b,d) │ └── anti-join (hash) - │ ├── columns: upsert_a:19 upsert_b:20 + │ ├── columns: a:19 b:20 │ ├── with-scan &1 - │ │ ├── columns: upsert_a:19 upsert_b:20 + │ │ ├── columns: a:19 b:20 │ │ └── mapping: - │ │ ├── upsert_a:17 => upsert_a:19 - │ │ └── upsert_b:18 => upsert_b:20 + │ │ ├── upsert_a:17 => a:19 + │ │ └── upsert_b:18 => b:20 │ ├── scan self │ │ └── columns: self.b:22!null self.d:24 │ └── filters - │ ├── upsert_a:19 = self.b:22 - │ └── upsert_b:20 = self.d:24 + │ ├── a:19 = self.b:22 + │ └── b:20 = self.d:24 ├── f-k-checks-item: self(d) -> self(c) │ └── anti-join (hash) - │ ├── columns: w:26!null + │ ├── columns: d:26!null │ ├── select - │ │ ├── columns: w:26!null + │ │ ├── columns: d:26!null │ │ ├── with-scan &1 - │ │ │ ├── columns: w:26 + │ │ │ ├── columns: d:26 │ │ │ └── mapping: - │ │ │ └── xyzw.w:9 => w:26 + │ │ │ └── w:9 => d:26 │ │ └── filters - │ │ └── w:26 IS NOT NULL + │ │ └── d:26 IS NOT NULL │ ├── scan self │ │ └── columns: self.c:29 │ └── filters - │ └── w:26 = self.c:29 + │ └── d:26 = self.c:29 ├── f-k-checks-item: self(a,b) -> self(b,d) │ └── semi-join (hash) │ ├── columns: b:32 d:33 │ ├── except │ │ ├── columns: b:32 d:33 │ │ ├── left columns: b:32 d:33 - │ │ ├── right columns: upsert_b:34 w:35 + │ │ ├── right columns: b:34 d:35 │ │ ├── with-scan &1 │ │ │ ├── columns: b:32 d:33 │ │ │ └── mapping: │ │ │ ├── self.b:13 => b:32 │ │ │ └── self.d:15 => d:33 │ │ └── with-scan &1 - │ │ ├── columns: upsert_b:34 w:35 + │ │ ├── columns: b:34 d:35 │ │ └── mapping: - │ │ ├── upsert_b:18 => upsert_b:34 - │ │ └── xyzw.w:9 => w:35 + │ │ ├── upsert_b:18 => b:34 + │ │ └── w:9 => d:35 │ ├── scan self - │ │ └── columns: a:36!null self.b:37!null + │ │ └── columns: self.a:36!null self.b:37!null │ └── filters - │ ├── b:32 = a:36 + │ ├── b:32 = self.a:36 │ └── d:33 = self.b:37 └── f-k-checks-item: self(d) -> self(c) └── semi-join (hash) @@ -2321,15 +2321,15 @@ upsert self ├── except │ ├── columns: c:41 │ ├── left columns: c:41 - │ ├── right columns: z:42 + │ ├── right columns: c:42 │ ├── with-scan &1 │ │ ├── columns: c:41 │ │ └── mapping: │ │ └── self.c:14 => c:41 │ └── with-scan &1 - │ ├── columns: z:42 + │ ├── columns: c:42 │ └── mapping: - │ └── xyzw.z:8 => z:42 + │ └── z:8 => c:42 ├── scan self │ └── columns: self.d:46 └── filters diff --git a/pkg/sql/opt/optbuilder/testdata/fk-on-delete-set-default b/pkg/sql/opt/optbuilder/testdata/fk-on-delete-set-default index ca79a3e07e8a..799d3cf7816c 100644 --- a/pkg/sql/opt/optbuilder/testdata/fk-on-delete-set-default +++ b/pkg/sql/opt/optbuilder/testdata/fk-on-delete-set-default @@ -46,15 +46,15 @@ root └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:13!null + ├── columns: p:13!null ├── with-scan &2 - │ ├── columns: p_new:13!null + │ ├── columns: p:13!null │ └── mapping: - │ └── p_new:12 => p_new:13 + │ └── p_new:12 => p:13 ├── scan parent │ └── columns: parent.p:14!null └── filters - └── p_new:13 = parent.p:14 + └── p:13 = parent.p:14 exec-ddl DROP TABLE child @@ -141,24 +141,24 @@ root └── cascade └── update child_multicol ├── columns: - ├── fetch columns: child_multicol.c:15 child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 + ├── fetch columns: c:15 child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 ├── update-mapping: - │ ├── child_multicol.c:15 => child_multicol.p:10 + │ ├── c:15 => child_multicol.p:10 │ ├── q_new:24 => child_multicol.q:11 │ ├── r_new:25 => child_multicol.r:12 │ └── column26:26 => x:13 ├── check columns: check1:27 ├── input binding: &2 ├── project - │ ├── columns: check1:27!null child_multicol.c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 q_new:24 r_new:25 column26:26 + │ ├── columns: check1:27!null c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 q_new:24 r_new:25 column26:26 │ ├── project - │ │ ├── columns: column26:26 child_multicol.c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 q_new:24 r_new:25 + │ │ ├── columns: column26:26 c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 q_new:24 r_new:25 │ │ ├── project - │ │ │ ├── columns: q_new:24 r_new:25 child_multicol.c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 + │ │ │ ├── columns: q_new:24 r_new:25 c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 │ │ │ ├── semi-join (hash) - │ │ │ │ ├── columns: child_multicol.c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 + │ │ │ │ ├── columns: c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 │ │ │ │ ├── scan child_multicol - │ │ │ │ │ ├── columns: child_multicol.c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 + │ │ │ │ │ ├── columns: c:15!null child_multicol.p:16 child_multicol.q:17 child_multicol.r:18 x:19 │ │ │ │ │ └── computed column expressions │ │ │ │ │ └── x:19 │ │ │ │ │ └── (child_multicol.p:16 + child_multicol.q:17) + child_multicol.r:18 @@ -176,30 +176,30 @@ root │ │ │ ├── child_multicol.p:16 + 1 [as=q_new:24] │ │ │ └── child_multicol.p:16 + child_multicol.q:17 [as=r_new:25] │ │ └── projections - │ │ └── (child_multicol.c:15 + q_new:24) + r_new:25 [as=column26:26] + │ │ └── (c:15 + q_new:24) + r_new:25 [as=column26:26] │ └── projections - │ └── (child_multicol.c:15 > 100) OR (child_multicol.c:15 > child_multicol.c:15) [as=check1:27] + │ └── (c:15 > 100) OR (c:15 > c:15) [as=check1:27] └── f-k-checks └── f-k-checks-item: child_multicol(p,q,r) -> parent_multicol(p,q,r) └── anti-join (hash) - ├── columns: c:28!null q_new:29!null r_new:30!null + ├── columns: p:28!null q:29!null r:30!null ├── select - │ ├── columns: c:28!null q_new:29!null r_new:30!null + │ ├── columns: p:28!null q:29!null r:30!null │ ├── with-scan &2 - │ │ ├── columns: c:28!null q_new:29 r_new:30 + │ │ ├── columns: p:28!null q:29 r:30 │ │ └── mapping: - │ │ ├── child_multicol.c:15 => c:28 - │ │ ├── q_new:24 => q_new:29 - │ │ └── r_new:25 => r_new:30 + │ │ ├── c:15 => p:28 + │ │ ├── q_new:24 => q:29 + │ │ └── r_new:25 => r:30 │ └── filters - │ ├── q_new:29 IS NOT NULL - │ └── r_new:30 IS NOT NULL + │ ├── q:29 IS NOT NULL + │ └── r:30 IS NOT NULL ├── scan parent_multicol │ └── columns: parent_multicol.p:31!null parent_multicol.q:32!null parent_multicol.r:33!null └── filters - ├── c:28 = parent_multicol.p:31 - ├── q_new:29 = parent_multicol.q:32 - └── r_new:30 = parent_multicol.r:33 + ├── p:28 = parent_multicol.p:31 + ├── q:29 = parent_multicol.q:32 + └── r:30 = parent_multicol.r:33 # Test a cascade to a child with a partial index. exec-ddl @@ -269,12 +269,12 @@ root └── f-k-checks └── f-k-checks-item: child_partial(p) -> parent_partial(p) └── anti-join (hash) - ├── columns: p_new:18!null + ├── columns: p:18!null ├── with-scan &2 - │ ├── columns: p_new:18!null + │ ├── columns: p:18!null │ └── mapping: - │ └── p_new:14 => p_new:18 + │ └── p_new:14 => p:18 ├── scan parent_partial │ └── columns: parent_partial.p:19!null └── filters - └── p_new:18 = parent_partial.p:19 + └── p:18 = parent_partial.p:19 diff --git a/pkg/sql/opt/optbuilder/testdata/fk-on-update-cascade b/pkg/sql/opt/optbuilder/testdata/fk-on-update-cascade index 33cebdf137fc..c86f6afc65f9 100644 --- a/pkg/sql/opt/optbuilder/testdata/fk-on-update-cascade +++ b/pkg/sql/opt/optbuilder/testdata/fk-on-update-cascade @@ -53,15 +53,15 @@ root └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:14!null + ├── columns: p:14!null ├── with-scan &2 - │ ├── columns: p_new:14!null + │ ├── columns: p:14!null │ └── mapping: - │ └── p_new:13 => p_new:14 + │ └── p_new:13 => p:14 ├── scan parent │ └── columns: parent.p:15!null └── filters - └── p_new:14 = parent.p:15 + └── p:14 = parent.p:15 exec-ddl CREATE TABLE parent_multi ( @@ -136,22 +136,22 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: p_new:23!null q_new:24!null + ├── columns: p:23!null q:24!null ├── select - │ ├── columns: p_new:23!null q_new:24!null + │ ├── columns: p:23!null q:24!null │ ├── with-scan &2 - │ │ ├── columns: p_new:23 q_new:24 + │ │ ├── columns: p:23 q:24 │ │ └── mapping: - │ │ ├── p_new:21 => p_new:23 - │ │ └── q_new:22 => q_new:24 + │ │ ├── p_new:21 => p:23 + │ │ └── q_new:22 => q:24 │ └── filters - │ ├── p_new:23 IS NOT NULL - │ └── q_new:24 IS NOT NULL + │ ├── p:23 IS NOT NULL + │ └── q:24 IS NOT NULL ├── scan parent_multi │ └── columns: parent_multi.p:26 parent_multi.q:27 └── filters - ├── p_new:23 = parent_multi.p:26 - └── q_new:24 = parent_multi.q:27 + ├── p:23 = parent_multi.p:26 + └── q:24 = parent_multi.q:27 # Update only one of the two FK columns. The "before" and "after" values of q # come from the same column in the mutation input. @@ -206,20 +206,20 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: p_new:22!null q:23!null + ├── columns: p:22!null q:23!null ├── select - │ ├── columns: p_new:22!null q:23!null + │ ├── columns: p:22!null q:23!null │ ├── with-scan &2 - │ │ ├── columns: p_new:22!null q:23 + │ │ ├── columns: p:22!null q:23 │ │ └── mapping: - │ │ ├── p_new:20 => p_new:22 + │ │ ├── p_new:20 => p:22 │ │ └── q:21 => q:23 │ └── filters │ └── q:23 IS NOT NULL ├── scan parent_multi │ └── columns: parent_multi.p:25 parent_multi.q:26 └── filters - ├── p_new:22 = parent_multi.p:25 + ├── p:22 = parent_multi.p:25 └── q:23 = parent_multi.q:26 build-cascades @@ -292,17 +292,17 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: column2:25!null column3:26!null + ├── columns: p:25!null q:26!null ├── with-scan &2 - │ ├── columns: column2:25!null column3:26!null + │ ├── columns: p:25!null q:26!null │ └── mapping: - │ ├── column2:23 => column2:25 - │ └── column3:24 => column3:26 + │ ├── column2:23 => p:25 + │ └── column3:24 => q:26 ├── scan parent_multi │ └── columns: parent_multi.p:28 parent_multi.q:29 └── filters - ├── column2:25 = parent_multi.p:28 - └── column3:26 = parent_multi.q:29 + ├── p:25 = parent_multi.p:28 + └── q:26 = parent_multi.q:29 # Upsert that only touches one of the FK columns. build-cascades @@ -379,20 +379,20 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: column2:26!null q:27!null + ├── columns: p:26!null q:27!null ├── select - │ ├── columns: column2:26!null q:27!null + │ ├── columns: p:26!null q:27!null │ ├── with-scan &2 - │ │ ├── columns: column2:26!null q:27 + │ │ ├── columns: p:26!null q:27 │ │ └── mapping: - │ │ ├── column2:24 => column2:26 + │ │ ├── column2:24 => p:26 │ │ └── q:25 => q:27 │ └── filters │ └── q:27 IS NOT NULL ├── scan parent_multi │ └── columns: parent_multi.p:29 parent_multi.q:30 └── filters - ├── column2:26 = parent_multi.p:29 + ├── p:26 = parent_multi.p:29 └── q:27 = parent_multi.q:30 build-cascades @@ -469,20 +469,20 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: upsert_p:28!null q:29!null + ├── columns: p:28!null q:29!null ├── select - │ ├── columns: upsert_p:28!null q:29!null + │ ├── columns: p:28!null q:29!null │ ├── with-scan &2 - │ │ ├── columns: upsert_p:28!null q:29 + │ │ ├── columns: p:28!null q:29 │ │ └── mapping: - │ │ ├── upsert_p:26 => upsert_p:28 + │ │ ├── upsert_p:26 => p:28 │ │ └── q:27 => q:29 │ └── filters │ └── q:29 IS NOT NULL ├── scan parent_multi │ └── columns: parent_multi.p:31 parent_multi.q:32 └── filters - ├── upsert_p:28 = parent_multi.p:31 + ├── p:28 = parent_multi.p:31 └── q:29 = parent_multi.q:32 # Test a two-level cascade. @@ -547,21 +547,21 @@ root │ └── f-k-checks │ └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) │ └── anti-join (hash) - │ ├── columns: p:22!null q_new:23!null + │ ├── columns: p:22!null q:23!null │ ├── select - │ │ ├── columns: p:22!null q_new:23!null + │ │ ├── columns: p:22!null q:23!null │ │ ├── with-scan &2 - │ │ │ ├── columns: p:22!null q_new:23 + │ │ │ ├── columns: p:22!null q:23 │ │ │ └── mapping: │ │ │ ├── p:20 => p:22 - │ │ │ └── q_new:21 => q_new:23 + │ │ │ └── q_new:21 => q:23 │ │ └── filters - │ │ └── q_new:23 IS NOT NULL + │ │ └── q:23 IS NOT NULL │ ├── scan parent_multi │ │ └── columns: parent_multi.p:25 parent_multi.q:26 │ └── filters │ ├── p:22 = parent_multi.p:25 - │ └── q_new:23 = parent_multi.q:26 + │ └── q:23 = parent_multi.q:26 └── cascade └── update grandchild ├── columns: @@ -591,21 +591,21 @@ root └── f-k-checks └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q) └── anti-join (hash) - ├── columns: c:40!null q_new:41!null + ├── columns: c:40!null q:41!null ├── select - │ ├── columns: c:40!null q_new:41!null + │ ├── columns: c:40!null q:41!null │ ├── with-scan &3 - │ │ ├── columns: c:40!null q_new:41 + │ │ ├── columns: c:40!null q:41 │ │ └── mapping: │ │ ├── c:38 => c:40 - │ │ └── q_new:39 => q_new:41 + │ │ └── q_new:39 => q:41 │ └── filters - │ └── q_new:41 IS NOT NULL + │ └── q:41 IS NOT NULL ├── scan child_multi │ └── columns: child_multi.c:42!null child_multi.q:44 └── filters ├── c:40 = child_multi.c:42 - └── q_new:41 = child_multi.q:44 + └── q:41 = child_multi.q:44 build-cascades UPSERT INTO parent_multi VALUES (1, 10, 10), (2, 20, 20) @@ -679,17 +679,17 @@ root │ └── f-k-checks │ └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) │ └── anti-join (hash) - │ ├── columns: column2:25!null column3:26!null + │ ├── columns: p:25!null q:26!null │ ├── with-scan &2 - │ │ ├── columns: column2:25!null column3:26!null + │ │ ├── columns: p:25!null q:26!null │ │ └── mapping: - │ │ ├── column2:23 => column2:25 - │ │ └── column3:24 => column3:26 + │ │ ├── column2:23 => p:25 + │ │ └── column3:24 => q:26 │ ├── scan parent_multi │ │ └── columns: parent_multi.p:28 parent_multi.q:29 │ └── filters - │ ├── column2:25 = parent_multi.p:28 - │ └── column3:26 = parent_multi.q:29 + │ ├── p:25 = parent_multi.p:28 + │ └── q:26 = parent_multi.q:29 └── cascade └── update grandchild ├── columns: @@ -719,17 +719,17 @@ root └── f-k-checks └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q) └── anti-join (hash) - ├── columns: c:43!null column3:44!null + ├── columns: c:43!null q:44!null ├── with-scan &3 - │ ├── columns: c:43!null column3:44!null + │ ├── columns: c:43!null q:44!null │ └── mapping: │ ├── c:41 => c:43 - │ └── column3:42 => column3:44 + │ └── column3:42 => q:44 ├── scan child_multi │ └── columns: child_multi.c:45!null child_multi.q:47 └── filters ├── c:43 = child_multi.c:45 - └── column3:44 = child_multi.q:47 + └── q:44 = child_multi.q:47 # Test a cascade to a child with a partial index. exec-ddl @@ -806,15 +806,15 @@ root └── f-k-checks └── f-k-checks-item: child_partial(p) -> parent_partial(p) └── anti-join (hash) - ├── columns: p_new:19!null + ├── columns: p:19!null ├── with-scan &2 - │ ├── columns: p_new:19!null + │ ├── columns: p:19!null │ └── mapping: - │ └── p_new:15 => p_new:19 + │ └── p_new:15 => p:19 ├── scan parent_partial │ └── columns: parent_partial.p:20!null └── filters - └── p_new:19 = parent_partial.p:20 + └── p:19 = parent_partial.p:20 # Test a cascade to a child with a partial index with an ambiguous name. exec-ddl @@ -1006,22 +1006,22 @@ root └── f-k-checks └── f-k-checks-item: child_multi_partial(p,q) -> parent_multi_partial(p,q) └── anti-join (hash) - ├── columns: column6:29!null column6:30!null + ├── columns: p:29!null q:30!null ├── select - │ ├── columns: column6:29!null column6:30!null + │ ├── columns: p:29!null q:30!null │ ├── with-scan &2 - │ │ ├── columns: column6:29 column6:30 + │ │ ├── columns: p:29 q:30 │ │ └── mapping: - │ │ ├── column6:24 => column6:29 - │ │ └── column6:25 => column6:30 + │ │ ├── column6:24 => p:29 + │ │ └── column6:25 => q:30 │ └── filters - │ ├── column6:29 IS NOT NULL - │ └── column6:30 IS NOT NULL + │ ├── p:29 IS NOT NULL + │ └── q:30 IS NOT NULL ├── scan parent_multi_partial │ └── columns: parent_multi_partial.p:32 parent_multi_partial.q:33 └── filters - ├── column6:29 = parent_multi_partial.p:32 - └── column6:30 = parent_multi_partial.q:33 + ├── p:29 = parent_multi_partial.p:32 + └── q:30 = parent_multi_partial.q:33 # Regression test for #57148. A check constraint or computed column in a child # table that references a column with the same name as the parent's synthesized diff --git a/pkg/sql/opt/optbuilder/testdata/fk-on-update-set-default b/pkg/sql/opt/optbuilder/testdata/fk-on-update-set-default index 7d34595e9117..b660557207dc 100644 --- a/pkg/sql/opt/optbuilder/testdata/fk-on-update-set-default +++ b/pkg/sql/opt/optbuilder/testdata/fk-on-update-set-default @@ -57,15 +57,15 @@ root └── f-k-checks └── f-k-checks-item: child(p) -> parent(p) └── anti-join (hash) - ├── columns: p_new:15!null + ├── columns: p:15!null ├── with-scan &2 - │ ├── columns: p_new:15!null + │ ├── columns: p:15!null │ └── mapping: - │ └── p_new:14 => p_new:15 + │ └── p_new:14 => p:15 ├── scan parent │ └── columns: parent.p:16!null └── filters - └── p_new:15 = parent.p:16 + └── p:15 = parent.p:16 exec-ddl CREATE TABLE parent_multi ( @@ -146,17 +146,17 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: p_new:25!null q_new:26!null + ├── columns: p:25!null q:26!null ├── with-scan &2 - │ ├── columns: p_new:25!null q_new:26!null + │ ├── columns: p:25!null q:26!null │ └── mapping: - │ ├── p_new:23 => p_new:25 - │ └── q_new:24 => q_new:26 + │ ├── p_new:23 => p:25 + │ └── q_new:24 => q:26 ├── scan parent_multi │ └── columns: parent_multi.p:28 parent_multi.q:29 └── filters - ├── p_new:25 = parent_multi.p:28 - └── q_new:26 = parent_multi.q:29 + ├── p:25 = parent_multi.p:28 + └── q:26 = parent_multi.q:29 # Update only one of the two FK columns. The "before" and "after" values of q # come from the same column in the mutation input. @@ -216,17 +216,17 @@ root └── f-k-checks └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) └── anti-join (hash) - ├── columns: p_new:24!null q_new:25!null + ├── columns: p:24!null q:25!null ├── with-scan &2 - │ ├── columns: p_new:24!null q_new:25!null + │ ├── columns: p:24!null q:25!null │ └── mapping: - │ ├── p_new:22 => p_new:24 - │ └── q_new:23 => q_new:25 + │ ├── p_new:22 => p:24 + │ └── q_new:23 => q:25 ├── scan parent_multi │ └── columns: parent_multi.p:27 parent_multi.q:28 └── filters - ├── p_new:24 = parent_multi.p:27 - └── q_new:25 = parent_multi.q:28 + ├── p:24 = parent_multi.p:27 + └── q:25 = parent_multi.q:28 # Test a two-level cascade. exec-ddl @@ -295,17 +295,17 @@ root │ └── f-k-checks │ └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) │ └── anti-join (hash) - │ ├── columns: p_new:24!null q_new:25!null + │ ├── columns: p:24!null q:25!null │ ├── with-scan &2 - │ │ ├── columns: p_new:24!null q_new:25!null + │ │ ├── columns: p:24!null q:25!null │ │ └── mapping: - │ │ ├── p_new:22 => p_new:24 - │ │ └── q_new:23 => q_new:25 + │ │ ├── p_new:22 => p:24 + │ │ └── q_new:23 => q:25 │ ├── scan parent_multi │ │ └── columns: parent_multi.p:27 parent_multi.q:28 │ └── filters - │ ├── p_new:24 = parent_multi.p:27 - │ └── q_new:25 = parent_multi.q:28 + │ ├── p:24 = parent_multi.p:27 + │ └── q:25 = parent_multi.q:28 └── cascade └── update grandchild ├── columns: @@ -340,17 +340,17 @@ root └── f-k-checks └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q) └── anti-join (hash) - ├── columns: c_new:44!null q_new:45!null + ├── columns: c:44!null q:45!null ├── with-scan &3 - │ ├── columns: c_new:44!null q_new:45!null + │ ├── columns: c:44!null q:45!null │ └── mapping: - │ ├── c_new:42 => c_new:44 - │ └── q_new:43 => q_new:45 + │ ├── c_new:42 => c:44 + │ └── q_new:43 => q:45 ├── scan child_multi │ └── columns: child_multi.c:46!null child_multi.q:48 └── filters - ├── c_new:44 = child_multi.c:46 - └── q_new:45 = child_multi.q:48 + ├── c:44 = child_multi.c:46 + └── q:45 = child_multi.q:48 build-cascades UPSERT INTO parent_multi VALUES (1, 10, 10), (2, 20, 20) @@ -429,17 +429,17 @@ root │ └── f-k-checks │ └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) │ └── anti-join (hash) - │ ├── columns: p_new:27!null q_new:28!null + │ ├── columns: p:27!null q:28!null │ ├── with-scan &2 - │ │ ├── columns: p_new:27!null q_new:28!null + │ │ ├── columns: p:27!null q:28!null │ │ └── mapping: - │ │ ├── p_new:25 => p_new:27 - │ │ └── q_new:26 => q_new:28 + │ │ ├── p_new:25 => p:27 + │ │ └── q_new:26 => q:28 │ ├── scan parent_multi │ │ └── columns: parent_multi.p:30 parent_multi.q:31 │ └── filters - │ ├── p_new:27 = parent_multi.p:30 - │ └── q_new:28 = parent_multi.q:31 + │ ├── p:27 = parent_multi.p:30 + │ └── q:28 = parent_multi.q:31 └── cascade └── update grandchild ├── columns: @@ -474,17 +474,17 @@ root └── f-k-checks └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q) └── anti-join (hash) - ├── columns: c_new:47!null q_new:48!null + ├── columns: c:47!null q:48!null ├── with-scan &3 - │ ├── columns: c_new:47!null q_new:48!null + │ ├── columns: c:47!null q:48!null │ └── mapping: - │ ├── c_new:45 => c_new:47 - │ └── q_new:46 => q_new:48 + │ ├── c_new:45 => c:47 + │ └── q_new:46 => q:48 ├── scan child_multi │ └── columns: child_multi.c:49!null child_multi.q:51 └── filters - ├── c_new:47 = child_multi.c:49 - └── q_new:48 = child_multi.q:51 + ├── c:47 = child_multi.c:49 + └── q:48 = child_multi.q:51 # Upsert that only touches one of the FK columns. build-cascades @@ -568,17 +568,17 @@ root │ └── f-k-checks │ └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) │ └── anti-join (hash) - │ ├── columns: p_new:28!null q_new:29!null + │ ├── columns: p:28!null q:29!null │ ├── with-scan &2 - │ │ ├── columns: p_new:28!null q_new:29!null + │ │ ├── columns: p:28!null q:29!null │ │ └── mapping: - │ │ ├── p_new:26 => p_new:28 - │ │ └── q_new:27 => q_new:29 + │ │ ├── p_new:26 => p:28 + │ │ └── q_new:27 => q:29 │ ├── scan parent_multi │ │ └── columns: parent_multi.p:31 parent_multi.q:32 │ └── filters - │ ├── p_new:28 = parent_multi.p:31 - │ └── q_new:29 = parent_multi.q:32 + │ ├── p:28 = parent_multi.p:31 + │ └── q:29 = parent_multi.q:32 └── cascade └── update grandchild ├── columns: @@ -613,17 +613,17 @@ root └── f-k-checks └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q) └── anti-join (hash) - ├── columns: c_new:48!null q_new:49!null + ├── columns: c:48!null q:49!null ├── with-scan &3 - │ ├── columns: c_new:48!null q_new:49!null + │ ├── columns: c:48!null q:49!null │ └── mapping: - │ ├── c_new:46 => c_new:48 - │ └── q_new:47 => q_new:49 + │ ├── c_new:46 => c:48 + │ └── q_new:47 => q:49 ├── scan child_multi │ └── columns: child_multi.c:50!null child_multi.q:52 └── filters - ├── c_new:48 = child_multi.c:50 - └── q_new:49 = child_multi.q:52 + ├── c:48 = child_multi.c:50 + └── q:49 = child_multi.q:52 build-cascades INSERT INTO parent_multi VALUES (1, 10, 10), (2, 20, 20) ON CONFLICT (p,q) DO UPDATE SET p = 100 @@ -706,17 +706,17 @@ root │ └── f-k-checks │ └── f-k-checks-item: child_multi(p,q) -> parent_multi(p,q) │ └── anti-join (hash) - │ ├── columns: p_new:30!null q_new:31!null + │ ├── columns: p:30!null q:31!null │ ├── with-scan &2 - │ │ ├── columns: p_new:30!null q_new:31!null + │ │ ├── columns: p:30!null q:31!null │ │ └── mapping: - │ │ ├── p_new:28 => p_new:30 - │ │ └── q_new:29 => q_new:31 + │ │ ├── p_new:28 => p:30 + │ │ └── q_new:29 => q:31 │ ├── scan parent_multi │ │ └── columns: parent_multi.p:33 parent_multi.q:34 │ └── filters - │ ├── p_new:30 = parent_multi.p:33 - │ └── q_new:31 = parent_multi.q:34 + │ ├── p:30 = parent_multi.p:33 + │ └── q:31 = parent_multi.q:34 └── cascade └── update grandchild ├── columns: @@ -751,17 +751,17 @@ root └── f-k-checks └── f-k-checks-item: grandchild(c,q) -> child_multi(c,q) └── anti-join (hash) - ├── columns: c_new:50!null q_new:51!null + ├── columns: c:50!null q:51!null ├── with-scan &3 - │ ├── columns: c_new:50!null q_new:51!null + │ ├── columns: c:50!null q:51!null │ └── mapping: - │ ├── c_new:48 => c_new:50 - │ └── q_new:49 => q_new:51 + │ ├── c_new:48 => c:50 + │ └── q_new:49 => q:51 ├── scan child_multi │ └── columns: child_multi.c:52!null child_multi.q:54 └── filters - ├── c_new:50 = child_multi.c:52 - └── q_new:51 = child_multi.q:54 + ├── c:50 = child_multi.c:52 + └── q:51 = child_multi.q:54 # Test a cascade to a child with a partial index. exec-ddl @@ -842,12 +842,12 @@ root └── f-k-checks └── f-k-checks-item: child_partial(p) -> parent_partial(p) └── anti-join (hash) - ├── columns: p_new:20!null + ├── columns: p:20!null ├── with-scan &2 - │ ├── columns: p_new:20!null + │ ├── columns: p:20!null │ └── mapping: - │ └── p_new:16 => p_new:20 + │ └── p_new:16 => p:20 ├── scan parent_partial │ └── columns: parent_partial.p:21!null └── filters - └── p_new:20 = parent_partial.p:21 + └── p:20 = parent_partial.p:21 diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-insert b/pkg/sql/opt/optbuilder/testdata/unique-checks-insert index 876623dcd9ba..0c2f6c71f29b 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-insert +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-insert @@ -16,11 +16,11 @@ INSERT INTO uniq VALUES (1, 1, 1, 1, 1), (2, 2, 2, 2, 2) insert uniq ├── columns: ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── values │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null @@ -29,32 +29,32 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column3:12!null column1:13!null + │ ├── columns: w:12!null k:13!null │ ├── with-scan &1 - │ │ ├── columns: column3:12!null column1:13!null + │ │ ├── columns: w:12!null k:13!null │ │ └── mapping: - │ │ ├── column3:9 => column3:12 - │ │ └── column1:7 => column1:13 + │ │ ├── column3:9 => w:12 + │ │ └── column1:7 => k:13 │ ├── scan uniq - │ │ └── columns: k:14!null w:16 + │ │ └── columns: uniq.k:14!null uniq.w:16 │ └── filters - │ ├── column3:12 = w:16 - │ └── column1:13 != k:14 + │ ├── w:12 = uniq.w:16 + │ └── k:13 != uniq.k:14 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column4:20!null column5:21!null column1:22!null + ├── columns: x:20!null y:21!null k:22!null ├── with-scan &1 - │ ├── columns: column4:20!null column5:21!null column1:22!null + │ ├── columns: x:20!null y:21!null k:22!null │ └── mapping: - │ ├── column4:10 => column4:20 - │ ├── column5:11 => column5:21 - │ └── column1:7 => column1:22 + │ ├── column4:10 => x:20 + │ ├── column5:11 => y:21 + │ └── column1:7 => k:22 ├── scan uniq - │ └── columns: k:23!null x:26 y:27 + │ └── columns: uniq.k:23!null uniq.x:26 uniq.y:27 └── filters - ├── column4:20 = x:26 - ├── column5:21 = y:27 - └── column1:22 != k:23 + ├── x:20 = uniq.x:26 + ├── y:21 = uniq.y:27 + └── k:22 != uniq.k:23 # Some of the inserted values have nulls. build @@ -63,11 +63,11 @@ INSERT INTO uniq VALUES (1, 1, 1, 1, 1), (2, 2, 2, 2, 2), (3, NULL, NULL, NULL, insert uniq ├── columns: ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── values │ ├── columns: column1:7!null column2:8 column3:9 column4:10 column5:11!null @@ -77,32 +77,32 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column3:12 column1:13!null + │ ├── columns: w:12 k:13!null │ ├── with-scan &1 - │ │ ├── columns: column3:12 column1:13!null + │ │ ├── columns: w:12 k:13!null │ │ └── mapping: - │ │ ├── column3:9 => column3:12 - │ │ └── column1:7 => column1:13 + │ │ ├── column3:9 => w:12 + │ │ └── column1:7 => k:13 │ ├── scan uniq - │ │ └── columns: k:14!null w:16 + │ │ └── columns: uniq.k:14!null uniq.w:16 │ └── filters - │ ├── column3:12 = w:16 - │ └── column1:13 != k:14 + │ ├── w:12 = uniq.w:16 + │ └── k:13 != uniq.k:14 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column4:20 column5:21!null column1:22!null + ├── columns: x:20 y:21!null k:22!null ├── with-scan &1 - │ ├── columns: column4:20 column5:21!null column1:22!null + │ ├── columns: x:20 y:21!null k:22!null │ └── mapping: - │ ├── column4:10 => column4:20 - │ ├── column5:11 => column5:21 - │ └── column1:7 => column1:22 + │ ├── column4:10 => x:20 + │ ├── column5:11 => y:21 + │ └── column1:7 => k:22 ├── scan uniq - │ └── columns: k:23!null x:26 y:27 + │ └── columns: uniq.k:23!null uniq.x:26 uniq.y:27 └── filters - ├── column4:20 = x:26 - ├── column5:21 = y:27 - └── column1:22 != k:23 + ├── x:20 = uniq.x:26 + ├── y:21 = uniq.y:27 + └── k:22 != uniq.k:23 # No need to plan checks for w since it's aways null. build @@ -111,11 +111,11 @@ INSERT INTO uniq VALUES (1, 1, NULL, 1, 1), (2, 2, NULL, 2, 2) insert uniq ├── columns: ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── values │ ├── columns: column1:7!null column2:8!null column3:9 column4:10!null column5:11!null @@ -124,19 +124,19 @@ insert uniq └── unique-checks └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column4:12!null column5:13!null column1:14!null + ├── columns: x:12!null y:13!null k:14!null ├── with-scan &1 - │ ├── columns: column4:12!null column5:13!null column1:14!null + │ ├── columns: x:12!null y:13!null k:14!null │ └── mapping: - │ ├── column4:10 => column4:12 - │ ├── column5:11 => column5:13 - │ └── column1:7 => column1:14 + │ ├── column4:10 => x:12 + │ ├── column5:11 => y:13 + │ └── column1:7 => k:14 ├── scan uniq - │ └── columns: k:15!null x:18 y:19 + │ └── columns: uniq.k:15!null uniq.x:18 uniq.y:19 └── filters - ├── column4:12 = x:18 - ├── column5:13 = y:19 - └── column1:14 != k:15 + ├── x:12 = uniq.x:18 + ├── y:13 = uniq.y:19 + └── k:14 != uniq.k:15 # No need to plan checks for x,y since x is aways null. build @@ -145,9 +145,9 @@ INSERT INTO uniq VALUES (1, 1, 1, NULL, 1), (2, 2, NULL, NULL, 2) insert uniq ├── columns: ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 + │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => x:4 │ └── column5:11 => y:5 ├── input binding: &1 @@ -158,17 +158,17 @@ insert uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: column3:12 column1:13!null + ├── columns: w:12 k:13!null ├── with-scan &1 - │ ├── columns: column3:12 column1:13!null + │ ├── columns: w:12 k:13!null │ └── mapping: - │ ├── column3:9 => column3:12 - │ └── column1:7 => column1:13 + │ ├── column3:9 => w:12 + │ └── column1:7 => k:13 ├── scan uniq - │ └── columns: k:14!null w:16 + │ └── columns: uniq.k:14!null uniq.w:16 └── filters - ├── column3:12 = w:16 - └── column1:13 != k:14 + ├── w:12 = uniq.w:16 + └── k:13 != uniq.k:14 # No need to plan checks for x,y since y is aways null. build @@ -177,9 +177,9 @@ INSERT INTO uniq VALUES (1, 1, 1, 1, NULL), (2, 2, 2, 2, NULL) insert uniq ├── columns: ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 + │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => x:4 │ └── column5:11 => y:5 ├── input binding: &1 @@ -190,17 +190,17 @@ insert uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: column3:12!null column1:13!null + ├── columns: w:12!null k:13!null ├── with-scan &1 - │ ├── columns: column3:12!null column1:13!null + │ ├── columns: w:12!null k:13!null │ └── mapping: - │ ├── column3:9 => column3:12 - │ └── column1:7 => column1:13 + │ ├── column3:9 => w:12 + │ └── column1:7 => k:13 ├── scan uniq - │ └── columns: k:14!null w:16 + │ └── columns: uniq.k:14!null uniq.w:16 └── filters - ├── column3:12 = w:16 - └── column1:13 != k:14 + ├── w:12 = uniq.w:16 + └── k:13 != uniq.k:14 # No need to plan any checks, since w, x and y are aways null. build @@ -231,11 +231,11 @@ insert uniq ├── arbiter indexes: primary uniq_v_key ├── arbiter constraints: unique_w unique_x_y ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── upsert-distinct-on │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null @@ -261,22 +261,22 @@ insert uniq │ │ │ │ │ │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ │ │ │ │ │ │ └── (1, 2, 3, 4, 5) │ │ │ │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 + │ │ │ │ │ │ │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 │ │ │ │ │ │ │ │ └── filters - │ │ │ │ │ │ │ │ └── column1:7 = k:12 + │ │ │ │ │ │ │ │ └── column1:7 = uniq.k:12 │ │ │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ │ │ └── columns: k:18!null v:19 w:20 x:21 y:22 + │ │ │ │ │ │ │ │ └── columns: uniq.k:18!null v:19 uniq.w:20 uniq.x:21 uniq.y:22 │ │ │ │ │ │ │ └── filters │ │ │ │ │ │ │ └── column2:8 = v:19 │ │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ │ └── columns: k:24!null v:25 w:26 x:27 y:28 + │ │ │ │ │ │ │ └── columns: uniq.k:24!null v:25 uniq.w:26 uniq.x:27 uniq.y:28 │ │ │ │ │ │ └── filters - │ │ │ │ │ │ └── column3:9 = w:26 + │ │ │ │ │ │ └── column3:9 = uniq.w:26 │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ └── columns: k:30!null v:31 w:32 x:33 y:34 + │ │ │ │ │ │ └── columns: uniq.k:30!null v:31 uniq.w:32 uniq.x:33 uniq.y:34 │ │ │ │ │ └── filters - │ │ │ │ │ ├── column4:10 = x:33 - │ │ │ │ │ └── column5:11 = y:34 + │ │ │ │ │ ├── column4:10 = uniq.x:33 + │ │ │ │ │ └── column5:11 = uniq.y:34 │ │ │ │ └── aggregations │ │ │ │ ├── first-agg [as=column2:8] │ │ │ │ │ └── column2:8 @@ -314,32 +314,32 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column3:36!null column1:37!null + │ ├── columns: w:36!null k:37!null │ ├── with-scan &1 - │ │ ├── columns: column3:36!null column1:37!null + │ │ ├── columns: w:36!null k:37!null │ │ └── mapping: - │ │ ├── column3:9 => column3:36 - │ │ └── column1:7 => column1:37 + │ │ ├── column3:9 => w:36 + │ │ └── column1:7 => k:37 │ ├── scan uniq - │ │ └── columns: k:38!null w:40 + │ │ └── columns: uniq.k:38!null uniq.w:40 │ └── filters - │ ├── column3:36 = w:40 - │ └── column1:37 != k:38 + │ ├── w:36 = uniq.w:40 + │ └── k:37 != uniq.k:38 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column4:44!null column5:45!null column1:46!null + ├── columns: x:44!null y:45!null k:46!null ├── with-scan &1 - │ ├── columns: column4:44!null column5:45!null column1:46!null + │ ├── columns: x:44!null y:45!null k:46!null │ └── mapping: - │ ├── column4:10 => column4:44 - │ ├── column5:11 => column5:45 - │ └── column1:7 => column1:46 + │ ├── column4:10 => x:44 + │ ├── column5:11 => y:45 + │ └── column1:7 => k:46 ├── scan uniq - │ └── columns: k:47!null x:50 y:51 + │ └── columns: uniq.k:47!null uniq.x:50 uniq.y:51 └── filters - ├── column4:44 = x:50 - ├── column5:45 = y:51 - └── column1:46 != k:47 + ├── x:44 = uniq.x:50 + ├── y:45 = uniq.y:51 + └── k:46 != uniq.k:47 # On conflict clause references unique without index constraint. # TODO(rytaft): we should be able to remove the unique check for w in this case @@ -351,11 +351,11 @@ insert uniq ├── columns: ├── arbiter constraints: unique_w ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── upsert-distinct-on │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null @@ -366,9 +366,9 @@ insert uniq │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ └── (1, 2, 3, 4, 5) │ │ ├── scan uniq - │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 + │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 │ │ └── filters - │ │ └── column3:9 = w:14 + │ │ └── column3:9 = uniq.w:14 │ └── aggregations │ ├── first-agg [as=column1:7] │ │ └── column1:7 @@ -381,32 +381,32 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column3:18!null column1:19!null + │ ├── columns: w:18!null k:19!null │ ├── with-scan &1 - │ │ ├── columns: column3:18!null column1:19!null + │ │ ├── columns: w:18!null k:19!null │ │ └── mapping: - │ │ ├── column3:9 => column3:18 - │ │ └── column1:7 => column1:19 + │ │ ├── column3:9 => w:18 + │ │ └── column1:7 => k:19 │ ├── scan uniq - │ │ └── columns: k:20!null w:22 + │ │ └── columns: uniq.k:20!null uniq.w:22 │ └── filters - │ ├── column3:18 = w:22 - │ └── column1:19 != k:20 + │ ├── w:18 = uniq.w:22 + │ └── k:19 != uniq.k:20 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column4:26!null column5:27!null column1:28!null + ├── columns: x:26!null y:27!null k:28!null ├── with-scan &1 - │ ├── columns: column4:26!null column5:27!null column1:28!null + │ ├── columns: x:26!null y:27!null k:28!null │ └── mapping: - │ ├── column4:10 => column4:26 - │ ├── column5:11 => column5:27 - │ └── column1:7 => column1:28 + │ ├── column4:10 => x:26 + │ ├── column5:11 => y:27 + │ └── column1:7 => k:28 ├── scan uniq - │ └── columns: k:29!null x:32 y:33 + │ └── columns: uniq.k:29!null uniq.x:32 uniq.y:33 └── filters - ├── column4:26 = x:32 - ├── column5:27 = y:33 - └── column1:28 != k:29 + ├── x:26 = uniq.x:32 + ├── y:27 = uniq.y:33 + └── k:28 != uniq.k:29 exec-ddl CREATE TABLE other (k INT, v INT, w INT NOT NULL, x INT, y INT) @@ -482,10 +482,10 @@ INSERT INTO uniq_overlaps_pk VALUES (1, 1, 1, 1), (2, 2, 2, 2) insert uniq_overlaps_pk ├── columns: ├── insert-mapping: - │ ├── column1:6 => a:1 - │ ├── column2:7 => b:2 - │ ├── column3:8 => c:3 - │ └── column4:9 => d:4 + │ ├── column1:6 => uniq_overlaps_pk.a:1 + │ ├── column2:7 => uniq_overlaps_pk.b:2 + │ ├── column3:8 => uniq_overlaps_pk.c:3 + │ └── column4:9 => uniq_overlaps_pk.d:4 ├── input binding: &1 ├── values │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null @@ -494,48 +494,48 @@ insert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: column2:10!null column3:11!null column1:12!null + │ ├── columns: b:10!null c:11!null a:12!null │ ├── with-scan &1 - │ │ ├── columns: column2:10!null column3:11!null column1:12!null + │ │ ├── columns: b:10!null c:11!null a:12!null │ │ └── mapping: - │ │ ├── column2:7 => column2:10 - │ │ ├── column3:8 => column3:11 - │ │ └── column1:6 => column1:12 + │ │ ├── column2:7 => b:10 + │ │ ├── column3:8 => c:11 + │ │ └── column1:6 => a:12 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:13!null b:14!null c:15 + │ │ └── columns: uniq_overlaps_pk.a:13!null uniq_overlaps_pk.b:14!null uniq_overlaps_pk.c:15 │ └── filters - │ ├── column2:10 = b:14 - │ ├── column3:11 = c:15 - │ └── column1:12 != a:13 + │ ├── b:10 = uniq_overlaps_pk.b:14 + │ ├── c:11 = uniq_overlaps_pk.c:15 + │ └── a:12 != uniq_overlaps_pk.a:13 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: column1:18!null column2:19!null + │ ├── columns: a:18!null b:19!null │ ├── with-scan &1 - │ │ ├── columns: column1:18!null column2:19!null + │ │ ├── columns: a:18!null b:19!null │ │ └── mapping: - │ │ ├── column1:6 => column1:18 - │ │ └── column2:7 => column2:19 + │ │ ├── column1:6 => a:18 + │ │ └── column2:7 => b:19 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:20!null b:21!null + │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null │ └── filters - │ ├── column1:18 = a:20 - │ └── column2:19 != b:21 + │ ├── a:18 = uniq_overlaps_pk.a:20 + │ └── b:19 != uniq_overlaps_pk.b:21 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: column3:25!null column4:26!null column1:27!null column2:28!null + ├── columns: c:25!null d:26!null a:27!null b:28!null ├── with-scan &1 - │ ├── columns: column3:25!null column4:26!null column1:27!null column2:28!null + │ ├── columns: c:25!null d:26!null a:27!null b:28!null │ └── mapping: - │ ├── column3:8 => column3:25 - │ ├── column4:9 => column4:26 - │ ├── column1:6 => column1:27 - │ └── column2:7 => column2:28 + │ ├── column3:8 => c:25 + │ ├── column4:9 => d:26 + │ ├── column1:6 => a:27 + │ └── column2:7 => b:28 ├── scan uniq_overlaps_pk - │ └── columns: a:29!null b:30!null c:31 d:32 + │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 └── filters - ├── column3:25 = c:31 - ├── column4:26 = d:32 - └── (column1:27 != a:29) OR (column2:28 != b:30) + ├── c:25 = uniq_overlaps_pk.c:31 + ├── d:26 = uniq_overlaps_pk.d:32 + └── (a:27 != uniq_overlaps_pk.a:29) OR (b:28 != uniq_overlaps_pk.b:30) # Insert with non-constant input. # Add inequality filters for the primary key columns that are not part of each @@ -546,60 +546,60 @@ INSERT INTO uniq_overlaps_pk SELECT k, v, x, y FROM other insert uniq_overlaps_pk ├── columns: ├── insert-mapping: - │ ├── other.k:6 => a:1 - │ ├── other.v:7 => b:2 - │ ├── other.x:9 => c:3 - │ └── other.y:10 => d:4 + │ ├── k:6 => uniq_overlaps_pk.a:1 + │ ├── v:7 => uniq_overlaps_pk.b:2 + │ ├── x:9 => uniq_overlaps_pk.c:3 + │ └── y:10 => uniq_overlaps_pk.d:4 ├── input binding: &1 ├── project - │ ├── columns: other.k:6 other.v:7 other.x:9 other.y:10 + │ ├── columns: k:6 v:7 x:9 y:10 │ └── scan other - │ └── columns: other.k:6 other.v:7 w:8!null other.x:9 other.y:10 rowid:11!null other.crdb_internal_mvcc_timestamp:12 + │ └── columns: k:6 v:7 w:8!null x:9 y:10 rowid:11!null other.crdb_internal_mvcc_timestamp:12 └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: v:13 x:14 k:15 + │ ├── columns: b:13 c:14 a:15 │ ├── with-scan &1 - │ │ ├── columns: v:13 x:14 k:15 + │ │ ├── columns: b:13 c:14 a:15 │ │ └── mapping: - │ │ ├── other.v:7 => v:13 - │ │ ├── other.x:9 => x:14 - │ │ └── other.k:6 => k:15 + │ │ ├── v:7 => b:13 + │ │ ├── x:9 => c:14 + │ │ └── k:6 => a:15 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:16!null b:17!null c:18 + │ │ └── columns: uniq_overlaps_pk.a:16!null uniq_overlaps_pk.b:17!null uniq_overlaps_pk.c:18 │ └── filters - │ ├── v:13 = b:17 - │ ├── x:14 = c:18 - │ └── k:15 != a:16 + │ ├── b:13 = uniq_overlaps_pk.b:17 + │ ├── c:14 = uniq_overlaps_pk.c:18 + │ └── a:15 != uniq_overlaps_pk.a:16 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: k:21 v:22 + │ ├── columns: a:21 b:22 │ ├── with-scan &1 - │ │ ├── columns: k:21 v:22 + │ │ ├── columns: a:21 b:22 │ │ └── mapping: - │ │ ├── other.k:6 => k:21 - │ │ └── other.v:7 => v:22 + │ │ ├── k:6 => a:21 + │ │ └── v:7 => b:22 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:23!null b:24!null + │ │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null │ └── filters - │ ├── k:21 = a:23 - │ └── v:22 != b:24 + │ ├── a:21 = uniq_overlaps_pk.a:23 + │ └── b:22 != uniq_overlaps_pk.b:24 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: x:28 y:29 k:30 v:31 + ├── columns: c:28 d:29 a:30 b:31 ├── with-scan &1 - │ ├── columns: x:28 y:29 k:30 v:31 + │ ├── columns: c:28 d:29 a:30 b:31 │ └── mapping: - │ ├── other.x:9 => x:28 - │ ├── other.y:10 => y:29 - │ ├── other.k:6 => k:30 - │ └── other.v:7 => v:31 + │ ├── x:9 => c:28 + │ ├── y:10 => d:29 + │ ├── k:6 => a:30 + │ └── v:7 => b:31 ├── scan uniq_overlaps_pk - │ └── columns: a:32!null b:33!null c:34 d:35 + │ └── columns: uniq_overlaps_pk.a:32!null uniq_overlaps_pk.b:33!null uniq_overlaps_pk.c:34 uniq_overlaps_pk.d:35 └── filters - ├── x:28 = c:34 - ├── y:29 = d:35 - └── (k:30 != a:32) OR (v:31 != b:33) + ├── c:28 = uniq_overlaps_pk.c:34 + ├── d:29 = uniq_overlaps_pk.d:35 + └── (a:30 != uniq_overlaps_pk.a:32) OR (b:31 != uniq_overlaps_pk.b:33) exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -621,11 +621,11 @@ INSERT INTO uniq_hidden_pk VALUES (1, 1, 1, 1), (2, 2, 2, 2) insert uniq_hidden_pk ├── columns: ├── insert-mapping: - │ ├── column1:7 => a:1 - │ ├── column2:8 => b:2 - │ ├── column3:9 => c:3 - │ ├── column4:10 => d:4 - │ └── column11:11 => rowid:5 + │ ├── column1:7 => uniq_hidden_pk.a:1 + │ ├── column2:8 => uniq_hidden_pk.b:2 + │ ├── column3:9 => uniq_hidden_pk.c:3 + │ ├── column4:10 => uniq_hidden_pk.d:4 + │ └── column11:11 => uniq_hidden_pk.rowid:5 ├── input binding: &1 ├── project │ ├── columns: column11:11 column1:7!null column2:8!null column3:9!null column4:10!null @@ -638,49 +638,49 @@ insert uniq_hidden_pk └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: column2:12!null column3:13!null column11:14 + │ ├── columns: b:12!null c:13!null rowid:14 │ ├── with-scan &1 - │ │ ├── columns: column2:12!null column3:13!null column11:14 + │ │ ├── columns: b:12!null c:13!null rowid:14 │ │ └── mapping: - │ │ ├── column2:8 => column2:12 - │ │ ├── column3:9 => column3:13 - │ │ └── column11:11 => column11:14 + │ │ ├── column2:8 => b:12 + │ │ ├── column3:9 => c:13 + │ │ └── column11:11 => rowid:14 │ ├── scan uniq_hidden_pk - │ │ └── columns: b:16 c:17 rowid:19!null + │ │ └── columns: uniq_hidden_pk.b:16 uniq_hidden_pk.c:17 uniq_hidden_pk.rowid:19!null │ └── filters - │ ├── column2:12 = b:16 - │ ├── column3:13 = c:17 - │ └── column11:14 != rowid:19 + │ ├── b:12 = uniq_hidden_pk.b:16 + │ ├── c:13 = uniq_hidden_pk.c:17 + │ └── rowid:14 != uniq_hidden_pk.rowid:19 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: column1:21!null column2:22!null column4:23!null column11:24 + │ ├── columns: a:21!null b:22!null d:23!null rowid:24 │ ├── with-scan &1 - │ │ ├── columns: column1:21!null column2:22!null column4:23!null column11:24 + │ │ ├── columns: a:21!null b:22!null d:23!null rowid:24 │ │ └── mapping: - │ │ ├── column1:7 => column1:21 - │ │ ├── column2:8 => column2:22 - │ │ ├── column4:10 => column4:23 - │ │ └── column11:11 => column11:24 + │ │ ├── column1:7 => a:21 + │ │ ├── column2:8 => b:22 + │ │ ├── column4:10 => d:23 + │ │ └── column11:11 => rowid:24 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:25 b:26 d:28 rowid:29!null + │ │ └── columns: uniq_hidden_pk.a:25 uniq_hidden_pk.b:26 uniq_hidden_pk.d:28 uniq_hidden_pk.rowid:29!null │ └── filters - │ ├── column1:21 = a:25 - │ ├── column2:22 = b:26 - │ ├── column4:23 = d:28 - │ └── column11:24 != rowid:29 + │ ├── a:21 = uniq_hidden_pk.a:25 + │ ├── b:22 = uniq_hidden_pk.b:26 + │ ├── d:23 = uniq_hidden_pk.d:28 + │ └── rowid:24 != uniq_hidden_pk.rowid:29 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: column1:31!null column11:32 + ├── columns: a:31!null rowid:32 ├── with-scan &1 - │ ├── columns: column1:31!null column11:32 + │ ├── columns: a:31!null rowid:32 │ └── mapping: - │ ├── column1:7 => column1:31 - │ └── column11:11 => column11:32 + │ ├── column1:7 => a:31 + │ └── column11:11 => rowid:32 ├── scan uniq_hidden_pk - │ └── columns: a:33 rowid:37!null + │ └── columns: uniq_hidden_pk.a:33 uniq_hidden_pk.rowid:37!null └── filters - ├── column1:31 = a:33 - └── column11:32 != rowid:37 + ├── a:31 = uniq_hidden_pk.a:33 + └── rowid:32 != uniq_hidden_pk.rowid:37 # Insert with non-constant input. # Add inequality filters for the hidden primary key column. @@ -690,63 +690,63 @@ INSERT INTO uniq_hidden_pk SELECT k, v, x, y FROM other insert uniq_hidden_pk ├── columns: ├── insert-mapping: - │ ├── other.k:7 => a:1 - │ ├── other.v:8 => b:2 - │ ├── other.x:10 => c:3 - │ ├── other.y:11 => d:4 + │ ├── k:7 => uniq_hidden_pk.a:1 + │ ├── v:8 => uniq_hidden_pk.b:2 + │ ├── x:10 => uniq_hidden_pk.c:3 + │ ├── y:11 => uniq_hidden_pk.d:4 │ └── column14:14 => uniq_hidden_pk.rowid:5 ├── input binding: &1 ├── project - │ ├── columns: column14:14 other.k:7 other.v:8 other.x:10 other.y:11 + │ ├── columns: column14:14 k:7 v:8 x:10 y:11 │ ├── project - │ │ ├── columns: other.k:7 other.v:8 other.x:10 other.y:11 + │ │ ├── columns: k:7 v:8 x:10 y:11 │ │ └── scan other - │ │ └── columns: other.k:7 other.v:8 w:9!null other.x:10 other.y:11 other.rowid:12!null other.crdb_internal_mvcc_timestamp:13 + │ │ └── columns: k:7 v:8 w:9!null x:10 y:11 other.rowid:12!null other.crdb_internal_mvcc_timestamp:13 │ └── projections │ └── unique_rowid() [as=column14:14] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: v:15 x:16 column14:17 + │ ├── columns: b:15 c:16 rowid:17 │ ├── with-scan &1 - │ │ ├── columns: v:15 x:16 column14:17 + │ │ ├── columns: b:15 c:16 rowid:17 │ │ └── mapping: - │ │ ├── other.v:8 => v:15 - │ │ ├── other.x:10 => x:16 - │ │ └── column14:14 => column14:17 + │ │ ├── v:8 => b:15 + │ │ ├── x:10 => c:16 + │ │ └── column14:14 => rowid:17 │ ├── scan uniq_hidden_pk - │ │ └── columns: b:19 c:20 uniq_hidden_pk.rowid:22!null + │ │ └── columns: uniq_hidden_pk.b:19 uniq_hidden_pk.c:20 uniq_hidden_pk.rowid:22!null │ └── filters - │ ├── v:15 = b:19 - │ ├── x:16 = c:20 - │ └── column14:17 != uniq_hidden_pk.rowid:22 + │ ├── b:15 = uniq_hidden_pk.b:19 + │ ├── c:16 = uniq_hidden_pk.c:20 + │ └── rowid:17 != uniq_hidden_pk.rowid:22 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: k:24 v:25 y:26 column14:27 + │ ├── columns: a:24 b:25 d:26 rowid:27 │ ├── with-scan &1 - │ │ ├── columns: k:24 v:25 y:26 column14:27 + │ │ ├── columns: a:24 b:25 d:26 rowid:27 │ │ └── mapping: - │ │ ├── other.k:7 => k:24 - │ │ ├── other.v:8 => v:25 - │ │ ├── other.y:11 => y:26 - │ │ └── column14:14 => column14:27 + │ │ ├── k:7 => a:24 + │ │ ├── v:8 => b:25 + │ │ ├── y:11 => d:26 + │ │ └── column14:14 => rowid:27 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:28 b:29 d:31 uniq_hidden_pk.rowid:32!null + │ │ └── columns: uniq_hidden_pk.a:28 uniq_hidden_pk.b:29 uniq_hidden_pk.d:31 uniq_hidden_pk.rowid:32!null │ └── filters - │ ├── k:24 = a:28 - │ ├── v:25 = b:29 - │ ├── y:26 = d:31 - │ └── column14:27 != uniq_hidden_pk.rowid:32 + │ ├── a:24 = uniq_hidden_pk.a:28 + │ ├── b:25 = uniq_hidden_pk.b:29 + │ ├── d:26 = uniq_hidden_pk.d:31 + │ └── rowid:27 != uniq_hidden_pk.rowid:32 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: k:34 column14:35 + ├── columns: a:34 rowid:35 ├── with-scan &1 - │ ├── columns: k:34 column14:35 + │ ├── columns: a:34 rowid:35 │ └── mapping: - │ ├── other.k:7 => k:34 - │ └── column14:14 => column14:35 + │ ├── k:7 => a:34 + │ └── column14:14 => rowid:35 ├── scan uniq_hidden_pk - │ └── columns: a:36 uniq_hidden_pk.rowid:40!null + │ └── columns: uniq_hidden_pk.a:36 uniq_hidden_pk.rowid:40!null └── filters - ├── k:34 = a:36 - └── column14:35 != uniq_hidden_pk.rowid:40 + ├── a:34 = uniq_hidden_pk.a:36 + └── rowid:35 != uniq_hidden_pk.rowid:40 diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-update b/pkg/sql/opt/optbuilder/testdata/unique-checks-update index 007675fc8f92..b83fdf774dfe 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-update +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-update @@ -15,45 +15,45 @@ UPDATE uniq SET w = 1, x = 2 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 w:9 x:10 uniq.y:11 + ├── fetch columns: uniq.k:7 v:8 uniq.w:9 uniq.x:10 uniq.y:11 ├── update-mapping: - │ ├── w_new:13 => w:3 - │ └── x_new:14 => x:4 + │ ├── w_new:13 => uniq.w:3 + │ └── x_new:14 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: w_new:13!null x_new:14!null uniq.k:7!null v:8 w:9 x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: w_new:13!null x_new:14!null uniq.k:7!null v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ ├── scan uniq - │ │ └── columns: uniq.k:7!null v:8 w:9 x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq.k:7!null v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ └── projections │ ├── 1 [as=w_new:13] │ └── 2 [as=x_new:14] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w_new:15!null k:16!null + │ ├── columns: w:15!null k:16!null │ ├── with-scan &1 - │ │ ├── columns: w_new:15!null k:16!null + │ │ ├── columns: w:15!null k:16!null │ │ └── mapping: - │ │ ├── w_new:13 => w_new:15 + │ │ ├── w_new:13 => w:15 │ │ └── uniq.k:7 => k:16 │ ├── scan uniq - │ │ └── columns: uniq.k:17!null w:19 + │ │ └── columns: uniq.k:17!null uniq.w:19 │ └── filters - │ ├── w_new:15 = w:19 + │ ├── w:15 = uniq.w:19 │ └── k:16 != uniq.k:17 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x_new:23!null y:24 k:25!null + ├── columns: x:23!null y:24 k:25!null ├── with-scan &1 - │ ├── columns: x_new:23!null y:24 k:25!null + │ ├── columns: x:23!null y:24 k:25!null │ └── mapping: - │ ├── x_new:14 => x_new:23 + │ ├── x_new:14 => x:23 │ ├── uniq.y:11 => y:24 │ └── uniq.k:7 => k:25 ├── scan uniq - │ └── columns: uniq.k:26!null x:29 uniq.y:30 + │ └── columns: uniq.k:26!null uniq.x:29 uniq.y:30 └── filters - ├── x_new:23 = x:29 + ├── x:23 = uniq.x:29 ├── y:24 = uniq.y:30 └── k:25 != uniq.k:26 @@ -63,32 +63,32 @@ UPDATE uniq SET w = NULL, x = 1 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 w:9 x:10 uniq.y:11 + ├── fetch columns: uniq.k:7 v:8 w:9 uniq.x:10 uniq.y:11 ├── update-mapping: │ ├── w_new:13 => w:3 - │ └── x_new:14 => x:4 + │ └── x_new:14 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: w_new:13 x_new:14!null uniq.k:7!null v:8 w:9 x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: w_new:13 x_new:14!null uniq.k:7!null v:8 w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ ├── scan uniq - │ │ └── columns: uniq.k:7!null v:8 w:9 x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq.k:7!null v:8 w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ └── projections │ ├── NULL::INT8 [as=w_new:13] │ └── 1 [as=x_new:14] └── unique-checks └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x_new:15!null y:16 k:17!null + ├── columns: x:15!null y:16 k:17!null ├── with-scan &1 - │ ├── columns: x_new:15!null y:16 k:17!null + │ ├── columns: x:15!null y:16 k:17!null │ └── mapping: - │ ├── x_new:14 => x_new:15 + │ ├── x_new:14 => x:15 │ ├── uniq.y:11 => y:16 │ └── uniq.k:7 => k:17 ├── scan uniq - │ └── columns: uniq.k:18!null x:21 uniq.y:22 + │ └── columns: uniq.k:18!null uniq.x:21 uniq.y:22 └── filters - ├── x_new:15 = x:21 + ├── x:15 = uniq.x:21 ├── y:16 = uniq.y:22 └── k:17 != uniq.k:18 @@ -99,16 +99,16 @@ UPDATE uniq SET k = 1, w = 2, x = NULL ---- update uniq ├── columns: - ├── fetch columns: k:7 v:8 w:9 x:10 y:11 + ├── fetch columns: uniq.k:7 v:8 uniq.w:9 x:10 y:11 ├── update-mapping: - │ ├── k_new:13 => k:1 - │ ├── w_new:14 => w:3 + │ ├── k_new:13 => uniq.k:1 + │ ├── w_new:14 => uniq.w:3 │ └── x_new:15 => x:4 ├── input binding: &1 ├── project - │ ├── columns: k_new:13!null w_new:14!null x_new:15 k:7!null v:8 w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: k_new:13!null w_new:14!null x_new:15 uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 │ ├── scan uniq - │ │ └── columns: k:7!null v:8 w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 │ └── projections │ ├── 1 [as=k_new:13] │ ├── 2 [as=w_new:14] @@ -116,17 +116,17 @@ update uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: w_new:16!null k_new:17!null + ├── columns: w:16!null k:17!null ├── with-scan &1 - │ ├── columns: w_new:16!null k_new:17!null + │ ├── columns: w:16!null k:17!null │ └── mapping: - │ ├── w_new:14 => w_new:16 - │ └── k_new:13 => k_new:17 + │ ├── w_new:14 => w:16 + │ └── k_new:13 => k:17 ├── scan uniq - │ └── columns: k:18!null w:20 + │ └── columns: uniq.k:18!null uniq.w:20 └── filters - ├── w_new:16 = w:20 - └── k_new:17 != k:18 + ├── w:16 = uniq.w:20 + └── k:17 != uniq.k:18 # No need to plan checks for x,y since y is aways null. build @@ -134,17 +134,17 @@ UPDATE uniq SET w = 1, y = NULL WHERE k = 1 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 w:9 x:10 y:11 + ├── fetch columns: uniq.k:7 v:8 uniq.w:9 x:10 y:11 ├── update-mapping: - │ ├── w_new:13 => w:3 + │ ├── w_new:13 => uniq.w:3 │ └── y_new:14 => y:5 ├── input binding: &1 ├── project - │ ├── columns: w_new:13!null y_new:14 uniq.k:7!null v:8 w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: w_new:13!null y_new:14 uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 │ ├── select - │ │ ├── columns: uniq.k:7!null v:8 w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ │ ├── columns: uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 │ │ ├── scan uniq - │ │ │ └── columns: uniq.k:7!null v:8 w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ │ │ └── columns: uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 │ │ └── filters │ │ └── uniq.k:7 = 1 │ └── projections @@ -153,16 +153,16 @@ update uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: w_new:15!null k:16!null + ├── columns: w:15!null k:16!null ├── with-scan &1 - │ ├── columns: w_new:15!null k:16!null + │ ├── columns: w:15!null k:16!null │ └── mapping: - │ ├── w_new:13 => w_new:15 + │ ├── w_new:13 => w:15 │ └── uniq.k:7 => k:16 ├── scan uniq - │ └── columns: uniq.k:17!null w:19 + │ └── columns: uniq.k:17!null uniq.w:19 └── filters - ├── w_new:15 = w:19 + ├── w:15 = uniq.w:19 └── k:16 != uniq.k:17 # No need to plan checks since none of the columns requiring checks are updated. @@ -285,21 +285,21 @@ UPDATE uniq_overlaps_pk SET a = 1, b = 2, c = 3, d = 4 WHERE a = 5 ---- update uniq_overlaps_pk ├── columns: - ├── fetch columns: a:6 b:7 c:8 d:9 + ├── fetch columns: uniq_overlaps_pk.a:6 uniq_overlaps_pk.b:7 uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 ├── update-mapping: - │ ├── a_new:11 => a:1 - │ ├── b_new:12 => b:2 - │ ├── c_new:13 => c:3 - │ └── d_new:14 => d:4 + │ ├── a_new:11 => uniq_overlaps_pk.a:1 + │ ├── b_new:12 => uniq_overlaps_pk.b:2 + │ ├── c_new:13 => uniq_overlaps_pk.c:3 + │ └── d_new:14 => uniq_overlaps_pk.d:4 ├── input binding: &1 ├── project - │ ├── columns: a_new:11!null b_new:12!null c_new:13!null d_new:14!null a:6!null b:7!null c:8 d:9 crdb_internal_mvcc_timestamp:10 + │ ├── columns: a_new:11!null b_new:12!null c_new:13!null d_new:14!null uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 crdb_internal_mvcc_timestamp:10 │ ├── select - │ │ ├── columns: a:6!null b:7!null c:8 d:9 crdb_internal_mvcc_timestamp:10 + │ │ ├── columns: uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 crdb_internal_mvcc_timestamp:10 │ │ ├── scan uniq_overlaps_pk - │ │ │ └── columns: a:6!null b:7!null c:8 d:9 crdb_internal_mvcc_timestamp:10 + │ │ │ └── columns: uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 crdb_internal_mvcc_timestamp:10 │ │ └── filters - │ │ └── a:6 = 5 + │ │ └── uniq_overlaps_pk.a:6 = 5 │ └── projections │ ├── 1 [as=a_new:11] │ ├── 2 [as=b_new:12] @@ -308,48 +308,48 @@ update uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b_new:15!null c_new:16!null a_new:17!null + │ ├── columns: b:15!null c:16!null a:17!null │ ├── with-scan &1 - │ │ ├── columns: b_new:15!null c_new:16!null a_new:17!null + │ │ ├── columns: b:15!null c:16!null a:17!null │ │ └── mapping: - │ │ ├── b_new:12 => b_new:15 - │ │ ├── c_new:13 => c_new:16 - │ │ └── a_new:11 => a_new:17 + │ │ ├── b_new:12 => b:15 + │ │ ├── c_new:13 => c:16 + │ │ └── a_new:11 => a:17 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:18!null b:19!null c:20 + │ │ └── columns: uniq_overlaps_pk.a:18!null uniq_overlaps_pk.b:19!null uniq_overlaps_pk.c:20 │ └── filters - │ ├── b_new:15 = b:19 - │ ├── c_new:16 = c:20 - │ └── a_new:17 != a:18 + │ ├── b:15 = uniq_overlaps_pk.b:19 + │ ├── c:16 = uniq_overlaps_pk.c:20 + │ └── a:17 != uniq_overlaps_pk.a:18 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a_new:23!null b_new:24!null + │ ├── columns: a:23!null b:24!null │ ├── with-scan &1 - │ │ ├── columns: a_new:23!null b_new:24!null + │ │ ├── columns: a:23!null b:24!null │ │ └── mapping: - │ │ ├── a_new:11 => a_new:23 - │ │ └── b_new:12 => b_new:24 + │ │ ├── a_new:11 => a:23 + │ │ └── b_new:12 => b:24 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:25!null b:26!null + │ │ └── columns: uniq_overlaps_pk.a:25!null uniq_overlaps_pk.b:26!null │ └── filters - │ ├── a_new:23 = a:25 - │ └── b_new:24 != b:26 + │ ├── a:23 = uniq_overlaps_pk.a:25 + │ └── b:24 != uniq_overlaps_pk.b:26 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c_new:30!null d_new:31!null a_new:32!null b_new:33!null + ├── columns: c:30!null d:31!null a:32!null b:33!null ├── with-scan &1 - │ ├── columns: c_new:30!null d_new:31!null a_new:32!null b_new:33!null + │ ├── columns: c:30!null d:31!null a:32!null b:33!null │ └── mapping: - │ ├── c_new:13 => c_new:30 - │ ├── d_new:14 => d_new:31 - │ ├── a_new:11 => a_new:32 - │ └── b_new:12 => b_new:33 + │ ├── c_new:13 => c:30 + │ ├── d_new:14 => d:31 + │ ├── a_new:11 => a:32 + │ └── b_new:12 => b:33 ├── scan uniq_overlaps_pk - │ └── columns: a:34!null b:35!null c:36 d:37 + │ └── columns: uniq_overlaps_pk.a:34!null uniq_overlaps_pk.b:35!null uniq_overlaps_pk.c:36 uniq_overlaps_pk.d:37 └── filters - ├── c_new:30 = c:36 - ├── d_new:31 = d:37 - └── (a_new:32 != a:34) OR (b_new:33 != b:35) + ├── c:30 = uniq_overlaps_pk.c:36 + ├── d:31 = uniq_overlaps_pk.d:37 + └── (a:32 != uniq_overlaps_pk.a:34) OR (b:33 != uniq_overlaps_pk.b:35) # Update with non-constant input. # No need to add a check for b,c since those columns weren't updated. @@ -360,32 +360,32 @@ UPDATE uniq_overlaps_pk SET a = k, d = v FROM other ---- update uniq_overlaps_pk ├── columns: - ├── fetch columns: a:6 uniq_overlaps_pk.b:7 uniq_overlaps_pk.c:8 d:9 + ├── fetch columns: uniq_overlaps_pk.a:6 uniq_overlaps_pk.b:7 uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 ├── update-mapping: - │ ├── other.k:11 => a:1 - │ └── other.v:12 => d:4 + │ ├── k:11 => uniq_overlaps_pk.a:1 + │ └── v:12 => uniq_overlaps_pk.d:4 ├── input binding: &1 ├── distinct-on - │ ├── columns: a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 d:9 uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 other.k:11 other.v:12 w:13!null x:14 y:15 rowid:16!null other.crdb_internal_mvcc_timestamp:17 - │ ├── grouping columns: a:6!null uniq_overlaps_pk.b:7!null + │ ├── columns: uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 k:11 v:12 w:13!null x:14 y:15 rowid:16!null other.crdb_internal_mvcc_timestamp:17 + │ ├── grouping columns: uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null │ ├── inner-join (cross) - │ │ ├── columns: a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 d:9 uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 other.k:11 other.v:12 w:13!null x:14 y:15 rowid:16!null other.crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 k:11 v:12 w:13!null x:14 y:15 rowid:16!null other.crdb_internal_mvcc_timestamp:17 │ │ ├── scan uniq_overlaps_pk - │ │ │ └── columns: a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 d:9 uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 + │ │ │ └── columns: uniq_overlaps_pk.a:6!null uniq_overlaps_pk.b:7!null uniq_overlaps_pk.c:8 uniq_overlaps_pk.d:9 uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 │ │ ├── scan other - │ │ │ └── columns: other.k:11 other.v:12 w:13!null x:14 y:15 rowid:16!null other.crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: k:11 v:12 w:13!null x:14 y:15 rowid:16!null other.crdb_internal_mvcc_timestamp:17 │ │ └── filters (true) │ └── aggregations │ ├── first-agg [as=uniq_overlaps_pk.c:8] │ │ └── uniq_overlaps_pk.c:8 - │ ├── first-agg [as=d:9] - │ │ └── d:9 + │ ├── first-agg [as=uniq_overlaps_pk.d:9] + │ │ └── uniq_overlaps_pk.d:9 │ ├── first-agg [as=uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10] │ │ └── uniq_overlaps_pk.crdb_internal_mvcc_timestamp:10 - │ ├── first-agg [as=other.k:11] - │ │ └── other.k:11 - │ ├── first-agg [as=other.v:12] - │ │ └── other.v:12 + │ ├── first-agg [as=k:11] + │ │ └── k:11 + │ ├── first-agg [as=v:12] + │ │ └── v:12 │ ├── first-agg [as=w:13] │ │ └── w:13 │ ├── first-agg [as=x:14] @@ -399,33 +399,33 @@ update uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: k:18 b:19!null + │ ├── columns: a:18 b:19!null │ ├── with-scan &1 - │ │ ├── columns: k:18 b:19!null + │ │ ├── columns: a:18 b:19!null │ │ └── mapping: - │ │ ├── other.k:11 => k:18 + │ │ ├── k:11 => a:18 │ │ └── uniq_overlaps_pk.b:7 => b:19 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:20!null uniq_overlaps_pk.b:21!null + │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null │ └── filters - │ ├── k:18 = a:20 + │ ├── a:18 = uniq_overlaps_pk.a:20 │ └── b:19 != uniq_overlaps_pk.b:21 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:25 v:26 k:27 b:28!null + ├── columns: c:25 d:26 a:27 b:28!null ├── with-scan &1 - │ ├── columns: c:25 v:26 k:27 b:28!null + │ ├── columns: c:25 d:26 a:27 b:28!null │ └── mapping: │ ├── uniq_overlaps_pk.c:8 => c:25 - │ ├── other.v:12 => v:26 - │ ├── other.k:11 => k:27 + │ ├── v:12 => d:26 + │ ├── k:11 => a:27 │ └── uniq_overlaps_pk.b:7 => b:28 ├── scan uniq_overlaps_pk - │ └── columns: a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 d:32 + │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 └── filters ├── c:25 = uniq_overlaps_pk.c:31 - ├── v:26 = d:32 - └── (k:27 != a:29) OR (b:28 != uniq_overlaps_pk.b:30) + ├── d:26 = uniq_overlaps_pk.d:32 + └── (a:27 != uniq_overlaps_pk.a:29) OR (b:28 != uniq_overlaps_pk.b:30) exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -447,46 +447,46 @@ UPDATE uniq_hidden_pk SET a = 1 ---- update uniq_hidden_pk ├── columns: - ├── fetch columns: a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 + ├── fetch columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 ├── update-mapping: - │ └── a_new:13 => a:1 + │ └── a_new:13 => uniq_hidden_pk.a:1 ├── input binding: &1 ├── project - │ ├── columns: a_new:13!null a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 + │ ├── columns: a_new:13!null uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 │ └── projections │ └── 1 [as=a_new:13] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a_new:14!null b:15 d:16 rowid:17!null + │ ├── columns: a:14!null b:15 d:16 rowid:17!null │ ├── with-scan &1 - │ │ ├── columns: a_new:14!null b:15 d:16 rowid:17!null + │ │ ├── columns: a:14!null b:15 d:16 rowid:17!null │ │ └── mapping: - │ │ ├── a_new:13 => a_new:14 + │ │ ├── a_new:13 => a:14 │ │ ├── uniq_hidden_pk.b:8 => b:15 │ │ ├── uniq_hidden_pk.d:10 => d:16 │ │ └── uniq_hidden_pk.rowid:11 => rowid:17 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:18 uniq_hidden_pk.b:19 uniq_hidden_pk.d:21 uniq_hidden_pk.rowid:22!null + │ │ └── columns: uniq_hidden_pk.a:18 uniq_hidden_pk.b:19 uniq_hidden_pk.d:21 uniq_hidden_pk.rowid:22!null │ └── filters - │ ├── a_new:14 = a:18 + │ ├── a:14 = uniq_hidden_pk.a:18 │ ├── b:15 = uniq_hidden_pk.b:19 │ ├── d:16 = uniq_hidden_pk.d:21 │ └── rowid:17 != uniq_hidden_pk.rowid:22 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a_new:24!null rowid:25!null + ├── columns: a:24!null rowid:25!null ├── with-scan &1 - │ ├── columns: a_new:24!null rowid:25!null + │ ├── columns: a:24!null rowid:25!null │ └── mapping: - │ ├── a_new:13 => a_new:24 + │ ├── a_new:13 => a:24 │ └── uniq_hidden_pk.rowid:11 => rowid:25 ├── scan uniq_hidden_pk - │ └── columns: a:26 uniq_hidden_pk.rowid:30!null + │ └── columns: uniq_hidden_pk.a:26 uniq_hidden_pk.rowid:30!null └── filters - ├── a_new:24 = a:26 + ├── a:24 = uniq_hidden_pk.a:26 └── rowid:25 != uniq_hidden_pk.rowid:30 # Update with non-constant input. @@ -497,45 +497,45 @@ UPDATE uniq_hidden_pk SET a = k FROM other ---- update uniq_hidden_pk ├── columns: - ├── fetch columns: a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 + ├── fetch columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 ├── update-mapping: - │ └── other.k:13 => a:1 + │ └── k:13 => uniq_hidden_pk.a:1 ├── input binding: &1 ├── inner-join (cross) - │ ├── columns: a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 other.k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 + │ ├── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 │ ├── scan other - │ │ └── columns: other.k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 + │ │ └── columns: k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 │ └── filters (true) └── unique-checks ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: k:20 b:21 d:22 rowid:23!null + │ ├── columns: a:20 b:21 d:22 rowid:23!null │ ├── with-scan &1 - │ │ ├── columns: k:20 b:21 d:22 rowid:23!null + │ │ ├── columns: a:20 b:21 d:22 rowid:23!null │ │ └── mapping: - │ │ ├── other.k:13 => k:20 + │ │ ├── k:13 => a:20 │ │ ├── uniq_hidden_pk.b:8 => b:21 │ │ ├── uniq_hidden_pk.d:10 => d:22 │ │ └── uniq_hidden_pk.rowid:11 => rowid:23 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:24 uniq_hidden_pk.b:25 uniq_hidden_pk.d:27 uniq_hidden_pk.rowid:28!null + │ │ └── columns: uniq_hidden_pk.a:24 uniq_hidden_pk.b:25 uniq_hidden_pk.d:27 uniq_hidden_pk.rowid:28!null │ └── filters - │ ├── k:20 = a:24 + │ ├── a:20 = uniq_hidden_pk.a:24 │ ├── b:21 = uniq_hidden_pk.b:25 │ ├── d:22 = uniq_hidden_pk.d:27 │ └── rowid:23 != uniq_hidden_pk.rowid:28 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: k:30 rowid:31!null + ├── columns: a:30 rowid:31!null ├── with-scan &1 - │ ├── columns: k:30 rowid:31!null + │ ├── columns: a:30 rowid:31!null │ └── mapping: - │ ├── other.k:13 => k:30 + │ ├── k:13 => a:30 │ └── uniq_hidden_pk.rowid:11 => rowid:31 ├── scan uniq_hidden_pk - │ └── columns: a:32 uniq_hidden_pk.rowid:36!null + │ └── columns: uniq_hidden_pk.a:32 uniq_hidden_pk.rowid:36!null └── filters - ├── k:30 = a:32 + ├── a:30 = uniq_hidden_pk.a:32 └── rowid:31 != uniq_hidden_pk.rowid:36 diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert b/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert index d463dd203dcb..bc202fc5242b 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert @@ -20,24 +20,24 @@ UPSERT INTO uniq VALUES (1, 1, 1, 1, 1), (2, 2, 2, 2, 2) upsert uniq ├── columns: ├── arbiter indexes: primary - ├── canary column: k:12 - ├── fetch columns: k:12 v:13 w:14 x:15 y:16 + ├── canary column: uniq.k:12 + ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── update-mapping: │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_k:18 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ ├── grouping columns: column1:7!null @@ -55,40 +55,40 @@ upsert uniq │ │ │ └── first-agg [as=column5:11] │ │ │ └── column5:11 │ │ ├── scan uniq - │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ └── filters - │ │ └── column1:7 = k:12 + │ │ └── column1:7 = uniq.k:12 │ └── projections - │ └── CASE WHEN k:12 IS NULL THEN column1:7 ELSE k:12 END [as=upsert_k:18] + │ └── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:18] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column3:19!null upsert_k:20 + │ ├── columns: w:19!null k:20 │ ├── with-scan &1 - │ │ ├── columns: column3:19!null upsert_k:20 + │ │ ├── columns: w:19!null k:20 │ │ └── mapping: - │ │ ├── column3:9 => column3:19 - │ │ └── upsert_k:18 => upsert_k:20 + │ │ ├── column3:9 => w:19 + │ │ └── upsert_k:18 => k:20 │ ├── scan uniq - │ │ └── columns: k:21!null w:23 + │ │ └── columns: uniq.k:21!null uniq.w:23 │ └── filters - │ ├── column3:19 = w:23 - │ └── upsert_k:20 != k:21 + │ ├── w:19 = uniq.w:23 + │ └── k:20 != uniq.k:21 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column4:27!null column5:28!null upsert_k:29 + ├── columns: x:27!null y:28!null k:29 ├── with-scan &1 - │ ├── columns: column4:27!null column5:28!null upsert_k:29 + │ ├── columns: x:27!null y:28!null k:29 │ └── mapping: - │ ├── column4:10 => column4:27 - │ ├── column5:11 => column5:28 - │ └── upsert_k:18 => upsert_k:29 + │ ├── column4:10 => x:27 + │ ├── column5:11 => y:28 + │ └── upsert_k:18 => k:29 ├── scan uniq - │ └── columns: k:30!null x:33 y:34 + │ └── columns: uniq.k:30!null uniq.x:33 uniq.y:34 └── filters - ├── column4:27 = x:33 - ├── column5:28 = y:34 - └── upsert_k:29 != k:30 + ├── x:27 = uniq.x:33 + ├── y:28 = uniq.y:34 + └── k:29 != uniq.k:30 # TODO(rytaft): The default value for x is NULL, and we're not updating either # x or y. Therefore, we could avoid planning checks for (x,y) (see #58300). @@ -98,22 +98,22 @@ UPSERT INTO uniq (k, v, w) VALUES (1, 1, 1), (2, 2, 2) upsert uniq ├── columns: ├── arbiter indexes: primary - ├── canary column: k:12 - ├── fetch columns: k:12 v:13 w:14 x:15 y:16 + ├── canary column: uniq.k:12 + ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column10:10 => x:4 - │ └── column11:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column10:10 => uniq.x:4 + │ └── column11:11 => uniq.y:5 ├── update-mapping: │ ├── column2:8 => v:2 - │ └── column3:9 => w:3 + │ └── column3:9 => uniq.w:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 upsert_x:19 upsert_y:20 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_k:18 upsert_x:19 upsert_y:20 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null │ │ │ ├── grouping columns: column1:7!null @@ -136,42 +136,42 @@ upsert uniq │ │ │ └── first-agg [as=column11:11] │ │ │ └── column11:11 │ │ ├── scan uniq - │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ └── filters - │ │ └── column1:7 = k:12 + │ │ └── column1:7 = uniq.k:12 │ └── projections - │ ├── CASE WHEN k:12 IS NULL THEN column1:7 ELSE k:12 END [as=upsert_k:18] - │ ├── CASE WHEN k:12 IS NULL THEN column10:10 ELSE x:15 END [as=upsert_x:19] - │ └── CASE WHEN k:12 IS NULL THEN column11:11 ELSE y:16 END [as=upsert_y:20] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:18] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column10:10 ELSE uniq.x:15 END [as=upsert_x:19] + │ └── CASE WHEN uniq.k:12 IS NULL THEN column11:11 ELSE uniq.y:16 END [as=upsert_y:20] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column3:21!null upsert_k:22 + │ ├── columns: w:21!null k:22 │ ├── with-scan &1 - │ │ ├── columns: column3:21!null upsert_k:22 + │ │ ├── columns: w:21!null k:22 │ │ └── mapping: - │ │ ├── column3:9 => column3:21 - │ │ └── upsert_k:18 => upsert_k:22 + │ │ ├── column3:9 => w:21 + │ │ └── upsert_k:18 => k:22 │ ├── scan uniq - │ │ └── columns: k:23!null w:25 + │ │ └── columns: uniq.k:23!null uniq.w:25 │ └── filters - │ ├── column3:21 = w:25 - │ └── upsert_k:22 != k:23 + │ ├── w:21 = uniq.w:25 + │ └── k:22 != uniq.k:23 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: upsert_x:29 upsert_y:30 upsert_k:31 + ├── columns: x:29 y:30 k:31 ├── with-scan &1 - │ ├── columns: upsert_x:29 upsert_y:30 upsert_k:31 + │ ├── columns: x:29 y:30 k:31 │ └── mapping: - │ ├── upsert_x:19 => upsert_x:29 - │ ├── upsert_y:20 => upsert_y:30 - │ └── upsert_k:18 => upsert_k:31 + │ ├── upsert_x:19 => x:29 + │ ├── upsert_y:20 => y:30 + │ └── upsert_k:18 => k:31 ├── scan uniq - │ └── columns: k:32!null x:35 y:36 + │ └── columns: uniq.k:32!null uniq.x:35 uniq.y:36 └── filters - ├── upsert_x:29 = x:35 - ├── upsert_y:30 = y:36 - └── upsert_k:31 != k:32 + ├── x:29 = uniq.x:35 + ├── y:30 = uniq.y:36 + └── k:31 != uniq.k:32 # TODO(rytaft): No need to plan checks for w since it's aways NULL. # We currently can't determine that w is always NULL since the function @@ -182,22 +182,22 @@ UPSERT INTO uniq (k, w, x) VALUES (1, NULL, 1), (2, NULL, NULL) upsert uniq ├── columns: ├── arbiter indexes: primary - ├── canary column: k:12 - ├── fetch columns: k:12 v:13 w:14 x:15 y:16 + ├── canary column: uniq.k:12 + ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column10:10 => v:2 - │ ├── column2:8 => w:3 - │ ├── column3:9 => x:4 - │ └── column11:11 => y:5 + │ ├── column2:8 => uniq.w:3 + │ ├── column3:9 => uniq.x:4 + │ └── column11:11 => uniq.y:5 ├── update-mapping: - │ ├── column2:8 => w:3 - │ └── column3:9 => x:4 + │ ├── column2:8 => uniq.w:3 + │ └── column3:9 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 upsert_v:19 upsert_y:20 column1:7!null column2:8 column3:9 column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_k:18 upsert_v:19 upsert_y:20 column1:7!null column2:8 column3:9 column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8 column3:9 column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8 column3:9 column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8 column3:9 column10:10 column11:11!null │ │ │ ├── grouping columns: column1:7!null @@ -220,42 +220,42 @@ upsert uniq │ │ │ └── first-agg [as=column11:11] │ │ │ └── column11:11 │ │ ├── scan uniq - │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ └── filters - │ │ └── column1:7 = k:12 + │ │ └── column1:7 = uniq.k:12 │ └── projections - │ ├── CASE WHEN k:12 IS NULL THEN column1:7 ELSE k:12 END [as=upsert_k:18] - │ ├── CASE WHEN k:12 IS NULL THEN column10:10 ELSE v:13 END [as=upsert_v:19] - │ └── CASE WHEN k:12 IS NULL THEN column11:11 ELSE y:16 END [as=upsert_y:20] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:18] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column10:10 ELSE v:13 END [as=upsert_v:19] + │ └── CASE WHEN uniq.k:12 IS NULL THEN column11:11 ELSE uniq.y:16 END [as=upsert_y:20] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: column2:21 upsert_k:22 + │ ├── columns: w:21 k:22 │ ├── with-scan &1 - │ │ ├── columns: column2:21 upsert_k:22 + │ │ ├── columns: w:21 k:22 │ │ └── mapping: - │ │ ├── column2:8 => column2:21 - │ │ └── upsert_k:18 => upsert_k:22 + │ │ ├── column2:8 => w:21 + │ │ └── upsert_k:18 => k:22 │ ├── scan uniq - │ │ └── columns: k:23!null w:25 + │ │ └── columns: uniq.k:23!null uniq.w:25 │ └── filters - │ ├── column2:21 = w:25 - │ └── upsert_k:22 != k:23 + │ ├── w:21 = uniq.w:25 + │ └── k:22 != uniq.k:23 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column3:29 upsert_y:30 upsert_k:31 + ├── columns: x:29 y:30 k:31 ├── with-scan &1 - │ ├── columns: column3:29 upsert_y:30 upsert_k:31 + │ ├── columns: x:29 y:30 k:31 │ └── mapping: - │ ├── column3:9 => column3:29 - │ ├── upsert_y:20 => upsert_y:30 - │ └── upsert_k:18 => upsert_k:31 + │ ├── column3:9 => x:29 + │ ├── upsert_y:20 => y:30 + │ └── upsert_k:18 => k:31 ├── scan uniq - │ └── columns: k:32!null x:35 y:36 + │ └── columns: uniq.k:32!null uniq.x:35 uniq.y:36 └── filters - ├── column3:29 = x:35 - ├── upsert_y:30 = y:36 - └── upsert_k:31 != k:32 + ├── x:29 = uniq.x:35 + ├── y:30 = uniq.y:36 + └── k:31 != uniq.k:32 # Upsert with non-constant input. # TODO(rytaft): The default value for x is NULL, and we're not updating either @@ -314,32 +314,32 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:23!null upsert_k:24 + │ ├── columns: w:23!null k:24 │ ├── with-scan &1 - │ │ ├── columns: w:23!null upsert_k:24 + │ │ ├── columns: w:23!null k:24 │ │ └── mapping: │ │ ├── other.w:9 => w:23 - │ │ └── upsert_k:22 => upsert_k:24 + │ │ └── upsert_k:22 => k:24 │ ├── scan uniq │ │ └── columns: uniq.k:25!null uniq.w:27 │ └── filters │ ├── w:23 = uniq.w:27 - │ └── upsert_k:24 != uniq.k:25 + │ └── k:24 != uniq.k:25 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: column14:31 column15:32!null upsert_k:33 + ├── columns: x:31 y:32!null k:33 ├── with-scan &1 - │ ├── columns: column14:31 column15:32!null upsert_k:33 + │ ├── columns: x:31 y:32!null k:33 │ └── mapping: - │ ├── column14:14 => column14:31 - │ ├── column15:15 => column15:32 - │ └── upsert_k:22 => upsert_k:33 + │ ├── column14:14 => x:31 + │ ├── column15:15 => y:32 + │ └── upsert_k:22 => k:33 ├── scan uniq │ └── columns: uniq.k:34!null uniq.x:37 uniq.y:38 └── filters - ├── column14:31 = uniq.x:37 - ├── column15:32 = uniq.y:38 - └── upsert_k:33 != uniq.k:34 + ├── x:31 = uniq.x:37 + ├── y:32 = uniq.y:38 + └── k:33 != uniq.k:34 # On conflict do update with constant input. # TODO(rytaft): The default value for x is NULL, and we're not updating either @@ -351,23 +351,23 @@ INSERT INTO uniq VALUES (100, 1), (200, 1) ON CONFLICT (k) DO UPDATE SET w = exc upsert uniq ├── columns: ├── arbiter indexes: primary - ├── canary column: k:11 - ├── fetch columns: k:11 v:12 w:13 x:14 y:15 + ├── canary column: uniq.k:11 + ├── fetch columns: uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column9:9 => w:3 - │ ├── column9:9 => x:4 - │ └── column10:10 => y:5 + │ ├── column9:9 => uniq.w:3 + │ ├── column9:9 => uniq.x:4 + │ └── column10:10 => uniq.y:5 ├── update-mapping: - │ └── upsert_w:20 => w:3 + │ └── upsert_w:20 => uniq.w:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 upsert_v:19 upsert_w:20 upsert_x:21 upsert_y:22 column1:7!null column2:8!null column9:9 column10:10!null k:11 v:12 w:13 x:14 y:15 crdb_internal_mvcc_timestamp:16 w_new:17 + │ ├── columns: upsert_k:18 upsert_v:19 upsert_w:20 upsert_x:21 upsert_y:22 column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 w_new:17 │ ├── project - │ │ ├── columns: w_new:17 column1:7!null column2:8!null column9:9 column10:10!null k:11 v:12 w:13 x:14 y:15 crdb_internal_mvcc_timestamp:16 + │ │ ├── columns: w_new:17 column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column9:9 column10:10!null k:11 v:12 w:13 x:14 y:15 crdb_internal_mvcc_timestamp:16 + │ │ │ ├── columns: column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column9:9 column10:10!null │ │ │ │ ├── grouping columns: column1:7!null @@ -388,46 +388,46 @@ upsert uniq │ │ │ │ └── first-agg [as=column10:10] │ │ │ │ └── column10:10 │ │ │ ├── scan uniq - │ │ │ │ └── columns: k:11!null v:12 w:13 x:14 y:15 crdb_internal_mvcc_timestamp:16 + │ │ │ │ └── columns: uniq.k:11!null v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 │ │ │ └── filters - │ │ │ └── column1:7 = k:11 + │ │ │ └── column1:7 = uniq.k:11 │ │ └── projections │ │ └── column9:9 + 1 [as=w_new:17] │ └── projections - │ ├── CASE WHEN k:11 IS NULL THEN column1:7 ELSE k:11 END [as=upsert_k:18] - │ ├── CASE WHEN k:11 IS NULL THEN column2:8 ELSE v:12 END [as=upsert_v:19] - │ ├── CASE WHEN k:11 IS NULL THEN column9:9 ELSE w_new:17 END [as=upsert_w:20] - │ ├── CASE WHEN k:11 IS NULL THEN column9:9 ELSE x:14 END [as=upsert_x:21] - │ └── CASE WHEN k:11 IS NULL THEN column10:10 ELSE y:15 END [as=upsert_y:22] + │ ├── CASE WHEN uniq.k:11 IS NULL THEN column1:7 ELSE uniq.k:11 END [as=upsert_k:18] + │ ├── CASE WHEN uniq.k:11 IS NULL THEN column2:8 ELSE v:12 END [as=upsert_v:19] + │ ├── CASE WHEN uniq.k:11 IS NULL THEN column9:9 ELSE w_new:17 END [as=upsert_w:20] + │ ├── CASE WHEN uniq.k:11 IS NULL THEN column9:9 ELSE uniq.x:14 END [as=upsert_x:21] + │ └── CASE WHEN uniq.k:11 IS NULL THEN column10:10 ELSE uniq.y:15 END [as=upsert_y:22] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: upsert_w:23 upsert_k:24 + │ ├── columns: w:23 k:24 │ ├── with-scan &1 - │ │ ├── columns: upsert_w:23 upsert_k:24 + │ │ ├── columns: w:23 k:24 │ │ └── mapping: - │ │ ├── upsert_w:20 => upsert_w:23 - │ │ └── upsert_k:18 => upsert_k:24 + │ │ ├── upsert_w:20 => w:23 + │ │ └── upsert_k:18 => k:24 │ ├── scan uniq - │ │ └── columns: k:25!null w:27 + │ │ └── columns: uniq.k:25!null uniq.w:27 │ └── filters - │ ├── upsert_w:23 = w:27 - │ └── upsert_k:24 != k:25 + │ ├── w:23 = uniq.w:27 + │ └── k:24 != uniq.k:25 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: upsert_x:31 upsert_y:32 upsert_k:33 + ├── columns: x:31 y:32 k:33 ├── with-scan &1 - │ ├── columns: upsert_x:31 upsert_y:32 upsert_k:33 + │ ├── columns: x:31 y:32 k:33 │ └── mapping: - │ ├── upsert_x:21 => upsert_x:31 - │ ├── upsert_y:22 => upsert_y:32 - │ └── upsert_k:18 => upsert_k:33 + │ ├── upsert_x:21 => x:31 + │ ├── upsert_y:22 => y:32 + │ └── upsert_k:18 => k:33 ├── scan uniq - │ └── columns: k:34!null x:37 y:38 + │ └── columns: uniq.k:34!null uniq.x:37 uniq.y:38 └── filters - ├── upsert_x:31 = x:37 - ├── upsert_y:32 = y:38 - └── upsert_k:33 != k:34 + ├── x:31 = uniq.x:37 + ├── y:32 = uniq.y:38 + └── k:33 != uniq.k:34 # On conflict do update with non-constant input. # TODO(rytaft): The default value for x is NULL, and we're not updating either @@ -489,32 +489,32 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: upsert_w:28 upsert_k:29 + │ ├── columns: w:28 k:29 │ ├── with-scan &1 - │ │ ├── columns: upsert_w:28 upsert_k:29 + │ │ ├── columns: w:28 k:29 │ │ └── mapping: - │ │ ├── upsert_w:25 => upsert_w:28 - │ │ └── upsert_k:23 => upsert_k:29 + │ │ ├── upsert_w:25 => w:28 + │ │ └── upsert_k:23 => k:29 │ ├── scan uniq │ │ └── columns: uniq.k:30!null uniq.w:32 │ └── filters - │ ├── upsert_w:28 = uniq.w:32 - │ └── upsert_k:29 != uniq.k:30 + │ ├── w:28 = uniq.w:32 + │ └── k:29 != uniq.k:30 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: upsert_x:36 upsert_y:37 upsert_k:38 + ├── columns: x:36 y:37 k:38 ├── with-scan &1 - │ ├── columns: upsert_x:36 upsert_y:37 upsert_k:38 + │ ├── columns: x:36 y:37 k:38 │ └── mapping: - │ ├── upsert_x:26 => upsert_x:36 - │ ├── upsert_y:27 => upsert_y:37 - │ └── upsert_k:23 => upsert_k:38 + │ ├── upsert_x:26 => x:36 + │ ├── upsert_y:27 => y:37 + │ └── upsert_k:23 => k:38 ├── scan uniq │ └── columns: uniq.k:39!null uniq.x:42 uniq.y:43 └── filters - ├── upsert_x:36 = uniq.x:42 - ├── upsert_y:37 = uniq.y:43 - └── upsert_k:38 != uniq.k:39 + ├── x:36 = uniq.x:42 + ├── y:37 = uniq.y:43 + └── k:38 != uniq.k:39 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # column. @@ -524,23 +524,23 @@ INSERT INTO uniq VALUES (100, 10, 1), (200, 20, 2) ON CONFLICT (w) DO UPDATE SET upsert uniq ├── columns: ├── arbiter constraints: unique_w - ├── canary column: k:12 - ├── fetch columns: k:12 v:13 w:14 x:15 y:16 + ├── canary column: uniq.k:12 + ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column10:10 => x:4 - │ └── column11:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column10:10 => uniq.x:4 + │ └── column11:11 => uniq.y:5 ├── update-mapping: - │ └── upsert_w:21 => w:3 + │ └── upsert_w:21 => uniq.w:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:19 upsert_v:20 upsert_w:21!null upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 w_new:18!null + │ ├── columns: upsert_k:19 upsert_v:20 upsert_w:21!null upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 w_new:18!null │ ├── project - │ │ ├── columns: w_new:18!null column1:7!null column2:8!null column3:9!null column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: w_new:18!null column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null │ │ │ │ ├── grouping columns: column3:9!null @@ -563,46 +563,46 @@ upsert uniq │ │ │ │ └── first-agg [as=column11:11] │ │ │ │ └── column11:11 │ │ │ ├── scan uniq - │ │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ └── filters - │ │ │ └── column3:9 = w:14 + │ │ │ └── column3:9 = uniq.w:14 │ │ └── projections │ │ └── 10 [as=w_new:18] │ └── projections - │ ├── CASE WHEN k:12 IS NULL THEN column1:7 ELSE k:12 END [as=upsert_k:19] - │ ├── CASE WHEN k:12 IS NULL THEN column2:8 ELSE v:13 END [as=upsert_v:20] - │ ├── CASE WHEN k:12 IS NULL THEN column3:9 ELSE w_new:18 END [as=upsert_w:21] - │ ├── CASE WHEN k:12 IS NULL THEN column10:10 ELSE x:15 END [as=upsert_x:22] - │ └── CASE WHEN k:12 IS NULL THEN column11:11 ELSE y:16 END [as=upsert_y:23] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:19] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column2:8 ELSE v:13 END [as=upsert_v:20] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column3:9 ELSE w_new:18 END [as=upsert_w:21] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column10:10 ELSE uniq.x:15 END [as=upsert_x:22] + │ └── CASE WHEN uniq.k:12 IS NULL THEN column11:11 ELSE uniq.y:16 END [as=upsert_y:23] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: upsert_w:24!null upsert_k:25 + │ ├── columns: w:24!null k:25 │ ├── with-scan &1 - │ │ ├── columns: upsert_w:24!null upsert_k:25 + │ │ ├── columns: w:24!null k:25 │ │ └── mapping: - │ │ ├── upsert_w:21 => upsert_w:24 - │ │ └── upsert_k:19 => upsert_k:25 + │ │ ├── upsert_w:21 => w:24 + │ │ └── upsert_k:19 => k:25 │ ├── scan uniq - │ │ └── columns: k:26!null w:28 + │ │ └── columns: uniq.k:26!null uniq.w:28 │ └── filters - │ ├── upsert_w:24 = w:28 - │ └── upsert_k:25 != k:26 + │ ├── w:24 = uniq.w:28 + │ └── k:25 != uniq.k:26 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: upsert_x:32 upsert_y:33 upsert_k:34 + ├── columns: x:32 y:33 k:34 ├── with-scan &1 - │ ├── columns: upsert_x:32 upsert_y:33 upsert_k:34 + │ ├── columns: x:32 y:33 k:34 │ └── mapping: - │ ├── upsert_x:22 => upsert_x:32 - │ ├── upsert_y:23 => upsert_y:33 - │ └── upsert_k:19 => upsert_k:34 + │ ├── upsert_x:22 => x:32 + │ ├── upsert_y:23 => y:33 + │ └── upsert_k:19 => k:34 ├── scan uniq - │ └── columns: k:35!null x:38 y:39 + │ └── columns: uniq.k:35!null uniq.x:38 uniq.y:39 └── filters - ├── upsert_x:32 = x:38 - ├── upsert_y:33 = y:39 - └── upsert_k:34 != k:35 + ├── x:32 = uniq.x:38 + ├── y:33 = uniq.y:39 + └── k:34 != uniq.k:35 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -612,23 +612,23 @@ INSERT INTO uniq VALUES (1, 2, 3, 4, 5) ON CONFLICT (x, y) DO UPDATE SET v = 10 upsert uniq ├── columns: ├── arbiter constraints: unique_x_y - ├── canary column: k:12 - ├── fetch columns: k:12 v:13 w:14 x:15 y:16 + ├── canary column: uniq.k:12 + ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: - │ ├── column1:7 => k:1 + │ ├── column1:7 => uniq.k:1 │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column3:9 => uniq.w:3 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── update-mapping: │ └── upsert_v:20 => v:2 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:19 upsert_v:20!null upsert_w:21 upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 v_new:18!null + │ ├── columns: upsert_k:19 upsert_v:20!null upsert_w:21 upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 v_new:18!null │ ├── project - │ │ ├── columns: v_new:18!null column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: v_new:18!null column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null k:12 v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ │ ├── grouping columns: column4:10!null column5:11!null @@ -643,47 +643,47 @@ upsert uniq │ │ │ │ └── first-agg [as=column3:9] │ │ │ │ └── column3:9 │ │ │ ├── scan uniq - │ │ │ │ └── columns: k:12!null v:13 w:14 x:15 y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ └── filters - │ │ │ ├── column4:10 = x:15 - │ │ │ └── column5:11 = y:16 + │ │ │ ├── column4:10 = uniq.x:15 + │ │ │ └── column5:11 = uniq.y:16 │ │ └── projections │ │ └── 10 [as=v_new:18] │ └── projections - │ ├── CASE WHEN k:12 IS NULL THEN column1:7 ELSE k:12 END [as=upsert_k:19] - │ ├── CASE WHEN k:12 IS NULL THEN column2:8 ELSE v_new:18 END [as=upsert_v:20] - │ ├── CASE WHEN k:12 IS NULL THEN column3:9 ELSE w:14 END [as=upsert_w:21] - │ ├── CASE WHEN k:12 IS NULL THEN column4:10 ELSE x:15 END [as=upsert_x:22] - │ └── CASE WHEN k:12 IS NULL THEN column5:11 ELSE y:16 END [as=upsert_y:23] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:19] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column2:8 ELSE v_new:18 END [as=upsert_v:20] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column3:9 ELSE uniq.w:14 END [as=upsert_w:21] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column4:10 ELSE uniq.x:15 END [as=upsert_x:22] + │ └── CASE WHEN uniq.k:12 IS NULL THEN column5:11 ELSE uniq.y:16 END [as=upsert_y:23] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: upsert_w:24 upsert_k:25 + │ ├── columns: w:24 k:25 │ ├── with-scan &1 - │ │ ├── columns: upsert_w:24 upsert_k:25 + │ │ ├── columns: w:24 k:25 │ │ └── mapping: - │ │ ├── upsert_w:21 => upsert_w:24 - │ │ └── upsert_k:19 => upsert_k:25 + │ │ ├── upsert_w:21 => w:24 + │ │ └── upsert_k:19 => k:25 │ ├── scan uniq - │ │ └── columns: k:26!null w:28 + │ │ └── columns: uniq.k:26!null uniq.w:28 │ └── filters - │ ├── upsert_w:24 = w:28 - │ └── upsert_k:25 != k:26 + │ ├── w:24 = uniq.w:28 + │ └── k:25 != uniq.k:26 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: upsert_x:32 upsert_y:33 upsert_k:34 + ├── columns: x:32 y:33 k:34 ├── with-scan &1 - │ ├── columns: upsert_x:32 upsert_y:33 upsert_k:34 + │ ├── columns: x:32 y:33 k:34 │ └── mapping: - │ ├── upsert_x:22 => upsert_x:32 - │ ├── upsert_y:23 => upsert_y:33 - │ └── upsert_k:19 => upsert_k:34 + │ ├── upsert_x:22 => x:32 + │ ├── upsert_y:23 => y:33 + │ └── upsert_k:19 => k:34 ├── scan uniq - │ └── columns: k:35!null x:38 y:39 + │ └── columns: uniq.k:35!null uniq.x:38 uniq.y:39 └── filters - ├── upsert_x:32 = x:38 - ├── upsert_y:33 = y:39 - └── upsert_k:34 != k:35 + ├── x:32 = uniq.x:38 + ├── y:33 = uniq.y:39 + └── k:34 != uniq.k:35 # Cannot conflict on a subset of columns in a unique constraint. build @@ -720,10 +720,10 @@ UPSERT INTO uniq_overlaps_pk VALUES (1, 1, 1, 1), (2, 2, 2, 2) upsert uniq_overlaps_pk ├── columns: ├── upsert-mapping: - │ ├── column1:6 => a:1 - │ ├── column2:7 => b:2 - │ ├── column3:8 => c:3 - │ └── column4:9 => d:4 + │ ├── column1:6 => uniq_overlaps_pk.a:1 + │ ├── column2:7 => uniq_overlaps_pk.b:2 + │ ├── column3:8 => uniq_overlaps_pk.c:3 + │ └── column4:9 => uniq_overlaps_pk.d:4 ├── input binding: &1 ├── values │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null @@ -732,48 +732,48 @@ upsert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: column2:10!null column3:11!null column1:12!null + │ ├── columns: b:10!null c:11!null a:12!null │ ├── with-scan &1 - │ │ ├── columns: column2:10!null column3:11!null column1:12!null + │ │ ├── columns: b:10!null c:11!null a:12!null │ │ └── mapping: - │ │ ├── column2:7 => column2:10 - │ │ ├── column3:8 => column3:11 - │ │ └── column1:6 => column1:12 + │ │ ├── column2:7 => b:10 + │ │ ├── column3:8 => c:11 + │ │ └── column1:6 => a:12 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:13!null b:14!null c:15 + │ │ └── columns: uniq_overlaps_pk.a:13!null uniq_overlaps_pk.b:14!null uniq_overlaps_pk.c:15 │ └── filters - │ ├── column2:10 = b:14 - │ ├── column3:11 = c:15 - │ └── column1:12 != a:13 + │ ├── b:10 = uniq_overlaps_pk.b:14 + │ ├── c:11 = uniq_overlaps_pk.c:15 + │ └── a:12 != uniq_overlaps_pk.a:13 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: column1:18!null column2:19!null + │ ├── columns: a:18!null b:19!null │ ├── with-scan &1 - │ │ ├── columns: column1:18!null column2:19!null + │ │ ├── columns: a:18!null b:19!null │ │ └── mapping: - │ │ ├── column1:6 => column1:18 - │ │ └── column2:7 => column2:19 + │ │ ├── column1:6 => a:18 + │ │ └── column2:7 => b:19 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:20!null b:21!null + │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null │ └── filters - │ ├── column1:18 = a:20 - │ └── column2:19 != b:21 + │ ├── a:18 = uniq_overlaps_pk.a:20 + │ └── b:19 != uniq_overlaps_pk.b:21 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: column3:25!null column4:26!null column1:27!null column2:28!null + ├── columns: c:25!null d:26!null a:27!null b:28!null ├── with-scan &1 - │ ├── columns: column3:25!null column4:26!null column1:27!null column2:28!null + │ ├── columns: c:25!null d:26!null a:27!null b:28!null │ └── mapping: - │ ├── column3:8 => column3:25 - │ ├── column4:9 => column4:26 - │ ├── column1:6 => column1:27 - │ └── column2:7 => column2:28 + │ ├── column3:8 => c:25 + │ ├── column4:9 => d:26 + │ ├── column1:6 => a:27 + │ └── column2:7 => b:28 ├── scan uniq_overlaps_pk - │ └── columns: a:29!null b:30!null c:31 d:32 + │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 └── filters - ├── column3:25 = c:31 - ├── column4:26 = d:32 - └── (column1:27 != a:29) OR (column2:28 != b:30) + ├── c:25 = uniq_overlaps_pk.c:31 + ├── d:26 = uniq_overlaps_pk.d:32 + └── (a:27 != uniq_overlaps_pk.a:29) OR (b:28 != uniq_overlaps_pk.b:30) # Upsert with non-constant input. # Add inequality filters for the primary key columns that are not part of each @@ -785,48 +785,48 @@ UPSERT INTO uniq_overlaps_pk SELECT k, v, x FROM other upsert uniq_overlaps_pk ├── columns: ├── upsert-mapping: - │ ├── other.k:6 => a:1 - │ ├── other.v:7 => b:2 - │ ├── other.x:9 => c:3 + │ ├── k:6 => uniq_overlaps_pk.a:1 + │ ├── v:7 => uniq_overlaps_pk.b:2 + │ ├── x:9 => uniq_overlaps_pk.c:3 │ └── column13:13 => d:4 ├── input binding: &1 ├── project - │ ├── columns: column13:13 other.k:6 other.v:7 other.x:9 + │ ├── columns: column13:13 k:6 v:7 x:9 │ ├── project - │ │ ├── columns: other.k:6 other.v:7 other.x:9 + │ │ ├── columns: k:6 v:7 x:9 │ │ └── scan other - │ │ └── columns: other.k:6 other.v:7 w:8!null other.x:9 y:10 rowid:11!null other.crdb_internal_mvcc_timestamp:12 + │ │ └── columns: k:6 v:7 w:8!null x:9 y:10 rowid:11!null other.crdb_internal_mvcc_timestamp:12 │ └── projections │ └── NULL::INT8 [as=column13:13] └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: v:14 x:15 k:16 + │ ├── columns: b:14 c:15 a:16 │ ├── with-scan &1 - │ │ ├── columns: v:14 x:15 k:16 + │ │ ├── columns: b:14 c:15 a:16 │ │ └── mapping: - │ │ ├── other.v:7 => v:14 - │ │ ├── other.x:9 => x:15 - │ │ └── other.k:6 => k:16 + │ │ ├── v:7 => b:14 + │ │ ├── x:9 => c:15 + │ │ └── k:6 => a:16 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:17!null b:18!null c:19 + │ │ └── columns: uniq_overlaps_pk.a:17!null uniq_overlaps_pk.b:18!null uniq_overlaps_pk.c:19 │ └── filters - │ ├── v:14 = b:18 - │ ├── x:15 = c:19 - │ └── k:16 != a:17 + │ ├── b:14 = uniq_overlaps_pk.b:18 + │ ├── c:15 = uniq_overlaps_pk.c:19 + │ └── a:16 != uniq_overlaps_pk.a:17 └── unique-checks-item: uniq_overlaps_pk(a) └── semi-join (hash) - ├── columns: k:22 v:23 + ├── columns: a:22 b:23 ├── with-scan &1 - │ ├── columns: k:22 v:23 + │ ├── columns: a:22 b:23 │ └── mapping: - │ ├── other.k:6 => k:22 - │ └── other.v:7 => v:23 + │ ├── k:6 => a:22 + │ └── v:7 => b:23 ├── scan uniq_overlaps_pk - │ └── columns: a:24!null b:25!null + │ └── columns: uniq_overlaps_pk.a:24!null uniq_overlaps_pk.b:25!null └── filters - ├── k:22 = a:24 - └── v:23 != b:25 + ├── a:22 = uniq_overlaps_pk.a:24 + └── b:23 != uniq_overlaps_pk.b:25 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # column. @@ -836,22 +836,22 @@ INSERT INTO uniq_overlaps_pk VALUES (100, 10, 1, 1), (200, 20, 2, 2) ON CONFLICT upsert uniq_overlaps_pk ├── columns: ├── arbiter constraints: unique_a - ├── canary column: a:10 - ├── fetch columns: a:10 b:11 c:12 d:13 + ├── canary column: uniq_overlaps_pk.a:10 + ├── fetch columns: uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 ├── insert-mapping: - │ ├── column1:6 => a:1 - │ ├── column2:7 => b:2 - │ ├── column3:8 => c:3 - │ └── column4:9 => d:4 + │ ├── column1:6 => uniq_overlaps_pk.a:1 + │ ├── column2:7 => uniq_overlaps_pk.b:2 + │ ├── column3:8 => uniq_overlaps_pk.c:3 + │ └── column4:9 => uniq_overlaps_pk.d:4 ├── update-mapping: - │ └── upsert_a:16 => a:1 + │ └── upsert_a:16 => uniq_overlaps_pk.a:1 ├── input binding: &1 ├── project - │ ├── columns: upsert_a:16!null upsert_b:17 upsert_c:18 upsert_d:19 column1:6!null column2:7!null column3:8!null column4:9!null a:10 b:11 c:12 d:13 crdb_internal_mvcc_timestamp:14 a_new:15!null + │ ├── columns: upsert_a:16!null upsert_b:17 upsert_c:18 upsert_d:19 column1:6!null column2:7!null column3:8!null column4:9!null uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 a_new:15!null │ ├── project - │ │ ├── columns: a_new:15!null column1:6!null column2:7!null column3:8!null column4:9!null a:10 b:11 c:12 d:13 crdb_internal_mvcc_timestamp:14 + │ │ ├── columns: a_new:15!null column1:6!null column2:7!null column3:8!null column4:9!null uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null a:10 b:11 c:12 d:13 crdb_internal_mvcc_timestamp:14 + │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null │ │ │ │ ├── grouping columns: column1:6!null @@ -867,61 +867,61 @@ upsert uniq_overlaps_pk │ │ │ │ └── first-agg [as=column4:9] │ │ │ │ └── column4:9 │ │ │ ├── scan uniq_overlaps_pk - │ │ │ │ └── columns: a:10!null b:11!null c:12 d:13 crdb_internal_mvcc_timestamp:14 + │ │ │ │ └── columns: uniq_overlaps_pk.a:10!null uniq_overlaps_pk.b:11!null uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 │ │ │ └── filters - │ │ │ └── column1:6 = a:10 + │ │ │ └── column1:6 = uniq_overlaps_pk.a:10 │ │ └── projections │ │ └── 10 [as=a_new:15] │ └── projections - │ ├── CASE WHEN a:10 IS NULL THEN column1:6 ELSE a_new:15 END [as=upsert_a:16] - │ ├── CASE WHEN a:10 IS NULL THEN column2:7 ELSE b:11 END [as=upsert_b:17] - │ ├── CASE WHEN a:10 IS NULL THEN column3:8 ELSE c:12 END [as=upsert_c:18] - │ └── CASE WHEN a:10 IS NULL THEN column4:9 ELSE d:13 END [as=upsert_d:19] + │ ├── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column1:6 ELSE a_new:15 END [as=upsert_a:16] + │ ├── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column2:7 ELSE uniq_overlaps_pk.b:11 END [as=upsert_b:17] + │ ├── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column3:8 ELSE uniq_overlaps_pk.c:12 END [as=upsert_c:18] + │ └── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column4:9 ELSE uniq_overlaps_pk.d:13 END [as=upsert_d:19] └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: upsert_b:20 upsert_c:21 upsert_a:22!null + │ ├── columns: b:20 c:21 a:22!null │ ├── with-scan &1 - │ │ ├── columns: upsert_b:20 upsert_c:21 upsert_a:22!null + │ │ ├── columns: b:20 c:21 a:22!null │ │ └── mapping: - │ │ ├── upsert_b:17 => upsert_b:20 - │ │ ├── upsert_c:18 => upsert_c:21 - │ │ └── upsert_a:16 => upsert_a:22 + │ │ ├── upsert_b:17 => b:20 + │ │ ├── upsert_c:18 => c:21 + │ │ └── upsert_a:16 => a:22 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:23!null b:24!null c:25 + │ │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 │ └── filters - │ ├── upsert_b:20 = b:24 - │ ├── upsert_c:21 = c:25 - │ └── upsert_a:22 != a:23 + │ ├── b:20 = uniq_overlaps_pk.b:24 + │ ├── c:21 = uniq_overlaps_pk.c:25 + │ └── a:22 != uniq_overlaps_pk.a:23 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: upsert_a:28!null upsert_b:29 + │ ├── columns: a:28!null b:29 │ ├── with-scan &1 - │ │ ├── columns: upsert_a:28!null upsert_b:29 + │ │ ├── columns: a:28!null b:29 │ │ └── mapping: - │ │ ├── upsert_a:16 => upsert_a:28 - │ │ └── upsert_b:17 => upsert_b:29 + │ │ ├── upsert_a:16 => a:28 + │ │ └── upsert_b:17 => b:29 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:30!null b:31!null + │ │ └── columns: uniq_overlaps_pk.a:30!null uniq_overlaps_pk.b:31!null │ └── filters - │ ├── upsert_a:28 = a:30 - │ └── upsert_b:29 != b:31 + │ ├── a:28 = uniq_overlaps_pk.a:30 + │ └── b:29 != uniq_overlaps_pk.b:31 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: upsert_c:35 upsert_d:36 upsert_a:37!null upsert_b:38 + ├── columns: c:35 d:36 a:37!null b:38 ├── with-scan &1 - │ ├── columns: upsert_c:35 upsert_d:36 upsert_a:37!null upsert_b:38 + │ ├── columns: c:35 d:36 a:37!null b:38 │ └── mapping: - │ ├── upsert_c:18 => upsert_c:35 - │ ├── upsert_d:19 => upsert_d:36 - │ ├── upsert_a:16 => upsert_a:37 - │ └── upsert_b:17 => upsert_b:38 + │ ├── upsert_c:18 => c:35 + │ ├── upsert_d:19 => d:36 + │ ├── upsert_a:16 => a:37 + │ └── upsert_b:17 => b:38 ├── scan uniq_overlaps_pk - │ └── columns: a:39!null b:40!null c:41 d:42 + │ └── columns: uniq_overlaps_pk.a:39!null uniq_overlaps_pk.b:40!null uniq_overlaps_pk.c:41 uniq_overlaps_pk.d:42 └── filters - ├── upsert_c:35 = c:41 - ├── upsert_d:36 = d:42 - └── (upsert_a:37 != a:39) OR (upsert_b:38 != b:40) + ├── c:35 = uniq_overlaps_pk.c:41 + ├── d:36 = uniq_overlaps_pk.d:42 + └── (a:37 != uniq_overlaps_pk.a:39) OR (b:38 != uniq_overlaps_pk.b:40) # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -931,22 +931,22 @@ INSERT INTO uniq_overlaps_pk VALUES (1, 2, 3, 4) ON CONFLICT (c, d) DO UPDATE SE upsert uniq_overlaps_pk ├── columns: ├── arbiter constraints: unique_c_d - ├── canary column: a:10 - ├── fetch columns: a:10 b:11 c:12 d:13 + ├── canary column: uniq_overlaps_pk.a:10 + ├── fetch columns: uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 ├── insert-mapping: - │ ├── column1:6 => a:1 - │ ├── column2:7 => b:2 - │ ├── column3:8 => c:3 - │ └── column4:9 => d:4 + │ ├── column1:6 => uniq_overlaps_pk.a:1 + │ ├── column2:7 => uniq_overlaps_pk.b:2 + │ ├── column3:8 => uniq_overlaps_pk.c:3 + │ └── column4:9 => uniq_overlaps_pk.d:4 ├── update-mapping: - │ └── upsert_b:17 => b:2 + │ └── upsert_b:17 => uniq_overlaps_pk.b:2 ├── input binding: &1 ├── project - │ ├── columns: upsert_a:16 upsert_b:17!null upsert_c:18 upsert_d:19 column1:6!null column2:7!null column3:8!null column4:9!null a:10 b:11 c:12 d:13 crdb_internal_mvcc_timestamp:14 b_new:15!null + │ ├── columns: upsert_a:16 upsert_b:17!null upsert_c:18 upsert_d:19 column1:6!null column2:7!null column3:8!null column4:9!null uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 b_new:15!null │ ├── project - │ │ ├── columns: b_new:15!null column1:6!null column2:7!null column3:8!null column4:9!null a:10 b:11 c:12 d:13 crdb_internal_mvcc_timestamp:14 + │ │ ├── columns: b_new:15!null column1:6!null column2:7!null column3:8!null column4:9!null uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null a:10 b:11 c:12 d:13 crdb_internal_mvcc_timestamp:14 + │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null uniq_overlaps_pk.a:10 uniq_overlaps_pk.b:11 uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null │ │ │ │ ├── grouping columns: column3:8!null column4:9!null @@ -959,62 +959,62 @@ upsert uniq_overlaps_pk │ │ │ │ └── first-agg [as=column2:7] │ │ │ │ └── column2:7 │ │ │ ├── scan uniq_overlaps_pk - │ │ │ │ └── columns: a:10!null b:11!null c:12 d:13 crdb_internal_mvcc_timestamp:14 + │ │ │ │ └── columns: uniq_overlaps_pk.a:10!null uniq_overlaps_pk.b:11!null uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 crdb_internal_mvcc_timestamp:14 │ │ │ └── filters - │ │ │ ├── column3:8 = c:12 - │ │ │ └── column4:9 = d:13 + │ │ │ ├── column3:8 = uniq_overlaps_pk.c:12 + │ │ │ └── column4:9 = uniq_overlaps_pk.d:13 │ │ └── projections │ │ └── 10 [as=b_new:15] │ └── projections - │ ├── CASE WHEN a:10 IS NULL THEN column1:6 ELSE a:10 END [as=upsert_a:16] - │ ├── CASE WHEN a:10 IS NULL THEN column2:7 ELSE b_new:15 END [as=upsert_b:17] - │ ├── CASE WHEN a:10 IS NULL THEN column3:8 ELSE c:12 END [as=upsert_c:18] - │ └── CASE WHEN a:10 IS NULL THEN column4:9 ELSE d:13 END [as=upsert_d:19] + │ ├── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column1:6 ELSE uniq_overlaps_pk.a:10 END [as=upsert_a:16] + │ ├── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column2:7 ELSE b_new:15 END [as=upsert_b:17] + │ ├── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column3:8 ELSE uniq_overlaps_pk.c:12 END [as=upsert_c:18] + │ └── CASE WHEN uniq_overlaps_pk.a:10 IS NULL THEN column4:9 ELSE uniq_overlaps_pk.d:13 END [as=upsert_d:19] └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: upsert_b:20!null upsert_c:21 upsert_a:22 + │ ├── columns: b:20!null c:21 a:22 │ ├── with-scan &1 - │ │ ├── columns: upsert_b:20!null upsert_c:21 upsert_a:22 + │ │ ├── columns: b:20!null c:21 a:22 │ │ └── mapping: - │ │ ├── upsert_b:17 => upsert_b:20 - │ │ ├── upsert_c:18 => upsert_c:21 - │ │ └── upsert_a:16 => upsert_a:22 + │ │ ├── upsert_b:17 => b:20 + │ │ ├── upsert_c:18 => c:21 + │ │ └── upsert_a:16 => a:22 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:23!null b:24!null c:25 + │ │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 │ └── filters - │ ├── upsert_b:20 = b:24 - │ ├── upsert_c:21 = c:25 - │ └── upsert_a:22 != a:23 + │ ├── b:20 = uniq_overlaps_pk.b:24 + │ ├── c:21 = uniq_overlaps_pk.c:25 + │ └── a:22 != uniq_overlaps_pk.a:23 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: upsert_a:28 upsert_b:29!null + │ ├── columns: a:28 b:29!null │ ├── with-scan &1 - │ │ ├── columns: upsert_a:28 upsert_b:29!null + │ │ ├── columns: a:28 b:29!null │ │ └── mapping: - │ │ ├── upsert_a:16 => upsert_a:28 - │ │ └── upsert_b:17 => upsert_b:29 + │ │ ├── upsert_a:16 => a:28 + │ │ └── upsert_b:17 => b:29 │ ├── scan uniq_overlaps_pk - │ │ └── columns: a:30!null b:31!null + │ │ └── columns: uniq_overlaps_pk.a:30!null uniq_overlaps_pk.b:31!null │ └── filters - │ ├── upsert_a:28 = a:30 - │ └── upsert_b:29 != b:31 + │ ├── a:28 = uniq_overlaps_pk.a:30 + │ └── b:29 != uniq_overlaps_pk.b:31 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: upsert_c:35 upsert_d:36 upsert_a:37 upsert_b:38!null + ├── columns: c:35 d:36 a:37 b:38!null ├── with-scan &1 - │ ├── columns: upsert_c:35 upsert_d:36 upsert_a:37 upsert_b:38!null + │ ├── columns: c:35 d:36 a:37 b:38!null │ └── mapping: - │ ├── upsert_c:18 => upsert_c:35 - │ ├── upsert_d:19 => upsert_d:36 - │ ├── upsert_a:16 => upsert_a:37 - │ └── upsert_b:17 => upsert_b:38 + │ ├── upsert_c:18 => c:35 + │ ├── upsert_d:19 => d:36 + │ ├── upsert_a:16 => a:37 + │ └── upsert_b:17 => b:38 ├── scan uniq_overlaps_pk - │ └── columns: a:39!null b:40!null c:41 d:42 + │ └── columns: uniq_overlaps_pk.a:39!null uniq_overlaps_pk.b:40!null uniq_overlaps_pk.c:41 uniq_overlaps_pk.d:42 └── filters - ├── upsert_c:35 = c:41 - ├── upsert_d:36 = d:42 - └── (upsert_a:37 != a:39) OR (upsert_b:38 != b:40) + ├── c:35 = uniq_overlaps_pk.c:41 + ├── d:36 = uniq_overlaps_pk.d:42 + └── (a:37 != uniq_overlaps_pk.a:39) OR (b:38 != uniq_overlaps_pk.b:40) exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -1036,23 +1036,23 @@ UPSERT INTO uniq_hidden_pk (a, b, d) VALUES (1, 1, 1), (2, 2, 2) upsert uniq_hidden_pk ├── columns: ├── arbiter indexes: primary - ├── canary column: rowid:16 - ├── fetch columns: a:12 b:13 c:14 d:15 rowid:16 + ├── canary column: uniq_hidden_pk.rowid:16 + ├── fetch columns: uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 ├── insert-mapping: - │ ├── column1:7 => a:1 - │ ├── column2:8 => b:2 - │ ├── column10:10 => c:3 - │ ├── column3:9 => d:4 - │ └── column11:11 => rowid:5 + │ ├── column1:7 => uniq_hidden_pk.a:1 + │ ├── column2:8 => uniq_hidden_pk.b:2 + │ ├── column10:10 => uniq_hidden_pk.c:3 + │ ├── column3:9 => uniq_hidden_pk.d:4 + │ └── column11:11 => uniq_hidden_pk.rowid:5 ├── update-mapping: - │ ├── column1:7 => a:1 - │ ├── column2:8 => b:2 - │ └── column3:9 => d:4 + │ ├── column1:7 => uniq_hidden_pk.a:1 + │ ├── column2:8 => uniq_hidden_pk.b:2 + │ └── column3:9 => uniq_hidden_pk.d:4 ├── input binding: &1 ├── project - │ ├── columns: upsert_c:18 upsert_rowid:19 column1:7!null column2:8!null column3:9!null column10:10 column11:11 a:12 b:13 c:14 d:15 rowid:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_c:18 upsert_rowid:19 column1:7!null column2:8!null column3:9!null column10:10 column11:11 uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11 a:12 b:13 c:14 d:15 rowid:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11 uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11 │ │ │ ├── grouping columns: column11:11 @@ -1075,58 +1075,58 @@ upsert uniq_hidden_pk │ │ │ └── first-agg [as=column10:10] │ │ │ └── column10:10 │ │ ├── scan uniq_hidden_pk - │ │ │ └── columns: a:12 b:13 c:14 d:15 rowid:16!null crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16!null crdb_internal_mvcc_timestamp:17 │ │ └── filters - │ │ └── column11:11 = rowid:16 + │ │ └── column11:11 = uniq_hidden_pk.rowid:16 │ └── projections - │ ├── CASE WHEN rowid:16 IS NULL THEN column10:10 ELSE c:14 END [as=upsert_c:18] - │ └── CASE WHEN rowid:16 IS NULL THEN column11:11 ELSE rowid:16 END [as=upsert_rowid:19] + │ ├── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column10:10 ELSE uniq_hidden_pk.c:14 END [as=upsert_c:18] + │ └── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column11:11 ELSE uniq_hidden_pk.rowid:16 END [as=upsert_rowid:19] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: column2:20!null upsert_c:21 upsert_rowid:22 + │ ├── columns: b:20!null c:21 rowid:22 │ ├── with-scan &1 - │ │ ├── columns: column2:20!null upsert_c:21 upsert_rowid:22 + │ │ ├── columns: b:20!null c:21 rowid:22 │ │ └── mapping: - │ │ ├── column2:8 => column2:20 - │ │ ├── upsert_c:18 => upsert_c:21 - │ │ └── upsert_rowid:19 => upsert_rowid:22 + │ │ ├── column2:8 => b:20 + │ │ ├── upsert_c:18 => c:21 + │ │ └── upsert_rowid:19 => rowid:22 │ ├── scan uniq_hidden_pk - │ │ └── columns: b:24 c:25 rowid:27!null + │ │ └── columns: uniq_hidden_pk.b:24 uniq_hidden_pk.c:25 uniq_hidden_pk.rowid:27!null │ └── filters - │ ├── column2:20 = b:24 - │ ├── upsert_c:21 = c:25 - │ └── upsert_rowid:22 != rowid:27 + │ ├── b:20 = uniq_hidden_pk.b:24 + │ ├── c:21 = uniq_hidden_pk.c:25 + │ └── rowid:22 != uniq_hidden_pk.rowid:27 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: column1:29!null column2:30!null column3:31!null upsert_rowid:32 + │ ├── columns: a:29!null b:30!null d:31!null rowid:32 │ ├── with-scan &1 - │ │ ├── columns: column1:29!null column2:30!null column3:31!null upsert_rowid:32 + │ │ ├── columns: a:29!null b:30!null d:31!null rowid:32 │ │ └── mapping: - │ │ ├── column1:7 => column1:29 - │ │ ├── column2:8 => column2:30 - │ │ ├── column3:9 => column3:31 - │ │ └── upsert_rowid:19 => upsert_rowid:32 + │ │ ├── column1:7 => a:29 + │ │ ├── column2:8 => b:30 + │ │ ├── column3:9 => d:31 + │ │ └── upsert_rowid:19 => rowid:32 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:33 b:34 d:36 rowid:37!null + │ │ └── columns: uniq_hidden_pk.a:33 uniq_hidden_pk.b:34 uniq_hidden_pk.d:36 uniq_hidden_pk.rowid:37!null │ └── filters - │ ├── column1:29 = a:33 - │ ├── column2:30 = b:34 - │ ├── column3:31 = d:36 - │ └── upsert_rowid:32 != rowid:37 + │ ├── a:29 = uniq_hidden_pk.a:33 + │ ├── b:30 = uniq_hidden_pk.b:34 + │ ├── d:31 = uniq_hidden_pk.d:36 + │ └── rowid:32 != uniq_hidden_pk.rowid:37 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: column1:39!null upsert_rowid:40 + ├── columns: a:39!null rowid:40 ├── with-scan &1 - │ ├── columns: column1:39!null upsert_rowid:40 + │ ├── columns: a:39!null rowid:40 │ └── mapping: - │ ├── column1:7 => column1:39 - │ └── upsert_rowid:19 => upsert_rowid:40 + │ ├── column1:7 => a:39 + │ └── upsert_rowid:19 => rowid:40 ├── scan uniq_hidden_pk - │ └── columns: a:41 rowid:45!null + │ └── columns: uniq_hidden_pk.a:41 uniq_hidden_pk.rowid:45!null └── filters - ├── column1:39 = a:41 - └── upsert_rowid:40 != rowid:45 + ├── a:39 = uniq_hidden_pk.a:41 + └── rowid:40 != uniq_hidden_pk.rowid:45 # Upsert with non-constant input. # Add inequality filters for the hidden primary key column. @@ -1136,66 +1136,66 @@ UPSERT INTO uniq_hidden_pk SELECT k, v, x, y FROM other upsert uniq_hidden_pk ├── columns: ├── upsert-mapping: - │ ├── other.k:7 => a:1 - │ ├── other.v:8 => b:2 - │ ├── other.x:10 => c:3 - │ ├── other.y:11 => d:4 + │ ├── k:7 => uniq_hidden_pk.a:1 + │ ├── v:8 => uniq_hidden_pk.b:2 + │ ├── x:10 => uniq_hidden_pk.c:3 + │ ├── y:11 => uniq_hidden_pk.d:4 │ └── column14:14 => uniq_hidden_pk.rowid:5 ├── input binding: &1 ├── project - │ ├── columns: column14:14 other.k:7 other.v:8 other.x:10 other.y:11 + │ ├── columns: column14:14 k:7 v:8 x:10 y:11 │ ├── project - │ │ ├── columns: other.k:7 other.v:8 other.x:10 other.y:11 + │ │ ├── columns: k:7 v:8 x:10 y:11 │ │ └── scan other - │ │ └── columns: other.k:7 other.v:8 w:9!null other.x:10 other.y:11 other.rowid:12!null other.crdb_internal_mvcc_timestamp:13 + │ │ └── columns: k:7 v:8 w:9!null x:10 y:11 other.rowid:12!null other.crdb_internal_mvcc_timestamp:13 │ └── projections │ └── unique_rowid() [as=column14:14] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: v:15 x:16 column14:17 + │ ├── columns: b:15 c:16 rowid:17 │ ├── with-scan &1 - │ │ ├── columns: v:15 x:16 column14:17 + │ │ ├── columns: b:15 c:16 rowid:17 │ │ └── mapping: - │ │ ├── other.v:8 => v:15 - │ │ ├── other.x:10 => x:16 - │ │ └── column14:14 => column14:17 + │ │ ├── v:8 => b:15 + │ │ ├── x:10 => c:16 + │ │ └── column14:14 => rowid:17 │ ├── scan uniq_hidden_pk - │ │ └── columns: b:19 c:20 uniq_hidden_pk.rowid:22!null + │ │ └── columns: uniq_hidden_pk.b:19 uniq_hidden_pk.c:20 uniq_hidden_pk.rowid:22!null │ └── filters - │ ├── v:15 = b:19 - │ ├── x:16 = c:20 - │ └── column14:17 != uniq_hidden_pk.rowid:22 + │ ├── b:15 = uniq_hidden_pk.b:19 + │ ├── c:16 = uniq_hidden_pk.c:20 + │ └── rowid:17 != uniq_hidden_pk.rowid:22 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: k:24 v:25 y:26 column14:27 + │ ├── columns: a:24 b:25 d:26 rowid:27 │ ├── with-scan &1 - │ │ ├── columns: k:24 v:25 y:26 column14:27 + │ │ ├── columns: a:24 b:25 d:26 rowid:27 │ │ └── mapping: - │ │ ├── other.k:7 => k:24 - │ │ ├── other.v:8 => v:25 - │ │ ├── other.y:11 => y:26 - │ │ └── column14:14 => column14:27 + │ │ ├── k:7 => a:24 + │ │ ├── v:8 => b:25 + │ │ ├── y:11 => d:26 + │ │ └── column14:14 => rowid:27 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:28 b:29 d:31 uniq_hidden_pk.rowid:32!null + │ │ └── columns: uniq_hidden_pk.a:28 uniq_hidden_pk.b:29 uniq_hidden_pk.d:31 uniq_hidden_pk.rowid:32!null │ └── filters - │ ├── k:24 = a:28 - │ ├── v:25 = b:29 - │ ├── y:26 = d:31 - │ └── column14:27 != uniq_hidden_pk.rowid:32 + │ ├── a:24 = uniq_hidden_pk.a:28 + │ ├── b:25 = uniq_hidden_pk.b:29 + │ ├── d:26 = uniq_hidden_pk.d:31 + │ └── rowid:27 != uniq_hidden_pk.rowid:32 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: k:34 column14:35 + ├── columns: a:34 rowid:35 ├── with-scan &1 - │ ├── columns: k:34 column14:35 + │ ├── columns: a:34 rowid:35 │ └── mapping: - │ ├── other.k:7 => k:34 - │ └── column14:14 => column14:35 + │ ├── k:7 => a:34 + │ └── column14:14 => rowid:35 ├── scan uniq_hidden_pk - │ └── columns: a:36 uniq_hidden_pk.rowid:40!null + │ └── columns: uniq_hidden_pk.a:36 uniq_hidden_pk.rowid:40!null └── filters - ├── k:34 = a:36 - └── column14:35 != uniq_hidden_pk.rowid:40 + ├── a:34 = uniq_hidden_pk.a:36 + └── rowid:35 != uniq_hidden_pk.rowid:40 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -1205,23 +1205,23 @@ INSERT INTO uniq_hidden_pk VALUES (1, 2, 3, 4) ON CONFLICT (a, b, d) DO UPDATE S upsert uniq_hidden_pk ├── columns: ├── arbiter constraints: unique_a_b_d - ├── canary column: rowid:16 - ├── fetch columns: a:12 b:13 c:14 d:15 rowid:16 + ├── canary column: uniq_hidden_pk.rowid:16 + ├── fetch columns: uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 ├── insert-mapping: - │ ├── column1:7 => a:1 - │ ├── column2:8 => b:2 - │ ├── column3:9 => c:3 - │ ├── column4:10 => d:4 - │ └── column11:11 => rowid:5 + │ ├── column1:7 => uniq_hidden_pk.a:1 + │ ├── column2:8 => uniq_hidden_pk.b:2 + │ ├── column3:9 => uniq_hidden_pk.c:3 + │ ├── column4:10 => uniq_hidden_pk.d:4 + │ └── column11:11 => uniq_hidden_pk.rowid:5 ├── update-mapping: - │ └── upsert_a:19 => a:1 + │ └── upsert_a:19 => uniq_hidden_pk.a:1 ├── input binding: &1 ├── project - │ ├── columns: upsert_a:19!null upsert_b:20 upsert_c:21 upsert_d:22 upsert_rowid:23 column1:7!null column2:8!null column3:9!null column4:10!null column11:11 a:12 b:13 c:14 d:15 rowid:16 crdb_internal_mvcc_timestamp:17 a_new:18!null + │ ├── columns: upsert_a:19!null upsert_b:20 upsert_c:21 upsert_d:22 upsert_rowid:23 column1:7!null column2:8!null column3:9!null column4:10!null column11:11 uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 crdb_internal_mvcc_timestamp:17 a_new:18!null │ ├── project - │ │ ├── columns: a_new:18!null column1:7!null column2:8!null column3:9!null column4:10!null column11:11 a:12 b:13 c:14 d:15 rowid:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: a_new:18!null column1:7!null column2:8!null column3:9!null column4:10!null column11:11 uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 crdb_internal_mvcc_timestamp:17 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column11:11 a:12 b:13 c:14 d:15 rowid:16 crdb_internal_mvcc_timestamp:17 + │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column11:11 uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16 crdb_internal_mvcc_timestamp:17 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column11:11 │ │ │ │ ├── grouping columns: column1:7!null column2:8!null column4:10!null @@ -1238,65 +1238,65 @@ upsert uniq_hidden_pk │ │ │ │ └── first-agg [as=column11:11] │ │ │ │ └── column11:11 │ │ │ ├── scan uniq_hidden_pk - │ │ │ │ └── columns: a:12 b:13 c:14 d:15 rowid:16!null crdb_internal_mvcc_timestamp:17 + │ │ │ │ └── columns: uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16!null crdb_internal_mvcc_timestamp:17 │ │ │ └── filters - │ │ │ ├── column1:7 = a:12 - │ │ │ ├── column2:8 = b:13 - │ │ │ └── column4:10 = d:15 + │ │ │ ├── column1:7 = uniq_hidden_pk.a:12 + │ │ │ ├── column2:8 = uniq_hidden_pk.b:13 + │ │ │ └── column4:10 = uniq_hidden_pk.d:15 │ │ └── projections │ │ └── 10 [as=a_new:18] │ └── projections - │ ├── CASE WHEN rowid:16 IS NULL THEN column1:7 ELSE a_new:18 END [as=upsert_a:19] - │ ├── CASE WHEN rowid:16 IS NULL THEN column2:8 ELSE b:13 END [as=upsert_b:20] - │ ├── CASE WHEN rowid:16 IS NULL THEN column3:9 ELSE c:14 END [as=upsert_c:21] - │ ├── CASE WHEN rowid:16 IS NULL THEN column4:10 ELSE d:15 END [as=upsert_d:22] - │ └── CASE WHEN rowid:16 IS NULL THEN column11:11 ELSE rowid:16 END [as=upsert_rowid:23] + │ ├── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column1:7 ELSE a_new:18 END [as=upsert_a:19] + │ ├── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column2:8 ELSE uniq_hidden_pk.b:13 END [as=upsert_b:20] + │ ├── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column3:9 ELSE uniq_hidden_pk.c:14 END [as=upsert_c:21] + │ ├── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column4:10 ELSE uniq_hidden_pk.d:15 END [as=upsert_d:22] + │ └── CASE WHEN uniq_hidden_pk.rowid:16 IS NULL THEN column11:11 ELSE uniq_hidden_pk.rowid:16 END [as=upsert_rowid:23] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: upsert_b:24 upsert_c:25 upsert_rowid:26 + │ ├── columns: b:24 c:25 rowid:26 │ ├── with-scan &1 - │ │ ├── columns: upsert_b:24 upsert_c:25 upsert_rowid:26 + │ │ ├── columns: b:24 c:25 rowid:26 │ │ └── mapping: - │ │ ├── upsert_b:20 => upsert_b:24 - │ │ ├── upsert_c:21 => upsert_c:25 - │ │ └── upsert_rowid:23 => upsert_rowid:26 + │ │ ├── upsert_b:20 => b:24 + │ │ ├── upsert_c:21 => c:25 + │ │ └── upsert_rowid:23 => rowid:26 │ ├── scan uniq_hidden_pk - │ │ └── columns: b:28 c:29 rowid:31!null + │ │ └── columns: uniq_hidden_pk.b:28 uniq_hidden_pk.c:29 uniq_hidden_pk.rowid:31!null │ └── filters - │ ├── upsert_b:24 = b:28 - │ ├── upsert_c:25 = c:29 - │ └── upsert_rowid:26 != rowid:31 + │ ├── b:24 = uniq_hidden_pk.b:28 + │ ├── c:25 = uniq_hidden_pk.c:29 + │ └── rowid:26 != uniq_hidden_pk.rowid:31 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: upsert_a:33!null upsert_b:34 upsert_d:35 upsert_rowid:36 + │ ├── columns: a:33!null b:34 d:35 rowid:36 │ ├── with-scan &1 - │ │ ├── columns: upsert_a:33!null upsert_b:34 upsert_d:35 upsert_rowid:36 + │ │ ├── columns: a:33!null b:34 d:35 rowid:36 │ │ └── mapping: - │ │ ├── upsert_a:19 => upsert_a:33 - │ │ ├── upsert_b:20 => upsert_b:34 - │ │ ├── upsert_d:22 => upsert_d:35 - │ │ └── upsert_rowid:23 => upsert_rowid:36 + │ │ ├── upsert_a:19 => a:33 + │ │ ├── upsert_b:20 => b:34 + │ │ ├── upsert_d:22 => d:35 + │ │ └── upsert_rowid:23 => rowid:36 │ ├── scan uniq_hidden_pk - │ │ └── columns: a:37 b:38 d:40 rowid:41!null + │ │ └── columns: uniq_hidden_pk.a:37 uniq_hidden_pk.b:38 uniq_hidden_pk.d:40 uniq_hidden_pk.rowid:41!null │ └── filters - │ ├── upsert_a:33 = a:37 - │ ├── upsert_b:34 = b:38 - │ ├── upsert_d:35 = d:40 - │ └── upsert_rowid:36 != rowid:41 + │ ├── a:33 = uniq_hidden_pk.a:37 + │ ├── b:34 = uniq_hidden_pk.b:38 + │ ├── d:35 = uniq_hidden_pk.d:40 + │ └── rowid:36 != uniq_hidden_pk.rowid:41 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: upsert_a:43!null upsert_rowid:44 + ├── columns: a:43!null rowid:44 ├── with-scan &1 - │ ├── columns: upsert_a:43!null upsert_rowid:44 + │ ├── columns: a:43!null rowid:44 │ └── mapping: - │ ├── upsert_a:19 => upsert_a:43 - │ └── upsert_rowid:23 => upsert_rowid:44 + │ ├── upsert_a:19 => a:43 + │ └── upsert_rowid:23 => rowid:44 ├── scan uniq_hidden_pk - │ └── columns: a:45 rowid:49!null + │ └── columns: uniq_hidden_pk.a:45 uniq_hidden_pk.rowid:49!null └── filters - ├── upsert_a:43 = a:45 - └── upsert_rowid:44 != rowid:49 + ├── a:43 = uniq_hidden_pk.a:45 + └── rowid:44 != uniq_hidden_pk.rowid:49 exec-ddl CREATE TABLE uniq_fk_parent ( @@ -1324,18 +1324,18 @@ UPSERT INTO uniq_fk_parent (a) VALUES (1) upsert uniq_fk_parent ├── columns: ├── arbiter indexes: primary - ├── canary column: rowid:7 - ├── fetch columns: uniq_fk_parent.a:6 rowid:7 + ├── canary column: uniq_fk_parent.rowid:7 + ├── fetch columns: uniq_fk_parent.a:6 uniq_fk_parent.rowid:7 ├── insert-mapping: │ ├── column1:4 => uniq_fk_parent.a:1 - │ └── column5:5 => rowid:2 + │ └── column5:5 => uniq_fk_parent.rowid:2 ├── update-mapping: │ └── column1:4 => uniq_fk_parent.a:1 ├── input binding: &1 ├── project - │ ├── columns: upsert_rowid:9 column1:4!null column5:5 uniq_fk_parent.a:6 rowid:7 uniq_fk_parent.crdb_internal_mvcc_timestamp:8 + │ ├── columns: upsert_rowid:9 column1:4!null column5:5 uniq_fk_parent.a:6 uniq_fk_parent.rowid:7 uniq_fk_parent.crdb_internal_mvcc_timestamp:8 │ ├── left-join (hash) - │ │ ├── columns: column1:4!null column5:5 uniq_fk_parent.a:6 rowid:7 uniq_fk_parent.crdb_internal_mvcc_timestamp:8 + │ │ ├── columns: column1:4!null column5:5 uniq_fk_parent.a:6 uniq_fk_parent.rowid:7 uniq_fk_parent.crdb_internal_mvcc_timestamp:8 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:4!null column5:5 │ │ │ ├── grouping columns: column5:5 @@ -1350,25 +1350,25 @@ upsert uniq_fk_parent │ │ │ └── first-agg [as=column1:4] │ │ │ └── column1:4 │ │ ├── scan uniq_fk_parent - │ │ │ └── columns: uniq_fk_parent.a:6 rowid:7!null uniq_fk_parent.crdb_internal_mvcc_timestamp:8 + │ │ │ └── columns: uniq_fk_parent.a:6 uniq_fk_parent.rowid:7!null uniq_fk_parent.crdb_internal_mvcc_timestamp:8 │ │ └── filters - │ │ └── column5:5 = rowid:7 + │ │ └── column5:5 = uniq_fk_parent.rowid:7 │ └── projections - │ └── CASE WHEN rowid:7 IS NULL THEN column5:5 ELSE rowid:7 END [as=upsert_rowid:9] + │ └── CASE WHEN uniq_fk_parent.rowid:7 IS NULL THEN column5:5 ELSE uniq_fk_parent.rowid:7 END [as=upsert_rowid:9] ├── unique-checks │ └── unique-checks-item: uniq_fk_parent(a) │ └── semi-join (hash) - │ ├── columns: column1:10!null upsert_rowid:11 + │ ├── columns: a:10!null rowid:11 │ ├── with-scan &1 - │ │ ├── columns: column1:10!null upsert_rowid:11 + │ │ ├── columns: a:10!null rowid:11 │ │ └── mapping: - │ │ ├── column1:4 => column1:10 - │ │ └── upsert_rowid:9 => upsert_rowid:11 + │ │ ├── column1:4 => a:10 + │ │ └── upsert_rowid:9 => rowid:11 │ ├── scan uniq_fk_parent - │ │ └── columns: uniq_fk_parent.a:12 rowid:13!null + │ │ └── columns: uniq_fk_parent.a:12 uniq_fk_parent.rowid:13!null │ └── filters - │ ├── column1:10 = uniq_fk_parent.a:12 - │ └── upsert_rowid:11 != rowid:13 + │ ├── a:10 = uniq_fk_parent.a:12 + │ └── rowid:11 != uniq_fk_parent.rowid:13 └── f-k-checks └── f-k-checks-item: uniq_fk_child(a) -> uniq_fk_parent(a) └── semi-join (hash) @@ -1376,15 +1376,15 @@ upsert uniq_fk_parent ├── except │ ├── columns: a:15 │ ├── left columns: a:15 - │ ├── right columns: column1:16 + │ ├── right columns: a:16 │ ├── with-scan &1 │ │ ├── columns: a:15 │ │ └── mapping: │ │ └── uniq_fk_parent.a:6 => a:15 │ └── with-scan &1 - │ ├── columns: column1:16!null + │ ├── columns: a:16!null │ └── mapping: - │ └── column1:4 => column1:16 + │ └── column1:4 => a:16 ├── scan uniq_fk_child │ └── columns: uniq_fk_child.a:18 └── filters @@ -1407,15 +1407,15 @@ upsert uniq_fk_child └── f-k-checks └── f-k-checks-item: uniq_fk_child(a) -> uniq_fk_parent(a) └── anti-join (hash) - ├── columns: column2:6!null + ├── columns: a:6!null ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: a:6!null │ └── mapping: - │ └── column2:5 => column2:6 + │ └── column2:5 => a:6 ├── scan uniq_fk_parent │ └── columns: uniq_fk_parent.a:7 └── filters - └── column2:6 = uniq_fk_parent.a:7 + └── a:6 = uniq_fk_parent.a:7 # Check that we choose the unique without index constraint as the arbiter. exec-ddl @@ -1432,24 +1432,24 @@ INSERT INTO t VALUES (1) ON CONFLICT (i) WHERE i > 0 DO UPDATE SET i = 2 upsert t ├── columns: ├── arbiter constraints: i2 - ├── canary column: rowid:7 - ├── fetch columns: i:6 rowid:7 + ├── canary column: t.rowid:7 + ├── fetch columns: t.i:6 t.rowid:7 ├── insert-mapping: - │ ├── column1:4 => i:1 - │ └── column5:5 => rowid:2 + │ ├── column1:4 => t.i:1 + │ └── column5:5 => t.rowid:2 ├── update-mapping: - │ └── upsert_i:10 => i:1 + │ └── upsert_i:10 => t.i:1 ├── partial index put columns: partial_index_put1:12 ├── partial index del columns: partial_index_del1:13 ├── input binding: &1 ├── project - │ ├── columns: partial_index_put1:12!null partial_index_del1:13 column1:4!null column5:5 i:6 rowid:7 crdb_internal_mvcc_timestamp:8 i_new:9!null upsert_i:10!null upsert_rowid:11 + │ ├── columns: partial_index_put1:12!null partial_index_del1:13 column1:4!null column5:5 t.i:6 t.rowid:7 crdb_internal_mvcc_timestamp:8 i_new:9!null upsert_i:10!null upsert_rowid:11 │ ├── project - │ │ ├── columns: upsert_i:10!null upsert_rowid:11 column1:4!null column5:5 i:6 rowid:7 crdb_internal_mvcc_timestamp:8 i_new:9!null + │ │ ├── columns: upsert_i:10!null upsert_rowid:11 column1:4!null column5:5 t.i:6 t.rowid:7 crdb_internal_mvcc_timestamp:8 i_new:9!null │ │ ├── project - │ │ │ ├── columns: i_new:9!null column1:4!null column5:5 i:6 rowid:7 crdb_internal_mvcc_timestamp:8 + │ │ │ ├── columns: i_new:9!null column1:4!null column5:5 t.i:6 t.rowid:7 crdb_internal_mvcc_timestamp:8 │ │ │ ├── left-join (hash) - │ │ │ │ ├── columns: column1:4!null column5:5 i:6 rowid:7 crdb_internal_mvcc_timestamp:8 + │ │ │ │ ├── columns: column1:4!null column5:5 t.i:6 t.rowid:7 crdb_internal_mvcc_timestamp:8 │ │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ │ ├── columns: column1:4!null column5:5 │ │ │ │ │ ├── grouping columns: column1:4!null @@ -1464,34 +1464,34 @@ upsert t │ │ │ │ │ └── first-agg [as=column5:5] │ │ │ │ │ └── column5:5 │ │ │ │ ├── scan t - │ │ │ │ │ ├── columns: i:6 rowid:7!null crdb_internal_mvcc_timestamp:8 + │ │ │ │ │ ├── columns: t.i:6 t.rowid:7!null crdb_internal_mvcc_timestamp:8 │ │ │ │ │ └── partial index predicates │ │ │ │ │ └── i1: filters - │ │ │ │ │ └── i:6 > 0 + │ │ │ │ │ └── t.i:6 > 0 │ │ │ │ └── filters - │ │ │ │ └── column1:4 = i:6 + │ │ │ │ └── column1:4 = t.i:6 │ │ │ └── projections │ │ │ └── 2 [as=i_new:9] │ │ └── projections - │ │ ├── CASE WHEN rowid:7 IS NULL THEN column1:4 ELSE i_new:9 END [as=upsert_i:10] - │ │ └── CASE WHEN rowid:7 IS NULL THEN column5:5 ELSE rowid:7 END [as=upsert_rowid:11] + │ │ ├── CASE WHEN t.rowid:7 IS NULL THEN column1:4 ELSE i_new:9 END [as=upsert_i:10] + │ │ └── CASE WHEN t.rowid:7 IS NULL THEN column5:5 ELSE t.rowid:7 END [as=upsert_rowid:11] │ └── projections │ ├── upsert_i:10 > 0 [as=partial_index_put1:12] - │ └── i:6 > 0 [as=partial_index_del1:13] + │ └── t.i:6 > 0 [as=partial_index_del1:13] └── unique-checks └── unique-checks-item: t(i) └── semi-join (hash) - ├── columns: upsert_i:14!null upsert_rowid:15 + ├── columns: i:14!null rowid:15 ├── with-scan &1 - │ ├── columns: upsert_i:14!null upsert_rowid:15 + │ ├── columns: i:14!null rowid:15 │ └── mapping: - │ ├── upsert_i:10 => upsert_i:14 - │ └── upsert_rowid:11 => upsert_rowid:15 + │ ├── upsert_i:10 => i:14 + │ └── upsert_rowid:11 => rowid:15 ├── scan t - │ ├── columns: i:16 rowid:17!null + │ ├── columns: t.i:16 t.rowid:17!null │ └── partial index predicates │ └── i1: filters - │ └── i:16 > 0 + │ └── t.i:16 > 0 └── filters - ├── upsert_i:14 = i:16 - └── upsert_rowid:15 != rowid:17 + ├── i:14 = t.i:16 + └── rowid:15 != t.rowid:17 diff --git a/pkg/sql/opt/xform/testdata/coster/join b/pkg/sql/opt/xform/testdata/coster/join index 4e38c34934bf..553a3760f6de 100644 --- a/pkg/sql/opt/xform/testdata/coster/join +++ b/pkg/sql/opt/xform/testdata/coster/join @@ -793,16 +793,16 @@ insert c └── f-k-checks └── f-k-checks-item: c(p) -> p(p) └── anti-join (lookup p) - ├── columns: column2:6!null + ├── columns: p:6!null ├── key columns: [6] = [7] ├── lookup columns are key ├── cardinality: [0 - 2] ├── stats: [rows=1e-10] ├── cost: 12.08 ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ ├── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => p:6 │ ├── cardinality: [2 - 2] │ ├── stats: [rows=2, distinct(6)=2, null(6)=0] │ └── cost: 0.01 @@ -832,7 +832,7 @@ insert c └── f-k-checks └── f-k-checks-item: c(p) -> p(p) └── anti-join (lookup p) - ├── columns: column2:6!null + ├── columns: p:6!null ├── flags: prefer lookup join (into right side) ├── key columns: [6] = [7] ├── lookup columns are key @@ -840,9 +840,9 @@ insert c ├── stats: [rows=1e-10] ├── cost: 0.02001206 ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ ├── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => p:6 │ ├── cardinality: [2 - 2] │ ├── stats: [rows=2, distinct(6)=2, null(6)=0] │ └── cost: 0.01 @@ -885,7 +885,7 @@ insert c └── f-k-checks └── f-k-checks-item: c(p) -> p(p) └── anti-join (lookup p) - ├── columns: column2:6!null + ├── columns: p:6!null ├── key columns: [6] = [7] ├── lookup columns are key ├── cardinality: [0 - 1] @@ -894,9 +894,9 @@ insert c ├── key: () ├── fd: ()-->(6) ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: p:6!null │ ├── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => p:6 │ ├── cardinality: [1 - 1] │ ├── stats: [rows=1, distinct(6)=1, null(6)=0] │ ├── cost: 0.01 diff --git a/pkg/sql/opt/xform/testdata/external/tpcc b/pkg/sql/opt/xform/testdata/external/tpcc index 9eb6621d9dfc..f99bdbcdf334 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc +++ b/pkg/sql/opt/xform/testdata/external/tpcc @@ -142,9 +142,9 @@ insert order ├── columns: ├── insert-mapping: │ ├── column1:10 => o_id:1 - │ ├── column2:11 => o_d_id:2 - │ ├── column3:12 => o_w_id:3 - │ ├── column4:13 => o_c_id:4 + │ ├── column2:11 => "order".o_d_id:2 + │ ├── column3:12 => "order".o_w_id:3 + │ ├── column4:13 => "order".o_c_id:4 │ ├── column5:14 => o_entry_d:5 │ ├── column17:17 => o_carrier_id:6 │ ├── column6:15 => o_ol_cnt:7 @@ -161,18 +161,18 @@ insert order └── f-k-checks └── f-k-checks-item: order(o_w_id,o_d_id,o_c_id) -> customer(c_w_id,c_d_id,c_id) └── anti-join (lookup customer) - ├── columns: column3:18!null column2:19!null column4:20!null + ├── columns: o_w_id:18!null o_d_id:19!null o_c_id:20!null ├── key columns: [18 19 20] = [23 22 21] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(18-20) ├── with-scan &1 - │ ├── columns: column3:18!null column2:19!null column4:20!null + │ ├── columns: o_w_id:18!null o_d_id:19!null o_c_id:20!null │ ├── mapping: - │ │ ├── column3:12 => column3:18 - │ │ ├── column2:11 => column2:19 - │ │ └── column4:13 => column4:20 + │ │ ├── column3:12 => o_w_id:18 + │ │ ├── column2:11 => o_d_id:19 + │ │ └── column4:13 => o_c_id:20 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(18-20) @@ -184,9 +184,9 @@ INSERT INTO new_order (no_o_id, no_d_id, no_w_id) VALUES (2000, 100, 10) insert new_order ├── columns: ├── insert-mapping: - │ ├── column1:5 => no_o_id:1 - │ ├── column2:6 => no_d_id:2 - │ └── column3:7 => no_w_id:3 + │ ├── column1:5 => new_order.no_o_id:1 + │ ├── column2:6 => new_order.no_d_id:2 + │ └── column3:7 => new_order.no_w_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -199,18 +199,18 @@ insert new_order └── f-k-checks └── f-k-checks-item: new_order(no_w_id,no_d_id,no_o_id) -> order(o_w_id,o_d_id,o_id) └── anti-join (lookup order) - ├── columns: column3:8!null column2:9!null column1:10!null + ├── columns: no_w_id:8!null no_d_id:9!null no_o_id:10!null ├── key columns: [8 9 10] = [13 12 11] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(8-10) ├── with-scan &1 - │ ├── columns: column3:8!null column2:9!null column1:10!null + │ ├── columns: no_w_id:8!null no_d_id:9!null no_o_id:10!null │ ├── mapping: - │ │ ├── column3:7 => column3:8 - │ │ ├── column2:6 => column2:9 - │ │ └── column1:5 => column1:10 + │ │ ├── column3:7 => no_w_id:8 + │ │ ├── column2:6 => no_d_id:9 + │ │ └── column1:5 => no_o_id:10 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(8-10) @@ -358,12 +358,12 @@ VALUES insert order_line ├── columns: ├── insert-mapping: - │ ├── column1:12 => ol_o_id:1 - │ ├── column2:13 => ol_d_id:2 - │ ├── column3:14 => ol_w_id:3 + │ ├── column1:12 => order_line.ol_o_id:1 + │ ├── column2:13 => order_line.ol_d_id:2 + │ ├── column3:14 => order_line.ol_w_id:3 │ ├── column4:15 => ol_number:4 - │ ├── column5:16 => ol_i_id:5 - │ ├── column6:17 => ol_supply_w_id:6 + │ ├── column5:16 => order_line.ol_i_id:5 + │ ├── column6:17 => order_line.ol_supply_w_id:6 │ ├── column21:21 => ol_delivery_d:7 │ ├── column7:18 => ol_quantity:8 │ ├── ol_amount:22 => order_line.ol_amount:9 @@ -391,29 +391,29 @@ insert order_line └── f-k-checks ├── f-k-checks-item: order_line(ol_w_id,ol_d_id,ol_o_id) -> order(o_w_id,o_d_id,o_id) │ └── anti-join (lookup order) - │ ├── columns: column3:23!null column2:24!null column1:25!null + │ ├── columns: ol_w_id:23!null ol_d_id:24!null ol_o_id:25!null │ ├── key columns: [23 24 25] = [28 27 26] │ ├── lookup columns are key │ ├── cardinality: [0 - 6] │ ├── with-scan &1 - │ │ ├── columns: column3:23!null column2:24!null column1:25!null + │ │ ├── columns: ol_w_id:23!null ol_d_id:24!null ol_o_id:25!null │ │ ├── mapping: - │ │ │ ├── column3:14 => column3:23 - │ │ │ ├── column2:13 => column2:24 - │ │ │ └── column1:12 => column1:25 + │ │ │ ├── column3:14 => ol_w_id:23 + │ │ │ ├── column2:13 => ol_d_id:24 + │ │ │ └── column1:12 => ol_o_id:25 │ │ └── cardinality: [6 - 6] │ └── filters (true) └── f-k-checks-item: order_line(ol_supply_w_id,ol_i_id) -> stock(s_w_id,s_i_id) └── anti-join (lookup stock) - ├── columns: column6:35!null column5:36!null + ├── columns: ol_supply_w_id:35!null ol_i_id:36!null ├── key columns: [35 36] = [38 37] ├── lookup columns are key ├── cardinality: [0 - 6] ├── with-scan &1 - │ ├── columns: column6:35!null column5:36!null + │ ├── columns: ol_supply_w_id:35!null ol_i_id:36!null │ ├── mapping: - │ │ ├── column6:17 => column6:35 - │ │ └── column5:16 => column5:36 + │ │ ├── column6:17 => ol_supply_w_id:35 + │ │ └── column5:16 => ol_i_id:36 │ └── cardinality: [6 - 6] └── filters (true) @@ -601,11 +601,11 @@ insert history ├── columns: ├── insert-mapping: │ ├── column19:19 => rowid:1 - │ ├── column1:11 => h_c_id:2 - │ ├── column2:12 => h_c_d_id:3 - │ ├── column3:13 => h_c_w_id:4 - │ ├── column4:14 => h_d_id:5 - │ ├── column5:15 => h_w_id:6 + │ ├── column1:11 => history.h_c_id:2 + │ ├── column2:12 => history.h_c_d_id:3 + │ ├── column3:13 => history.h_c_w_id:4 + │ ├── column4:14 => history.h_d_id:5 + │ ├── column5:15 => history.h_w_id:6 │ ├── column7:17 => h_date:7 │ ├── h_amount:20 => history.h_amount:8 │ └── column8:18 => h_data:9 @@ -622,35 +622,35 @@ insert history └── f-k-checks ├── f-k-checks-item: history(h_c_w_id,h_c_d_id,h_c_id) -> customer(c_w_id,c_d_id,c_id) │ └── anti-join (lookup customer) - │ ├── columns: column3:21!null column2:22!null column1:23!null + │ ├── columns: h_c_w_id:21!null h_c_d_id:22!null h_c_id:23!null │ ├── key columns: [21 22 23] = [26 25 24] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(21-23) │ ├── with-scan &1 - │ │ ├── columns: column3:21!null column2:22!null column1:23!null + │ │ ├── columns: h_c_w_id:21!null h_c_d_id:22!null h_c_id:23!null │ │ ├── mapping: - │ │ │ ├── column3:13 => column3:21 - │ │ │ ├── column2:12 => column2:22 - │ │ │ └── column1:11 => column1:23 + │ │ │ ├── column3:13 => h_c_w_id:21 + │ │ │ ├── column2:12 => h_c_d_id:22 + │ │ │ └── column1:11 => h_c_id:23 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(21-23) │ └── filters (true) └── f-k-checks-item: history(h_w_id,h_d_id) -> district(d_w_id,d_id) └── anti-join (lookup district) - ├── columns: column5:46!null column4:47!null + ├── columns: h_w_id:46!null h_d_id:47!null ├── key columns: [46 47] = [49 48] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(46,47) ├── with-scan &1 - │ ├── columns: column5:46!null column4:47!null + │ ├── columns: h_w_id:46!null h_d_id:47!null │ ├── mapping: - │ │ ├── column5:15 => column5:46 - │ │ └── column4:14 => column4:47 + │ │ ├── column5:15 => h_w_id:46 + │ │ └── column4:14 => h_d_id:47 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(46,47) diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-later-stats b/pkg/sql/opt/xform/testdata/external/tpcc-later-stats index 462109b14773..1cb4417264db 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-later-stats +++ b/pkg/sql/opt/xform/testdata/external/tpcc-later-stats @@ -145,9 +145,9 @@ insert order ├── columns: ├── insert-mapping: │ ├── column1:10 => o_id:1 - │ ├── column2:11 => o_d_id:2 - │ ├── column3:12 => o_w_id:3 - │ ├── column4:13 => o_c_id:4 + │ ├── column2:11 => "order".o_d_id:2 + │ ├── column3:12 => "order".o_w_id:3 + │ ├── column4:13 => "order".o_c_id:4 │ ├── column5:14 => o_entry_d:5 │ ├── column17:17 => o_carrier_id:6 │ ├── column6:15 => o_ol_cnt:7 @@ -164,18 +164,18 @@ insert order └── f-k-checks └── f-k-checks-item: order(o_w_id,o_d_id,o_c_id) -> customer(c_w_id,c_d_id,c_id) └── anti-join (lookup customer) - ├── columns: column3:18!null column2:19!null column4:20!null + ├── columns: o_w_id:18!null o_d_id:19!null o_c_id:20!null ├── key columns: [18 19 20] = [23 22 21] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(18-20) ├── with-scan &1 - │ ├── columns: column3:18!null column2:19!null column4:20!null + │ ├── columns: o_w_id:18!null o_d_id:19!null o_c_id:20!null │ ├── mapping: - │ │ ├── column3:12 => column3:18 - │ │ ├── column2:11 => column2:19 - │ │ └── column4:13 => column4:20 + │ │ ├── column3:12 => o_w_id:18 + │ │ ├── column2:11 => o_d_id:19 + │ │ └── column4:13 => o_c_id:20 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(18-20) @@ -187,9 +187,9 @@ INSERT INTO new_order (no_o_id, no_d_id, no_w_id) VALUES (2000, 100, 10) insert new_order ├── columns: ├── insert-mapping: - │ ├── column1:5 => no_o_id:1 - │ ├── column2:6 => no_d_id:2 - │ └── column3:7 => no_w_id:3 + │ ├── column1:5 => new_order.no_o_id:1 + │ ├── column2:6 => new_order.no_d_id:2 + │ └── column3:7 => new_order.no_w_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -202,18 +202,18 @@ insert new_order └── f-k-checks └── f-k-checks-item: new_order(no_w_id,no_d_id,no_o_id) -> order(o_w_id,o_d_id,o_id) └── anti-join (lookup order) - ├── columns: column3:8!null column2:9!null column1:10!null + ├── columns: no_w_id:8!null no_d_id:9!null no_o_id:10!null ├── key columns: [8 9 10] = [13 12 11] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(8-10) ├── with-scan &1 - │ ├── columns: column3:8!null column2:9!null column1:10!null + │ ├── columns: no_w_id:8!null no_d_id:9!null no_o_id:10!null │ ├── mapping: - │ │ ├── column3:7 => column3:8 - │ │ ├── column2:6 => column2:9 - │ │ └── column1:5 => column1:10 + │ │ ├── column3:7 => no_w_id:8 + │ │ ├── column2:6 => no_d_id:9 + │ │ └── column1:5 => no_o_id:10 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(8-10) @@ -361,12 +361,12 @@ VALUES insert order_line ├── columns: ├── insert-mapping: - │ ├── column1:12 => ol_o_id:1 - │ ├── column2:13 => ol_d_id:2 - │ ├── column3:14 => ol_w_id:3 + │ ├── column1:12 => order_line.ol_o_id:1 + │ ├── column2:13 => order_line.ol_d_id:2 + │ ├── column3:14 => order_line.ol_w_id:3 │ ├── column4:15 => ol_number:4 - │ ├── column5:16 => ol_i_id:5 - │ ├── column6:17 => ol_supply_w_id:6 + │ ├── column5:16 => order_line.ol_i_id:5 + │ ├── column6:17 => order_line.ol_supply_w_id:6 │ ├── column21:21 => ol_delivery_d:7 │ ├── column7:18 => ol_quantity:8 │ ├── ol_amount:22 => order_line.ol_amount:9 @@ -394,29 +394,29 @@ insert order_line └── f-k-checks ├── f-k-checks-item: order_line(ol_w_id,ol_d_id,ol_o_id) -> order(o_w_id,o_d_id,o_id) │ └── anti-join (lookup order) - │ ├── columns: column3:23!null column2:24!null column1:25!null + │ ├── columns: ol_w_id:23!null ol_d_id:24!null ol_o_id:25!null │ ├── key columns: [23 24 25] = [28 27 26] │ ├── lookup columns are key │ ├── cardinality: [0 - 6] │ ├── with-scan &1 - │ │ ├── columns: column3:23!null column2:24!null column1:25!null + │ │ ├── columns: ol_w_id:23!null ol_d_id:24!null ol_o_id:25!null │ │ ├── mapping: - │ │ │ ├── column3:14 => column3:23 - │ │ │ ├── column2:13 => column2:24 - │ │ │ └── column1:12 => column1:25 + │ │ │ ├── column3:14 => ol_w_id:23 + │ │ │ ├── column2:13 => ol_d_id:24 + │ │ │ └── column1:12 => ol_o_id:25 │ │ └── cardinality: [6 - 6] │ └── filters (true) └── f-k-checks-item: order_line(ol_supply_w_id,ol_i_id) -> stock(s_w_id,s_i_id) └── anti-join (lookup stock) - ├── columns: column6:35!null column5:36!null + ├── columns: ol_supply_w_id:35!null ol_i_id:36!null ├── key columns: [35 36] = [38 37] ├── lookup columns are key ├── cardinality: [0 - 6] ├── with-scan &1 - │ ├── columns: column6:35!null column5:36!null + │ ├── columns: ol_supply_w_id:35!null ol_i_id:36!null │ ├── mapping: - │ │ ├── column6:17 => column6:35 - │ │ └── column5:16 => column5:36 + │ │ ├── column6:17 => ol_supply_w_id:35 + │ │ └── column5:16 => ol_i_id:36 │ └── cardinality: [6 - 6] └── filters (true) @@ -604,11 +604,11 @@ insert history ├── columns: ├── insert-mapping: │ ├── column19:19 => rowid:1 - │ ├── column1:11 => h_c_id:2 - │ ├── column2:12 => h_c_d_id:3 - │ ├── column3:13 => h_c_w_id:4 - │ ├── column4:14 => h_d_id:5 - │ ├── column5:15 => h_w_id:6 + │ ├── column1:11 => history.h_c_id:2 + │ ├── column2:12 => history.h_c_d_id:3 + │ ├── column3:13 => history.h_c_w_id:4 + │ ├── column4:14 => history.h_d_id:5 + │ ├── column5:15 => history.h_w_id:6 │ ├── column7:17 => h_date:7 │ ├── h_amount:20 => history.h_amount:8 │ └── column8:18 => h_data:9 @@ -625,35 +625,35 @@ insert history └── f-k-checks ├── f-k-checks-item: history(h_c_w_id,h_c_d_id,h_c_id) -> customer(c_w_id,c_d_id,c_id) │ └── anti-join (lookup customer) - │ ├── columns: column3:21!null column2:22!null column1:23!null + │ ├── columns: h_c_w_id:21!null h_c_d_id:22!null h_c_id:23!null │ ├── key columns: [21 22 23] = [26 25 24] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(21-23) │ ├── with-scan &1 - │ │ ├── columns: column3:21!null column2:22!null column1:23!null + │ │ ├── columns: h_c_w_id:21!null h_c_d_id:22!null h_c_id:23!null │ │ ├── mapping: - │ │ │ ├── column3:13 => column3:21 - │ │ │ ├── column2:12 => column2:22 - │ │ │ └── column1:11 => column1:23 + │ │ │ ├── column3:13 => h_c_w_id:21 + │ │ │ ├── column2:12 => h_c_d_id:22 + │ │ │ └── column1:11 => h_c_id:23 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(21-23) │ └── filters (true) └── f-k-checks-item: history(h_w_id,h_d_id) -> district(d_w_id,d_id) └── anti-join (lookup district) - ├── columns: column5:46!null column4:47!null + ├── columns: h_w_id:46!null h_d_id:47!null ├── key columns: [46 47] = [49 48] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(46,47) ├── with-scan &1 - │ ├── columns: column5:46!null column4:47!null + │ ├── columns: h_w_id:46!null h_d_id:47!null │ ├── mapping: - │ │ ├── column5:15 => column5:46 - │ │ └── column4:14 => column4:47 + │ │ ├── column5:15 => h_w_id:46 + │ │ └── column4:14 => h_d_id:47 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(46,47) diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats index de6a19c012ab..239210500d7e 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats @@ -139,9 +139,9 @@ insert order ├── columns: ├── insert-mapping: │ ├── column1:10 => o_id:1 - │ ├── column2:11 => o_d_id:2 - │ ├── column3:12 => o_w_id:3 - │ ├── column4:13 => o_c_id:4 + │ ├── column2:11 => "order".o_d_id:2 + │ ├── column3:12 => "order".o_w_id:3 + │ ├── column4:13 => "order".o_c_id:4 │ ├── column5:14 => o_entry_d:5 │ ├── column17:17 => o_carrier_id:6 │ ├── column6:15 => o_ol_cnt:7 @@ -158,18 +158,18 @@ insert order └── f-k-checks └── f-k-checks-item: order(o_w_id,o_d_id,o_c_id) -> customer(c_w_id,c_d_id,c_id) └── anti-join (lookup customer) - ├── columns: column3:18!null column2:19!null column4:20!null + ├── columns: o_w_id:18!null o_d_id:19!null o_c_id:20!null ├── key columns: [18 19 20] = [23 22 21] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(18-20) ├── with-scan &1 - │ ├── columns: column3:18!null column2:19!null column4:20!null + │ ├── columns: o_w_id:18!null o_d_id:19!null o_c_id:20!null │ ├── mapping: - │ │ ├── column3:12 => column3:18 - │ │ ├── column2:11 => column2:19 - │ │ └── column4:13 => column4:20 + │ │ ├── column3:12 => o_w_id:18 + │ │ ├── column2:11 => o_d_id:19 + │ │ └── column4:13 => o_c_id:20 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(18-20) @@ -181,9 +181,9 @@ INSERT INTO new_order (no_o_id, no_d_id, no_w_id) VALUES (2000, 100, 10) insert new_order ├── columns: ├── insert-mapping: - │ ├── column1:5 => no_o_id:1 - │ ├── column2:6 => no_d_id:2 - │ └── column3:7 => no_w_id:3 + │ ├── column1:5 => new_order.no_o_id:1 + │ ├── column2:6 => new_order.no_d_id:2 + │ └── column3:7 => new_order.no_w_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -196,18 +196,18 @@ insert new_order └── f-k-checks └── f-k-checks-item: new_order(no_w_id,no_d_id,no_o_id) -> order(o_w_id,o_d_id,o_id) └── anti-join (lookup order) - ├── columns: column3:8!null column2:9!null column1:10!null + ├── columns: no_w_id:8!null no_d_id:9!null no_o_id:10!null ├── key columns: [8 9 10] = [13 12 11] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(8-10) ├── with-scan &1 - │ ├── columns: column3:8!null column2:9!null column1:10!null + │ ├── columns: no_w_id:8!null no_d_id:9!null no_o_id:10!null │ ├── mapping: - │ │ ├── column3:7 => column3:8 - │ │ ├── column2:6 => column2:9 - │ │ └── column1:5 => column1:10 + │ │ ├── column3:7 => no_w_id:8 + │ │ ├── column2:6 => no_d_id:9 + │ │ └── column1:5 => no_o_id:10 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(8-10) @@ -355,12 +355,12 @@ VALUES insert order_line ├── columns: ├── insert-mapping: - │ ├── column1:12 => ol_o_id:1 - │ ├── column2:13 => ol_d_id:2 - │ ├── column3:14 => ol_w_id:3 + │ ├── column1:12 => order_line.ol_o_id:1 + │ ├── column2:13 => order_line.ol_d_id:2 + │ ├── column3:14 => order_line.ol_w_id:3 │ ├── column4:15 => ol_number:4 - │ ├── column5:16 => ol_i_id:5 - │ ├── column6:17 => ol_supply_w_id:6 + │ ├── column5:16 => order_line.ol_i_id:5 + │ ├── column6:17 => order_line.ol_supply_w_id:6 │ ├── column21:21 => ol_delivery_d:7 │ ├── column7:18 => ol_quantity:8 │ ├── ol_amount:22 => order_line.ol_amount:9 @@ -388,29 +388,29 @@ insert order_line └── f-k-checks ├── f-k-checks-item: order_line(ol_w_id,ol_d_id,ol_o_id) -> order(o_w_id,o_d_id,o_id) │ └── anti-join (lookup order) - │ ├── columns: column3:23!null column2:24!null column1:25!null + │ ├── columns: ol_w_id:23!null ol_d_id:24!null ol_o_id:25!null │ ├── key columns: [23 24 25] = [28 27 26] │ ├── lookup columns are key │ ├── cardinality: [0 - 6] │ ├── with-scan &1 - │ │ ├── columns: column3:23!null column2:24!null column1:25!null + │ │ ├── columns: ol_w_id:23!null ol_d_id:24!null ol_o_id:25!null │ │ ├── mapping: - │ │ │ ├── column3:14 => column3:23 - │ │ │ ├── column2:13 => column2:24 - │ │ │ └── column1:12 => column1:25 + │ │ │ ├── column3:14 => ol_w_id:23 + │ │ │ ├── column2:13 => ol_d_id:24 + │ │ │ └── column1:12 => ol_o_id:25 │ │ └── cardinality: [6 - 6] │ └── filters (true) └── f-k-checks-item: order_line(ol_supply_w_id,ol_i_id) -> stock(s_w_id,s_i_id) └── anti-join (lookup stock) - ├── columns: column6:35!null column5:36!null + ├── columns: ol_supply_w_id:35!null ol_i_id:36!null ├── key columns: [35 36] = [38 37] ├── lookup columns are key ├── cardinality: [0 - 6] ├── with-scan &1 - │ ├── columns: column6:35!null column5:36!null + │ ├── columns: ol_supply_w_id:35!null ol_i_id:36!null │ ├── mapping: - │ │ ├── column6:17 => column6:35 - │ │ └── column5:16 => column5:36 + │ │ ├── column6:17 => ol_supply_w_id:35 + │ │ └── column5:16 => ol_i_id:36 │ └── cardinality: [6 - 6] └── filters (true) @@ -598,11 +598,11 @@ insert history ├── columns: ├── insert-mapping: │ ├── column19:19 => rowid:1 - │ ├── column1:11 => h_c_id:2 - │ ├── column2:12 => h_c_d_id:3 - │ ├── column3:13 => h_c_w_id:4 - │ ├── column4:14 => h_d_id:5 - │ ├── column5:15 => h_w_id:6 + │ ├── column1:11 => history.h_c_id:2 + │ ├── column2:12 => history.h_c_d_id:3 + │ ├── column3:13 => history.h_c_w_id:4 + │ ├── column4:14 => history.h_d_id:5 + │ ├── column5:15 => history.h_w_id:6 │ ├── column7:17 => h_date:7 │ ├── h_amount:20 => history.h_amount:8 │ └── column8:18 => h_data:9 @@ -619,35 +619,35 @@ insert history └── f-k-checks ├── f-k-checks-item: history(h_c_w_id,h_c_d_id,h_c_id) -> customer(c_w_id,c_d_id,c_id) │ └── anti-join (lookup customer) - │ ├── columns: column3:21!null column2:22!null column1:23!null + │ ├── columns: h_c_w_id:21!null h_c_d_id:22!null h_c_id:23!null │ ├── key columns: [21 22 23] = [26 25 24] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(21-23) │ ├── with-scan &1 - │ │ ├── columns: column3:21!null column2:22!null column1:23!null + │ │ ├── columns: h_c_w_id:21!null h_c_d_id:22!null h_c_id:23!null │ │ ├── mapping: - │ │ │ ├── column3:13 => column3:21 - │ │ │ ├── column2:12 => column2:22 - │ │ │ └── column1:11 => column1:23 + │ │ │ ├── column3:13 => h_c_w_id:21 + │ │ │ ├── column2:12 => h_c_d_id:22 + │ │ │ └── column1:11 => h_c_id:23 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(21-23) │ └── filters (true) └── f-k-checks-item: history(h_w_id,h_d_id) -> district(d_w_id,d_id) └── anti-join (lookup district) - ├── columns: column5:46!null column4:47!null + ├── columns: h_w_id:46!null h_d_id:47!null ├── key columns: [46 47] = [49 48] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(46,47) ├── with-scan &1 - │ ├── columns: column5:46!null column4:47!null + │ ├── columns: h_w_id:46!null h_d_id:47!null │ ├── mapping: - │ │ ├── column5:15 => column5:46 - │ │ └── column4:14 => column4:47 + │ │ ├── column5:15 => h_w_id:46 + │ │ └── column4:14 => h_d_id:47 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(46,47) diff --git a/pkg/sql/opt/xform/testdata/external/tpce b/pkg/sql/opt/xform/testdata/external/tpce index aece6458f775..ae4bc8ac593d 100644 --- a/pkg/sql/opt/xform/testdata/external/tpce +++ b/pkg/sql/opt/xform/testdata/external/tpce @@ -411,20 +411,20 @@ UPDATE trade ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:33 => t_dts:2 - │ └── t_st_id_new:34 => t_st_id:3 + │ └── t_st_id_new:34 => trade.t_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: t_dts_new:33!null t_st_id_new:34!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: t_dts_new:33!null t_st_id_new:34!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,33,34) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -435,16 +435,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:40!null + ├── columns: t_st_id:40!null ├── key columns: [40] = [41] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(40) ├── with-scan &1 - │ ├── columns: t_st_id_new:40!null + │ ├── columns: t_st_id:40!null │ ├── mapping: - │ │ └── t_st_id_new:34 => t_st_id_new:40 + │ │ └── t_st_id_new:34 => t_st_id:40 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(40) @@ -474,9 +474,9 @@ VALUES (0, '2020-06-17 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -489,32 +489,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -1721,13 +1721,13 @@ insert trade ├── insert-mapping: │ ├── column1:17 => t_id:1 │ ├── column2:18 => t_dts:2 - │ ├── column3:19 => t_st_id:3 - │ ├── column4:20 => t_tt_id:4 + │ ├── column3:19 => trade.t_st_id:3 + │ ├── column4:20 => trade.t_tt_id:4 │ ├── column5:21 => t_is_cash:5 - │ ├── column6:22 => t_s_symb:6 + │ ├── column6:22 => trade.t_s_symb:6 │ ├── column7:23 => t_qty:7 │ ├── t_bid_price:32 => trade.t_bid_price:8 - │ ├── column9:25 => t_ca_id:9 + │ ├── column9:25 => trade.t_ca_id:9 │ ├── column10:26 => t_exec_name:10 │ ├── t_trade_price:33 => trade.t_trade_price:11 │ ├── t_chrg:34 => trade.t_chrg:12 @@ -1747,64 +1747,64 @@ insert trade └── f-k-checks ├── f-k-checks-item: trade(t_st_id) -> status_type(st_id) │ └── anti-join (lookup status_type) - │ ├── columns: column3:42!null + │ ├── columns: t_st_id:42!null │ ├── key columns: [42] = [43] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(42) │ ├── with-scan &1 - │ │ ├── columns: column3:42!null + │ │ ├── columns: t_st_id:42!null │ │ ├── mapping: - │ │ │ └── column3:19 => column3:42 + │ │ │ └── column3:19 => t_st_id:42 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(42) │ └── filters (true) ├── f-k-checks-item: trade(t_tt_id) -> trade_type(tt_id) │ └── anti-join (lookup trade_type) - │ ├── columns: column4:46!null + │ ├── columns: t_tt_id:46!null │ ├── key columns: [46] = [47] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(46) │ ├── with-scan &1 - │ │ ├── columns: column4:46!null + │ │ ├── columns: t_tt_id:46!null │ │ ├── mapping: - │ │ │ └── column4:20 => column4:46 + │ │ │ └── column4:20 => t_tt_id:46 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(46) │ └── filters (true) ├── f-k-checks-item: trade(t_s_symb) -> security(s_symb) │ └── anti-join (lookup security) - │ ├── columns: column6:52!null + │ ├── columns: t_s_symb:52!null │ ├── key columns: [52] = [53] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(52) │ ├── with-scan &1 - │ │ ├── columns: column6:52!null + │ │ ├── columns: t_s_symb:52!null │ │ ├── mapping: - │ │ │ └── column6:22 => column6:52 + │ │ │ └── column6:22 => t_s_symb:52 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(52) │ └── filters (true) └── f-k-checks-item: trade(t_ca_id) -> customer_account(ca_id) └── anti-join (lookup customer_account) - ├── columns: column9:70!null + ├── columns: t_ca_id:70!null ├── key columns: [70] = [71] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(70) ├── with-scan &1 - │ ├── columns: column9:70!null + │ ├── columns: t_ca_id:70!null │ ├── mapping: - │ │ └── column9:25 => column9:70 + │ │ └── column9:25 => t_ca_id:70 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(70) @@ -1818,12 +1818,12 @@ VALUES (0, 'TMB', 'SYMB', 10, '100.00':::FLOAT8::DECIMAL, 0) insert trade_request ├── columns: ├── insert-mapping: - │ ├── column1:8 => tr_t_id:1 - │ ├── column2:9 => tr_tt_id:2 - │ ├── column3:10 => tr_s_symb:3 + │ ├── column1:8 => trade_request.tr_t_id:1 + │ ├── column2:9 => trade_request.tr_tt_id:2 + │ ├── column3:10 => trade_request.tr_s_symb:3 │ ├── column4:11 => tr_qty:4 │ ├── tr_bid_price:14 => trade_request.tr_bid_price:5 - │ └── column6:13 => tr_b_id:6 + │ └── column6:13 => trade_request.tr_b_id:6 ├── check columns: check1:15 check2:16 ├── input binding: &1 ├── cardinality: [0 - 0] @@ -1837,64 +1837,64 @@ insert trade_request └── f-k-checks ├── f-k-checks-item: trade_request(tr_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:17!null + │ ├── columns: tr_t_id:17!null │ ├── key columns: [17] = [18] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17) │ ├── with-scan &1 - │ │ ├── columns: column1:17!null + │ │ ├── columns: tr_t_id:17!null │ │ ├── mapping: - │ │ │ └── column1:8 => column1:17 + │ │ │ └── column1:8 => tr_t_id:17 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(17) │ └── filters (true) ├── f-k-checks-item: trade_request(tr_tt_id) -> trade_type(tt_id) │ └── anti-join (lookup trade_type) - │ ├── columns: column2:34!null + │ ├── columns: tr_tt_id:34!null │ ├── key columns: [34] = [35] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(34) │ ├── with-scan &1 - │ │ ├── columns: column2:34!null + │ │ ├── columns: tr_tt_id:34!null │ │ ├── mapping: - │ │ │ └── column2:9 => column2:34 + │ │ │ └── column2:9 => tr_tt_id:34 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(34) │ └── filters (true) ├── f-k-checks-item: trade_request(tr_s_symb) -> security(s_symb) │ └── anti-join (lookup security) - │ ├── columns: column3:40!null + │ ├── columns: tr_s_symb:40!null │ ├── key columns: [40] = [41] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(40) │ ├── with-scan &1 - │ │ ├── columns: column3:40!null + │ │ ├── columns: tr_s_symb:40!null │ │ ├── mapping: - │ │ │ └── column3:10 => column3:40 + │ │ │ └── column3:10 => tr_s_symb:40 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(40) │ └── filters (true) └── f-k-checks-item: trade_request(tr_b_id) -> broker(b_id) └── anti-join (lookup broker) - ├── columns: column6:58!null + ├── columns: tr_b_id:58!null ├── key columns: [58] = [59] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(58) ├── with-scan &1 - │ ├── columns: column6:58!null + │ ├── columns: tr_b_id:58!null │ ├── mapping: - │ │ └── column6:13 => column6:58 + │ │ └── column6:13 => tr_b_id:58 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(58) @@ -1908,9 +1908,9 @@ VALUES (0, '2020-06-15 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -1923,32 +1923,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -2046,8 +2046,8 @@ INSERT INTO holding_summary (hs_ca_id, hs_s_symb, hs_qty) VALUES (0, 'SYMB', 10) insert holding_summary ├── columns: ├── insert-mapping: - │ ├── column1:5 => hs_ca_id:1 - │ ├── column2:6 => hs_s_symb:2 + │ ├── column1:5 => holding_summary.hs_ca_id:1 + │ ├── column2:6 => holding_summary.hs_s_symb:2 │ └── column3:7 => hs_qty:3 ├── input binding: &1 ├── cardinality: [0 - 0] @@ -2061,32 +2061,32 @@ insert holding_summary └── f-k-checks ├── f-k-checks-item: holding_summary(hs_ca_id) -> customer_account(ca_id) │ └── anti-join (lookup customer_account) - │ ├── columns: column1:8!null + │ ├── columns: hs_ca_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: hs_ca_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => hs_ca_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: holding_summary(hs_s_symb) -> security(s_symb) └── anti-join (lookup security) - ├── columns: column2:16!null + ├── columns: hs_s_symb:16!null ├── key columns: [16] = [17] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(16) ├── with-scan &1 - │ ├── columns: column2:16!null + │ ├── columns: hs_s_symb:16!null │ ├── mapping: - │ │ └── column2:6 => column2:16 + │ │ └── column2:6 => hs_s_symb:16 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(16) @@ -2172,8 +2172,8 @@ VALUES (0, 0, 0, 10) insert holding_history ├── columns: ├── insert-mapping: - │ ├── column1:6 => hh_h_t_id:1 - │ ├── column2:7 => hh_t_id:2 + │ ├── column1:6 => holding_history.hh_h_t_id:1 + │ ├── column2:7 => holding_history.hh_t_id:2 │ ├── column3:8 => hh_before_qty:3 │ └── column4:9 => hh_after_qty:4 ├── input binding: &1 @@ -2188,32 +2188,32 @@ insert holding_history └── f-k-checks ├── f-k-checks-item: holding_history(hh_h_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:10!null + │ ├── columns: hh_h_t_id:10!null │ ├── key columns: [10] = [11] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(10) │ ├── with-scan &1 - │ │ ├── columns: column1:10!null + │ │ ├── columns: hh_h_t_id:10!null │ │ ├── mapping: - │ │ │ └── column1:6 => column1:10 + │ │ │ └── column1:6 => hh_h_t_id:10 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(10) │ └── filters (true) └── f-k-checks-item: holding_history(hh_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column2:27!null + ├── columns: hh_t_id:27!null ├── key columns: [27] = [28] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(27) ├── with-scan &1 - │ ├── columns: column2:27!null + │ ├── columns: hh_t_id:27!null │ ├── mapping: - │ │ └── column2:7 => column2:27 + │ │ └── column2:7 => hh_t_id:27 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(27) @@ -2275,9 +2275,9 @@ VALUES ( insert holding ├── columns: ├── insert-mapping: - │ ├── column1:8 => h_t_id:1 - │ ├── column2:9 => h_ca_id:2 - │ ├── column3:10 => h_s_symb:3 + │ ├── column1:8 => holding.h_t_id:1 + │ ├── column2:9 => holding.h_ca_id:2 + │ ├── column3:10 => holding.h_s_symb:3 │ ├── column4:11 => h_dts:4 │ ├── h_price:14 => holding.h_price:5 │ └── column6:13 => h_qty:6 @@ -2294,33 +2294,33 @@ insert holding └── f-k-checks ├── f-k-checks-item: holding(h_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:16!null + │ ├── columns: h_t_id:16!null │ ├── key columns: [16] = [17] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(16) │ ├── with-scan &1 - │ │ ├── columns: column1:16!null + │ │ ├── columns: h_t_id:16!null │ │ ├── mapping: - │ │ │ └── column1:8 => column1:16 + │ │ │ └── column1:8 => h_t_id:16 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(16) │ └── filters (true) └── f-k-checks-item: holding(h_ca_id,h_s_symb) -> holding_summary(hs_ca_id,hs_s_symb) └── anti-join (lookup holding_summary) - ├── columns: column2:33!null column3:34!null + ├── columns: h_ca_id:33!null h_s_symb:34!null ├── key columns: [33 34] = [35 36] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(33,34) ├── with-scan &1 - │ ├── columns: column2:33!null column3:34!null + │ ├── columns: h_ca_id:33!null h_s_symb:34!null │ ├── mapping: - │ │ ├── column2:9 => column2:33 - │ │ └── column3:10 => column3:34 + │ │ ├── column2:9 => h_ca_id:33 + │ │ └── column3:10 => h_s_symb:34 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(33,34) @@ -2368,8 +2368,8 @@ VALUES (0, 'SYMB', 10) insert holding_summary ├── columns: ├── insert-mapping: - │ ├── column1:5 => hs_ca_id:1 - │ ├── column2:6 => hs_s_symb:2 + │ ├── column1:5 => holding_summary.hs_ca_id:1 + │ ├── column2:6 => holding_summary.hs_s_symb:2 │ └── column3:7 => hs_qty:3 ├── input binding: &1 ├── cardinality: [0 - 0] @@ -2383,32 +2383,32 @@ insert holding_summary └── f-k-checks ├── f-k-checks-item: holding_summary(hs_ca_id) -> customer_account(ca_id) │ └── anti-join (lookup customer_account) - │ ├── columns: column1:8!null + │ ├── columns: hs_ca_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: hs_ca_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => hs_ca_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: holding_summary(hs_s_symb) -> security(s_symb) └── anti-join (lookup security) - ├── columns: column2:16!null + ├── columns: hs_s_symb:16!null ├── key columns: [16] = [17] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(16) ├── with-scan &1 - │ ├── columns: column2:16!null + │ ├── columns: hs_s_symb:16!null │ ├── mapping: - │ │ └── column2:6 => column2:16 + │ │ └── column2:6 => hs_s_symb:16 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(16) @@ -2452,8 +2452,8 @@ VALUES (0, 0, 0, 10) insert holding_history ├── columns: ├── insert-mapping: - │ ├── column1:6 => hh_h_t_id:1 - │ ├── column2:7 => hh_t_id:2 + │ ├── column1:6 => holding_history.hh_h_t_id:1 + │ ├── column2:7 => holding_history.hh_t_id:2 │ ├── column3:8 => hh_before_qty:3 │ └── column4:9 => hh_after_qty:4 ├── input binding: &1 @@ -2468,32 +2468,32 @@ insert holding_history └── f-k-checks ├── f-k-checks-item: holding_history(hh_h_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:10!null + │ ├── columns: hh_h_t_id:10!null │ ├── key columns: [10] = [11] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(10) │ ├── with-scan &1 - │ │ ├── columns: column1:10!null + │ │ ├── columns: hh_h_t_id:10!null │ │ ├── mapping: - │ │ │ └── column1:6 => column1:10 + │ │ │ └── column1:6 => hh_h_t_id:10 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(10) │ └── filters (true) └── f-k-checks-item: holding_history(hh_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column2:27!null + ├── columns: hh_t_id:27!null ├── key columns: [27] = [28] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(27) ├── with-scan &1 - │ ├── columns: column2:27!null + │ ├── columns: hh_t_id:27!null │ ├── mapping: - │ │ └── column2:7 => column2:27 + │ │ └── column2:7 => hh_t_id:27 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(27) @@ -2655,10 +2655,10 @@ UPDATE trade ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 trade.t_trade_price:27 t_chrg:28 trade.t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 trade.t_trade_price:27 t_chrg:28 trade.t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:34 => t_dts:2 - │ ├── t_st_id_new:35 => t_st_id:3 + │ ├── t_st_id_new:35 => trade.t_st_id:3 │ ├── t_trade_price:37 => trade.t_trade_price:11 │ └── t_comm:38 => trade.t_comm:13 ├── check columns: check4:42 @@ -2666,12 +2666,12 @@ update trade ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: check4:42!null t_comm:38!null t_trade_price:37!null t_dts_new:34!null t_st_id_new:35!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: check4:42!null t_comm:38!null t_trade_price:37!null t_dts_new:34!null t_st_id_new:35!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,34,35,37,38,42) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -2685,16 +2685,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:44!null + ├── columns: t_st_id:44!null ├── key columns: [44] = [45] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(44) ├── with-scan &1 - │ ├── columns: t_st_id_new:44!null + │ ├── columns: t_st_id:44!null │ ├── mapping: - │ │ └── t_st_id_new:35 => t_st_id_new:44 + │ │ └── t_st_id_new:35 => t_st_id:44 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(44) @@ -2708,9 +2708,9 @@ VALUES (0, '2020-06-17 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -2723,32 +2723,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -2793,7 +2793,7 @@ VALUES (0, 'Cash Account', '2020-06-19'::DATE, '100.00':::FLOAT8::DECIMAL) insert settlement ├── columns: ├── insert-mapping: - │ ├── column1:6 => se_t_id:1 + │ ├── column1:6 => settlement.se_t_id:1 │ ├── column2:7 => se_cash_type:2 │ ├── column3:8 => se_cash_due_date:3 │ └── se_amt:10 => settlement.se_amt:4 @@ -2809,16 +2809,16 @@ insert settlement └── f-k-checks └── f-k-checks-item: settlement(se_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column1:11!null + ├── columns: se_t_id:11!null ├── key columns: [11] = [12] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(11) ├── with-scan &1 - │ ├── columns: column1:11!null + │ ├── columns: se_t_id:11!null │ ├── mapping: - │ │ └── column1:6 => column1:11 + │ │ └── column1:6 => se_t_id:11 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(11) @@ -2876,7 +2876,7 @@ VALUES ( insert cash_transaction ├── columns: ├── insert-mapping: - │ ├── column1:6 => ct_t_id:1 + │ ├── column1:6 => cash_transaction.ct_t_id:1 │ ├── column2:7 => ct_dts:2 │ ├── ct_amt:10 => cash_transaction.ct_amt:3 │ └── column4:9 => ct_name:4 @@ -2892,16 +2892,16 @@ insert cash_transaction └── f-k-checks └── f-k-checks-item: cash_transaction(ct_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column1:11!null + ├── columns: ct_t_id:11!null ├── key columns: [11] = [12] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(11) ├── with-scan &1 - │ ├── columns: column1:11!null + │ ├── columns: ct_t_id:11!null │ ├── mapping: - │ │ └── column1:6 => column1:11 + │ │ └── column1:6 => ct_t_id:11 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(11) @@ -3668,19 +3668,19 @@ UPDATE customer_taxrate ---- update customer_taxrate ├── columns: - ├── fetch columns: cx_tx_id:4 cx_c_id:5 + ├── fetch columns: customer_taxrate.cx_tx_id:4 cx_c_id:5 ├── update-mapping: - │ └── cx_tx_id_new:7 => cx_tx_id:1 + │ └── cx_tx_id_new:7 => customer_taxrate.cx_tx_id:1 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: cx_tx_id_new:7!null cx_tx_id:4!null cx_c_id:5!null + │ ├── columns: cx_tx_id_new:7!null customer_taxrate.cx_tx_id:4!null cx_c_id:5!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(4,5,7) │ ├── scan customer_taxrate - │ │ ├── columns: cx_tx_id:4!null cx_c_id:5!null + │ │ ├── columns: customer_taxrate.cx_tx_id:4!null cx_c_id:5!null │ │ ├── constraint: /4/5: [/'US13'/0 - /'US13'/0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -3690,16 +3690,16 @@ update customer_taxrate └── f-k-checks └── f-k-checks-item: customer_taxrate(cx_tx_id) -> taxrate(tx_id) └── anti-join (lookup taxrate) - ├── columns: cx_tx_id_new:8!null + ├── columns: cx_tx_id:8!null ├── key columns: [8] = [9] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(8) ├── with-scan &1 - │ ├── columns: cx_tx_id_new:8!null + │ ├── columns: cx_tx_id:8!null │ ├── mapping: - │ │ └── cx_tx_id_new:7 => cx_tx_id_new:8 + │ │ └── cx_tx_id_new:7 => cx_tx_id:8 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(8) @@ -4140,18 +4140,18 @@ UPDATE watch_item ---- update watch_item ├── columns: - ├── fetch columns: wi_wl_id:4 wi_s_symb:5 + ├── fetch columns: wi_wl_id:4 watch_item.wi_s_symb:5 ├── update-mapping: - │ └── wi_s_symb_new:10 => wi_s_symb:2 + │ └── wi_s_symb_new:10 => watch_item.wi_s_symb:2 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: wi_s_symb_new:10!null wi_wl_id:4!null wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 + │ ├── columns: wi_s_symb_new:10!null wi_wl_id:4!null watch_item.wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 │ ├── key: (7) │ ├── fd: ()-->(5,8,10), (7)-->(9), (4)==(7), (7)==(4) │ ├── inner-join (lookup watch_item) - │ │ ├── columns: wi_wl_id:4!null wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 + │ │ ├── columns: wi_wl_id:4!null watch_item.wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 │ │ ├── key columns: [7 29] = [4 5] │ │ ├── lookup columns are key │ │ ├── key: (7) @@ -4178,14 +4178,14 @@ update watch_item └── f-k-checks └── f-k-checks-item: watch_item(wi_s_symb) -> security(s_symb) └── anti-join (lookup security) - ├── columns: wi_s_symb_new:11!null + ├── columns: wi_s_symb:11!null ├── key columns: [11] = [12] ├── lookup columns are key ├── fd: ()-->(11) ├── with-scan &1 - │ ├── columns: wi_s_symb_new:11!null + │ ├── columns: wi_s_symb:11!null │ ├── mapping: - │ │ └── wi_s_symb_new:10 => wi_s_symb_new:11 + │ │ └── wi_s_symb_new:10 => wi_s_symb:11 │ └── fd: ()-->(11) └── filters (true) @@ -4215,9 +4215,9 @@ VALUES (0, '2020-06-17 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -4230,32 +4230,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -4269,20 +4269,20 @@ WHERE t_id = 0 ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:34 => t_dts:2 - │ └── t_st_id_new:33 => t_st_id:3 + │ └── t_st_id_new:33 => trade.t_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,33,34) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -4293,16 +4293,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:40!null + ├── columns: t_st_id:40!null ├── key columns: [40] = [41] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(40) ├── with-scan &1 - │ ├── columns: t_st_id_new:40!null + │ ├── columns: t_st_id:40!null │ ├── mapping: - │ │ └── t_st_id_new:33 => t_st_id_new:40 + │ │ └── t_st_id_new:33 => t_st_id:40 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(40) @@ -4349,20 +4349,20 @@ WHERE t_id = 0 ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:34 => t_dts:2 - │ └── t_st_id_new:33 => t_st_id:3 + │ └── t_st_id_new:33 => trade.t_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,33,34) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -4373,16 +4373,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:40!null + ├── columns: t_st_id:40!null ├── key columns: [40] = [41] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(40) ├── with-scan &1 - │ ├── columns: t_st_id_new:40!null + │ ├── columns: t_st_id:40!null │ ├── mapping: - │ │ └── t_st_id_new:33 => t_st_id_new:40 + │ │ └── t_st_id_new:33 => t_st_id:40 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(40) diff --git a/pkg/sql/opt/xform/testdata/external/tpce-no-stats b/pkg/sql/opt/xform/testdata/external/tpce-no-stats index ec6d64ebde33..3c3979755e51 100644 --- a/pkg/sql/opt/xform/testdata/external/tpce-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpce-no-stats @@ -401,20 +401,20 @@ UPDATE trade ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:33 => t_dts:2 - │ └── t_st_id_new:34 => t_st_id:3 + │ └── t_st_id_new:34 => trade.t_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: t_dts_new:33!null t_st_id_new:34!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: t_dts_new:33!null t_st_id_new:34!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,33,34) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -425,16 +425,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:40!null + ├── columns: t_st_id:40!null ├── key columns: [40] = [41] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(40) ├── with-scan &1 - │ ├── columns: t_st_id_new:40!null + │ ├── columns: t_st_id:40!null │ ├── mapping: - │ │ └── t_st_id_new:34 => t_st_id_new:40 + │ │ └── t_st_id_new:34 => t_st_id:40 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(40) @@ -464,9 +464,9 @@ VALUES (0, '2020-06-17 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -479,32 +479,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -1737,13 +1737,13 @@ insert trade ├── insert-mapping: │ ├── column1:17 => t_id:1 │ ├── column2:18 => t_dts:2 - │ ├── column3:19 => t_st_id:3 - │ ├── column4:20 => t_tt_id:4 + │ ├── column3:19 => trade.t_st_id:3 + │ ├── column4:20 => trade.t_tt_id:4 │ ├── column5:21 => t_is_cash:5 - │ ├── column6:22 => t_s_symb:6 + │ ├── column6:22 => trade.t_s_symb:6 │ ├── column7:23 => t_qty:7 │ ├── t_bid_price:32 => trade.t_bid_price:8 - │ ├── column9:25 => t_ca_id:9 + │ ├── column9:25 => trade.t_ca_id:9 │ ├── column10:26 => t_exec_name:10 │ ├── t_trade_price:33 => trade.t_trade_price:11 │ ├── t_chrg:34 => trade.t_chrg:12 @@ -1763,64 +1763,64 @@ insert trade └── f-k-checks ├── f-k-checks-item: trade(t_st_id) -> status_type(st_id) │ └── anti-join (lookup status_type) - │ ├── columns: column3:42!null + │ ├── columns: t_st_id:42!null │ ├── key columns: [42] = [43] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(42) │ ├── with-scan &1 - │ │ ├── columns: column3:42!null + │ │ ├── columns: t_st_id:42!null │ │ ├── mapping: - │ │ │ └── column3:19 => column3:42 + │ │ │ └── column3:19 => t_st_id:42 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(42) │ └── filters (true) ├── f-k-checks-item: trade(t_tt_id) -> trade_type(tt_id) │ └── anti-join (lookup trade_type) - │ ├── columns: column4:46!null + │ ├── columns: t_tt_id:46!null │ ├── key columns: [46] = [47] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(46) │ ├── with-scan &1 - │ │ ├── columns: column4:46!null + │ │ ├── columns: t_tt_id:46!null │ │ ├── mapping: - │ │ │ └── column4:20 => column4:46 + │ │ │ └── column4:20 => t_tt_id:46 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(46) │ └── filters (true) ├── f-k-checks-item: trade(t_s_symb) -> security(s_symb) │ └── anti-join (lookup security) - │ ├── columns: column6:52!null + │ ├── columns: t_s_symb:52!null │ ├── key columns: [52] = [53] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(52) │ ├── with-scan &1 - │ │ ├── columns: column6:52!null + │ │ ├── columns: t_s_symb:52!null │ │ ├── mapping: - │ │ │ └── column6:22 => column6:52 + │ │ │ └── column6:22 => t_s_symb:52 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(52) │ └── filters (true) └── f-k-checks-item: trade(t_ca_id) -> customer_account(ca_id) └── anti-join (lookup customer_account) - ├── columns: column9:70!null + ├── columns: t_ca_id:70!null ├── key columns: [70] = [71] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(70) ├── with-scan &1 - │ ├── columns: column9:70!null + │ ├── columns: t_ca_id:70!null │ ├── mapping: - │ │ └── column9:25 => column9:70 + │ │ └── column9:25 => t_ca_id:70 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(70) @@ -1834,12 +1834,12 @@ VALUES (0, 'TMB', 'SYMB', 10, '100.00':::FLOAT8::DECIMAL, 0) insert trade_request ├── columns: ├── insert-mapping: - │ ├── column1:8 => tr_t_id:1 - │ ├── column2:9 => tr_tt_id:2 - │ ├── column3:10 => tr_s_symb:3 + │ ├── column1:8 => trade_request.tr_t_id:1 + │ ├── column2:9 => trade_request.tr_tt_id:2 + │ ├── column3:10 => trade_request.tr_s_symb:3 │ ├── column4:11 => tr_qty:4 │ ├── tr_bid_price:14 => trade_request.tr_bid_price:5 - │ └── column6:13 => tr_b_id:6 + │ └── column6:13 => trade_request.tr_b_id:6 ├── check columns: check1:15 check2:16 ├── input binding: &1 ├── cardinality: [0 - 0] @@ -1853,64 +1853,64 @@ insert trade_request └── f-k-checks ├── f-k-checks-item: trade_request(tr_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:17!null + │ ├── columns: tr_t_id:17!null │ ├── key columns: [17] = [18] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17) │ ├── with-scan &1 - │ │ ├── columns: column1:17!null + │ │ ├── columns: tr_t_id:17!null │ │ ├── mapping: - │ │ │ └── column1:8 => column1:17 + │ │ │ └── column1:8 => tr_t_id:17 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(17) │ └── filters (true) ├── f-k-checks-item: trade_request(tr_tt_id) -> trade_type(tt_id) │ └── anti-join (lookup trade_type) - │ ├── columns: column2:34!null + │ ├── columns: tr_tt_id:34!null │ ├── key columns: [34] = [35] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(34) │ ├── with-scan &1 - │ │ ├── columns: column2:34!null + │ │ ├── columns: tr_tt_id:34!null │ │ ├── mapping: - │ │ │ └── column2:9 => column2:34 + │ │ │ └── column2:9 => tr_tt_id:34 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(34) │ └── filters (true) ├── f-k-checks-item: trade_request(tr_s_symb) -> security(s_symb) │ └── anti-join (lookup security) - │ ├── columns: column3:40!null + │ ├── columns: tr_s_symb:40!null │ ├── key columns: [40] = [41] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(40) │ ├── with-scan &1 - │ │ ├── columns: column3:40!null + │ │ ├── columns: tr_s_symb:40!null │ │ ├── mapping: - │ │ │ └── column3:10 => column3:40 + │ │ │ └── column3:10 => tr_s_symb:40 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(40) │ └── filters (true) └── f-k-checks-item: trade_request(tr_b_id) -> broker(b_id) └── anti-join (lookup broker) - ├── columns: column6:58!null + ├── columns: tr_b_id:58!null ├── key columns: [58] = [59] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(58) ├── with-scan &1 - │ ├── columns: column6:58!null + │ ├── columns: tr_b_id:58!null │ ├── mapping: - │ │ └── column6:13 => column6:58 + │ │ └── column6:13 => tr_b_id:58 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(58) @@ -1924,9 +1924,9 @@ VALUES (0, '2020-06-15 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -1939,32 +1939,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -2062,8 +2062,8 @@ INSERT INTO holding_summary (hs_ca_id, hs_s_symb, hs_qty) VALUES (0, 'SYMB', 10) insert holding_summary ├── columns: ├── insert-mapping: - │ ├── column1:5 => hs_ca_id:1 - │ ├── column2:6 => hs_s_symb:2 + │ ├── column1:5 => holding_summary.hs_ca_id:1 + │ ├── column2:6 => holding_summary.hs_s_symb:2 │ └── column3:7 => hs_qty:3 ├── input binding: &1 ├── cardinality: [0 - 0] @@ -2077,32 +2077,32 @@ insert holding_summary └── f-k-checks ├── f-k-checks-item: holding_summary(hs_ca_id) -> customer_account(ca_id) │ └── anti-join (lookup customer_account) - │ ├── columns: column1:8!null + │ ├── columns: hs_ca_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: hs_ca_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => hs_ca_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: holding_summary(hs_s_symb) -> security(s_symb) └── anti-join (lookup security) - ├── columns: column2:16!null + ├── columns: hs_s_symb:16!null ├── key columns: [16] = [17] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(16) ├── with-scan &1 - │ ├── columns: column2:16!null + │ ├── columns: hs_s_symb:16!null │ ├── mapping: - │ │ └── column2:6 => column2:16 + │ │ └── column2:6 => hs_s_symb:16 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(16) @@ -2188,8 +2188,8 @@ VALUES (0, 0, 0, 10) insert holding_history ├── columns: ├── insert-mapping: - │ ├── column1:6 => hh_h_t_id:1 - │ ├── column2:7 => hh_t_id:2 + │ ├── column1:6 => holding_history.hh_h_t_id:1 + │ ├── column2:7 => holding_history.hh_t_id:2 │ ├── column3:8 => hh_before_qty:3 │ └── column4:9 => hh_after_qty:4 ├── input binding: &1 @@ -2204,32 +2204,32 @@ insert holding_history └── f-k-checks ├── f-k-checks-item: holding_history(hh_h_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:10!null + │ ├── columns: hh_h_t_id:10!null │ ├── key columns: [10] = [11] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(10) │ ├── with-scan &1 - │ │ ├── columns: column1:10!null + │ │ ├── columns: hh_h_t_id:10!null │ │ ├── mapping: - │ │ │ └── column1:6 => column1:10 + │ │ │ └── column1:6 => hh_h_t_id:10 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(10) │ └── filters (true) └── f-k-checks-item: holding_history(hh_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column2:27!null + ├── columns: hh_t_id:27!null ├── key columns: [27] = [28] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(27) ├── with-scan &1 - │ ├── columns: column2:27!null + │ ├── columns: hh_t_id:27!null │ ├── mapping: - │ │ └── column2:7 => column2:27 + │ │ └── column2:7 => hh_t_id:27 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(27) @@ -2291,9 +2291,9 @@ VALUES ( insert holding ├── columns: ├── insert-mapping: - │ ├── column1:8 => h_t_id:1 - │ ├── column2:9 => h_ca_id:2 - │ ├── column3:10 => h_s_symb:3 + │ ├── column1:8 => holding.h_t_id:1 + │ ├── column2:9 => holding.h_ca_id:2 + │ ├── column3:10 => holding.h_s_symb:3 │ ├── column4:11 => h_dts:4 │ ├── h_price:14 => holding.h_price:5 │ └── column6:13 => h_qty:6 @@ -2310,33 +2310,33 @@ insert holding └── f-k-checks ├── f-k-checks-item: holding(h_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:16!null + │ ├── columns: h_t_id:16!null │ ├── key columns: [16] = [17] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(16) │ ├── with-scan &1 - │ │ ├── columns: column1:16!null + │ │ ├── columns: h_t_id:16!null │ │ ├── mapping: - │ │ │ └── column1:8 => column1:16 + │ │ │ └── column1:8 => h_t_id:16 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(16) │ └── filters (true) └── f-k-checks-item: holding(h_ca_id,h_s_symb) -> holding_summary(hs_ca_id,hs_s_symb) └── anti-join (lookup holding_summary) - ├── columns: column2:33!null column3:34!null + ├── columns: h_ca_id:33!null h_s_symb:34!null ├── key columns: [33 34] = [35 36] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(33,34) ├── with-scan &1 - │ ├── columns: column2:33!null column3:34!null + │ ├── columns: h_ca_id:33!null h_s_symb:34!null │ ├── mapping: - │ │ ├── column2:9 => column2:33 - │ │ └── column3:10 => column3:34 + │ │ ├── column2:9 => h_ca_id:33 + │ │ └── column3:10 => h_s_symb:34 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(33,34) @@ -2384,8 +2384,8 @@ VALUES (0, 'SYMB', 10) insert holding_summary ├── columns: ├── insert-mapping: - │ ├── column1:5 => hs_ca_id:1 - │ ├── column2:6 => hs_s_symb:2 + │ ├── column1:5 => holding_summary.hs_ca_id:1 + │ ├── column2:6 => holding_summary.hs_s_symb:2 │ └── column3:7 => hs_qty:3 ├── input binding: &1 ├── cardinality: [0 - 0] @@ -2399,32 +2399,32 @@ insert holding_summary └── f-k-checks ├── f-k-checks-item: holding_summary(hs_ca_id) -> customer_account(ca_id) │ └── anti-join (lookup customer_account) - │ ├── columns: column1:8!null + │ ├── columns: hs_ca_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: hs_ca_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => hs_ca_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: holding_summary(hs_s_symb) -> security(s_symb) └── anti-join (lookup security) - ├── columns: column2:16!null + ├── columns: hs_s_symb:16!null ├── key columns: [16] = [17] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(16) ├── with-scan &1 - │ ├── columns: column2:16!null + │ ├── columns: hs_s_symb:16!null │ ├── mapping: - │ │ └── column2:6 => column2:16 + │ │ └── column2:6 => hs_s_symb:16 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(16) @@ -2468,8 +2468,8 @@ VALUES (0, 0, 0, 10) insert holding_history ├── columns: ├── insert-mapping: - │ ├── column1:6 => hh_h_t_id:1 - │ ├── column2:7 => hh_t_id:2 + │ ├── column1:6 => holding_history.hh_h_t_id:1 + │ ├── column2:7 => holding_history.hh_t_id:2 │ ├── column3:8 => hh_before_qty:3 │ └── column4:9 => hh_after_qty:4 ├── input binding: &1 @@ -2484,32 +2484,32 @@ insert holding_history └── f-k-checks ├── f-k-checks-item: holding_history(hh_h_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:10!null + │ ├── columns: hh_h_t_id:10!null │ ├── key columns: [10] = [11] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(10) │ ├── with-scan &1 - │ │ ├── columns: column1:10!null + │ │ ├── columns: hh_h_t_id:10!null │ │ ├── mapping: - │ │ │ └── column1:6 => column1:10 + │ │ │ └── column1:6 => hh_h_t_id:10 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(10) │ └── filters (true) └── f-k-checks-item: holding_history(hh_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column2:27!null + ├── columns: hh_t_id:27!null ├── key columns: [27] = [28] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(27) ├── with-scan &1 - │ ├── columns: column2:27!null + │ ├── columns: hh_t_id:27!null │ ├── mapping: - │ │ └── column2:7 => column2:27 + │ │ └── column2:7 => hh_t_id:27 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(27) @@ -2675,10 +2675,10 @@ UPDATE trade ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 trade.t_trade_price:27 t_chrg:28 trade.t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 trade.t_trade_price:27 t_chrg:28 trade.t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:34 => t_dts:2 - │ ├── t_st_id_new:35 => t_st_id:3 + │ ├── t_st_id_new:35 => trade.t_st_id:3 │ ├── t_trade_price:37 => trade.t_trade_price:11 │ └── t_comm:38 => trade.t_comm:13 ├── check columns: check4:42 @@ -2686,12 +2686,12 @@ update trade ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: check4:42!null t_comm:38!null t_trade_price:37!null t_dts_new:34!null t_st_id_new:35!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: check4:42!null t_comm:38!null t_trade_price:37!null t_dts_new:34!null t_st_id_new:35!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,34,35,37,38,42) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null trade.t_trade_price:27 t_chrg:28!null trade.t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -2705,16 +2705,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:44!null + ├── columns: t_st_id:44!null ├── key columns: [44] = [45] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(44) ├── with-scan &1 - │ ├── columns: t_st_id_new:44!null + │ ├── columns: t_st_id:44!null │ ├── mapping: - │ │ └── t_st_id_new:35 => t_st_id_new:44 + │ │ └── t_st_id_new:35 => t_st_id:44 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(44) @@ -2728,9 +2728,9 @@ VALUES (0, '2020-06-17 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -2743,32 +2743,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -2813,7 +2813,7 @@ VALUES (0, 'Cash Account', '2020-06-19'::DATE, '100.00':::FLOAT8::DECIMAL) insert settlement ├── columns: ├── insert-mapping: - │ ├── column1:6 => se_t_id:1 + │ ├── column1:6 => settlement.se_t_id:1 │ ├── column2:7 => se_cash_type:2 │ ├── column3:8 => se_cash_due_date:3 │ └── se_amt:10 => settlement.se_amt:4 @@ -2829,16 +2829,16 @@ insert settlement └── f-k-checks └── f-k-checks-item: settlement(se_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column1:11!null + ├── columns: se_t_id:11!null ├── key columns: [11] = [12] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(11) ├── with-scan &1 - │ ├── columns: column1:11!null + │ ├── columns: se_t_id:11!null │ ├── mapping: - │ │ └── column1:6 => column1:11 + │ │ └── column1:6 => se_t_id:11 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(11) @@ -2896,7 +2896,7 @@ VALUES ( insert cash_transaction ├── columns: ├── insert-mapping: - │ ├── column1:6 => ct_t_id:1 + │ ├── column1:6 => cash_transaction.ct_t_id:1 │ ├── column2:7 => ct_dts:2 │ ├── ct_amt:10 => cash_transaction.ct_amt:3 │ └── column4:9 => ct_name:4 @@ -2912,16 +2912,16 @@ insert cash_transaction └── f-k-checks └── f-k-checks-item: cash_transaction(ct_t_id) -> trade(t_id) └── anti-join (lookup trade) - ├── columns: column1:11!null + ├── columns: ct_t_id:11!null ├── key columns: [11] = [12] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(11) ├── with-scan &1 - │ ├── columns: column1:11!null + │ ├── columns: ct_t_id:11!null │ ├── mapping: - │ │ └── column1:6 => column1:11 + │ │ └── column1:6 => ct_t_id:11 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(11) @@ -3688,19 +3688,19 @@ UPDATE customer_taxrate ---- update customer_taxrate ├── columns: - ├── fetch columns: cx_tx_id:4 cx_c_id:5 + ├── fetch columns: customer_taxrate.cx_tx_id:4 cx_c_id:5 ├── update-mapping: - │ └── cx_tx_id_new:7 => cx_tx_id:1 + │ └── cx_tx_id_new:7 => customer_taxrate.cx_tx_id:1 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: cx_tx_id_new:7!null cx_tx_id:4!null cx_c_id:5!null + │ ├── columns: cx_tx_id_new:7!null customer_taxrate.cx_tx_id:4!null cx_c_id:5!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(4,5,7) │ ├── scan customer_taxrate - │ │ ├── columns: cx_tx_id:4!null cx_c_id:5!null + │ │ ├── columns: customer_taxrate.cx_tx_id:4!null cx_c_id:5!null │ │ ├── constraint: /4/5: [/'US13'/0 - /'US13'/0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -3710,16 +3710,16 @@ update customer_taxrate └── f-k-checks └── f-k-checks-item: customer_taxrate(cx_tx_id) -> taxrate(tx_id) └── anti-join (lookup taxrate) - ├── columns: cx_tx_id_new:8!null + ├── columns: cx_tx_id:8!null ├── key columns: [8] = [9] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(8) ├── with-scan &1 - │ ├── columns: cx_tx_id_new:8!null + │ ├── columns: cx_tx_id:8!null │ ├── mapping: - │ │ └── cx_tx_id_new:7 => cx_tx_id_new:8 + │ │ └── cx_tx_id_new:7 => cx_tx_id:8 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(8) @@ -4160,31 +4160,31 @@ UPDATE watch_item ---- update watch_item ├── columns: - ├── fetch columns: wi_wl_id:4 wi_s_symb:5 + ├── fetch columns: wi_wl_id:4 watch_item.wi_s_symb:5 ├── update-mapping: - │ └── wi_s_symb_new:10 => wi_s_symb:2 + │ └── wi_s_symb_new:10 => watch_item.wi_s_symb:2 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: wi_s_symb_new:10!null wi_wl_id:4!null wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 + │ ├── columns: wi_s_symb_new:10!null wi_wl_id:4!null watch_item.wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 │ ├── key: (7) │ ├── fd: ()-->(5,8,10), (7)-->(9), (4)==(7), (7)==(4) │ ├── inner-join (lookup watch_list) - │ │ ├── columns: wi_wl_id:4!null wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 + │ │ ├── columns: wi_wl_id:4!null watch_item.wi_s_symb:5!null wl_id:7!null wl_c_id:8!null watch_list.crdb_internal_mvcc_timestamp:9 │ │ ├── key columns: [4] = [7] │ │ ├── lookup columns are key │ │ ├── key: (7) │ │ ├── fd: ()-->(5,8), (7)-->(9), (4)==(7), (7)==(4) │ │ ├── select - │ │ │ ├── columns: wi_wl_id:4!null wi_s_symb:5!null + │ │ │ ├── columns: wi_wl_id:4!null watch_item.wi_s_symb:5!null │ │ │ ├── key: (4) │ │ │ ├── fd: ()-->(5) │ │ │ ├── scan watch_item - │ │ │ │ ├── columns: wi_wl_id:4!null wi_s_symb:5!null + │ │ │ │ ├── columns: wi_wl_id:4!null watch_item.wi_s_symb:5!null │ │ │ │ └── key: (4,5) │ │ │ └── filters - │ │ │ └── wi_s_symb:5 = 'SYMB' [outer=(5), constraints=(/5: [/'SYMB' - /'SYMB']; tight), fd=()-->(5)] + │ │ │ └── watch_item.wi_s_symb:5 = 'SYMB' [outer=(5), constraints=(/5: [/'SYMB' - /'SYMB']; tight), fd=()-->(5)] │ │ └── filters │ │ └── wl_c_id:8 = 0 [outer=(8), constraints=(/8: [/0 - /0]; tight), fd=()-->(8)] │ └── projections @@ -4192,14 +4192,14 @@ update watch_item └── f-k-checks └── f-k-checks-item: watch_item(wi_s_symb) -> security(s_symb) └── anti-join (lookup security) - ├── columns: wi_s_symb_new:11!null + ├── columns: wi_s_symb:11!null ├── key columns: [11] = [12] ├── lookup columns are key ├── fd: ()-->(11) ├── with-scan &1 - │ ├── columns: wi_s_symb_new:11!null + │ ├── columns: wi_s_symb:11!null │ ├── mapping: - │ │ └── wi_s_symb_new:10 => wi_s_symb_new:11 + │ │ └── wi_s_symb_new:10 => wi_s_symb:11 │ └── fd: ()-->(11) └── filters (true) @@ -4229,9 +4229,9 @@ VALUES (0, '2020-06-17 22:27:42.148484+00:00'::TIMESTAMP, 'SBMT') insert trade_history ├── columns: ├── insert-mapping: - │ ├── column1:5 => th_t_id:1 + │ ├── column1:5 => trade_history.th_t_id:1 │ ├── column2:6 => th_dts:2 - │ └── column3:7 => th_st_id:3 + │ └── column3:7 => trade_history.th_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations @@ -4244,32 +4244,32 @@ insert trade_history └── f-k-checks ├── f-k-checks-item: trade_history(th_t_id) -> trade(t_id) │ └── anti-join (lookup trade) - │ ├── columns: column1:8!null + │ ├── columns: th_t_id:8!null │ ├── key columns: [8] = [9] │ ├── lookup columns are key │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(8) │ ├── with-scan &1 - │ │ ├── columns: column1:8!null + │ │ ├── columns: th_t_id:8!null │ │ ├── mapping: - │ │ │ └── column1:5 => column1:8 + │ │ │ └── column1:5 => th_t_id:8 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () │ │ └── fd: ()-->(8) │ └── filters (true) └── f-k-checks-item: trade_history(th_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: column3:25!null + ├── columns: th_st_id:25!null ├── key columns: [25] = [26] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(25) ├── with-scan &1 - │ ├── columns: column3:25!null + │ ├── columns: th_st_id:25!null │ ├── mapping: - │ │ └── column3:7 => column3:25 + │ │ └── column3:7 => th_st_id:25 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(25) @@ -4283,20 +4283,20 @@ WHERE t_id = 0 ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:34 => t_dts:2 - │ └── t_st_id_new:33 => t_st_id:3 + │ └── t_st_id_new:33 => trade.t_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,33,34) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -4307,16 +4307,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:40!null + ├── columns: t_st_id:40!null ├── key columns: [40] = [41] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(40) ├── with-scan &1 - │ ├── columns: t_st_id_new:40!null + │ ├── columns: t_st_id:40!null │ ├── mapping: - │ │ └── t_st_id_new:33 => t_st_id_new:40 + │ │ └── t_st_id_new:33 => t_st_id:40 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(40) @@ -4363,20 +4363,20 @@ WHERE t_id = 0 ---- update trade ├── columns: - ├── fetch columns: t_id:17 t_dts:18 t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 + ├── fetch columns: t_id:17 t_dts:18 trade.t_st_id:19 t_tt_id:20 t_is_cash:21 t_s_symb:22 t_qty:23 t_bid_price:24 t_ca_id:25 t_exec_name:26 t_trade_price:27 t_chrg:28 t_comm:29 t_tax:30 t_lifo:31 ├── update-mapping: │ ├── t_dts_new:34 => t_dts:2 - │ └── t_st_id_new:33 => t_st_id:3 + │ └── t_st_id_new:33 => trade.t_st_id:3 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ ├── columns: t_st_id_new:33!null t_dts_new:34!null t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ ├── cardinality: [0 - 1] │ ├── key: () │ ├── fd: ()-->(17-31,33,34) │ ├── scan trade - │ │ ├── columns: t_id:17!null t_dts:18!null t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null + │ │ ├── columns: t_id:17!null t_dts:18!null trade.t_st_id:19!null t_tt_id:20!null t_is_cash:21!null t_s_symb:22!null t_qty:23!null t_bid_price:24 t_ca_id:25!null t_exec_name:26!null t_trade_price:27 t_chrg:28!null t_comm:29!null t_tax:30!null t_lifo:31!null │ │ ├── constraint: /17: [/0 - /0] │ │ ├── cardinality: [0 - 1] │ │ ├── key: () @@ -4387,16 +4387,16 @@ update trade └── f-k-checks └── f-k-checks-item: trade(t_st_id) -> status_type(st_id) └── anti-join (lookup status_type) - ├── columns: t_st_id_new:40!null + ├── columns: t_st_id:40!null ├── key columns: [40] = [41] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(40) ├── with-scan &1 - │ ├── columns: t_st_id_new:40!null + │ ├── columns: t_st_id:40!null │ ├── mapping: - │ │ └── t_st_id_new:33 => t_st_id_new:40 + │ │ └── t_st_id_new:33 => t_st_id:40 │ ├── cardinality: [0 - 1] │ ├── key: () │ └── fd: ()-->(40) diff --git a/pkg/sql/opt/xform/testdata/external/trading b/pkg/sql/opt/xform/testdata/external/trading index c1ab2aee7cd4..a1aa94877983 100644 --- a/pkg/sql/opt/xform/testdata/external/trading +++ b/pkg/sql/opt/xform/testdata/external/trading @@ -1329,12 +1329,12 @@ upsert transactiondetails ├── columns: ├── arbiter indexes: detailsprimarykey ├── canary column: transactiondetails.dealerid:22 - ├── fetch columns: transactiondetails.dealerid:22 transactiondetails.isbuy:23 transactiondate:24 cardid:25 quantity:26 transactiondetails.sellprice:27 transactiondetails.buyprice:28 transactiondetails.version:29 + ├── fetch columns: transactiondetails.dealerid:22 transactiondetails.isbuy:23 transactiondetails.transactiondate:24 transactiondetails.cardid:25 quantity:26 transactiondetails.sellprice:27 transactiondetails.buyprice:28 transactiondetails.version:29 ├── insert-mapping: │ ├── "?column?":12 => transactiondetails.dealerid:2 │ ├── bool:13 => transactiondetails.isbuy:3 - │ ├── current_timestamp:14 => transactiondate:4 - │ ├── int8:15 => cardid:5 + │ ├── current_timestamp:14 => transactiondetails.transactiondate:4 + │ ├── int8:15 => transactiondetails.cardid:5 │ ├── int8:16 => quantity:6 │ ├── sellprice:20 => transactiondetails.sellprice:7 │ ├── buyprice:21 => transactiondetails.buyprice:8 @@ -1346,13 +1346,13 @@ upsert transactiondetails ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: upsert_dealerid:31 upsert_isbuy:32 upsert_transactiondate:33 upsert_cardid:34 "?column?":12!null bool:13!null current_timestamp:14!null int8:15!null int8:16!null column19:19 sellprice:20 buyprice:21 transactiondetails.dealerid:22 transactiondetails.isbuy:23 transactiondate:24 cardid:25 quantity:26 transactiondetails.sellprice:27 transactiondetails.buyprice:28 transactiondetails.version:29 + │ ├── columns: upsert_dealerid:31 upsert_isbuy:32 upsert_transactiondate:33 upsert_cardid:34 "?column?":12!null bool:13!null current_timestamp:14!null int8:15!null int8:16!null column19:19 sellprice:20 buyprice:21 transactiondetails.dealerid:22 transactiondetails.isbuy:23 transactiondetails.transactiondate:24 transactiondetails.cardid:25 quantity:26 transactiondetails.sellprice:27 transactiondetails.buyprice:28 transactiondetails.version:29 │ ├── cardinality: [1 - 2] │ ├── volatile │ ├── key: (15,16) │ ├── fd: ()-->(12-14), (15,16)-->(19-29), (22-26)-->(27-29), (22)-->(31), (22,23)-->(32), (22,24)-->(33), (15,22,25)-->(34) │ ├── left-join (lookup transactiondetails) - │ │ ├── columns: "?column?":12!null bool:13!null current_timestamp:14!null int8:15!null int8:16!null column19:19 sellprice:20 buyprice:21 transactiondetails.dealerid:22 transactiondetails.isbuy:23 transactiondate:24 cardid:25 quantity:26 transactiondetails.sellprice:27 transactiondetails.buyprice:28 transactiondetails.version:29 + │ │ ├── columns: "?column?":12!null bool:13!null current_timestamp:14!null int8:15!null int8:16!null column19:19 sellprice:20 buyprice:21 transactiondetails.dealerid:22 transactiondetails.isbuy:23 transactiondetails.transactiondate:24 transactiondetails.cardid:25 quantity:26 transactiondetails.sellprice:27 transactiondetails.buyprice:28 transactiondetails.version:29 │ │ ├── key columns: [12 13 14 15 16] = [22 23 24 25 26] │ │ ├── lookup columns are key │ │ ├── cardinality: [1 - 2] @@ -1403,33 +1403,33 @@ upsert transactiondetails │ └── projections │ ├── CASE WHEN transactiondetails.dealerid:22 IS NULL THEN "?column?":12 ELSE transactiondetails.dealerid:22 END [as=upsert_dealerid:31, outer=(12,22)] │ ├── CASE WHEN transactiondetails.dealerid:22 IS NULL THEN bool:13 ELSE transactiondetails.isbuy:23 END [as=upsert_isbuy:32, outer=(13,22,23)] - │ ├── CASE WHEN transactiondetails.dealerid:22 IS NULL THEN current_timestamp:14 ELSE transactiondate:24 END [as=upsert_transactiondate:33, outer=(14,22,24)] - │ └── CASE WHEN transactiondetails.dealerid:22 IS NULL THEN int8:15 ELSE cardid:25 END [as=upsert_cardid:34, outer=(15,22,25)] + │ ├── CASE WHEN transactiondetails.dealerid:22 IS NULL THEN current_timestamp:14 ELSE transactiondetails.transactiondate:24 END [as=upsert_transactiondate:33, outer=(14,22,24)] + │ └── CASE WHEN transactiondetails.dealerid:22 IS NULL THEN int8:15 ELSE transactiondetails.cardid:25 END [as=upsert_cardid:34, outer=(15,22,25)] └── f-k-checks ├── f-k-checks-item: transactiondetails(dealerid,isbuy,transactiondate) -> transactions(dealerid,isbuy,date) │ └── anti-join (lookup transactions) - │ ├── columns: upsert_dealerid:37 upsert_isbuy:38 upsert_transactiondate:39 + │ ├── columns: dealerid:37 isbuy:38 transactiondate:39 │ ├── key columns: [37 38 39] = [40 41 42] │ ├── lookup columns are key │ ├── cardinality: [0 - 2] │ ├── with-scan &2 - │ │ ├── columns: upsert_dealerid:37 upsert_isbuy:38 upsert_transactiondate:39 + │ │ ├── columns: dealerid:37 isbuy:38 transactiondate:39 │ │ ├── mapping: - │ │ │ ├── upsert_dealerid:31 => upsert_dealerid:37 - │ │ │ ├── upsert_isbuy:32 => upsert_isbuy:38 - │ │ │ └── upsert_transactiondate:33 => upsert_transactiondate:39 + │ │ │ ├── upsert_dealerid:31 => dealerid:37 + │ │ │ ├── upsert_isbuy:32 => isbuy:38 + │ │ │ └── upsert_transactiondate:33 => transactiondate:39 │ │ └── cardinality: [1 - 2] │ └── filters (true) └── f-k-checks-item: transactiondetails(cardid) -> cards(id) └── anti-join (lookup cards) - ├── columns: upsert_cardid:48 + ├── columns: cardid:48 ├── key columns: [48] = [49] ├── lookup columns are key ├── cardinality: [0 - 2] ├── with-scan &2 - │ ├── columns: upsert_cardid:48 + │ ├── columns: cardid:48 │ ├── mapping: - │ │ └── upsert_cardid:34 => upsert_cardid:48 + │ │ └── upsert_cardid:34 => cardid:48 │ └── cardinality: [1 - 2] └── filters (true) diff --git a/pkg/sql/opt/xform/testdata/external/trading-mutation b/pkg/sql/opt/xform/testdata/external/trading-mutation index 027549437559..20bc1c93615a 100644 --- a/pkg/sql/opt/xform/testdata/external/trading-mutation +++ b/pkg/sql/opt/xform/testdata/external/trading-mutation @@ -1336,12 +1336,12 @@ upsert transactiondetails ├── columns: ├── arbiter indexes: detailsprimarykey ├── canary column: transactiondetails.dealerid:26 - ├── fetch columns: transactiondetails.dealerid:26 transactiondetails.isbuy:27 transactiondate:28 cardid:29 quantity:30 transactiondetails.sellprice:31 transactiondetails.buyprice:32 transactiondetails.version:33 transactiondetails.discount:34 transactiondetails.extra:35 + ├── fetch columns: transactiondetails.dealerid:26 transactiondetails.isbuy:27 transactiondetails.transactiondate:28 transactiondetails.cardid:29 quantity:30 transactiondetails.sellprice:31 transactiondetails.buyprice:32 transactiondetails.version:33 transactiondetails.discount:34 transactiondetails.extra:35 ├── insert-mapping: │ ├── "?column?":14 => transactiondetails.dealerid:2 │ ├── bool:15 => transactiondetails.isbuy:3 - │ ├── current_timestamp:16 => transactiondate:4 - │ ├── int8:17 => cardid:5 + │ ├── current_timestamp:16 => transactiondetails.transactiondate:4 + │ ├── int8:17 => transactiondetails.cardid:5 │ ├── int8:18 => quantity:6 │ ├── sellprice:23 => transactiondetails.sellprice:7 │ ├── buyprice:24 => transactiondetails.buyprice:8 @@ -1355,13 +1355,13 @@ upsert transactiondetails ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: upsert_dealerid:37 upsert_isbuy:38 upsert_transactiondate:39 upsert_cardid:40 "?column?":14!null bool:15!null current_timestamp:16!null int8:17!null int8:18!null column21:21 sellprice:23 buyprice:24 discount:25!null transactiondetails.dealerid:26 transactiondetails.isbuy:27 transactiondate:28 cardid:29 quantity:30 transactiondetails.sellprice:31 transactiondetails.buyprice:32 transactiondetails.version:33 transactiondetails.discount:34 transactiondetails.extra:35 + │ ├── columns: upsert_dealerid:37 upsert_isbuy:38 upsert_transactiondate:39 upsert_cardid:40 "?column?":14!null bool:15!null current_timestamp:16!null int8:17!null int8:18!null column21:21 sellprice:23 buyprice:24 discount:25!null transactiondetails.dealerid:26 transactiondetails.isbuy:27 transactiondetails.transactiondate:28 transactiondetails.cardid:29 quantity:30 transactiondetails.sellprice:31 transactiondetails.buyprice:32 transactiondetails.version:33 transactiondetails.discount:34 transactiondetails.extra:35 │ ├── cardinality: [1 - 2] │ ├── volatile │ ├── key: (17,18) │ ├── fd: ()-->(14-16,25), (17,18)-->(21,23,24,26-35), (26-30)-->(31-35), (26)-->(37), (26,27)-->(38), (26,28)-->(39), (17,26,29)-->(40) │ ├── left-join (lookup transactiondetails) - │ │ ├── columns: "?column?":14!null bool:15!null current_timestamp:16!null int8:17!null int8:18!null column21:21 sellprice:23 buyprice:24 discount:25!null transactiondetails.dealerid:26 transactiondetails.isbuy:27 transactiondate:28 cardid:29 quantity:30 transactiondetails.sellprice:31 transactiondetails.buyprice:32 transactiondetails.version:33 transactiondetails.discount:34 transactiondetails.extra:35 + │ │ ├── columns: "?column?":14!null bool:15!null current_timestamp:16!null int8:17!null int8:18!null column21:21 sellprice:23 buyprice:24 discount:25!null transactiondetails.dealerid:26 transactiondetails.isbuy:27 transactiondetails.transactiondate:28 transactiondetails.cardid:29 quantity:30 transactiondetails.sellprice:31 transactiondetails.buyprice:32 transactiondetails.version:33 transactiondetails.discount:34 transactiondetails.extra:35 │ │ ├── key columns: [14 15 16 17 18] = [26 27 28 29 30] │ │ ├── lookup columns are key │ │ ├── cardinality: [1 - 2] @@ -1415,33 +1415,33 @@ upsert transactiondetails │ └── projections │ ├── CASE WHEN transactiondetails.dealerid:26 IS NULL THEN "?column?":14 ELSE transactiondetails.dealerid:26 END [as=upsert_dealerid:37, outer=(14,26)] │ ├── CASE WHEN transactiondetails.dealerid:26 IS NULL THEN bool:15 ELSE transactiondetails.isbuy:27 END [as=upsert_isbuy:38, outer=(15,26,27)] - │ ├── CASE WHEN transactiondetails.dealerid:26 IS NULL THEN current_timestamp:16 ELSE transactiondate:28 END [as=upsert_transactiondate:39, outer=(16,26,28)] - │ └── CASE WHEN transactiondetails.dealerid:26 IS NULL THEN int8:17 ELSE cardid:29 END [as=upsert_cardid:40, outer=(17,26,29)] + │ ├── CASE WHEN transactiondetails.dealerid:26 IS NULL THEN current_timestamp:16 ELSE transactiondetails.transactiondate:28 END [as=upsert_transactiondate:39, outer=(16,26,28)] + │ └── CASE WHEN transactiondetails.dealerid:26 IS NULL THEN int8:17 ELSE transactiondetails.cardid:29 END [as=upsert_cardid:40, outer=(17,26,29)] └── f-k-checks ├── f-k-checks-item: transactiondetails(dealerid,isbuy,transactiondate) -> transactions(dealerid,isbuy,date) │ └── anti-join (lookup transactions) - │ ├── columns: upsert_dealerid:43 upsert_isbuy:44 upsert_transactiondate:45 + │ ├── columns: dealerid:43 isbuy:44 transactiondate:45 │ ├── key columns: [43 44 45] = [46 47 48] │ ├── lookup columns are key │ ├── cardinality: [0 - 2] │ ├── with-scan &2 - │ │ ├── columns: upsert_dealerid:43 upsert_isbuy:44 upsert_transactiondate:45 + │ │ ├── columns: dealerid:43 isbuy:44 transactiondate:45 │ │ ├── mapping: - │ │ │ ├── upsert_dealerid:37 => upsert_dealerid:43 - │ │ │ ├── upsert_isbuy:38 => upsert_isbuy:44 - │ │ │ └── upsert_transactiondate:39 => upsert_transactiondate:45 + │ │ │ ├── upsert_dealerid:37 => dealerid:43 + │ │ │ ├── upsert_isbuy:38 => isbuy:44 + │ │ │ └── upsert_transactiondate:39 => transactiondate:45 │ │ └── cardinality: [1 - 2] │ └── filters (true) └── f-k-checks-item: transactiondetails(cardid) -> cards(id) └── anti-join (lookup cards) - ├── columns: upsert_cardid:56 + ├── columns: cardid:56 ├── key columns: [56] = [57] ├── lookup columns are key ├── cardinality: [0 - 2] ├── with-scan &2 - │ ├── columns: upsert_cardid:56 + │ ├── columns: cardid:56 │ ├── mapping: - │ │ └── upsert_cardid:40 => upsert_cardid:56 + │ │ └── upsert_cardid:40 => cardid:56 │ └── cardinality: [1 - 2] └── filters (true) diff --git a/pkg/sql/opt/xform/testdata/rules/scan b/pkg/sql/opt/xform/testdata/rules/scan index 9673096daeaf..91eb69b23c3b 100644 --- a/pkg/sql/opt/xform/testdata/rules/scan +++ b/pkg/sql/opt/xform/testdata/rules/scan @@ -415,16 +415,16 @@ insert fk_b └── f-k-checks └── f-k-checks-item: fk_b(a) -> fk_a(a) └── anti-join (lookup fk_a) - ├── columns: column2:6!null + ├── columns: a:6!null ├── key columns: [6] = [7] ├── lookup columns are key ├── cardinality: [0 - 1] ├── key: () ├── fd: ()-->(6) ├── with-scan &1 - │ ├── columns: column2:6!null + │ ├── columns: a:6!null │ ├── mapping: - │ │ └── column2:5 => column2:6 + │ │ └── column2:5 => a:6 │ ├── cardinality: [1 - 1] │ ├── key: () │ └── fd: ()-->(6) From 16d927cfb9fea36dca592acfb8a89ec2f4fc8b60 Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Fri, 12 Feb 2021 08:38:39 -0800 Subject: [PATCH 2/2] sql: support INSERT with partial UNIQUE WITHOUT INDEX constraints Uniqueness checks on INSERTs are now performed for partial UNIQUE WITHOUT INDEX constraints. The semi-join filters in the uniqueness checks filter out rows that do not satisfy the predicate. Rows on both sides of the join are filtered. This is required to prevent duplicate key violations from occurring for rows that do not satisfy the predicate of the partial unique constraint. The WithScan and Scan of the uniqueness check now produce all ordinary table columns, rather than just the PK and unique columns, because predicates may refer any columns in the table. Informs #59195 There is no release note because these constraints are gated behind the experimental_enable_unique_without_index_constraints session variable. Release note: None --- .../testdata/logic_test/regional_by_row | 18 +- pkg/sql/logictest/testdata/logic_test/unique | 43 + pkg/sql/opt/exec/execbuilder/testdata/unique | 515 ++++++++-- pkg/sql/opt/norm/testdata/rules/prune_cols | 196 ++-- pkg/sql/opt/optbuilder/mutation_builder.go | 39 +- .../opt/optbuilder/mutation_builder_unique.go | 101 +- .../optbuilder/testdata/unique-checks-insert | 888 +++++++++++++----- .../optbuilder/testdata/unique-checks-update | 343 ++++--- .../optbuilder/testdata/unique-checks-upsert | 786 +++++++++------- 9 files changed, 1966 insertions(+), 963 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row b/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row index f3cefcbb99cc..8d5d1dfa8290 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row +++ b/pkg/ccl/logictestccl/testdata/logic_test/regional_by_row @@ -297,7 +297,7 @@ vectorized: true │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@primary -│ │ equality: (lookup_join_const_col_@24, column1) = (crdb_region,pk) +│ │ equality: (lookup_join_const_col_@22, column1) = (crdb_region,pk) │ │ equality cols are key │ │ pred: column15 != crdb_region │ │ @@ -315,7 +315,7 @@ vectorized: true │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@regional_by_row_table_b_key -│ │ equality: (lookup_join_const_col_@36, column4) = (crdb_region,b) +│ │ equality: (lookup_join_const_col_@37, column4) = (crdb_region,b) │ │ equality cols are key │ │ pred: (column1 != pk) OR (column15 != crdb_region) │ │ @@ -333,7 +333,7 @@ vectorized: true │ └── • lookup join (semi) │ table: regional_by_row_table@new_idx - │ equality: (lookup_join_const_col_@49, column3, column4) = (crdb_region,a,b) + │ equality: (lookup_join_const_col_@52, column3, column4) = (crdb_region,a,b) │ equality cols are key │ pred: (column1 != pk) OR (column15 != crdb_region) │ @@ -383,7 +383,7 @@ vectorized: true │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@primary -│ │ equality: (lookup_join_const_col_@35, upsert_pk) = (crdb_region,pk) +│ │ equality: (lookup_join_const_col_@33, upsert_pk) = (crdb_region,pk) │ │ equality cols are key │ │ pred: column1 != crdb_region │ │ @@ -401,7 +401,7 @@ vectorized: true │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@regional_by_row_table_b_key -│ │ equality: (lookup_join_const_col_@47, column5) = (crdb_region,b) +│ │ equality: (lookup_join_const_col_@48, column5) = (crdb_region,b) │ │ equality cols are key │ │ pred: (upsert_pk != pk) OR (column1 != crdb_region) │ │ @@ -419,7 +419,7 @@ vectorized: true │ └── • lookup join (semi) │ table: regional_by_row_table@new_idx - │ equality: (lookup_join_const_col_@60, column4, column5) = (crdb_region,a,b) + │ equality: (lookup_join_const_col_@63, column4, column5) = (crdb_region,a,b) │ equality cols are key │ pred: (upsert_pk != pk) OR (column1 != crdb_region) │ @@ -465,7 +465,7 @@ vectorized: true │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@primary -│ │ equality: (lookup_join_const_col_@35, upsert_pk) = (crdb_region,pk) +│ │ equality: (lookup_join_const_col_@33, upsert_pk) = (crdb_region,pk) │ │ equality cols are key │ │ pred: column1 != crdb_region │ │ @@ -483,7 +483,7 @@ vectorized: true │ │ │ └── • lookup join (semi) │ │ table: regional_by_row_table@regional_by_row_table_b_key -│ │ equality: (lookup_join_const_col_@47, column5) = (crdb_region,b) +│ │ equality: (lookup_join_const_col_@48, column5) = (crdb_region,b) │ │ equality cols are key │ │ pred: (upsert_pk != pk) OR (column1 != crdb_region) │ │ @@ -501,7 +501,7 @@ vectorized: true │ └── • lookup join (semi) │ table: regional_by_row_table@new_idx - │ equality: (lookup_join_const_col_@60, column4, column5) = (crdb_region,a,b) + │ equality: (lookup_join_const_col_@63, column4, column5) = (crdb_region,a,b) │ equality cols are key │ pred: (upsert_pk != pk) OR (column1 != crdb_region) │ diff --git a/pkg/sql/logictest/testdata/logic_test/unique b/pkg/sql/logictest/testdata/logic_test/unique index 67de2a6d8781..acf32539420c 100644 --- a/pkg/sql/logictest/testdata/logic_test/unique +++ b/pkg/sql/logictest/testdata/logic_test/unique @@ -251,6 +251,49 @@ us-west foo 1 1 eu-west bar 2 2 +# Insert some non-null data into a table with a partial unique without index +# constraint. +statement ok +INSERT INTO uniq_partial VALUES (1, 1), (1, -1), (2, 2) + +# Partial unique constraint violation. +statement error pgcode 23505 pq: duplicate key value violates unique constraint "unique_a"\nDETAIL: Key \(a\)=\(1\) already exists\. +INSERT INTO uniq_partial VALUES (1, 3) + +# No partial unique constraint violation because b <= 0. +statement ok +INSERT INTO uniq_partial VALUES (1, -3) + +# Attempt to insert conflicting keys twice in the same statement. +statement error pgcode 23505 pq: duplicate key value violates unique constraint "unique_a"\nDETAIL: Key \(a\)=\(3\) already exists\. +INSERT INTO uniq_partial VALUES (3, 3), (3, 4) + +# Attempt to insert one conflicting key and one non-conflicting key in the same +# statement. +statement error pgcode 23505 pq: duplicate key value violates unique constraint "unique_a"\nDETAIL: Key \(a\)=\(1\) already exists\. +INSERT INTO uniq_partial VALUES (1, 3), (3, 3) + +# Insert some rows with NULL keys. +statement ok +INSERT INTO uniq_partial VALUES (NULL, 5), (5, 5), (NULL, 5) + +# Insert with non-constant input. +statement error pgcode 23505 pq: duplicate key value violates unique constraint "unique_a"\nDETAIL: Key \(a\)=\(1\) already exists\. +INSERT INTO uniq_partial SELECT w, x FROM other + +query II colnames,rowsort +SELECT * FROM uniq_partial +---- +a b +1 1 +1 -1 +1 -3 +2 2 +5 5 +NULL 5 +NULL 5 + + # -- Tests with UPDATE -- subtest Update diff --git a/pkg/sql/opt/exec/execbuilder/testdata/unique b/pkg/sql/opt/exec/execbuilder/testdata/unique index 64cb152a6c81..a9cc49842b92 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/unique +++ b/pkg/sql/opt/exec/execbuilder/testdata/unique @@ -71,6 +71,41 @@ CREATE TABLE uniq_fk_child ( FAMILY (c) ) +statement ok +CREATE TABLE uniq_partial ( + k INT PRIMARY KEY, + a INT, + b INT, + UNIQUE WITHOUT INDEX (a) WHERE b > 0, + UNIQUE WITHOUT INDEX (b) WHERE b > 0, + FAMILY (k), + FAMILY (a), + FAMILY (b) +) + +statement ok +CREATE TABLE uniq_partial_overlaps_pk ( + k INT PRIMARY KEY, + a INT, + b INT, + UNIQUE WITHOUT INDEX (k) WHERE b > 0, + UNIQUE WITHOUT INDEX (k, a) WHERE b > 0, + FAMILY (k), + FAMILY (a), + FAMILY (b) +) + +statement ok +CREATE TABLE uniq_partial_hidden_pk ( + a INT, + b INT, + c INT, + UNIQUE WITHOUT INDEX (b) WHERE c > 0, + FAMILY (a), + FAMILY (b), + FAMILY (c) +) + statement ok CREATE TYPE region AS ENUM ('us-east', 'us-west', 'eu-west') @@ -92,6 +127,19 @@ CREATE TABLE uniq_enum ( FAMILY (j) ) +statement ok +CREATE TABLE uniq_partial_enum ( + r region DEFAULT CASE (random()*3)::int WHEN 0 THEN 'us-east' WHEN 1 THEN 'us-west' ELSE 'eu-west' END, + i INT, + s STRING, + PRIMARY KEY (r, i), + UNIQUE WITHOUT INDEX (i) WHERE s IN ('foo', 'bar', 'baz'), + INDEX (r, i) WHERE s IN ('foo', 'bar', 'baz'), + FAMILY (r), + FAMILY (s), + FAMILY (i) +) + statement ok CREATE TABLE other (k INT, v INT, w INT NOT NULL, x INT, y INT) @@ -148,7 +196,7 @@ vectorized: true └── • scan buffer label: buffer 1 -# No need to plan checks for w since it's aways null. +# No need to plan checks for w since it's always null. # We still plan checks for x,y since neither column is null in all rows. query T EXPLAIN INSERT INTO uniq VALUES (4, 4, NULL, NULL, 1), (5, 5, NULL, 2, NULL) @@ -263,7 +311,7 @@ vectorized: true │ │ columns: () │ │ │ └── • hash join (right semi) -│ │ columns: (column3, column1) +│ │ columns: (column1, column2, column3, column4, column5) │ │ estimated row count: 0 (missing stats) │ │ equality: (w) = (column3) │ │ right cols are key @@ -275,13 +323,10 @@ vectorized: true │ │ table: uniq@primary │ │ spans: FULL SCAN │ │ -│ └── • project -│ │ columns: (column3, column1) -│ │ estimated row count: 0 (missing stats) -│ │ -│ └── • scan buffer -│ columns: (column1, column2, column3, column4, column5) -│ label: buffer 1 +│ └── • scan buffer +│ columns: (column1, column2, column3, column4, column5) +│ estimated row count: 0 (missing stats) +│ label: buffer 1 │ └── • constraint-check │ @@ -289,7 +334,7 @@ vectorized: true │ columns: () │ └── • hash join (right semi) - │ columns: (column4, column5, column1) + │ columns: (column1, column2, column3, column4, column5) │ estimated row count: 0 (missing stats) │ equality: (x, y) = (column4, column5) │ right cols are key @@ -301,13 +346,10 @@ vectorized: true │ table: uniq@primary │ spans: FULL SCAN │ - └── • project - │ columns: (column4, column5, column1) - │ estimated row count: 0 (missing stats) - │ - └── • scan buffer - columns: (column1, column2, column3, column4, column5) - label: buffer 1 + └── • scan buffer + columns: (column1, column2, column3, column4, column5) + estimated row count: 0 (missing stats) + label: buffer 1 # Insert with non-constant input. query T @@ -660,29 +702,29 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (column3, column1) +│ │ columns: (column1, column2, column3, column4) │ │ estimated row count: 1 (missing stats) │ │ │ └── • lookup join (semi) -│ │ columns: ("lookup_join_const_col_@14", column3, column1) +│ │ columns: ("lookup_join_const_col_@12", column1, column2, column3, column4) │ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@14, column3) = (r,i) +│ │ equality: (lookup_join_const_col_@12, column3) = (r,i) │ │ equality cols are key │ │ pred: column1 != r │ │ │ └── • cross join (inner) -│ │ columns: ("lookup_join_const_col_@14", column3, column1) +│ │ columns: ("lookup_join_const_col_@12", column1, column2, column3, column4) │ │ estimated row count: 6 │ │ │ ├── • values -│ │ columns: ("lookup_join_const_col_@14") +│ │ columns: ("lookup_join_const_col_@12") │ │ size: 1 column, 3 rows │ │ row 0, expr 0: 'us-east' │ │ row 1, expr 0: 'us-west' │ │ row 2, expr 0: 'eu-west' │ │ │ └── • project -│ │ columns: (column3, column1) +│ │ columns: (column1, column2, column3, column4) │ │ estimated row count: 2 │ │ │ └── • scan buffer @@ -695,29 +737,29 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column2, column4, column1, column3) + │ columns: (column1, column2, column3, column4) │ estimated row count: 1 (missing stats) │ └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@24", column2, column4, column1, column3) + │ columns: ("lookup_join_const_col_@22", column1, column2, column3, column4) │ table: uniq_enum@uniq_enum_r_s_j_key - │ equality: (lookup_join_const_col_@24, column2, column4) = (r,s,j) + │ equality: (lookup_join_const_col_@22, column2, column4) = (r,s,j) │ equality cols are key │ pred: (column1 != r) OR (column3 != i) │ └── • cross join (inner) - │ columns: ("lookup_join_const_col_@24", column2, column4, column1, column3) + │ columns: ("lookup_join_const_col_@22", column1, column2, column3, column4) │ estimated row count: 6 │ ├── • values - │ columns: ("lookup_join_const_col_@24") + │ columns: ("lookup_join_const_col_@22") │ size: 1 column, 3 rows │ row 0, expr 0: 'us-east' │ row 1, expr 0: 'us-west' │ row 2, expr 0: 'eu-west' │ └── • project - │ columns: (column2, column4, column1, column3) + │ columns: (column1, column2, column3, column4) │ estimated row count: 2 │ └── • scan buffer @@ -775,29 +817,29 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column2, column9) + │ columns: (column9, column1, column2, column10) │ estimated row count: 1 (missing stats) │ └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@14", column2, column9) + │ columns: ("lookup_join_const_col_@12", column9, column1, column2, column10) │ table: uniq_enum@primary - │ equality: (lookup_join_const_col_@14, column2) = (r,i) + │ equality: (lookup_join_const_col_@12, column2) = (r,i) │ equality cols are key │ pred: column9 != r │ └── • cross join (inner) - │ columns: ("lookup_join_const_col_@14", column2, column9) + │ columns: ("lookup_join_const_col_@12", column9, column1, column2, column10) │ estimated row count: 6 │ ├── • values - │ columns: ("lookup_join_const_col_@14") + │ columns: ("lookup_join_const_col_@12") │ size: 1 column, 3 rows │ row 0, expr 0: 'us-east' │ row 1, expr 0: 'us-west' │ row 2, expr 0: 'eu-west' │ └── • project - │ columns: (column2, column9) + │ columns: (column9, column1, column2, column10) │ estimated row count: 2 │ └── • scan buffer @@ -879,29 +921,29 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (column3, column1) +│ │ columns: (column1, column2, column3, column4) │ │ estimated row count: 0 (missing stats) │ │ │ └── • lookup join (semi) -│ │ columns: ("lookup_join_const_col_@38", column3, column1) +│ │ columns: ("lookup_join_const_col_@36", column1, column2, column3, column4) │ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@38, column3) = (r,i) +│ │ equality: (lookup_join_const_col_@36, column3) = (r,i) │ │ equality cols are key │ │ pred: column1 != r │ │ │ └── • cross join (inner) -│ │ columns: ("lookup_join_const_col_@38", column3, column1) +│ │ columns: ("lookup_join_const_col_@36", column1, column2, column3, column4) │ │ estimated row count: 0 (missing stats) │ │ │ ├── • values -│ │ columns: ("lookup_join_const_col_@38") +│ │ columns: ("lookup_join_const_col_@36") │ │ size: 1 column, 3 rows │ │ row 0, expr 0: 'us-east' │ │ row 1, expr 0: 'us-west' │ │ row 2, expr 0: 'eu-west' │ │ │ └── • project -│ │ columns: (column3, column1) +│ │ columns: (column1, column2, column3, column4) │ │ estimated row count: 0 (missing stats) │ │ │ └── • scan buffer @@ -914,35 +956,337 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column2, column4, column1, column3) + │ columns: (column1, column2, column3, column4) │ estimated row count: 0 (missing stats) │ └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@48", column2, column4, column1, column3) + │ columns: ("lookup_join_const_col_@46", column1, column2, column3, column4) │ table: uniq_enum@uniq_enum_r_s_j_key - │ equality: (lookup_join_const_col_@48, column2, column4) = (r,s,j) + │ equality: (lookup_join_const_col_@46, column2, column4) = (r,s,j) │ equality cols are key │ pred: (column1 != r) OR (column3 != i) │ └── • cross join (inner) - │ columns: ("lookup_join_const_col_@48", column2, column4, column1, column3) + │ columns: ("lookup_join_const_col_@46", column1, column2, column3, column4) │ estimated row count: 0 (missing stats) │ ├── • values - │ columns: ("lookup_join_const_col_@48") + │ columns: ("lookup_join_const_col_@46") │ size: 1 column, 3 rows │ row 0, expr 0: 'us-east' │ row 1, expr 0: 'us-west' │ row 2, expr 0: 'eu-west' │ └── • project - │ columns: (column2, column4, column1, column3) + │ columns: (column1, column2, column3, column4) │ estimated row count: 0 (missing stats) │ └── • scan buffer columns: (column1, column2, column3, column4, check1) label: buffer 1 +# None of the inserted values have nulls. +query T +EXPLAIN INSERT INTO uniq_partial VALUES (1, 1, 1), (2, 2, 2) +---- +distribution: local +vectorized: true +· +• root +│ +├── • insert +│ │ into: uniq_partial(k, a, b) +│ │ +│ └── • buffer +│ │ label: buffer 1 +│ │ +│ └── • values +│ size: 3 columns, 2 rows +│ +├── • constraint-check +│ │ +│ └── • error if rows +│ │ +│ └── • hash join (right semi) +│ │ equality: (a) = (column2) +│ │ pred: column1 != k +│ │ +│ ├── • filter +│ │ │ filter: b > 0 +│ │ │ +│ │ └── • scan +│ │ missing stats +│ │ table: uniq_partial@primary +│ │ spans: FULL SCAN +│ │ +│ └── • filter +│ │ filter: column3 > 0 +│ │ +│ └── • scan buffer +│ label: buffer 1 +│ +└── • constraint-check + │ + └── • error if rows + │ + └── • hash join (right semi) + │ equality: (b) = (column3) + │ pred: column1 != k + │ + ├── • filter + │ │ filter: b > 0 + │ │ + │ └── • scan + │ missing stats + │ table: uniq_partial@primary + │ spans: FULL SCAN + │ + └── • filter + │ filter: column3 > 0 + │ + └── • scan buffer + label: buffer 1 + +# No need to plan checks for a since it's always null. +query T +EXPLAIN INSERT INTO uniq_partial VALUES (1, NULL, 1), (2, NULL, 2) +---- +distribution: local +vectorized: true +· +• root +│ +├── • insert +│ │ into: uniq_partial(k, a, b) +│ │ +│ └── • buffer +│ │ label: buffer 1 +│ │ +│ └── • values +│ size: 3 columns, 2 rows +│ +└── • constraint-check + │ + └── • error if rows + │ + └── • hash join (right semi) + │ equality: (b) = (column3) + │ pred: column1 != k + │ + ├── • filter + │ │ filter: b > 0 + │ │ + │ └── • scan + │ missing stats + │ table: uniq_partial@primary + │ spans: FULL SCAN + │ + └── • filter + │ filter: column3 > 0 + │ + └── • scan buffer + label: buffer 1 + +# Insert with non-constant input. +query T +EXPLAIN INSERT INTO uniq_partial SELECT k, v, w FROM other +---- +distribution: local +vectorized: true +· +• root +│ +├── • insert +│ │ into: uniq_partial(k, a, b) +│ │ +│ └── • buffer +│ │ label: buffer 1 +│ │ +│ └── • scan +│ missing stats +│ table: other@primary +│ spans: FULL SCAN +│ +├── • constraint-check +│ │ +│ └── • error if rows +│ │ +│ └── • hash join (right semi) +│ │ equality: (a) = (v) +│ │ pred: k != k +│ │ +│ ├── • filter +│ │ │ filter: b > 0 +│ │ │ +│ │ └── • scan +│ │ missing stats +│ │ table: uniq_partial@primary +│ │ spans: FULL SCAN +│ │ +│ └── • filter +│ │ filter: w > 0 +│ │ +│ └── • scan buffer +│ label: buffer 1 +│ +└── • constraint-check + │ + └── • error if rows + │ + └── • hash join (right semi) + │ equality: (b) = (w) + │ pred: k != k + │ + ├── • filter + │ │ filter: b > 0 + │ │ + │ └── • scan + │ missing stats + │ table: uniq_partial@primary + │ spans: FULL SCAN + │ + └── • filter + │ filter: w > 0 + │ + └── • scan buffer + label: buffer 1 + +# No need to build uniqueness checks when the primary key columns are a subset +# of the partial unique constraint columns. +query T +EXPLAIN INSERT INTO uniq_partial_overlaps_pk VALUES (1, 1, 1), (2, 2, 2) +---- +distribution: local +vectorized: true +· +• insert fast path + into: uniq_partial_overlaps_pk(k, a, b) + auto commit + size: 3 columns, 2 rows + +# Insert with non-constant input. +# Add inequality filters for the hidden primary key column. +query T +EXPLAIN INSERT INTO uniq_partial_hidden_pk SELECT k, v, x FROM other +---- +distribution: local +vectorized: true +· +• root +│ +├── • insert +│ │ into: uniq_partial_hidden_pk(a, b, c, rowid) +│ │ +│ └── • buffer +│ │ label: buffer 1 +│ │ +│ └── • render +│ │ +│ └── • scan +│ missing stats +│ table: other@primary +│ spans: FULL SCAN +│ +└── • constraint-check + │ + └── • error if rows + │ + └── • hash join (semi) + │ equality: (v) = (b) + │ pred: column15 != rowid + │ + ├── • filter + │ │ filter: x > 0 + │ │ + │ └── • scan buffer + │ label: buffer 1 + │ + └── • filter + │ filter: c > 0 + │ + └── • scan + missing stats + table: uniq_partial_hidden_pk@primary + spans: FULL SCAN + +# Test that we use the partial index when available for the insert checks. +query T +EXPLAIN (VERBOSE) INSERT INTO uniq_partial_enum VALUES ('us-west', 1, 'foo'), ('us-east', 2, 'bar') +---- +distribution: local +vectorized: true +· +• root +│ columns: () +│ +├── • insert +│ │ columns: () +│ │ estimated row count: 0 (missing stats) +│ │ into: uniq_partial_enum(r, i, s) +│ │ +│ └── • buffer +│ │ columns: (column1, column2, column3, check1, partial_index_put1) +│ │ label: buffer 1 +│ │ +│ └── • render +│ │ columns: (column1, column2, column3, check1, partial_index_put1) +│ │ estimated row count: 2 +│ │ render partial_index_put1: column3 IN ('bar', 'baz', 'foo') +│ │ render check1: column1 IN ('us-east', 'us-west', 'eu-west') +│ │ render column1: column1 +│ │ render column2: column2 +│ │ render column3: column3 +│ │ +│ └── • values +│ columns: (column1, column2, column3) +│ size: 3 columns, 2 rows +│ row 0, expr 0: 'us-west' +│ row 0, expr 1: 1 +│ row 0, expr 2: 'foo' +│ row 1, expr 0: 'us-east' +│ row 1, expr 1: 2 +│ row 1, expr 2: 'bar' +│ +└── • constraint-check + │ + └── • error if rows + │ columns: () + │ + └── • project + │ columns: (column1, column2, column3) + │ estimated row count: 1 (missing stats) + │ + └── • lookup join (semi) + │ columns: ("lookup_join_const_col_@11", column1, column2, column3) + │ table: uniq_partial_enum@uniq_partial_enum_r_i_idx (partial index) + │ equality: (lookup_join_const_col_@11, column2) = (r,i) + │ equality cols are key + │ pred: column1 != r + │ + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@11", column1, column2, column3) + │ estimated row count: 6 + │ + ├── • values + │ columns: ("lookup_join_const_col_@11") + │ size: 1 column, 3 rows + │ row 0, expr 0: 'us-east' + │ row 1, expr 0: 'us-west' + │ row 2, expr 0: 'eu-west' + │ + └── • filter + │ columns: (column1, column2, column3) + │ estimated row count: 2 + │ filter: column3 IN ('bar', 'baz', 'foo') + │ + └── • project + │ columns: (column1, column2, column3) + │ estimated row count: 2 + │ + └── • scan buffer + columns: (column1, column2, column3, check1, partial_index_put1) + label: buffer 1 + # -- Tests with UPDATE -- subtest Update @@ -1002,7 +1346,7 @@ vectorized: true table: uniq@primary spans: FULL SCAN -# No need to plan checks for x,y since x is aways null. +# No need to plan checks for x,y since x is always null. # Also update the primary key. query T EXPLAIN UPDATE uniq SET k = 1, w = 2, x = NULL @@ -1408,22 +1752,22 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (i_new, r_new) +│ │ columns: (r_new, s_new, i_new, j) │ │ estimated row count: 3 (missing stats) │ │ │ └── • lookup join (semi) -│ │ columns: (i_new, r_new, "lookup_join_const_col_@19") +│ │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@17") │ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@19, i_new) = (r,i) +│ │ equality: (lookup_join_const_col_@17, i_new) = (r,i) │ │ equality cols are key │ │ pred: r_new != r │ │ │ └── • cross join (inner) -│ │ columns: (i_new, r_new, "lookup_join_const_col_@19") +│ │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@17") │ │ estimated row count: 30 (missing stats) │ │ │ ├── • project -│ │ │ columns: (i_new, r_new) +│ │ │ columns: (r_new, s_new, i_new, j) │ │ │ estimated row count: 10 (missing stats) │ │ │ │ │ └── • scan buffer @@ -1431,7 +1775,7 @@ vectorized: true │ │ label: buffer 1 │ │ │ └── • values -│ columns: ("lookup_join_const_col_@19") +│ columns: ("lookup_join_const_col_@17") │ size: 1 column, 3 rows │ row 0, expr 0: 'us-east' │ row 1, expr 0: 'us-west' @@ -1443,22 +1787,22 @@ vectorized: true │ columns: () │ └── • project - │ columns: (s_new, j, r_new, i_new) + │ columns: (r_new, s_new, i_new, j) │ estimated row count: 3 (missing stats) │ └── • lookup join (semi) - │ columns: (s_new, j, r_new, i_new, "lookup_join_const_col_@29") + │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@27") │ table: uniq_enum@uniq_enum_r_s_j_key - │ equality: (lookup_join_const_col_@29, s_new, j) = (r,s,j) + │ equality: (lookup_join_const_col_@27, s_new, j) = (r,s,j) │ equality cols are key │ pred: (r_new != r) OR (i_new != i) │ └── • cross join (inner) - │ columns: (s_new, j, r_new, i_new, "lookup_join_const_col_@29") + │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@27") │ estimated row count: 30 (missing stats) │ ├── • project - │ │ columns: (s_new, j, r_new, i_new) + │ │ columns: (r_new, s_new, i_new, j) │ │ estimated row count: 10 (missing stats) │ │ │ └── • scan buffer @@ -1466,7 +1810,7 @@ vectorized: true │ label: buffer 1 │ └── • values - columns: ("lookup_join_const_col_@29") + columns: ("lookup_join_const_col_@27") size: 1 column, 3 rows row 0, expr 0: 'us-east' row 1, expr 0: 'us-west' @@ -1596,7 +1940,8 @@ vectorized: true └── • scan buffer label: buffer 1 -# TODO(rytaft): No need to plan checks for w since it's aways NULL (see #58300). +# TODO(rytaft): No need to plan checks for w since it's always NULL (see +# #58300). query T EXPLAIN UPSERT INTO uniq (k, w, x) VALUES (1, NULL, 1), (2, NULL, NULL) ---- @@ -2218,29 +2563,29 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (upsert_i, upsert_r) +│ │ columns: (upsert_r, column2, upsert_i, column4) │ │ estimated row count: 1 (missing stats) │ │ │ └── • lookup join (semi) -│ │ columns: ("lookup_join_const_col_@22", upsert_i, upsert_r) +│ │ columns: ("lookup_join_const_col_@20", upsert_r, column2, upsert_i, column4) │ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@22, upsert_i) = (r,i) +│ │ equality: (lookup_join_const_col_@20, upsert_i) = (r,i) │ │ equality cols are key │ │ pred: upsert_r != r │ │ │ └── • cross join (inner) -│ │ columns: ("lookup_join_const_col_@22", upsert_i, upsert_r) +│ │ columns: ("lookup_join_const_col_@20", upsert_r, column2, upsert_i, column4) │ │ estimated row count: 6 (missing stats) │ │ │ ├── • values -│ │ columns: ("lookup_join_const_col_@22") +│ │ columns: ("lookup_join_const_col_@20") │ │ size: 1 column, 3 rows │ │ row 0, expr 0: 'us-east' │ │ row 1, expr 0: 'us-west' │ │ row 2, expr 0: 'eu-west' │ │ │ └── • project -│ │ columns: (upsert_i, upsert_r) +│ │ columns: (upsert_r, column2, upsert_i, column4) │ │ estimated row count: 2 (missing stats) │ │ │ └── • scan buffer @@ -2253,29 +2598,29 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column2, column4, upsert_r, upsert_i) + │ columns: (upsert_r, column2, upsert_i, column4) │ estimated row count: 1 (missing stats) │ └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@32", column2, column4, upsert_r, upsert_i) + │ columns: ("lookup_join_const_col_@30", upsert_r, column2, upsert_i, column4) │ table: uniq_enum@uniq_enum_r_s_j_key - │ equality: (lookup_join_const_col_@32, column2, column4) = (r,s,j) + │ equality: (lookup_join_const_col_@30, column2, column4) = (r,s,j) │ equality cols are key │ pred: (upsert_r != r) OR (upsert_i != i) │ └── • cross join (inner) - │ columns: ("lookup_join_const_col_@32", column2, column4, upsert_r, upsert_i) + │ columns: ("lookup_join_const_col_@30", upsert_r, column2, upsert_i, column4) │ estimated row count: 6 (missing stats) │ ├── • values - │ columns: ("lookup_join_const_col_@32") + │ columns: ("lookup_join_const_col_@30") │ size: 1 column, 3 rows │ row 0, expr 0: 'us-east' │ row 1, expr 0: 'us-west' │ row 2, expr 0: 'eu-west' │ └── • project - │ columns: (column2, column4, upsert_r, upsert_i) + │ columns: (upsert_r, column2, upsert_i, column4) │ estimated row count: 2 (missing stats) │ └── • scan buffer @@ -2363,29 +2708,29 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (upsert_i, upsert_r) +│ │ columns: (upsert_r, upsert_s, upsert_i, upsert_j) │ │ estimated row count: 1 (missing stats) │ │ │ └── • lookup join (semi) -│ │ columns: ("lookup_join_const_col_@25", upsert_i, upsert_r) +│ │ columns: ("lookup_join_const_col_@23", upsert_r, upsert_s, upsert_i, upsert_j) │ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@25, upsert_i) = (r,i) +│ │ equality: (lookup_join_const_col_@23, upsert_i) = (r,i) │ │ equality cols are key │ │ pred: upsert_r != r │ │ │ └── • cross join (inner) -│ │ columns: ("lookup_join_const_col_@25", upsert_i, upsert_r) +│ │ columns: ("lookup_join_const_col_@23", upsert_r, upsert_s, upsert_i, upsert_j) │ │ estimated row count: 6 (missing stats) │ │ │ ├── • values -│ │ columns: ("lookup_join_const_col_@25") +│ │ columns: ("lookup_join_const_col_@23") │ │ size: 1 column, 3 rows │ │ row 0, expr 0: 'us-east' │ │ row 1, expr 0: 'us-west' │ │ row 2, expr 0: 'eu-west' │ │ │ └── • project -│ │ columns: (upsert_i, upsert_r) +│ │ columns: (upsert_r, upsert_s, upsert_i, upsert_j) │ │ estimated row count: 2 (missing stats) │ │ │ └── • scan buffer @@ -2398,29 +2743,29 @@ vectorized: true │ columns: () │ └── • project - │ columns: (upsert_s, upsert_j, upsert_r, upsert_i) + │ columns: (upsert_r, upsert_s, upsert_i, upsert_j) │ estimated row count: 1 (missing stats) │ └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@35", upsert_s, upsert_j, upsert_r, upsert_i) + │ columns: ("lookup_join_const_col_@33", upsert_r, upsert_s, upsert_i, upsert_j) │ table: uniq_enum@uniq_enum_r_s_j_key - │ equality: (lookup_join_const_col_@35, upsert_s, upsert_j) = (r,s,j) + │ equality: (lookup_join_const_col_@33, upsert_s, upsert_j) = (r,s,j) │ equality cols are key │ pred: (upsert_r != r) OR (upsert_i != i) │ └── • cross join (inner) - │ columns: ("lookup_join_const_col_@35", upsert_s, upsert_j, upsert_r, upsert_i) + │ columns: ("lookup_join_const_col_@33", upsert_r, upsert_s, upsert_i, upsert_j) │ estimated row count: 6 (missing stats) │ ├── • values - │ columns: ("lookup_join_const_col_@35") + │ columns: ("lookup_join_const_col_@33") │ size: 1 column, 3 rows │ row 0, expr 0: 'us-east' │ row 1, expr 0: 'us-west' │ row 2, expr 0: 'eu-west' │ └── • project - │ columns: (upsert_s, upsert_j, upsert_r, upsert_i) + │ columns: (upsert_r, upsert_s, upsert_i, upsert_j) │ estimated row count: 2 (missing stats) │ └── • scan buffer diff --git a/pkg/sql/opt/norm/testdata/rules/prune_cols b/pkg/sql/opt/norm/testdata/rules/prune_cols index aee982723767..922dfec7bffd 100644 --- a/pkg/sql/opt/norm/testdata/rules/prune_cols +++ b/pkg/sql/opt/norm/testdata/rules/prune_cols @@ -3591,19 +3591,19 @@ update uniq ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: w_new:15!null x_new:16!null uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 + │ ├── columns: w_new:15!null x_new:16!null uniq.k:8!null uniq.v:9 uniq.w:10 uniq.x:11 uniq.y:12 uniq.z:13 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(8,10-12,15,16) + │ ├── fd: ()-->(8-13,15,16) │ ├── select - │ │ ├── columns: uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 + │ │ ├── columns: uniq.k:8!null uniq.v:9 uniq.w:10 uniq.x:11 uniq.y:12 uniq.z:13 │ │ ├── cardinality: [0 - 1] │ │ ├── key: () - │ │ ├── fd: ()-->(8,10-12) + │ │ ├── fd: ()-->(8-13) │ │ ├── scan uniq - │ │ │ ├── columns: uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 + │ │ │ ├── columns: uniq.k:8!null uniq.v:9 uniq.w:10 uniq.x:11 uniq.y:12 uniq.z:13 │ │ │ ├── key: (8) - │ │ │ └── fd: (8)-->(10-12) + │ │ │ └── fd: (8)-->(9-13), (13)~~>(8-12) │ │ └── filters │ │ └── uniq.k:8 = 3 [outer=(8), constraints=(/8: [/3 - /3]; tight), fd=()-->(8)] │ └── projections @@ -3612,48 +3612,55 @@ update uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:17!null k:18!null + │ ├── columns: k:24!null v:25 w:26!null x:27!null y:28 z:29 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(17,18) + │ ├── fd: ()-->(24-29) │ ├── with-scan &1 - │ │ ├── columns: w:17!null k:18!null + │ │ ├── columns: k:24!null v:25 w:26!null x:27!null y:28 z:29 │ │ ├── mapping: - │ │ │ ├── w_new:15 => w:17 - │ │ │ └── uniq.k:8 => k:18 + │ │ │ ├── uniq.k:8 => k:24 + │ │ │ ├── uniq.v:9 => v:25 + │ │ │ ├── w_new:15 => w:26 + │ │ │ ├── x_new:16 => x:27 + │ │ │ ├── uniq.y:12 => y:28 + │ │ │ └── uniq.z:13 => z:29 │ │ ├── cardinality: [0 - 1] │ │ ├── key: () - │ │ └── fd: ()-->(17,18) + │ │ └── fd: ()-->(24-29) │ ├── scan uniq - │ │ ├── columns: uniq.k:19!null uniq.w:21 - │ │ ├── key: (19) - │ │ └── fd: (19)-->(21) + │ │ ├── columns: uniq.k:17!null uniq.w:19 + │ │ ├── key: (17) + │ │ └── fd: (17)-->(19) │ └── filters - │ ├── w:17 = uniq.w:21 [outer=(17,21), constraints=(/17: (/NULL - ]; /21: (/NULL - ]), fd=(17)==(21), (21)==(17)] - │ └── k:18 != uniq.k:19 [outer=(18,19), constraints=(/18: (/NULL - ]; /19: (/NULL - ])] + │ ├── w:26 = uniq.w:19 [outer=(19,26), constraints=(/19: (/NULL - ]; /26: (/NULL - ]), fd=(19)==(26), (26)==(19)] + │ └── k:24 != uniq.k:17 [outer=(17,24), constraints=(/17: (/NULL - ]; /24: (/NULL - ])] └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:26!null y:27 k:28!null + ├── columns: k:37!null v:38 w:39!null x:40!null y:41 z:42 ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(26-28) + ├── fd: ()-->(37-42) ├── with-scan &1 - │ ├── columns: x:26!null y:27 k:28!null + │ ├── columns: k:37!null v:38 w:39!null x:40!null y:41 z:42 │ ├── mapping: - │ │ ├── x_new:16 => x:26 - │ │ ├── uniq.y:12 => y:27 - │ │ └── uniq.k:8 => k:28 + │ │ ├── uniq.k:8 => k:37 + │ │ ├── uniq.v:9 => v:38 + │ │ ├── w_new:15 => w:39 + │ │ ├── x_new:16 => x:40 + │ │ ├── uniq.y:12 => y:41 + │ │ └── uniq.z:13 => z:42 │ ├── cardinality: [0 - 1] │ ├── key: () - │ └── fd: ()-->(26-28) + │ └── fd: ()-->(37-42) ├── scan uniq - │ ├── columns: uniq.k:29!null uniq.x:32 uniq.y:33 - │ ├── key: (29) - │ └── fd: (29)-->(32,33) + │ ├── columns: uniq.k:30!null uniq.x:33 uniq.y:34 + │ ├── key: (30) + │ └── fd: (30)-->(33,34) └── filters - ├── x:26 = uniq.x:32 [outer=(26,32), constraints=(/26: (/NULL - ]; /32: (/NULL - ]), fd=(26)==(32), (32)==(26)] - ├── y:27 = uniq.y:33 [outer=(27,33), constraints=(/27: (/NULL - ]; /33: (/NULL - ]), fd=(27)==(33), (33)==(27)] - └── k:28 != uniq.k:29 [outer=(28,29), constraints=(/28: (/NULL - ]; /29: (/NULL - ])] + ├── x:40 = uniq.x:33 [outer=(33,40), constraints=(/33: (/NULL - ]; /40: (/NULL - ]), fd=(33)==(40), (40)==(33)] + ├── y:41 = uniq.y:34 [outer=(34,41), constraints=(/34: (/NULL - ]; /41: (/NULL - ]), fd=(34)==(41), (41)==(34)] + └── k:37 != uniq.k:30 [outer=(30,37), constraints=(/30: (/NULL - ]; /37: (/NULL - ])] # Do not prune columns that are needed for foreign key checks or cascades. norm expect=PruneMutationInputCols @@ -3669,7 +3676,7 @@ upsert uniq_fk_parent │ ├── column2:8 => uniq_fk_parent.a:2 │ ├── column9:9 => uniq_fk_parent.b:3 │ ├── column9:9 => uniq_fk_parent.c:4 - │ └── column9:9 => d:5 + │ └── column9:9 => uniq_fk_parent.d:5 ├── update-mapping: │ └── upsert_c:20 => uniq_fk_parent.c:4 ├── input binding: &1 @@ -3678,16 +3685,16 @@ upsert uniq_fk_parent ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: upsert_k:17 upsert_a:18 upsert_b:19 upsert_c:20 column1:7!null column2:8!null column9:9 uniq_fk_parent.k:10 uniq_fk_parent.b:12 uniq_fk_parent.c:13 + │ ├── columns: upsert_k:17 upsert_a:18 upsert_b:19 upsert_c:20 upsert_d:21 column1:7!null column2:8!null column9:9 uniq_fk_parent.k:10 uniq_fk_parent.b:12 uniq_fk_parent.c:13 │ ├── cardinality: [1 - 1] │ ├── key: () - │ ├── fd: ()-->(7-10,12,13,17-20) + │ ├── fd: ()-->(7-10,12,13,17-21) │ ├── left-join (cross) - │ │ ├── columns: column1:7!null column2:8!null column9:9 uniq_fk_parent.k:10 uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 + │ │ ├── columns: column1:7!null column2:8!null column9:9 uniq_fk_parent.k:10 uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 uniq_fk_parent.d:14 │ │ ├── cardinality: [1 - 1] │ │ ├── multiplicity: left-rows(exactly-one), right-rows(exactly-one) │ │ ├── key: () - │ │ ├── fd: ()-->(7-13) + │ │ ├── fd: ()-->(7-14) │ │ ├── values │ │ │ ├── columns: column1:7!null column2:8!null column9:9 │ │ │ ├── cardinality: [1 - 1] @@ -3695,14 +3702,14 @@ upsert uniq_fk_parent │ │ │ ├── fd: ()-->(7-9) │ │ │ └── (2, 1, NULL) │ │ ├── select - │ │ │ ├── columns: uniq_fk_parent.k:10!null uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 + │ │ │ ├── columns: uniq_fk_parent.k:10!null uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 uniq_fk_parent.d:14 │ │ │ ├── cardinality: [0 - 1] │ │ │ ├── key: () - │ │ │ ├── fd: ()-->(10-13) + │ │ │ ├── fd: ()-->(10-14) │ │ │ ├── scan uniq_fk_parent - │ │ │ │ ├── columns: uniq_fk_parent.k:10!null uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 + │ │ │ │ ├── columns: uniq_fk_parent.k:10!null uniq_fk_parent.a:11 uniq_fk_parent.b:12 uniq_fk_parent.c:13 uniq_fk_parent.d:14 │ │ │ │ ├── key: (10) - │ │ │ │ └── fd: (10)-->(11-13) + │ │ │ │ └── fd: (10)-->(11-14) │ │ │ └── filters │ │ │ └── uniq_fk_parent.k:10 = 2 [outer=(10), constraints=(/10: [/2 - /2]; tight), fd=()-->(10)] │ │ └── filters (true) @@ -3710,52 +3717,58 @@ upsert uniq_fk_parent │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column1:7 ELSE uniq_fk_parent.k:10 END [as=upsert_k:17, outer=(7,10)] │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column2:8 ELSE uniq_fk_parent.a:11 END [as=upsert_a:18, outer=(8,10,11)] │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column9:9 ELSE uniq_fk_parent.b:12 END [as=upsert_b:19, outer=(9,10,12)] - │ └── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column9:9 ELSE 1 END [as=upsert_c:20, outer=(9,10)] + │ ├── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column9:9 ELSE 1 END [as=upsert_c:20, outer=(9,10)] + │ └── CASE WHEN uniq_fk_parent.k:10 IS NULL THEN column9:9 ELSE uniq_fk_parent.d:14 END [as=upsert_d:21, outer=(9,10,14)] └── unique-checks ├── unique-checks-item: uniq_fk_parent(a) │ └── semi-join (hash) - │ ├── columns: a:22 k:23 + │ ├── columns: k:28 a:29 b:30 c:31 d:32 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(22,23) + │ ├── fd: ()-->(28-32) │ ├── with-scan &1 - │ │ ├── columns: a:22 k:23 + │ │ ├── columns: k:28 a:29 b:30 c:31 d:32 │ │ ├── mapping: - │ │ │ ├── upsert_a:18 => a:22 - │ │ │ └── upsert_k:17 => k:23 + │ │ │ ├── upsert_k:17 => k:28 + │ │ │ ├── upsert_a:18 => a:29 + │ │ │ ├── upsert_b:19 => b:30 + │ │ │ ├── upsert_c:20 => c:31 + │ │ │ └── upsert_d:21 => d:32 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () - │ │ └── fd: ()-->(22,23) + │ │ └── fd: ()-->(28-32) │ ├── scan uniq_fk_parent - │ │ ├── columns: uniq_fk_parent.k:24!null uniq_fk_parent.a:25 - │ │ ├── key: (24) - │ │ └── fd: (24)-->(25) + │ │ ├── columns: uniq_fk_parent.k:22!null uniq_fk_parent.a:23 + │ │ ├── key: (22) + │ │ └── fd: (22)-->(23) │ └── filters - │ ├── a:22 = uniq_fk_parent.a:25 [outer=(22,25), constraints=(/22: (/NULL - ]; /25: (/NULL - ]), fd=(22)==(25), (25)==(22)] - │ └── k:23 != uniq_fk_parent.k:24 [outer=(23,24), constraints=(/23: (/NULL - ]; /24: (/NULL - ])] + │ ├── a:29 = uniq_fk_parent.a:23 [outer=(23,29), constraints=(/23: (/NULL - ]; /29: (/NULL - ]), fd=(23)==(29), (29)==(23)] + │ └── k:28 != uniq_fk_parent.k:22 [outer=(22,28), constraints=(/22: (/NULL - ]; /28: (/NULL - ])] └── unique-checks-item: uniq_fk_parent(b,c) └── semi-join (hash) - ├── columns: b:30 c:31 k:32 + ├── columns: k:39 a:40 b:41 c:42 d:43 ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(30-32) + ├── fd: ()-->(39-43) ├── with-scan &1 - │ ├── columns: b:30 c:31 k:32 + │ ├── columns: k:39 a:40 b:41 c:42 d:43 │ ├── mapping: - │ │ ├── upsert_b:19 => b:30 - │ │ ├── upsert_c:20 => c:31 - │ │ └── upsert_k:17 => k:32 + │ │ ├── upsert_k:17 => k:39 + │ │ ├── upsert_a:18 => a:40 + │ │ ├── upsert_b:19 => b:41 + │ │ ├── upsert_c:20 => c:42 + │ │ └── upsert_d:21 => d:43 │ ├── cardinality: [1 - 1] │ ├── key: () - │ └── fd: ()-->(30-32) + │ └── fd: ()-->(39-43) ├── scan uniq_fk_parent │ ├── columns: uniq_fk_parent.k:33!null uniq_fk_parent.b:35 uniq_fk_parent.c:36 │ ├── key: (33) │ └── fd: (33)-->(35,36) └── filters - ├── b:30 = uniq_fk_parent.b:35 [outer=(30,35), constraints=(/30: (/NULL - ]; /35: (/NULL - ]), fd=(30)==(35), (35)==(30)] - ├── c:31 = uniq_fk_parent.c:36 [outer=(31,36), constraints=(/31: (/NULL - ]; /36: (/NULL - ]), fd=(31)==(36), (36)==(31)] - └── k:32 != uniq_fk_parent.k:33 [outer=(32,33), constraints=(/32: (/NULL - ]; /33: (/NULL - ])] + ├── b:41 = uniq_fk_parent.b:35 [outer=(35,41), constraints=(/35: (/NULL - ]; /41: (/NULL - ]), fd=(35)==(41), (41)==(35)] + ├── c:42 = uniq_fk_parent.c:36 [outer=(36,42), constraints=(/36: (/NULL - ]; /42: (/NULL - ]), fd=(36)==(42), (42)==(36)] + └── k:39 != uniq_fk_parent.k:33 [outer=(33,39), constraints=(/33: (/NULL - ]; /39: (/NULL - ])] # Prune inbound foreign key columns when they are not updated. norm expect=PruneMutationInputCols @@ -3765,25 +3778,25 @@ upsert uniq_fk_parent ├── columns: ├── arbiter indexes: primary ├── canary column: uniq_fk_parent.k:9 - ├── fetch columns: uniq_fk_parent.k:9 d:13 + ├── fetch columns: uniq_fk_parent.k:9 uniq_fk_parent.d:13 ├── insert-mapping: │ ├── column1:7 => uniq_fk_parent.k:1 │ ├── column8:8 => uniq_fk_parent.a:2 │ ├── column8:8 => uniq_fk_parent.b:3 │ ├── column8:8 => uniq_fk_parent.c:4 - │ └── column8:8 => d:5 + │ └── column8:8 => uniq_fk_parent.d:5 ├── update-mapping: - │ └── upsert_d:20 => d:5 + │ └── upsert_d:20 => uniq_fk_parent.d:5 ├── input binding: &1 ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: upsert_k:16 upsert_a:17 upsert_b:18 upsert_c:19 upsert_d:20 column1:7!null column8:8 uniq_fk_parent.k:9 d:13 + │ ├── columns: upsert_k:16 upsert_a:17 upsert_b:18 upsert_c:19 upsert_d:20 column1:7!null column8:8 uniq_fk_parent.k:9 uniq_fk_parent.d:13 │ ├── cardinality: [1 - 1] │ ├── key: () │ ├── fd: ()-->(7-9,13,16-20) │ ├── left-join (cross) - │ │ ├── columns: column1:7!null column8:8 uniq_fk_parent.k:9 uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 d:13 + │ │ ├── columns: column1:7!null column8:8 uniq_fk_parent.k:9 uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 uniq_fk_parent.d:13 │ │ ├── cardinality: [1 - 1] │ │ ├── multiplicity: left-rows(exactly-one), right-rows(exactly-one) │ │ ├── key: () @@ -3795,12 +3808,12 @@ upsert uniq_fk_parent │ │ │ ├── fd: ()-->(7,8) │ │ │ └── (1, NULL) │ │ ├── select - │ │ │ ├── columns: uniq_fk_parent.k:9!null uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 d:13 + │ │ │ ├── columns: uniq_fk_parent.k:9!null uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 uniq_fk_parent.d:13 │ │ │ ├── cardinality: [0 - 1] │ │ │ ├── key: () │ │ │ ├── fd: ()-->(9-13) │ │ │ ├── scan uniq_fk_parent - │ │ │ │ ├── columns: uniq_fk_parent.k:9!null uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 d:13 + │ │ │ │ ├── columns: uniq_fk_parent.k:9!null uniq_fk_parent.a:10 uniq_fk_parent.b:11 uniq_fk_parent.c:12 uniq_fk_parent.d:13 │ │ │ │ ├── key: (9) │ │ │ │ └── fd: (9)-->(10-13) │ │ │ └── filters @@ -3815,48 +3828,53 @@ upsert uniq_fk_parent └── unique-checks ├── unique-checks-item: uniq_fk_parent(a) │ └── semi-join (hash) - │ ├── columns: a:21 k:22 + │ ├── columns: k:27 a:28 b:29 c:30 d:31 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(21,22) + │ ├── fd: ()-->(27-31) │ ├── with-scan &1 - │ │ ├── columns: a:21 k:22 + │ │ ├── columns: k:27 a:28 b:29 c:30 d:31 │ │ ├── mapping: - │ │ │ ├── upsert_a:17 => a:21 - │ │ │ └── upsert_k:16 => k:22 + │ │ │ ├── upsert_k:16 => k:27 + │ │ │ ├── upsert_a:17 => a:28 + │ │ │ ├── upsert_b:18 => b:29 + │ │ │ ├── upsert_c:19 => c:30 + │ │ │ └── upsert_d:20 => d:31 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () - │ │ └── fd: ()-->(21,22) + │ │ └── fd: ()-->(27-31) │ ├── scan uniq_fk_parent - │ │ ├── columns: uniq_fk_parent.k:23!null uniq_fk_parent.a:24 - │ │ ├── key: (23) - │ │ └── fd: (23)-->(24) + │ │ ├── columns: uniq_fk_parent.k:21!null uniq_fk_parent.a:22 + │ │ ├── key: (21) + │ │ └── fd: (21)-->(22) │ └── filters - │ ├── a:21 = uniq_fk_parent.a:24 [outer=(21,24), constraints=(/21: (/NULL - ]; /24: (/NULL - ]), fd=(21)==(24), (24)==(21)] - │ └── k:22 != uniq_fk_parent.k:23 [outer=(22,23), constraints=(/22: (/NULL - ]; /23: (/NULL - ])] + │ ├── a:28 = uniq_fk_parent.a:22 [outer=(22,28), constraints=(/22: (/NULL - ]; /28: (/NULL - ]), fd=(22)==(28), (28)==(22)] + │ └── k:27 != uniq_fk_parent.k:21 [outer=(21,27), constraints=(/21: (/NULL - ]; /27: (/NULL - ])] └── unique-checks-item: uniq_fk_parent(b,c) └── semi-join (hash) - ├── columns: b:29 c:30 k:31 + ├── columns: k:38 a:39 b:40 c:41 d:42 ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(29-31) + ├── fd: ()-->(38-42) ├── with-scan &1 - │ ├── columns: b:29 c:30 k:31 + │ ├── columns: k:38 a:39 b:40 c:41 d:42 │ ├── mapping: - │ │ ├── upsert_b:18 => b:29 - │ │ ├── upsert_c:19 => c:30 - │ │ └── upsert_k:16 => k:31 + │ │ ├── upsert_k:16 => k:38 + │ │ ├── upsert_a:17 => a:39 + │ │ ├── upsert_b:18 => b:40 + │ │ ├── upsert_c:19 => c:41 + │ │ └── upsert_d:20 => d:42 │ ├── cardinality: [1 - 1] │ ├── key: () - │ └── fd: ()-->(29-31) + │ └── fd: ()-->(38-42) ├── scan uniq_fk_parent │ ├── columns: uniq_fk_parent.k:32!null uniq_fk_parent.b:34 uniq_fk_parent.c:35 │ ├── key: (32) │ └── fd: (32)-->(34,35) └── filters - ├── b:29 = uniq_fk_parent.b:34 [outer=(29,34), constraints=(/29: (/NULL - ]; /34: (/NULL - ]), fd=(29)==(34), (34)==(29)] - ├── c:30 = uniq_fk_parent.c:35 [outer=(30,35), constraints=(/30: (/NULL - ]; /35: (/NULL - ]), fd=(30)==(35), (35)==(30)] - └── k:31 != uniq_fk_parent.k:32 [outer=(31,32), constraints=(/31: (/NULL - ]; /32: (/NULL - ])] + ├── b:40 = uniq_fk_parent.b:34 [outer=(34,40), constraints=(/34: (/NULL - ]; /40: (/NULL - ]), fd=(34)==(40), (40)==(34)] + ├── c:41 = uniq_fk_parent.c:35 [outer=(35,41), constraints=(/35: (/NULL - ]; /41: (/NULL - ]), fd=(35)==(41), (41)==(35)] + └── k:38 != uniq_fk_parent.k:32 [outer=(32,38), constraints=(/32: (/NULL - ]; /38: (/NULL - ])] # Do not prune columns that are needed for foreign key checks or cascades. norm expect=PruneMutationInputCols diff --git a/pkg/sql/opt/optbuilder/mutation_builder.go b/pkg/sql/opt/optbuilder/mutation_builder.go index ad4c6320ae17..7fbb810b04fd 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder.go +++ b/pkg/sql/opt/optbuilder/mutation_builder.go @@ -159,6 +159,11 @@ type mutationBuilder struct { // reuse. parsedIndexExprs []tree.Expr + // parsedUniqueConstraintExprs is a cached set of parsed partial unique + // constraint predicate expressions from the table schema. These are parsed + // once and cached for reuse. + parsedUniqueConstraintExprs []tree.Expr + // uniqueChecks contains unique check queries; see buildUnique* methods. uniqueChecks memo.UniqueChecksExpr @@ -1193,6 +1198,35 @@ func (mb *mutationBuilder) parsePartialIndexPredicateExpr(idx cat.IndexOrdinal) return expr } +// parseUniqueConstraintPredicateExpr parses the predicate of the given partial +// unique constraint and caches it for reuse. This function panics if the unique +// constraint at the given ordinal is not partial. +func (mb *mutationBuilder) parseUniqueConstraintPredicateExpr(idx cat.UniqueOrdinal) tree.Expr { + uniqueConstraint := mb.tab.Unique(idx) + + predStr, isPartial := uniqueConstraint.Predicate() + if !isPartial { + panic(errors.AssertionFailedf("unique constraint at ordinal %d is not a partial unique constraint", idx)) + } + + if mb.parsedUniqueConstraintExprs == nil { + mb.parsedUniqueConstraintExprs = make([]tree.Expr, mb.tab.UniqueCount()) + } + + // Return expression from the cache, if it was already parsed previously. + if mb.parsedUniqueConstraintExprs[idx] != nil { + return mb.parsedUniqueConstraintExprs[idx] + } + + expr, err := parser.ParseExpr(predStr) + if err != nil { + panic(err) + } + + mb.parsedUniqueConstraintExprs[idx] = expr + return expr +} + // getIndexLaxKeyOrdinals returns the ordinals of all lax key columns in the // given index. A column's ordinal is the ordered position of that column in the // owning table. @@ -1314,7 +1348,10 @@ func (mb *mutationBuilder) buildCheckInputScan( } // Synthesize a new output column for the input column, using the name - // of the column in the underlying table. + // of the column in the underlying table. The table's column names are + // used because partial unique constraint checks must filter the + // WithScan rows with a predicate expression that references the table's + // columns. tableCol := mb.b.factory.Metadata().Table(mb.tabID).Column(tabOrd) outCol := mb.md.AddColumn(string(tableCol.ColName()), tableCol.DatumType()) withScanScope.cols[i] = scopeColumn{ diff --git a/pkg/sql/opt/optbuilder/mutation_builder_unique.go b/pkg/sql/opt/optbuilder/mutation_builder_unique.go index cc30ee2bdc42..8d38b126152c 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder_unique.go +++ b/pkg/sql/opt/optbuilder/mutation_builder_unique.go @@ -17,6 +17,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" + "github.com/cockroachdb/cockroach/pkg/sql/types" "github.com/cockroachdb/cockroach/pkg/util" ) @@ -129,12 +130,11 @@ type uniqueCheckHelper struct { // uniqueOrdinals are the table ordinals of the unique columns in the table // that is being mutated. They correspond 1-to-1 to the columns in the // UniqueConstraint. - uniqueOrdinals []int + uniqueOrdinals util.FastIntSet - // uniqueAndPrimaryKeyOrdinals includes all the ordinals from uniqueOrdinals, - // plus the ordinals from any primary key columns that are not already - // included in uniqueOrdinals. - uniqueAndPrimaryKeyOrdinals []int + // primaryKeyOrdinals includes the ordinals from any primary key columns + // that are not included in uniqueOrdinals. + primaryKeyOrdinals util.FastIntSet } // init initializes the helper with a unique constraint. @@ -150,15 +150,18 @@ func (h *uniqueCheckHelper) init(mb *mutationBuilder, uniqueOrdinal int) bool { uniqueOrdinal: uniqueOrdinal, } - uniqueCount := h.unique.ColumnCount() - var uniqueOrds util.FastIntSet - for i := 0; i < uniqueCount; i++ { + for i, n := 0, h.unique.ColumnCount(); i < n; i++ { uniqueOrds.Add(h.unique.ColumnOrdinal(mb.tab, i)) } // Find the primary key columns that are not part of the unique constraint. // If there aren't any, we don't need a check. + // TODO(mgartner): We also don't need a check if there exists a unique index + // with columns that are a subset of the unique constraint columns. + // Similarly, we don't need a check for a partial unique constraint if there + // exists a non-partial unique constraint with columns that are a subset of + // the partial unique constrain columns. primaryOrds := getIndexLaxKeyOrdinals(mb.tab.Index(cat.PrimaryIndex)) primaryOrds.DifferenceWith(uniqueOrds) if primaryOrds.Empty() { @@ -167,13 +170,13 @@ func (h *uniqueCheckHelper) init(mb *mutationBuilder, uniqueOrdinal int) bool { return false } - h.uniqueAndPrimaryKeyOrdinals = append(uniqueOrds.Ordered(), primaryOrds.Ordered()...) - h.uniqueOrdinals = h.uniqueAndPrimaryKeyOrdinals[:uniqueCount] + h.uniqueOrdinals = uniqueOrds + h.primaryKeyOrdinals = primaryOrds // Check if we are setting NULL values for the unique columns, like when this // mutation is the result of a SET NULL cascade action. numNullCols := 0 - for _, tabOrd := range h.uniqueOrdinals { + for tabOrd, ok := h.uniqueOrdinals.Next(0); ok; tabOrd, ok = h.uniqueOrdinals.Next(tabOrd + 1) { colID := mb.mapToReturnColID(tabOrd) if memo.OutputColumnIsAlwaysNull(mb.outScope.expr, colID) { numNullCols++ @@ -189,26 +192,31 @@ func (h *uniqueCheckHelper) init(mb *mutationBuilder, uniqueOrdinal int) bool { // table. The input to the insertion check will be produced from the input to // the mutation operator. func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { - withScanScope, _ := h.mb.buildCheckInputScan( - checkInputScanNewVals, h.uniqueAndPrimaryKeyOrdinals, - ) - - numCols := len(withScanScope.cols) f := h.mb.b.factory // Build a self semi-join, with the new values on the left and the // existing values on the right. + scanScope, ordinals := h.buildTableScan() - scanScope, _ := h.buildTableScan() + withScanScope, _ := h.mb.buildCheckInputScan( + checkInputScanNewVals, ordinals, + ) // Build the join filters: // (new_a = existing_a) AND (new_b = existing_b) AND ... // - // Set the capacity to len(h.uniqueOrdinals)+1 since we'll have an equality + // Set the capacity to h.uniqueOrdinals.Len()+1 since we'll have an equality // condition for each column in the unique constraint, plus one additional - // condition to prevent rows from matching themselves (see below). - semiJoinFilters := make(memo.FiltersExpr, 0, len(h.uniqueOrdinals)+1) - for i := 0; i < len(h.uniqueOrdinals); i++ { + // condition to prevent rows from matching themselves (see below). If the + // constraint is partial, add 2 to account for filtering both the WithScan + // and the Scan by the partial unique constraint predicate. + numFilters := h.uniqueOrdinals.Len() + 1 + _, isPartial := h.unique.Predicate() + if isPartial { + numFilters += 2 + } + semiJoinFilters := make(memo.FiltersExpr, 0, numFilters) + for i, ok := h.uniqueOrdinals.Next(0); ok; i, ok = h.uniqueOrdinals.Next(i + 1) { semiJoinFilters = append(semiJoinFilters, f.ConstructFiltersItem( f.ConstructEq( f.ConstructVariable(withScanScope.cols[i].id), @@ -217,12 +225,29 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { )) } + // If the unique constraint is partial, we need to filter out inserted rows + // that don't satisfy the predicate. We also need to make sure that rows do + // not match existing rows in the the table that do not satisfy the + // predicate. So we add the predicate as a filter on both the WithScan + // columns and the Scan columns. + if isPartial { + pred := h.mb.parseUniqueConstraintPredicateExpr(h.uniqueOrdinal) + + typedPred := withScanScope.resolveAndRequireType(pred, types.Bool) + withScanPred := h.mb.b.buildScalar(typedPred, withScanScope, nil, nil, nil) + semiJoinFilters = append(semiJoinFilters, f.ConstructFiltersItem(withScanPred)) + + typedPred = scanScope.resolveAndRequireType(pred, types.Bool) + scanPred := h.mb.b.buildScalar(typedPred, scanScope, nil, nil, nil) + semiJoinFilters = append(semiJoinFilters, f.ConstructFiltersItem(scanPred)) + } + // We need to prevent rows from matching themselves in the semi join. We can // do this by adding another filter that uses the primary keys to check if // two rows are identical: // (new_pk1 != existing_pk1) OR (new_pk2 != existing_pk2) OR ... var pkFilter opt.ScalarExpr - for i := len(h.uniqueOrdinals); i < numCols; i++ { + for i, ok := h.primaryKeyOrdinals.Next(0); ok; i, ok = h.primaryKeyOrdinals.Next(i + 1) { pkFilterLocal := f.ConstructNe( f.ConstructVariable(withScanScope.cols[i].id), f.ConstructVariable(scanScope.cols[i].id), @@ -237,26 +262,36 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { semiJoin := f.ConstructSemiJoin(withScanScope.expr, scanScope.expr, semiJoinFilters, memo.EmptyJoinPrivate) + // Collect the key columns that will be shown in the error message if there + // is a duplicate key violation resulting from this uniqueness check. + keyCols := make(opt.ColList, 0, h.uniqueOrdinals.Len()) + for i, ok := h.uniqueOrdinals.Next(0); ok; i, ok = h.uniqueOrdinals.Next(i + 1) { + keyCols = append(keyCols, withScanScope.cols[i].id) + } + return f.ConstructUniqueChecksItem(semiJoin, &memo.UniqueChecksItemPrivate{ Table: h.mb.tabID, CheckOrdinal: h.uniqueOrdinal, - // uniqueOrdinals is always a prefix of uniqueAndPrimaryKeyOrdinals, - // which maps 1-to-1 to the columns in withScanScope.cols. The remaining - // columns are primary key columns and should not be included in the - // KeyCols. - KeyCols: withScanScope.colList()[:len(h.uniqueOrdinals)], - OpName: h.mb.opName, + KeyCols: keyCols, + OpName: h.mb.opName, }) } -// buildTableScan builds a Scan of the table. -func (h *uniqueCheckHelper) buildTableScan() (outScope *scope, tabMeta *opt.TableMeta) { - tabMeta = h.mb.b.addTable(h.mb.tab, tree.NewUnqualifiedTableName(h.mb.tab.Name())) +// buildTableScan builds a Scan of the table. The ordinals of the columns +// scanned are also returned. +func (h *uniqueCheckHelper) buildTableScan() (outScope *scope, ordinals []int) { + tabMeta := h.mb.b.addTable(h.mb.tab, tree.NewUnqualifiedTableName(h.mb.tab.Name())) + ordinals = tableOrdinals(tabMeta.Table, columnKinds{ + includeMutations: false, + includeSystem: false, + includeVirtualInverted: false, + includeVirtualComputed: true, + }) return h.mb.b.buildScan( tabMeta, - h.uniqueAndPrimaryKeyOrdinals, + ordinals, nil, /* indexFlags */ noRowLocking, h.mb.b.allocScope(), - ), tabMeta + ), ordinals } diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-insert b/pkg/sql/opt/optbuilder/testdata/unique-checks-insert index 0c2f6c71f29b..55dce437f057 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-insert +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-insert @@ -17,7 +17,7 @@ insert uniq ├── columns: ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 @@ -29,32 +29,37 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:12!null k:13!null + │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22!null │ ├── with-scan &1 - │ │ ├── columns: w:12!null k:13!null + │ │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22!null │ │ └── mapping: - │ │ ├── column3:9 => w:12 - │ │ └── column1:7 => k:13 + │ │ ├── column1:7 => k:18 + │ │ ├── column2:8 => v:19 + │ │ ├── column3:9 => w:20 + │ │ ├── column4:10 => x:21 + │ │ └── column5:11 => y:22 │ ├── scan uniq - │ │ └── columns: uniq.k:14!null uniq.w:16 + │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 │ └── filters - │ ├── w:12 = uniq.w:16 - │ └── k:13 != uniq.k:14 + │ ├── w:20 = uniq.w:14 + │ └── k:18 != uniq.k:12 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:20!null y:21!null k:22!null + ├── columns: k:29!null v:30!null w:31!null x:32!null y:33!null ├── with-scan &1 - │ ├── columns: x:20!null y:21!null k:22!null + │ ├── columns: k:29!null v:30!null w:31!null x:32!null y:33!null │ └── mapping: - │ ├── column4:10 => x:20 - │ ├── column5:11 => y:21 - │ └── column1:7 => k:22 + │ ├── column1:7 => k:29 + │ ├── column2:8 => v:30 + │ ├── column3:9 => w:31 + │ ├── column4:10 => x:32 + │ └── column5:11 => y:33 ├── scan uniq - │ └── columns: uniq.k:23!null uniq.x:26 uniq.y:27 + │ └── columns: uniq.k:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 └── filters - ├── x:20 = uniq.x:26 - ├── y:21 = uniq.y:27 - └── k:22 != uniq.k:23 + ├── x:32 = uniq.x:26 + ├── y:33 = uniq.y:27 + └── k:29 != uniq.k:23 # Some of the inserted values have nulls. build @@ -64,7 +69,7 @@ insert uniq ├── columns: ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 @@ -77,34 +82,39 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:12 k:13!null + │ ├── columns: k:18!null v:19 w:20 x:21 y:22!null │ ├── with-scan &1 - │ │ ├── columns: w:12 k:13!null + │ │ ├── columns: k:18!null v:19 w:20 x:21 y:22!null │ │ └── mapping: - │ │ ├── column3:9 => w:12 - │ │ └── column1:7 => k:13 + │ │ ├── column1:7 => k:18 + │ │ ├── column2:8 => v:19 + │ │ ├── column3:9 => w:20 + │ │ ├── column4:10 => x:21 + │ │ └── column5:11 => y:22 │ ├── scan uniq - │ │ └── columns: uniq.k:14!null uniq.w:16 + │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 │ └── filters - │ ├── w:12 = uniq.w:16 - │ └── k:13 != uniq.k:14 + │ ├── w:20 = uniq.w:14 + │ └── k:18 != uniq.k:12 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:20 y:21!null k:22!null + ├── columns: k:29!null v:30 w:31 x:32 y:33!null ├── with-scan &1 - │ ├── columns: x:20 y:21!null k:22!null + │ ├── columns: k:29!null v:30 w:31 x:32 y:33!null │ └── mapping: - │ ├── column4:10 => x:20 - │ ├── column5:11 => y:21 - │ └── column1:7 => k:22 + │ ├── column1:7 => k:29 + │ ├── column2:8 => v:30 + │ ├── column3:9 => w:31 + │ ├── column4:10 => x:32 + │ └── column5:11 => y:33 ├── scan uniq - │ └── columns: uniq.k:23!null uniq.x:26 uniq.y:27 + │ └── columns: uniq.k:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 └── filters - ├── x:20 = uniq.x:26 - ├── y:21 = uniq.y:27 - └── k:22 != uniq.k:23 + ├── x:32 = uniq.x:26 + ├── y:33 = uniq.y:27 + └── k:29 != uniq.k:23 -# No need to plan checks for w since it's aways null. +# No need to plan checks for w since it's always null. build INSERT INTO uniq VALUES (1, 1, NULL, 1, 1), (2, 2, NULL, 2, 2) ---- @@ -112,8 +122,8 @@ insert uniq ├── columns: ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 - │ ├── column3:9 => w:3 + │ ├── column2:8 => uniq.v:2 + │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 ├── input binding: &1 @@ -124,21 +134,23 @@ insert uniq └── unique-checks └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:12!null y:13!null k:14!null + ├── columns: k:18!null v:19!null w:20 x:21!null y:22!null ├── with-scan &1 - │ ├── columns: x:12!null y:13!null k:14!null + │ ├── columns: k:18!null v:19!null w:20 x:21!null y:22!null │ └── mapping: - │ ├── column4:10 => x:12 - │ ├── column5:11 => y:13 - │ └── column1:7 => k:14 + │ ├── column1:7 => k:18 + │ ├── column2:8 => v:19 + │ ├── column3:9 => w:20 + │ ├── column4:10 => x:21 + │ └── column5:11 => y:22 ├── scan uniq - │ └── columns: uniq.k:15!null uniq.x:18 uniq.y:19 + │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 └── filters - ├── x:12 = uniq.x:18 - ├── y:13 = uniq.y:19 - └── k:14 != uniq.k:15 + ├── x:21 = uniq.x:15 + ├── y:22 = uniq.y:16 + └── k:18 != uniq.k:12 -# No need to plan checks for x,y since x is aways null. +# No need to plan checks for x,y since x is always null. build INSERT INTO uniq VALUES (1, 1, 1, NULL, 1), (2, 2, NULL, NULL, 2) ---- @@ -146,10 +158,10 @@ insert uniq ├── columns: ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── values │ ├── columns: column1:7!null column2:8!null column3:9 column4:10 column5:11!null @@ -158,19 +170,22 @@ insert uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: w:12 k:13!null + ├── columns: k:18!null v:19!null w:20 x:21 y:22!null ├── with-scan &1 - │ ├── columns: w:12 k:13!null + │ ├── columns: k:18!null v:19!null w:20 x:21 y:22!null │ └── mapping: - │ ├── column3:9 => w:12 - │ └── column1:7 => k:13 + │ ├── column1:7 => k:18 + │ ├── column2:8 => v:19 + │ ├── column3:9 => w:20 + │ ├── column4:10 => x:21 + │ └── column5:11 => y:22 ├── scan uniq - │ └── columns: uniq.k:14!null uniq.w:16 + │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 └── filters - ├── w:12 = uniq.w:16 - └── k:13 != uniq.k:14 + ├── w:20 = uniq.w:14 + └── k:18 != uniq.k:12 -# No need to plan checks for x,y since y is aways null. +# No need to plan checks for x,y since y is always null. build INSERT INTO uniq VALUES (1, 1, 1, 1, NULL), (2, 2, 2, 2, NULL) ---- @@ -178,10 +193,10 @@ insert uniq ├── columns: ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 - │ ├── column4:10 => x:4 - │ └── column5:11 => y:5 + │ ├── column4:10 => uniq.x:4 + │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── values │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11 @@ -190,19 +205,22 @@ insert uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: w:12!null k:13!null + ├── columns: k:18!null v:19!null w:20!null x:21!null y:22 ├── with-scan &1 - │ ├── columns: w:12!null k:13!null + │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22 │ └── mapping: - │ ├── column3:9 => w:12 - │ └── column1:7 => k:13 + │ ├── column1:7 => k:18 + │ ├── column2:8 => v:19 + │ ├── column3:9 => w:20 + │ ├── column4:10 => x:21 + │ └── column5:11 => y:22 ├── scan uniq - │ └── columns: uniq.k:14!null uniq.w:16 + │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 └── filters - ├── w:12 = uniq.w:16 - └── k:13 != uniq.k:14 + ├── w:20 = uniq.w:14 + └── k:18 != uniq.k:12 -# No need to plan any checks, since w, x and y are aways null. +# No need to plan any checks, since w, x and y are always null. build INSERT INTO uniq VALUES (1, 1, NULL, NULL, NULL), (2, 2, NULL, NULL, NULL) ---- @@ -232,7 +250,7 @@ insert uniq ├── arbiter constraints: unique_w unique_x_y ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 @@ -261,19 +279,19 @@ insert uniq │ │ │ │ │ │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ │ │ │ │ │ │ └── (1, 2, 3, 4, 5) │ │ │ │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 + │ │ │ │ │ │ │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 │ │ │ │ │ │ │ │ └── filters │ │ │ │ │ │ │ │ └── column1:7 = uniq.k:12 │ │ │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ │ │ └── columns: uniq.k:18!null v:19 uniq.w:20 uniq.x:21 uniq.y:22 + │ │ │ │ │ │ │ │ └── columns: uniq.k:18!null uniq.v:19 uniq.w:20 uniq.x:21 uniq.y:22 │ │ │ │ │ │ │ └── filters - │ │ │ │ │ │ │ └── column2:8 = v:19 + │ │ │ │ │ │ │ └── column2:8 = uniq.v:19 │ │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ │ └── columns: uniq.k:24!null v:25 uniq.w:26 uniq.x:27 uniq.y:28 + │ │ │ │ │ │ │ └── columns: uniq.k:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 │ │ │ │ │ │ └── filters │ │ │ │ │ │ └── column3:9 = uniq.w:26 │ │ │ │ │ ├── scan uniq - │ │ │ │ │ │ └── columns: uniq.k:30!null v:31 uniq.w:32 uniq.x:33 uniq.y:34 + │ │ │ │ │ │ └── columns: uniq.k:30!null uniq.v:31 uniq.w:32 uniq.x:33 uniq.y:34 │ │ │ │ │ └── filters │ │ │ │ │ ├── column4:10 = uniq.x:33 │ │ │ │ │ └── column5:11 = uniq.y:34 @@ -314,45 +332,50 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:36!null k:37!null + │ ├── columns: k:42!null v:43!null w:44!null x:45!null y:46!null │ ├── with-scan &1 - │ │ ├── columns: w:36!null k:37!null + │ │ ├── columns: k:42!null v:43!null w:44!null x:45!null y:46!null │ │ └── mapping: - │ │ ├── column3:9 => w:36 - │ │ └── column1:7 => k:37 + │ │ ├── column1:7 => k:42 + │ │ ├── column2:8 => v:43 + │ │ ├── column3:9 => w:44 + │ │ ├── column4:10 => x:45 + │ │ └── column5:11 => y:46 │ ├── scan uniq - │ │ └── columns: uniq.k:38!null uniq.w:40 + │ │ └── columns: uniq.k:36!null uniq.v:37 uniq.w:38 uniq.x:39 uniq.y:40 │ └── filters - │ ├── w:36 = uniq.w:40 - │ └── k:37 != uniq.k:38 + │ ├── w:44 = uniq.w:38 + │ └── k:42 != uniq.k:36 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:44!null y:45!null k:46!null + ├── columns: k:53!null v:54!null w:55!null x:56!null y:57!null ├── with-scan &1 - │ ├── columns: x:44!null y:45!null k:46!null + │ ├── columns: k:53!null v:54!null w:55!null x:56!null y:57!null │ └── mapping: - │ ├── column4:10 => x:44 - │ ├── column5:11 => y:45 - │ └── column1:7 => k:46 + │ ├── column1:7 => k:53 + │ ├── column2:8 => v:54 + │ ├── column3:9 => w:55 + │ ├── column4:10 => x:56 + │ └── column5:11 => y:57 ├── scan uniq - │ └── columns: uniq.k:47!null uniq.x:50 uniq.y:51 + │ └── columns: uniq.k:47!null uniq.v:48 uniq.w:49 uniq.x:50 uniq.y:51 └── filters - ├── x:44 = uniq.x:50 - ├── y:45 = uniq.y:51 - └── k:46 != uniq.k:47 + ├── x:56 = uniq.x:50 + ├── y:57 = uniq.y:51 + └── k:53 != uniq.k:47 # On conflict clause references unique without index constraint. # TODO(rytaft): we should be able to remove the unique check for w in this case # (see #59119). build -INSERT INTO uniq VALUES (1, 2, 3, 4, 5) ON CONFLICT (w) DO NOTHING +INSERT INTO UNIQ VALUES (1, 2, 3, 4, 5) ON CONFLICT (W) DO NOTHING ---- insert uniq ├── columns: ├── arbiter constraints: unique_w ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 @@ -366,7 +389,7 @@ insert uniq │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ └── (1, 2, 3, 4, 5) │ │ ├── scan uniq - │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 + │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 │ │ └── filters │ │ └── column3:9 = uniq.w:14 │ └── aggregations @@ -381,32 +404,37 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:18!null k:19!null + │ ├── columns: k:24!null v:25!null w:26!null x:27!null y:28!null │ ├── with-scan &1 - │ │ ├── columns: w:18!null k:19!null + │ │ ├── columns: k:24!null v:25!null w:26!null x:27!null y:28!null │ │ └── mapping: - │ │ ├── column3:9 => w:18 - │ │ └── column1:7 => k:19 + │ │ ├── column1:7 => k:24 + │ │ ├── column2:8 => v:25 + │ │ ├── column3:9 => w:26 + │ │ ├── column4:10 => x:27 + │ │ └── column5:11 => y:28 │ ├── scan uniq - │ │ └── columns: uniq.k:20!null uniq.w:22 + │ │ └── columns: uniq.k:18!null uniq.v:19 uniq.w:20 uniq.x:21 uniq.y:22 │ └── filters - │ ├── w:18 = uniq.w:22 - │ └── k:19 != uniq.k:20 + │ ├── w:26 = uniq.w:20 + │ └── k:24 != uniq.k:18 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:26!null y:27!null k:28!null + ├── columns: k:35!null v:36!null w:37!null x:38!null y:39!null ├── with-scan &1 - │ ├── columns: x:26!null y:27!null k:28!null + │ ├── columns: k:35!null v:36!null w:37!null x:38!null y:39!null │ └── mapping: - │ ├── column4:10 => x:26 - │ ├── column5:11 => y:27 - │ └── column1:7 => k:28 + │ ├── column1:7 => k:35 + │ ├── column2:8 => v:36 + │ ├── column3:9 => w:37 + │ ├── column4:10 => x:38 + │ └── column5:11 => y:39 ├── scan uniq - │ └── columns: uniq.k:29!null uniq.x:32 uniq.y:33 + │ └── columns: uniq.k:29!null uniq.v:30 uniq.w:31 uniq.x:32 uniq.y:33 └── filters - ├── x:26 = uniq.x:32 - ├── y:27 = uniq.y:33 - └── k:28 != uniq.k:29 + ├── x:38 = uniq.x:32 + ├── y:39 = uniq.y:33 + └── k:35 != uniq.k:29 exec-ddl CREATE TABLE other (k INT, v INT, w INT NOT NULL, x INT, y INT) @@ -432,32 +460,37 @@ insert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:14!null k:15 + │ ├── columns: k:20 v:21 w:22!null x:23 y:24 │ ├── with-scan &1 - │ │ ├── columns: w:14!null k:15 + │ │ ├── columns: k:20 v:21 w:22!null x:23 y:24 │ │ └── mapping: - │ │ ├── other.w:9 => w:14 - │ │ └── other.k:7 => k:15 + │ │ ├── other.k:7 => k:20 + │ │ ├── other.v:8 => v:21 + │ │ ├── other.w:9 => w:22 + │ │ ├── other.x:10 => x:23 + │ │ └── other.y:11 => y:24 │ ├── scan uniq - │ │ └── columns: uniq.k:16!null uniq.w:18 + │ │ └── columns: uniq.k:14!null uniq.v:15 uniq.w:16 uniq.x:17 uniq.y:18 │ └── filters - │ ├── w:14 = uniq.w:18 - │ └── k:15 != uniq.k:16 + │ ├── w:22 = uniq.w:16 + │ └── k:20 != uniq.k:14 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:22 y:23 k:24 + ├── columns: k:31 v:32 w:33!null x:34 y:35 ├── with-scan &1 - │ ├── columns: x:22 y:23 k:24 + │ ├── columns: k:31 v:32 w:33!null x:34 y:35 │ └── mapping: - │ ├── other.x:10 => x:22 - │ ├── other.y:11 => y:23 - │ └── other.k:7 => k:24 + │ ├── other.k:7 => k:31 + │ ├── other.v:8 => v:32 + │ ├── other.w:9 => w:33 + │ ├── other.x:10 => x:34 + │ └── other.y:11 => y:35 ├── scan uniq - │ └── columns: uniq.k:25!null uniq.x:28 uniq.y:29 + │ └── columns: uniq.k:25!null uniq.v:26 uniq.w:27 uniq.x:28 uniq.y:29 └── filters - ├── x:22 = uniq.x:28 - ├── y:23 = uniq.y:29 - └── k:24 != uniq.k:25 + ├── x:34 = uniq.x:28 + ├── y:35 = uniq.y:29 + └── k:31 != uniq.k:25 exec-ddl CREATE TABLE uniq_overlaps_pk ( @@ -494,48 +527,51 @@ insert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:10!null c:11!null a:12!null + │ ├── columns: a:15!null b:16!null c:17!null d:18!null │ ├── with-scan &1 - │ │ ├── columns: b:10!null c:11!null a:12!null + │ │ ├── columns: a:15!null b:16!null c:17!null d:18!null │ │ └── mapping: - │ │ ├── column2:7 => b:10 - │ │ ├── column3:8 => c:11 - │ │ └── column1:6 => a:12 + │ │ ├── column1:6 => a:15 + │ │ ├── column2:7 => b:16 + │ │ ├── column3:8 => c:17 + │ │ └── column4:9 => d:18 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:13!null uniq_overlaps_pk.b:14!null uniq_overlaps_pk.c:15 + │ │ └── columns: uniq_overlaps_pk.a:10!null uniq_overlaps_pk.b:11!null uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 │ └── filters - │ ├── b:10 = uniq_overlaps_pk.b:14 - │ ├── c:11 = uniq_overlaps_pk.c:15 - │ └── a:12 != uniq_overlaps_pk.a:13 + │ ├── b:16 = uniq_overlaps_pk.b:11 + │ ├── c:17 = uniq_overlaps_pk.c:12 + │ └── a:15 != uniq_overlaps_pk.a:10 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:18!null b:19!null + │ ├── columns: a:24!null b:25!null c:26!null d:27!null │ ├── with-scan &1 - │ │ ├── columns: a:18!null b:19!null + │ │ ├── columns: a:24!null b:25!null c:26!null d:27!null │ │ └── mapping: - │ │ ├── column1:6 => a:18 - │ │ └── column2:7 => b:19 + │ │ ├── column1:6 => a:24 + │ │ ├── column2:7 => b:25 + │ │ ├── column3:8 => c:26 + │ │ └── column4:9 => d:27 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null + │ │ └── columns: uniq_overlaps_pk.a:19!null uniq_overlaps_pk.b:20!null uniq_overlaps_pk.c:21 uniq_overlaps_pk.d:22 │ └── filters - │ ├── a:18 = uniq_overlaps_pk.a:20 - │ └── b:19 != uniq_overlaps_pk.b:21 + │ ├── a:24 = uniq_overlaps_pk.a:19 + │ └── b:25 != uniq_overlaps_pk.b:20 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:25!null d:26!null a:27!null b:28!null + ├── columns: a:33!null b:34!null c:35!null d:36!null ├── with-scan &1 - │ ├── columns: c:25!null d:26!null a:27!null b:28!null + │ ├── columns: a:33!null b:34!null c:35!null d:36!null │ └── mapping: - │ ├── column3:8 => c:25 - │ ├── column4:9 => d:26 - │ ├── column1:6 => a:27 - │ └── column2:7 => b:28 + │ ├── column1:6 => a:33 + │ ├── column2:7 => b:34 + │ ├── column3:8 => c:35 + │ └── column4:9 => d:36 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 + │ └── columns: uniq_overlaps_pk.a:28!null uniq_overlaps_pk.b:29!null uniq_overlaps_pk.c:30 uniq_overlaps_pk.d:31 └── filters - ├── c:25 = uniq_overlaps_pk.c:31 - ├── d:26 = uniq_overlaps_pk.d:32 - └── (a:27 != uniq_overlaps_pk.a:29) OR (b:28 != uniq_overlaps_pk.b:30) + ├── c:35 = uniq_overlaps_pk.c:30 + ├── d:36 = uniq_overlaps_pk.d:31 + └── (a:33 != uniq_overlaps_pk.a:28) OR (b:34 != uniq_overlaps_pk.b:29) # Insert with non-constant input. # Add inequality filters for the primary key columns that are not part of each @@ -558,48 +594,51 @@ insert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:13 c:14 a:15 + │ ├── columns: a:18 b:19 c:20 d:21 │ ├── with-scan &1 - │ │ ├── columns: b:13 c:14 a:15 + │ │ ├── columns: a:18 b:19 c:20 d:21 │ │ └── mapping: - │ │ ├── v:7 => b:13 - │ │ ├── x:9 => c:14 - │ │ └── k:6 => a:15 + │ │ ├── k:6 => a:18 + │ │ ├── v:7 => b:19 + │ │ ├── x:9 => c:20 + │ │ └── y:10 => d:21 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:16!null uniq_overlaps_pk.b:17!null uniq_overlaps_pk.c:18 + │ │ └── columns: uniq_overlaps_pk.a:13!null uniq_overlaps_pk.b:14!null uniq_overlaps_pk.c:15 uniq_overlaps_pk.d:16 │ └── filters - │ ├── b:13 = uniq_overlaps_pk.b:17 - │ ├── c:14 = uniq_overlaps_pk.c:18 - │ └── a:15 != uniq_overlaps_pk.a:16 + │ ├── b:19 = uniq_overlaps_pk.b:14 + │ ├── c:20 = uniq_overlaps_pk.c:15 + │ └── a:18 != uniq_overlaps_pk.a:13 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:21 b:22 + │ ├── columns: a:27 b:28 c:29 d:30 │ ├── with-scan &1 - │ │ ├── columns: a:21 b:22 + │ │ ├── columns: a:27 b:28 c:29 d:30 │ │ └── mapping: - │ │ ├── k:6 => a:21 - │ │ └── v:7 => b:22 + │ │ ├── k:6 => a:27 + │ │ ├── v:7 => b:28 + │ │ ├── x:9 => c:29 + │ │ └── y:10 => d:30 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null + │ │ └── columns: uniq_overlaps_pk.a:22!null uniq_overlaps_pk.b:23!null uniq_overlaps_pk.c:24 uniq_overlaps_pk.d:25 │ └── filters - │ ├── a:21 = uniq_overlaps_pk.a:23 - │ └── b:22 != uniq_overlaps_pk.b:24 + │ ├── a:27 = uniq_overlaps_pk.a:22 + │ └── b:28 != uniq_overlaps_pk.b:23 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:28 d:29 a:30 b:31 + ├── columns: a:36 b:37 c:38 d:39 ├── with-scan &1 - │ ├── columns: c:28 d:29 a:30 b:31 + │ ├── columns: a:36 b:37 c:38 d:39 │ └── mapping: - │ ├── x:9 => c:28 - │ ├── y:10 => d:29 - │ ├── k:6 => a:30 - │ └── v:7 => b:31 + │ ├── k:6 => a:36 + │ ├── v:7 => b:37 + │ ├── x:9 => c:38 + │ └── y:10 => d:39 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:32!null uniq_overlaps_pk.b:33!null uniq_overlaps_pk.c:34 uniq_overlaps_pk.d:35 + │ └── columns: uniq_overlaps_pk.a:31!null uniq_overlaps_pk.b:32!null uniq_overlaps_pk.c:33 uniq_overlaps_pk.d:34 └── filters - ├── c:28 = uniq_overlaps_pk.c:34 - ├── d:29 = uniq_overlaps_pk.d:35 - └── (a:30 != uniq_overlaps_pk.a:32) OR (b:31 != uniq_overlaps_pk.b:33) + ├── c:38 = uniq_overlaps_pk.c:33 + ├── d:39 = uniq_overlaps_pk.d:34 + └── (a:36 != uniq_overlaps_pk.a:31) OR (b:37 != uniq_overlaps_pk.b:32) exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -638,49 +677,55 @@ insert uniq_hidden_pk └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:12!null c:13!null rowid:14 + │ ├── columns: a:18!null b:19!null c:20!null d:21!null rowid:22 │ ├── with-scan &1 - │ │ ├── columns: b:12!null c:13!null rowid:14 + │ │ ├── columns: a:18!null b:19!null c:20!null d:21!null rowid:22 │ │ └── mapping: - │ │ ├── column2:8 => b:12 - │ │ ├── column3:9 => c:13 - │ │ └── column11:11 => rowid:14 + │ │ ├── column1:7 => a:18 + │ │ ├── column2:8 => b:19 + │ │ ├── column3:9 => c:20 + │ │ ├── column4:10 => d:21 + │ │ └── column11:11 => rowid:22 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.b:16 uniq_hidden_pk.c:17 uniq_hidden_pk.rowid:19!null + │ │ └── columns: uniq_hidden_pk.a:12 uniq_hidden_pk.b:13 uniq_hidden_pk.c:14 uniq_hidden_pk.d:15 uniq_hidden_pk.rowid:16!null │ └── filters - │ ├── b:12 = uniq_hidden_pk.b:16 - │ ├── c:13 = uniq_hidden_pk.c:17 - │ └── rowid:14 != uniq_hidden_pk.rowid:19 + │ ├── b:19 = uniq_hidden_pk.b:13 + │ ├── c:20 = uniq_hidden_pk.c:14 + │ └── rowid:22 != uniq_hidden_pk.rowid:16 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:21!null b:22!null d:23!null rowid:24 + │ ├── columns: a:29!null b:30!null c:31!null d:32!null rowid:33 │ ├── with-scan &1 - │ │ ├── columns: a:21!null b:22!null d:23!null rowid:24 + │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null rowid:33 │ │ └── mapping: - │ │ ├── column1:7 => a:21 - │ │ ├── column2:8 => b:22 - │ │ ├── column4:10 => d:23 - │ │ └── column11:11 => rowid:24 + │ │ ├── column1:7 => a:29 + │ │ ├── column2:8 => b:30 + │ │ ├── column3:9 => c:31 + │ │ ├── column4:10 => d:32 + │ │ └── column11:11 => rowid:33 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:25 uniq_hidden_pk.b:26 uniq_hidden_pk.d:28 uniq_hidden_pk.rowid:29!null + │ │ └── columns: uniq_hidden_pk.a:23 uniq_hidden_pk.b:24 uniq_hidden_pk.c:25 uniq_hidden_pk.d:26 uniq_hidden_pk.rowid:27!null │ └── filters - │ ├── a:21 = uniq_hidden_pk.a:25 - │ ├── b:22 = uniq_hidden_pk.b:26 - │ ├── d:23 = uniq_hidden_pk.d:28 - │ └── rowid:24 != uniq_hidden_pk.rowid:29 + │ ├── a:29 = uniq_hidden_pk.a:23 + │ ├── b:30 = uniq_hidden_pk.b:24 + │ ├── d:32 = uniq_hidden_pk.d:26 + │ └── rowid:33 != uniq_hidden_pk.rowid:27 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:31!null rowid:32 + ├── columns: a:40!null b:41!null c:42!null d:43!null rowid:44 ├── with-scan &1 - │ ├── columns: a:31!null rowid:32 + │ ├── columns: a:40!null b:41!null c:42!null d:43!null rowid:44 │ └── mapping: - │ ├── column1:7 => a:31 - │ └── column11:11 => rowid:32 + │ ├── column1:7 => a:40 + │ ├── column2:8 => b:41 + │ ├── column3:9 => c:42 + │ ├── column4:10 => d:43 + │ └── column11:11 => rowid:44 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:33 uniq_hidden_pk.rowid:37!null + │ └── columns: uniq_hidden_pk.a:34 uniq_hidden_pk.b:35 uniq_hidden_pk.c:36 uniq_hidden_pk.d:37 uniq_hidden_pk.rowid:38!null └── filters - ├── a:31 = uniq_hidden_pk.a:33 - └── rowid:32 != uniq_hidden_pk.rowid:37 + ├── a:40 = uniq_hidden_pk.a:34 + └── rowid:44 != uniq_hidden_pk.rowid:38 # Insert with non-constant input. # Add inequality filters for the hidden primary key column. @@ -707,46 +752,425 @@ insert uniq_hidden_pk └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:15 c:16 rowid:17 + │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 │ ├── with-scan &1 - │ │ ├── columns: b:15 c:16 rowid:17 + │ │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 │ │ └── mapping: - │ │ ├── v:8 => b:15 - │ │ ├── x:10 => c:16 - │ │ └── column14:14 => rowid:17 + │ │ ├── k:7 => a:21 + │ │ ├── v:8 => b:22 + │ │ ├── x:10 => c:23 + │ │ ├── y:11 => d:24 + │ │ └── column14:14 => rowid:25 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.b:19 uniq_hidden_pk.c:20 uniq_hidden_pk.rowid:22!null + │ │ └── columns: uniq_hidden_pk.a:15 uniq_hidden_pk.b:16 uniq_hidden_pk.c:17 uniq_hidden_pk.d:18 uniq_hidden_pk.rowid:19!null │ └── filters - │ ├── b:15 = uniq_hidden_pk.b:19 - │ ├── c:16 = uniq_hidden_pk.c:20 - │ └── rowid:17 != uniq_hidden_pk.rowid:22 + │ ├── b:22 = uniq_hidden_pk.b:16 + │ ├── c:23 = uniq_hidden_pk.c:17 + │ └── rowid:25 != uniq_hidden_pk.rowid:19 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:24 b:25 d:26 rowid:27 + │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 │ ├── with-scan &1 - │ │ ├── columns: a:24 b:25 d:26 rowid:27 + │ │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 │ │ └── mapping: - │ │ ├── k:7 => a:24 - │ │ ├── v:8 => b:25 - │ │ ├── y:11 => d:26 - │ │ └── column14:14 => rowid:27 + │ │ ├── k:7 => a:32 + │ │ ├── v:8 => b:33 + │ │ ├── x:10 => c:34 + │ │ ├── y:11 => d:35 + │ │ └── column14:14 => rowid:36 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:28 uniq_hidden_pk.b:29 uniq_hidden_pk.d:31 uniq_hidden_pk.rowid:32!null + │ │ └── columns: uniq_hidden_pk.a:26 uniq_hidden_pk.b:27 uniq_hidden_pk.c:28 uniq_hidden_pk.d:29 uniq_hidden_pk.rowid:30!null │ └── filters - │ ├── a:24 = uniq_hidden_pk.a:28 - │ ├── b:25 = uniq_hidden_pk.b:29 - │ ├── d:26 = uniq_hidden_pk.d:31 - │ └── rowid:27 != uniq_hidden_pk.rowid:32 + │ ├── a:32 = uniq_hidden_pk.a:26 + │ ├── b:33 = uniq_hidden_pk.b:27 + │ ├── d:35 = uniq_hidden_pk.d:29 + │ └── rowid:36 != uniq_hidden_pk.rowid:30 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:34 rowid:35 + ├── columns: a:43 b:44 c:45 d:46 rowid:47 ├── with-scan &1 - │ ├── columns: a:34 rowid:35 + │ ├── columns: a:43 b:44 c:45 d:46 rowid:47 │ └── mapping: - │ ├── k:7 => a:34 - │ └── column14:14 => rowid:35 + │ ├── k:7 => a:43 + │ ├── v:8 => b:44 + │ ├── x:10 => c:45 + │ ├── y:11 => d:46 + │ └── column14:14 => rowid:47 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:36 uniq_hidden_pk.rowid:40!null + │ └── columns: uniq_hidden_pk.a:37 uniq_hidden_pk.b:38 uniq_hidden_pk.c:39 uniq_hidden_pk.d:40 uniq_hidden_pk.rowid:41!null + └── filters + ├── a:43 = uniq_hidden_pk.a:37 + └── rowid:47 != uniq_hidden_pk.rowid:41 + +exec-ddl +CREATE TABLE uniq_partial ( + k INT PRIMARY KEY, + a INT, + b INT, + UNIQUE WITHOUT INDEX (a) WHERE b > 0 +) +---- + +# None of the inserted values have nulls. +build +INSERT INTO uniq_partial VALUES (1, 1, 1), (2, 2, 2) +---- +insert uniq_partial + ├── columns: + ├── insert-mapping: + │ ├── column1:5 => uniq_partial.k:1 + │ ├── column2:6 => uniq_partial.a:2 + │ └── column3:7 => uniq_partial.b:3 + ├── input binding: &1 + ├── values + │ ├── columns: column1:5!null column2:6!null column3:7!null + │ ├── (1, 1, 1) + │ └── (2, 2, 2) + └── unique-checks + └── unique-checks-item: uniq_partial(a) + └── semi-join (hash) + ├── columns: k:12!null a:13!null b:14!null + ├── with-scan &1 + │ ├── columns: k:12!null a:13!null b:14!null + │ └── mapping: + │ ├── column1:5 => k:12 + │ ├── column2:6 => a:13 + │ └── column3:7 => b:14 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:8!null uniq_partial.a:9 uniq_partial.b:10 + └── filters + ├── a:13 = uniq_partial.a:9 + ├── b:14 > 0 + ├── uniq_partial.b:10 > 0 + └── k:12 != uniq_partial.k:8 + +# Some of the inserted values have nulls. +build +INSERT INTO uniq_partial VALUES (1, 1, 1), (2, 2, 2), (3, NULL, 3) +---- +insert uniq_partial + ├── columns: + ├── insert-mapping: + │ ├── column1:5 => uniq_partial.k:1 + │ ├── column2:6 => uniq_partial.a:2 + │ └── column3:7 => uniq_partial.b:3 + ├── input binding: &1 + ├── values + │ ├── columns: column1:5!null column2:6 column3:7!null + │ ├── (1, 1, 1) + │ ├── (2, 2, 2) + │ └── (3, NULL::INT8, 3) + └── unique-checks + └── unique-checks-item: uniq_partial(a) + └── semi-join (hash) + ├── columns: k:12!null a:13 b:14!null + ├── with-scan &1 + │ ├── columns: k:12!null a:13 b:14!null + │ └── mapping: + │ ├── column1:5 => k:12 + │ ├── column2:6 => a:13 + │ └── column3:7 => b:14 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:8!null uniq_partial.a:9 uniq_partial.b:10 + └── filters + ├── a:13 = uniq_partial.a:9 + ├── b:14 > 0 + ├── uniq_partial.b:10 > 0 + └── k:12 != uniq_partial.k:8 + +# No need to plan checks for a since it's always null. +build +INSERT INTO uniq_partial VALUES (1, NULL, 1), (2, NULL, 2) +---- +insert uniq_partial + ├── columns: + ├── insert-mapping: + │ ├── column1:5 => k:1 + │ ├── column2:6 => a:2 + │ └── column3:7 => b:3 + └── values + ├── columns: column1:5!null column2:6 column3:7!null + ├── (1, NULL::INT8, 1) + └── (2, NULL::INT8, 2) + +# Insert with non-constant input. +build +INSERT INTO uniq_partial SELECT k, v, w FROM other +---- +insert uniq_partial + ├── columns: + ├── insert-mapping: + │ ├── other.k:5 => uniq_partial.k:1 + │ ├── v:6 => uniq_partial.a:2 + │ └── w:7 => uniq_partial.b:3 + ├── input binding: &1 + ├── project + │ ├── columns: other.k:5 v:6 w:7!null + │ └── scan other + │ └── columns: other.k:5 v:6 w:7!null x:8 y:9 rowid:10!null other.crdb_internal_mvcc_timestamp:11 + └── unique-checks + └── unique-checks-item: uniq_partial(a) + └── semi-join (hash) + ├── columns: k:16 a:17 b:18!null + ├── with-scan &1 + │ ├── columns: k:16 a:17 b:18!null + │ └── mapping: + │ ├── other.k:5 => k:16 + │ ├── v:6 => a:17 + │ └── w:7 => b:18 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:12!null uniq_partial.a:13 uniq_partial.b:14 + └── filters + ├── a:17 = uniq_partial.a:13 + ├── b:18 > 0 + ├── uniq_partial.b:14 > 0 + └── k:16 != uniq_partial.k:12 + +exec-ddl +CREATE TABLE uniq_partial_overlaps_pk ( + a INT, + b INT, + c INT, + d INT, + PRIMARY KEY (a, b), + UNIQUE WITHOUT INDEX (c) WHERE d > 0, + UNIQUE WITHOUT INDEX (a) WHERE d > 0, + UNIQUE WITHOUT INDEX (a, b) WHERE d > 0, + UNIQUE WITHOUT INDEX (b, c) WHERE d > 0, + UNIQUE WITHOUT INDEX (a, b, c) WHERE d > 0 +) +---- + +# Insert with constant input. +# Do not build uniqueness checks when the primary key columns are a subset of +# the partial unique constraint columns. +build +INSERT INTO uniq_partial_overlaps_pk VALUES (1, 1, 1, 1), (2, 2, 2, 2) +---- +insert uniq_partial_overlaps_pk + ├── columns: + ├── insert-mapping: + │ ├── column1:6 => uniq_partial_overlaps_pk.a:1 + │ ├── column2:7 => uniq_partial_overlaps_pk.b:2 + │ ├── column3:8 => uniq_partial_overlaps_pk.c:3 + │ └── column4:9 => uniq_partial_overlaps_pk.d:4 + ├── input binding: &1 + ├── values + │ ├── columns: column1:6!null column2:7!null column3:8!null column4:9!null + │ ├── (1, 1, 1, 1) + │ └── (2, 2, 2, 2) + └── unique-checks + ├── unique-checks-item: uniq_partial_overlaps_pk(c) + │ └── semi-join (hash) + │ ├── columns: a:15!null b:16!null c:17!null d:18!null + │ ├── with-scan &1 + │ │ ├── columns: a:15!null b:16!null c:17!null d:18!null + │ │ └── mapping: + │ │ ├── column1:6 => a:15 + │ │ ├── column2:7 => b:16 + │ │ ├── column3:8 => c:17 + │ │ └── column4:9 => d:18 + │ ├── scan uniq_partial_overlaps_pk + │ │ └── columns: uniq_partial_overlaps_pk.a:10!null uniq_partial_overlaps_pk.b:11!null uniq_partial_overlaps_pk.c:12 uniq_partial_overlaps_pk.d:13 + │ └── filters + │ ├── c:17 = uniq_partial_overlaps_pk.c:12 + │ ├── d:18 > 0 + │ ├── uniq_partial_overlaps_pk.d:13 > 0 + │ └── (a:15 != uniq_partial_overlaps_pk.a:10) OR (b:16 != uniq_partial_overlaps_pk.b:11) + ├── unique-checks-item: uniq_partial_overlaps_pk(a) + │ └── semi-join (hash) + │ ├── columns: a:24!null b:25!null c:26!null d:27!null + │ ├── with-scan &1 + │ │ ├── columns: a:24!null b:25!null c:26!null d:27!null + │ │ └── mapping: + │ │ ├── column1:6 => a:24 + │ │ ├── column2:7 => b:25 + │ │ ├── column3:8 => c:26 + │ │ └── column4:9 => d:27 + │ ├── scan uniq_partial_overlaps_pk + │ │ └── columns: uniq_partial_overlaps_pk.a:19!null uniq_partial_overlaps_pk.b:20!null uniq_partial_overlaps_pk.c:21 uniq_partial_overlaps_pk.d:22 + │ └── filters + │ ├── a:24 = uniq_partial_overlaps_pk.a:19 + │ ├── d:27 > 0 + │ ├── uniq_partial_overlaps_pk.d:22 > 0 + │ └── b:25 != uniq_partial_overlaps_pk.b:20 + └── unique-checks-item: uniq_partial_overlaps_pk(b,c) + └── semi-join (hash) + ├── columns: a:33!null b:34!null c:35!null d:36!null + ├── with-scan &1 + │ ├── columns: a:33!null b:34!null c:35!null d:36!null + │ └── mapping: + │ ├── column1:6 => a:33 + │ ├── column2:7 => b:34 + │ ├── column3:8 => c:35 + │ └── column4:9 => d:36 + ├── scan uniq_partial_overlaps_pk + │ └── columns: uniq_partial_overlaps_pk.a:28!null uniq_partial_overlaps_pk.b:29!null uniq_partial_overlaps_pk.c:30 uniq_partial_overlaps_pk.d:31 + └── filters + ├── b:34 = uniq_partial_overlaps_pk.b:29 + ├── c:35 = uniq_partial_overlaps_pk.c:30 + ├── d:36 > 0 + ├── uniq_partial_overlaps_pk.d:31 > 0 + └── a:33 != uniq_partial_overlaps_pk.a:28 + +# Insert with non-constant input. +# Do not build uniqueness checks when the primary key columns are a subset of +# the partial unique constraint columns. +build +INSERT INTO uniq_partial_overlaps_pk SELECT k, v, x, y FROM other +---- +insert uniq_partial_overlaps_pk + ├── columns: + ├── insert-mapping: + │ ├── k:6 => uniq_partial_overlaps_pk.a:1 + │ ├── v:7 => uniq_partial_overlaps_pk.b:2 + │ ├── x:9 => uniq_partial_overlaps_pk.c:3 + │ └── y:10 => uniq_partial_overlaps_pk.d:4 + ├── input binding: &1 + ├── project + │ ├── columns: k:6 v:7 x:9 y:10 + │ └── scan other + │ └── columns: k:6 v:7 w:8!null x:9 y:10 rowid:11!null other.crdb_internal_mvcc_timestamp:12 + └── unique-checks + ├── unique-checks-item: uniq_partial_overlaps_pk(c) + │ └── semi-join (hash) + │ ├── columns: a:18 b:19 c:20 d:21 + │ ├── with-scan &1 + │ │ ├── columns: a:18 b:19 c:20 d:21 + │ │ └── mapping: + │ │ ├── k:6 => a:18 + │ │ ├── v:7 => b:19 + │ │ ├── x:9 => c:20 + │ │ └── y:10 => d:21 + │ ├── scan uniq_partial_overlaps_pk + │ │ └── columns: uniq_partial_overlaps_pk.a:13!null uniq_partial_overlaps_pk.b:14!null uniq_partial_overlaps_pk.c:15 uniq_partial_overlaps_pk.d:16 + │ └── filters + │ ├── c:20 = uniq_partial_overlaps_pk.c:15 + │ ├── d:21 > 0 + │ ├── uniq_partial_overlaps_pk.d:16 > 0 + │ └── (a:18 != uniq_partial_overlaps_pk.a:13) OR (b:19 != uniq_partial_overlaps_pk.b:14) + ├── unique-checks-item: uniq_partial_overlaps_pk(a) + │ └── semi-join (hash) + │ ├── columns: a:27 b:28 c:29 d:30 + │ ├── with-scan &1 + │ │ ├── columns: a:27 b:28 c:29 d:30 + │ │ └── mapping: + │ │ ├── k:6 => a:27 + │ │ ├── v:7 => b:28 + │ │ ├── x:9 => c:29 + │ │ └── y:10 => d:30 + │ ├── scan uniq_partial_overlaps_pk + │ │ └── columns: uniq_partial_overlaps_pk.a:22!null uniq_partial_overlaps_pk.b:23!null uniq_partial_overlaps_pk.c:24 uniq_partial_overlaps_pk.d:25 + │ └── filters + │ ├── a:27 = uniq_partial_overlaps_pk.a:22 + │ ├── d:30 > 0 + │ ├── uniq_partial_overlaps_pk.d:25 > 0 + │ └── b:28 != uniq_partial_overlaps_pk.b:23 + └── unique-checks-item: uniq_partial_overlaps_pk(b,c) + └── semi-join (hash) + ├── columns: a:36 b:37 c:38 d:39 + ├── with-scan &1 + │ ├── columns: a:36 b:37 c:38 d:39 + │ └── mapping: + │ ├── k:6 => a:36 + │ ├── v:7 => b:37 + │ ├── x:9 => c:38 + │ └── y:10 => d:39 + ├── scan uniq_partial_overlaps_pk + │ └── columns: uniq_partial_overlaps_pk.a:31!null uniq_partial_overlaps_pk.b:32!null uniq_partial_overlaps_pk.c:33 uniq_partial_overlaps_pk.d:34 + └── filters + ├── b:37 = uniq_partial_overlaps_pk.b:32 + ├── c:38 = uniq_partial_overlaps_pk.c:33 + ├── d:39 > 0 + ├── uniq_partial_overlaps_pk.d:34 > 0 + └── a:36 != uniq_partial_overlaps_pk.a:31 + +exec-ddl +CREATE TABLE uniq_partial_hidden_pk ( + a INT, + b INT, + c INT, + UNIQUE WITHOUT INDEX (b) WHERE c > 0 +) +---- + +# Insert with constant input. +# Add inequality filters for the hidden primary key column. +build +INSERT INTO uniq_partial_hidden_pk VALUES (1, 1), (2, 2) +---- +insert uniq_partial_hidden_pk + ├── columns: + ├── insert-mapping: + │ ├── column1:6 => uniq_partial_hidden_pk.a:1 + │ ├── column2:7 => uniq_partial_hidden_pk.b:2 + │ ├── column8:8 => uniq_partial_hidden_pk.c:3 + │ └── column9:9 => uniq_partial_hidden_pk.rowid:4 + ├── input binding: &1 + ├── project + │ ├── columns: column8:8 column9:9 column1:6!null column2:7!null + │ ├── values + │ │ ├── columns: column1:6!null column2:7!null + │ │ ├── (1, 1) + │ │ └── (2, 2) + │ └── projections + │ ├── NULL::INT8 [as=column8:8] + │ └── unique_rowid() [as=column9:9] + └── unique-checks + └── unique-checks-item: uniq_partial_hidden_pk(b) + └── semi-join (hash) + ├── columns: a:15!null b:16!null c:17 rowid:18 + ├── with-scan &1 + │ ├── columns: a:15!null b:16!null c:17 rowid:18 + │ └── mapping: + │ ├── column1:6 => a:15 + │ ├── column2:7 => b:16 + │ ├── column8:8 => c:17 + │ └── column9:9 => rowid:18 + ├── scan uniq_partial_hidden_pk + │ └── columns: uniq_partial_hidden_pk.a:10 uniq_partial_hidden_pk.b:11 uniq_partial_hidden_pk.c:12 uniq_partial_hidden_pk.rowid:13!null + └── filters + ├── b:16 = uniq_partial_hidden_pk.b:11 + ├── c:17 > 0 + ├── uniq_partial_hidden_pk.c:12 > 0 + └── rowid:18 != uniq_partial_hidden_pk.rowid:13 + +# Add inequality filters for the hidden primary key column. +build +INSERT INTO uniq_partial_hidden_pk SELECT k, v FROM other +---- +insert uniq_partial_hidden_pk + ├── columns: + ├── insert-mapping: + │ ├── k:6 => uniq_partial_hidden_pk.a:1 + │ ├── v:7 => uniq_partial_hidden_pk.b:2 + │ ├── column13:13 => uniq_partial_hidden_pk.c:3 + │ └── column14:14 => uniq_partial_hidden_pk.rowid:4 + ├── input binding: &1 + ├── project + │ ├── columns: column13:13 column14:14 k:6 v:7 + │ ├── project + │ │ ├── columns: k:6 v:7 + │ │ └── scan other + │ │ └── columns: k:6 v:7 w:8!null x:9 y:10 other.rowid:11!null other.crdb_internal_mvcc_timestamp:12 + │ └── projections + │ ├── NULL::INT8 [as=column13:13] + │ └── unique_rowid() [as=column14:14] + └── unique-checks + └── unique-checks-item: uniq_partial_hidden_pk(b) + └── semi-join (hash) + ├── columns: a:20 b:21 c:22 rowid:23 + ├── with-scan &1 + │ ├── columns: a:20 b:21 c:22 rowid:23 + │ └── mapping: + │ ├── k:6 => a:20 + │ ├── v:7 => b:21 + │ ├── column13:13 => c:22 + │ └── column14:14 => rowid:23 + ├── scan uniq_partial_hidden_pk + │ └── columns: uniq_partial_hidden_pk.a:15 uniq_partial_hidden_pk.b:16 uniq_partial_hidden_pk.c:17 uniq_partial_hidden_pk.rowid:18!null └── filters - ├── a:34 = uniq_hidden_pk.a:36 - └── rowid:35 != uniq_hidden_pk.rowid:40 + ├── b:21 = uniq_partial_hidden_pk.b:16 + ├── c:22 > 0 + ├── uniq_partial_hidden_pk.c:17 > 0 + └── rowid:23 != uniq_partial_hidden_pk.rowid:18 diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-update b/pkg/sql/opt/optbuilder/testdata/unique-checks-update index b83fdf774dfe..77ced5f530b6 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-update +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-update @@ -15,47 +15,52 @@ UPDATE uniq SET w = 1, x = 2 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 uniq.w:9 uniq.x:10 uniq.y:11 + ├── fetch columns: uniq.k:7 uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 ├── update-mapping: │ ├── w_new:13 => uniq.w:3 │ └── x_new:14 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: w_new:13!null x_new:14!null uniq.k:7!null v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: w_new:13!null x_new:14!null uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ ├── scan uniq - │ │ └── columns: uniq.k:7!null v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ └── projections │ ├── 1 [as=w_new:13] │ └── 2 [as=x_new:14] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:15!null k:16!null + │ ├── columns: k:21!null v:22 w:23!null x:24!null y:25 │ ├── with-scan &1 - │ │ ├── columns: w:15!null k:16!null + │ │ ├── columns: k:21!null v:22 w:23!null x:24!null y:25 │ │ └── mapping: - │ │ ├── w_new:13 => w:15 - │ │ └── uniq.k:7 => k:16 + │ │ ├── uniq.k:7 => k:21 + │ │ ├── uniq.v:8 => v:22 + │ │ ├── w_new:13 => w:23 + │ │ ├── x_new:14 => x:24 + │ │ └── uniq.y:11 => y:25 │ ├── scan uniq - │ │ └── columns: uniq.k:17!null uniq.w:19 + │ │ └── columns: uniq.k:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 │ └── filters - │ ├── w:15 = uniq.w:19 - │ └── k:16 != uniq.k:17 + │ ├── w:23 = uniq.w:17 + │ └── k:21 != uniq.k:15 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:23!null y:24 k:25!null + ├── columns: k:32!null v:33 w:34!null x:35!null y:36 ├── with-scan &1 - │ ├── columns: x:23!null y:24 k:25!null + │ ├── columns: k:32!null v:33 w:34!null x:35!null y:36 │ └── mapping: - │ ├── x_new:14 => x:23 - │ ├── uniq.y:11 => y:24 - │ └── uniq.k:7 => k:25 + │ ├── uniq.k:7 => k:32 + │ ├── uniq.v:8 => v:33 + │ ├── w_new:13 => w:34 + │ ├── x_new:14 => x:35 + │ └── uniq.y:11 => y:36 ├── scan uniq - │ └── columns: uniq.k:26!null uniq.x:29 uniq.y:30 + │ └── columns: uniq.k:26!null uniq.v:27 uniq.w:28 uniq.x:29 uniq.y:30 └── filters - ├── x:23 = uniq.x:29 - ├── y:24 = uniq.y:30 - └── k:25 != uniq.k:26 + ├── x:35 = uniq.x:29 + ├── y:36 = uniq.y:30 + └── k:32 != uniq.k:26 # No need to plan checks for w since it's aways null. build @@ -63,34 +68,36 @@ UPDATE uniq SET w = NULL, x = 1 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 w:9 uniq.x:10 uniq.y:11 + ├── fetch columns: uniq.k:7 uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 ├── update-mapping: - │ ├── w_new:13 => w:3 + │ ├── w_new:13 => uniq.w:3 │ └── x_new:14 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: w_new:13 x_new:14!null uniq.k:7!null v:8 w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: w_new:13 x_new:14!null uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ ├── scan uniq - │ │ └── columns: uniq.k:7!null v:8 w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ └── projections │ ├── NULL::INT8 [as=w_new:13] │ └── 1 [as=x_new:14] └── unique-checks └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:15!null y:16 k:17!null + ├── columns: k:21!null v:22 w:23 x:24!null y:25 ├── with-scan &1 - │ ├── columns: x:15!null y:16 k:17!null + │ ├── columns: k:21!null v:22 w:23 x:24!null y:25 │ └── mapping: - │ ├── x_new:14 => x:15 - │ ├── uniq.y:11 => y:16 - │ └── uniq.k:7 => k:17 + │ ├── uniq.k:7 => k:21 + │ ├── uniq.v:8 => v:22 + │ ├── w_new:13 => w:23 + │ ├── x_new:14 => x:24 + │ └── uniq.y:11 => y:25 ├── scan uniq - │ └── columns: uniq.k:18!null uniq.x:21 uniq.y:22 + │ └── columns: uniq.k:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 └── filters - ├── x:15 = uniq.x:21 - ├── y:16 = uniq.y:22 - └── k:17 != uniq.k:18 + ├── x:24 = uniq.x:18 + ├── y:25 = uniq.y:19 + └── k:21 != uniq.k:15 # No need to plan checks for x,y since x is aways null. # Also update the primary key. @@ -99,16 +106,16 @@ UPDATE uniq SET k = 1, w = 2, x = NULL ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 uniq.w:9 x:10 y:11 + ├── fetch columns: uniq.k:7 uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 ├── update-mapping: │ ├── k_new:13 => uniq.k:1 │ ├── w_new:14 => uniq.w:3 - │ └── x_new:15 => x:4 + │ └── x_new:15 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: k_new:13!null w_new:14!null x_new:15 uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: k_new:13!null w_new:14!null x_new:15 uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ ├── scan uniq - │ │ └── columns: uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ └── projections │ ├── 1 [as=k_new:13] │ ├── 2 [as=w_new:14] @@ -116,17 +123,20 @@ update uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: w:16!null k:17!null + ├── columns: k:22!null v:23 w:24!null x:25 y:26 ├── with-scan &1 - │ ├── columns: w:16!null k:17!null + │ ├── columns: k:22!null v:23 w:24!null x:25 y:26 │ └── mapping: - │ ├── w_new:14 => w:16 - │ └── k_new:13 => k:17 + │ ├── k_new:13 => k:22 + │ ├── uniq.v:8 => v:23 + │ ├── w_new:14 => w:24 + │ ├── x_new:15 => x:25 + │ └── uniq.y:11 => y:26 ├── scan uniq - │ └── columns: uniq.k:18!null uniq.w:20 + │ └── columns: uniq.k:16!null uniq.v:17 uniq.w:18 uniq.x:19 uniq.y:20 └── filters - ├── w:16 = uniq.w:20 - └── k:17 != uniq.k:18 + ├── w:24 = uniq.w:18 + └── k:22 != uniq.k:16 # No need to plan checks for x,y since y is aways null. build @@ -134,17 +144,17 @@ UPDATE uniq SET w = 1, y = NULL WHERE k = 1 ---- update uniq ├── columns: - ├── fetch columns: uniq.k:7 v:8 uniq.w:9 x:10 y:11 + ├── fetch columns: uniq.k:7 uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 ├── update-mapping: │ ├── w_new:13 => uniq.w:3 - │ └── y_new:14 => y:5 + │ └── y_new:14 => uniq.y:5 ├── input binding: &1 ├── project - │ ├── columns: w_new:13!null y_new:14 uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ ├── columns: w_new:13!null y_new:14 uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ ├── select - │ │ ├── columns: uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ │ ├── columns: uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ │ ├── scan uniq - │ │ │ └── columns: uniq.k:7!null v:8 uniq.w:9 x:10 y:11 crdb_internal_mvcc_timestamp:12 + │ │ │ └── columns: uniq.k:7!null uniq.v:8 uniq.w:9 uniq.x:10 uniq.y:11 crdb_internal_mvcc_timestamp:12 │ │ └── filters │ │ └── uniq.k:7 = 1 │ └── projections @@ -153,17 +163,20 @@ update uniq └── unique-checks └── unique-checks-item: uniq(w) └── semi-join (hash) - ├── columns: w:15!null k:16!null + ├── columns: k:21!null v:22 w:23!null x:24 y:25 ├── with-scan &1 - │ ├── columns: w:15!null k:16!null + │ ├── columns: k:21!null v:22 w:23!null x:24 y:25 │ └── mapping: - │ ├── w_new:13 => w:15 - │ └── uniq.k:7 => k:16 + │ ├── uniq.k:7 => k:21 + │ ├── uniq.v:8 => v:22 + │ ├── w_new:13 => w:23 + │ ├── uniq.x:10 => x:24 + │ └── y_new:14 => y:25 ├── scan uniq - │ └── columns: uniq.k:17!null uniq.w:19 + │ └── columns: uniq.k:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 └── filters - ├── w:15 = uniq.w:19 - └── k:16 != uniq.k:17 + ├── w:23 = uniq.w:17 + └── k:21 != uniq.k:15 # No need to plan checks since none of the columns requiring checks are updated. build @@ -236,32 +249,37 @@ update uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:20!null k:21!null + │ ├── columns: k:26!null v:27 w:28!null x:29 y:30 │ ├── with-scan &1 - │ │ ├── columns: w:20!null k:21!null + │ │ ├── columns: k:26!null v:27 w:28!null x:29 y:30 │ │ └── mapping: - │ │ ├── other.w:15 => w:20 - │ │ └── uniq.k:7 => k:21 + │ │ ├── uniq.k:7 => k:26 + │ │ ├── uniq.v:8 => v:27 + │ │ ├── other.w:15 => w:28 + │ │ ├── other.x:16 => x:29 + │ │ └── uniq.y:11 => y:30 │ ├── scan uniq - │ │ └── columns: uniq.k:22!null uniq.w:24 + │ │ └── columns: uniq.k:20!null uniq.v:21 uniq.w:22 uniq.x:23 uniq.y:24 │ └── filters - │ ├── w:20 = uniq.w:24 - │ └── k:21 != uniq.k:22 + │ ├── w:28 = uniq.w:22 + │ └── k:26 != uniq.k:20 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:28 y:29 k:30!null + ├── columns: k:37!null v:38 w:39!null x:40 y:41 ├── with-scan &1 - │ ├── columns: x:28 y:29 k:30!null + │ ├── columns: k:37!null v:38 w:39!null x:40 y:41 │ └── mapping: - │ ├── other.x:16 => x:28 - │ ├── uniq.y:11 => y:29 - │ └── uniq.k:7 => k:30 + │ ├── uniq.k:7 => k:37 + │ ├── uniq.v:8 => v:38 + │ ├── other.w:15 => w:39 + │ ├── other.x:16 => x:40 + │ └── uniq.y:11 => y:41 ├── scan uniq - │ └── columns: uniq.k:31!null uniq.x:34 uniq.y:35 + │ └── columns: uniq.k:31!null uniq.v:32 uniq.w:33 uniq.x:34 uniq.y:35 └── filters - ├── x:28 = uniq.x:34 - ├── y:29 = uniq.y:35 - └── k:30 != uniq.k:31 + ├── x:40 = uniq.x:34 + ├── y:41 = uniq.y:35 + └── k:37 != uniq.k:31 exec-ddl CREATE TABLE uniq_overlaps_pk ( @@ -308,48 +326,51 @@ update uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:15!null c:16!null a:17!null + │ ├── columns: a:20!null b:21!null c:22!null d:23!null │ ├── with-scan &1 - │ │ ├── columns: b:15!null c:16!null a:17!null + │ │ ├── columns: a:20!null b:21!null c:22!null d:23!null │ │ └── mapping: - │ │ ├── b_new:12 => b:15 - │ │ ├── c_new:13 => c:16 - │ │ └── a_new:11 => a:17 + │ │ ├── a_new:11 => a:20 + │ │ ├── b_new:12 => b:21 + │ │ ├── c_new:13 => c:22 + │ │ └── d_new:14 => d:23 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:18!null uniq_overlaps_pk.b:19!null uniq_overlaps_pk.c:20 + │ │ └── columns: uniq_overlaps_pk.a:15!null uniq_overlaps_pk.b:16!null uniq_overlaps_pk.c:17 uniq_overlaps_pk.d:18 │ └── filters - │ ├── b:15 = uniq_overlaps_pk.b:19 - │ ├── c:16 = uniq_overlaps_pk.c:20 - │ └── a:17 != uniq_overlaps_pk.a:18 + │ ├── b:21 = uniq_overlaps_pk.b:16 + │ ├── c:22 = uniq_overlaps_pk.c:17 + │ └── a:20 != uniq_overlaps_pk.a:15 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:23!null b:24!null + │ ├── columns: a:29!null b:30!null c:31!null d:32!null │ ├── with-scan &1 - │ │ ├── columns: a:23!null b:24!null + │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null │ │ └── mapping: - │ │ ├── a_new:11 => a:23 - │ │ └── b_new:12 => b:24 + │ │ ├── a_new:11 => a:29 + │ │ ├── b_new:12 => b:30 + │ │ ├── c_new:13 => c:31 + │ │ └── d_new:14 => d:32 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:25!null uniq_overlaps_pk.b:26!null + │ │ └── columns: uniq_overlaps_pk.a:24!null uniq_overlaps_pk.b:25!null uniq_overlaps_pk.c:26 uniq_overlaps_pk.d:27 │ └── filters - │ ├── a:23 = uniq_overlaps_pk.a:25 - │ └── b:24 != uniq_overlaps_pk.b:26 + │ ├── a:29 = uniq_overlaps_pk.a:24 + │ └── b:30 != uniq_overlaps_pk.b:25 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:30!null d:31!null a:32!null b:33!null + ├── columns: a:38!null b:39!null c:40!null d:41!null ├── with-scan &1 - │ ├── columns: c:30!null d:31!null a:32!null b:33!null + │ ├── columns: a:38!null b:39!null c:40!null d:41!null │ └── mapping: - │ ├── c_new:13 => c:30 - │ ├── d_new:14 => d:31 - │ ├── a_new:11 => a:32 - │ └── b_new:12 => b:33 + │ ├── a_new:11 => a:38 + │ ├── b_new:12 => b:39 + │ ├── c_new:13 => c:40 + │ └── d_new:14 => d:41 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:34!null uniq_overlaps_pk.b:35!null uniq_overlaps_pk.c:36 uniq_overlaps_pk.d:37 + │ └── columns: uniq_overlaps_pk.a:33!null uniq_overlaps_pk.b:34!null uniq_overlaps_pk.c:35 uniq_overlaps_pk.d:36 └── filters - ├── c:30 = uniq_overlaps_pk.c:36 - ├── d:31 = uniq_overlaps_pk.d:37 - └── (a:32 != uniq_overlaps_pk.a:34) OR (b:33 != uniq_overlaps_pk.b:35) + ├── c:40 = uniq_overlaps_pk.c:35 + ├── d:41 = uniq_overlaps_pk.d:36 + └── (a:38 != uniq_overlaps_pk.a:33) OR (b:39 != uniq_overlaps_pk.b:34) # Update with non-constant input. # No need to add a check for b,c since those columns weren't updated. @@ -399,33 +420,35 @@ update uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:18 b:19!null + │ ├── columns: a:23 b:24!null c:25 d:26 │ ├── with-scan &1 - │ │ ├── columns: a:18 b:19!null + │ │ ├── columns: a:23 b:24!null c:25 d:26 │ │ └── mapping: - │ │ ├── k:11 => a:18 - │ │ └── uniq_overlaps_pk.b:7 => b:19 + │ │ ├── k:11 => a:23 + │ │ ├── uniq_overlaps_pk.b:7 => b:24 + │ │ ├── uniq_overlaps_pk.c:8 => c:25 + │ │ └── v:12 => d:26 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null + │ │ └── columns: uniq_overlaps_pk.a:18!null uniq_overlaps_pk.b:19!null uniq_overlaps_pk.c:20 uniq_overlaps_pk.d:21 │ └── filters - │ ├── a:18 = uniq_overlaps_pk.a:20 - │ └── b:19 != uniq_overlaps_pk.b:21 + │ ├── a:23 = uniq_overlaps_pk.a:18 + │ └── b:24 != uniq_overlaps_pk.b:19 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:25 d:26 a:27 b:28!null + ├── columns: a:32 b:33!null c:34 d:35 ├── with-scan &1 - │ ├── columns: c:25 d:26 a:27 b:28!null + │ ├── columns: a:32 b:33!null c:34 d:35 │ └── mapping: - │ ├── uniq_overlaps_pk.c:8 => c:25 - │ ├── v:12 => d:26 - │ ├── k:11 => a:27 - │ └── uniq_overlaps_pk.b:7 => b:28 + │ ├── k:11 => a:32 + │ ├── uniq_overlaps_pk.b:7 => b:33 + │ ├── uniq_overlaps_pk.c:8 => c:34 + │ └── v:12 => d:35 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 + │ └── columns: uniq_overlaps_pk.a:27!null uniq_overlaps_pk.b:28!null uniq_overlaps_pk.c:29 uniq_overlaps_pk.d:30 └── filters - ├── c:25 = uniq_overlaps_pk.c:31 - ├── d:26 = uniq_overlaps_pk.d:32 - └── (a:27 != uniq_overlaps_pk.a:29) OR (b:28 != uniq_overlaps_pk.b:30) + ├── c:34 = uniq_overlaps_pk.c:29 + ├── d:35 = uniq_overlaps_pk.d:30 + └── (a:32 != uniq_overlaps_pk.a:27) OR (b:33 != uniq_overlaps_pk.b:28) exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -447,47 +470,51 @@ UPDATE uniq_hidden_pk SET a = 1 ---- update uniq_hidden_pk ├── columns: - ├── fetch columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 + ├── fetch columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 uniq_hidden_pk.c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 ├── update-mapping: │ └── a_new:13 => uniq_hidden_pk.a:1 ├── input binding: &1 ├── project - │ ├── columns: a_new:13!null uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 + │ ├── columns: a_new:13!null uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 uniq_hidden_pk.c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 uniq_hidden_pk.c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null crdb_internal_mvcc_timestamp:12 │ └── projections │ └── 1 [as=a_new:13] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:14!null b:15 d:16 rowid:17!null + │ ├── columns: a:20!null b:21 c:22 d:23 rowid:24!null │ ├── with-scan &1 - │ │ ├── columns: a:14!null b:15 d:16 rowid:17!null + │ │ ├── columns: a:20!null b:21 c:22 d:23 rowid:24!null │ │ └── mapping: - │ │ ├── a_new:13 => a:14 - │ │ ├── uniq_hidden_pk.b:8 => b:15 - │ │ ├── uniq_hidden_pk.d:10 => d:16 - │ │ └── uniq_hidden_pk.rowid:11 => rowid:17 + │ │ ├── a_new:13 => a:20 + │ │ ├── uniq_hidden_pk.b:8 => b:21 + │ │ ├── uniq_hidden_pk.c:9 => c:22 + │ │ ├── uniq_hidden_pk.d:10 => d:23 + │ │ └── uniq_hidden_pk.rowid:11 => rowid:24 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:18 uniq_hidden_pk.b:19 uniq_hidden_pk.d:21 uniq_hidden_pk.rowid:22!null + │ │ └── columns: uniq_hidden_pk.a:14 uniq_hidden_pk.b:15 uniq_hidden_pk.c:16 uniq_hidden_pk.d:17 uniq_hidden_pk.rowid:18!null │ └── filters - │ ├── a:14 = uniq_hidden_pk.a:18 - │ ├── b:15 = uniq_hidden_pk.b:19 - │ ├── d:16 = uniq_hidden_pk.d:21 - │ └── rowid:17 != uniq_hidden_pk.rowid:22 + │ ├── a:20 = uniq_hidden_pk.a:14 + │ ├── b:21 = uniq_hidden_pk.b:15 + │ ├── d:23 = uniq_hidden_pk.d:17 + │ └── rowid:24 != uniq_hidden_pk.rowid:18 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:24!null rowid:25!null + ├── columns: a:31!null b:32 c:33 d:34 rowid:35!null ├── with-scan &1 - │ ├── columns: a:24!null rowid:25!null + │ ├── columns: a:31!null b:32 c:33 d:34 rowid:35!null │ └── mapping: - │ ├── a_new:13 => a:24 - │ └── uniq_hidden_pk.rowid:11 => rowid:25 + │ ├── a_new:13 => a:31 + │ ├── uniq_hidden_pk.b:8 => b:32 + │ ├── uniq_hidden_pk.c:9 => c:33 + │ ├── uniq_hidden_pk.d:10 => d:34 + │ └── uniq_hidden_pk.rowid:11 => rowid:35 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:26 uniq_hidden_pk.rowid:30!null + │ └── columns: uniq_hidden_pk.a:25 uniq_hidden_pk.b:26 uniq_hidden_pk.c:27 uniq_hidden_pk.d:28 uniq_hidden_pk.rowid:29!null └── filters - ├── a:24 = uniq_hidden_pk.a:26 - └── rowid:25 != uniq_hidden_pk.rowid:30 + ├── a:31 = uniq_hidden_pk.a:25 + └── rowid:35 != uniq_hidden_pk.rowid:29 # Update with non-constant input. # No need to add a check for b,c since those columns weren't updated. @@ -497,45 +524,49 @@ UPDATE uniq_hidden_pk SET a = k FROM other ---- update uniq_hidden_pk ├── columns: - ├── fetch columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 + ├── fetch columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 uniq_hidden_pk.c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11 ├── update-mapping: │ └── k:13 => uniq_hidden_pk.a:1 ├── input binding: &1 ├── inner-join (cross) - │ ├── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 + │ ├── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 uniq_hidden_pk.c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 + │ │ └── columns: uniq_hidden_pk.a:7 uniq_hidden_pk.b:8 uniq_hidden_pk.c:9 uniq_hidden_pk.d:10 uniq_hidden_pk.rowid:11!null uniq_hidden_pk.crdb_internal_mvcc_timestamp:12 │ ├── scan other │ │ └── columns: k:13 v:14 w:15!null x:16 y:17 other.rowid:18!null other.crdb_internal_mvcc_timestamp:19 │ └── filters (true) └── unique-checks ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:20 b:21 d:22 rowid:23!null + │ ├── columns: a:26 b:27 c:28 d:29 rowid:30!null │ ├── with-scan &1 - │ │ ├── columns: a:20 b:21 d:22 rowid:23!null + │ │ ├── columns: a:26 b:27 c:28 d:29 rowid:30!null │ │ └── mapping: - │ │ ├── k:13 => a:20 - │ │ ├── uniq_hidden_pk.b:8 => b:21 - │ │ ├── uniq_hidden_pk.d:10 => d:22 - │ │ └── uniq_hidden_pk.rowid:11 => rowid:23 + │ │ ├── k:13 => a:26 + │ │ ├── uniq_hidden_pk.b:8 => b:27 + │ │ ├── uniq_hidden_pk.c:9 => c:28 + │ │ ├── uniq_hidden_pk.d:10 => d:29 + │ │ └── uniq_hidden_pk.rowid:11 => rowid:30 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:24 uniq_hidden_pk.b:25 uniq_hidden_pk.d:27 uniq_hidden_pk.rowid:28!null + │ │ └── columns: uniq_hidden_pk.a:20 uniq_hidden_pk.b:21 uniq_hidden_pk.c:22 uniq_hidden_pk.d:23 uniq_hidden_pk.rowid:24!null │ └── filters - │ ├── a:20 = uniq_hidden_pk.a:24 - │ ├── b:21 = uniq_hidden_pk.b:25 - │ ├── d:22 = uniq_hidden_pk.d:27 - │ └── rowid:23 != uniq_hidden_pk.rowid:28 + │ ├── a:26 = uniq_hidden_pk.a:20 + │ ├── b:27 = uniq_hidden_pk.b:21 + │ ├── d:29 = uniq_hidden_pk.d:23 + │ └── rowid:30 != uniq_hidden_pk.rowid:24 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:30 rowid:31!null + ├── columns: a:37 b:38 c:39 d:40 rowid:41!null ├── with-scan &1 - │ ├── columns: a:30 rowid:31!null + │ ├── columns: a:37 b:38 c:39 d:40 rowid:41!null │ └── mapping: - │ ├── k:13 => a:30 - │ └── uniq_hidden_pk.rowid:11 => rowid:31 + │ ├── k:13 => a:37 + │ ├── uniq_hidden_pk.b:8 => b:38 + │ ├── uniq_hidden_pk.c:9 => c:39 + │ ├── uniq_hidden_pk.d:10 => d:40 + │ └── uniq_hidden_pk.rowid:11 => rowid:41 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:32 uniq_hidden_pk.rowid:36!null + │ └── columns: uniq_hidden_pk.a:31 uniq_hidden_pk.b:32 uniq_hidden_pk.c:33 uniq_hidden_pk.d:34 uniq_hidden_pk.rowid:35!null └── filters - ├── a:30 = uniq_hidden_pk.a:32 - └── rowid:31 != uniq_hidden_pk.rowid:36 + ├── a:37 = uniq_hidden_pk.a:31 + └── rowid:41 != uniq_hidden_pk.rowid:35 diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert b/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert index bc202fc5242b..2d4e220a5389 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert @@ -21,23 +21,23 @@ upsert uniq ├── columns: ├── arbiter indexes: primary ├── canary column: uniq.k:12 - ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 + ├── fetch columns: uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 ├── update-mapping: - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_k:18 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ ├── grouping columns: column1:7!null @@ -55,7 +55,7 @@ upsert uniq │ │ │ └── first-agg [as=column5:11] │ │ │ └── column5:11 │ │ ├── scan uniq - │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ └── filters │ │ └── column1:7 = uniq.k:12 │ └── projections @@ -63,32 +63,37 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:19!null k:20 + │ ├── columns: k:25 v:26!null w:27!null x:28!null y:29!null │ ├── with-scan &1 - │ │ ├── columns: w:19!null k:20 + │ │ ├── columns: k:25 v:26!null w:27!null x:28!null y:29!null │ │ └── mapping: - │ │ ├── column3:9 => w:19 - │ │ └── upsert_k:18 => k:20 + │ │ ├── upsert_k:18 => k:25 + │ │ ├── column2:8 => v:26 + │ │ ├── column3:9 => w:27 + │ │ ├── column4:10 => x:28 + │ │ └── column5:11 => y:29 │ ├── scan uniq - │ │ └── columns: uniq.k:21!null uniq.w:23 + │ │ └── columns: uniq.k:19!null uniq.v:20 uniq.w:21 uniq.x:22 uniq.y:23 │ └── filters - │ ├── w:19 = uniq.w:23 - │ └── k:20 != uniq.k:21 + │ ├── w:27 = uniq.w:21 + │ └── k:25 != uniq.k:19 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:27!null y:28!null k:29 + ├── columns: k:36 v:37!null w:38!null x:39!null y:40!null ├── with-scan &1 - │ ├── columns: x:27!null y:28!null k:29 + │ ├── columns: k:36 v:37!null w:38!null x:39!null y:40!null │ └── mapping: - │ ├── column4:10 => x:27 - │ ├── column5:11 => y:28 - │ └── upsert_k:18 => k:29 + │ ├── upsert_k:18 => k:36 + │ ├── column2:8 => v:37 + │ ├── column3:9 => w:38 + │ ├── column4:10 => x:39 + │ └── column5:11 => y:40 ├── scan uniq - │ └── columns: uniq.k:30!null uniq.x:33 uniq.y:34 + │ └── columns: uniq.k:30!null uniq.v:31 uniq.w:32 uniq.x:33 uniq.y:34 └── filters - ├── x:27 = uniq.x:33 - ├── y:28 = uniq.y:34 - └── k:29 != uniq.k:30 + ├── x:39 = uniq.x:33 + ├── y:40 = uniq.y:34 + └── k:36 != uniq.k:30 # TODO(rytaft): The default value for x is NULL, and we're not updating either # x or y. Therefore, we could avoid planning checks for (x,y) (see #58300). @@ -99,21 +104,21 @@ upsert uniq ├── columns: ├── arbiter indexes: primary ├── canary column: uniq.k:12 - ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 + ├── fetch columns: uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column10:10 => uniq.x:4 │ └── column11:11 => uniq.y:5 ├── update-mapping: - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ └── column3:9 => uniq.w:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 upsert_x:19 upsert_y:20 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_k:18 upsert_x:19 upsert_y:20 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null │ │ │ ├── grouping columns: column1:7!null @@ -136,7 +141,7 @@ upsert uniq │ │ │ └── first-agg [as=column11:11] │ │ │ └── column11:11 │ │ ├── scan uniq - │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ └── filters │ │ └── column1:7 = uniq.k:12 │ └── projections @@ -146,32 +151,37 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:21!null k:22 + │ ├── columns: k:27 v:28!null w:29!null x:30 y:31 │ ├── with-scan &1 - │ │ ├── columns: w:21!null k:22 + │ │ ├── columns: k:27 v:28!null w:29!null x:30 y:31 │ │ └── mapping: - │ │ ├── column3:9 => w:21 - │ │ └── upsert_k:18 => k:22 + │ │ ├── upsert_k:18 => k:27 + │ │ ├── column2:8 => v:28 + │ │ ├── column3:9 => w:29 + │ │ ├── upsert_x:19 => x:30 + │ │ └── upsert_y:20 => y:31 │ ├── scan uniq - │ │ └── columns: uniq.k:23!null uniq.w:25 + │ │ └── columns: uniq.k:21!null uniq.v:22 uniq.w:23 uniq.x:24 uniq.y:25 │ └── filters - │ ├── w:21 = uniq.w:25 - │ └── k:22 != uniq.k:23 + │ ├── w:29 = uniq.w:23 + │ └── k:27 != uniq.k:21 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:29 y:30 k:31 + ├── columns: k:38 v:39!null w:40!null x:41 y:42 ├── with-scan &1 - │ ├── columns: x:29 y:30 k:31 + │ ├── columns: k:38 v:39!null w:40!null x:41 y:42 │ └── mapping: - │ ├── upsert_x:19 => x:29 - │ ├── upsert_y:20 => y:30 - │ └── upsert_k:18 => k:31 + │ ├── upsert_k:18 => k:38 + │ ├── column2:8 => v:39 + │ ├── column3:9 => w:40 + │ ├── upsert_x:19 => x:41 + │ └── upsert_y:20 => y:42 ├── scan uniq - │ └── columns: uniq.k:32!null uniq.x:35 uniq.y:36 + │ └── columns: uniq.k:32!null uniq.v:33 uniq.w:34 uniq.x:35 uniq.y:36 └── filters - ├── x:29 = uniq.x:35 - ├── y:30 = uniq.y:36 - └── k:31 != uniq.k:32 + ├── x:41 = uniq.x:35 + ├── y:42 = uniq.y:36 + └── k:38 != uniq.k:32 # TODO(rytaft): No need to plan checks for w since it's aways NULL. # We currently can't determine that w is always NULL since the function @@ -183,10 +193,10 @@ upsert uniq ├── columns: ├── arbiter indexes: primary ├── canary column: uniq.k:12 - ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 + ├── fetch columns: uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column10:10 => v:2 + │ ├── column10:10 => uniq.v:2 │ ├── column2:8 => uniq.w:3 │ ├── column3:9 => uniq.x:4 │ └── column11:11 => uniq.y:5 @@ -195,9 +205,9 @@ upsert uniq │ └── column3:9 => uniq.x:4 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 upsert_v:19 upsert_y:20 column1:7!null column2:8 column3:9 column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ ├── columns: upsert_k:18 upsert_v:19 upsert_y:20 column1:7!null column2:8 column3:9 column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ ├── left-join (hash) - │ │ ├── columns: column1:7!null column2:8 column3:9 column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: column1:7!null column2:8 column3:9 column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── ensure-upsert-distinct-on │ │ │ ├── columns: column1:7!null column2:8 column3:9 column10:10 column11:11!null │ │ │ ├── grouping columns: column1:7!null @@ -220,42 +230,47 @@ upsert uniq │ │ │ └── first-agg [as=column11:11] │ │ │ └── column11:11 │ │ ├── scan uniq - │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ └── filters │ │ └── column1:7 = uniq.k:12 │ └── projections │ ├── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:18] - │ ├── CASE WHEN uniq.k:12 IS NULL THEN column10:10 ELSE v:13 END [as=upsert_v:19] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column10:10 ELSE uniq.v:13 END [as=upsert_v:19] │ └── CASE WHEN uniq.k:12 IS NULL THEN column11:11 ELSE uniq.y:16 END [as=upsert_y:20] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:21 k:22 + │ ├── columns: k:27 v:28 w:29 x:30 y:31 │ ├── with-scan &1 - │ │ ├── columns: w:21 k:22 + │ │ ├── columns: k:27 v:28 w:29 x:30 y:31 │ │ └── mapping: - │ │ ├── column2:8 => w:21 - │ │ └── upsert_k:18 => k:22 + │ │ ├── upsert_k:18 => k:27 + │ │ ├── upsert_v:19 => v:28 + │ │ ├── column2:8 => w:29 + │ │ ├── column3:9 => x:30 + │ │ └── upsert_y:20 => y:31 │ ├── scan uniq - │ │ └── columns: uniq.k:23!null uniq.w:25 + │ │ └── columns: uniq.k:21!null uniq.v:22 uniq.w:23 uniq.x:24 uniq.y:25 │ └── filters - │ ├── w:21 = uniq.w:25 - │ └── k:22 != uniq.k:23 + │ ├── w:29 = uniq.w:23 + │ └── k:27 != uniq.k:21 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:29 y:30 k:31 + ├── columns: k:38 v:39 w:40 x:41 y:42 ├── with-scan &1 - │ ├── columns: x:29 y:30 k:31 + │ ├── columns: k:38 v:39 w:40 x:41 y:42 │ └── mapping: - │ ├── column3:9 => x:29 - │ ├── upsert_y:20 => y:30 - │ └── upsert_k:18 => k:31 + │ ├── upsert_k:18 => k:38 + │ ├── upsert_v:19 => v:39 + │ ├── column2:8 => w:40 + │ ├── column3:9 => x:41 + │ └── upsert_y:20 => y:42 ├── scan uniq - │ └── columns: uniq.k:32!null uniq.x:35 uniq.y:36 + │ └── columns: uniq.k:32!null uniq.v:33 uniq.w:34 uniq.x:35 uniq.y:36 └── filters - ├── x:29 = uniq.x:35 - ├── y:30 = uniq.y:36 - └── k:31 != uniq.k:32 + ├── x:41 = uniq.x:35 + ├── y:42 = uniq.y:36 + └── k:38 != uniq.k:32 # Upsert with non-constant input. # TODO(rytaft): The default value for x is NULL, and we're not updating either @@ -314,32 +329,37 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:23!null k:24 + │ ├── columns: k:29 v:30 w:31!null x:32 y:33!null │ ├── with-scan &1 - │ │ ├── columns: w:23!null k:24 + │ │ ├── columns: k:29 v:30 w:31!null x:32 y:33!null │ │ └── mapping: - │ │ ├── other.w:9 => w:23 - │ │ └── upsert_k:22 => k:24 + │ │ ├── upsert_k:22 => k:29 + │ │ ├── other.v:8 => v:30 + │ │ ├── other.w:9 => w:31 + │ │ ├── column14:14 => x:32 + │ │ └── column15:15 => y:33 │ ├── scan uniq - │ │ └── columns: uniq.k:25!null uniq.w:27 + │ │ └── columns: uniq.k:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 │ └── filters - │ ├── w:23 = uniq.w:27 - │ └── k:24 != uniq.k:25 + │ ├── w:31 = uniq.w:25 + │ └── k:29 != uniq.k:23 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:31 y:32!null k:33 + ├── columns: k:40 v:41 w:42!null x:43 y:44!null ├── with-scan &1 - │ ├── columns: x:31 y:32!null k:33 + │ ├── columns: k:40 v:41 w:42!null x:43 y:44!null │ └── mapping: - │ ├── column14:14 => x:31 - │ ├── column15:15 => y:32 - │ └── upsert_k:22 => k:33 + │ ├── upsert_k:22 => k:40 + │ ├── other.v:8 => v:41 + │ ├── other.w:9 => w:42 + │ ├── column14:14 => x:43 + │ └── column15:15 => y:44 ├── scan uniq - │ └── columns: uniq.k:34!null uniq.x:37 uniq.y:38 + │ └── columns: uniq.k:34!null uniq.v:35 uniq.w:36 uniq.x:37 uniq.y:38 └── filters - ├── x:31 = uniq.x:37 - ├── y:32 = uniq.y:38 - └── k:33 != uniq.k:34 + ├── x:43 = uniq.x:37 + ├── y:44 = uniq.y:38 + └── k:40 != uniq.k:34 # On conflict do update with constant input. # TODO(rytaft): The default value for x is NULL, and we're not updating either @@ -352,10 +372,10 @@ upsert uniq ├── columns: ├── arbiter indexes: primary ├── canary column: uniq.k:11 - ├── fetch columns: uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 + ├── fetch columns: uniq.k:11 uniq.v:12 uniq.w:13 uniq.x:14 uniq.y:15 ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column9:9 => uniq.w:3 │ ├── column9:9 => uniq.x:4 │ └── column10:10 => uniq.y:5 @@ -363,11 +383,11 @@ upsert uniq │ └── upsert_w:20 => uniq.w:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:18 upsert_v:19 upsert_w:20 upsert_x:21 upsert_y:22 column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 w_new:17 + │ ├── columns: upsert_k:18 upsert_v:19 upsert_w:20 upsert_x:21 upsert_y:22 column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 uniq.v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 w_new:17 │ ├── project - │ │ ├── columns: w_new:17 column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 + │ │ ├── columns: w_new:17 column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 uniq.v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 + │ │ │ ├── columns: column1:7!null column2:8!null column9:9 column10:10!null uniq.k:11 uniq.v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column9:9 column10:10!null │ │ │ │ ├── grouping columns: column1:7!null @@ -388,46 +408,51 @@ upsert uniq │ │ │ │ └── first-agg [as=column10:10] │ │ │ │ └── column10:10 │ │ │ ├── scan uniq - │ │ │ │ └── columns: uniq.k:11!null v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 + │ │ │ │ └── columns: uniq.k:11!null uniq.v:12 uniq.w:13 uniq.x:14 uniq.y:15 crdb_internal_mvcc_timestamp:16 │ │ │ └── filters │ │ │ └── column1:7 = uniq.k:11 │ │ └── projections │ │ └── column9:9 + 1 [as=w_new:17] │ └── projections │ ├── CASE WHEN uniq.k:11 IS NULL THEN column1:7 ELSE uniq.k:11 END [as=upsert_k:18] - │ ├── CASE WHEN uniq.k:11 IS NULL THEN column2:8 ELSE v:12 END [as=upsert_v:19] + │ ├── CASE WHEN uniq.k:11 IS NULL THEN column2:8 ELSE uniq.v:12 END [as=upsert_v:19] │ ├── CASE WHEN uniq.k:11 IS NULL THEN column9:9 ELSE w_new:17 END [as=upsert_w:20] │ ├── CASE WHEN uniq.k:11 IS NULL THEN column9:9 ELSE uniq.x:14 END [as=upsert_x:21] │ └── CASE WHEN uniq.k:11 IS NULL THEN column10:10 ELSE uniq.y:15 END [as=upsert_y:22] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:23 k:24 + │ ├── columns: k:29 v:30 w:31 x:32 y:33 │ ├── with-scan &1 - │ │ ├── columns: w:23 k:24 + │ │ ├── columns: k:29 v:30 w:31 x:32 y:33 │ │ └── mapping: - │ │ ├── upsert_w:20 => w:23 - │ │ └── upsert_k:18 => k:24 + │ │ ├── upsert_k:18 => k:29 + │ │ ├── upsert_v:19 => v:30 + │ │ ├── upsert_w:20 => w:31 + │ │ ├── upsert_x:21 => x:32 + │ │ └── upsert_y:22 => y:33 │ ├── scan uniq - │ │ └── columns: uniq.k:25!null uniq.w:27 + │ │ └── columns: uniq.k:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 │ └── filters - │ ├── w:23 = uniq.w:27 - │ └── k:24 != uniq.k:25 + │ ├── w:31 = uniq.w:25 + │ └── k:29 != uniq.k:23 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:31 y:32 k:33 + ├── columns: k:40 v:41 w:42 x:43 y:44 ├── with-scan &1 - │ ├── columns: x:31 y:32 k:33 + │ ├── columns: k:40 v:41 w:42 x:43 y:44 │ └── mapping: - │ ├── upsert_x:21 => x:31 - │ ├── upsert_y:22 => y:32 - │ └── upsert_k:18 => k:33 + │ ├── upsert_k:18 => k:40 + │ ├── upsert_v:19 => v:41 + │ ├── upsert_w:20 => w:42 + │ ├── upsert_x:21 => x:43 + │ └── upsert_y:22 => y:44 ├── scan uniq - │ └── columns: uniq.k:34!null uniq.x:37 uniq.y:38 + │ └── columns: uniq.k:34!null uniq.v:35 uniq.w:36 uniq.x:37 uniq.y:38 └── filters - ├── x:31 = uniq.x:37 - ├── y:32 = uniq.y:38 - └── k:33 != uniq.k:34 + ├── x:43 = uniq.x:37 + ├── y:44 = uniq.y:38 + └── k:40 != uniq.k:34 # On conflict do update with non-constant input. # TODO(rytaft): The default value for x is NULL, and we're not updating either @@ -489,32 +514,37 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:28 k:29 + │ ├── columns: k:34 v:35 w:36 x:37 y:38 │ ├── with-scan &1 - │ │ ├── columns: w:28 k:29 + │ │ ├── columns: k:34 v:35 w:36 x:37 y:38 │ │ └── mapping: - │ │ ├── upsert_w:25 => w:28 - │ │ └── upsert_k:23 => k:29 + │ │ ├── upsert_k:23 => k:34 + │ │ ├── upsert_v:24 => v:35 + │ │ ├── upsert_w:25 => w:36 + │ │ ├── upsert_x:26 => x:37 + │ │ └── upsert_y:27 => y:38 │ ├── scan uniq - │ │ └── columns: uniq.k:30!null uniq.w:32 + │ │ └── columns: uniq.k:28!null uniq.v:29 uniq.w:30 uniq.x:31 uniq.y:32 │ └── filters - │ ├── w:28 = uniq.w:32 - │ └── k:29 != uniq.k:30 + │ ├── w:36 = uniq.w:30 + │ └── k:34 != uniq.k:28 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:36 y:37 k:38 + ├── columns: k:45 v:46 w:47 x:48 y:49 ├── with-scan &1 - │ ├── columns: x:36 y:37 k:38 + │ ├── columns: k:45 v:46 w:47 x:48 y:49 │ └── mapping: - │ ├── upsert_x:26 => x:36 - │ ├── upsert_y:27 => y:37 - │ └── upsert_k:23 => k:38 + │ ├── upsert_k:23 => k:45 + │ ├── upsert_v:24 => v:46 + │ ├── upsert_w:25 => w:47 + │ ├── upsert_x:26 => x:48 + │ └── upsert_y:27 => y:49 ├── scan uniq - │ └── columns: uniq.k:39!null uniq.x:42 uniq.y:43 + │ └── columns: uniq.k:39!null uniq.v:40 uniq.w:41 uniq.x:42 uniq.y:43 └── filters - ├── x:36 = uniq.x:42 - ├── y:37 = uniq.y:43 - └── k:38 != uniq.k:39 + ├── x:48 = uniq.x:42 + ├── y:49 = uniq.y:43 + └── k:45 != uniq.k:39 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # column. @@ -525,10 +555,10 @@ upsert uniq ├── columns: ├── arbiter constraints: unique_w ├── canary column: uniq.k:12 - ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 + ├── fetch columns: uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column10:10 => uniq.x:4 │ └── column11:11 => uniq.y:5 @@ -536,11 +566,11 @@ upsert uniq │ └── upsert_w:21 => uniq.w:3 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:19 upsert_v:20 upsert_w:21!null upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 w_new:18!null + │ ├── columns: upsert_k:19 upsert_v:20 upsert_w:21!null upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 w_new:18!null │ ├── project - │ │ ├── columns: w_new:18!null column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: w_new:18!null column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column10:10 column11:11!null │ │ │ │ ├── grouping columns: column3:9!null @@ -563,46 +593,51 @@ upsert uniq │ │ │ │ └── first-agg [as=column11:11] │ │ │ │ └── column11:11 │ │ │ ├── scan uniq - │ │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ └── filters │ │ │ └── column3:9 = uniq.w:14 │ │ └── projections │ │ └── 10 [as=w_new:18] │ └── projections │ ├── CASE WHEN uniq.k:12 IS NULL THEN column1:7 ELSE uniq.k:12 END [as=upsert_k:19] - │ ├── CASE WHEN uniq.k:12 IS NULL THEN column2:8 ELSE v:13 END [as=upsert_v:20] + │ ├── CASE WHEN uniq.k:12 IS NULL THEN column2:8 ELSE uniq.v:13 END [as=upsert_v:20] │ ├── CASE WHEN uniq.k:12 IS NULL THEN column3:9 ELSE w_new:18 END [as=upsert_w:21] │ ├── CASE WHEN uniq.k:12 IS NULL THEN column10:10 ELSE uniq.x:15 END [as=upsert_x:22] │ └── CASE WHEN uniq.k:12 IS NULL THEN column11:11 ELSE uniq.y:16 END [as=upsert_y:23] └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:24!null k:25 + │ ├── columns: k:30 v:31 w:32!null x:33 y:34 │ ├── with-scan &1 - │ │ ├── columns: w:24!null k:25 + │ │ ├── columns: k:30 v:31 w:32!null x:33 y:34 │ │ └── mapping: - │ │ ├── upsert_w:21 => w:24 - │ │ └── upsert_k:19 => k:25 + │ │ ├── upsert_k:19 => k:30 + │ │ ├── upsert_v:20 => v:31 + │ │ ├── upsert_w:21 => w:32 + │ │ ├── upsert_x:22 => x:33 + │ │ └── upsert_y:23 => y:34 │ ├── scan uniq - │ │ └── columns: uniq.k:26!null uniq.w:28 + │ │ └── columns: uniq.k:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 │ └── filters - │ ├── w:24 = uniq.w:28 - │ └── k:25 != uniq.k:26 + │ ├── w:32 = uniq.w:26 + │ └── k:30 != uniq.k:24 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:32 y:33 k:34 + ├── columns: k:41 v:42 w:43!null x:44 y:45 ├── with-scan &1 - │ ├── columns: x:32 y:33 k:34 + │ ├── columns: k:41 v:42 w:43!null x:44 y:45 │ └── mapping: - │ ├── upsert_x:22 => x:32 - │ ├── upsert_y:23 => y:33 - │ └── upsert_k:19 => k:34 + │ ├── upsert_k:19 => k:41 + │ ├── upsert_v:20 => v:42 + │ ├── upsert_w:21 => w:43 + │ ├── upsert_x:22 => x:44 + │ └── upsert_y:23 => y:45 ├── scan uniq - │ └── columns: uniq.k:35!null uniq.x:38 uniq.y:39 + │ └── columns: uniq.k:35!null uniq.v:36 uniq.w:37 uniq.x:38 uniq.y:39 └── filters - ├── x:32 = uniq.x:38 - ├── y:33 = uniq.y:39 - └── k:34 != uniq.k:35 + ├── x:44 = uniq.x:38 + ├── y:45 = uniq.y:39 + └── k:41 != uniq.k:35 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -613,22 +648,22 @@ upsert uniq ├── columns: ├── arbiter constraints: unique_x_y ├── canary column: uniq.k:12 - ├── fetch columns: uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 + ├── fetch columns: uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 ├── insert-mapping: │ ├── column1:7 => uniq.k:1 - │ ├── column2:8 => v:2 + │ ├── column2:8 => uniq.v:2 │ ├── column3:9 => uniq.w:3 │ ├── column4:10 => uniq.x:4 │ └── column5:11 => uniq.y:5 ├── update-mapping: - │ └── upsert_v:20 => v:2 + │ └── upsert_v:20 => uniq.v:2 ├── input binding: &1 ├── project - │ ├── columns: upsert_k:19 upsert_v:20!null upsert_w:21 upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 v_new:18!null + │ ├── columns: upsert_k:19 upsert_v:20!null upsert_w:21 upsert_x:22 upsert_y:23 column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 v_new:18!null │ ├── project - │ │ ├── columns: v_new:18!null column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ ├── columns: v_new:18!null column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ ├── left-join (hash) - │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null uniq.k:12 uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ ├── ensure-upsert-distinct-on │ │ │ │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null column5:11!null │ │ │ │ ├── grouping columns: column4:10!null column5:11!null @@ -643,7 +678,7 @@ upsert uniq │ │ │ │ └── first-agg [as=column3:9] │ │ │ │ └── column3:9 │ │ │ ├── scan uniq - │ │ │ │ └── columns: uniq.k:12!null v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 + │ │ │ │ └── columns: uniq.k:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 crdb_internal_mvcc_timestamp:17 │ │ │ └── filters │ │ │ ├── column4:10 = uniq.x:15 │ │ │ └── column5:11 = uniq.y:16 @@ -658,32 +693,37 @@ upsert uniq └── unique-checks ├── unique-checks-item: uniq(w) │ └── semi-join (hash) - │ ├── columns: w:24 k:25 + │ ├── columns: k:30 v:31!null w:32 x:33 y:34 │ ├── with-scan &1 - │ │ ├── columns: w:24 k:25 + │ │ ├── columns: k:30 v:31!null w:32 x:33 y:34 │ │ └── mapping: - │ │ ├── upsert_w:21 => w:24 - │ │ └── upsert_k:19 => k:25 + │ │ ├── upsert_k:19 => k:30 + │ │ ├── upsert_v:20 => v:31 + │ │ ├── upsert_w:21 => w:32 + │ │ ├── upsert_x:22 => x:33 + │ │ └── upsert_y:23 => y:34 │ ├── scan uniq - │ │ └── columns: uniq.k:26!null uniq.w:28 + │ │ └── columns: uniq.k:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 │ └── filters - │ ├── w:24 = uniq.w:28 - │ └── k:25 != uniq.k:26 + │ ├── w:32 = uniq.w:26 + │ └── k:30 != uniq.k:24 └── unique-checks-item: uniq(x,y) └── semi-join (hash) - ├── columns: x:32 y:33 k:34 + ├── columns: k:41 v:42!null w:43 x:44 y:45 ├── with-scan &1 - │ ├── columns: x:32 y:33 k:34 + │ ├── columns: k:41 v:42!null w:43 x:44 y:45 │ └── mapping: - │ ├── upsert_x:22 => x:32 - │ ├── upsert_y:23 => y:33 - │ └── upsert_k:19 => k:34 + │ ├── upsert_k:19 => k:41 + │ ├── upsert_v:20 => v:42 + │ ├── upsert_w:21 => w:43 + │ ├── upsert_x:22 => x:44 + │ └── upsert_y:23 => y:45 ├── scan uniq - │ └── columns: uniq.k:35!null uniq.x:38 uniq.y:39 + │ └── columns: uniq.k:35!null uniq.v:36 uniq.w:37 uniq.x:38 uniq.y:39 └── filters - ├── x:32 = uniq.x:38 - ├── y:33 = uniq.y:39 - └── k:34 != uniq.k:35 + ├── x:44 = uniq.x:38 + ├── y:45 = uniq.y:39 + └── k:41 != uniq.k:35 # Cannot conflict on a subset of columns in a unique constraint. build @@ -732,48 +772,51 @@ upsert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:10!null c:11!null a:12!null + │ ├── columns: a:15!null b:16!null c:17!null d:18!null │ ├── with-scan &1 - │ │ ├── columns: b:10!null c:11!null a:12!null + │ │ ├── columns: a:15!null b:16!null c:17!null d:18!null │ │ └── mapping: - │ │ ├── column2:7 => b:10 - │ │ ├── column3:8 => c:11 - │ │ └── column1:6 => a:12 + │ │ ├── column1:6 => a:15 + │ │ ├── column2:7 => b:16 + │ │ ├── column3:8 => c:17 + │ │ └── column4:9 => d:18 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:13!null uniq_overlaps_pk.b:14!null uniq_overlaps_pk.c:15 + │ │ └── columns: uniq_overlaps_pk.a:10!null uniq_overlaps_pk.b:11!null uniq_overlaps_pk.c:12 uniq_overlaps_pk.d:13 │ └── filters - │ ├── b:10 = uniq_overlaps_pk.b:14 - │ ├── c:11 = uniq_overlaps_pk.c:15 - │ └── a:12 != uniq_overlaps_pk.a:13 + │ ├── b:16 = uniq_overlaps_pk.b:11 + │ ├── c:17 = uniq_overlaps_pk.c:12 + │ └── a:15 != uniq_overlaps_pk.a:10 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:18!null b:19!null + │ ├── columns: a:24!null b:25!null c:26!null d:27!null │ ├── with-scan &1 - │ │ ├── columns: a:18!null b:19!null + │ │ ├── columns: a:24!null b:25!null c:26!null d:27!null │ │ └── mapping: - │ │ ├── column1:6 => a:18 - │ │ └── column2:7 => b:19 + │ │ ├── column1:6 => a:24 + │ │ ├── column2:7 => b:25 + │ │ ├── column3:8 => c:26 + │ │ └── column4:9 => d:27 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null + │ │ └── columns: uniq_overlaps_pk.a:19!null uniq_overlaps_pk.b:20!null uniq_overlaps_pk.c:21 uniq_overlaps_pk.d:22 │ └── filters - │ ├── a:18 = uniq_overlaps_pk.a:20 - │ └── b:19 != uniq_overlaps_pk.b:21 + │ ├── a:24 = uniq_overlaps_pk.a:19 + │ └── b:25 != uniq_overlaps_pk.b:20 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:25!null d:26!null a:27!null b:28!null + ├── columns: a:33!null b:34!null c:35!null d:36!null ├── with-scan &1 - │ ├── columns: c:25!null d:26!null a:27!null b:28!null + │ ├── columns: a:33!null b:34!null c:35!null d:36!null │ └── mapping: - │ ├── column3:8 => c:25 - │ ├── column4:9 => d:26 - │ ├── column1:6 => a:27 - │ └── column2:7 => b:28 + │ ├── column1:6 => a:33 + │ ├── column2:7 => b:34 + │ ├── column3:8 => c:35 + │ └── column4:9 => d:36 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 + │ └── columns: uniq_overlaps_pk.a:28!null uniq_overlaps_pk.b:29!null uniq_overlaps_pk.c:30 uniq_overlaps_pk.d:31 └── filters - ├── c:25 = uniq_overlaps_pk.c:31 - ├── d:26 = uniq_overlaps_pk.d:32 - └── (a:27 != uniq_overlaps_pk.a:29) OR (b:28 != uniq_overlaps_pk.b:30) + ├── c:35 = uniq_overlaps_pk.c:30 + ├── d:36 = uniq_overlaps_pk.d:31 + └── (a:33 != uniq_overlaps_pk.a:28) OR (b:34 != uniq_overlaps_pk.b:29) # Upsert with non-constant input. # Add inequality filters for the primary key columns that are not part of each @@ -788,7 +831,7 @@ upsert uniq_overlaps_pk │ ├── k:6 => uniq_overlaps_pk.a:1 │ ├── v:7 => uniq_overlaps_pk.b:2 │ ├── x:9 => uniq_overlaps_pk.c:3 - │ └── column13:13 => d:4 + │ └── column13:13 => uniq_overlaps_pk.d:4 ├── input binding: &1 ├── project │ ├── columns: column13:13 k:6 v:7 x:9 @@ -801,32 +844,35 @@ upsert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:14 c:15 a:16 + │ ├── columns: a:19 b:20 c:21 d:22 │ ├── with-scan &1 - │ │ ├── columns: b:14 c:15 a:16 + │ │ ├── columns: a:19 b:20 c:21 d:22 │ │ └── mapping: - │ │ ├── v:7 => b:14 - │ │ ├── x:9 => c:15 - │ │ └── k:6 => a:16 + │ │ ├── k:6 => a:19 + │ │ ├── v:7 => b:20 + │ │ ├── x:9 => c:21 + │ │ └── column13:13 => d:22 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:17!null uniq_overlaps_pk.b:18!null uniq_overlaps_pk.c:19 + │ │ └── columns: uniq_overlaps_pk.a:14!null uniq_overlaps_pk.b:15!null uniq_overlaps_pk.c:16 uniq_overlaps_pk.d:17 │ └── filters - │ ├── b:14 = uniq_overlaps_pk.b:18 - │ ├── c:15 = uniq_overlaps_pk.c:19 - │ └── a:16 != uniq_overlaps_pk.a:17 + │ ├── b:20 = uniq_overlaps_pk.b:15 + │ ├── c:21 = uniq_overlaps_pk.c:16 + │ └── a:19 != uniq_overlaps_pk.a:14 └── unique-checks-item: uniq_overlaps_pk(a) └── semi-join (hash) - ├── columns: a:22 b:23 + ├── columns: a:28 b:29 c:30 d:31 ├── with-scan &1 - │ ├── columns: a:22 b:23 + │ ├── columns: a:28 b:29 c:30 d:31 │ └── mapping: - │ ├── k:6 => a:22 - │ └── v:7 => b:23 + │ ├── k:6 => a:28 + │ ├── v:7 => b:29 + │ ├── x:9 => c:30 + │ └── column13:13 => d:31 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:24!null uniq_overlaps_pk.b:25!null + │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 uniq_overlaps_pk.d:26 └── filters - ├── a:22 = uniq_overlaps_pk.a:24 - └── b:23 != uniq_overlaps_pk.b:25 + ├── a:28 = uniq_overlaps_pk.a:23 + └── b:29 != uniq_overlaps_pk.b:24 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # column. @@ -880,48 +926,51 @@ upsert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:20 c:21 a:22!null + │ ├── columns: a:25!null b:26 c:27 d:28 │ ├── with-scan &1 - │ │ ├── columns: b:20 c:21 a:22!null + │ │ ├── columns: a:25!null b:26 c:27 d:28 │ │ └── mapping: - │ │ ├── upsert_b:17 => b:20 - │ │ ├── upsert_c:18 => c:21 - │ │ └── upsert_a:16 => a:22 + │ │ ├── upsert_a:16 => a:25 + │ │ ├── upsert_b:17 => b:26 + │ │ ├── upsert_c:18 => c:27 + │ │ └── upsert_d:19 => d:28 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 + │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null uniq_overlaps_pk.c:22 uniq_overlaps_pk.d:23 │ └── filters - │ ├── b:20 = uniq_overlaps_pk.b:24 - │ ├── c:21 = uniq_overlaps_pk.c:25 - │ └── a:22 != uniq_overlaps_pk.a:23 + │ ├── b:26 = uniq_overlaps_pk.b:21 + │ ├── c:27 = uniq_overlaps_pk.c:22 + │ └── a:25 != uniq_overlaps_pk.a:20 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:28!null b:29 + │ ├── columns: a:34!null b:35 c:36 d:37 │ ├── with-scan &1 - │ │ ├── columns: a:28!null b:29 + │ │ ├── columns: a:34!null b:35 c:36 d:37 │ │ └── mapping: - │ │ ├── upsert_a:16 => a:28 - │ │ └── upsert_b:17 => b:29 + │ │ ├── upsert_a:16 => a:34 + │ │ ├── upsert_b:17 => b:35 + │ │ ├── upsert_c:18 => c:36 + │ │ └── upsert_d:19 => d:37 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:30!null uniq_overlaps_pk.b:31!null + │ │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 │ └── filters - │ ├── a:28 = uniq_overlaps_pk.a:30 - │ └── b:29 != uniq_overlaps_pk.b:31 + │ ├── a:34 = uniq_overlaps_pk.a:29 + │ └── b:35 != uniq_overlaps_pk.b:30 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:35 d:36 a:37!null b:38 + ├── columns: a:43!null b:44 c:45 d:46 ├── with-scan &1 - │ ├── columns: c:35 d:36 a:37!null b:38 + │ ├── columns: a:43!null b:44 c:45 d:46 │ └── mapping: - │ ├── upsert_c:18 => c:35 - │ ├── upsert_d:19 => d:36 - │ ├── upsert_a:16 => a:37 - │ └── upsert_b:17 => b:38 + │ ├── upsert_a:16 => a:43 + │ ├── upsert_b:17 => b:44 + │ ├── upsert_c:18 => c:45 + │ └── upsert_d:19 => d:46 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:39!null uniq_overlaps_pk.b:40!null uniq_overlaps_pk.c:41 uniq_overlaps_pk.d:42 + │ └── columns: uniq_overlaps_pk.a:38!null uniq_overlaps_pk.b:39!null uniq_overlaps_pk.c:40 uniq_overlaps_pk.d:41 └── filters - ├── c:35 = uniq_overlaps_pk.c:41 - ├── d:36 = uniq_overlaps_pk.d:42 - └── (a:37 != uniq_overlaps_pk.a:39) OR (b:38 != uniq_overlaps_pk.b:40) + ├── c:45 = uniq_overlaps_pk.c:40 + ├── d:46 = uniq_overlaps_pk.d:41 + └── (a:43 != uniq_overlaps_pk.a:38) OR (b:44 != uniq_overlaps_pk.b:39) # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -973,48 +1022,51 @@ upsert uniq_overlaps_pk └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:20!null c:21 a:22 + │ ├── columns: a:25 b:26!null c:27 d:28 │ ├── with-scan &1 - │ │ ├── columns: b:20!null c:21 a:22 + │ │ ├── columns: a:25 b:26!null c:27 d:28 │ │ └── mapping: - │ │ ├── upsert_b:17 => b:20 - │ │ ├── upsert_c:18 => c:21 - │ │ └── upsert_a:16 => a:22 + │ │ ├── upsert_a:16 => a:25 + │ │ ├── upsert_b:17 => b:26 + │ │ ├── upsert_c:18 => c:27 + │ │ └── upsert_d:19 => d:28 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 + │ │ └── columns: uniq_overlaps_pk.a:20!null uniq_overlaps_pk.b:21!null uniq_overlaps_pk.c:22 uniq_overlaps_pk.d:23 │ └── filters - │ ├── b:20 = uniq_overlaps_pk.b:24 - │ ├── c:21 = uniq_overlaps_pk.c:25 - │ └── a:22 != uniq_overlaps_pk.a:23 + │ ├── b:26 = uniq_overlaps_pk.b:21 + │ ├── c:27 = uniq_overlaps_pk.c:22 + │ └── a:25 != uniq_overlaps_pk.a:20 ├── unique-checks-item: uniq_overlaps_pk(a) │ └── semi-join (hash) - │ ├── columns: a:28 b:29!null + │ ├── columns: a:34 b:35!null c:36 d:37 │ ├── with-scan &1 - │ │ ├── columns: a:28 b:29!null + │ │ ├── columns: a:34 b:35!null c:36 d:37 │ │ └── mapping: - │ │ ├── upsert_a:16 => a:28 - │ │ └── upsert_b:17 => b:29 + │ │ ├── upsert_a:16 => a:34 + │ │ ├── upsert_b:17 => b:35 + │ │ ├── upsert_c:18 => c:36 + │ │ └── upsert_d:19 => d:37 │ ├── scan uniq_overlaps_pk - │ │ └── columns: uniq_overlaps_pk.a:30!null uniq_overlaps_pk.b:31!null + │ │ └── columns: uniq_overlaps_pk.a:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 │ └── filters - │ ├── a:28 = uniq_overlaps_pk.a:30 - │ └── b:29 != uniq_overlaps_pk.b:31 + │ ├── a:34 = uniq_overlaps_pk.a:29 + │ └── b:35 != uniq_overlaps_pk.b:30 └── unique-checks-item: uniq_overlaps_pk(c,d) └── semi-join (hash) - ├── columns: c:35 d:36 a:37 b:38!null + ├── columns: a:43 b:44!null c:45 d:46 ├── with-scan &1 - │ ├── columns: c:35 d:36 a:37 b:38!null + │ ├── columns: a:43 b:44!null c:45 d:46 │ └── mapping: - │ ├── upsert_c:18 => c:35 - │ ├── upsert_d:19 => d:36 - │ ├── upsert_a:16 => a:37 - │ └── upsert_b:17 => b:38 + │ ├── upsert_a:16 => a:43 + │ ├── upsert_b:17 => b:44 + │ ├── upsert_c:18 => c:45 + │ └── upsert_d:19 => d:46 ├── scan uniq_overlaps_pk - │ └── columns: uniq_overlaps_pk.a:39!null uniq_overlaps_pk.b:40!null uniq_overlaps_pk.c:41 uniq_overlaps_pk.d:42 + │ └── columns: uniq_overlaps_pk.a:38!null uniq_overlaps_pk.b:39!null uniq_overlaps_pk.c:40 uniq_overlaps_pk.d:41 └── filters - ├── c:35 = uniq_overlaps_pk.c:41 - ├── d:36 = uniq_overlaps_pk.d:42 - └── (a:37 != uniq_overlaps_pk.a:39) OR (b:38 != uniq_overlaps_pk.b:40) + ├── c:45 = uniq_overlaps_pk.c:40 + ├── d:46 = uniq_overlaps_pk.d:41 + └── (a:43 != uniq_overlaps_pk.a:38) OR (b:44 != uniq_overlaps_pk.b:39) exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -1084,49 +1136,55 @@ upsert uniq_hidden_pk └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:20!null c:21 rowid:22 + │ ├── columns: a:26!null b:27!null c:28 d:29!null rowid:30 │ ├── with-scan &1 - │ │ ├── columns: b:20!null c:21 rowid:22 + │ │ ├── columns: a:26!null b:27!null c:28 d:29!null rowid:30 │ │ └── mapping: - │ │ ├── column2:8 => b:20 - │ │ ├── upsert_c:18 => c:21 - │ │ └── upsert_rowid:19 => rowid:22 + │ │ ├── column1:7 => a:26 + │ │ ├── column2:8 => b:27 + │ │ ├── upsert_c:18 => c:28 + │ │ ├── column3:9 => d:29 + │ │ └── upsert_rowid:19 => rowid:30 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.b:24 uniq_hidden_pk.c:25 uniq_hidden_pk.rowid:27!null + │ │ └── columns: uniq_hidden_pk.a:20 uniq_hidden_pk.b:21 uniq_hidden_pk.c:22 uniq_hidden_pk.d:23 uniq_hidden_pk.rowid:24!null │ └── filters - │ ├── b:20 = uniq_hidden_pk.b:24 - │ ├── c:21 = uniq_hidden_pk.c:25 - │ └── rowid:22 != uniq_hidden_pk.rowid:27 + │ ├── b:27 = uniq_hidden_pk.b:21 + │ ├── c:28 = uniq_hidden_pk.c:22 + │ └── rowid:30 != uniq_hidden_pk.rowid:24 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:29!null b:30!null d:31!null rowid:32 + │ ├── columns: a:37!null b:38!null c:39 d:40!null rowid:41 │ ├── with-scan &1 - │ │ ├── columns: a:29!null b:30!null d:31!null rowid:32 + │ │ ├── columns: a:37!null b:38!null c:39 d:40!null rowid:41 │ │ └── mapping: - │ │ ├── column1:7 => a:29 - │ │ ├── column2:8 => b:30 - │ │ ├── column3:9 => d:31 - │ │ └── upsert_rowid:19 => rowid:32 + │ │ ├── column1:7 => a:37 + │ │ ├── column2:8 => b:38 + │ │ ├── upsert_c:18 => c:39 + │ │ ├── column3:9 => d:40 + │ │ └── upsert_rowid:19 => rowid:41 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:33 uniq_hidden_pk.b:34 uniq_hidden_pk.d:36 uniq_hidden_pk.rowid:37!null + │ │ └── columns: uniq_hidden_pk.a:31 uniq_hidden_pk.b:32 uniq_hidden_pk.c:33 uniq_hidden_pk.d:34 uniq_hidden_pk.rowid:35!null │ └── filters - │ ├── a:29 = uniq_hidden_pk.a:33 - │ ├── b:30 = uniq_hidden_pk.b:34 - │ ├── d:31 = uniq_hidden_pk.d:36 - │ └── rowid:32 != uniq_hidden_pk.rowid:37 + │ ├── a:37 = uniq_hidden_pk.a:31 + │ ├── b:38 = uniq_hidden_pk.b:32 + │ ├── d:40 = uniq_hidden_pk.d:34 + │ └── rowid:41 != uniq_hidden_pk.rowid:35 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:39!null rowid:40 + ├── columns: a:48!null b:49!null c:50 d:51!null rowid:52 ├── with-scan &1 - │ ├── columns: a:39!null rowid:40 + │ ├── columns: a:48!null b:49!null c:50 d:51!null rowid:52 │ └── mapping: - │ ├── column1:7 => a:39 - │ └── upsert_rowid:19 => rowid:40 + │ ├── column1:7 => a:48 + │ ├── column2:8 => b:49 + │ ├── upsert_c:18 => c:50 + │ ├── column3:9 => d:51 + │ └── upsert_rowid:19 => rowid:52 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:41 uniq_hidden_pk.rowid:45!null + │ └── columns: uniq_hidden_pk.a:42 uniq_hidden_pk.b:43 uniq_hidden_pk.c:44 uniq_hidden_pk.d:45 uniq_hidden_pk.rowid:46!null └── filters - ├── a:39 = uniq_hidden_pk.a:41 - └── rowid:40 != uniq_hidden_pk.rowid:45 + ├── a:48 = uniq_hidden_pk.a:42 + └── rowid:52 != uniq_hidden_pk.rowid:46 # Upsert with non-constant input. # Add inequality filters for the hidden primary key column. @@ -1153,49 +1211,55 @@ upsert uniq_hidden_pk └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:15 c:16 rowid:17 + │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 │ ├── with-scan &1 - │ │ ├── columns: b:15 c:16 rowid:17 + │ │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 │ │ └── mapping: - │ │ ├── v:8 => b:15 - │ │ ├── x:10 => c:16 - │ │ └── column14:14 => rowid:17 + │ │ ├── k:7 => a:21 + │ │ ├── v:8 => b:22 + │ │ ├── x:10 => c:23 + │ │ ├── y:11 => d:24 + │ │ └── column14:14 => rowid:25 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.b:19 uniq_hidden_pk.c:20 uniq_hidden_pk.rowid:22!null + │ │ └── columns: uniq_hidden_pk.a:15 uniq_hidden_pk.b:16 uniq_hidden_pk.c:17 uniq_hidden_pk.d:18 uniq_hidden_pk.rowid:19!null │ └── filters - │ ├── b:15 = uniq_hidden_pk.b:19 - │ ├── c:16 = uniq_hidden_pk.c:20 - │ └── rowid:17 != uniq_hidden_pk.rowid:22 + │ ├── b:22 = uniq_hidden_pk.b:16 + │ ├── c:23 = uniq_hidden_pk.c:17 + │ └── rowid:25 != uniq_hidden_pk.rowid:19 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:24 b:25 d:26 rowid:27 + │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 │ ├── with-scan &1 - │ │ ├── columns: a:24 b:25 d:26 rowid:27 + │ │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 │ │ └── mapping: - │ │ ├── k:7 => a:24 - │ │ ├── v:8 => b:25 - │ │ ├── y:11 => d:26 - │ │ └── column14:14 => rowid:27 + │ │ ├── k:7 => a:32 + │ │ ├── v:8 => b:33 + │ │ ├── x:10 => c:34 + │ │ ├── y:11 => d:35 + │ │ └── column14:14 => rowid:36 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:28 uniq_hidden_pk.b:29 uniq_hidden_pk.d:31 uniq_hidden_pk.rowid:32!null + │ │ └── columns: uniq_hidden_pk.a:26 uniq_hidden_pk.b:27 uniq_hidden_pk.c:28 uniq_hidden_pk.d:29 uniq_hidden_pk.rowid:30!null │ └── filters - │ ├── a:24 = uniq_hidden_pk.a:28 - │ ├── b:25 = uniq_hidden_pk.b:29 - │ ├── d:26 = uniq_hidden_pk.d:31 - │ └── rowid:27 != uniq_hidden_pk.rowid:32 + │ ├── a:32 = uniq_hidden_pk.a:26 + │ ├── b:33 = uniq_hidden_pk.b:27 + │ ├── d:35 = uniq_hidden_pk.d:29 + │ └── rowid:36 != uniq_hidden_pk.rowid:30 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:34 rowid:35 + ├── columns: a:43 b:44 c:45 d:46 rowid:47 ├── with-scan &1 - │ ├── columns: a:34 rowid:35 + │ ├── columns: a:43 b:44 c:45 d:46 rowid:47 │ └── mapping: - │ ├── k:7 => a:34 - │ └── column14:14 => rowid:35 + │ ├── k:7 => a:43 + │ ├── v:8 => b:44 + │ ├── x:10 => c:45 + │ ├── y:11 => d:46 + │ └── column14:14 => rowid:47 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:36 uniq_hidden_pk.rowid:40!null + │ └── columns: uniq_hidden_pk.a:37 uniq_hidden_pk.b:38 uniq_hidden_pk.c:39 uniq_hidden_pk.d:40 uniq_hidden_pk.rowid:41!null └── filters - ├── a:34 = uniq_hidden_pk.a:36 - └── rowid:35 != uniq_hidden_pk.rowid:40 + ├── a:43 = uniq_hidden_pk.a:37 + └── rowid:47 != uniq_hidden_pk.rowid:41 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -1254,49 +1318,55 @@ upsert uniq_hidden_pk └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) │ └── semi-join (hash) - │ ├── columns: b:24 c:25 rowid:26 + │ ├── columns: a:30!null b:31 c:32 d:33 rowid:34 │ ├── with-scan &1 - │ │ ├── columns: b:24 c:25 rowid:26 + │ │ ├── columns: a:30!null b:31 c:32 d:33 rowid:34 │ │ └── mapping: - │ │ ├── upsert_b:20 => b:24 - │ │ ├── upsert_c:21 => c:25 - │ │ └── upsert_rowid:23 => rowid:26 + │ │ ├── upsert_a:19 => a:30 + │ │ ├── upsert_b:20 => b:31 + │ │ ├── upsert_c:21 => c:32 + │ │ ├── upsert_d:22 => d:33 + │ │ └── upsert_rowid:23 => rowid:34 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.b:28 uniq_hidden_pk.c:29 uniq_hidden_pk.rowid:31!null + │ │ └── columns: uniq_hidden_pk.a:24 uniq_hidden_pk.b:25 uniq_hidden_pk.c:26 uniq_hidden_pk.d:27 uniq_hidden_pk.rowid:28!null │ └── filters - │ ├── b:24 = uniq_hidden_pk.b:28 - │ ├── c:25 = uniq_hidden_pk.c:29 - │ └── rowid:26 != uniq_hidden_pk.rowid:31 + │ ├── b:31 = uniq_hidden_pk.b:25 + │ ├── c:32 = uniq_hidden_pk.c:26 + │ └── rowid:34 != uniq_hidden_pk.rowid:28 ├── unique-checks-item: uniq_hidden_pk(a,b,d) │ └── semi-join (hash) - │ ├── columns: a:33!null b:34 d:35 rowid:36 + │ ├── columns: a:41!null b:42 c:43 d:44 rowid:45 │ ├── with-scan &1 - │ │ ├── columns: a:33!null b:34 d:35 rowid:36 + │ │ ├── columns: a:41!null b:42 c:43 d:44 rowid:45 │ │ └── mapping: - │ │ ├── upsert_a:19 => a:33 - │ │ ├── upsert_b:20 => b:34 - │ │ ├── upsert_d:22 => d:35 - │ │ └── upsert_rowid:23 => rowid:36 + │ │ ├── upsert_a:19 => a:41 + │ │ ├── upsert_b:20 => b:42 + │ │ ├── upsert_c:21 => c:43 + │ │ ├── upsert_d:22 => d:44 + │ │ └── upsert_rowid:23 => rowid:45 │ ├── scan uniq_hidden_pk - │ │ └── columns: uniq_hidden_pk.a:37 uniq_hidden_pk.b:38 uniq_hidden_pk.d:40 uniq_hidden_pk.rowid:41!null + │ │ └── columns: uniq_hidden_pk.a:35 uniq_hidden_pk.b:36 uniq_hidden_pk.c:37 uniq_hidden_pk.d:38 uniq_hidden_pk.rowid:39!null │ └── filters - │ ├── a:33 = uniq_hidden_pk.a:37 - │ ├── b:34 = uniq_hidden_pk.b:38 - │ ├── d:35 = uniq_hidden_pk.d:40 - │ └── rowid:36 != uniq_hidden_pk.rowid:41 + │ ├── a:41 = uniq_hidden_pk.a:35 + │ ├── b:42 = uniq_hidden_pk.b:36 + │ ├── d:44 = uniq_hidden_pk.d:38 + │ └── rowid:45 != uniq_hidden_pk.rowid:39 └── unique-checks-item: uniq_hidden_pk(a) └── semi-join (hash) - ├── columns: a:43!null rowid:44 + ├── columns: a:52!null b:53 c:54 d:55 rowid:56 ├── with-scan &1 - │ ├── columns: a:43!null rowid:44 + │ ├── columns: a:52!null b:53 c:54 d:55 rowid:56 │ └── mapping: - │ ├── upsert_a:19 => a:43 - │ └── upsert_rowid:23 => rowid:44 + │ ├── upsert_a:19 => a:52 + │ ├── upsert_b:20 => b:53 + │ ├── upsert_c:21 => c:54 + │ ├── upsert_d:22 => d:55 + │ └── upsert_rowid:23 => rowid:56 ├── scan uniq_hidden_pk - │ └── columns: uniq_hidden_pk.a:45 uniq_hidden_pk.rowid:49!null + │ └── columns: uniq_hidden_pk.a:46 uniq_hidden_pk.b:47 uniq_hidden_pk.c:48 uniq_hidden_pk.d:49 uniq_hidden_pk.rowid:50!null └── filters - ├── a:43 = uniq_hidden_pk.a:45 - └── rowid:44 != uniq_hidden_pk.rowid:49 + ├── a:52 = uniq_hidden_pk.a:46 + └── rowid:56 != uniq_hidden_pk.rowid:50 exec-ddl CREATE TABLE uniq_fk_parent ( @@ -1358,17 +1428,17 @@ upsert uniq_fk_parent ├── unique-checks │ └── unique-checks-item: uniq_fk_parent(a) │ └── semi-join (hash) - │ ├── columns: a:10!null rowid:11 + │ ├── columns: a:13!null rowid:14 │ ├── with-scan &1 - │ │ ├── columns: a:10!null rowid:11 + │ │ ├── columns: a:13!null rowid:14 │ │ └── mapping: - │ │ ├── column1:4 => a:10 - │ │ └── upsert_rowid:9 => rowid:11 + │ │ ├── column1:4 => a:13 + │ │ └── upsert_rowid:9 => rowid:14 │ ├── scan uniq_fk_parent - │ │ └── columns: uniq_fk_parent.a:12 uniq_fk_parent.rowid:13!null + │ │ └── columns: uniq_fk_parent.a:10 uniq_fk_parent.rowid:11!null │ └── filters - │ ├── a:10 = uniq_fk_parent.a:12 - │ └── rowid:11 != uniq_fk_parent.rowid:13 + │ ├── a:13 = uniq_fk_parent.a:10 + │ └── rowid:14 != uniq_fk_parent.rowid:11 └── f-k-checks └── f-k-checks-item: uniq_fk_child(a) -> uniq_fk_parent(a) └── semi-join (hash) @@ -1481,17 +1551,17 @@ upsert t └── unique-checks └── unique-checks-item: t(i) └── semi-join (hash) - ├── columns: i:14!null rowid:15 + ├── columns: i:17!null rowid:18 ├── with-scan &1 - │ ├── columns: i:14!null rowid:15 + │ ├── columns: i:17!null rowid:18 │ └── mapping: - │ ├── upsert_i:10 => i:14 - │ └── upsert_rowid:11 => rowid:15 + │ ├── upsert_i:10 => i:17 + │ └── upsert_rowid:11 => rowid:18 ├── scan t - │ ├── columns: t.i:16 t.rowid:17!null + │ ├── columns: t.i:14 t.rowid:15!null │ └── partial index predicates │ └── i1: filters - │ └── t.i:16 > 0 + │ └── t.i:14 > 0 └── filters - ├── i:14 = t.i:16 - └── rowid:15 != t.rowid:17 + ├── i:17 = t.i:14 + └── rowid:18 != t.rowid:15