# --------------------------------------------------
# SimplifyPartialIndexProjections
# --------------------------------------------------

exec-ddl
CREATE TABLE t (
  k INT PRIMARY KEY,
  a INT,
  b INT,
  c INT,
  d INT,
  e INT,
  f INT,
  g INT,
  h BOOL,
  INDEX (a),
  INDEX (c) WHERE d > 1,
  INDEX (e) WHERE f > 1 AND g > 1,
  INDEX (b),
  INDEX (d) WHERE c > 1
)
----

# Simplify UPDATE partial index put/del column to false when the indexed columns
# and columns referenced in predicates are not mutating.
norm expect=SimplifyPartialIndexProjections
UPDATE t SET a = 2, b = 2 WHERE k = 1
----
update t
 ├── columns: <none>
 ├── fetch columns: k:12 a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
 ├── update-mapping:
 │    ├── a_new:23 => a:2
 │    └── a_new:23 => b:3
 ├── partial index put columns: partial_index_put1:24 partial_index_put2:25 partial_index_put3:26
 ├── partial index del columns: partial_index_put1:24 partial_index_put2:25 partial_index_put3:26
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: partial_index_put1:24!null partial_index_put2:25!null partial_index_put3:26!null a_new:23!null k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      ├── cardinality: [0 - 1]
      ├── key: ()
      ├── fd: ()-->(12-20,23-26)
      ├── select
      │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    ├── cardinality: [0 - 1]
      │    ├── key: ()
      │    ├── fd: ()-->(12-20)
      │    ├── scan t
      │    │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    │    ├── partial index predicates
      │    │    │    ├── t_c_idx: filters
      │    │    │    │    └── d:16 > 1 [outer=(16), constraints=(/16: [/2 - ]; tight)]
      │    │    │    ├── t_e_idx: filters
      │    │    │    │    ├── f:18 > 1 [outer=(18), constraints=(/18: [/2 - ]; tight)]
      │    │    │    │    └── g:19 > 1 [outer=(19), constraints=(/19: [/2 - ]; tight)]
      │    │    │    └── t_d_idx: filters
      │    │    │         └── c:15 > 1 [outer=(15), constraints=(/15: [/2 - ]; tight)]
      │    │    ├── flags: avoid-full-scan
      │    │    ├── key: (12)
      │    │    └── fd: (12)-->(13-20)
      │    └── filters
      │         └── k:12 = 1 [outer=(12), constraints=(/12: [/1 - /1]; tight), fd=()-->(12)]
      └── projections
           ├── false [as=partial_index_put1:24]
           ├── false [as=partial_index_put2:25]
           ├── false [as=partial_index_put3:26]
           └── 2 [as=a_new:23]

# Simplify UPDATE partial index put/del column to false for second partial index
# only.
norm expect=SimplifyPartialIndexProjections
UPDATE t SET a = 2, d = 2 WHERE k = 1
----
update t
 ├── columns: <none>
 ├── fetch columns: k:12 a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
 ├── update-mapping:
 │    ├── a_new:23 => a:2
 │    └── a_new:23 => d:5
 ├── partial index put columns: partial_index_put1:24 partial_index_put2:26 partial_index_put3:27
 ├── partial index del columns: partial_index_del1:25 partial_index_put2:26 partial_index_put3:27
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: partial_index_put1:24!null partial_index_del1:25 partial_index_put2:26!null partial_index_put3:27 a_new:23!null k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      ├── cardinality: [0 - 1]
      ├── key: ()
      ├── fd: ()-->(12-20,23-27)
      ├── select
      │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    ├── cardinality: [0 - 1]
      │    ├── key: ()
      │    ├── fd: ()-->(12-20)
      │    ├── scan t
      │    │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    │    ├── partial index predicates
      │    │    │    ├── t_c_idx: filters
      │    │    │    │    └── d:16 > 1 [outer=(16), constraints=(/16: [/2 - ]; tight)]
      │    │    │    ├── t_e_idx: filters
      │    │    │    │    ├── f:18 > 1 [outer=(18), constraints=(/18: [/2 - ]; tight)]
      │    │    │    │    └── g:19 > 1 [outer=(19), constraints=(/19: [/2 - ]; tight)]
      │    │    │    └── t_d_idx: filters
      │    │    │         └── c:15 > 1 [outer=(15), constraints=(/15: [/2 - ]; tight)]
      │    │    ├── flags: avoid-full-scan
      │    │    ├── key: (12)
      │    │    └── fd: (12)-->(13-20)
      │    └── filters
      │         └── k:12 = 1 [outer=(12), constraints=(/12: [/1 - /1]; tight), fd=()-->(12)]
      └── projections
           ├── true [as=partial_index_put1:24]
           ├── d:16 > 1 [as=partial_index_del1:25, outer=(16)]
           ├── false [as=partial_index_put2:26]
           ├── c:15 > 1 [as=partial_index_put3:27, outer=(15)]
           └── 2 [as=a_new:23]

