diff --git a/pkg/sql/opt/xform/testdata/rules/insert b/pkg/sql/opt/xform/testdata/rules/insert new file mode 100644 index 000000000000..f309505d8579 --- /dev/null +++ b/pkg/sql/opt/xform/testdata/rules/insert @@ -0,0 +1,424 @@ +#################### +# InsertFastPath # +#################### + +exec-ddl +CREATE TABLE t ( + k INT PRIMARY KEY, + r STRING NOT NULL, + a INT, + b INT, + INDEX (r, a) WHERE k != 1, + UNIQUE WITHOUT INDEX (a) WHERE k != 1, + CHECK (r IN ('east', 'west')) +) +---- + +# Fast path is not allowed when there is a UNIQUE WITHOUT INDEX with a +# partial index predicate. +opt format=show-fastpathchecks +INSERT INTO t VALUES (1, 'east', 10, 100) +---- +insert t + ├── columns: + ├── insert-mapping: + │ ├── column1:7 => t.k:1 + │ ├── column2:8 => t.r:2 + │ ├── column3:9 => t.a:3 + │ └── column4:10 => t.b:4 + ├── check columns: check1:11 + ├── partial index put columns: partial_index_put1:12 + ├── cardinality: [0 - 0] + ├── volatile, mutations + ├── values + │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null check1:11!null partial_index_put1:12!null + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(7-12) + │ └── (1, 'east', 10, 100, true, false) + ├── unique-checks + │ └── unique-checks-item: t(a) + │ └── values + │ ├── columns: a:21!null + │ ├── cardinality: [0 - 0] + │ ├── key: () + │ └── fd: ()-->(21) + └── fast-path-unique-checks + └── fast-path-unique-checks-item: t(a) + └── values + ├── cardinality: [0 - 0] + └── key: () + +exec-ddl +DROP TABLE t +---- + +exec-ddl +CREATE TABLE t ( + k INT PRIMARY KEY, + r STRING NOT NULL, + a INT, + b INT AS (k % 9) STORED, + c INT, + INDEX (b, a), + INDEX (r, c), + UNIQUE WITHOUT INDEX (a), + UNIQUE WITHOUT INDEX (c), + CHECK (r IN ('east', 'west')) +) +---- + +# A computed leading index column allows fast path uniqueness checks. +# Note, the best-cost fast path check relation selected may not be one +# which would enable fast path uniqueness checks. +opt format=show-fastpathchecks +INSERT INTO t (k, r, a, c) VALUES (2, 'east', 10, 20) +---- +insert t + ├── columns: + ├── insert-mapping: + │ ├── column1:8 => t.k:1 + │ ├── column2:9 => t.r:2 + │ ├── column3:10 => t.a:3 + │ ├── b_comp:12 => t.b:4 + │ └── column4:11 => t.c:5 + ├── check columns: check1:13 + ├── cardinality: [0 - 0] + ├── volatile, mutations + ├── values + │ ├── columns: column1:8!null column2:9!null column3:10!null column4:11!null b_comp:12!null check1:13!null + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(8-13) + │ └── (2, 'east', 10, 20, 2, true) + ├── unique-checks + │ ├── unique-checks-item: t(a) + │ │ └── project + │ │ ├── columns: a:23!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(23) + │ │ └── project + │ │ ├── columns: a:23!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(23) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:14!null t.a:16!null a:23!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(14,16,23) + │ │ ├── values + │ │ │ ├── columns: a:23!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(23) + │ │ │ └── (10,) + │ │ ├── limit + │ │ │ ├── columns: t.k:14!null t.a:16!null + │ │ │ ├── cardinality: [0 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(14,16) + │ │ │ ├── select + │ │ │ │ ├── columns: t.k:14!null t.a:16!null + │ │ │ │ ├── key: (14) + │ │ │ │ ├── fd: ()-->(16) + │ │ │ │ ├── limit hint: 1.00 + │ │ │ │ ├── scan t + │ │ │ │ │ ├── columns: t.k:14!null t.a:16 + │ │ │ │ │ ├── constraint: /14 + │ │ │ │ │ │ ├── [ - /1] + │ │ │ │ │ │ └── [/3 - ] + │ │ │ │ │ ├── key: (14) + │ │ │ │ │ ├── fd: (14)-->(16) + │ │ │ │ │ └── limit hint: 35.71 + │ │ │ │ └── filters + │ │ │ │ └── t.a:16 = 10 [outer=(16), constraints=(/16: [/10 - /10]; tight), fd=()-->(16)] + │ │ │ └── 1 + │ │ └── filters (true) + │ └── unique-checks-item: t(c) + │ └── project + │ ├── columns: c:44!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(44) + │ └── project + │ ├── columns: c:44!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(44) + │ └── inner-join (cross) + │ ├── columns: t.k:33!null t.c:37!null c:44!null + │ ├── cardinality: [0 - 1] + │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ ├── key: () + │ ├── fd: ()-->(33,37,44) + │ ├── values + │ │ ├── columns: c:44!null + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(44) + │ │ └── (20,) + │ ├── scan t@t_r_c_idx + │ │ ├── columns: t.k:33!null t.c:37!null + │ │ ├── constraint: /34/37/33 + │ │ │ ├── [/'east'/20 - /'east'/20/1] + │ │ │ ├── [/'east'/20/3 - /'east'/20] + │ │ │ ├── [/'west'/20 - /'west'/20/1] + │ │ │ └── [/'west'/20/3 - /'west'/20] + │ │ ├── limit: 1 + │ │ ├── key: () + │ │ └── fd: ()-->(33,37) + │ └── filters (true) + └── fast-path-unique-checks + ├── fast-path-unique-checks-item: t(a) + │ └── select + │ ├── columns: t.k:26!null t.r:27!null t.a:28!null t.b:29 t.c:30 + │ ├── key: (26) + │ ├── fd: ()-->(28), (26)-->(27,29,30) + │ ├── index-join t + │ │ ├── columns: t.k:26!null t.r:27!null t.a:28 t.b:29 t.c:30 + │ │ ├── key: (26) + │ │ ├── fd: (26)-->(27-30) + │ │ └── scan t@t_r_c_idx + │ │ ├── columns: t.k:26!null t.r:27!null t.c:30 + │ │ ├── constraint: /27/30/26 + │ │ │ ├── [/'east' - /'east'] + │ │ │ └── [/'west' - /'west'] + │ │ ├── key: (26) + │ │ └── fd: (26)-->(27,30) + │ └── filters + │ └── t.a:28 = 10 [outer=(28), constraints=(/28: [/10 - /10]; tight), fd=()-->(28)] + └── fast-path-unique-checks-item: t(c) + └── index-join t + ├── columns: t.k:45!null t.r:46!null t.a:47 t.b:48 t.c:49!null + ├── key: (45) + ├── fd: ()-->(49), (45)-->(46-48) + └── scan t@t_r_c_idx + ├── columns: t.k:45!null t.r:46!null t.c:49!null + ├── constraint: /46/49/45 + │ ├── [/'east'/20 - /'east'/20] + │ └── [/'west'/20 - /'west'/20] + ├── key: (45) + └── fd: ()-->(49), (45)-->(46) + +exec-ddl +DROP TABLE t +---- + +exec-ddl +CREATE TABLE t ( + k INT PRIMARY KEY, + r STRING NOT NULL, + a INT, + b INT AS (k % 9) STORED, + INDEX (a), + INDEX (r, a, b), + INDEX (b, a), + UNIQUE WITHOUT INDEX (a), + UNIQUE WITHOUT INDEX (b), + UNIQUE WITHOUT INDEX (r, a, b), + UNIQUE WITHOUT INDEX (a, b), + CHECK (r IN ('east', 'west')) +) +---- + +# An insert to a table with multiple unique without index checks can build +# fast path checks for all of them. +opt format=show-fastpathchecks +INSERT INTO t (k, r, a) VALUES (2, 'east', 10) +---- +insert t + ├── columns: + ├── insert-mapping: + │ ├── column1:7 => t.k:1 + │ ├── column2:8 => t.r:2 + │ ├── column3:9 => t.a:3 + │ └── b_comp:10 => t.b:4 + ├── check columns: check1:11 + ├── cardinality: [0 - 0] + ├── volatile, mutations + ├── values + │ ├── columns: column1:7!null column2:8!null column3:9!null b_comp:10!null check1:11!null + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(7-11) + │ └── (2, 'east', 10, 2, true) + ├── unique-checks + │ ├── unique-checks-item: t(a) + │ │ └── project + │ │ ├── columns: a:20!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(20) + │ │ └── project + │ │ ├── columns: a:20!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(20) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:12!null t.a:14!null a:20!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(12,14,20) + │ │ ├── values + │ │ │ ├── columns: a:20!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(20) + │ │ │ └── (10,) + │ │ ├── scan t@t_a_idx + │ │ │ ├── columns: t.k:12!null t.a:14!null + │ │ │ ├── constraint: /14/12 + │ │ │ │ ├── [/10 - /10/1] + │ │ │ │ └── [/10/3 - /10] + │ │ │ ├── limit: 1 + │ │ │ ├── key: () + │ │ │ └── fd: ()-->(12,14) + │ │ └── filters (true) + │ ├── unique-checks-item: t(b) + │ │ └── project + │ │ ├── columns: b:37!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(37) + │ │ └── project + │ │ ├── columns: b:37!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(37) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:28!null t.b:31!null b:37!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(28,31,37) + │ │ ├── values + │ │ │ ├── columns: b:37!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(37) + │ │ │ └── (2,) + │ │ ├── limit + │ │ │ ├── columns: t.k:28!null t.b:31!null + │ │ │ ├── cardinality: [0 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(28,31) + │ │ │ ├── select + │ │ │ │ ├── columns: t.k:28!null t.b:31!null + │ │ │ │ ├── key: (28) + │ │ │ │ ├── fd: ()-->(31) + │ │ │ │ ├── limit hint: 1.00 + │ │ │ │ ├── scan t@t_b_a_idx + │ │ │ │ │ ├── columns: t.k:28!null t.b:31!null + │ │ │ │ │ ├── constraint: /31/30/28: [/2 - /2] + │ │ │ │ │ ├── key: (28) + │ │ │ │ │ ├── fd: ()-->(31) + │ │ │ │ │ └── limit hint: 1.07 + │ │ │ │ └── filters + │ │ │ │ └── t.k:28 != 2 [outer=(28), constraints=(/28: (/NULL - /1] [/3 - ]; tight)] + │ │ │ └── 1 + │ │ └── filters (true) + │ ├── unique-checks-item: t(r,a,b) + │ │ └── project + │ │ ├── columns: r:51!null a:52!null b:53!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(51-53) + │ │ └── project + │ │ ├── columns: r:51!null a:52!null b:53!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(51-53) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:44!null t.r:45!null t.a:46!null t.b:47!null r:51!null a:52!null b:53!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(44-47,51-53) + │ │ ├── values + │ │ │ ├── columns: r:51!null a:52!null b:53!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(51-53) + │ │ │ └── ('east', 10, 2) + │ │ ├── scan t@t_r_a_b_idx + │ │ │ ├── columns: t.k:44!null t.r:45!null t.a:46!null t.b:47!null + │ │ │ ├── constraint: /45/46/47/44 + │ │ │ │ ├── [/'east'/10/2 - /'east'/10/2/1] + │ │ │ │ └── [/'east'/10/2/3 - /'east'/10/2] + │ │ │ ├── limit: 1 + │ │ │ ├── key: () + │ │ │ └── fd: ()-->(44-47) + │ │ └── filters (true) + │ └── unique-checks-item: t(a,b) + │ └── project + │ ├── columns: a:68!null b:69!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(68,69) + │ └── project + │ ├── columns: a:68!null b:69!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(68,69) + │ └── inner-join (cross) + │ ├── columns: t.k:60!null t.a:62!null t.b:63!null a:68!null b:69!null + │ ├── cardinality: [0 - 1] + │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ ├── key: () + │ ├── fd: ()-->(60,62,63,68,69) + │ ├── values + │ │ ├── columns: a:68!null b:69!null + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(68,69) + │ │ └── (10, 2) + │ ├── scan t@t_b_a_idx + │ │ ├── columns: t.k:60!null t.a:62!null t.b:63!null + │ │ ├── constraint: /63/62/60 + │ │ │ ├── [/2/10 - /2/10/1] + │ │ │ └── [/2/10/3 - /2/10] + │ │ ├── limit: 1 + │ │ ├── key: () + │ │ └── fd: ()-->(60,62,63) + │ └── filters (true) + └── fast-path-unique-checks + ├── fast-path-unique-checks-item: t(a) + │ └── scan t@t_r_a_b_idx + │ ├── columns: t.k:22!null t.r:23!null t.a:24!null t.b:25 + │ ├── constraint: /23/24/25/22 + │ │ ├── [/'east'/10 - /'east'/10] + │ │ └── [/'west'/10 - /'west'/10] + │ ├── key: (22) + │ └── fd: ()-->(24), (22)-->(23,25) + ├── fast-path-unique-checks-item: t(b) + │ └── select + │ ├── columns: t.k:38!null t.r:39!null t.a:40 t.b:41!null + │ ├── key: (38) + │ ├── fd: ()-->(41), (38)-->(39,40) + │ ├── scan t@t_r_a_b_idx + │ │ ├── columns: t.k:38!null t.r:39!null t.a:40 t.b:41 + │ │ ├── constraint: /39/40/41/38 + │ │ │ ├── [/'east' - /'east'] + │ │ │ └── [/'west' - /'west'] + │ │ ├── key: (38) + │ │ └── fd: (38)-->(39-41) + │ └── filters + │ └── t.b:41 = 2 [outer=(41), constraints=(/41: [/2 - /2]; tight), fd=()-->(41)] + ├── fast-path-unique-checks-item: t(r,a,b) + │ └── scan t@t_r_a_b_idx + │ ├── columns: t.k:54!null t.r:55!null t.a:56!null t.b:57!null + │ ├── constraint: /55/56/57/54: [/'east'/10/2 - /'east'/10/2] + │ ├── key: (54) + │ └── fd: ()-->(55-57) + └── fast-path-unique-checks-item: t(a,b) + └── scan t@t_r_a_b_idx + ├── columns: t.k:70!null t.r:71!null t.a:72!null t.b:73!null + ├── constraint: /71/72/73/70 + │ ├── [/'east'/10/2 - /'east'/10/2] + │ └── [/'west'/10/2 - /'west'/10/2] + ├── key: (70) + └── fd: ()-->(72,73), (70)-->(71)