diff --git a/pkg/sql/opt/exec/execbuilder/testdata/unique b/pkg/sql/opt/exec/execbuilder/testdata/unique index d079a2ffeea7..0cf9d7811df5 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/unique +++ b/pkg/sql/opt/exec/execbuilder/testdata/unique @@ -741,34 +741,38 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (column1, column2, column3, column4) +│ │ columns: (column3) │ │ estimated row count: 1 (missing stats) │ │ -│ └── • lookup join (semi) -│ │ columns: ("lookup_join_const_col_@12", column1, column2, column3, column4) -│ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@12, column3) = (r,i) -│ │ equality cols are key -│ │ pred: column1 != r +│ └── • project +│ │ columns: (column1, column3) +│ │ estimated row count: 1 (missing stats) │ │ -│ └── • cross join (inner) -│ │ columns: ("lookup_join_const_col_@12", column1, column2, column3, column4) -│ │ estimated row count: 6 -│ │ -│ ├── • values -│ │ 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' +│ └── • lookup join (semi) +│ │ columns: ("lookup_join_const_col_@12", column1, column3) +│ │ table: uniq_enum@primary +│ │ equality: (lookup_join_const_col_@12, column3) = (r,i) +│ │ equality cols are key +│ │ pred: column1 != r │ │ -│ └── • project -│ │ columns: (column1, column2, column3, column4) -│ │ estimated row count: 2 +│ └── • cross join (inner) +│ │ columns: ("lookup_join_const_col_@12", column1, column3) +│ │ estimated row count: 6 │ │ -│ └── • scan buffer -│ columns: (column1, column2, column3, column4, check1) -│ label: buffer 1 +│ ├── • values +│ │ 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: (column1, column3) +│ │ estimated row count: 2 +│ │ +│ └── • scan buffer +│ columns: (column1, column2, column3, column4, check1) +│ label: buffer 1 │ └── • constraint-check │ @@ -776,34 +780,38 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column1, column2, column3, column4) + │ columns: (column2) │ estimated row count: 1 (missing stats) │ - └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@22", column1, column2, column3, column4) - │ table: uniq_enum@uniq_enum_r_s_j_key - │ equality: (lookup_join_const_col_@22, column2, column4) = (r,s,j) - │ equality cols are key - │ pred: (column1 != r) OR (column3 != i) + └── • project + │ columns: (column1, column2, column3, column4) + │ estimated row count: 1 (missing stats) │ - └── • cross join (inner) + └── • lookup join (semi) │ columns: ("lookup_join_const_col_@22", column1, column2, column3, column4) - │ estimated row count: 6 - │ - ├── • values - │ 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' + │ table: uniq_enum@uniq_enum_r_s_j_key + │ equality: (lookup_join_const_col_@22, column2, column4) = (r,s,j) + │ equality cols are key + │ pred: (column1 != r) OR (column3 != i) │ - └── • project - │ columns: (column1, column2, column3, column4) - │ estimated row count: 2 + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@22", column1, column2, column3, column4) + │ estimated row count: 6 + │ + ├── • values + │ 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' │ - └── • scan buffer - columns: (column1, column2, column3, column4, check1) - label: buffer 1 + └── • project + │ columns: (column1, column2, column3, column4) + │ estimated row count: 2 + │ + └── • scan buffer + columns: (column1, column2, column3, column4, check1) + label: buffer 1 # Test that we use the index when available for the insert checks. This uses # the default value for columns r and j. @@ -856,34 +864,38 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column9, column1, column2, column10) + │ columns: (column2) │ estimated row count: 1 (missing stats) │ - └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@12", column9, column1, column2, column10) - │ table: uniq_enum@primary - │ equality: (lookup_join_const_col_@12, column2) = (r,i) - │ equality cols are key - │ pred: column9 != r + └── • project + │ columns: (column9, column2) + │ estimated row count: 1 (missing stats) │ - └── • cross join (inner) - │ columns: ("lookup_join_const_col_@12", column9, column1, column2, column10) - │ estimated row count: 6 - │ - ├── • values - │ 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' + └── • lookup join (semi) + │ columns: ("lookup_join_const_col_@12", column9, column2) + │ table: uniq_enum@primary + │ equality: (lookup_join_const_col_@12, column2) = (r,i) + │ equality cols are key + │ pred: column9 != r │ - └── • project - │ columns: (column9, column1, column2, column10) - │ estimated row count: 2 + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@12", column9, column2) + │ estimated row count: 6 + │ + ├── • values + │ 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' │ - └── • scan buffer - columns: (column9, column1, column2, column10, check1) - label: buffer 1 + └── • project + │ columns: (column9, column2) + │ estimated row count: 2 + │ + └── • scan buffer + columns: (column9, column1, column2, column10, check1) + label: buffer 1 # Test that we use the index when available for de-duplicating INSERT ON # CONFLICT DO NOTHING rows before inserting. @@ -1322,38 +1334,42 @@ vectorized: true │ columns: () │ └── • project - │ columns: (column1, column2, column3, column4) + │ columns: (column3) │ estimated row count: 1 │ - └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@13", column1, column2, column3, column4) - │ table: uniq_partial_enum@uniq_partial_enum_r_b_idx (partial index) - │ equality: (lookup_join_const_col_@13, column3) = (r,b) - │ pred: (column1 != r) OR (column2 != a) + └── • project + │ columns: (column1, column2, column3, column4) + │ estimated row count: 1 │ - └── • cross join (inner) + └── • lookup join (semi) │ columns: ("lookup_join_const_col_@13", column1, column2, column3, column4) - │ estimated row count: 6 - │ - ├── • values - │ columns: ("lookup_join_const_col_@13") - │ size: 1 column, 3 rows - │ row 0, expr 0: 'us-east' - │ row 1, expr 0: 'us-west' - │ row 2, expr 0: 'eu-west' + │ table: uniq_partial_enum@uniq_partial_enum_r_b_idx (partial index) + │ equality: (lookup_join_const_col_@13, column3) = (r,b) + │ pred: (column1 != r) OR (column2 != a) │ - └── • filter - │ columns: (column1, column2, column3, column4) - │ estimated row count: 2 - │ filter: column4 IN ('bar', 'baz', 'foo') + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@13", column1, column2, column3, column4) + │ estimated row count: 6 │ - └── • project + ├── • values + │ columns: ("lookup_join_const_col_@13") + │ 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, column4) │ estimated row count: 2 + │ filter: column4 IN ('bar', 'baz', 'foo') │ - └── • scan buffer - columns: (column1, column2, column3, column4, check1, partial_index_put1) - label: buffer 1 + └── • project + │ columns: (column1, column2, column3, column4) + │ estimated row count: 2 + │ + └── • scan buffer + columns: (column1, column2, column3, column4, check1, partial_index_put1) + label: buffer 1 # Test that we use the partial index when available for de-duplicating INSERT ON # CONFLICT DO NOTHING rows before inserting. @@ -2171,34 +2187,38 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (r_new, s_new, i_new, j) +│ │ columns: (i_new) │ │ estimated row count: 3 (missing stats) │ │ -│ └── • lookup join (semi) -│ │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@17") -│ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@17, i_new) = (r,i) -│ │ equality cols are key -│ │ pred: r_new != r +│ └── • project +│ │ columns: (r_new, i_new) +│ │ estimated row count: 3 (missing stats) │ │ -│ └── • cross join (inner) -│ │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@17") -│ │ estimated row count: 30 (missing stats) -│ │ -│ ├── • project -│ │ │ columns: (r_new, s_new, i_new, j) -│ │ │ estimated row count: 10 (missing stats) -│ │ │ -│ │ └── • scan buffer -│ │ columns: (r, s, i, j, r_new, s_new, i_new, check1) -│ │ label: buffer 1 +│ └── • lookup join (semi) +│ │ columns: (r_new, i_new, "lookup_join_const_col_@17") +│ │ table: uniq_enum@primary +│ │ equality: (lookup_join_const_col_@17, i_new) = (r,i) +│ │ equality cols are key +│ │ pred: r_new != r │ │ -│ └── • values -│ columns: ("lookup_join_const_col_@17") -│ size: 1 column, 3 rows -│ row 0, expr 0: 'us-east' -│ row 1, expr 0: 'us-west' -│ row 2, expr 0: 'eu-west' +│ └── • cross join (inner) +│ │ columns: (r_new, i_new, "lookup_join_const_col_@17") +│ │ estimated row count: 30 (missing stats) +│ │ +│ ├── • project +│ │ │ columns: (r_new, i_new) +│ │ │ estimated row count: 10 (missing stats) +│ │ │ +│ │ └── • scan buffer +│ │ columns: (r, s, i, j, r_new, s_new, i_new, check1) +│ │ label: buffer 1 +│ │ +│ └── • values +│ columns: ("lookup_join_const_col_@17") +│ size: 1 column, 3 rows +│ row 0, expr 0: 'us-east' +│ row 1, expr 0: 'us-west' +│ row 2, expr 0: 'eu-west' │ └── • constraint-check │ @@ -2206,34 +2226,38 @@ vectorized: true │ columns: () │ └── • project - │ columns: (r_new, s_new, i_new, j) + │ columns: (s_new) │ estimated row count: 3 (missing stats) │ - └── • lookup join (semi) - │ 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_@27, s_new, j) = (r,s,j) - │ equality cols are key - │ pred: (r_new != r) OR (i_new != i) + └── • project + │ columns: (r_new, s_new, i_new, j) + │ estimated row count: 3 (missing stats) │ - └── • cross join (inner) + └── • lookup join (semi) │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@27") - │ estimated row count: 30 (missing stats) - │ - ├── • project - │ │ columns: (r_new, s_new, i_new, j) - │ │ estimated row count: 10 (missing stats) - │ │ - │ └── • scan buffer - │ columns: (r, s, i, j, r_new, s_new, i_new, check1) - │ label: buffer 1 + │ table: uniq_enum@uniq_enum_r_s_j_key + │ equality: (lookup_join_const_col_@27, s_new, j) = (r,s,j) + │ equality cols are key + │ pred: (r_new != r) OR (i_new != i) │ - └── • values - columns: ("lookup_join_const_col_@27") - size: 1 column, 3 rows - row 0, expr 0: 'us-east' - row 1, expr 0: 'us-west' - row 2, expr 0: 'eu-west' + └── • cross join (inner) + │ columns: (r_new, s_new, i_new, j, "lookup_join_const_col_@27") + │ estimated row count: 30 (missing stats) + │ + ├── • project + │ │ columns: (r_new, s_new, i_new, j) + │ │ estimated row count: 10 (missing stats) + │ │ + │ └── • scan buffer + │ columns: (r, s, i, j, r_new, s_new, i_new, check1) + │ label: buffer 1 + │ + └── • values + columns: ("lookup_join_const_col_@27") + size: 1 column, 3 rows + row 0, expr 0: 'us-east' + row 1, expr 0: 'us-west' + row 2, expr 0: 'eu-west' # None of the updated values have nulls. query T @@ -2485,38 +2509,42 @@ vectorized: true │ columns: () │ └── • project - │ columns: (r, a, b_new, c) + │ columns: (b_new) │ estimated row count: 0 │ - └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@16", r, a, b_new, c) - │ table: uniq_partial_enum@uniq_partial_enum_r_b_idx (partial index) - │ equality: (lookup_join_const_col_@16, b_new) = (r,b) - │ pred: (r != r) OR (a != a) + └── • project + │ columns: (r, a, b_new, c) + │ estimated row count: 0 │ - └── • cross join (inner) + └── • lookup join (semi) │ columns: ("lookup_join_const_col_@16", r, a, b_new, c) - │ estimated row count: 3 + │ table: uniq_partial_enum@uniq_partial_enum_r_b_idx (partial index) + │ equality: (lookup_join_const_col_@16, b_new) = (r,b) + │ pred: (r != r) OR (a != a) │ - ├── • values - │ columns: ("lookup_join_const_col_@16") - │ 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: (r, a, b_new, c) - │ estimated row count: 1 - │ filter: c IN ('bar', 'baz', 'foo') + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@16", r, a, b_new, c) + │ estimated row count: 3 │ - └── • project + ├── • values + │ columns: ("lookup_join_const_col_@16") + │ 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: (r, a, b_new, c) │ estimated row count: 1 + │ filter: c IN ('bar', 'baz', 'foo') │ - └── • scan buffer - columns: (r, a, b, b_new, partial_index_put1, partial_index_put1, c) - label: buffer 1 + └── • project + │ columns: (r, a, b_new, c) + │ estimated row count: 1 + │ + └── • scan buffer + columns: (r, a, b, b_new, partial_index_put1, partial_index_put1, c) + label: buffer 1 # By default, we do not require checks on UUID columns set to gen_random_uuid(), # but we do for UUID columns set to other values. @@ -3369,34 +3397,38 @@ vectorized: true │ │ columns: () │ │ │ └── • project -│ │ columns: (upsert_r, column2, upsert_i, column4) +│ │ columns: (upsert_i) │ │ estimated row count: 1 (missing stats) │ │ -│ └── • lookup join (semi) -│ │ columns: ("lookup_join_const_col_@20", upsert_r, column2, upsert_i, column4) -│ │ table: uniq_enum@primary -│ │ equality: (lookup_join_const_col_@20, upsert_i) = (r,i) -│ │ equality cols are key -│ │ pred: upsert_r != r +│ └── • project +│ │ columns: (upsert_r, upsert_i) +│ │ estimated row count: 1 (missing stats) │ │ -│ └── • cross join (inner) -│ │ columns: ("lookup_join_const_col_@20", upsert_r, column2, upsert_i, column4) -│ │ estimated row count: 6 (missing stats) -│ │ -│ ├── • values -│ │ 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' +│ └── • lookup join (semi) +│ │ columns: ("lookup_join_const_col_@20", upsert_r, upsert_i) +│ │ table: uniq_enum@primary +│ │ equality: (lookup_join_const_col_@20, upsert_i) = (r,i) +│ │ equality cols are key +│ │ pred: upsert_r != r │ │ -│ └── • project -│ │ columns: (upsert_r, column2, upsert_i, column4) -│ │ estimated row count: 2 (missing stats) +│ └── • cross join (inner) +│ │ columns: ("lookup_join_const_col_@20", upsert_r, upsert_i) +│ │ estimated row count: 6 (missing stats) │ │ -│ └── • scan buffer -│ columns: (column1, column2, column3, column4, r, s, i, j, column2, column4, r, check1, upsert_r, upsert_i) -│ label: buffer 1 +│ ├── • values +│ │ 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_r, upsert_i) +│ │ estimated row count: 2 (missing stats) +│ │ +│ └── • scan buffer +│ columns: (column1, column2, column3, column4, r, s, i, j, column2, column4, r, check1, upsert_r, upsert_i) +│ label: buffer 1 │ └── • constraint-check │ @@ -3404,34 +3436,38 @@ vectorized: true │ columns: () │ └── • project - │ columns: (upsert_r, column2, upsert_i, column4) + │ columns: (column2) │ estimated row count: 1 (missing stats) │ - └── • lookup join (semi) - │ 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_@30, column2, column4) = (r,s,j) - │ equality cols are key - │ pred: (upsert_r != r) OR (upsert_i != i) + └── • project + │ columns: (upsert_r, column2, upsert_i, column4) + │ estimated row count: 1 (missing stats) │ - └── • cross join (inner) + └── • lookup join (semi) │ columns: ("lookup_join_const_col_@30", upsert_r, column2, upsert_i, column4) - │ estimated row count: 6 (missing stats) - │ - ├── • values - │ 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' + │ table: uniq_enum@uniq_enum_r_s_j_key + │ equality: (lookup_join_const_col_@30, column2, column4) = (r,s,j) + │ equality cols are key + │ pred: (upsert_r != r) OR (upsert_i != i) │ - └── • project - │ columns: (upsert_r, column2, upsert_i, column4) - │ estimated row count: 2 (missing stats) + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@30", upsert_r, column2, upsert_i, column4) + │ estimated row count: 6 (missing stats) + │ + ├── • values + │ 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' │ - └── • scan buffer - columns: (column1, column2, column3, column4, r, s, i, j, column2, column4, r, check1, upsert_r, upsert_i) - label: buffer 1 + └── • project + │ columns: (upsert_r, column2, upsert_i, column4) + │ estimated row count: 2 (missing stats) + │ + └── • scan buffer + columns: (column1, column2, column3, column4, r, s, i, j, column2, column4, r, check1, upsert_r, upsert_i) + label: buffer 1 # Test that we use the index when available for the ON CONFLICT checks. query T @@ -3451,14 +3487,14 @@ vectorized: true │ │ arbiter constraints: unique_s_j │ │ │ └── • buffer -│ │ columns: (column1, column2, column3, column4, r, s, i, j, upsert_i, r, check1, upsert_r, upsert_s, upsert_j) +│ │ columns: (column1, column2, column3, column4, r, s, i, j, upsert_i, r, check1, upsert_r) │ │ label: buffer 1 │ │ │ └── • project -│ │ columns: (column1, column2, column3, column4, r, s, i, j, upsert_i, r, check1, upsert_r, upsert_s, upsert_j) +│ │ columns: (column1, column2, column3, column4, r, s, i, j, upsert_i, r, check1, upsert_r) │ │ │ └── • render -│ │ columns: (check1, column1, column2, column3, column4, r, s, i, j, upsert_r, upsert_s, upsert_i, upsert_j) +│ │ columns: (check1, column1, column2, column3, column4, r, s, i, j, upsert_r, upsert_i) │ │ estimated row count: 2 (missing stats) │ │ render check1: upsert_r IN ('us-east', 'us-west', 'eu-west') │ │ render column1: column1 @@ -3470,17 +3506,13 @@ vectorized: true │ │ render i: i │ │ render j: j │ │ render upsert_r: upsert_r -│ │ render upsert_s: upsert_s │ │ render upsert_i: upsert_i -│ │ render upsert_j: upsert_j │ │ │ └── • render -│ │ columns: (upsert_r, upsert_s, upsert_i, upsert_j, column1, column2, column3, column4, r, s, i, j) +│ │ columns: (upsert_r, upsert_i, column1, column2, column3, column4, r, s, i, j) │ │ estimated row count: 2 (missing stats) │ │ render upsert_r: CASE WHEN r IS NULL THEN column1 ELSE r END -│ │ render upsert_s: CASE WHEN r IS NULL THEN column2 ELSE s END │ │ render upsert_i: CASE WHEN r IS NULL THEN column3 ELSE 3 END -│ │ render upsert_j: CASE WHEN r IS NULL THEN column4 ELSE j END │ │ render column1: column1 │ │ render column2: column2 │ │ render column3: column3 @@ -3515,34 +3547,38 @@ vectorized: true │ columns: () │ └── • project - │ columns: (upsert_r, upsert_s, upsert_i, upsert_j) + │ columns: (upsert_i) │ estimated row count: 1 (missing stats) │ - └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@23", upsert_r, upsert_s, upsert_i, upsert_j) - │ table: uniq_enum@primary - │ equality: (lookup_join_const_col_@23, upsert_i) = (r,i) - │ equality cols are key - │ pred: upsert_r != r + └── • project + │ columns: (upsert_r, upsert_i) + │ estimated row count: 1 (missing stats) │ - └── • cross join (inner) - │ 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_@23") - │ size: 1 column, 3 rows - │ row 0, expr 0: 'us-east' - │ row 1, expr 0: 'us-west' - │ row 2, expr 0: 'eu-west' + └── • lookup join (semi) + │ columns: ("lookup_join_const_col_@23", upsert_r, upsert_i) + │ table: uniq_enum@primary + │ equality: (lookup_join_const_col_@23, upsert_i) = (r,i) + │ equality cols are key + │ pred: upsert_r != r │ - └── • project - │ columns: (upsert_r, upsert_s, upsert_i, upsert_j) - │ estimated row count: 2 (missing stats) + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@23", upsert_r, upsert_i) + │ estimated row count: 6 (missing stats) + │ + ├── • values + │ 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' │ - └── • scan buffer - columns: (column1, column2, column3, column4, r, s, i, j, upsert_i, r, check1, upsert_r, upsert_s, upsert_j) - label: buffer 1 + └── • project + │ columns: (upsert_r, upsert_i) + │ estimated row count: 2 (missing stats) + │ + └── • scan buffer + columns: (column1, column2, column3, column4, r, s, i, j, upsert_i, r, check1, upsert_r) + label: buffer 1 # None of the upserted values have nulls. query T @@ -4033,38 +4069,42 @@ vectorized: true │ columns: () │ └── • project - │ columns: (upsert_r, upsert_a, column3, column4) + │ columns: (column3) │ estimated row count: 1 │ - └── • lookup join (semi) - │ columns: ("lookup_join_const_col_@22", upsert_r, upsert_a, column3, column4) - │ table: uniq_partial_enum@uniq_partial_enum_r_b_idx (partial index) - │ equality: (lookup_join_const_col_@22, column3) = (r,b) - │ pred: (upsert_r != r) OR (upsert_a != a) + └── • project + │ columns: (upsert_r, upsert_a, column3, column4) + │ estimated row count: 1 │ - └── • cross join (inner) + └── • lookup join (semi) │ columns: ("lookup_join_const_col_@22", upsert_r, upsert_a, column3, column4) - │ estimated row count: 6 - │ - ├── • values - │ 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' + │ table: uniq_partial_enum@uniq_partial_enum_r_b_idx (partial index) + │ equality: (lookup_join_const_col_@22, column3) = (r,b) + │ pred: (upsert_r != r) OR (upsert_a != a) │ - └── • filter - │ columns: (upsert_r, upsert_a, column3, column4) - │ estimated row count: 2 - │ filter: column4 IN ('bar', 'baz', 'foo') + └── • cross join (inner) + │ columns: ("lookup_join_const_col_@22", upsert_r, upsert_a, column3, column4) + │ estimated row count: 6 │ - └── • project + ├── • values + │ 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' + │ + └── • filter │ columns: (upsert_r, upsert_a, column3, column4) │ estimated row count: 2 + │ filter: column4 IN ('bar', 'baz', 'foo') │ - └── • scan buffer - columns: (column1, column2, column3, column4, r, a, b, c, column3, column4, r, check1, partial_index_put1, partial_index_del1, upsert_r, upsert_a) - label: buffer 1 + └── • project + │ columns: (upsert_r, upsert_a, column3, column4) + │ estimated row count: 2 + │ + └── • scan buffer + columns: (column1, column2, column3, column4, r, a, b, c, column3, column4, r, check1, partial_index_put1, partial_index_del1, upsert_r, upsert_a) + label: buffer 1 # Test that we use the partial index when available for de-duplicating INSERT ON # CONFLICT DO UPDATE rows before inserting. diff --git a/pkg/sql/opt/norm/testdata/rules/prune_cols b/pkg/sql/opt/norm/testdata/rules/prune_cols index baac757e9e03..7519698af79b 100644 --- a/pkg/sql/opt/norm/testdata/rules/prune_cols +++ b/pkg/sql/opt/norm/testdata/rules/prune_cols @@ -3592,8 +3592,6 @@ upsert checks └── column2:7 > upsert_b:16 [as=check3:19, outer=(7,16)] # Do not prune columns from updates that are needed for unique checks. -# TODO(mgartner): v and z can be pruned because they are not updated and not -# needed for uniqueness checks. norm expect=PruneMutationInputCols UPDATE uniq SET w = 1, x = 2 WHERE k = 3 ---- @@ -3607,19 +3605,19 @@ update uniq ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── 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 + │ ├── 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-13,15,16) + │ ├── fd: ()-->(8,10-12,15,16) │ ├── select - │ │ ├── columns: uniq.k:8!null uniq.v:9 uniq.w:10 uniq.x:11 uniq.y:12 uniq.z:13 + │ │ ├── columns: uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 │ │ ├── cardinality: [0 - 1] │ │ ├── key: () - │ │ ├── fd: ()-->(8-13) + │ │ ├── fd: ()-->(8,10-12) │ │ ├── scan uniq - │ │ │ ├── columns: uniq.k:8!null uniq.v:9 uniq.w:10 uniq.x:11 uniq.y:12 uniq.z:13 + │ │ │ ├── columns: uniq.k:8!null uniq.w:10 uniq.x:11 uniq.y:12 │ │ │ ├── key: (8) - │ │ │ └── fd: (8)-->(9-13), (13)~~>(8-12), (10)~~>(8,9,11-13), (11,12)~~>(8-10,13) + │ │ │ └── fd: (8)-->(10-12), (10)~~>(8,11,12), (11,12)~~>(8,10) │ │ └── filters │ │ └── uniq.k:8 = 3 [outer=(8), constraints=(/8: [/3 - /3]; tight), fd=()-->(8)] │ └── projections @@ -3627,60 +3625,61 @@ update uniq │ └── 2 [as=x_new:16] └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:24!null v:25 w:26!null x:27!null y:28 z:29 + │ └── project + │ ├── columns: w:26!null │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(24-29) - │ ├── with-scan &1 - │ │ ├── columns: k:24!null v:25 w:26!null x:27!null y:28 z:29 - │ │ ├── mapping: - │ │ │ ├── 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: ()-->(24-29) - │ ├── scan uniq - │ │ ├── columns: uniq.k:17!null uniq.w:19 - │ │ ├── key: (17) - │ │ └── fd: (17)-->(19) - │ └── filters - │ ├── 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 - ])] + │ ├── fd: ()-->(26) + │ └── semi-join (hash) + │ ├── columns: k:24!null w:26!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(24,26) + │ ├── with-scan &1 + │ │ ├── columns: k:24!null w:26!null + │ │ ├── mapping: + │ │ │ ├── uniq.k:8 => k:24 + │ │ │ └── w_new:15 => w:26 + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ └── fd: ()-->(24,26) + │ ├── scan uniq + │ │ ├── columns: uniq.k:17!null uniq.w:19 + │ │ ├── key: (17) + │ │ └── fd: (17)-->(19) + │ └── filters + │ ├── 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: k:37!null v:38 w:39!null x:40!null y:41 z:42 + └── project + ├── columns: x:40!null ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(37-42) - ├── with-scan &1 - │ ├── columns: k:37!null v:38 w:39!null x:40!null y:41 z:42 - │ ├── mapping: - │ │ ├── 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: ()-->(37-42) - ├── scan uniq - │ ├── columns: uniq.k:30!null uniq.x:33 uniq.y:34 - │ ├── key: (30) - │ └── fd: (30)-->(33,34) - └── filters - ├── 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 - ])] + ├── fd: ()-->(40) + └── semi-join (hash) + ├── columns: k:37!null x:40!null y:41 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(37,40,41) + ├── with-scan &1 + │ ├── columns: k:37!null x:40!null y:41 + │ ├── mapping: + │ │ ├── uniq.k:8 => k:37 + │ │ ├── x_new:16 => x:40 + │ │ └── uniq.y:12 => y:41 + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ └── fd: ()-->(37,40,41) + ├── scan uniq + │ ├── columns: uniq.k:30!null uniq.x:33 uniq.y:34 + │ ├── key: (30) + │ └── fd: (30)-->(33,34) + └── filters + ├── 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 from updates that are needed for partial unique checks. -# TODO(mgartner): x can be pruned because it is not updated and not needed for -# uniqueness checks. norm expect=PruneMutationInputCols UPDATE uniq_partial SET v = 1 WHERE k = 3 ---- @@ -3693,60 +3692,64 @@ update uniq_partial ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── columns: v_new:11!null uniq_partial.k:6!null uniq_partial.v:7 uniq_partial.w:8 uniq_partial.x:9 + │ ├── columns: v_new:11!null uniq_partial.k:6!null uniq_partial.v:7 uniq_partial.w:8 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(6-9,11) + │ ├── fd: ()-->(6-8,11) │ ├── select - │ │ ├── columns: uniq_partial.k:6!null uniq_partial.v:7 uniq_partial.w:8 uniq_partial.x:9 + │ │ ├── columns: uniq_partial.k:6!null uniq_partial.v:7 uniq_partial.w:8 │ │ ├── cardinality: [0 - 1] │ │ ├── key: () - │ │ ├── fd: ()-->(6-9) + │ │ ├── fd: ()-->(6-8) │ │ ├── scan uniq_partial - │ │ │ ├── columns: uniq_partial.k:6!null uniq_partial.v:7 uniq_partial.w:8 uniq_partial.x:9 + │ │ │ ├── columns: uniq_partial.k:6!null uniq_partial.v:7 uniq_partial.w:8 │ │ │ ├── key: (6) - │ │ │ └── fd: (6)-->(7-9) + │ │ │ └── fd: (6)-->(7,8) │ │ └── filters │ │ └── uniq_partial.k:6 = 3 [outer=(6), constraints=(/6: [/3 - /3]; tight), fd=()-->(6)] │ └── projections │ └── 1 [as=v_new:11] └── unique-checks └── unique-checks-item: uniq_partial(v) - └── semi-join (hash) - ├── columns: k:17!null v:18!null w:19!null x:20 + └── project + ├── columns: v:18!null ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(17-20) - ├── select - │ ├── columns: k:17!null v:18!null w:19!null x:20 - │ ├── cardinality: [0 - 1] - │ ├── key: () - │ ├── fd: ()-->(17-20) - │ ├── with-scan &1 - │ │ ├── columns: k:17!null v:18!null w:19 x:20 - │ │ ├── mapping: - │ │ │ ├── uniq_partial.k:6 => k:17 - │ │ │ ├── v_new:11 => v:18 - │ │ │ ├── uniq_partial.w:8 => w:19 - │ │ │ └── uniq_partial.x:9 => x:20 - │ │ ├── cardinality: [0 - 1] - │ │ ├── key: () - │ │ └── fd: ()-->(17-20) - │ └── filters - │ └── w:19 > 0 [outer=(19), constraints=(/19: [/1 - ]; tight)] - ├── select - │ ├── columns: uniq_partial.k:12!null uniq_partial.v:13 uniq_partial.w:14!null - │ ├── key: (12) - │ ├── fd: (12)-->(13,14) - │ ├── scan uniq_partial - │ │ ├── columns: uniq_partial.k:12!null uniq_partial.v:13 uniq_partial.w:14 - │ │ ├── key: (12) - │ │ └── fd: (12)-->(13,14) - │ └── filters - │ └── uniq_partial.w:14 > 0 [outer=(14), constraints=(/14: [/1 - ]; tight)] - └── filters - ├── v:18 = uniq_partial.v:13 [outer=(13,18), constraints=(/13: (/NULL - ]; /18: (/NULL - ]), fd=(13)==(18), (18)==(13)] - └── k:17 != uniq_partial.k:12 [outer=(12,17), constraints=(/12: (/NULL - ]; /17: (/NULL - ])] + ├── fd: ()-->(18) + └── semi-join (hash) + ├── columns: k:17!null v:18!null w:19!null + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(17-19) + ├── select + │ ├── columns: k:17!null v:18!null w:19!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(17-19) + │ ├── with-scan &1 + │ │ ├── columns: k:17!null v:18!null w:19 + │ │ ├── mapping: + │ │ │ ├── uniq_partial.k:6 => k:17 + │ │ │ ├── v_new:11 => v:18 + │ │ │ └── uniq_partial.w:8 => w:19 + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ └── fd: ()-->(17-19) + │ └── filters + │ └── w:19 > 0 [outer=(19), constraints=(/19: [/1 - ]; tight)] + ├── select + │ ├── columns: uniq_partial.k:12!null uniq_partial.v:13 uniq_partial.w:14!null + │ ├── key: (12) + │ ├── fd: (12)-->(13,14) + │ ├── scan uniq_partial + │ │ ├── columns: uniq_partial.k:12!null uniq_partial.v:13 uniq_partial.w:14 + │ │ ├── key: (12) + │ │ └── fd: (12)-->(13,14) + │ └── filters + │ └── uniq_partial.w:14 > 0 [outer=(14), constraints=(/14: [/1 - ]; tight)] + └── filters + ├── v:18 = uniq_partial.v:13 [outer=(13,18), constraints=(/13: (/NULL - ]; /18: (/NULL - ]), fd=(13)==(18), (18)==(13)] + └── k:17 != uniq_partial.k:12 [outer=(12,17), constraints=(/12: (/NULL - ]; /17: (/NULL - ])] # Do not prune columns that are needed for foreign key checks or cascades. norm expect=PruneMutationInputCols @@ -3771,16 +3774,16 @@ upsert uniq_fk_parent ├── cardinality: [0 - 0] ├── volatile, mutations ├── project - │ ├── 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 + │ ├── 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-21) + │ ├── fd: ()-->(7-10,12,13,17-20) │ ├── 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 uniq_fk_parent.d:14 + │ │ ├── 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: () - │ │ ├── fd: ()-->(7-14) + │ │ ├── fd: ()-->(7-13) │ │ ├── values │ │ │ ├── columns: column1:7!null column2:8!null column9:9 │ │ │ ├── cardinality: [1 - 1] @@ -3788,14 +3791,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 uniq_fk_parent.d:14 + │ │ │ ├── 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-14) + │ │ │ ├── fd: ()-->(10-13) │ │ │ ├── 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 uniq_fk_parent.d:14 + │ │ │ │ ├── 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-14), (11)~~>(10,12-14), (12,13)~~>(10,11,14) + │ │ │ │ └── fd: (10)-->(11-13), (11)~~>(10,12,13), (12,13)~~>(10,11) │ │ │ └── filters │ │ │ └── uniq_fk_parent.k:10 = 2 [outer=(10), constraints=(/10: [/2 - /2]; tight), fd=()-->(10)] │ │ └── filters (true) @@ -3803,58 +3806,62 @@ 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 uniq_fk_parent.d:14 END [as=upsert_d:21, outer=(9,10,14)] + │ └── 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: k:28 a:29 b:30 c:31 d:32 + │ └── project + │ ├── columns: a:29 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(28-32) - │ ├── with-scan &1 - │ │ ├── columns: k:28 a:29 b:30 c:31 d:32 - │ │ ├── mapping: - │ │ │ ├── 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: ()-->(28-32) - │ ├── scan uniq_fk_parent - │ │ ├── columns: uniq_fk_parent.k:22!null uniq_fk_parent.a:23 - │ │ ├── key: (22) - │ │ └── fd: (22)-->(23) - │ └── filters - │ ├── 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 - ])] + │ ├── fd: ()-->(29) + │ └── semi-join (hash) + │ ├── columns: k:28 a:29 + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(28,29) + │ ├── with-scan &1 + │ │ ├── columns: k:28 a:29 + │ │ ├── mapping: + │ │ │ ├── upsert_k:17 => k:28 + │ │ │ └── upsert_a:18 => a:29 + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ └── fd: ()-->(28,29) + │ ├── scan uniq_fk_parent + │ │ ├── columns: uniq_fk_parent.k:22!null uniq_fk_parent.a:23 + │ │ ├── key: (22) + │ │ └── fd: (22)-->(23) + │ └── filters + │ ├── 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: k:39 a:40 b:41 c:42 d:43 + └── project + ├── columns: b:41 ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(39-43) - ├── with-scan &1 - │ ├── columns: k:39 a:40 b:41 c:42 d:43 - │ ├── mapping: - │ │ ├── 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: ()-->(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: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 - ])] + ├── fd: ()-->(41) + └── semi-join (hash) + ├── columns: k:39 b:41 c:42 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(39,41,42) + ├── with-scan &1 + │ ├── columns: k:39 b:41 c:42 + │ ├── mapping: + │ │ ├── upsert_k:17 => k:39 + │ │ ├── upsert_b:19 => b:41 + │ │ └── upsert_c:20 => c:42 + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ └── fd: ()-->(39,41,42) + ├── 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: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 @@ -3913,54 +3920,59 @@ upsert uniq_fk_parent │ └── 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: k:27 a:28 b:29 c:30 d:31 + │ └── project + │ ├── columns: a:28 │ ├── cardinality: [0 - 1] │ ├── key: () - │ ├── fd: ()-->(27-31) - │ ├── with-scan &1 - │ │ ├── columns: k:27 a:28 b:29 c:30 d:31 - │ │ ├── mapping: - │ │ │ ├── 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: ()-->(27-31) - │ ├── scan uniq_fk_parent - │ │ ├── columns: uniq_fk_parent.k:21!null uniq_fk_parent.a:22 - │ │ ├── key: (21) - │ │ └── fd: (21)-->(22) - │ └── filters - │ ├── 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 - ])] + │ ├── fd: ()-->(28) + │ └── semi-join (hash) + │ ├── columns: k:27 a:28 + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(27,28) + │ ├── with-scan &1 + │ │ ├── columns: k:27 a:28 + │ │ ├── mapping: + │ │ │ ├── upsert_k:16 => k:27 + │ │ │ └── upsert_a:17 => a:28 + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ └── fd: ()-->(27,28) + │ ├── scan uniq_fk_parent + │ │ ├── columns: uniq_fk_parent.k:21!null uniq_fk_parent.a:22 + │ │ ├── key: (21) + │ │ └── fd: (21)-->(22) + │ └── filters + │ ├── 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: k:38 a:39 b:40 c:41 d:42 + └── project + ├── columns: b:40 ├── cardinality: [0 - 1] ├── key: () - ├── fd: ()-->(38-42) - ├── with-scan &1 - │ ├── columns: k:38 a:39 b:40 c:41 d:42 - │ ├── mapping: - │ │ ├── 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: ()-->(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: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 - ])] + ├── fd: ()-->(40) + └── semi-join (hash) + ├── columns: k:38 b:40 c:41 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(38,40,41) + ├── with-scan &1 + │ ├── columns: k:38 b:40 c:41 + │ ├── mapping: + │ │ ├── upsert_k:16 => k:38 + │ │ ├── upsert_b:18 => b:40 + │ │ └── upsert_c:19 => c:41 + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ └── fd: ()-->(38,40,41) + ├── 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: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_unique.go b/pkg/sql/opt/optbuilder/mutation_builder_unique.go index fa48ea750815..2843a2d7cb1c 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder_unique.go +++ b/pkg/sql/opt/optbuilder/mutation_builder_unique.go @@ -20,6 +20,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" "github.com/cockroachdb/cockroach/pkg/sql/types" "github.com/cockroachdb/cockroach/pkg/util" + "github.com/cockroachdb/errors" ) // UniquenessChecksForGenRandomUUIDClusterMode controls the cluster setting for @@ -151,7 +152,7 @@ func (mb *mutationBuilder) hasUniqueWithoutIndexConstraints() bool { // constraint are being updated (according to updateColIDs). When the unique // constraint has a partial predicate, it also returns true if the predicate // references any of the columns being updated. -func (mb *mutationBuilder) uniqueColsUpdated(uniqueOrdinal int) bool { +func (mb *mutationBuilder) uniqueColsUpdated(uniqueOrdinal cat.UniqueOrdinal) bool { uc := mb.tab.Unique(uniqueOrdinal) for i, n := 0, uc.ColumnCount(); i < n; i++ { @@ -379,7 +380,26 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem { keyCols = append(keyCols, withScanScope.cols[i].id) } - return f.ConstructUniqueChecksItem(semiJoin, &memo.UniqueChecksItemPrivate{ + // Project only a single column so that normalization rules prune any + // unnecessary columns from the expression. The column type and value does + // not matter. The unique check will fail if there are any rows produced by + // the expression regardless of the values in the row. We project the first + // column in the unique constraint from the WithScan side of the semi-join + // because it will always be needed in the semi-join filter. This guarantees + // that we don't project a column that is otherwise not needed. + uniqueColOrd, ok := h.uniqueOrdinals.Next(0) + if !ok { + panic(errors.AssertionFailedf("uniqueOrdinals cannot be empty")) + } + var passthrough opt.ColSet + passthrough.Add(withScanScope.cols[uniqueColOrd].id) + project := f.ConstructProject( + semiJoin, + nil, /* projections */ + passthrough, + ) + + return f.ConstructUniqueChecksItem(project, &memo.UniqueChecksItemPrivate{ Table: h.mb.tabID, CheckOrdinal: h.uniqueOrdinal, KeyCols: keyCols, diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-insert b/pkg/sql/opt/optbuilder/testdata/unique-checks-insert index 80db059a957c..7280e60f09d4 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-insert +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-insert @@ -28,38 +28,42 @@ insert uniq │ └── (2, 2, 2, 2, 2) └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22!null - │ ├── with-scan &1 - │ │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22!null - │ │ └── mapping: - │ │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 - │ └── filters - │ ├── w:20 = uniq.w:14 - │ └── k:18 != uniq.k:12 + │ └── project + │ ├── columns: w:20!null + │ └── semi-join (hash) + │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22!null + │ ├── with-scan &1 + │ │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22!null + │ │ └── mapping: + │ │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 + │ └── filters + │ ├── w:20 = uniq.w:14 + │ └── k:18 != uniq.k:12 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:29!null v:30!null w:31!null x:32!null y:33!null - ├── with-scan &1 - │ ├── columns: k:29!null v:30!null w:31!null x:32!null y:33!null - │ └── mapping: - │ ├── 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.v:24 uniq.w:25 uniq.x:26 uniq.y:27 - └── filters - ├── x:32 = uniq.x:26 - ├── y:33 = uniq.y:27 - └── k:29 != uniq.k:23 + └── project + ├── columns: x:32!null + └── semi-join (hash) + ├── columns: k:29!null v:30!null w:31!null x:32!null y:33!null + ├── with-scan &1 + │ ├── columns: k:29!null v:30!null w:31!null x:32!null y:33!null + │ └── mapping: + │ ├── 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.v:24 uniq.w:25 uniq.x:26 uniq.y:27 + └── filters + ├── x:32 = uniq.x:26 + ├── y:33 = uniq.y:27 + └── k:29 != uniq.k:23 # Some of the inserted values have nulls. build @@ -81,38 +85,42 @@ insert uniq │ └── (3, NULL::INT8, NULL::INT8, NULL::INT8, 3) └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:18!null v:19 w:20 x:21 y:22!null - │ ├── with-scan &1 - │ │ ├── columns: k:18!null v:19 w:20 x:21 y:22!null - │ │ └── mapping: - │ │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 - │ └── filters - │ ├── w:20 = uniq.w:14 - │ └── k:18 != uniq.k:12 + │ └── project + │ ├── columns: w:20 + │ └── semi-join (hash) + │ ├── columns: k:18!null v:19 w:20 x:21 y:22!null + │ ├── with-scan &1 + │ │ ├── columns: k:18!null v:19 w:20 x:21 y:22!null + │ │ └── mapping: + │ │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 + │ └── filters + │ ├── w:20 = uniq.w:14 + │ └── k:18 != uniq.k:12 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:29!null v:30 w:31 x:32 y:33!null - ├── with-scan &1 - │ ├── columns: k:29!null v:30 w:31 x:32 y:33!null - │ └── mapping: - │ ├── 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.v:24 uniq.w:25 uniq.x:26 uniq.y:27 - └── filters - ├── x:32 = uniq.x:26 - ├── y:33 = uniq.y:27 - └── k:29 != uniq.k:23 + └── project + ├── columns: x:32 + └── semi-join (hash) + ├── columns: k:29!null v:30 w:31 x:32 y:33!null + ├── with-scan &1 + │ ├── columns: k:29!null v:30 w:31 x:32 y:33!null + │ └── mapping: + │ ├── 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.v:24 uniq.w:25 uniq.x:26 uniq.y:27 + └── filters + ├── 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 always null. build @@ -133,22 +141,24 @@ insert uniq │ └── (2, 2, NULL::INT8, 2, 2) └── unique-checks └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:18!null v:19!null w:20 x:21!null y:22!null - ├── with-scan &1 - │ ├── columns: k:18!null v:19!null w:20 x:21!null y:22!null - │ └── mapping: - │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 - └── filters - ├── x:21 = uniq.x:15 - ├── y:22 = uniq.y:16 - └── k:18 != uniq.k:12 + └── project + ├── columns: x:21!null + └── semi-join (hash) + ├── columns: k:18!null v:19!null w:20 x:21!null y:22!null + ├── with-scan &1 + │ ├── columns: k:18!null v:19!null w:20 x:21!null y:22!null + │ └── mapping: + │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 + └── filters + ├── 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 always null. build @@ -169,21 +179,23 @@ insert uniq │ └── (2, 2, NULL::INT8, NULL::INT8, 2) └── unique-checks └── unique-checks-item: uniq(w) - └── semi-join (hash) - ├── columns: k:18!null v:19!null w:20 x:21 y:22!null - ├── with-scan &1 - │ ├── columns: k:18!null v:19!null w:20 x:21 y:22!null - │ └── mapping: - │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 - └── filters - ├── w:20 = uniq.w:14 - └── k:18 != uniq.k:12 + └── project + ├── columns: w:20 + └── semi-join (hash) + ├── columns: k:18!null v:19!null w:20 x:21 y:22!null + ├── with-scan &1 + │ ├── columns: k:18!null v:19!null w:20 x:21 y:22!null + │ └── mapping: + │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 + └── filters + ├── w:20 = uniq.w:14 + └── k:18 != uniq.k:12 # No need to plan checks for x,y since y is always null. build @@ -204,21 +216,23 @@ insert uniq │ └── (2, 2, 2, 2, NULL::INT8) └── unique-checks └── unique-checks-item: uniq(w) - └── semi-join (hash) - ├── columns: k:18!null v:19!null w:20!null x:21!null y:22 - ├── with-scan &1 - │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22 - │ └── mapping: - │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 - └── filters - ├── w:20 = uniq.w:14 - └── k:18 != uniq.k:12 + └── project + ├── columns: w:20!null + └── semi-join (hash) + ├── columns: k:18!null v:19!null w:20!null x:21!null y:22 + ├── with-scan &1 + │ ├── columns: k:18!null v:19!null w:20!null x:21!null y:22 + │ └── mapping: + │ ├── 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:12!null uniq.v:13 uniq.w:14 uniq.x:15 uniq.y:16 + └── filters + ├── w:20 = uniq.w:14 + └── k:18 != uniq.k:12 # No need to plan any checks, since w, x and y are always null. build @@ -364,22 +378,24 @@ insert uniq │ └── column5:11 └── unique-checks └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:24!null v:25!null w:26!null x:27!null y:28!null - ├── with-scan &1 - │ ├── columns: k:24!null v:25!null w:26!null x:27!null y:28!null - │ └── mapping: - │ ├── 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:18!null uniq.v:19 uniq.w:20 uniq.x:21 uniq.y:22 - └── filters - ├── x:27 = uniq.x:21 - ├── y:28 = uniq.y:22 - └── k:24 != uniq.k:18 + └── project + ├── columns: x:27!null + └── semi-join (hash) + ├── columns: k:24!null v:25!null w:26!null x:27!null y:28!null + ├── with-scan &1 + │ ├── columns: k:24!null v:25!null w:26!null x:27!null y:28!null + │ └── mapping: + │ ├── 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:18!null uniq.v:19 uniq.w:20 uniq.x:21 uniq.y:22 + └── filters + ├── x:27 = uniq.x:21 + ├── y:28 = uniq.y:22 + └── k:24 != uniq.k:18 exec-ddl CREATE TABLE other (k INT, v INT, w INT NOT NULL, x INT, y INT) @@ -404,38 +420,42 @@ insert uniq │ └── columns: other.k:7 other.v:8 other.w:9!null other.x:10 other.y:11 rowid:12!null other.crdb_internal_mvcc_timestamp:13 └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:20 v:21 w:22!null x:23 y:24 - │ ├── with-scan &1 - │ │ ├── columns: k:20 v:21 w:22!null x:23 y:24 - │ │ └── mapping: - │ │ ├── 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:14!null uniq.v:15 uniq.w:16 uniq.x:17 uniq.y:18 - │ └── filters - │ ├── w:22 = uniq.w:16 - │ └── k:20 != uniq.k:14 + │ └── project + │ ├── columns: w:22!null + │ └── semi-join (hash) + │ ├── columns: k:20 v:21 w:22!null x:23 y:24 + │ ├── with-scan &1 + │ │ ├── columns: k:20 v:21 w:22!null x:23 y:24 + │ │ └── mapping: + │ │ ├── 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:14!null uniq.v:15 uniq.w:16 uniq.x:17 uniq.y:18 + │ └── filters + │ ├── w:22 = uniq.w:16 + │ └── k:20 != uniq.k:14 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:31 v:32 w:33!null x:34 y:35 - ├── with-scan &1 - │ ├── columns: k:31 v:32 w:33!null x:34 y:35 - │ └── mapping: - │ ├── 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.v:26 uniq.w:27 uniq.x:28 uniq.y:29 - └── filters - ├── x:34 = uniq.x:28 - ├── y:35 = uniq.y:29 - └── k:31 != uniq.k:25 + └── project + ├── columns: x:34 + └── semi-join (hash) + ├── columns: k:31 v:32 w:33!null x:34 y:35 + ├── with-scan &1 + │ ├── columns: k:31 v:32 w:33!null x:34 y:35 + │ └── mapping: + │ ├── 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.v:26 uniq.w:27 uniq.x:28 uniq.y:29 + └── filters + ├── x:34 = uniq.x:28 + ├── y:35 = uniq.y:29 + └── k:31 != uniq.k:25 exec-ddl CREATE TABLE uniq_overlaps_pk ( @@ -471,52 +491,58 @@ insert uniq_overlaps_pk │ └── (2, 2, 2, 2) └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,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_overlaps_pk - │ │ └── 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:16 = uniq_overlaps_pk.b:11 - │ ├── c:17 = uniq_overlaps_pk.c:12 - │ └── a:15 != uniq_overlaps_pk.a:10 + │ └── project + │ ├── columns: b:16!null + │ └── 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_overlaps_pk + │ │ └── 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: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: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_overlaps_pk - │ │ └── 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:24 = uniq_overlaps_pk.a:19 - │ └── b:25 != uniq_overlaps_pk.b:20 + │ └── project + │ ├── columns: a:24!null + │ └── 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_overlaps_pk + │ │ └── 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: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: 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_overlaps_pk - │ └── 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: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) + └── project + ├── columns: c:35!null + └── 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_overlaps_pk + │ └── 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: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 @@ -538,52 +564,58 @@ insert uniq_overlaps_pk │ └── 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: 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_overlaps_pk - │ │ └── 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:19 = uniq_overlaps_pk.b:14 - │ ├── c:20 = uniq_overlaps_pk.c:15 - │ └── a:18 != uniq_overlaps_pk.a:13 + │ └── project + │ ├── columns: b:19 + │ └── 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_overlaps_pk + │ │ └── 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: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: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_overlaps_pk - │ │ └── 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:27 = uniq_overlaps_pk.a:22 - │ └── b:28 != uniq_overlaps_pk.b:23 + │ └── project + │ ├── columns: a:27 + │ └── 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_overlaps_pk + │ │ └── 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: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: 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_overlaps_pk - │ └── 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: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) + └── project + ├── columns: c:38 + └── 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_overlaps_pk + │ └── 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: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 ( @@ -621,56 +653,62 @@ insert uniq_hidden_pk │ └── unique_rowid() [as=column11:11] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) - │ └── semi-join (hash) - │ ├── columns: a:18!null b:19!null c:20!null d:21!null rowid:22 - │ ├── with-scan &1 - │ │ ├── columns: a:18!null b:19!null c:20!null d:21!null rowid:22 - │ │ └── mapping: - │ │ ├── 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.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:19 = uniq_hidden_pk.b:13 - │ ├── c:20 = uniq_hidden_pk.c:14 - │ └── rowid:22 != uniq_hidden_pk.rowid:16 + │ └── project + │ ├── columns: b:19!null + │ └── semi-join (hash) + │ ├── columns: a:18!null b:19!null c:20!null d:21!null rowid:22 + │ ├── with-scan &1 + │ │ ├── columns: a:18!null b:19!null c:20!null d:21!null rowid:22 + │ │ └── mapping: + │ │ ├── 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.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: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:29!null b:30!null c:31!null d:32!null rowid:33 - │ ├── with-scan &1 - │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null rowid:33 - │ │ └── mapping: - │ │ ├── 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:23 uniq_hidden_pk.b:24 uniq_hidden_pk.c:25 uniq_hidden_pk.d:26 uniq_hidden_pk.rowid:27!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:29!null + │ └── semi-join (hash) + │ ├── columns: a:29!null b:30!null c:31!null d:32!null rowid:33 + │ ├── with-scan &1 + │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null rowid:33 + │ │ └── mapping: + │ │ ├── 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:23 uniq_hidden_pk.b:24 uniq_hidden_pk.c:25 uniq_hidden_pk.d:26 uniq_hidden_pk.rowid:27!null + │ └── filters + │ ├── 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:40!null b:41!null c:42!null d:43!null rowid:44 - ├── with-scan &1 - │ ├── columns: a:40!null b:41!null c:42!null d:43!null rowid:44 - │ └── mapping: - │ ├── 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:34 uniq_hidden_pk.b:35 uniq_hidden_pk.c:36 uniq_hidden_pk.d:37 uniq_hidden_pk.rowid:38!null - └── filters - ├── a:40 = uniq_hidden_pk.a:34 - └── rowid:44 != uniq_hidden_pk.rowid:38 + └── project + ├── columns: a:40!null + └── semi-join (hash) + ├── columns: a:40!null b:41!null c:42!null d:43!null rowid:44 + ├── with-scan &1 + │ ├── columns: a:40!null b:41!null c:42!null d:43!null rowid:44 + │ └── mapping: + │ ├── 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:34 uniq_hidden_pk.b:35 uniq_hidden_pk.c:36 uniq_hidden_pk.d:37 uniq_hidden_pk.rowid:38!null + └── filters + ├── 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. @@ -696,56 +734,62 @@ insert uniq_hidden_pk │ └── unique_rowid() [as=column14:14] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) - │ └── semi-join (hash) - │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 - │ ├── with-scan &1 - │ │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 - │ │ └── mapping: - │ │ ├── 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.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:22 = uniq_hidden_pk.b:16 - │ ├── c:23 = uniq_hidden_pk.c:17 - │ └── rowid:25 != uniq_hidden_pk.rowid:19 + │ └── project + │ ├── columns: b:22 + │ └── semi-join (hash) + │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 + │ ├── with-scan &1 + │ │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 + │ │ └── mapping: + │ │ ├── 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.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: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:32 b:33 c:34 d:35 rowid:36 - │ ├── with-scan &1 - │ │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 - │ │ └── mapping: - │ │ ├── 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:26 uniq_hidden_pk.b:27 uniq_hidden_pk.c:28 uniq_hidden_pk.d:29 uniq_hidden_pk.rowid:30!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:32 + │ └── semi-join (hash) + │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 + │ ├── with-scan &1 + │ │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 + │ │ └── mapping: + │ │ ├── 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:26 uniq_hidden_pk.b:27 uniq_hidden_pk.c:28 uniq_hidden_pk.d:29 uniq_hidden_pk.rowid:30!null + │ └── filters + │ ├── 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:43 b:44 c:45 d:46 rowid:47 - ├── with-scan &1 - │ ├── columns: a:43 b:44 c:45 d:46 rowid:47 - │ └── mapping: - │ ├── 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: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 + └── project + ├── columns: a:43 + └── semi-join (hash) + ├── columns: a:43 b:44 c:45 d:46 rowid:47 + ├── with-scan &1 + │ ├── columns: a:43 b:44 c:45 d:46 rowid:47 + │ └── mapping: + │ ├── 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: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 ( @@ -773,21 +817,23 @@ insert uniq_partial │ └── (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 + └── project + ├── columns: a:13!null + └── 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 @@ -807,21 +853,23 @@ insert uniq_partial │ └── (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 + └── project + ├── columns: a:13 + └── 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 @@ -959,21 +1007,23 @@ insert uniq_partial │ └── 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 + └── project + ├── columns: a:17 + └── 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 ( @@ -1010,57 +1060,63 @@ insert uniq_partial_overlaps_pk │ └── (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) + │ └── project + │ ├── columns: c:17!null + │ └── 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 + │ └── project + │ ├── columns: a:24!null + │ └── 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 + └── project + ├── columns: b:34!null + └── 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 @@ -1082,57 +1138,63 @@ insert uniq_partial_overlaps_pk │ └── 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) + │ └── project + │ ├── columns: c:20 + │ └── 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 + │ └── project + │ ├── columns: a:27 + │ └── 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 + └── project + ├── columns: b:37 + └── 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 ( @@ -1167,22 +1229,24 @@ insert uniq_partial_hidden_pk │ └── 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 + └── project + ├── columns: b:16!null + └── 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 @@ -1207,22 +1271,24 @@ insert uniq_partial_hidden_pk │ └── 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 - ├── 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 + └── project + ├── columns: b:21 + └── 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 + ├── 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 exec-ddl CREATE TABLE uniq_partial_constraint_and_index ( @@ -1270,29 +1336,31 @@ insert uniq_partial_constraint_and_index │ └── true [as=partial_index_put1:13] └── unique-checks └── unique-checks-item: uniq_partial_constraint_and_index(a) - └── semi-join (hash) - ├── columns: k:18!null a:19!null b:20!null - ├── select - │ ├── columns: k:18!null a:19!null b:20!null - │ ├── with-scan &1 - │ │ ├── columns: k:18!null a:19!null b:20!null - │ │ └── mapping: - │ │ ├── column1:5 => k:18 - │ │ ├── column2:6 => a:19 - │ │ └── column3:7 => b:20 - │ └── filters - │ └── b:20 > 10 - ├── select - │ ├── columns: uniq_partial_constraint_and_index.k:14!null uniq_partial_constraint_and_index.a:15 uniq_partial_constraint_and_index.b:16!null - │ ├── scan uniq_partial_constraint_and_index - │ │ ├── columns: uniq_partial_constraint_and_index.k:14!null uniq_partial_constraint_and_index.a:15 uniq_partial_constraint_and_index.b:16 - │ │ └── partial index predicates - │ │ └── secondary: filters (true) - │ └── filters - │ └── uniq_partial_constraint_and_index.b:16 > 10 - └── filters - ├── a:19 = uniq_partial_constraint_and_index.a:15 - └── k:18 != uniq_partial_constraint_and_index.k:14 + └── project + ├── columns: a:19!null + └── semi-join (hash) + ├── columns: k:18!null a:19!null b:20!null + ├── select + │ ├── columns: k:18!null a:19!null b:20!null + │ ├── with-scan &1 + │ │ ├── columns: k:18!null a:19!null b:20!null + │ │ └── mapping: + │ │ ├── column1:5 => k:18 + │ │ ├── column2:6 => a:19 + │ │ └── column3:7 => b:20 + │ └── filters + │ └── b:20 > 10 + ├── select + │ ├── columns: uniq_partial_constraint_and_index.k:14!null uniq_partial_constraint_and_index.a:15 uniq_partial_constraint_and_index.b:16!null + │ ├── scan uniq_partial_constraint_and_index + │ │ ├── columns: uniq_partial_constraint_and_index.k:14!null uniq_partial_constraint_and_index.a:15 uniq_partial_constraint_and_index.b:16 + │ │ └── partial index predicates + │ │ └── secondary: filters (true) + │ └── filters + │ └── uniq_partial_constraint_and_index.b:16 > 10 + └── filters + ├── a:19 = uniq_partial_constraint_and_index.a:15 + └── k:18 != uniq_partial_constraint_and_index.k:14 exec-ddl CREATE TABLE uniq_constraint_and_partial_index ( @@ -1474,33 +1542,35 @@ insert uniq_computed_pk │ └── column3:11::STRING [as=column13:13] └── unique-checks └── unique-checks-item: uniq_computed_pk(d) - └── semi-join (hash) - ├── columns: i:38!null s:39!null d:40!null c_i_expr:41!null c_s:42!null c_d:43!null c_d_expr:44!null - ├── with-scan &1 - │ ├── columns: i:38!null s:39!null d:40!null c_i_expr:41!null c_s:42!null c_d:43!null c_d_expr:44!null - │ └── mapping: - │ ├── column1:9 => i:38 - │ ├── column2:10 => s:39 - │ ├── column3:11 => d:40 - │ ├── column12:12 => c_i_expr:41 - │ ├── column2:10 => c_s:42 - │ ├── column3:11 => c_d:43 - │ └── column13:13 => c_d_expr:44 - ├── project - │ ├── columns: uniq_computed_pk.c_s:34 uniq_computed_pk.i:30!null uniq_computed_pk.s:31 uniq_computed_pk.d:32 uniq_computed_pk.c_i_expr:33!null uniq_computed_pk.c_d:35 uniq_computed_pk.c_d_expr:36 - │ ├── scan uniq_computed_pk - │ │ ├── columns: uniq_computed_pk.i:30!null uniq_computed_pk.s:31 uniq_computed_pk.d:32 uniq_computed_pk.c_i_expr:33!null uniq_computed_pk.c_d:35 uniq_computed_pk.c_d_expr:36 - │ │ └── computed column expressions - │ │ ├── uniq_computed_pk.c_i_expr:33 - │ │ │ └── CASE WHEN uniq_computed_pk.i:30 < 0 THEN 'foo' ELSE 'bar' END - │ │ ├── uniq_computed_pk.c_s:34 - │ │ │ └── uniq_computed_pk.s:31 - │ │ ├── uniq_computed_pk.c_d:35 - │ │ │ └── uniq_computed_pk.d:32 - │ │ └── uniq_computed_pk.c_d_expr:36 - │ │ └── uniq_computed_pk.d:32::STRING - │ └── projections - │ └── uniq_computed_pk.s:31 [as=uniq_computed_pk.c_s:34] - └── filters - ├── d:40 = uniq_computed_pk.d:32 - └── (i:38 != uniq_computed_pk.i:30) OR (c_i_expr:41 != uniq_computed_pk.c_i_expr:33) + └── project + ├── columns: d:40!null + └── semi-join (hash) + ├── columns: i:38!null s:39!null d:40!null c_i_expr:41!null c_s:42!null c_d:43!null c_d_expr:44!null + ├── with-scan &1 + │ ├── columns: i:38!null s:39!null d:40!null c_i_expr:41!null c_s:42!null c_d:43!null c_d_expr:44!null + │ └── mapping: + │ ├── column1:9 => i:38 + │ ├── column2:10 => s:39 + │ ├── column3:11 => d:40 + │ ├── column12:12 => c_i_expr:41 + │ ├── column2:10 => c_s:42 + │ ├── column3:11 => c_d:43 + │ └── column13:13 => c_d_expr:44 + ├── project + │ ├── columns: uniq_computed_pk.c_s:34 uniq_computed_pk.i:30!null uniq_computed_pk.s:31 uniq_computed_pk.d:32 uniq_computed_pk.c_i_expr:33!null uniq_computed_pk.c_d:35 uniq_computed_pk.c_d_expr:36 + │ ├── scan uniq_computed_pk + │ │ ├── columns: uniq_computed_pk.i:30!null uniq_computed_pk.s:31 uniq_computed_pk.d:32 uniq_computed_pk.c_i_expr:33!null uniq_computed_pk.c_d:35 uniq_computed_pk.c_d_expr:36 + │ │ └── computed column expressions + │ │ ├── uniq_computed_pk.c_i_expr:33 + │ │ │ └── CASE WHEN uniq_computed_pk.i:30 < 0 THEN 'foo' ELSE 'bar' END + │ │ ├── uniq_computed_pk.c_s:34 + │ │ │ └── uniq_computed_pk.s:31 + │ │ ├── uniq_computed_pk.c_d:35 + │ │ │ └── uniq_computed_pk.d:32 + │ │ └── uniq_computed_pk.c_d_expr:36 + │ │ └── uniq_computed_pk.d:32::STRING + │ └── projections + │ └── uniq_computed_pk.s:31 [as=uniq_computed_pk.c_s:34] + └── filters + ├── d:40 = uniq_computed_pk.d:32 + └── (i:38 != uniq_computed_pk.i:30) OR (c_i_expr:41 != uniq_computed_pk.c_i_expr:33) diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-update b/pkg/sql/opt/optbuilder/testdata/unique-checks-update index 8a3398c8ec03..665905861f0f 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-update +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-update @@ -29,38 +29,42 @@ update uniq │ └── 2 [as=x_new:14] └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:21!null v:22 w:23!null x:24!null y:25 - │ ├── with-scan &1 - │ │ ├── columns: k:21!null v:22 w:23!null x:24!null y:25 - │ │ └── mapping: - │ │ ├── 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:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 - │ └── filters - │ ├── w:23 = uniq.w:17 - │ └── k:21 != uniq.k:15 + │ └── project + │ ├── columns: w:23!null + │ └── semi-join (hash) + │ ├── columns: k:21!null v:22 w:23!null x:24!null y:25 + │ ├── with-scan &1 + │ │ ├── columns: k:21!null v:22 w:23!null x:24!null y:25 + │ │ └── mapping: + │ │ ├── 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:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 + │ └── filters + │ ├── w:23 = uniq.w:17 + │ └── k:21 != uniq.k:15 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:32!null v:33 w:34!null x:35!null y:36 - ├── with-scan &1 - │ ├── columns: k:32!null v:33 w:34!null x:35!null y:36 - │ └── mapping: - │ ├── 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.v:27 uniq.w:28 uniq.x:29 uniq.y:30 - └── filters - ├── x:35 = uniq.x:29 - ├── y:36 = uniq.y:30 - └── k:32 != uniq.k:26 + └── project + ├── columns: x:35!null + └── semi-join (hash) + ├── columns: k:32!null v:33 w:34!null x:35!null y:36 + ├── with-scan &1 + │ ├── columns: k:32!null v:33 w:34!null x:35!null y:36 + │ └── mapping: + │ ├── 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.v:27 uniq.w:28 uniq.x:29 uniq.y:30 + └── filters + ├── 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 always null. build @@ -82,22 +86,24 @@ update uniq │ └── 1 [as=x_new:14] └── unique-checks └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:21!null v:22 w:23 x:24!null y:25 - ├── with-scan &1 - │ ├── columns: k:21!null v:22 w:23 x:24!null y:25 - │ └── mapping: - │ ├── 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:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 - └── filters - ├── x:24 = uniq.x:18 - ├── y:25 = uniq.y:19 - └── k:21 != uniq.k:15 + └── project + ├── columns: x:24!null + └── semi-join (hash) + ├── columns: k:21!null v:22 w:23 x:24!null y:25 + ├── with-scan &1 + │ ├── columns: k:21!null v:22 w:23 x:24!null y:25 + │ └── mapping: + │ ├── 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:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 + └── filters + ├── 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 always null. # Also update the primary key. @@ -122,21 +128,23 @@ update uniq │ └── NULL::INT8 [as=x_new:15] └── unique-checks └── unique-checks-item: uniq(w) - └── semi-join (hash) - ├── columns: k:22!null v:23 w:24!null x:25 y:26 - ├── with-scan &1 - │ ├── columns: k:22!null v:23 w:24!null x:25 y:26 - │ └── mapping: - │ ├── 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:16!null uniq.v:17 uniq.w:18 uniq.x:19 uniq.y:20 - └── filters - ├── w:24 = uniq.w:18 - └── k:22 != uniq.k:16 + └── project + ├── columns: w:24!null + └── semi-join (hash) + ├── columns: k:22!null v:23 w:24!null x:25 y:26 + ├── with-scan &1 + │ ├── columns: k:22!null v:23 w:24!null x:25 y:26 + │ └── mapping: + │ ├── 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:16!null uniq.v:17 uniq.w:18 uniq.x:19 uniq.y:20 + └── filters + ├── w:24 = uniq.w:18 + └── k:22 != uniq.k:16 # No need to plan checks for x,y since y is always null. build @@ -162,21 +170,23 @@ update uniq │ └── NULL::INT8 [as=y_new:14] └── unique-checks └── unique-checks-item: uniq(w) - └── semi-join (hash) - ├── columns: k:21!null v:22 w:23!null x:24 y:25 - ├── with-scan &1 - │ ├── columns: k:21!null v:22 w:23!null x:24 y:25 - │ └── mapping: - │ ├── 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:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 - └── filters - ├── w:23 = uniq.w:17 - └── k:21 != uniq.k:15 + └── project + ├── columns: w:23!null + └── semi-join (hash) + ├── columns: k:21!null v:22 w:23!null x:24 y:25 + ├── with-scan &1 + │ ├── columns: k:21!null v:22 w:23!null x:24 y:25 + │ └── mapping: + │ ├── 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:15!null uniq.v:16 uniq.w:17 uniq.x:18 uniq.y:19 + └── filters + ├── 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 @@ -248,38 +258,42 @@ update uniq │ └── other.crdb_internal_mvcc_timestamp:19 └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:26!null v:27 w:28!null x:29 y:30 - │ ├── with-scan &1 - │ │ ├── columns: k:26!null v:27 w:28!null x:29 y:30 - │ │ └── mapping: - │ │ ├── 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:20!null uniq.v:21 uniq.w:22 uniq.x:23 uniq.y:24 - │ └── filters - │ ├── w:28 = uniq.w:22 - │ └── k:26 != uniq.k:20 + │ └── project + │ ├── columns: w:28!null + │ └── semi-join (hash) + │ ├── columns: k:26!null v:27 w:28!null x:29 y:30 + │ ├── with-scan &1 + │ │ ├── columns: k:26!null v:27 w:28!null x:29 y:30 + │ │ └── mapping: + │ │ ├── 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:20!null uniq.v:21 uniq.w:22 uniq.x:23 uniq.y:24 + │ └── filters + │ ├── w:28 = uniq.w:22 + │ └── k:26 != uniq.k:20 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:37!null v:38 w:39!null x:40 y:41 - ├── with-scan &1 - │ ├── columns: k:37!null v:38 w:39!null x:40 y:41 - │ └── mapping: - │ ├── 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.v:32 uniq.w:33 uniq.x:34 uniq.y:35 - └── filters - ├── x:40 = uniq.x:34 - ├── y:41 = uniq.y:35 - └── k:37 != uniq.k:31 + └── project + ├── columns: x:40 + └── semi-join (hash) + ├── columns: k:37!null v:38 w:39!null x:40 y:41 + ├── with-scan &1 + │ ├── columns: k:37!null v:38 w:39!null x:40 y:41 + │ └── mapping: + │ ├── 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.v:32 uniq.w:33 uniq.x:34 uniq.y:35 + └── filters + ├── x:40 = uniq.x:34 + ├── y:41 = uniq.y:35 + └── k:37 != uniq.k:31 exec-ddl CREATE TABLE uniq_overlaps_pk ( @@ -325,52 +339,58 @@ update uniq_overlaps_pk │ └── 4 [as=d_new:14] └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) - │ └── semi-join (hash) - │ ├── columns: a:20!null b:21!null c:22!null d:23!null - │ ├── with-scan &1 - │ │ ├── columns: a:20!null b:21!null c:22!null d:23!null - │ │ └── mapping: - │ │ ├── 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:15!null uniq_overlaps_pk.b:16!null uniq_overlaps_pk.c:17 uniq_overlaps_pk.d:18 - │ └── filters - │ ├── b:21 = uniq_overlaps_pk.b:16 - │ ├── c:22 = uniq_overlaps_pk.c:17 - │ └── a:20 != uniq_overlaps_pk.a:15 + │ └── project + │ ├── columns: b:21!null + │ └── semi-join (hash) + │ ├── columns: a:20!null b:21!null c:22!null d:23!null + │ ├── with-scan &1 + │ │ ├── columns: a:20!null b:21!null c:22!null d:23!null + │ │ └── mapping: + │ │ ├── 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:15!null uniq_overlaps_pk.b:16!null uniq_overlaps_pk.c:17 uniq_overlaps_pk.d:18 + │ └── filters + │ ├── 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:29!null b:30!null c:31!null d:32!null - │ ├── with-scan &1 - │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null - │ │ └── mapping: - │ │ ├── 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:24!null uniq_overlaps_pk.b:25!null uniq_overlaps_pk.c:26 uniq_overlaps_pk.d:27 - │ └── filters - │ ├── a:29 = uniq_overlaps_pk.a:24 - │ └── b:30 != uniq_overlaps_pk.b:25 + │ └── project + │ ├── columns: a:29!null + │ └── semi-join (hash) + │ ├── columns: a:29!null b:30!null c:31!null d:32!null + │ ├── with-scan &1 + │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null + │ │ └── mapping: + │ │ ├── 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:24!null uniq_overlaps_pk.b:25!null uniq_overlaps_pk.c:26 uniq_overlaps_pk.d:27 + │ └── filters + │ ├── 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: a:38!null b:39!null c:40!null d:41!null - ├── with-scan &1 - │ ├── columns: a:38!null b:39!null c:40!null d:41!null - │ └── mapping: - │ ├── 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:33!null uniq_overlaps_pk.b:34!null uniq_overlaps_pk.c:35 uniq_overlaps_pk.d:36 - └── filters - ├── 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) + └── project + ├── columns: c:40!null + └── semi-join (hash) + ├── columns: a:38!null b:39!null c:40!null d:41!null + ├── with-scan &1 + │ ├── columns: a:38!null b:39!null c:40!null d:41!null + │ └── mapping: + │ ├── 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:33!null uniq_overlaps_pk.b:34!null uniq_overlaps_pk.c:35 uniq_overlaps_pk.d:36 + └── filters + ├── 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. @@ -419,36 +439,40 @@ update uniq_overlaps_pk │ └── other.crdb_internal_mvcc_timestamp:17 └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(a) - │ └── semi-join (hash) - │ ├── columns: a:23 b:24!null c:25 d:26 - │ ├── with-scan &1 - │ │ ├── columns: a:23 b:24!null c:25 d:26 - │ │ └── mapping: - │ │ ├── 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:18!null uniq_overlaps_pk.b:19!null uniq_overlaps_pk.c:20 uniq_overlaps_pk.d:21 - │ └── filters - │ ├── a:23 = uniq_overlaps_pk.a:18 - │ └── b:24 != uniq_overlaps_pk.b:19 + │ └── project + │ ├── columns: a:23 + │ └── semi-join (hash) + │ ├── columns: a:23 b:24!null c:25 d:26 + │ ├── with-scan &1 + │ │ ├── columns: a:23 b:24!null c:25 d:26 + │ │ └── mapping: + │ │ ├── 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:18!null uniq_overlaps_pk.b:19!null uniq_overlaps_pk.c:20 uniq_overlaps_pk.d:21 + │ └── filters + │ ├── 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: a:32 b:33!null c:34 d:35 - ├── with-scan &1 - │ ├── columns: a:32 b:33!null c:34 d:35 - │ └── mapping: - │ ├── 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:27!null uniq_overlaps_pk.b:28!null uniq_overlaps_pk.c:29 uniq_overlaps_pk.d:30 - └── filters - ├── 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) + └── project + ├── columns: c:34 + └── semi-join (hash) + ├── columns: a:32 b:33!null c:34 d:35 + ├── with-scan &1 + │ ├── columns: a:32 b:33!null c:34 d:35 + │ └── mapping: + │ ├── 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:27!null uniq_overlaps_pk.b:28!null uniq_overlaps_pk.c:29 uniq_overlaps_pk.d:30 + └── filters + ├── 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 ( @@ -482,39 +506,43 @@ update uniq_hidden_pk │ └── 1 [as=a_new:13] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(a,b,d) - │ └── semi-join (hash) - │ ├── columns: a:20!null b:21 c:22 d:23 rowid:24!null - │ ├── with-scan &1 - │ │ ├── columns: a:20!null b:21 c:22 d:23 rowid:24!null - │ │ └── mapping: - │ │ ├── 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:14 uniq_hidden_pk.b:15 uniq_hidden_pk.c:16 uniq_hidden_pk.d:17 uniq_hidden_pk.rowid:18!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:20!null + │ └── semi-join (hash) + │ ├── columns: a:20!null b:21 c:22 d:23 rowid:24!null + │ ├── with-scan &1 + │ │ ├── columns: a:20!null b:21 c:22 d:23 rowid:24!null + │ │ └── mapping: + │ │ ├── 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:14 uniq_hidden_pk.b:15 uniq_hidden_pk.c:16 uniq_hidden_pk.d:17 uniq_hidden_pk.rowid:18!null + │ └── filters + │ ├── 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:31!null b:32 c:33 d:34 rowid:35!null - ├── with-scan &1 - │ ├── columns: a:31!null b:32 c:33 d:34 rowid:35!null - │ └── mapping: - │ ├── 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:25 uniq_hidden_pk.b:26 uniq_hidden_pk.c:27 uniq_hidden_pk.d:28 uniq_hidden_pk.rowid:29!null - └── filters - ├── a:31 = uniq_hidden_pk.a:25 - └── rowid:35 != uniq_hidden_pk.rowid:29 + └── project + ├── columns: a:31!null + └── semi-join (hash) + ├── columns: a:31!null b:32 c:33 d:34 rowid:35!null + ├── with-scan &1 + │ ├── columns: a:31!null b:32 c:33 d:34 rowid:35!null + │ └── mapping: + │ ├── 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:25 uniq_hidden_pk.b:26 uniq_hidden_pk.c:27 uniq_hidden_pk.d:28 uniq_hidden_pk.rowid:29!null + └── filters + ├── 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. @@ -537,39 +565,43 @@ update uniq_hidden_pk │ └── filters (true) └── unique-checks ├── unique-checks-item: uniq_hidden_pk(a,b,d) - │ └── semi-join (hash) - │ ├── columns: a:26 b:27 c:28 d:29 rowid:30!null - │ ├── with-scan &1 - │ │ ├── columns: a:26 b:27 c:28 d:29 rowid:30!null - │ │ └── mapping: - │ │ ├── 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:20 uniq_hidden_pk.b:21 uniq_hidden_pk.c:22 uniq_hidden_pk.d:23 uniq_hidden_pk.rowid:24!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:26 + │ └── semi-join (hash) + │ ├── columns: a:26 b:27 c:28 d:29 rowid:30!null + │ ├── with-scan &1 + │ │ ├── columns: a:26 b:27 c:28 d:29 rowid:30!null + │ │ └── mapping: + │ │ ├── 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:20 uniq_hidden_pk.b:21 uniq_hidden_pk.c:22 uniq_hidden_pk.d:23 uniq_hidden_pk.rowid:24!null + │ └── filters + │ ├── 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:37 b:38 c:39 d:40 rowid:41!null - ├── with-scan &1 - │ ├── columns: a:37 b:38 c:39 d:40 rowid:41!null - │ └── mapping: - │ ├── 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:31 uniq_hidden_pk.b:32 uniq_hidden_pk.c:33 uniq_hidden_pk.d:34 uniq_hidden_pk.rowid:35!null - └── filters - ├── a:37 = uniq_hidden_pk.a:31 - └── rowid:41 != uniq_hidden_pk.rowid:35 + └── project + ├── columns: a:37 + └── semi-join (hash) + ├── columns: a:37 b:38 c:39 d:40 rowid:41!null + ├── with-scan &1 + │ ├── columns: a:37 b:38 c:39 d:40 rowid:41!null + │ └── mapping: + │ ├── 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:31 uniq_hidden_pk.b:32 uniq_hidden_pk.c:33 uniq_hidden_pk.d:34 uniq_hidden_pk.rowid:35!null + └── filters + ├── a:37 = uniq_hidden_pk.a:31 + └── rowid:41 != uniq_hidden_pk.rowid:35 exec-ddl CREATE TABLE uniq_partial ( @@ -599,22 +631,24 @@ update uniq_partial │ └── 1 [as=a_new:11] └── unique-checks └── unique-checks-item: uniq_partial(a) - └── semi-join (hash) - ├── columns: k:17!null a:18!null b:19 c:20 - ├── with-scan &1 - │ ├── columns: k:17!null a:18!null b:19 c:20 - │ └── mapping: - │ ├── uniq_partial.k:6 => k:17 - │ ├── a_new:11 => a:18 - │ ├── uniq_partial.b:8 => b:19 - │ └── uniq_partial.c:9 => c:20 - ├── scan uniq_partial - │ └── columns: uniq_partial.k:12!null uniq_partial.a:13 uniq_partial.b:14 uniq_partial.c:15 - └── filters - ├── a:18 = uniq_partial.a:13 - ├── b:19 > 0 - ├── uniq_partial.b:14 > 0 - └── k:17 != uniq_partial.k:12 + └── project + ├── columns: a:18!null + └── semi-join (hash) + ├── columns: k:17!null a:18!null b:19 c:20 + ├── with-scan &1 + │ ├── columns: k:17!null a:18!null b:19 c:20 + │ └── mapping: + │ ├── uniq_partial.k:6 => k:17 + │ ├── a_new:11 => a:18 + │ ├── uniq_partial.b:8 => b:19 + │ └── uniq_partial.c:9 => c:20 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:12!null uniq_partial.a:13 uniq_partial.b:14 uniq_partial.c:15 + └── filters + ├── a:18 = uniq_partial.a:13 + ├── b:19 > 0 + ├── uniq_partial.b:14 > 0 + └── k:17 != uniq_partial.k:12 # Plan a check when a column in the predicate is updated. build @@ -634,22 +668,24 @@ update uniq_partial │ └── 1 [as=b_new:11] └── unique-checks └── unique-checks-item: uniq_partial(a) - └── semi-join (hash) - ├── columns: k:17!null a:18 b:19!null c:20 - ├── with-scan &1 - │ ├── columns: k:17!null a:18 b:19!null c:20 - │ └── mapping: - │ ├── uniq_partial.k:6 => k:17 - │ ├── uniq_partial.a:7 => a:18 - │ ├── b_new:11 => b:19 - │ └── uniq_partial.c:9 => c:20 - ├── scan uniq_partial - │ └── columns: uniq_partial.k:12!null uniq_partial.a:13 uniq_partial.b:14 uniq_partial.c:15 - └── filters - ├── a:18 = uniq_partial.a:13 - ├── b:19 > 0 - ├── uniq_partial.b:14 > 0 - └── k:17 != uniq_partial.k:12 + └── project + ├── columns: a:18 + └── semi-join (hash) + ├── columns: k:17!null a:18 b:19!null c:20 + ├── with-scan &1 + │ ├── columns: k:17!null a:18 b:19!null c:20 + │ └── mapping: + │ ├── uniq_partial.k:6 => k:17 + │ ├── uniq_partial.a:7 => a:18 + │ ├── b_new:11 => b:19 + │ └── uniq_partial.c:9 => c:20 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:12!null uniq_partial.a:13 uniq_partial.b:14 uniq_partial.c:15 + └── filters + ├── a:18 = uniq_partial.a:13 + ├── b:19 > 0 + ├── uniq_partial.b:14 > 0 + └── k:17 != uniq_partial.k:12 # No need to plan checks for a since it's always null. build @@ -752,22 +788,24 @@ update uniq_partial │ └── other.crdb_internal_mvcc_timestamp:17 └── unique-checks └── unique-checks-item: uniq_partial(a) - └── semi-join (hash) - ├── columns: k:23!null a:24!null b:25 c:26 - ├── with-scan &1 - │ ├── columns: k:23!null a:24!null b:25 c:26 - │ └── mapping: - │ ├── uniq_partial.k:6 => k:23 - │ ├── w:13 => a:24 - │ ├── x:14 => b:25 - │ └── uniq_partial.c:9 => c:26 - ├── scan uniq_partial - │ └── columns: uniq_partial.k:18!null uniq_partial.a:19 uniq_partial.b:20 uniq_partial.c:21 - └── filters - ├── a:24 = uniq_partial.a:19 - ├── b:25 > 0 - ├── uniq_partial.b:20 > 0 - └── k:23 != uniq_partial.k:18 + └── project + ├── columns: a:24!null + └── semi-join (hash) + ├── columns: k:23!null a:24!null b:25 c:26 + ├── with-scan &1 + │ ├── columns: k:23!null a:24!null b:25 c:26 + │ └── mapping: + │ ├── uniq_partial.k:6 => k:23 + │ ├── w:13 => a:24 + │ ├── x:14 => b:25 + │ └── uniq_partial.c:9 => c:26 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:18!null uniq_partial.a:19 uniq_partial.b:20 uniq_partial.c:21 + └── filters + ├── a:24 = uniq_partial.a:19 + ├── b:25 > 0 + ├── uniq_partial.b:20 > 0 + └── k:23 != uniq_partial.k:18 exec-ddl CREATE TABLE uniq_partial_overlaps_pk ( @@ -816,57 +854,63 @@ update uniq_partial_overlaps_pk │ └── 4 [as=d_new:14] └── unique-checks ├── unique-checks-item: uniq_partial_overlaps_pk(c) - │ └── semi-join (hash) - │ ├── columns: a:20!null b:21!null c:22!null d:23!null - │ ├── with-scan &1 - │ │ ├── columns: a:20!null b:21!null c:22!null d:23!null - │ │ └── mapping: - │ │ ├── a_new:11 => a:20 - │ │ ├── b_new:12 => b:21 - │ │ ├── c_new:13 => c:22 - │ │ └── d_new:14 => d:23 - │ ├── scan uniq_partial_overlaps_pk - │ │ └── columns: uniq_partial_overlaps_pk.a:15!null uniq_partial_overlaps_pk.b:16!null uniq_partial_overlaps_pk.c:17 uniq_partial_overlaps_pk.d:18 - │ └── filters - │ ├── c:22 = uniq_partial_overlaps_pk.c:17 - │ ├── d:23 > 0 - │ ├── uniq_partial_overlaps_pk.d:18 > 0 - │ └── (a:20 != uniq_partial_overlaps_pk.a:15) OR (b:21 != uniq_partial_overlaps_pk.b:16) + │ └── project + │ ├── columns: c:22!null + │ └── semi-join (hash) + │ ├── columns: a:20!null b:21!null c:22!null d:23!null + │ ├── with-scan &1 + │ │ ├── columns: a:20!null b:21!null c:22!null d:23!null + │ │ └── mapping: + │ │ ├── a_new:11 => a:20 + │ │ ├── b_new:12 => b:21 + │ │ ├── c_new:13 => c:22 + │ │ └── d_new:14 => d:23 + │ ├── scan uniq_partial_overlaps_pk + │ │ └── columns: uniq_partial_overlaps_pk.a:15!null uniq_partial_overlaps_pk.b:16!null uniq_partial_overlaps_pk.c:17 uniq_partial_overlaps_pk.d:18 + │ └── filters + │ ├── c:22 = uniq_partial_overlaps_pk.c:17 + │ ├── d:23 > 0 + │ ├── uniq_partial_overlaps_pk.d:18 > 0 + │ └── (a:20 != uniq_partial_overlaps_pk.a:15) OR (b:21 != uniq_partial_overlaps_pk.b:16) ├── unique-checks-item: uniq_partial_overlaps_pk(a) - │ └── semi-join (hash) - │ ├── columns: a:29!null b:30!null c:31!null d:32!null - │ ├── with-scan &1 - │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null - │ │ └── mapping: - │ │ ├── a_new:11 => a:29 - │ │ ├── b_new:12 => b:30 - │ │ ├── c_new:13 => c:31 - │ │ └── d_new:14 => d:32 - │ ├── scan uniq_partial_overlaps_pk - │ │ └── columns: uniq_partial_overlaps_pk.a:24!null uniq_partial_overlaps_pk.b:25!null uniq_partial_overlaps_pk.c:26 uniq_partial_overlaps_pk.d:27 - │ └── filters - │ ├── a:29 = uniq_partial_overlaps_pk.a:24 - │ ├── d:32 > 0 - │ ├── uniq_partial_overlaps_pk.d:27 > 0 - │ └── b:30 != uniq_partial_overlaps_pk.b:25 + │ └── project + │ ├── columns: a:29!null + │ └── semi-join (hash) + │ ├── columns: a:29!null b:30!null c:31!null d:32!null + │ ├── with-scan &1 + │ │ ├── columns: a:29!null b:30!null c:31!null d:32!null + │ │ └── mapping: + │ │ ├── a_new:11 => a:29 + │ │ ├── b_new:12 => b:30 + │ │ ├── c_new:13 => c:31 + │ │ └── d_new:14 => d:32 + │ ├── scan uniq_partial_overlaps_pk + │ │ └── columns: uniq_partial_overlaps_pk.a:24!null uniq_partial_overlaps_pk.b:25!null uniq_partial_overlaps_pk.c:26 uniq_partial_overlaps_pk.d:27 + │ └── filters + │ ├── a:29 = uniq_partial_overlaps_pk.a:24 + │ ├── d:32 > 0 + │ ├── uniq_partial_overlaps_pk.d:27 > 0 + │ └── b:30 != uniq_partial_overlaps_pk.b:25 └── unique-checks-item: uniq_partial_overlaps_pk(b,c) - └── semi-join (hash) - ├── columns: a:38!null b:39!null c:40!null d:41!null - ├── with-scan &1 - │ ├── columns: a:38!null b:39!null c:40!null d:41!null - │ └── mapping: - │ ├── a_new:11 => a:38 - │ ├── b_new:12 => b:39 - │ ├── c_new:13 => c:40 - │ └── d_new:14 => d:41 - ├── scan uniq_partial_overlaps_pk - │ └── columns: uniq_partial_overlaps_pk.a:33!null uniq_partial_overlaps_pk.b:34!null uniq_partial_overlaps_pk.c:35 uniq_partial_overlaps_pk.d:36 - └── filters - ├── b:39 = uniq_partial_overlaps_pk.b:34 - ├── c:40 = uniq_partial_overlaps_pk.c:35 - ├── d:41 > 0 - ├── uniq_partial_overlaps_pk.d:36 > 0 - └── a:38 != uniq_partial_overlaps_pk.a:33 + └── project + ├── columns: b:39!null + └── semi-join (hash) + ├── columns: a:38!null b:39!null c:40!null d:41!null + ├── with-scan &1 + │ ├── columns: a:38!null b:39!null c:40!null d:41!null + │ └── mapping: + │ ├── a_new:11 => a:38 + │ ├── b_new:12 => b:39 + │ ├── c_new:13 => c:40 + │ └── d_new:14 => d:41 + ├── scan uniq_partial_overlaps_pk + │ └── columns: uniq_partial_overlaps_pk.a:33!null uniq_partial_overlaps_pk.b:34!null uniq_partial_overlaps_pk.c:35 uniq_partial_overlaps_pk.d:36 + └── filters + ├── b:39 = uniq_partial_overlaps_pk.b:34 + ├── c:40 = uniq_partial_overlaps_pk.c:35 + ├── d:41 > 0 + ├── uniq_partial_overlaps_pk.d:36 > 0 + └── a:38 != uniq_partial_overlaps_pk.a:33 # Update with non-constant input. # Do not build uniqueness checks when the primary key columns are a subset of @@ -916,22 +960,24 @@ update uniq_partial_overlaps_pk │ └── other.crdb_internal_mvcc_timestamp:17 └── unique-checks └── unique-checks-item: uniq_partial_overlaps_pk(a) - └── semi-join (hash) - ├── columns: a:23 b:24!null c:25 d:26 - ├── with-scan &1 - │ ├── columns: a:23 b:24!null c:25 d:26 - │ └── mapping: - │ ├── k:11 => a:23 - │ ├── uniq_partial_overlaps_pk.b:7 => b:24 - │ ├── uniq_partial_overlaps_pk.c:8 => c:25 - │ └── uniq_partial_overlaps_pk.d:9 => d:26 - ├── scan uniq_partial_overlaps_pk - │ └── columns: uniq_partial_overlaps_pk.a:18!null uniq_partial_overlaps_pk.b:19!null uniq_partial_overlaps_pk.c:20 uniq_partial_overlaps_pk.d:21 - └── filters - ├── a:23 = uniq_partial_overlaps_pk.a:18 - ├── d:26 > 0 - ├── uniq_partial_overlaps_pk.d:21 > 0 - └── b:24 != uniq_partial_overlaps_pk.b:19 + └── project + ├── columns: a:23 + └── semi-join (hash) + ├── columns: a:23 b:24!null c:25 d:26 + ├── with-scan &1 + │ ├── columns: a:23 b:24!null c:25 d:26 + │ └── mapping: + │ ├── k:11 => a:23 + │ ├── uniq_partial_overlaps_pk.b:7 => b:24 + │ ├── uniq_partial_overlaps_pk.c:8 => c:25 + │ └── uniq_partial_overlaps_pk.d:9 => d:26 + ├── scan uniq_partial_overlaps_pk + │ └── columns: uniq_partial_overlaps_pk.a:18!null uniq_partial_overlaps_pk.b:19!null uniq_partial_overlaps_pk.c:20 uniq_partial_overlaps_pk.d:21 + └── filters + ├── a:23 = uniq_partial_overlaps_pk.a:18 + ├── d:26 > 0 + ├── uniq_partial_overlaps_pk.d:21 > 0 + └── b:24 != uniq_partial_overlaps_pk.b:19 exec-ddl CREATE TABLE uniq_partial_hidden_pk ( @@ -960,21 +1006,23 @@ update uniq_partial_hidden_pk │ └── 1 [as=a_new:9] └── unique-checks └── unique-checks-item: uniq_partial_hidden_pk(a) - └── semi-join (hash) - ├── columns: a:14!null b:15 rowid:16!null - ├── with-scan &1 - │ ├── columns: a:14!null b:15 rowid:16!null - │ └── mapping: - │ ├── a_new:9 => a:14 - │ ├── uniq_partial_hidden_pk.b:6 => b:15 - │ └── uniq_partial_hidden_pk.rowid:7 => rowid:16 - ├── scan uniq_partial_hidden_pk - │ └── columns: uniq_partial_hidden_pk.a:10 uniq_partial_hidden_pk.b:11 uniq_partial_hidden_pk.rowid:12!null - └── filters - ├── a:14 = uniq_partial_hidden_pk.a:10 - ├── b:15 > 0 - ├── uniq_partial_hidden_pk.b:11 > 0 - └── rowid:16 != uniq_partial_hidden_pk.rowid:12 + └── project + ├── columns: a:14!null + └── semi-join (hash) + ├── columns: a:14!null b:15 rowid:16!null + ├── with-scan &1 + │ ├── columns: a:14!null b:15 rowid:16!null + │ └── mapping: + │ ├── a_new:9 => a:14 + │ ├── uniq_partial_hidden_pk.b:6 => b:15 + │ └── uniq_partial_hidden_pk.rowid:7 => rowid:16 + ├── scan uniq_partial_hidden_pk + │ └── columns: uniq_partial_hidden_pk.a:10 uniq_partial_hidden_pk.b:11 uniq_partial_hidden_pk.rowid:12!null + └── filters + ├── a:14 = uniq_partial_hidden_pk.a:10 + ├── b:15 > 0 + ├── uniq_partial_hidden_pk.b:11 > 0 + └── rowid:16 != uniq_partial_hidden_pk.rowid:12 # Update with non-constant input. # Add inequality filters for the hidden primary key column. @@ -996,21 +1044,23 @@ update uniq_partial_hidden_pk │ └── filters (true) └── unique-checks └── unique-checks-item: uniq_partial_hidden_pk(a) - └── semi-join (hash) - ├── columns: a:20 b:21 rowid:22!null - ├── with-scan &1 - │ ├── columns: a:20 b:21 rowid:22!null - │ └── mapping: - │ ├── k:9 => a:20 - │ ├── uniq_partial_hidden_pk.b:6 => b:21 - │ └── uniq_partial_hidden_pk.rowid:7 => rowid:22 - ├── scan uniq_partial_hidden_pk - │ └── columns: uniq_partial_hidden_pk.a:16 uniq_partial_hidden_pk.b:17 uniq_partial_hidden_pk.rowid:18!null - └── filters - ├── a:20 = uniq_partial_hidden_pk.a:16 - ├── b:21 > 0 - ├── uniq_partial_hidden_pk.b:17 > 0 - └── rowid:22 != uniq_partial_hidden_pk.rowid:18 + └── project + ├── columns: a:20 + └── semi-join (hash) + ├── columns: a:20 b:21 rowid:22!null + ├── with-scan &1 + │ ├── columns: a:20 b:21 rowid:22!null + │ └── mapping: + │ ├── k:9 => a:20 + │ ├── uniq_partial_hidden_pk.b:6 => b:21 + │ └── uniq_partial_hidden_pk.rowid:7 => rowid:22 + ├── scan uniq_partial_hidden_pk + │ └── columns: uniq_partial_hidden_pk.a:16 uniq_partial_hidden_pk.b:17 uniq_partial_hidden_pk.rowid:18!null + └── filters + ├── a:20 = uniq_partial_hidden_pk.a:16 + ├── b:21 > 0 + ├── uniq_partial_hidden_pk.b:17 > 0 + └── rowid:22 != uniq_partial_hidden_pk.rowid:18 exec-ddl CREATE TABLE uniq_computed_pk ( @@ -1076,33 +1126,35 @@ update uniq_computed_pk │ └── d_new:19::STRING [as=column21:21] └── unique-checks └── unique-checks-item: uniq_computed_pk(d) - └── semi-join (hash) - ├── columns: i:46!null s:47!null d:48!null c_i_expr:49!null c_s:50!null c_d:51!null c_d_expr:52!null - ├── with-scan &1 - │ ├── columns: i:46!null s:47!null d:48!null c_i_expr:49!null c_s:50!null c_d:51!null c_d_expr:52!null - │ └── mapping: - │ ├── i_new:17 => i:46 - │ ├── s_new:18 => s:47 - │ ├── d_new:19 => d:48 - │ ├── column20:20 => c_i_expr:49 - │ ├── s_new:18 => c_s:50 - │ ├── d_new:19 => c_d:51 - │ └── column21:21 => c_d_expr:52 - ├── project - │ ├── columns: uniq_computed_pk.c_s:42 uniq_computed_pk.i:38!null uniq_computed_pk.s:39 uniq_computed_pk.d:40 uniq_computed_pk.c_i_expr:41!null uniq_computed_pk.c_d:43 uniq_computed_pk.c_d_expr:44 - │ ├── scan uniq_computed_pk - │ │ ├── columns: uniq_computed_pk.i:38!null uniq_computed_pk.s:39 uniq_computed_pk.d:40 uniq_computed_pk.c_i_expr:41!null uniq_computed_pk.c_d:43 uniq_computed_pk.c_d_expr:44 - │ │ └── computed column expressions - │ │ ├── uniq_computed_pk.c_i_expr:41 - │ │ │ └── CASE WHEN uniq_computed_pk.i:38 < 0 THEN 'foo' ELSE 'bar' END - │ │ ├── uniq_computed_pk.c_s:42 - │ │ │ └── uniq_computed_pk.s:39 - │ │ ├── uniq_computed_pk.c_d:43 - │ │ │ └── uniq_computed_pk.d:40 - │ │ └── uniq_computed_pk.c_d_expr:44 - │ │ └── uniq_computed_pk.d:40::STRING - │ └── projections - │ └── uniq_computed_pk.s:39 [as=uniq_computed_pk.c_s:42] - └── filters - ├── d:48 = uniq_computed_pk.d:40 - └── (i:46 != uniq_computed_pk.i:38) OR (c_i_expr:49 != uniq_computed_pk.c_i_expr:41) + └── project + ├── columns: d:48!null + └── semi-join (hash) + ├── columns: i:46!null s:47!null d:48!null c_i_expr:49!null c_s:50!null c_d:51!null c_d_expr:52!null + ├── with-scan &1 + │ ├── columns: i:46!null s:47!null d:48!null c_i_expr:49!null c_s:50!null c_d:51!null c_d_expr:52!null + │ └── mapping: + │ ├── i_new:17 => i:46 + │ ├── s_new:18 => s:47 + │ ├── d_new:19 => d:48 + │ ├── column20:20 => c_i_expr:49 + │ ├── s_new:18 => c_s:50 + │ ├── d_new:19 => c_d:51 + │ └── column21:21 => c_d_expr:52 + ├── project + │ ├── columns: uniq_computed_pk.c_s:42 uniq_computed_pk.i:38!null uniq_computed_pk.s:39 uniq_computed_pk.d:40 uniq_computed_pk.c_i_expr:41!null uniq_computed_pk.c_d:43 uniq_computed_pk.c_d_expr:44 + │ ├── scan uniq_computed_pk + │ │ ├── columns: uniq_computed_pk.i:38!null uniq_computed_pk.s:39 uniq_computed_pk.d:40 uniq_computed_pk.c_i_expr:41!null uniq_computed_pk.c_d:43 uniq_computed_pk.c_d_expr:44 + │ │ └── computed column expressions + │ │ ├── uniq_computed_pk.c_i_expr:41 + │ │ │ └── CASE WHEN uniq_computed_pk.i:38 < 0 THEN 'foo' ELSE 'bar' END + │ │ ├── uniq_computed_pk.c_s:42 + │ │ │ └── uniq_computed_pk.s:39 + │ │ ├── uniq_computed_pk.c_d:43 + │ │ │ └── uniq_computed_pk.d:40 + │ │ └── uniq_computed_pk.c_d_expr:44 + │ │ └── uniq_computed_pk.d:40::STRING + │ └── projections + │ └── uniq_computed_pk.s:39 [as=uniq_computed_pk.c_s:42] + └── filters + ├── d:48 = uniq_computed_pk.d:40 + └── (i:46 != uniq_computed_pk.i:38) OR (c_i_expr:49 != uniq_computed_pk.c_i_expr:41) diff --git a/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert b/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert index 0ce52179b695..cbf268f42675 100644 --- a/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert +++ b/pkg/sql/opt/optbuilder/testdata/unique-checks-upsert @@ -62,38 +62,42 @@ upsert uniq │ └── 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: k:25 v:26!null w:27!null x:28!null y:29!null - │ ├── with-scan &1 - │ │ ├── columns: k:25 v:26!null w:27!null x:28!null y:29!null - │ │ └── mapping: - │ │ ├── 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:19!null uniq.v:20 uniq.w:21 uniq.x:22 uniq.y:23 - │ └── filters - │ ├── w:27 = uniq.w:21 - │ └── k:25 != uniq.k:19 + │ └── project + │ ├── columns: w:27!null + │ └── semi-join (hash) + │ ├── columns: k:25 v:26!null w:27!null x:28!null y:29!null + │ ├── with-scan &1 + │ │ ├── columns: k:25 v:26!null w:27!null x:28!null y:29!null + │ │ └── mapping: + │ │ ├── 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:19!null uniq.v:20 uniq.w:21 uniq.x:22 uniq.y:23 + │ └── filters + │ ├── w:27 = uniq.w:21 + │ └── k:25 != uniq.k:19 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:36 v:37!null w:38!null x:39!null y:40!null - ├── with-scan &1 - │ ├── columns: k:36 v:37!null w:38!null x:39!null y:40!null - │ └── mapping: - │ ├── 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.v:31 uniq.w:32 uniq.x:33 uniq.y:34 - └── filters - ├── x:39 = uniq.x:33 - ├── y:40 = uniq.y:34 - └── k:36 != uniq.k:30 + └── project + ├── columns: x:39!null + └── semi-join (hash) + ├── columns: k:36 v:37!null w:38!null x:39!null y:40!null + ├── with-scan &1 + │ ├── columns: k:36 v:37!null w:38!null x:39!null y:40!null + │ └── mapping: + │ ├── 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.v:31 uniq.w:32 uniq.x:33 uniq.y:34 + └── filters + ├── 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). @@ -150,38 +154,42 @@ upsert uniq │ └── 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: k:27 v:28!null w:29!null x:30 y:31 - │ ├── with-scan &1 - │ │ ├── columns: k:27 v:28!null w:29!null x:30 y:31 - │ │ └── mapping: - │ │ ├── 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:21!null uniq.v:22 uniq.w:23 uniq.x:24 uniq.y:25 - │ └── filters - │ ├── w:29 = uniq.w:23 - │ └── k:27 != uniq.k:21 + │ └── project + │ ├── columns: w:29!null + │ └── semi-join (hash) + │ ├── columns: k:27 v:28!null w:29!null x:30 y:31 + │ ├── with-scan &1 + │ │ ├── columns: k:27 v:28!null w:29!null x:30 y:31 + │ │ └── mapping: + │ │ ├── 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:21!null uniq.v:22 uniq.w:23 uniq.x:24 uniq.y:25 + │ └── filters + │ ├── w:29 = uniq.w:23 + │ └── k:27 != uniq.k:21 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:38 v:39!null w:40!null x:41 y:42 - ├── with-scan &1 - │ ├── columns: k:38 v:39!null w:40!null x:41 y:42 - │ └── mapping: - │ ├── 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.v:33 uniq.w:34 uniq.x:35 uniq.y:36 - └── filters - ├── x:41 = uniq.x:35 - ├── y:42 = uniq.y:36 - └── k:38 != uniq.k:32 + └── project + ├── columns: x:41 + └── semi-join (hash) + ├── columns: k:38 v:39!null w:40!null x:41 y:42 + ├── with-scan &1 + │ ├── columns: k:38 v:39!null w:40!null x:41 y:42 + │ └── mapping: + │ ├── 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.v:33 uniq.w:34 uniq.x:35 uniq.y:36 + └── filters + ├── 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 always NULL. # We currently can't determine that w is always NULL since the function @@ -239,38 +247,42 @@ upsert uniq │ └── 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: k:27 v:28 w:29 x:30 y:31 - │ ├── with-scan &1 - │ │ ├── columns: k:27 v:28 w:29 x:30 y:31 - │ │ └── mapping: - │ │ ├── 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:21!null uniq.v:22 uniq.w:23 uniq.x:24 uniq.y:25 - │ └── filters - │ ├── w:29 = uniq.w:23 - │ └── k:27 != uniq.k:21 + │ └── project + │ ├── columns: w:29 + │ └── semi-join (hash) + │ ├── columns: k:27 v:28 w:29 x:30 y:31 + │ ├── with-scan &1 + │ │ ├── columns: k:27 v:28 w:29 x:30 y:31 + │ │ └── mapping: + │ │ ├── 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:21!null uniq.v:22 uniq.w:23 uniq.x:24 uniq.y:25 + │ └── filters + │ ├── w:29 = uniq.w:23 + │ └── k:27 != uniq.k:21 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:38 v:39 w:40 x:41 y:42 - ├── with-scan &1 - │ ├── columns: k:38 v:39 w:40 x:41 y:42 - │ └── mapping: - │ ├── 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.v:33 uniq.w:34 uniq.x:35 uniq.y:36 - └── filters - ├── x:41 = uniq.x:35 - ├── y:42 = uniq.y:36 - └── k:38 != uniq.k:32 + └── project + ├── columns: x:41 + └── semi-join (hash) + ├── columns: k:38 v:39 w:40 x:41 y:42 + ├── with-scan &1 + │ ├── columns: k:38 v:39 w:40 x:41 y:42 + │ └── mapping: + │ ├── 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.v:33 uniq.w:34 uniq.x:35 uniq.y:36 + └── filters + ├── 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 @@ -328,38 +340,42 @@ upsert uniq │ └── CASE WHEN uniq.k:16 IS NULL THEN other.k:7 ELSE uniq.k:16 END [as=upsert_k:22] └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:29 v:30 w:31!null x:32 y:33!null - │ ├── with-scan &1 - │ │ ├── columns: k:29 v:30 w:31!null x:32 y:33!null - │ │ └── mapping: - │ │ ├── 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:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 - │ └── filters - │ ├── w:31 = uniq.w:25 - │ └── k:29 != uniq.k:23 + │ └── project + │ ├── columns: w:31!null + │ └── semi-join (hash) + │ ├── columns: k:29 v:30 w:31!null x:32 y:33!null + │ ├── with-scan &1 + │ │ ├── columns: k:29 v:30 w:31!null x:32 y:33!null + │ │ └── mapping: + │ │ ├── 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:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 + │ └── filters + │ ├── w:31 = uniq.w:25 + │ └── k:29 != uniq.k:23 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:40 v:41 w:42!null x:43 y:44!null - ├── with-scan &1 - │ ├── columns: k:40 v:41 w:42!null x:43 y:44!null - │ └── mapping: - │ ├── 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.v:35 uniq.w:36 uniq.x:37 uniq.y:38 - └── filters - ├── x:43 = uniq.x:37 - ├── y:44 = uniq.y:38 - └── k:40 != uniq.k:34 + └── project + ├── columns: x:43 + └── semi-join (hash) + ├── columns: k:40 v:41 w:42!null x:43 y:44!null + ├── with-scan &1 + │ ├── columns: k:40 v:41 w:42!null x:43 y:44!null + │ └── mapping: + │ ├── 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.v:35 uniq.w:36 uniq.x:37 uniq.y:38 + └── filters + ├── 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 @@ -421,38 +437,42 @@ upsert uniq │ └── 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: k:29 v:30 w:31 x:32 y:33 - │ ├── with-scan &1 - │ │ ├── columns: k:29 v:30 w:31 x:32 y:33 - │ │ └── mapping: - │ │ ├── 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:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 - │ └── filters - │ ├── w:31 = uniq.w:25 - │ └── k:29 != uniq.k:23 + │ └── project + │ ├── columns: w:31 + │ └── semi-join (hash) + │ ├── columns: k:29 v:30 w:31 x:32 y:33 + │ ├── with-scan &1 + │ │ ├── columns: k:29 v:30 w:31 x:32 y:33 + │ │ └── mapping: + │ │ ├── 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:23!null uniq.v:24 uniq.w:25 uniq.x:26 uniq.y:27 + │ └── filters + │ ├── w:31 = uniq.w:25 + │ └── k:29 != uniq.k:23 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:40 v:41 w:42 x:43 y:44 - ├── with-scan &1 - │ ├── columns: k:40 v:41 w:42 x:43 y:44 - │ └── mapping: - │ ├── 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.v:35 uniq.w:36 uniq.x:37 uniq.y:38 - └── filters - ├── x:43 = uniq.x:37 - ├── y:44 = uniq.y:38 - └── k:40 != uniq.k:34 + └── project + ├── columns: x:43 + └── semi-join (hash) + ├── columns: k:40 v:41 w:42 x:43 y:44 + ├── with-scan &1 + │ ├── columns: k:40 v:41 w:42 x:43 y:44 + │ └── mapping: + │ ├── 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.v:35 uniq.w:36 uniq.x:37 uniq.y:38 + └── filters + ├── 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 @@ -513,38 +533,42 @@ upsert uniq │ └── CASE WHEN uniq.k:16 IS NULL THEN column15:15 ELSE uniq.y:20 END [as=upsert_y:27] └── unique-checks ├── unique-checks-item: uniq(w) - │ └── semi-join (hash) - │ ├── columns: k:34 v:35 w:36 x:37 y:38 - │ ├── with-scan &1 - │ │ ├── columns: k:34 v:35 w:36 x:37 y:38 - │ │ └── mapping: - │ │ ├── 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:28!null uniq.v:29 uniq.w:30 uniq.x:31 uniq.y:32 - │ └── filters - │ ├── w:36 = uniq.w:30 - │ └── k:34 != uniq.k:28 + │ └── project + │ ├── columns: w:36 + │ └── semi-join (hash) + │ ├── columns: k:34 v:35 w:36 x:37 y:38 + │ ├── with-scan &1 + │ │ ├── columns: k:34 v:35 w:36 x:37 y:38 + │ │ └── mapping: + │ │ ├── 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:28!null uniq.v:29 uniq.w:30 uniq.x:31 uniq.y:32 + │ └── filters + │ ├── w:36 = uniq.w:30 + │ └── k:34 != uniq.k:28 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:45 v:46 w:47 x:48 y:49 - ├── with-scan &1 - │ ├── columns: k:45 v:46 w:47 x:48 y:49 - │ └── mapping: - │ ├── 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.v:40 uniq.w:41 uniq.x:42 uniq.y:43 - └── filters - ├── x:48 = uniq.x:42 - ├── y:49 = uniq.y:43 - └── k:45 != uniq.k:39 + └── project + ├── columns: x:48 + └── semi-join (hash) + ├── columns: k:45 v:46 w:47 x:48 y:49 + ├── with-scan &1 + │ ├── columns: k:45 v:46 w:47 x:48 y:49 + │ └── mapping: + │ ├── 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.v:40 uniq.w:41 uniq.x:42 uniq.y:43 + └── filters + ├── 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. @@ -606,38 +630,42 @@ upsert uniq │ └── 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: k:30 v:31 w:32!null x:33 y:34 - │ ├── with-scan &1 - │ │ ├── columns: k:30 v:31 w:32!null x:33 y:34 - │ │ └── mapping: - │ │ ├── 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:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 - │ └── filters - │ ├── w:32 = uniq.w:26 - │ └── k:30 != uniq.k:24 + │ └── project + │ ├── columns: w:32!null + │ └── semi-join (hash) + │ ├── columns: k:30 v:31 w:32!null x:33 y:34 + │ ├── with-scan &1 + │ │ ├── columns: k:30 v:31 w:32!null x:33 y:34 + │ │ └── mapping: + │ │ ├── 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:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 + │ └── filters + │ ├── w:32 = uniq.w:26 + │ └── k:30 != uniq.k:24 └── unique-checks-item: uniq(x,y) - └── semi-join (hash) - ├── columns: k:41 v:42 w:43!null x:44 y:45 - ├── with-scan &1 - │ ├── columns: k:41 v:42 w:43!null x:44 y:45 - │ └── mapping: - │ ├── 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.v:36 uniq.w:37 uniq.x:38 uniq.y:39 - └── filters - ├── x:44 = uniq.x:38 - ├── y:45 = uniq.y:39 - └── k:41 != uniq.k:35 + └── project + ├── columns: x:44 + └── semi-join (hash) + ├── columns: k:41 v:42 w:43!null x:44 y:45 + ├── with-scan &1 + │ ├── columns: k:41 v:42 w:43!null x:44 y:45 + │ └── mapping: + │ ├── 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.v:36 uniq.w:37 uniq.x:38 uniq.y:39 + └── filters + ├── 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. @@ -692,21 +720,23 @@ upsert uniq │ └── 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: k:30 v:31!null w:32 x:33 y:34 - ├── with-scan &1 - │ ├── columns: k:30 v:31!null w:32 x:33 y:34 - │ └── mapping: - │ ├── 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:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 - └── filters - ├── w:32 = uniq.w:26 - └── k:30 != uniq.k:24 + └── project + ├── columns: w:32 + └── semi-join (hash) + ├── columns: k:30 v:31!null w:32 x:33 y:34 + ├── with-scan &1 + │ ├── columns: k:30 v:31!null w:32 x:33 y:34 + │ └── mapping: + │ ├── 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:24!null uniq.v:25 uniq.w:26 uniq.x:27 uniq.y:28 + └── filters + ├── w:32 = uniq.w:26 + └── k:30 != uniq.k:24 # Cannot conflict on a subset of columns in a unique constraint. build @@ -754,52 +784,58 @@ upsert uniq_overlaps_pk │ └── (2, 2, 2, 2) └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,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_overlaps_pk - │ │ └── 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:16 = uniq_overlaps_pk.b:11 - │ ├── c:17 = uniq_overlaps_pk.c:12 - │ └── a:15 != uniq_overlaps_pk.a:10 + │ └── project + │ ├── columns: b:16!null + │ └── 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_overlaps_pk + │ │ └── 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: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: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_overlaps_pk - │ │ └── 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:24 = uniq_overlaps_pk.a:19 - │ └── b:25 != uniq_overlaps_pk.b:20 + │ └── project + │ ├── columns: a:24!null + │ └── 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_overlaps_pk + │ │ └── 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: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: 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_overlaps_pk - │ └── 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: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) + └── project + ├── columns: c:35!null + └── 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_overlaps_pk + │ └── 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: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 @@ -826,36 +862,40 @@ upsert uniq_overlaps_pk │ └── NULL::INT8 [as=column13:13] └── unique-checks ├── unique-checks-item: uniq_overlaps_pk(b,c) - │ └── semi-join (hash) - │ ├── columns: a:19 b:20 c:21 d:22 - │ ├── with-scan &1 - │ │ ├── columns: a:19 b:20 c:21 d:22 - │ │ └── mapping: - │ │ ├── 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:14!null uniq_overlaps_pk.b:15!null uniq_overlaps_pk.c:16 uniq_overlaps_pk.d:17 - │ └── filters - │ ├── b:20 = uniq_overlaps_pk.b:15 - │ ├── c:21 = uniq_overlaps_pk.c:16 - │ └── a:19 != uniq_overlaps_pk.a:14 + │ └── project + │ ├── columns: b:20 + │ └── semi-join (hash) + │ ├── columns: a:19 b:20 c:21 d:22 + │ ├── with-scan &1 + │ │ ├── columns: a:19 b:20 c:21 d:22 + │ │ └── mapping: + │ │ ├── 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:14!null uniq_overlaps_pk.b:15!null uniq_overlaps_pk.c:16 uniq_overlaps_pk.d:17 + │ └── filters + │ ├── 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:28 b:29 c:30 d:31 - ├── with-scan &1 - │ ├── columns: a:28 b:29 c:30 d:31 - │ └── mapping: - │ ├── 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:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 uniq_overlaps_pk.d:26 - └── filters - ├── a:28 = uniq_overlaps_pk.a:23 - └── b:29 != uniq_overlaps_pk.b:24 + └── project + ├── columns: a:28 + └── semi-join (hash) + ├── columns: a:28 b:29 c:30 d:31 + ├── with-scan &1 + │ ├── columns: a:28 b:29 c:30 d:31 + │ └── mapping: + │ ├── 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:23!null uniq_overlaps_pk.b:24!null uniq_overlaps_pk.c:25 uniq_overlaps_pk.d:26 + └── filters + ├── 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. @@ -908,52 +948,58 @@ upsert uniq_overlaps_pk │ └── 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: a:25!null b:26 c:27 d:28 - │ ├── with-scan &1 - │ │ ├── columns: a:25!null b:26 c:27 d:28 - │ │ └── mapping: - │ │ ├── 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:20!null uniq_overlaps_pk.b:21!null uniq_overlaps_pk.c:22 uniq_overlaps_pk.d:23 - │ └── filters - │ ├── b:26 = uniq_overlaps_pk.b:21 - │ ├── c:27 = uniq_overlaps_pk.c:22 - │ └── a:25 != uniq_overlaps_pk.a:20 + │ └── project + │ ├── columns: b:26 + │ └── semi-join (hash) + │ ├── columns: a:25!null b:26 c:27 d:28 + │ ├── with-scan &1 + │ │ ├── columns: a:25!null b:26 c:27 d:28 + │ │ └── mapping: + │ │ ├── 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:20!null uniq_overlaps_pk.b:21!null uniq_overlaps_pk.c:22 uniq_overlaps_pk.d:23 + │ └── filters + │ ├── 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:34!null b:35 c:36 d:37 - │ ├── with-scan &1 - │ │ ├── columns: a:34!null b:35 c:36 d:37 - │ │ └── mapping: - │ │ ├── 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:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 - │ └── filters - │ ├── a:34 = uniq_overlaps_pk.a:29 - │ └── b:35 != uniq_overlaps_pk.b:30 + │ └── project + │ ├── columns: a:34!null + │ └── semi-join (hash) + │ ├── columns: a:34!null b:35 c:36 d:37 + │ ├── with-scan &1 + │ │ ├── columns: a:34!null b:35 c:36 d:37 + │ │ └── mapping: + │ │ ├── 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:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 + │ └── filters + │ ├── 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: a:43!null b:44 c:45 d:46 - ├── with-scan &1 - │ ├── columns: a:43!null b:44 c:45 d:46 - │ └── mapping: - │ ├── 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:38!null uniq_overlaps_pk.b:39!null uniq_overlaps_pk.c:40 uniq_overlaps_pk.d:41 - └── filters - ├── 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) + └── project + ├── columns: c:45 + └── semi-join (hash) + ├── columns: a:43!null b:44 c:45 d:46 + ├── with-scan &1 + │ ├── columns: a:43!null b:44 c:45 d:46 + │ └── mapping: + │ ├── 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:38!null uniq_overlaps_pk.b:39!null uniq_overlaps_pk.c:40 uniq_overlaps_pk.d:41 + └── filters + ├── 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. @@ -1004,36 +1050,40 @@ upsert uniq_overlaps_pk │ └── 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: a:25 b:26!null c:27 d:28 - │ ├── with-scan &1 - │ │ ├── columns: a:25 b:26!null c:27 d:28 - │ │ └── mapping: - │ │ ├── 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:20!null uniq_overlaps_pk.b:21!null uniq_overlaps_pk.c:22 uniq_overlaps_pk.d:23 - │ └── filters - │ ├── b:26 = uniq_overlaps_pk.b:21 - │ ├── c:27 = uniq_overlaps_pk.c:22 - │ └── a:25 != uniq_overlaps_pk.a:20 + │ └── project + │ ├── columns: b:26!null + │ └── semi-join (hash) + │ ├── columns: a:25 b:26!null c:27 d:28 + │ ├── with-scan &1 + │ │ ├── columns: a:25 b:26!null c:27 d:28 + │ │ └── mapping: + │ │ ├── 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:20!null uniq_overlaps_pk.b:21!null uniq_overlaps_pk.c:22 uniq_overlaps_pk.d:23 + │ └── filters + │ ├── 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:34 b:35!null c:36 d:37 - ├── with-scan &1 - │ ├── columns: a:34 b:35!null c:36 d:37 - │ └── mapping: - │ ├── 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:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 - └── filters - ├── a:34 = uniq_overlaps_pk.a:29 - └── b:35 != uniq_overlaps_pk.b:30 + └── project + ├── columns: a:34 + └── semi-join (hash) + ├── columns: a:34 b:35!null c:36 d:37 + ├── with-scan &1 + │ ├── columns: a:34 b:35!null c:36 d:37 + │ └── mapping: + │ ├── 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:29!null uniq_overlaps_pk.b:30!null uniq_overlaps_pk.c:31 uniq_overlaps_pk.d:32 + └── filters + ├── a:34 = uniq_overlaps_pk.a:29 + └── b:35 != uniq_overlaps_pk.b:30 exec-ddl CREATE TABLE uniq_hidden_pk ( @@ -1102,56 +1152,62 @@ upsert uniq_hidden_pk │ └── 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: a:26!null b:27!null c:28 d:29!null rowid:30 - │ ├── with-scan &1 - │ │ ├── columns: a:26!null b:27!null c:28 d:29!null rowid:30 - │ │ └── mapping: - │ │ ├── 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.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:27 = uniq_hidden_pk.b:21 - │ ├── c:28 = uniq_hidden_pk.c:22 - │ └── rowid:30 != uniq_hidden_pk.rowid:24 + │ └── project + │ ├── columns: b:27!null + │ └── semi-join (hash) + │ ├── columns: a:26!null b:27!null c:28 d:29!null rowid:30 + │ ├── with-scan &1 + │ │ ├── columns: a:26!null b:27!null c:28 d:29!null rowid:30 + │ │ └── mapping: + │ │ ├── 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.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: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:37!null b:38!null c:39 d:40!null rowid:41 - │ ├── with-scan &1 - │ │ ├── columns: a:37!null b:38!null c:39 d:40!null rowid:41 - │ │ └── mapping: - │ │ ├── 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:31 uniq_hidden_pk.b:32 uniq_hidden_pk.c:33 uniq_hidden_pk.d:34 uniq_hidden_pk.rowid:35!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:37!null + │ └── semi-join (hash) + │ ├── columns: a:37!null b:38!null c:39 d:40!null rowid:41 + │ ├── with-scan &1 + │ │ ├── columns: a:37!null b:38!null c:39 d:40!null rowid:41 + │ │ └── mapping: + │ │ ├── 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:31 uniq_hidden_pk.b:32 uniq_hidden_pk.c:33 uniq_hidden_pk.d:34 uniq_hidden_pk.rowid:35!null + │ └── filters + │ ├── 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:48!null b:49!null c:50 d:51!null rowid:52 - ├── with-scan &1 - │ ├── columns: a:48!null b:49!null c:50 d:51!null rowid:52 - │ └── mapping: - │ ├── 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:42 uniq_hidden_pk.b:43 uniq_hidden_pk.c:44 uniq_hidden_pk.d:45 uniq_hidden_pk.rowid:46!null - └── filters - ├── a:48 = uniq_hidden_pk.a:42 - └── rowid:52 != uniq_hidden_pk.rowid:46 + └── project + ├── columns: a:48!null + └── semi-join (hash) + ├── columns: a:48!null b:49!null c:50 d:51!null rowid:52 + ├── with-scan &1 + │ ├── columns: a:48!null b:49!null c:50 d:51!null rowid:52 + │ └── mapping: + │ ├── 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:42 uniq_hidden_pk.b:43 uniq_hidden_pk.c:44 uniq_hidden_pk.d:45 uniq_hidden_pk.rowid:46!null + └── filters + ├── 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. @@ -1177,56 +1233,62 @@ upsert uniq_hidden_pk │ └── unique_rowid() [as=column14:14] └── unique-checks ├── unique-checks-item: uniq_hidden_pk(b,c) - │ └── semi-join (hash) - │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 - │ ├── with-scan &1 - │ │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 - │ │ └── mapping: - │ │ ├── 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.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:22 = uniq_hidden_pk.b:16 - │ ├── c:23 = uniq_hidden_pk.c:17 - │ └── rowid:25 != uniq_hidden_pk.rowid:19 + │ └── project + │ ├── columns: b:22 + │ └── semi-join (hash) + │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 + │ ├── with-scan &1 + │ │ ├── columns: a:21 b:22 c:23 d:24 rowid:25 + │ │ └── mapping: + │ │ ├── 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.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: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:32 b:33 c:34 d:35 rowid:36 - │ ├── with-scan &1 - │ │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 - │ │ └── mapping: - │ │ ├── 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:26 uniq_hidden_pk.b:27 uniq_hidden_pk.c:28 uniq_hidden_pk.d:29 uniq_hidden_pk.rowid:30!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:32 + │ └── semi-join (hash) + │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 + │ ├── with-scan &1 + │ │ ├── columns: a:32 b:33 c:34 d:35 rowid:36 + │ │ └── mapping: + │ │ ├── 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:26 uniq_hidden_pk.b:27 uniq_hidden_pk.c:28 uniq_hidden_pk.d:29 uniq_hidden_pk.rowid:30!null + │ └── filters + │ ├── 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:43 b:44 c:45 d:46 rowid:47 - ├── with-scan &1 - │ ├── columns: a:43 b:44 c:45 d:46 rowid:47 - │ └── mapping: - │ ├── 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: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 + └── project + ├── columns: a:43 + └── semi-join (hash) + ├── columns: a:43 b:44 c:45 d:46 rowid:47 + ├── with-scan &1 + │ ├── columns: a:43 b:44 c:45 d:46 rowid:47 + │ └── mapping: + │ ├── 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: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 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # columns. @@ -1284,56 +1346,62 @@ upsert uniq_hidden_pk │ └── 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: a:30!null b:31 c:32 d:33 rowid:34 - │ ├── with-scan &1 - │ │ ├── columns: a:30!null b:31 c:32 d:33 rowid:34 - │ │ └── mapping: - │ │ ├── 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.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:31 = uniq_hidden_pk.b:25 - │ ├── c:32 = uniq_hidden_pk.c:26 - │ └── rowid:34 != uniq_hidden_pk.rowid:28 + │ └── project + │ ├── columns: b:31 + │ └── semi-join (hash) + │ ├── columns: a:30!null b:31 c:32 d:33 rowid:34 + │ ├── with-scan &1 + │ │ ├── columns: a:30!null b:31 c:32 d:33 rowid:34 + │ │ └── mapping: + │ │ ├── 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.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: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:41!null b:42 c:43 d:44 rowid:45 - │ ├── with-scan &1 - │ │ ├── columns: a:41!null b:42 c:43 d:44 rowid:45 - │ │ └── mapping: - │ │ ├── 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:35 uniq_hidden_pk.b:36 uniq_hidden_pk.c:37 uniq_hidden_pk.d:38 uniq_hidden_pk.rowid:39!null - │ └── filters - │ ├── 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 + │ └── project + │ ├── columns: a:41!null + │ └── semi-join (hash) + │ ├── columns: a:41!null b:42 c:43 d:44 rowid:45 + │ ├── with-scan &1 + │ │ ├── columns: a:41!null b:42 c:43 d:44 rowid:45 + │ │ └── mapping: + │ │ ├── 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:35 uniq_hidden_pk.b:36 uniq_hidden_pk.c:37 uniq_hidden_pk.d:38 uniq_hidden_pk.rowid:39!null + │ └── filters + │ ├── 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:52!null b:53 c:54 d:55 rowid:56 - ├── with-scan &1 - │ ├── columns: a:52!null b:53 c:54 d:55 rowid:56 - │ └── mapping: - │ ├── 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:46 uniq_hidden_pk.b:47 uniq_hidden_pk.c:48 uniq_hidden_pk.d:49 uniq_hidden_pk.rowid:50!null - └── filters - ├── a:52 = uniq_hidden_pk.a:46 - └── rowid:56 != uniq_hidden_pk.rowid:50 + └── project + ├── columns: a:52!null + └── semi-join (hash) + ├── columns: a:52!null b:53 c:54 d:55 rowid:56 + ├── with-scan &1 + │ ├── columns: a:52!null b:53 c:54 d:55 rowid:56 + │ └── mapping: + │ ├── 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:46 uniq_hidden_pk.b:47 uniq_hidden_pk.c:48 uniq_hidden_pk.d:49 uniq_hidden_pk.rowid:50!null + └── filters + ├── a:52 = uniq_hidden_pk.a:46 + └── rowid:56 != uniq_hidden_pk.rowid:50 exec-ddl CREATE TABLE uniq_fk_parent ( @@ -1394,18 +1462,20 @@ upsert uniq_fk_parent │ └── 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: a:13!null rowid:14 - │ ├── with-scan &1 - │ │ ├── columns: a:13!null rowid:14 - │ │ └── mapping: - │ │ ├── column1:4 => a:13 - │ │ └── upsert_rowid:9 => rowid:14 - │ ├── scan uniq_fk_parent - │ │ └── columns: uniq_fk_parent.a:10 uniq_fk_parent.rowid:11!null - │ └── filters - │ ├── a:13 = uniq_fk_parent.a:10 - │ └── rowid:14 != uniq_fk_parent.rowid:11 + │ └── project + │ ├── columns: a:13!null + │ └── semi-join (hash) + │ ├── columns: a:13!null rowid:14 + │ ├── with-scan &1 + │ │ ├── columns: a:13!null rowid:14 + │ │ └── mapping: + │ │ ├── column1:4 => a:13 + │ │ └── upsert_rowid:9 => rowid:14 + │ ├── scan uniq_fk_parent + │ │ └── columns: uniq_fk_parent.a:10 uniq_fk_parent.rowid:11!null + │ └── filters + │ ├── 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) @@ -1517,21 +1587,23 @@ upsert t │ └── t.i:6 > 0 [as=partial_index_del1:13] └── unique-checks └── unique-checks-item: t(i) - └── semi-join (hash) - ├── columns: i:17!null rowid:18 - ├── with-scan &1 - │ ├── columns: i:17!null rowid:18 - │ └── mapping: - │ ├── upsert_i:10 => i:17 - │ └── upsert_rowid:11 => rowid:18 - ├── scan t - │ ├── columns: t.i:14 t.rowid:15!null - │ └── partial index predicates - │ └── i1: filters - │ └── t.i:14 > 0 - └── filters - ├── i:17 = t.i:14 - └── rowid:18 != t.rowid:15 + └── project + ├── columns: i:17!null + └── semi-join (hash) + ├── columns: i:17!null rowid:18 + ├── with-scan &1 + │ ├── columns: i:17!null rowid:18 + │ └── mapping: + │ ├── upsert_i:10 => i:17 + │ └── upsert_rowid:11 => rowid:18 + ├── scan t + │ ├── columns: t.i:14 t.rowid:15!null + │ └── partial index predicates + │ └── i1: filters + │ └── t.i:14 > 0 + └── filters + ├── i:17 = t.i:14 + └── rowid:18 != t.rowid:15 exec-ddl CREATE TABLE uniq_partial ( @@ -1559,21 +1631,23 @@ upsert uniq_partial │ └── (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 + └── project + ├── columns: a:13!null + └── 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 # No need to plan checks for a since it's always null. build @@ -1607,21 +1681,23 @@ upsert uniq_partial │ └── 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 + └── project + ├── columns: a:17 + └── 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 # On conflict do update with constant input, conflict on UNIQUE WITHOUT INDEX # column and predicate. @@ -1681,21 +1757,23 @@ upsert uniq_partial │ └── CASE WHEN uniq_partial.k:9 IS NULL THEN column3:7 ELSE uniq_partial.b:11 END [as=upsert_b:16] └── unique-checks └── unique-checks-item: uniq_partial(a) - └── semi-join (hash) - ├── columns: k:21 a:22!null b:23 - ├── with-scan &1 - │ ├── columns: k:21 a:22!null b:23 - │ └── mapping: - │ ├── upsert_k:14 => k:21 - │ ├── upsert_a:15 => a:22 - │ └── upsert_b:16 => b:23 - ├── scan uniq_partial - │ └── columns: uniq_partial.k:17!null uniq_partial.a:18 uniq_partial.b:19 - └── filters - ├── a:22 = uniq_partial.a:18 - ├── b:23 > 0 - ├── uniq_partial.b:19 > 0 - └── k:21 != uniq_partial.k:17 + └── project + ├── columns: a:22!null + └── semi-join (hash) + ├── columns: k:21 a:22!null b:23 + ├── with-scan &1 + │ ├── columns: k:21 a:22!null b:23 + │ └── mapping: + │ ├── upsert_k:14 => k:21 + │ ├── upsert_a:15 => a:22 + │ └── upsert_b:16 => b:23 + ├── scan uniq_partial + │ └── columns: uniq_partial.k:17!null uniq_partial.a:18 uniq_partial.b:19 + └── filters + ├── a:22 = uniq_partial.a:18 + ├── b:23 > 0 + ├── uniq_partial.b:19 > 0 + └── k:21 != uniq_partial.k:17 # Error when there is no arbiter predicate to match the partial unique # constraint predicate. @@ -1758,29 +1836,31 @@ upsert uniq_partial_constraint_and_index │ └── CASE WHEN uniq_partial_constraint_and_index.k:9 IS NULL THEN column3:7 ELSE uniq_partial_constraint_and_index.b:11 END [as=upsert_b:16] └── unique-checks └── unique-checks-item: uniq_partial_constraint_and_index(a) - └── semi-join (hash) - ├── columns: k:22 a:23!null b:24!null - ├── select - │ ├── columns: k:22 a:23!null b:24!null - │ ├── with-scan &1 - │ │ ├── columns: k:22 a:23!null b:24 - │ │ └── mapping: - │ │ ├── upsert_k:14 => k:22 - │ │ ├── upsert_a:15 => a:23 - │ │ └── upsert_b:16 => b:24 - │ └── filters - │ └── b:24 > 10 - ├── select - │ ├── columns: uniq_partial_constraint_and_index.k:18!null uniq_partial_constraint_and_index.a:19 uniq_partial_constraint_and_index.b:20!null - │ ├── scan uniq_partial_constraint_and_index - │ │ ├── columns: uniq_partial_constraint_and_index.k:18!null uniq_partial_constraint_and_index.a:19 uniq_partial_constraint_and_index.b:20 - │ │ └── partial index predicates - │ │ └── secondary: filters (true) - │ └── filters - │ └── uniq_partial_constraint_and_index.b:20 > 10 - └── filters - ├── a:23 = uniq_partial_constraint_and_index.a:19 - └── k:22 != uniq_partial_constraint_and_index.k:18 + └── project + ├── columns: a:23!null + └── semi-join (hash) + ├── columns: k:22 a:23!null b:24!null + ├── select + │ ├── columns: k:22 a:23!null b:24!null + │ ├── with-scan &1 + │ │ ├── columns: k:22 a:23!null b:24 + │ │ └── mapping: + │ │ ├── upsert_k:14 => k:22 + │ │ ├── upsert_a:15 => a:23 + │ │ └── upsert_b:16 => b:24 + │ └── filters + │ └── b:24 > 10 + ├── select + │ ├── columns: uniq_partial_constraint_and_index.k:18!null uniq_partial_constraint_and_index.a:19 uniq_partial_constraint_and_index.b:20!null + │ ├── scan uniq_partial_constraint_and_index + │ │ ├── columns: uniq_partial_constraint_and_index.k:18!null uniq_partial_constraint_and_index.a:19 uniq_partial_constraint_and_index.b:20 + │ │ └── partial index predicates + │ │ └── secondary: filters (true) + │ └── filters + │ └── uniq_partial_constraint_and_index.b:20 > 10 + └── filters + ├── a:23 = uniq_partial_constraint_and_index.a:19 + └── k:22 != uniq_partial_constraint_and_index.k:18 exec-ddl CREATE TABLE uniq_constraint_and_partial_index ( @@ -1814,49 +1894,46 @@ upsert uniq_constraint_and_partial_index ├── partial index del columns: partial_index_del1:18 ├── input binding: &1 ├── project - │ ├── columns: partial_index_put1:17 partial_index_del1:18 column1:5!null column2:6!null column3:7!null uniq_constraint_and_partial_index.k:9 uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 upsert_k:14 upsert_a:15!null upsert_b:16 - │ ├── project - │ │ ├── columns: upsert_k:14 upsert_a:15!null upsert_b:16 column1:5!null column2:6!null column3:7!null uniq_constraint_and_partial_index.k:9 uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 - │ │ ├── left-join (cross) - │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null uniq_constraint_and_partial_index.k:9 uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 - │ │ │ ├── values - │ │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null - │ │ │ │ └── (1, 1, 1) - │ │ │ ├── select - │ │ │ │ ├── columns: uniq_constraint_and_partial_index.k:9!null uniq_constraint_and_partial_index.a:10!null uniq_constraint_and_partial_index.b:11 - │ │ │ │ ├── scan uniq_constraint_and_partial_index - │ │ │ │ │ ├── columns: uniq_constraint_and_partial_index.k:9!null uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 - │ │ │ │ │ └── partial index predicates - │ │ │ │ │ └── secondary: filters - │ │ │ │ │ └── uniq_constraint_and_partial_index.b:11 > 0 - │ │ │ │ └── filters - │ │ │ │ └── uniq_constraint_and_partial_index.a:10 = 1 - │ │ │ └── filters (true) - │ │ └── projections - │ │ ├── CASE WHEN uniq_constraint_and_partial_index.k:9 IS NULL THEN column1:5 ELSE uniq_constraint_and_partial_index.k:9 END [as=upsert_k:14] - │ │ ├── CASE WHEN uniq_constraint_and_partial_index.k:9 IS NULL THEN column2:6 ELSE 10 END [as=upsert_a:15] - │ │ └── CASE WHEN uniq_constraint_and_partial_index.k:9 IS NULL THEN column3:7 ELSE uniq_constraint_and_partial_index.b:11 END [as=upsert_b:16] + │ ├── columns: partial_index_put1:17 partial_index_del1:18 upsert_k:14 upsert_a:15!null column1:5!null column2:6!null column3:7!null uniq_constraint_and_partial_index.k:9 uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 + │ ├── left-join (cross) + │ │ ├── columns: column1:5!null column2:6!null column3:7!null uniq_constraint_and_partial_index.k:9 uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 + │ │ ├── values + │ │ │ ├── columns: column1:5!null column2:6!null column3:7!null + │ │ │ └── (1, 1, 1) + │ │ ├── select + │ │ │ ├── columns: uniq_constraint_and_partial_index.k:9!null uniq_constraint_and_partial_index.a:10!null uniq_constraint_and_partial_index.b:11 + │ │ │ ├── scan uniq_constraint_and_partial_index + │ │ │ │ ├── columns: uniq_constraint_and_partial_index.k:9!null uniq_constraint_and_partial_index.a:10 uniq_constraint_and_partial_index.b:11 + │ │ │ │ └── partial index predicates + │ │ │ │ └── secondary: filters + │ │ │ │ └── uniq_constraint_and_partial_index.b:11 > 0 + │ │ │ └── filters + │ │ │ └── uniq_constraint_and_partial_index.a:10 = 1 + │ │ └── filters (true) │ └── projections - │ ├── upsert_b:16 > 0 [as=partial_index_put1:17] - │ └── uniq_constraint_and_partial_index.b:11 > 0 [as=partial_index_del1:18] + │ ├── CASE WHEN uniq_constraint_and_partial_index.k:9 IS NULL THEN column3:7 ELSE uniq_constraint_and_partial_index.b:11 END > 0 [as=partial_index_put1:17] + │ ├── uniq_constraint_and_partial_index.b:11 > 0 [as=partial_index_del1:18] + │ ├── CASE WHEN uniq_constraint_and_partial_index.k:9 IS NULL THEN column1:5 ELSE uniq_constraint_and_partial_index.k:9 END [as=upsert_k:14] + │ └── CASE WHEN uniq_constraint_and_partial_index.k:9 IS NULL THEN column2:6 ELSE 10 END [as=upsert_a:15] └── unique-checks └── unique-checks-item: uniq_constraint_and_partial_index(a) - └── semi-join (hash) - ├── columns: k:23 a:24!null b:25 - ├── with-scan &1 - │ ├── columns: k:23 a:24!null b:25 - │ └── mapping: - │ ├── upsert_k:14 => k:23 - │ ├── upsert_a:15 => a:24 - │ └── upsert_b:16 => b:25 - ├── scan uniq_constraint_and_partial_index - │ ├── columns: uniq_constraint_and_partial_index.k:19!null uniq_constraint_and_partial_index.a:20 - │ └── partial index predicates - │ └── secondary: filters - │ └── uniq_constraint_and_partial_index.b:21 > 0 - └── filters - ├── a:24 = uniq_constraint_and_partial_index.a:20 - └── k:23 != uniq_constraint_and_partial_index.k:19 + └── project + ├── columns: a:24!null + └── semi-join (hash) + ├── columns: k:23 a:24!null + ├── with-scan &1 + │ ├── columns: k:23 a:24!null + │ └── mapping: + │ ├── upsert_k:14 => k:23 + │ └── upsert_a:15 => a:24 + ├── scan uniq_constraint_and_partial_index + │ ├── columns: uniq_constraint_and_partial_index.k:19!null uniq_constraint_and_partial_index.a:20 + │ └── partial index predicates + │ └── secondary: filters + │ └── uniq_constraint_and_partial_index.b:21 > 0 + └── filters + ├── a:24 = uniq_constraint_and_partial_index.a:20 + └── k:23 != uniq_constraint_and_partial_index.k:19 exec-ddl CREATE TABLE uniq_partial_constraint_and_partial_index ( @@ -1970,33 +2047,35 @@ upsert uniq_computed_pk │ └── CASE WHEN uniq_computed_pk.c_i_expr:17 IS NULL THEN column12:12 ELSE uniq_computed_pk.c_i_expr:17 END [as=upsert_c_i_expr:24] └── unique-checks └── unique-checks-item: uniq_computed_pk(d) - └── semi-join (hash) - ├── columns: i:49 s:50!null d:51!null c_i_expr:52 c_s:53!null c_d:54!null c_d_expr:55!null - ├── with-scan &1 - │ ├── columns: i:49 s:50!null d:51!null c_i_expr:52 c_s:53!null c_d:54!null c_d_expr:55!null - │ └── mapping: - │ ├── upsert_i:23 => i:49 - │ ├── column2:10 => s:50 - │ ├── column3:11 => d:51 - │ ├── upsert_c_i_expr:24 => c_i_expr:52 - │ ├── column2:10 => c_s:53 - │ ├── column3:11 => c_d:54 - │ └── column13:13 => c_d_expr:55 - ├── project - │ ├── columns: uniq_computed_pk.c_s:45 uniq_computed_pk.i:41!null uniq_computed_pk.s:42 uniq_computed_pk.d:43 uniq_computed_pk.c_i_expr:44!null uniq_computed_pk.c_d:46 uniq_computed_pk.c_d_expr:47 - │ ├── scan uniq_computed_pk - │ │ ├── columns: uniq_computed_pk.i:41!null uniq_computed_pk.s:42 uniq_computed_pk.d:43 uniq_computed_pk.c_i_expr:44!null uniq_computed_pk.c_d:46 uniq_computed_pk.c_d_expr:47 - │ │ └── computed column expressions - │ │ ├── uniq_computed_pk.c_i_expr:44 - │ │ │ └── CASE WHEN uniq_computed_pk.i:41 < 0 THEN 'foo' ELSE 'bar' END - │ │ ├── uniq_computed_pk.c_s:45 - │ │ │ └── uniq_computed_pk.s:42 - │ │ ├── uniq_computed_pk.c_d:46 - │ │ │ └── uniq_computed_pk.d:43 - │ │ └── uniq_computed_pk.c_d_expr:47 - │ │ └── uniq_computed_pk.d:43::STRING - │ └── projections - │ └── uniq_computed_pk.s:42 [as=uniq_computed_pk.c_s:45] - └── filters - ├── d:51 = uniq_computed_pk.d:43 - └── (i:49 != uniq_computed_pk.i:41) OR (c_i_expr:52 != uniq_computed_pk.c_i_expr:44) + └── project + ├── columns: d:51!null + └── semi-join (hash) + ├── columns: i:49 s:50!null d:51!null c_i_expr:52 c_s:53!null c_d:54!null c_d_expr:55!null + ├── with-scan &1 + │ ├── columns: i:49 s:50!null d:51!null c_i_expr:52 c_s:53!null c_d:54!null c_d_expr:55!null + │ └── mapping: + │ ├── upsert_i:23 => i:49 + │ ├── column2:10 => s:50 + │ ├── column3:11 => d:51 + │ ├── upsert_c_i_expr:24 => c_i_expr:52 + │ ├── column2:10 => c_s:53 + │ ├── column3:11 => c_d:54 + │ └── column13:13 => c_d_expr:55 + ├── project + │ ├── columns: uniq_computed_pk.c_s:45 uniq_computed_pk.i:41!null uniq_computed_pk.s:42 uniq_computed_pk.d:43 uniq_computed_pk.c_i_expr:44!null uniq_computed_pk.c_d:46 uniq_computed_pk.c_d_expr:47 + │ ├── scan uniq_computed_pk + │ │ ├── columns: uniq_computed_pk.i:41!null uniq_computed_pk.s:42 uniq_computed_pk.d:43 uniq_computed_pk.c_i_expr:44!null uniq_computed_pk.c_d:46 uniq_computed_pk.c_d_expr:47 + │ │ └── computed column expressions + │ │ ├── uniq_computed_pk.c_i_expr:44 + │ │ │ └── CASE WHEN uniq_computed_pk.i:41 < 0 THEN 'foo' ELSE 'bar' END + │ │ ├── uniq_computed_pk.c_s:45 + │ │ │ └── uniq_computed_pk.s:42 + │ │ ├── uniq_computed_pk.c_d:46 + │ │ │ └── uniq_computed_pk.d:43 + │ │ └── uniq_computed_pk.c_d_expr:47 + │ │ └── uniq_computed_pk.d:43::STRING + │ └── projections + │ └── uniq_computed_pk.s:42 [as=uniq_computed_pk.c_s:45] + └── filters + ├── d:51 = uniq_computed_pk.d:43 + └── (i:49 != uniq_computed_pk.i:41) OR (c_i_expr:52 != uniq_computed_pk.c_i_expr:44)