# Do not simplify partial index put/del column to false when the indexed columns
# are mutating.
norm expect-not=SimplifyPartialIndexProjections
UPDATE t SET c = 1, e = 1 WHERE k = 1
----
update t
 ├── columns: <none>
 ├── fetch columns: k:12 a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
 ├── update-mapping:
 │    ├── c_new:23 => c:4
 │    └── c_new:23 => e:6
 ├── partial index put columns: partial_index_put1:24 partial_index_put2:25 partial_index_put3:26
 ├── partial index del columns: partial_index_put1:24 partial_index_put2:25 partial_index_del3:27
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: partial_index_put1:24 partial_index_put2:25 partial_index_put3:26!null partial_index_del3:27 c_new:23!null k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      ├── cardinality: [0 - 1]
      ├── key: ()
      ├── fd: ()-->(12-20,23-27)
      ├── select
      │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    ├── cardinality: [0 - 1]
      │    ├── key: ()
      │    ├── fd: ()-->(12-20)
      │    ├── scan t
      │    │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    │    ├── partial index predicates
      │    │    │    ├── t_c_idx: filters
      │    │    │    │    └── d:16 > 1 [outer=(16), constraints=(/16: [/2 - ]; tight)]
      │    │    │    ├── t_e_idx: filters
      │    │    │    │    ├── f:18 > 1 [outer=(18), constraints=(/18: [/2 - ]; tight)]
      │    │    │    │    └── g:19 > 1 [outer=(19), constraints=(/19: [/2 - ]; tight)]
      │    │    │    └── t_d_idx: filters
      │    │    │         └── c:15 > 1 [outer=(15), constraints=(/15: [/2 - ]; tight)]
      │    │    ├── flags: avoid-full-scan
      │    │    ├── key: (12)
      │    │    └── fd: (12)-->(13-20)
      │    └── filters
      │         └── k:12 = 1 [outer=(12), constraints=(/12: [/1 - /1]; tight), fd=()-->(12)]
      └── projections
           ├── d:16 > 1 [as=partial_index_put1:24, outer=(16)]
           ├── (f:18 > 1) AND (g:19 > 1) [as=partial_index_put2:25, outer=(18,19)]
           ├── false [as=partial_index_put3:26]
           ├── c:15 > 1 [as=partial_index_del3:27, outer=(15)]
           └── 1 [as=c_new:23]

# Do not simplify partial index put/del column to false when the columns
# referenced in partial index predicates are mutating.
norm expect-not=SimplifyPartialIndexProjections
UPDATE t SET d = d + 1, g = g + 1 WHERE k = 1
----
update t
 ├── columns: <none>
 ├── fetch columns: k:12 a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
 ├── update-mapping:
 │    ├── d_new:23 => d:5
 │    └── g_new:24 => g:8
 ├── partial index put columns: partial_index_put1:25 partial_index_put2:27 partial_index_put3:29
 ├── partial index del columns: partial_index_del1:26 partial_index_del2:28 partial_index_put3:29
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: partial_index_put1:25 partial_index_del1:26 partial_index_put2:27 partial_index_del2:28 partial_index_put3:29 k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20 d_new:23 g_new:24
      ├── cardinality: [0 - 1]
      ├── immutable
      ├── key: ()
      ├── fd: ()-->(12-20,23-29)
      ├── project
      │    ├── columns: d_new:23 g_new:24 k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    ├── cardinality: [0 - 1]
      │    ├── immutable
      │    ├── key: ()
      │    ├── fd: ()-->(12-20,23,24)
      │    ├── select
      │    │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    │    ├── cardinality: [0 - 1]
      │    │    ├── key: ()
      │    │    ├── fd: ()-->(12-20)
      │    │    ├── scan t
      │    │    │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    │    │    ├── partial index predicates
      │    │    │    │    ├── t_c_idx: filters
      │    │    │    │    │    └── d:16 > 1 [outer=(16), constraints=(/16: [/2 - ]; tight)]
      │    │    │    │    ├── t_e_idx: filters
      │    │    │    │    │    ├── f:18 > 1 [outer=(18), constraints=(/18: [/2 - ]; tight)]
      │    │    │    │    │    └── g:19 > 1 [outer=(19), constraints=(/19: [/2 - ]; tight)]
      │    │    │    │    └── t_d_idx: filters
      │    │    │    │         └── c:15 > 1 [outer=(15), constraints=(/15: [/2 - ]; tight)]
      │    │    │    ├── flags: avoid-full-scan
      │    │    │    ├── key: (12)
      │    │    │    └── fd: (12)-->(13-20)
      │    │    └── filters
      │    │         └── k:12 = 1 [outer=(12), constraints=(/12: [/1 - /1]; tight), fd=()-->(12)]
      │    └── projections
      │         ├── d:16 + 1 [as=d_new:23, outer=(16), immutable]
      │         └── g:19 + 1 [as=g_new:24, outer=(19), immutable]
      └── projections
           ├── d_new:23 > 1 [as=partial_index_put1:25, outer=(23)]
           ├── d:16 > 1 [as=partial_index_del1:26, outer=(16)]
           ├── (f:18 > 1) AND (g_new:24 > 1) [as=partial_index_put2:27, outer=(18,24)]
           ├── (f:18 > 1) AND (g:19 > 1) [as=partial_index_del2:28, outer=(18,19)]
           └── c:15 > 1 [as=partial_index_put3:29, outer=(15)]

