diff --git a/pkg/sql/logictest/testdata/logic_test/insert b/pkg/sql/logictest/testdata/logic_test/insert index 9279e75fcdc7..af262116c4c0 100644 --- a/pkg/sql/logictest/testdata/logic_test/insert +++ b/pkg/sql/logictest/testdata/logic_test/insert @@ -672,3 +672,17 @@ INSERT INTO xy (x, y) SELECT a, b FROM ab ORDER BY -b LIMIT 10 RETURNING *; statement ok DROP TABLE xy; DROP TABLE ab + +subtest regression_35611 + +statement ok +CREATE TABLE t35611(a INT PRIMARY KEY, CHECK (a > 0)) + +statement ok +BEGIN; ALTER TABLE t35611 ADD COLUMN b INT + +statement ok +INSERT INTO t35611 (a) VALUES (1) + +statement ok +COMMIT diff --git a/pkg/sql/opt/optbuilder/mutation_builder.go b/pkg/sql/opt/optbuilder/mutation_builder.go index ff20ee5332fa..7622b26aebde 100644 --- a/pkg/sql/opt/optbuilder/mutation_builder.go +++ b/pkg/sql/opt/optbuilder/mutation_builder.go @@ -406,7 +406,12 @@ func (mb *mutationBuilder) addCheckConstraintCols() { func (mb *mutationBuilder) disambiguateColumns() { for i, n := 0, mb.tab.DeletableColumnCount(); i < n; i++ { colName := mb.tab.Column(i).ColName() - colID := mb.mapToReturnColID(i) + colID := mb.mapToInputColID(i) + if colID == 0 { + // Column not involved in the statement, so skip it (e.g. a delete-only + // column in an Insert statement). + continue + } for i := range mb.outScope.cols { col := &mb.outScope.cols[i] if col.name == colName { @@ -441,16 +446,20 @@ func (mb *mutationBuilder) makeMutationPrivate(needResults bool) *memo.MutationP // can be non-zero. private.ReturnCols = make(opt.ColList, mb.tab.DeletableColumnCount()) for i, n := 0, mb.tab.ColumnCount(); i < n; i++ { - private.ReturnCols[i] = mb.mapToReturnColID(i) + private.ReturnCols[i] = mb.mapToInputColID(i) + if private.ReturnCols[i] == 0 { + panic(fmt.Sprintf("column %d is not available in the mutation input", i)) + } } } return private } -// mapToReturnColID returns the ID of the input column that will provide the -// value for the corresponding return column. Columns take priority in this -// order: +// mapToInputColID returns the ID of the input column that provides the final +// value for the column at the given ordinal position in the table. This value +// might mutate the column, or it might be returned by the mutation statement, +// or it might not be used at all. Columns take priority in this order: // // upsert, update, fetch, insert // @@ -459,7 +468,11 @@ func (mb *mutationBuilder) makeMutationPrivate(needResults bool) *memo.MutationP // available, then it overrides any fetch value. Finally, the relative priority // of fetch and insert columns doesn't matter, since they're only used together // in the upsert case where an upsert column would be available. -func (mb *mutationBuilder) mapToReturnColID(ord int) opt.ColumnID { +// +// If the column is never referenced by the statement, then mapToInputColID +// returns 0. This would be the case for delete-only columns in an Insert +// statement, because they're neither fetched nor mutated. +func (mb *mutationBuilder) mapToInputColID(ord int) opt.ColumnID { switch { case mb.upsertColList != nil && mb.upsertColList[ord] != 0: return mb.upsertColList[ord] @@ -474,7 +487,8 @@ func (mb *mutationBuilder) mapToReturnColID(ord int) opt.ColumnID { return mb.insertColList[ord] default: - panic("could not find return column") + // Column is never referenced by the statement. + return 0 } } diff --git a/pkg/sql/opt/optbuilder/testdata/insert b/pkg/sql/opt/optbuilder/testdata/insert index 3c059f409d5e..8068e5f9f721 100644 --- a/pkg/sql/opt/optbuilder/testdata/insert +++ b/pkg/sql/opt/optbuilder/testdata/insert @@ -50,7 +50,8 @@ CREATE TABLE mutation ( n INT, "o:write-only" INT DEFAULT(10), "p:write-only" INT AS (o + n) STORED, - "q:delete-only" INT + "q:delete-only" INT AS (m * p) STORED, + CHECK (m > 0) ) ---- TABLE mutation @@ -59,8 +60,9 @@ TABLE mutation ├── o int (mutation) ├── p int (mutation) ├── q int (mutation) - └── INDEX primary - └── m int not null + ├── INDEX primary + │ └── m int not null + └── CHECK (m > 0) exec-ddl CREATE TABLE checks ( @@ -1186,21 +1188,28 @@ insert mutation │ ├── column2:7 => n:2 │ ├── column8:8 => o:3 │ └── column9:9 => p:4 + ├── check columns: check1:10(bool) └── project - ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + ├── columns: check1:10(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) ├── project - │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) - │ ├── values - │ │ ├── columns: column1:6(int) column2:7(int) - │ │ └── tuple [type=tuple{int, int}] - │ │ ├── const: 1 [type=int] - │ │ └── const: 2 [type=int] + │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ ├── project + │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) + │ │ ├── values + │ │ │ ├── columns: column1:6(int) column2:7(int) + │ │ │ └── tuple [type=tuple{int, int}] + │ │ │ ├── const: 1 [type=int] + │ │ │ └── const: 2 [type=int] + │ │ └── projections + │ │ └── const: 10 [type=int] │ └── projections - │ └── const: 10 [type=int] + │ └── plus [type=int] + │ ├── variable: column8 [type=int] + │ └── variable: column2 [type=int] └── projections - └── plus [type=int] - ├── variable: column8 [type=int] - └── variable: column2 [type=int] + └── gt [type=bool] + ├── variable: column1 [type=int] + └── const: 0 [type=int] # Use RETURNING clause and ensure that mutation columns aren't projected. build @@ -1213,21 +1222,28 @@ insert mutation │ ├── column2:7 => n:2 │ ├── column8:8 => o:3 │ └── column9:9 => p:4 + ├── check columns: check1:10(bool) └── project - ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + ├── columns: check1:10(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) ├── project - │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) - │ ├── values - │ │ ├── columns: column1:6(int) column2:7(int) - │ │ └── tuple [type=tuple{int, int}] - │ │ ├── const: 1 [type=int] - │ │ └── const: 2 [type=int] + │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ ├── project + │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) + │ │ ├── values + │ │ │ ├── columns: column1:6(int) column2:7(int) + │ │ │ └── tuple [type=tuple{int, int}] + │ │ │ ├── const: 1 [type=int] + │ │ │ └── const: 2 [type=int] + │ │ └── projections + │ │ └── const: 10 [type=int] │ └── projections - │ └── const: 10 [type=int] + │ └── plus [type=int] + │ ├── variable: column8 [type=int] + │ └── variable: column2 [type=int] └── projections - └── plus [type=int] - ├── variable: column8 [type=int] - └── variable: column2 [type=int] + └── gt [type=bool] + ├── variable: column1 [type=int] + └── const: 0 [type=int] # Try to reference write-only mutation column in RETURNING clause. build diff --git a/pkg/sql/opt/optbuilder/testdata/update b/pkg/sql/opt/optbuilder/testdata/update index 530b49291801..061f4849dc5d 100644 --- a/pkg/sql/opt/optbuilder/testdata/update +++ b/pkg/sql/opt/optbuilder/testdata/update @@ -49,7 +49,9 @@ CREATE TABLE mutation ( m INT PRIMARY KEY, n INT, "o:write-only" INT DEFAULT(10), - "p:write-only" INT AS (o + n) STORED + "p:write-only" INT AS (o + n) STORED, + "q:delete-only" INT AS (m * p) STORED, + CHECK (m > 0) ) ---- TABLE mutation @@ -57,8 +59,10 @@ TABLE mutation ├── n int ├── o int (mutation) ├── p int (mutation) - └── INDEX primary - └── m int not null + ├── q int (mutation) + ├── INDEX primary + │ └── m int not null + └── CHECK (m > 0) exec-ddl CREATE TABLE checks ( @@ -1222,22 +1226,29 @@ UPDATE mutation SET m=1 ---- update mutation ├── columns: - ├── fetch columns: m:5(int) n:6(int) o:7(int) p:8(int) + ├── fetch columns: m:6(int) n:7(int) o:8(int) p:9(int) q:10(int) ├── update-mapping: - │ ├── column9:9 => m:1 - │ └── column10:10 => p:4 + │ ├── column11:11 => m:1 + │ └── column12:12 => p:4 + ├── check columns: check1:13(bool) └── project - ├── columns: column10:10(int) m:5(int!null) n:6(int) o:7(int) p:8(int) column9:9(int!null) + ├── columns: check1:13(bool) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) column11:11(int!null) column12:12(int) ├── project - │ ├── columns: column9:9(int!null) m:5(int!null) n:6(int) o:7(int) p:8(int) - │ ├── scan mutation - │ │ └── columns: m:5(int!null) n:6(int) o:7(int) p:8(int) + │ ├── columns: column12:12(int) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) column11:11(int!null) + │ ├── project + │ │ ├── columns: column11:11(int!null) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ ├── scan mutation + │ │ │ └── columns: m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ └── projections + │ │ └── const: 1 [type=int] │ └── projections - │ └── const: 1 [type=int] + │ └── plus [type=int] + │ ├── variable: o [type=int] + │ └── variable: n [type=int] └── projections - └── plus [type=int] - ├── variable: o [type=int] - └── variable: n [type=int] + └── gt [type=bool] + ├── variable: column11 [type=int] + └── const: 0 [type=int] # Test update that requires computed mutation column to be recalculated. build @@ -1245,24 +1256,31 @@ UPDATE mutation SET m=1, n=2 ---- update mutation ├── columns: - ├── fetch columns: m:5(int) n:6(int) o:7(int) p:8(int) + ├── fetch columns: m:6(int) n:7(int) o:8(int) p:9(int) q:10(int) ├── update-mapping: - │ ├── column9:9 => m:1 - │ ├── column10:10 => n:2 - │ └── column11:11 => p:4 + │ ├── column11:11 => m:1 + │ ├── column12:12 => n:2 + │ └── column13:13 => p:4 + ├── check columns: check1:14(bool) └── project - ├── columns: column11:11(int) m:5(int!null) n:6(int) o:7(int) p:8(int) column9:9(int!null) column10:10(int!null) + ├── columns: check1:14(bool) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) column11:11(int!null) column12:12(int!null) column13:13(int) ├── project - │ ├── columns: column9:9(int!null) column10:10(int!null) m:5(int!null) n:6(int) o:7(int) p:8(int) - │ ├── scan mutation - │ │ └── columns: m:5(int!null) n:6(int) o:7(int) p:8(int) + │ ├── columns: column13:13(int) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) column11:11(int!null) column12:12(int!null) + │ ├── project + │ │ ├── columns: column11:11(int!null) column12:12(int!null) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ ├── scan mutation + │ │ │ └── columns: m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ └── projections + │ │ ├── const: 1 [type=int] + │ │ └── const: 2 [type=int] │ └── projections - │ ├── const: 1 [type=int] - │ └── const: 2 [type=int] + │ └── plus [type=int] + │ ├── variable: o [type=int] + │ └── variable: column12 [type=int] └── projections - └── plus [type=int] - ├── variable: o [type=int] - └── variable: column10 [type=int] + └── gt [type=bool] + ├── variable: column11 [type=int] + └── const: 0 [type=int] # Ensure that ORDER BY wildcard does not select mutation columns. build @@ -1270,29 +1288,36 @@ UPDATE mutation SET m=1 ORDER BY mutation.* LIMIT 10 ---- update mutation ├── columns: - ├── fetch columns: m:5(int) n:6(int) o:7(int) p:8(int) + ├── fetch columns: m:6(int) n:7(int) o:8(int) p:9(int) q:10(int) ├── update-mapping: - │ ├── column9:9 => m:1 - │ └── column10:10 => p:4 + │ ├── column11:11 => m:1 + │ └── column12:12 => p:4 + ├── check columns: check1:13(bool) └── project - ├── columns: column10:10(int) m:5(int!null) n:6(int) o:7(int) p:8(int) column9:9(int!null) + ├── columns: check1:13(bool) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) column11:11(int!null) column12:12(int) ├── project - │ ├── columns: column9:9(int!null) m:5(int!null) n:6(int) o:7(int) p:8(int) - │ ├── limit - │ │ ├── columns: m:5(int!null) n:6(int) o:7(int) p:8(int) - │ │ ├── internal-ordering: +5,+6 - │ │ ├── sort - │ │ │ ├── columns: m:5(int!null) n:6(int) o:7(int) p:8(int) - │ │ │ ├── ordering: +5,+6 - │ │ │ └── scan mutation - │ │ │ └── columns: m:5(int!null) n:6(int) o:7(int) p:8(int) - │ │ └── const: 10 [type=int] + │ ├── columns: column12:12(int) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) column11:11(int!null) + │ ├── project + │ │ ├── columns: column11:11(int!null) m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ ├── limit + │ │ │ ├── columns: m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ │ ├── internal-ordering: +6,+7 + │ │ │ ├── sort + │ │ │ │ ├── columns: m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ │ │ ├── ordering: +6,+7 + │ │ │ │ └── scan mutation + │ │ │ │ └── columns: m:6(int!null) n:7(int) o:8(int) p:9(int) q:10(int) + │ │ │ └── const: 10 [type=int] + │ │ └── projections + │ │ └── const: 1 [type=int] │ └── projections - │ └── const: 1 [type=int] + │ └── plus [type=int] + │ ├── variable: o [type=int] + │ └── variable: n [type=int] └── projections - └── plus [type=int] - ├── variable: o [type=int] - └── variable: n [type=int] + └── gt [type=bool] + ├── variable: column11 [type=int] + └── const: 0 [type=int] # Use column "o" from higher scope that is shadowed by mutation column "o". build @@ -1308,22 +1333,29 @@ project └── exists [type=bool] └── update mutation ├── columns: mutation.m:7(int!null) mutation.n:8(int) - ├── fetch columns: mutation.m:11(int) mutation.n:12(int) mutation.o:13(int) p:14(int) + ├── fetch columns: mutation.m:12(int) mutation.n:13(int) mutation.o:14(int) p:15(int) q:16(int) ├── update-mapping: - │ ├── o:15 => mutation.m:7 - │ └── column16:16 => p:10 + │ ├── o:17 => mutation.m:7 + │ └── column18:18 => p:10 + ├── check columns: check1:19(bool) └── project - ├── columns: column16:16(int) mutation.m:11(int!null) mutation.n:12(int) mutation.o:13(int) p:14(int) o:15(int) + ├── columns: check1:19(bool) mutation.m:12(int!null) mutation.n:13(int) mutation.o:14(int) p:15(int) q:16(int) o:17(int) column18:18(int) ├── project - │ ├── columns: o:15(int) mutation.m:11(int!null) mutation.n:12(int) mutation.o:13(int) p:14(int) - │ ├── scan mutation - │ │ └── columns: mutation.m:11(int!null) mutation.n:12(int) mutation.o:13(int) p:14(int) + │ ├── columns: column18:18(int) mutation.m:12(int!null) mutation.n:13(int) mutation.o:14(int) p:15(int) q:16(int) o:17(int) + │ ├── project + │ │ ├── columns: o:17(int) mutation.m:12(int!null) mutation.n:13(int) mutation.o:14(int) p:15(int) q:16(int) + │ │ ├── scan mutation + │ │ │ └── columns: mutation.m:12(int!null) mutation.n:13(int) mutation.o:14(int) p:15(int) q:16(int) + │ │ └── projections + │ │ └── variable: mno.o [type=int] │ └── projections - │ └── variable: mno.o [type=int] + │ └── plus [type=int] + │ ├── variable: mutation.o [type=int] + │ └── variable: mutation.n [type=int] └── projections - └── plus [type=int] - ├── variable: mutation.o [type=int] - └── variable: mutation.n [type=int] + └── gt [type=bool] + ├── variable: o [type=int] + └── const: 0 [type=int] # Try to return a mutation column. build diff --git a/pkg/sql/opt/optbuilder/testdata/upsert b/pkg/sql/opt/optbuilder/testdata/upsert index 169906064198..1396fe7e4925 100644 --- a/pkg/sql/opt/optbuilder/testdata/upsert +++ b/pkg/sql/opt/optbuilder/testdata/upsert @@ -84,7 +84,8 @@ CREATE TABLE mutation ( n INT, "o:write-only" INT DEFAULT(10), "p:write-only" INT AS (o + n) STORED, - "q:delete-only" INT + "q:delete-only" INT AS (m * p) STORED, + CHECK (m > 0) ) ---- TABLE mutation @@ -93,8 +94,9 @@ TABLE mutation ├── o int (mutation) ├── p int (mutation) ├── q int (mutation) - └── INDEX primary - └── m int not null + ├── INDEX primary + │ └── m int not null + └── CHECK (m > 0) exec-ddl CREATE TABLE checks ( @@ -1088,76 +1090,83 @@ upsert mutation ├── update-mapping: │ ├── upsert_m:17 => m:1 │ └── upsert_p:20 => p:4 + ├── check columns: check1:21(bool) └── project - ├── columns: upsert_m:17(int) upsert_n:18(int) upsert_o:19(int) upsert_p:20(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + ├── columns: check1:21(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) upsert_m:17(int) upsert_n:18(int) upsert_o:19(int) upsert_p:20(int) ├── project - │ ├── columns: column16:16(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int) + │ ├── columns: upsert_m:17(int) upsert_n:18(int) upsert_o:19(int) upsert_p:20(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) │ ├── project - │ │ ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ ├── left-join - │ │ │ ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ │ ├── project - │ │ │ │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ │ ├── columns: column16:16(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int) + │ │ ├── project + │ │ │ ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + │ │ │ ├── left-join + │ │ │ │ ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) │ │ │ │ ├── project - │ │ │ │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) - │ │ │ │ │ ├── values - │ │ │ │ │ │ ├── columns: column1:6(int) column2:7(int) - │ │ │ │ │ │ └── tuple [type=tuple{int, int}] - │ │ │ │ │ │ ├── const: 1 [type=int] - │ │ │ │ │ │ └── const: 2 [type=int] + │ │ │ │ │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ │ │ │ │ ├── project + │ │ │ │ │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) + │ │ │ │ │ │ ├── values + │ │ │ │ │ │ │ ├── columns: column1:6(int) column2:7(int) + │ │ │ │ │ │ │ └── tuple [type=tuple{int, int}] + │ │ │ │ │ │ │ ├── const: 1 [type=int] + │ │ │ │ │ │ │ └── const: 2 [type=int] + │ │ │ │ │ │ └── projections + │ │ │ │ │ │ └── const: 10 [type=int] │ │ │ │ │ └── projections - │ │ │ │ │ └── const: 10 [type=int] - │ │ │ │ └── projections - │ │ │ │ └── plus [type=int] - │ │ │ │ ├── variable: column8 [type=int] - │ │ │ │ └── variable: column2 [type=int] - │ │ │ ├── scan mutation - │ │ │ │ └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ │ └── filters - │ │ │ └── eq [type=bool] - │ │ │ ├── variable: column1 [type=int] - │ │ │ └── variable: m [type=int] + │ │ │ │ │ └── plus [type=int] + │ │ │ │ │ ├── variable: column8 [type=int] + │ │ │ │ │ └── variable: column2 [type=int] + │ │ │ │ ├── scan mutation + │ │ │ │ │ └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int) + │ │ │ │ └── filters + │ │ │ │ └── eq [type=bool] + │ │ │ │ ├── variable: column1 [type=int] + │ │ │ │ └── variable: m [type=int] + │ │ │ └── projections + │ │ │ └── plus [type=int] + │ │ │ ├── variable: m [type=int] + │ │ │ └── const: 1 [type=int] │ │ └── projections │ │ └── plus [type=int] - │ │ ├── variable: m [type=int] - │ │ └── const: 1 [type=int] + │ │ ├── variable: o [type=int] + │ │ └── variable: n [type=int] │ └── projections - │ └── plus [type=int] - │ ├── variable: o [type=int] - │ └── variable: n [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column1 [type=int] + │ │ └── variable: column15 [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column2 [type=int] + │ │ └── variable: n [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column8 [type=int] + │ │ └── variable: o [type=int] + │ └── case [type=int] + │ ├── true [type=bool] + │ ├── when [type=int] + │ │ ├── is [type=bool] + │ │ │ ├── variable: m [type=int] + │ │ │ └── null [type=unknown] + │ │ └── variable: column9 [type=int] + │ └── variable: column16 [type=int] └── projections - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column1 [type=int] - │ └── variable: column15 [type=int] - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column2 [type=int] - │ └── variable: n [type=int] - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column8 [type=int] - │ └── variable: o [type=int] - └── case [type=int] - ├── true [type=bool] - ├── when [type=int] - │ ├── is [type=bool] - │ │ ├── variable: m [type=int] - │ │ └── null [type=unknown] - │ └── variable: column9 [type=int] - └── variable: column16 [type=int] + └── gt [type=bool] + ├── variable: upsert_m [type=int] + └── const: 0 [type=int] # ------------------------------------------------------------------------------ # Test UPSERT. @@ -1419,62 +1428,69 @@ upsert mutation ├── update-mapping: │ ├── column2:7 => n:2 │ └── upsert_p:18 => p:4 + ├── check columns: check1:19(bool) └── project - ├── columns: upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + ├── columns: check1:19(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) ├── project - │ ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) - │ ├── left-join - │ │ ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ ├── project - │ │ │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ ├── columns: upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + │ ├── project + │ │ ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + │ │ ├── left-join + │ │ │ ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) │ │ │ ├── project - │ │ │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) - │ │ │ │ ├── values - │ │ │ │ │ ├── columns: column1:6(int) column2:7(int) - │ │ │ │ │ └── tuple [type=tuple{int, int}] - │ │ │ │ │ ├── const: 1 [type=int] - │ │ │ │ │ └── const: 2 [type=int] + │ │ │ │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ │ │ │ ├── project + │ │ │ │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) + │ │ │ │ │ ├── values + │ │ │ │ │ │ ├── columns: column1:6(int) column2:7(int) + │ │ │ │ │ │ └── tuple [type=tuple{int, int}] + │ │ │ │ │ │ ├── const: 1 [type=int] + │ │ │ │ │ │ └── const: 2 [type=int] + │ │ │ │ │ └── projections + │ │ │ │ │ └── const: 10 [type=int] │ │ │ │ └── projections - │ │ │ │ └── const: 10 [type=int] - │ │ │ └── projections - │ │ │ └── plus [type=int] - │ │ │ ├── variable: column8 [type=int] - │ │ │ └── variable: column2 [type=int] - │ │ ├── scan mutation - │ │ │ └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ └── filters - │ │ └── eq [type=bool] - │ │ ├── variable: column1 [type=int] - │ │ └── variable: m [type=int] + │ │ │ │ └── plus [type=int] + │ │ │ │ ├── variable: column8 [type=int] + │ │ │ │ └── variable: column2 [type=int] + │ │ │ ├── scan mutation + │ │ │ │ └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int) + │ │ │ └── filters + │ │ │ └── eq [type=bool] + │ │ │ ├── variable: column1 [type=int] + │ │ │ └── variable: m [type=int] + │ │ └── projections + │ │ └── plus [type=int] + │ │ ├── variable: o [type=int] + │ │ └── variable: column2 [type=int] │ └── projections - │ └── plus [type=int] - │ ├── variable: o [type=int] - │ └── variable: column2 [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column1 [type=int] + │ │ └── variable: m [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column8 [type=int] + │ │ └── variable: o [type=int] + │ └── case [type=int] + │ ├── true [type=bool] + │ ├── when [type=int] + │ │ ├── is [type=bool] + │ │ │ ├── variable: m [type=int] + │ │ │ └── null [type=unknown] + │ │ └── variable: column9 [type=int] + │ └── variable: column15 [type=int] └── projections - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column1 [type=int] - │ └── variable: m [type=int] - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column8 [type=int] - │ └── variable: o [type=int] - └── case [type=int] - ├── true [type=bool] - ├── when [type=int] - │ ├── is [type=bool] - │ │ ├── variable: m [type=int] - │ │ └── null [type=unknown] - │ └── variable: column9 [type=int] - └── variable: column15 [type=int] + └── gt [type=bool] + ├── variable: upsert_m [type=int] + └── const: 0 [type=int] # Don't directly update mutation columns. However, computed columns do need to # be updated. Use implicit target columns. @@ -1493,62 +1509,69 @@ upsert mutation ├── update-mapping: │ ├── column2:7 => n:2 │ └── upsert_p:18 => p:4 + ├── check columns: check1:19(bool) └── project - ├── columns: upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + ├── columns: check1:19(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) ├── project - │ ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) - │ ├── left-join - │ │ ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ ├── project - │ │ │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ ├── columns: upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + │ ├── project + │ │ ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) + │ │ ├── left-join + │ │ │ ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) │ │ │ ├── project - │ │ │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) - │ │ │ │ ├── values - │ │ │ │ │ ├── columns: column1:6(int) column2:7(int) - │ │ │ │ │ └── tuple [type=tuple{int, int}] - │ │ │ │ │ ├── const: 1 [type=int] - │ │ │ │ │ └── const: 2 [type=int] + │ │ │ │ ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null) + │ │ │ │ ├── project + │ │ │ │ │ ├── columns: column8:8(int!null) column1:6(int) column2:7(int) + │ │ │ │ │ ├── values + │ │ │ │ │ │ ├── columns: column1:6(int) column2:7(int) + │ │ │ │ │ │ └── tuple [type=tuple{int, int}] + │ │ │ │ │ │ ├── const: 1 [type=int] + │ │ │ │ │ │ └── const: 2 [type=int] + │ │ │ │ │ └── projections + │ │ │ │ │ └── const: 10 [type=int] │ │ │ │ └── projections - │ │ │ │ └── const: 10 [type=int] - │ │ │ └── projections - │ │ │ └── plus [type=int] - │ │ │ ├── variable: column8 [type=int] - │ │ │ └── variable: column2 [type=int] - │ │ ├── scan mutation - │ │ │ └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int) - │ │ └── filters - │ │ └── eq [type=bool] - │ │ ├── variable: column1 [type=int] - │ │ └── variable: m [type=int] + │ │ │ │ └── plus [type=int] + │ │ │ │ ├── variable: column8 [type=int] + │ │ │ │ └── variable: column2 [type=int] + │ │ │ ├── scan mutation + │ │ │ │ └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int) + │ │ │ └── filters + │ │ │ └── eq [type=bool] + │ │ │ ├── variable: column1 [type=int] + │ │ │ └── variable: m [type=int] + │ │ └── projections + │ │ └── plus [type=int] + │ │ ├── variable: o [type=int] + │ │ └── variable: column2 [type=int] │ └── projections - │ └── plus [type=int] - │ ├── variable: o [type=int] - │ └── variable: column2 [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column1 [type=int] + │ │ └── variable: m [type=int] + │ ├── case [type=int] + │ │ ├── true [type=bool] + │ │ ├── when [type=int] + │ │ │ ├── is [type=bool] + │ │ │ │ ├── variable: m [type=int] + │ │ │ │ └── null [type=unknown] + │ │ │ └── variable: column8 [type=int] + │ │ └── variable: o [type=int] + │ └── case [type=int] + │ ├── true [type=bool] + │ ├── when [type=int] + │ │ ├── is [type=bool] + │ │ │ ├── variable: m [type=int] + │ │ │ └── null [type=unknown] + │ │ └── variable: column9 [type=int] + │ └── variable: column15 [type=int] └── projections - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column1 [type=int] - │ └── variable: m [type=int] - ├── case [type=int] - │ ├── true [type=bool] - │ ├── when [type=int] - │ │ ├── is [type=bool] - │ │ │ ├── variable: m [type=int] - │ │ │ └── null [type=unknown] - │ │ └── variable: column8 [type=int] - │ └── variable: o [type=int] - └── case [type=int] - ├── true [type=bool] - ├── when [type=int] - │ ├── is [type=bool] - │ │ ├── variable: m [type=int] - │ │ └── null [type=unknown] - │ └── variable: column9 [type=int] - └── variable: column15 [type=int] + └── gt [type=bool] + ├── variable: upsert_m [type=int] + └── const: 0 [type=int] # Use unknown name in upsert column list. build