diff --git a/pkg/sql/opt/optbuilder/testdata/delete b/pkg/sql/opt/optbuilder/testdata/delete index 8b6a2524e594..34c5fa432438 100644 --- a/pkg/sql/opt/optbuilder/testdata/delete +++ b/pkg/sql/opt/optbuilder/testdata/delete @@ -510,3 +510,38 @@ delete t │ └── t.partial_index_del1:4 = 5 └── projections └── t.partial_index_del1:4 > 0 [as=partial_index_del1:7] + +# Test partial indexes with virtual columns in the predicate. +exec-ddl +CREATE TABLE partial_index_virtual ( + a INT PRIMARY KEY, + b INT, + c STRING, + d STRING AS (lower(c)) VIRTUAL, + INDEX (b) WHERE d = 'foo' +) +---- + +build +DELETE FROM partial_index_virtual +---- +delete partial_index_virtual + ├── columns: + ├── fetch columns: a:6 b:7 c:8 d:9 + ├── partial index del columns: partial_index_del1:11 + └── project + ├── columns: partial_index_del1:11 a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 + ├── project + │ ├── columns: d:9 a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:10 + │ ├── scan partial_index_virtual + │ │ ├── columns: a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:10 + │ │ ├── computed column expressions + │ │ │ └── d:9 + │ │ │ └── lower(c:8) + │ │ └── partial index predicates + │ │ └── secondary: filters + │ │ └── d:9 = 'foo' + │ └── projections + │ └── lower(c:8) [as=d:9] + └── projections + └── d:9 = 'foo' [as=partial_index_del1:11] diff --git a/pkg/sql/opt/optbuilder/testdata/insert b/pkg/sql/opt/optbuilder/testdata/insert index e0fa2e92fef4..cebf00ac12d7 100644 --- a/pkg/sql/opt/optbuilder/testdata/insert +++ b/pkg/sql/opt/optbuilder/testdata/insert @@ -1302,6 +1302,40 @@ insert t └── projections └── column1:4 > 0 [as=partial_index_put1:6] +# Test partial indexes with virtual columns in the predicate. +exec-ddl +CREATE TABLE partial_index_virtual ( + a INT PRIMARY KEY, + b INT, + c STRING, + d STRING AS (lower(c)) VIRTUAL, + INDEX (b) WHERE d = 'foo' +) +---- + +build +INSERT INTO partial_index_virtual (a, b, c) VALUES (2, 1, 'Foo') +---- +insert partial_index_virtual + ├── columns: + ├── insert-mapping: + │ ├── column1:6 => a:1 + │ ├── column2:7 => b:2 + │ ├── column3:8 => c:3 + │ └── column9:9 => d:4 + ├── partial index put columns: partial_index_put1:10 + └── project + ├── columns: partial_index_put1:10 column1:6!null column2:7!null column3:8!null column9:9 + ├── project + │ ├── columns: column9:9 column1:6!null column2:7!null column3:8!null + │ ├── values + │ │ ├── columns: column1:6!null column2:7!null column3:8!null + │ │ └── (2, 1, 'Foo') + │ └── projections + │ └── lower(column3:8) [as=column9:9] + └── projections + └── column9:9 = 'foo' [as=partial_index_put1:10] + # Regression test for issue #52546. Building partial index predicate expressions # that are only a single column reference should not panic. diff --git a/pkg/sql/opt/optbuilder/testdata/update b/pkg/sql/opt/optbuilder/testdata/update index 7e8c384cde1a..b55c8af1c600 100644 --- a/pkg/sql/opt/optbuilder/testdata/update +++ b/pkg/sql/opt/optbuilder/testdata/update @@ -1771,3 +1771,86 @@ update t └── projections ├── (partial_index_put1_new:9 > 0) AND (partial_index_del1_new:10 > 0) [as=partial_index_put1:11] └── (t.partial_index_put1:5 > 0) AND (t.partial_index_del1:6 > 0) [as=partial_index_del1:12] + +# Test partial indexes with virtual columns in the predicate. +exec-ddl +CREATE TABLE partial_index_virtual ( + a INT PRIMARY KEY, + b INT, + c STRING, + d STRING AS (lower(c)) VIRTUAL, + INDEX (b) WHERE d = 'foo' +) +---- + +build +UPDATE partial_index_virtual SET b = 1 +---- +update partial_index_virtual + ├── columns: + ├── fetch columns: a:6 b:7 c:8 d:9 + ├── update-mapping: + │ └── b_new:11 => b:2 + ├── partial index put columns: partial_index_put1:13 + ├── partial index del columns: partial_index_put1:13 + └── project + ├── columns: partial_index_put1:13 a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 b_new:11!null column12:12 + ├── project + │ ├── columns: column12:12 a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 b_new:11!null + │ ├── project + │ │ ├── columns: b_new:11!null a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 + │ │ ├── project + │ │ │ ├── columns: d:9 a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:10 + │ │ │ ├── scan partial_index_virtual + │ │ │ │ ├── columns: a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:10 + │ │ │ │ ├── computed column expressions + │ │ │ │ │ └── d:9 + │ │ │ │ │ └── lower(c:8) + │ │ │ │ └── partial index predicates + │ │ │ │ └── secondary: filters + │ │ │ │ └── d:9 = 'foo' + │ │ │ └── projections + │ │ │ └── lower(c:8) [as=d:9] + │ │ └── projections + │ │ └── 1 [as=b_new:11] + │ └── projections + │ └── lower(c:8) [as=column12:12] + └── projections + └── d:9 = 'foo' [as=partial_index_put1:13] + +build +UPDATE partial_index_virtual SET c = 'Bar' +---- +update partial_index_virtual + ├── columns: + ├── fetch columns: a:6 b:7 c:8 d:9 + ├── update-mapping: + │ ├── c_new:11 => c:3 + │ └── column12:12 => d:4 + ├── partial index put columns: partial_index_put1:13 + ├── partial index del columns: partial_index_del1:14 + └── project + ├── columns: partial_index_put1:13 partial_index_del1:14 a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 c_new:11!null column12:12 + ├── project + │ ├── columns: column12:12 a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 c_new:11!null + │ ├── project + │ │ ├── columns: c_new:11!null a:6!null b:7 c:8 d:9 crdb_internal_mvcc_timestamp:10 + │ │ ├── project + │ │ │ ├── columns: d:9 a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:10 + │ │ │ ├── scan partial_index_virtual + │ │ │ │ ├── columns: a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:10 + │ │ │ │ ├── computed column expressions + │ │ │ │ │ └── d:9 + │ │ │ │ │ └── lower(c:8) + │ │ │ │ └── partial index predicates + │ │ │ │ └── secondary: filters + │ │ │ │ └── d:9 = 'foo' + │ │ │ └── projections + │ │ │ └── lower(c:8) [as=d:9] + │ │ └── projections + │ │ └── 'Bar' [as=c_new:11] + │ └── projections + │ └── lower(c_new:11) [as=column12:12] + └── projections + ├── column12:12 = 'foo' [as=partial_index_put1:13] + └── d:9 = 'foo' [as=partial_index_del1:14] diff --git a/pkg/sql/opt/optbuilder/testdata/upsert b/pkg/sql/opt/optbuilder/testdata/upsert index 92f8e9fc4c6e..709c9d7278cc 100644 --- a/pkg/sql/opt/optbuilder/testdata/upsert +++ b/pkg/sql/opt/optbuilder/testdata/upsert @@ -2129,6 +2129,77 @@ INSERT INTO partial_indexes (a, b, c) VALUES (1, 1, 'foo') ON CONFLICT (a) DO UP ---- error (42702): column reference "b" is ambiguous (candidates: excluded.b, partial_indexes.b) +# Test partial indexes with virtual columns in the predicate. +exec-ddl +CREATE TABLE partial_index_virtual ( + a INT PRIMARY KEY, + b INT, + c STRING, + d STRING AS (lower(c)) VIRTUAL, + INDEX (b) WHERE d = 'foo' +) +---- + +build +INSERT INTO partial_index_virtual VALUES (2, 1, 'Foo') ON CONFLICT DO NOTHING +---- +insert partial_index_virtual + ├── columns: + ├── arbiter indexes: primary + ├── insert-mapping: + │ ├── column1:6 => a:1 + │ ├── column2:7 => b:2 + │ ├── column3:8 => c:3 + │ └── column9:9 => d:4 + ├── partial index put columns: partial_index_put1:15 + └── project + ├── columns: partial_index_put1:15 column1:6!null column2:7!null column3:8!null column9:9 + ├── upsert-distinct-on + │ ├── columns: column1:6!null column2:7!null column3:8!null column9:9 + │ ├── grouping columns: column1:6!null + │ ├── anti-join (hash) + │ │ ├── columns: column1:6!null column2:7!null column3:8!null column9:9 + │ │ ├── project + │ │ │ ├── columns: column9:9 column1:6!null column2:7!null column3:8!null + │ │ │ ├── values + │ │ │ │ ├── columns: column1:6!null column2:7!null column3:8!null + │ │ │ │ └── (2, 1, 'Foo') + │ │ │ └── projections + │ │ │ └── lower(column3:8) [as=column9:9] + │ │ ├── scan partial_index_virtual + │ │ │ ├── columns: a:10!null b:11 c:12 + │ │ │ ├── computed column expressions + │ │ │ │ └── d:13 + │ │ │ │ └── lower(c:12) + │ │ │ └── partial index predicates + │ │ │ └── secondary: filters + │ │ │ └── d:13 = 'foo' + │ │ └── filters + │ │ └── column1:6 = a:10 + │ └── aggregations + │ ├── first-agg [as=column2:7] + │ │ └── column2:7 + │ ├── first-agg [as=column3:8] + │ │ └── column3:8 + │ └── first-agg [as=column9:9] + │ └── column9:9 + └── projections + └── column9:9 = 'foo' [as=partial_index_put1:15] + +# TODO(mgartner): This should be successful once UPSERTs with virtual columns +# are supported. +build +INSERT INTO partial_index_virtual VALUES (2, 1, 'Foo') ON CONFLICT (a) DO UPDATE SET b = partial_index_virtual.b + 1, c = 'Bar' +---- +error (42703): column "d" does not exist + +# TODO(mgartner): This should be successful once UPSERTs with virtual columns +# are supported. +build +UPSERT INTO partial_index_virtual VALUES (2, 1, 'Foo') +---- +error (42703): column "d" does not exist + # ------------------------------------------------------------------------------ # Test unique partial indexes. # ------------------------------------------------------------------------------