# Do not simplify partial index put/del column to false when it is also an
# update column (h_new).
norm
UPDATE t SET h = d > 1 WHERE k = 1
----
update t
 ├── columns: <none>
 ├── fetch columns: k:12 a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
 ├── update-mapping:
 │    └── h_new:23 => h:9
 ├── partial index put columns: h_new:23 partial_index_put2:24 partial_index_put3:25
 ├── partial index del columns: h_new:23 partial_index_put2:24 partial_index_put3:25
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: partial_index_put2:24!null partial_index_put3:25!null h_new:23 k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      ├── cardinality: [0 - 1]
      ├── key: ()
      ├── fd: ()-->(12-20,23-25)
      ├── select
      │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    ├── cardinality: [0 - 1]
      │    ├── key: ()
      │    ├── fd: ()-->(12-20)
      │    ├── scan t
      │    │    ├── columns: k:12!null a:13 b:14 c:15 d:16 e:17 f:18 g:19 h:20
      │    │    ├── partial index predicates
      │    │    │    ├── t_c_idx: filters
      │    │    │    │    └── d:16 > 1 [outer=(16), constraints=(/16: [/2 - ]; tight)]
      │    │    │    ├── t_e_idx: filters
      │    │    │    │    ├── f:18 > 1 [outer=(18), constraints=(/18: [/2 - ]; tight)]
      │    │    │    │    └── g:19 > 1 [outer=(19), constraints=(/19: [/2 - ]; tight)]
      │    │    │    └── t_d_idx: filters
      │    │    │         └── c:15 > 1 [outer=(15), constraints=(/15: [/2 - ]; tight)]
      │    │    ├── flags: avoid-full-scan
      │    │    ├── key: (12)
      │    │    └── fd: (12)-->(13-20)
      │    └── filters
      │         └── k:12 = 1 [outer=(12), constraints=(/12: [/1 - /1]; tight), fd=()-->(12)]
      └── projections
           ├── false [as=partial_index_put2:24]
           ├── false [as=partial_index_put3:25]
           └── d:16 > 1 [as=h_new:23, outer=(16)]

# Regression for #74385. Do not simplify partial index put/del columns to false
# for one index which includes mutating columns where there is another index
# with the same predicate that does not include mutating columns.
exec-ddl
CREATE TABLE t74385 (
  k INT PRIMARY KEY,
  a INT,
  b INT,
  c INT,
  INDEX b_idx (b) WHERE c IS NULL,
  INDEX a_idx (a) WHERE c IS NULL
)
----

norm expect-not=SimplifyPartialIndexProjections
UPDATE t74385 SET b = NULL
----
update t74385
 ├── columns: <none>
 ├── fetch columns: k:7 a:8 b:9 c:10
 ├── update-mapping:
 │    └── b_new:13 => b:3
 ├── partial index put columns: partial_index_put1:14 partial_index_put1:14
 ├── partial index del columns: partial_index_put1:14 partial_index_put1:14
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: partial_index_put1:14!null b_new:13 k:7!null a:8 b:9 c:10
      ├── key: (7)
      ├── fd: ()-->(13), (7)-->(8-10), (10)-->(14)
      ├── scan t74385
      │    ├── columns: k:7!null a:8 b:9 c:10
      │    ├── partial index predicates
      │    │    ├── b_idx: filters
      │    │    │    └── c:10 IS NULL [outer=(10), constraints=(/10: [/NULL - /NULL]; tight), fd=()-->(10)]
      │    │    └── a_idx: filters
      │    │         └── c:10 IS NULL [outer=(10), constraints=(/10: [/NULL - /NULL]; tight), fd=()-->(10)]
      │    ├── flags: avoid-full-scan
      │    ├── key: (7)
      │    └── fd: (7)-->(8-10)
      └── projections
           ├── c:10 IS NULL [as=partial_index_put1:14, outer=(10)]
           └── CAST(NULL AS INT8) [as=b_new:13]

# Regression for #106663. Also simplify passthrough partial index put/del
# columns to false when the indexed columns and columns referenced in predicates
# are not changing.

exec-ddl
CREATE TABLE t106663 (a INT, b INT, c BOOL, INDEX (b) WHERE c, FAMILY (a, b), FAMILY (c))
----

norm expect=SimplifyPartialIndexProjections
UPDATE t106663 SET a = 1 WHERE true
----
update t106663
 ├── columns: <none>
 ├── fetch columns: a:7 b:8 rowid:10
 ├── update-mapping:
 │    └── a_new:13 => a:1
 ├── partial index put columns: partial_index_put2:14
 ├── partial index del columns: partial_index_del2:15
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: a_new:13!null partial_index_put2:14!null partial_index_del2:15!null a:7 b:8 rowid:10!null
      ├── key: (10)
      ├── fd: ()-->(13-15), (10)-->(7,8)
      ├── scan t106663
      │    ├── columns: a:7 b:8 rowid:10!null
      │    ├── partial index predicates
      │    │    └── t106663_b_idx: filters
      │    │         └── c:9 [outer=(9), constraints=(/9: [/true - /true]; tight), fd=()-->(9)]
      │    ├── flags: avoid-full-scan
      │    ├── key: (10)
      │    └── fd: (10)-->(7,8)
      └── projections
           ├── 1 [as=a_new:13]
           ├── false [as=partial_index_put2:14]
           └── false [as=partial_index_del2:15]

norm set=optimizer_use_lock_op_for_serializable=true expect=RemoveZeroCardLock
SELECT a FROM t WHERE a = 1 AND a = 2 FOR UPDATE;
----
values
 ├── columns: a:2!null
 ├── cardinality: [0 - 0]
 ├── key: ()
 └── fd: ()-->(2)

norm set=optimizer_use_lock_op_for_serializable=true expect=RemoveZeroCardLock
SELECT a FROM t WHERE a = 1 AND a = 2 FOR SHARE;
----
values
 ├── columns: a:2!null
 ├── cardinality: [0 - 0]
 ├── key: ()
 └── fd: ()-->(2)

norm set=optimizer_use_lock_op_for_serializable=true expect-not=RemoveZeroCardLock
SELECT a FROM t WHERE a = 1 FOR SHARE;
----
lock t
 ├── columns: a:2!null  [hidden: k:1!null]
 ├── key columns: k:1
 ├── lock columns: (12-20)
 ├── locking: for-share
 ├── volatile, mutations
 ├── key: (1)
 ├── fd: ()-->(2)
 └── select
      ├── columns: k:1!null a:2!null
      ├── key: (1)
      ├── fd: ()-->(2)
      ├── scan t
      │    ├── columns: k:1!null a:2
      │    ├── partial index predicates
      │    │    ├── t_c_idx: filters
      │    │    │    └── d:5 > 1 [outer=(5), constraints=(/5: [/2 - ]; tight)]
      │    │    ├── t_e_idx: filters
      │    │    │    ├── f:7 > 1 [outer=(7), constraints=(/7: [/2 - ]; tight)]
      │    │    │    └── g:8 > 1 [outer=(8), constraints=(/8: [/2 - ]; tight)]
      │    │    └── t_d_idx: filters
      │    │         └── c:4 > 1 [outer=(4), constraints=(/4: [/2 - ]; tight)]
      │    ├── key: (1)
      │    └── fd: (1)-->(2)
      └── filters
           └── a:2 = 1 [outer=(2), constraints=(/2: [/1 - /1]; tight), fd=()-->(2)]
