# LogicTest: multiregion-9node-3region-3azs !metamorphic-batch-sizes
# TODO(#75864): enable multiregion-9node-3region-3azs-tenant and/or revert
# the commit that split these changes out.

# Set the closed timestamp interval to be short to shorten the amount of time
# we need to wait for the system config to propagate.
statement ok
SET CLUSTER SETTING kv.closed_timestamp.side_transport_interval = '10ms';

statement ok
SET CLUSTER SETTING kv.closed_timestamp.target_duration = '10ms';

statement ok
SET CLUSTER SETTING kv.rangefeed.closed_timestamp_refresh_interval = '10ms';

statement ok
CREATE DATABASE multi_region_test_db PRIMARY REGION "ca-central-1" REGIONS "ap-southeast-2", "us-east-1" SURVIVE REGION FAILURE;

statement ok
USE multi_region_test_db

statement ok
CREATE TABLE regional_by_row_table (
  pk int PRIMARY KEY,
  pk2 int NOT NULL,
  a int NOT NULL,
  b int NOT NULL,
  j JSON,
  INDEX (a),
  UNIQUE (b),
  INVERTED INDEX (j),
  FAMILY (pk, pk2, a, b)
) LOCALITY REGIONAL BY ROW

# Do a REGEXP replace of the enums as these may not be static.
query T retry
SELECT regexp_replace(info, '@\d+', '@<enum_val>', 'g') FROM
[EXPLAIN (OPT, CATALOG) SELECT * FROM regional_by_row_table]
----
TABLE regional_by_row_table
 ├── pk int not null
 ├── pk2 int not null
 ├── a int not null
 ├── b int not null
 ├── j jsonb
 ├── crdb_region crdb_internal_region not null default (default_to_database_primary_region(gateway_region())::@<enum_val>) [hidden]
 ├── crdb_internal_mvcc_timestamp decimal [hidden] [system]
 ├── tableoid oid [hidden] [system]
 ├── crdb_internal_origin_id int4 [hidden] [system]
 ├── crdb_internal_origin_timestamp decimal [hidden] [system]
 ├── j_inverted_key encodedkey not null [inverted]
 ├── FAMILY fam_0_pk_pk2_a_b_j_crdb_region (pk, pk2, a, b, j, crdb_region)
 ├── CHECK (crdb_region IN (x'40':::@<enum_val>, x'80':::@<enum_val>, x'c0':::@<enum_val>))
 ├── PRIMARY INDEX regional_by_row_table_pkey
 │    ├── crdb_region crdb_internal_region not null default (default_to_database_primary_region(gateway_region())::@<enum_val>) [hidden] (implicit)
 │    ├── pk int not null
 │    ├── ZONE
 │    │    ├── replica constraints
 │    │    │    ├── 1 replicas: [+region=ap-southeast-2]
 │    │    │    ├── 1 replicas: [+region=ca-central-1]
 │    │    │    └── 1 replicas: [+region=us-east-1]
 │    │    ├── voter constraints: [+region=ca-central-1]
 │    │    └── lease preference: [+region=ca-central-1]
 │    └── partitions
 │         ├── ap-southeast-2
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ap-southeast-2')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ap-southeast-2]
 │         │         └── lease preference: [+region=ap-southeast-2]
 │         ├── ca-central-1
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ca-central-1')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ca-central-1]
 │         │         └── lease preference: [+region=ca-central-1]
 │         └── us-east-1
 │              ├── partition by list prefixes
 │              │    └── ('us-east-1')
 │              └── ZONE
 │                   ├── replica constraints
 │                   │    ├── 1 replicas: [+region=ap-southeast-2]
 │                   │    ├── 1 replicas: [+region=ca-central-1]
 │                   │    └── 1 replicas: [+region=us-east-1]
 │                   ├── voter constraints: [+region=us-east-1]
 │                   └── lease preference: [+region=us-east-1]
 ├── INDEX regional_by_row_table_a_idx
 │    ├── crdb_region crdb_internal_region not null default (default_to_database_primary_region(gateway_region())::@<enum_val>) [hidden] (implicit)
 │    ├── a int not null
 │    ├── pk int not null
 │    ├── ZONE
 │    │    ├── replica constraints
 │    │    │    ├── 1 replicas: [+region=ap-southeast-2]
 │    │    │    ├── 1 replicas: [+region=ca-central-1]
 │    │    │    └── 1 replicas: [+region=us-east-1]
 │    │    ├── voter constraints: [+region=ca-central-1]
 │    │    └── lease preference: [+region=ca-central-1]
 │    └── partitions
 │         ├── ap-southeast-2
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ap-southeast-2')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ap-southeast-2]
 │         │         └── lease preference: [+region=ap-southeast-2]
 │         ├── ca-central-1
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ca-central-1')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ca-central-1]
 │         │         └── lease preference: [+region=ca-central-1]
 │         └── us-east-1
 │              ├── partition by list prefixes
 │              │    └── ('us-east-1')
 │              └── ZONE
 │                   ├── replica constraints
 │                   │    ├── 1 replicas: [+region=ap-southeast-2]
 │                   │    ├── 1 replicas: [+region=ca-central-1]
 │                   │    └── 1 replicas: [+region=us-east-1]
 │                   ├── voter constraints: [+region=us-east-1]
 │                   └── lease preference: [+region=us-east-1]
 ├── UNIQUE INDEX regional_by_row_table_b_key
 │    ├── crdb_region crdb_internal_region not null default (default_to_database_primary_region(gateway_region())::@<enum_val>) [hidden] (implicit)
 │    ├── b int not null
 │    ├── pk int not null (storing)
 │    ├── ZONE
 │    │    ├── replica constraints
 │    │    │    ├── 1 replicas: [+region=ap-southeast-2]
 │    │    │    ├── 1 replicas: [+region=ca-central-1]
 │    │    │    └── 1 replicas: [+region=us-east-1]
 │    │    ├── voter constraints: [+region=ca-central-1]
 │    │    └── lease preference: [+region=ca-central-1]
 │    └── partitions
 │         ├── ap-southeast-2
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ap-southeast-2')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ap-southeast-2]
 │         │         └── lease preference: [+region=ap-southeast-2]
 │         ├── ca-central-1
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ca-central-1')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ca-central-1]
 │         │         └── lease preference: [+region=ca-central-1]
 │         └── us-east-1
 │              ├── partition by list prefixes
 │              │    └── ('us-east-1')
 │              └── ZONE
 │                   ├── replica constraints
 │                   │    ├── 1 replicas: [+region=ap-southeast-2]
 │                   │    ├── 1 replicas: [+region=ca-central-1]
 │                   │    └── 1 replicas: [+region=us-east-1]
 │                   ├── voter constraints: [+region=us-east-1]
 │                   └── lease preference: [+region=us-east-1]
 ├── INVERTED INDEX regional_by_row_table_j_idx
 │    ├── crdb_region crdb_internal_region not null default (default_to_database_primary_region(gateway_region())::@<enum_val>) [hidden] (implicit)
 │    ├── j_inverted_key encodedkey not null [inverted]
 │    ├── pk int not null
 │    ├── ZONE
 │    │    ├── replica constraints
 │    │    │    ├── 1 replicas: [+region=ap-southeast-2]
 │    │    │    ├── 1 replicas: [+region=ca-central-1]
 │    │    │    └── 1 replicas: [+region=us-east-1]
 │    │    ├── voter constraints: [+region=ca-central-1]
 │    │    └── lease preference: [+region=ca-central-1]
 │    └── partitions
 │         ├── ap-southeast-2
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ap-southeast-2')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ap-southeast-2]
 │         │         └── lease preference: [+region=ap-southeast-2]
 │         ├── ca-central-1
 │         │    ├── partition by list prefixes
 │         │    │    └── ('ca-central-1')
 │         │    └── ZONE
 │         │         ├── replica constraints
 │         │         │    ├── 1 replicas: [+region=ap-southeast-2]
 │         │         │    ├── 1 replicas: [+region=ca-central-1]
 │         │         │    └── 1 replicas: [+region=us-east-1]
 │         │         ├── voter constraints: [+region=ca-central-1]
 │         │         └── lease preference: [+region=ca-central-1]
 │         └── us-east-1
 │              ├── partition by list prefixes
 │              │    └── ('us-east-1')
 │              └── ZONE
 │                   ├── replica constraints
 │                   │    ├── 1 replicas: [+region=ap-southeast-2]
 │                   │    ├── 1 replicas: [+region=ca-central-1]
 │                   │    └── 1 replicas: [+region=us-east-1]
 │                   ├── voter constraints: [+region=us-east-1]
 │                   └── lease preference: [+region=us-east-1]
 ├── UNIQUE WITHOUT INDEX (pk)
 └── UNIQUE WITHOUT INDEX (b)
scan regional_by_row_table
 └── check constraint expressions
      └── crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')


statement ok
INSERT INTO regional_by_row_table (pk, pk2, a, b, j) VALUES
  (1, 1, 2, 3, '{"a": "b"}'),
  (4, 4, 5, 6, '{"c": "d"}');
INSERT INTO multi_region_test_db.regional_by_row_table (crdb_region, pk, pk2, a, b) VALUES
  ('ca-central-1', 6, 6, 5, -5)

statement ok
CREATE UNIQUE INDEX uniq_idx ON regional_by_row_table(a) WHERE b > 0

query TI
INSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b) VALUES
('ca-central-1', 7, 7, 8, 9)
RETURNING crdb_region, pk
----
ca-central-1  7

query TI nodeidx=3
USE multi_region_test_db; INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES
(10, 10, 11, 12)
RETURNING crdb_region, pk
----
ca-central-1  10

query TI nodeidx=6
USE multi_region_test_db; INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES
(20, 20, 21, 22)
RETURNING crdb_region, pk
----
us-east-1  20

query TI
INSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b) VALUES
(gateway_region()::crdb_internal_region, 23, 23, 24, 25)
RETURNING crdb_region, pk
----
ap-southeast-2  23

query TT
SELECT start_key, end_key FROM [SHOW RANGE FROM TABLE regional_by_row_table FOR ROW ('ap-southeast-2', 1)]
----
<before:/Table/72>  …

query TIIII
SELECT crdb_region, pk, pk2, a, b FROM regional_by_row_table
ORDER BY pk
----
ap-southeast-2  1   1   2   3
ap-southeast-2  4   4   5   6
ca-central-1    6   6   5   -5
ca-central-1    7   7   8   9
ca-central-1    10  10  11  12
us-east-1       20  20  21  22
ap-southeast-2  23  23  24  25

query IIIIT colnames
SELECT * FROM regional_by_row_table ORDER BY pk
----
pk  pk2  a   b   j
1   1    2   3   {"a": "b"}
4   4    5   6   {"c": "d"}
6   6    5   -5  NULL
7   7    8   9   NULL
10  10   11  12  NULL
20  20   21  22  NULL
23  23   24  25  NULL


# Test that a limited, ordered scan is efficient.
query T retry
SELECT * FROM [EXPLAIN (VERBOSE) SELECT * FROM regional_by_row_table
ORDER BY pk LIMIT 5] OFFSET 2
----
·
• limit
│ columns: (pk, pk2, a, b, j)
│ count: 5
│
└── • union all
    │ columns: (pk, pk2, a, b, j)
    │ ordering: +pk
    │ estimated row count: 15 (missing stats)
    │
    ├── • union all
    │   │ columns: (pk, pk2, a, b, j)
    │   │ ordering: +pk
    │   │ estimated row count: 10 (missing stats)
    │   │
    │   ├── • scan
    │   │     columns: (pk, pk2, a, b, j)
    │   │     ordering: +pk
    │   │     estimated row count: 5 (missing stats)
    │   │     table: regional_by_row_table@regional_by_row_table_pkey
    │   │     spans: /"@"-/"@"/PrefixEnd
    │   │     limit: 5
    │   │
    │   └── • scan
    │         columns: (pk, pk2, a, b, j)
    │         ordering: +pk
    │         estimated row count: 5 (missing stats)
    │         table: regional_by_row_table@regional_by_row_table_pkey
    │         spans: /"\x80"-/"\x80"/PrefixEnd
    │         limit: 5
    │
    └── • scan
          columns: (pk, pk2, a, b, j)
          ordering: +pk
          estimated row count: 5 (missing stats)
          table: regional_by_row_table@regional_by_row_table_pkey
          spans: /"\xc0"-/"\xc0"/PrefixEnd
          limit: 5

# Test that the synthesized UNIQUE WITHOUT INDEX constraints do not cause
# lookups into redundant arbiters.
query T retry
SELECT * FROM [
  EXPLAIN INSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b)
  VALUES ('ca-central-1', 7, 7, 8, 9) ON CONFLICT DO NOTHING
] OFFSET 2
----
·
• insert
│ into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
│ auto commit
│ arbiter constraints: regional_by_row_table_pkey, regional_by_row_table_b_key, uniq_idx
│
└── • render
    │
    └── • lookup join (anti)
        │ table: regional_by_row_table@uniq_idx (partial index)
        │ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column4 = a)
        │ pred: column5 > 0
        │
        └── • lookup join (anti)
            │ table: regional_by_row_table@uniq_idx (partial index)
            │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column4 = a)
            │ pred: column5 > 0
            │
            └── • lookup join (anti)
                │ table: regional_by_row_table@regional_by_row_table_b_key
                │ equality cols are key
                │ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column5 = b)
                │
                └── • lookup join (anti)
                    │ table: regional_by_row_table@regional_by_row_table_b_key
                    │ equality cols are key
                    │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column5 = b)
                    │
                    └── • cross join (anti)
                        │
                        ├── • values
                        │     size: 6 columns, 1 row
                        │
                        └── • union all
                            │ limit: 1
                            │
                            ├── • scan
                            │     missing stats
                            │     table: regional_by_row_table@regional_by_row_table_pkey
                            │     spans: [/'ap-southeast-2'/7 - /'ap-southeast-2'/7]
                            │
                            └── • scan
                                  missing stats
                                  table: regional_by_row_table@regional_by_row_table_pkey
                                  spans: [/'ca-central-1'/7 - /'ca-central-1'/7] [/'us-east-1'/7 - /'us-east-1'/7]

# Tests for locality optimized search.

# Split the table into 3 regions and change the leaseholders to be "local"
# according to the crdb_region column.
statement ok
ALTER TABLE regional_by_row_table SPLIT AT VALUES ('ca-central-1', 0), ('us-east-1', 0);
ALTER TABLE regional_by_row_table EXPERIMENTAL_RELOCATE VALUES (ARRAY[1], 'ap-southeast-2', 0), (ARRAY[4], 'ca-central-1', 0), (ARRAY[7], 'us-east-1', 0);

query TTTI colnames,rowsort
SELECT start_key, end_key, replicas, lease_holder FROM [SHOW RANGES FROM INDEX regional_by_row_table@primary WITH DETAILS]
ORDER BY 1
----
start_key           end_key               replicas  lease_holder
<before:/Table/72>  …/"\x80"/0            {1}       1
…/"\x80"/0          …/"\xc0"/0            {4}       4
…/"\xc0"/0          <after:/Table/110/5>  {7}       7

statement ok
SET locality_optimized_partitioned_index_scan = false

# Query with locality optimized search disabled.
query T
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM regional_by_row_table WHERE pk = 1] OFFSET 2
----
·
• scan
  missing stats
  table: regional_by_row_table@regional_by_row_table_pkey
  spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1] [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy8klGrmzAUx9_3KcJ52kaKxu5hBAZ33Fom9LZ3VdjgViTVczunNVkS6S3F7z602-6tuLH2oXkQcnL8nf8vegDzowQOoT_zbyPylkyXizvy4H-9n30M5uT1JAij8PPsDTlt0LjJZSXKZL1PtNwlVqxLJF8--UufqIJ8ICwmi-k09CPiAYVKZjgXWzTAH4BBTEFpmaIxUrelQ9cQZE_AXQp5pWrblmMKqdQI_AA2tyUCh6ids0SRoXZcoJChFXnZYQcj3QxWE1XgHijcyrLeVoYTVVCiCo8SQcmaku9AIVSiPXFWcLMChzkuxA0FWdvncMaKDQJnL2yCCXC3oZcJsSsJrVZP790zpdilUt71pNJzpby_Sj271JXUGWrMTjziZkB7LkdSOeNe43AUrxdlfM79LtEoWRn8r0lub9KItdkx2-BR1Mhap3ivZdr1HreLDtQVMjT2eDo-boKqO2LtBI1i--eff0lil5JYn-RdSvL6pPE_Se9OSO6pXUzhsZS7JM-Ag_trjQYevxe0L4iNaT9b-E3uOmy0V-2lP4rSIIU7UeAELeptXuXG5ilwq2tsmlc_AwAA__9wGtJB

statement ok
SET vectorize=on

query T
EXPLAIN (VEC) SELECT * FROM regional_by_row_table WHERE pk = 1
----
│
└ Node 1
  └ *colexec.ParallelUnorderedSynchronizer
    ├ *colfetcher.ColBatchScan
    ├ *colfetcher.ColBatchScan
    └ *colfetcher.ColBatchScan

statement ok
RESET vectorize

statement ok
SET tracing = on,kv,results; SELECT * FROM regional_by_row_table WHERE pk = 1; SET tracing = off

# All rows are scanned at once without the optimization.
query T rowsort
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/110/1/"@"/1/0
Scan /Table/110/1/"\x80"/1/0
Scan /Table/110/1/"\xc0"/1/0
fetched: /regional_by_row_table/regional_by_row_table_pkey/?/1/pk2/a/b/j -> /1/2/3/'{"a": "b"}'
output row: [1 1 2 3 '{"a": "b"}']

statement ok
SET locality_optimized_partitioned_index_scan = true

# Same query with locality optimized search enabled.

# First check the plan with the vectorized engine.
statement ok
SET vectorize=on

query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM regional_by_row_table WHERE pk = 1] OFFSET 2
----
·
• union all
│ limit: 1
│
├── • scan
│     missing stats
│     table: regional_by_row_table@regional_by_row_table_pkey
│     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│
└── • scan
      missing stats
      table: regional_by_row_table@regional_by_row_table_pkey
      spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy8k1Fr2zAUhd_3K8R92oZCLCeDIRh0NA4LpEkXBzZoTFDs20yLY2mSTBqC__uws621cbomD9WDQVfX3z3nyD6A_ZUChzAYB9dz8p4MZ9Mbchd8vx1_Hk3I28EonIdfx-9IvcHgWqpMpMvVfmnUbunEKkXy7UswC4jekE-ERWQ6HIbBnPhAIVMJTsQWLfA7YBBR0EbFaK0yZelQNYySB-AeBZnp3JXliEKsDAI_gJMuReAwL-fMUCRouh5QSNAJmVbYVklXrdWl3uAeKFyrNN9mlhO9oURvfEoEJStKfgKFUIvypLuAxeLho7eALut6EBUUVO4eBVon1gicPXE0GgD3CnqZKfZ6puJzTbGTph695JkyCRpMaj6iosX2RHWU7vqNxnYpfkOKf2m-vVfK9-o_2fYahnovyNaikSIlZ0fcr3sey610hJ2U5jWk9c_JeoZWq8zii261OanDShOYrPFo3KrcxHhrVFz1HrfTClQVErTueOofN6OsOmLlBINi--9XfEpil5JYk-Q_S-qfJvWapN6lJL9J6j9L-lAjefWcIgr3qdotZQIcvD-r0_L4u6B8Qaxt-QGEP9Suws73ury-e5FapHAjNjhAh2YrM2mdjIE7k2NRvPkdAAD__67tHiA=

query T
EXPLAIN (VEC) SELECT * FROM regional_by_row_table WHERE pk = 1
----
│
└ Node 1
  └ *colexec.limitOp
    └ *colexec.SerialUnorderedSynchronizer
      ├ *colfetcher.ColBatchScan
      └ *colexec.ParallelUnorderedSynchronizer
        ├ *colfetcher.ColBatchScan
        └ *colfetcher.ColBatchScan

# Now check the physical plan for the row-by-row engine.
statement ok
SET vectorize=off

query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM regional_by_row_table WHERE pk = 1] AS temp(a) WHERE a LIKE '%Diagram%'
----
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy8kFFr2zAQx9_3KY6D0nYoxPJehmDQ0njMLE27OLBBY4ISXVMttqVJMmkI-e7DTrc2IRlbH6YHg-7OP_1_t0b_o0CBWdJPrkbwFj4Ob67hLvl2279MB3DWS7NR9qV_DrsDjubaVLKYTFcTZ5aTIKcFwddPyTABu4APwHO4zCBQaeFMnj91JPTTzwmcnvS0nDtZnpwiw8ooGsiSPIo75JgztM7MyHvjmtK6HUjVI4qIoa5sHZpyznBmHKFYY9ChIBQ4ajIMSSpy3QgZKgpSFy32YNyLg9WJXdAKGV6Zoi4rL8AuGNhFzEAymDL4jgwzK5tOd4zj8eP7aIxd3o1AVgo4mPBADvMNQ1OH57A-yDmh4C_s0h6KaMNeJ8j_k-DFVu6oULwnxI8KPXt4cloWUFfGKXKkdlTyzQHzgekY2413nfu61AH40WjRXrT4X3Y9JG9N5Wkv29-91OGNBKk5bcW9qd2Mbp2ZtbPb600LaguKfNh24-0lrdoWb15wJMvfm31J4q8lRfuk-I-kdzukaJeUM7wvzHKiFQqMnk7nwOfXweYHOffNsrMHs2yxo5VtVnUvC08Mr-WCehTIlbrSPugZiuBq2mze_AwAAP__m_KD0g==

statement ok
RESET vectorize

statement ok
SET tracing = on,kv,results; SELECT * FROM regional_by_row_table WHERE pk = 1; SET tracing = off

# If the row is found in the local region, the other regions are not searched.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/110/1/"@"/1/0
fetched: /regional_by_row_table/regional_by_row_table_pkey/?/1/pk2/a/b/j -> /1/2/3/'{"a": "b"}'
output row: [1 1 2 3 '{"a": "b"}']

statement ok
SET vectorize=on

statement ok
SET tracing = on,kv,results; SELECT * FROM regional_by_row_table WHERE pk = 10; SET tracing = off

# If the row is not found in the local region, the other regions are searched
# in parallel. Note that if the row is quickly found in one remote region, the
# other remote region might not be read from at all.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%' AND message NOT LIKE 'Scan%"\\xc0"%'
 ORDER BY ordinality ASC
----
Scan /Table/110/1/"@"/10/0
Scan /Table/110/1/"\x80"/10/0
fetched: /regional_by_row_table/regional_by_row_table_pkey/?/10/pk2/a/b -> /10/11/12
output row: [10 10 11 12 NULL]

statement ok
SET vectorize=off

statement ok
SET tracing = on,kv,results; SELECT * FROM regional_by_row_table WHERE pk = 10; SET tracing = off

# If the row is not found in the local region, the other regions are searched
# in parallel.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/110/1/"@"/10/0
Scan /Table/110/1/"\x80"/10/0, /Table/110/1/"\xc0"/10/0
fetched: /regional_by_row_table/regional_by_row_table_pkey/'ca-central-1'/10/pk2/a/b -> /10/11/12
output row: [10 10 11 12 NULL]

statement ok
RESET vectorize

# The local region for this query is ca-central-1, so that span should be
# scanned in the first child of the limited union all.
query T nodeidx=3 retry
USE multi_region_test_db; SET locality_optimized_partitioned_index_scan = true;
SELECT * FROM [EXPLAIN SELECT * FROM regional_by_row_table WHERE pk = 1] OFFSET 2
----
·
• union all
│ limit: 1
│
├── • scan
│     missing stats
│     table: regional_by_row_table@regional_by_row_table_pkey
│     spans: [/'ca-central-1'/1 - /'ca-central-1'/1]
│
└── • scan
      missing stats
      table: regional_by_row_table@regional_by_row_table_pkey
      spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1] [/'us-east-1'/1 - /'us-east-1'/1]


# Query with more than one key.
query T retry
SELECT * FROM [EXPLAIN SELECT * FROM regional_by_row_table WHERE pk IN (1, 4)] OFFSET 2
----
·
• union all
│ limit: 2
│
├── • scan
│     missing stats
│     table: regional_by_row_table@regional_by_row_table_pkey
│     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1] [/'ap-southeast-2'/4 - /'ap-southeast-2'/4]
│
└── • scan
      missing stats
      table: regional_by_row_table@regional_by_row_table_pkey
      spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'ca-central-1'/4 - /'ca-central-1'/4] [/'us-east-1'/1 - /'us-east-1'/1] [/'us-east-1'/4 - /'us-east-1'/4]

statement ok
SET tracing = on,kv,results; SELECT * FROM regional_by_row_table WHERE pk IN (1, 4); SET tracing = off

# Both rows are found in the local region, so the other regions are not searched.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/110/1/"@"/1/0, /Table/110/1/"@"/4/0
fetched: /regional_by_row_table/regional_by_row_table_pkey/?/1/pk2/a/b/j -> /1/2/3/'{"a": "b"}'
output row: [1 1 2 3 '{"a": "b"}']
fetched: /regional_by_row_table/regional_by_row_table_pkey/?/4/pk2/a/b/j -> /4/5/6/'{"c": "d"}'
output row: [4 4 5 6 '{"c": "d"}']

# Tests using locality optimized search for lookup joins (including foreign
# key checks).
statement ok
CREATE TABLE parent (
  p_id INT PRIMARY KEY,
  FAMILY (p_id)
) LOCALITY REGIONAL BY ROW;

statement ok
CREATE TABLE child (
  c_id INT PRIMARY KEY,
  c_p_id INT REFERENCES parent (p_id),
  INDEX (c_p_id),
  FAMILY (c_id, c_p_id)
) LOCALITY REGIONAL BY ROW;

statement ok
INSERT INTO parent (crdb_region, p_id)
VALUES ('ap-southeast-2', 10), ('ca-central-1', 20), ('us-east-1', 30)

statement ok
INSERT INTO child (crdb_region, c_id, c_p_id)
VALUES ('ap-southeast-2', 10, 10), ('ca-central-1', 20, 20), ('us-east-1', 30, 30)

# Split the child table into 3 regions and change the leaseholders to be "local"
# according to the crdb_region column.
statement ok
ALTER TABLE child SPLIT AT VALUES ('ca-central-1', 0), ('us-east-1', 0);
ALTER TABLE child EXPERIMENTAL_RELOCATE VALUES (ARRAY[1], 'ap-southeast-2', 0), (ARRAY[4], 'ca-central-1', 0), (ARRAY[7], 'us-east-1', 0);

query TTTI colnames,rowsort
SELECT start_key, end_key, replicas, lease_holder FROM [SHOW RANGES FROM INDEX child@primary WITH DETAILS]
----
start_key              end_key       replicas  lease_holder
<before:/Table/110/6>  …/"\x80"/0    {1}       1
…/"\x80"/0             …/"\xc0"/0    {4}       4
…/"\xc0"/0             <after:/Max>  {7}       7

statement ok
SET locality_optimized_partitioned_index_scan = false

# Anti join with locality optimized search disabled.
query T
SELECT * FROM [EXPLAIN SELECT * FROM child WHERE NOT EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10] OFFSET 2
----
·
• lookup join (anti)
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • scan
      missing stats
      table: child@child_pkey
      spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10] [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child WHERE NOT EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10; SET tracing = off

# All regions are scanned without the optimization.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0, /Table/112/1/"\x80"/10/0, /Table/112/1/"\xc0"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0, /Table/111/1/"\x80"/10/0, /Table/111/1/"\xc0"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>

# Semi join with locality optimized search disabled.
query T
SELECT * FROM [EXPLAIN SELECT * FROM child WHERE EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10] OFFSET 2
----
·
• lookup join (semi)
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • scan
      missing stats
      table: child@child_pkey
      spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10] [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child WHERE EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10; SET tracing = off

# All regions are scanned without the optimization.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0, /Table/112/1/"\x80"/10/0, /Table/112/1/"\xc0"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0, /Table/111/1/"\x80"/10/0, /Table/111/1/"\xc0"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>
output row: [10 10]

# Inner join with locality optimized search disabled.
query T
SELECT * FROM [EXPLAIN SELECT * FROM child INNER JOIN parent ON p_id = c_p_id WHERE c_id = 10] OFFSET 2
----
·
• lookup join
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • scan
      missing stats
      table: child@child_pkey
      spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10] [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child INNER JOIN parent ON p_id = c_p_id WHERE c_id = 10; SET tracing = off

# All regions are scanned without the optimization.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0, /Table/112/1/"\x80"/10/0, /Table/112/1/"\xc0"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0, /Table/111/1/"\x80"/10/0, /Table/111/1/"\xc0"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>
output row: [10 10 10]

# Left join with locality optimized search disabled.
query T
SELECT * FROM [EXPLAIN SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 10] OFFSET 2
----
·
• lookup join (left outer)
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • scan
      missing stats
      table: child@child_pkey
      spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10] [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 10; SET tracing = off

# All regions are scanned without the optimization.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0, /Table/112/1/"\x80"/10/0, /Table/112/1/"\xc0"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0, /Table/111/1/"\x80"/10/0, /Table/111/1/"\xc0"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>
output row: [10 10 10]

statement ok
SET locality_optimized_partitioned_index_scan = true

# Anti join with locality optimized search enabled.
query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM child WHERE NOT EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10] OFFSET 2
----
·
• lookup join (anti)
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • lookup join (anti)
    │ table: parent@parent_pkey
    │ equality cols are key
    │ lookup condition: (crdb_region = 'ap-southeast-2') AND (c_p_id = p_id)
    │
    └── • union all
        │ limit: 1
        │
        ├── • scan
        │     missing stats
        │     table: child@child_pkey
        │     spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10]
        │
        └── • scan
              missing stats
              table: child@child_pkey
              spans: [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJyslNFr6kgUxt_3rzicF3VJcRJdKAOFlBrZFBu7GthCFUmTUzu3MZM7k1BL8X-_TGJvTajltjQP0Zwcf_N9Zz7nBfXPFDnOvYl3EcLfMJ5Nr-DWu7menPsBdEf-PJz_N-lBsyF-EGkC___rzTzoBtMQvBvTCN1mWx4pyop9X74SCZxBvDJfej04D0bQjeuizXpLmI7Hcy8EBy3MZEJBtCGN_BZtXFqYKxmT1lKZ0kvV4Cdb5MxCkeVlYcpLC2OpCPkLFqJICTmG0V1KM4oSUn2GFiZURCKtsJUHt7qv8kd6RgsvZFpuMs3ByLL2UtHCeR6Zan-Bi8X2lC2wb7M-gyhLwAZZPJDC5c5CWRZvSnQRrQm5fSDdHyFnO-tr6u1vUO_ulR9V67TU2kfVvonUpESUQplJlZCipKFzuXvHViBPZN53moYmYiMKsI9KYy1pzmcGeSlFtp_joLls-JwTh4k3DuE8CH24nPoBWlgn160_Xgc8kfKxzOGHFBnIjEPXHcIZbDtD1uGcuzZjNjvdB9t14AzcQe9wX_J6X1Ryt1K0FjI7anbQMjv4otnh95o1J8K2c3po14JtJ274_5YBDFsDGH5mADPSucw0tZL4Z7k6sU1kKVlTHXMtSxXTtZJx1Vs_TitQVUhIF_Vbp37ws-qVbVZQFG1-_48OSfZXSaxNcj4kDRokdkhy2qTBh6ThcdKgTRp-SPrnOImZ2d-n8smcXBzZ_jp55_Z6oflBtNYmAPMH-VRhTdA18vso1WThVfRIIypIbUQmdCFi5IUqabf761cAAAD__yS4NdA=

statement ok
SET vectorize=on

query T
EXPLAIN (VEC) SELECT * FROM child WHERE NOT EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10
----
│
└ Node 1
  └ *rowexec.joinReader
    └ *rowexec.joinReader
      └ *colexec.limitOp
        └ *colexec.SerialUnorderedSynchronizer
          ├ *colfetcher.ColBatchScan
          └ *colfetcher.ColBatchScan

statement ok
RESET vectorize

statement ok
SET tracing = on,kv,results; SELECT * FROM child WHERE NOT EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10; SET tracing = off

# If the row is found in the local region, the other regions are not searched.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>

statement ok
SET tracing = on,kv,results; SELECT * FROM child WHERE NOT EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 20; SET tracing = off

# If the row is not found in the local region, the other regions are searched in
# parallel.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/20/0
Scan /Table/112/1/"\x80"/20/0, /Table/112/1/"\xc0"/20/0
fetched: /child/child_pkey/?/20/c_p_id -> /20
Scan /Table/111/1/"@"/20/0
Scan /Table/111/1/"\x80"/20/0, /Table/111/1/"\xc0"/20/0
fetched: /parent/parent_pkey/'ca-central-1'/20 -> <undecoded>

# Semi join with locality optimized search enabled.
query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM child WHERE EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10] OFFSET 2
----
·
• lookup join (semi)
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region = 'ap-southeast-2') AND (c_p_id = p_id)
│ remote lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • union all
    │ limit: 1
    │
    ├── • scan
    │     missing stats
    │     table: child@child_pkey
    │     spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10]
    │
    └── • scan
          missing stats
          table: child@child_pkey
          spans: [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJysk0Fv4jwQhu_frxjNBfjkCif0UFmqRFWClopClyBtpYJQmkyptyHO2o5KVfHfV05oS9hSbavNweDx-PXjd8bPaH6lKDAMhsH5FP6H_mR8CTfB9dXwbDCCZm8QTsPvwxbUE-J7mSbw41swCSC4djnQrGfkkabMblPyhUzgFOKF-9OCs1EPmnEV83hrDuN-Pwym4CPDTCU0ilZkUNygh3OGuVYxGaO0Cz2XCYNkjYIzlFleWBeeM4yVJhTPaKVNCQVOo9uUJhQlpNscGSZkI5mWsiV9txwX-QM9IcNzlRarzAhwWGxLigzDPHLR9gxns_UJn2Hb420OUZaAB8rek8b5hqEq7BuJsdGSUHg76IMeCr5hX6P3_gF9d0t-kNbfo_UO0r5BGtIySqHIlE5IU1LjnG_eudZIHam87dcvNJQracE7iMb30PzPGHmhZLb1sVM_dvqUk4Bh0J9CGFwO4GI8GCHDqnG71c-LwUOlHoocfiqZgcoENLvHcArrxjFvCCG6HuceP9k2dteHU-h2WshwQitlCdJ3drvHtW6c7O5nsG7ENcE_FV8rnVeV1sntQtNSquygfZ09-zqfsW9CJleZob3S_l2hjjzXA5Qsqeobowod05VWcZlbTcelUBlIyNhq1a8mg6xc8twJmqLVa2PuKnlfVeL7Sv6HSp2aEt9V8veVOh8qHR9W4s6xu1Q9ugcskG-_o3eGlw_dhmhpXNnCe_VYyrrmNijuotQQw8vogXpkSa9kJo2VMQqrC9ps_vsdAAD__6Zd4k0=

statement ok
SET vectorize=on

query T
EXPLAIN (VEC) SELECT * FROM child WHERE EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10
----
│
└ Node 1
  └ *rowexec.joinReader
    └ *colexec.limitOp
      └ *colexec.SerialUnorderedSynchronizer
        ├ *colfetcher.ColBatchScan
        └ *colfetcher.ColBatchScan

statement ok
RESET vectorize

statement ok
SET tracing = on,kv,results; SELECT * FROM child WHERE EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 10; SET tracing = off

# If the row is found in the local region, the other regions are not searched.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>
output row: [10 10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child WHERE EXISTS (SELECT * FROM parent WHERE p_id = c_p_id) AND c_id = 20; SET tracing = off

# If the row is not found in the local region, the other regions are searched in
# parallel.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/20/0
Scan /Table/112/1/"\x80"/20/0, /Table/112/1/"\xc0"/20/0
fetched: /child/child_pkey/?/20/c_p_id -> /20
Scan /Table/111/1/"@"/20/0
Scan /Table/111/1/"\x80"/20/0, /Table/111/1/"\xc0"/20/0
fetched: /parent/parent_pkey/'ca-central-1'/20 -> <undecoded>
output row: [20 20]

# Inner join with locality optimized search enabled.
query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM child INNER JOIN parent ON p_id = c_p_id WHERE c_id = 10] OFFSET 2
----
·
• lookup join
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region = 'ap-southeast-2') AND (c_p_id = p_id)
│ remote lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • union all
    │ limit: 1
    │
    ├── • scan
    │     missing stats
    │     table: child@child_pkey
    │     spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10]
    │
    └── • scan
          missing stats
          table: child@child_pkey
          spans: [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJysk9FO4zoQhu_PU4zmpnBkVDvhAllCCqJBJ6iknLbSrkSrKiRD8ZLGWdsRRajvvkpSoO1StKD1hROP7d-f_xk_o_2Zo8RR2A_Px_AvXAwHV3ATfr_un0UxHPSi0Xj0f_8Qthek9yrPIIrjcAiXgyiGMjFUOBjEUM5UBqeQzpqfb_-FwxDSNib4FAYXF6NwDB4yLHRGcbIgi_IGBU4ZlkanZK02dei5WRBlS5ScoSrKytXhKcNUG0L5jE65nFDiOLnNaUhJRqbLkWFGLlF5I9uABk0_Kx_oCRme67xaFFY2VGwNigxHZVJHuxOcTJYnfIJdwbsckiIDAdrdk8HpiqGu3BuJdcmcUIoN9KiHkq_Y1-jFX6AP1uR7ab0dWrGX9g3SklFJDlWhTUaGsi3O6eqda8X6SJddb_tCfbVQDsReNL6D5n3GyEutirWP_vaxbXUG7efFyb7WD1UJP7QqQBcSDoJjOIVl55h3pJSB4Fzwk0M4i3twEHhwCoF_iAyHtNCOIH9nd_1glp2Tzf0Mlp10S_B3xdeUlm1KTXY7MzRXukCGg8pJCAQLPBb4e33zd3zzP-PbkGypC0s7Of2zDB2JOvmUzaktGKsrk9K10Wmzth0OGqEmkJF17azXDqKimRL1CYaSxWtFbiqJryrxXSXvQyV_S4lvKnm7Sv6HSsf7lXjt2F2uH-uXK5Gv29E73UvDekMyt3XaRvf6sZEdP5W16XdJbonhVfJAPXJkFqpQ1qkUpTMVrVb__AoAAP__93baww==

statement ok
SET vectorize=on

query T
EXPLAIN (VEC) SELECT * FROM child INNER JOIN parent ON p_id = c_p_id WHERE c_id = 10
----
│
└ Node 1
  └ *rowexec.joinReader
    └ *colexec.limitOp
      └ *colexec.SerialUnorderedSynchronizer
        ├ *colfetcher.ColBatchScan
        └ *colfetcher.ColBatchScan

statement ok
RESET vectorize

statement ok
SET tracing = on,kv,results; SELECT * FROM child INNER JOIN parent ON p_id = c_p_id WHERE c_id = 10; SET tracing = off

# If the row is found in the local region, the other regions are not searched.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>
output row: [10 10 10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child INNER JOIN parent ON p_id = c_p_id WHERE c_id = 20; SET tracing = off

# If the row is not found in the local region, the other regions are searched in
# parallel.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/20/0
Scan /Table/112/1/"\x80"/20/0, /Table/112/1/"\xc0"/20/0
fetched: /child/child_pkey/?/20/c_p_id -> /20
Scan /Table/111/1/"@"/20/0
Scan /Table/111/1/"\x80"/20/0, /Table/111/1/"\xc0"/20/0
fetched: /parent/parent_pkey/'ca-central-1'/20 -> <undecoded>
output row: [20 20 20]

# Left join with locality optimized search enabled.
query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 10] OFFSET 2
----
·
• lookup join (left outer)
│ table: parent@parent_pkey
│ equality cols are key
│ lookup condition: (crdb_region = 'ap-southeast-2') AND (c_p_id = p_id)
│ remote lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • union all
    │ limit: 1
    │
    ├── • scan
    │     missing stats
    │     table: child@child_pkey
    │     spans: [/'ap-southeast-2'/10 - /'ap-southeast-2'/10]
    │
    └── • scan
          missing stats
          table: child@child_pkey
          spans: [/'ca-central-1'/10 - /'ca-central-1'/10] [/'us-east-1'/10 - /'us-east-1'/10]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJysk1FP2zwUhu-_X3F0bgqfjGqnXCBLSEE01YpKw9pMm0SrKiSH4pHGme2IItT_PiUp0HYUDTRfOPGx_frxOa-f0P7KUOI4GATnEfwPvVF4CdfBj6vBWX8IB93-OBp_HRzC9oLkTmUpDIJeBBdhfwhFbCh3EA6hmKkUTiGZ1T_fvwSjAJImJvgUwl5vHETgIcNcpzSMF2RRXqPAKcPC6ISs1aYKPdUL-ukSJWeo8qJ0VXjKMNGGUD6hUy4jlBjFNxmNKE7JtDkyTMnFKqtla06_7mfFPT0iw3OdlYvcypqKrUGR4biIq2h7gpPJ8oRPsC14m0OcpyBAuzsyOF0x1KV7JbEunhNKsYHe76LkK_Y5evEP6P01-V5ab4dW7KV9hbRkVJxBmWuTkqF0i3O6euNaQ32ki7a3faGBWigHYi8a30HzPpLIC63ydR4728dGjwXJxq3htygY1Z5Fho1r_ebznOGB1vdlAT-1ykHnEg78YziFZeuYt6SUvuBc8JNDOBt24cD34BT8ziEyHNFCO4Lsjd3VO1q2Tjb3M1i2ki3BPxVfSl00pTbpzczQXOkcGYalk-AL5nvM7-zNZ2cnn52P5HNEttC5pZ1a_13ljkRlCkrn1BjJ6tIkdGV0Uq9thmEtVAdSsq6Z9ZpBP6-nRHWCoXjx4tRNJfFZJb6r5L2r1NlS4ptK3q5S512l4_1KvMrYbaYfqhctka_b0Rvdc8NqQzy3VdnGd_qhlq3cblHexpklhpfxPXXJkVmoXFmnEpTOlLRa_fc7AAD__0CL4Qg=

statement ok
SET vectorize=on

query T
EXPLAIN (VEC) SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 10
----
│
└ Node 1
  └ *rowexec.joinReader
    └ *colexec.limitOp
      └ *colexec.SerialUnorderedSynchronizer
        ├ *colfetcher.ColBatchScan
        └ *colfetcher.ColBatchScan

statement ok
RESET vectorize

statement ok
SET tracing = on,kv,results; SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 10; SET tracing = off

# If the row is found in the local region, the other regions are not searched.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/10/0
fetched: /child/child_pkey/?/10/c_p_id -> /10
Scan /Table/111/1/"@"/10/0
fetched: /parent/parent_pkey/'ap-southeast-2'/10 -> <undecoded>
output row: [10 10 10]

statement ok
SET tracing = on,kv,results; SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 20; SET tracing = off

# If the row is not found in the local region, the other regions are searched in
# parallel.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/112/1/"@"/20/0
Scan /Table/112/1/"\x80"/20/0, /Table/112/1/"\xc0"/20/0
fetched: /child/child_pkey/?/20/c_p_id -> /20
Scan /Table/111/1/"@"/20/0
Scan /Table/111/1/"\x80"/20/0, /Table/111/1/"\xc0"/20/0
fetched: /parent/parent_pkey/'ca-central-1'/20 -> <undecoded>
output row: [20 20 20]

query T retry
SELECT * FROM [EXPLAIN INSERT INTO child VALUES (1, 1)] OFFSET 2
----
·
• root
│
├── • insert
│   │ into: child(c_id, c_p_id, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • values
│             size: 4 columns, 1 row
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • scan
│                 missing stats
│                 table: child@child_pkey
│                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│                 limit: 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (anti)
            │ table: parent@parent_pkey
            │ equality cols are key
            │ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column2 = p_id)
            │
            └── • lookup join (anti)
                │ table: parent@parent_pkey
                │ equality cols are key
                │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column2 = p_id)
                │
                └── • scan buffer
                      estimated row count: 1
                      label: buffer 1

# Non-constant insert values cannot be inlined in uniqueness check, and all
# regions must be searched for duplicates.
query T retry
SELECT * FROM [EXPLAIN INSERT INTO child VALUES (1, 1), (2, 2)] OFFSET 2
----
·
• root
│
├── • insert
│   │ into: child(c_id, c_p_id, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • values
│                 size: 2 columns, 2 rows
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: child@child_pkey
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column1 = c_id)
│           │ pred: crdb_region_default != crdb_region
│           │
│           └── • scan buffer
│                 estimated row count: 2
│                 label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (anti)
            │ table: parent@parent_pkey
            │ equality cols are key
            │ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column2 = p_id)
            │
            └── • lookup join (anti)
                │ table: parent@parent_pkey
                │ equality cols are key
                │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column2 = p_id)
                │
                └── • scan buffer
                      estimated row count: 2
                      label: buffer 1

query T retry
SELECT * FROM [EXPLAIN UPSERT INTO child VALUES (1, 1)] OFFSET 2
----
·
• root
│
├── • upsert
│   │ into: child(c_id, c_p_id, crdb_region)
│   │ arbiter constraints: child_pkey
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • cross join (left outer)
│               │
│               ├── • values
│               │     size: 3 columns, 1 row
│               │
│               └── • union all
│                   │ limit: 1
│                   │
│                   ├── • scan
│                   │     missing stats
│                   │     table: child@child_pkey
│                   │     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│                   │
│                   └── • scan
│                         missing stats
│                         table: child@child_pkey
│                         spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (anti)
            │ table: parent@parent_pkey
            │ equality cols are key
            │ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column2 = p_id)
            │
            └── • lookup join (anti)
                │ table: parent@parent_pkey
                │ equality cols are key
                │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column2 = p_id)
                │
                └── • scan buffer
                      label: buffer 1

query T
SELECT * FROM [EXPLAIN DELETE FROM parent WHERE p_id = 1] OFFSET 2
----
·
• root
│
├── • delete
│   │ from: parent
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • union all
│           │ limit: 1
│           │
│           ├── • scan
│           │     missing stats
│           │     table: parent@parent_pkey
│           │     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│           │
│           └── • scan
│                 missing stats
│                 table: parent@parent_pkey
│                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: child@child_c_p_id_idx
            │ lookup condition: (crdb_region = 'ap-southeast-2') AND (p_id = c_p_id)
            │ remote lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (p_id = c_p_id)
            │
            └── • scan buffer
                  label: buffer 1

# Tests creating a index and a unique constraint on a REGIONAL BY ROW table.
statement ok
CREATE INDEX new_idx ON regional_by_row_table(a, b)

# The validation query to create the unique constraint should be efficient (see
# #56201).
statement ok
CREATE TABLE t56201 (a INT, b STRING, c STRING NOT NULL) LOCALITY REGIONAL BY ROW;

statement ok
ALTER TABLE t56201 INJECT STATISTICS '[
  {
    "columns": ["a"],
    "distinct_count": 3,
    "row_count": 1000000,
    "created_at": "2018-01-01 1:00:00.00000+00:00"
  },
  {
    "columns": ["b"],
    "distinct_count": 999900,
    "null_count": 5,
    "row_count": 1000000,
    "created_at": "2018-01-01 1:00:00.00000+00:00"
  },
  {
    "columns": ["c"],
    "distinct_count": 999999,
    "row_count": 1000000,
    "created_at": "2018-01-01 1:00:00.00000+00:00"
  }
]';

statement ok
ALTER TABLE t56201 ADD CONSTRAINT key_a_b UNIQUE (a, b);

query T retry
SELECT * FROM [EXPLAIN (VERBOSE) SELECT a, b
FROM t56201
WHERE a IS NOT NULL AND b IS NOT NULL
GROUP BY a, b
HAVING count(*) > 1
LIMIT 1] OFFSET 2
----
·
• project
│ columns: (a, b)
│
└── • limit
    │ columns: (a, b, count_rows)
    │ count: 1
    │
    └── • filter
        │ columns: (a, b, count_rows)
        │ estimated row count: 333,300
        │ filter: count_rows > 1
        │
        └── • group (streaming)
            │ columns: (a, b, count_rows)
            │ estimated row count: 999,900
            │ aggregate 0: count_rows()
            │ group by: a, b
            │ ordered: +a,+b
            │
            └── • union all
                │ columns: (a, b)
                │ ordering: +a,+b
                │ estimated row count: 999,995
                │
                ├── • union all
                │   │ columns: (a, b)
                │   │ ordering: +a,+b
                │   │ estimated row count: 666,663
                │   │
                │   ├── • filter
                │   │   │ columns: (a, b)
                │   │   │ ordering: +a,+b
                │   │   │ estimated row count: 333,332
                │   │   │ filter: b IS NOT NULL
                │   │   │
                │   │   └── • scan
                │   │         columns: (a, b)
                │   │         ordering: +a,+b
                │   │         estimated row count: 4 - 333,334 (33% of the table; stats collected <hidden> ago)
                │   │         table: t56201@key_a_b
                │   │         spans: /"@"/!NULL-/"@"/PrefixEnd
                │   │
                │   └── • filter
                │       │ columns: (a, b)
                │       │ ordering: +a,+b
                │       │ estimated row count: 333,332
                │       │ filter: b IS NOT NULL
                │       │
                │       └── • scan
                │             columns: (a, b)
                │             ordering: +a,+b
                │             estimated row count: 4 - 333,334 (33% of the table; stats collected <hidden> ago)
                │             table: t56201@key_a_b
                │             spans: /"\x80"/!NULL-/"\x80"/PrefixEnd
                │
                └── • filter
                    │ columns: (a, b)
                    │ ordering: +a,+b
                    │ estimated row count: 333,332
                    │ filter: b IS NOT NULL
                    │
                    └── • scan
                          columns: (a, b)
                          ordering: +a,+b
                          estimated row count: 4 - 333,334 (33% of the table; stats collected <hidden> ago)
                          table: t56201@key_a_b
                          spans: /"\xc0"/!NULL-/"\xc0"/PrefixEnd

statement ok
CREATE UNIQUE INDEX key_b_partial ON t56201 (b) WHERE a > 0;

query T retry
SELECT * FROM [EXPLAIN (VERBOSE) SELECT b
FROM t56201@key_b_partial
WHERE b IS NOT NULL AND a > 0
GROUP BY b
HAVING count(*) > 1
LIMIT 1] OFFSET 2
----
·
• project
│ columns: (b)
│
└── • limit
    │ columns: (b, count_rows)
    │ count: 1
    │
    └── • filter
        │ columns: (b, count_rows)
        │ estimated row count: 111,111
        │ filter: count_rows > 1
        │
        └── • group (streaming)
            │ columns: (b, count_rows)
            │ estimated row count: 333,332
            │ aggregate 0: count_rows()
            │ group by: b
            │ ordered: +b
            │
            └── • project
                │ columns: (b)
                │ ordering: +b
                │
                └── • union all
                    │ columns: (b, crdb_region, rowid)
                    │ ordering: +b
                    │ estimated row count: 333,332
                    │
                    ├── • union all
                    │   │ columns: (b, crdb_region, rowid)
                    │   │ ordering: +b
                    │   │ estimated row count: 222,221
                    │   │
                    │   ├── • scan
                    │   │     columns: (b, crdb_region, rowid)
                    │   │     ordering: +b
                    │   │     estimated row count: 4 - 111,111 (11% of the table; stats collected <hidden> ago)
                    │   │     table: t56201@key_b_partial (partial index)
                    │   │     spans: /"@"/!NULL-/"@"/PrefixEnd
                    │   │
                    │   └── • scan
                    │         columns: (b, crdb_region, rowid)
                    │         ordering: +b
                    │         estimated row count: 4 - 111,111 (11% of the table; stats collected <hidden> ago)
                    │         table: t56201@key_b_partial (partial index)
                    │         spans: /"\x80"/!NULL-/"\x80"/PrefixEnd
                    │
                    └── • scan
                          columns: (b, crdb_region, rowid)
                          ordering: +b
                          estimated row count: 4 - 111,111 (11% of the table; stats collected <hidden> ago)
                          table: t56201@key_b_partial (partial index)
                          spans: /"\xc0"/!NULL-/"\xc0"/PrefixEnd

statement ok
CREATE UNIQUE INDEX key_c_partial ON t56201 (c) WHERE a = 1;

query T retry
SELECT * FROM [EXPLAIN (VERBOSE) SELECT c
FROM t56201
WHERE c IS NOT NULL AND a = 1
GROUP BY c
HAVING count(*) > 1
LIMIT 1] OFFSET 2
----
·
• project
│ columns: (c)
│
└── • limit
    │ columns: (c, count_rows)
    │ count: 1
    │
    └── • filter
        │ columns: (c, count_rows)
        │ estimated row count: 111,111
        │ filter: count_rows > 1
        │
        └── • group (streaming)
            │ columns: (c, count_rows)
            │ estimated row count: 333,333
            │ aggregate 0: count_rows()
            │ group by: c
            │ ordered: +c
            │
            └── • union all
                │ columns: (c)
                │ ordering: +c
                │ estimated row count: 333,333
                │
                ├── • union all
                │   │ columns: (c)
                │   │ ordering: +c
                │   │ estimated row count: 222,222
                │   │
                │   ├── • scan
                │   │     columns: (c)
                │   │     ordering: +c
                │   │     estimated row count: 4 - 111,112 (11% of the table; stats collected <hidden> ago)
                │   │     table: t56201@key_c_partial (partial index)
                │   │     spans: /"@"-/"@"/PrefixEnd
                │   │
                │   └── • scan
                │         columns: (c)
                │         ordering: +c
                │         estimated row count: 4 - 111,112 (11% of the table; stats collected <hidden> ago)
                │         table: t56201@key_c_partial (partial index)
                │         spans: /"\x80"-/"\x80"/PrefixEnd
                │
                └── • scan
                      columns: (c)
                      ordering: +c
                      estimated row count: 4 - 111,112 (11% of the table; stats collected <hidden> ago)
                      table: t56201@key_c_partial (partial index)
                      spans: /"\xc0"-/"\xc0"/PrefixEnd

statement ok
ALTER TABLE regional_by_row_table ADD CONSTRAINT unique_b_a UNIQUE(b, a)

# The unique partial index disallows fast path insert.
query T retry
SELECT * FROM [EXPLAIN INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES (1, 1, 1, 1)] OFFSET 2
----
·
• root
│
├── • insert
│   │ into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
│   │
│   └── • values
│         size: 8 columns, 1 row
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • scan
│                 missing stats
│                 table: regional_by_row_table@regional_by_row_table_pkey
│                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│                 limit: 1
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • limit
│               │ count: 1
│               │
│               └── • filter
│                   │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
│                   │
│                   └── • union all
│                       │ limit: 3
│                       │
│                       ├── • scan
│                       │     missing stats
│                       │     table: regional_by_row_table@regional_by_row_table_b_key
│                       │     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│                       │
│                       └── • scan
│                             missing stats
│                             table: regional_by_row_table@regional_by_row_table_b_key
│                             spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • index join
│               │ table: regional_by_row_table@regional_by_row_table_pkey
│               │
│               └── • limit
│                   │ count: 1
│                   │
│                   └── • filter
│                       │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
│                       │
│                       └── • union all
│                           │ limit: 3
│                           │
│                           ├── • scan
│                           │     missing stats
│                           │     table: regional_by_row_table@uniq_idx (partial index)
│                           │     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│                           │
│                           └── • scan
│                                 missing stats
│                                 table: regional_by_row_table@uniq_idx (partial index)
│                                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • cross join (semi)
            │
            ├── • values
            │     size: 2 columns, 1 row
            │
            └── • filter
                │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
                │
                └── • union all
                    │ limit: 3
                    │
                    ├── • scan
                    │     missing stats
                    │     table: regional_by_row_table@new_idx
                    │     spans: [/'ap-southeast-2'/1/1 - /'ap-southeast-2'/1/1]
                    │
                    └── • scan
                          missing stats
                          table: regional_by_row_table@new_idx
                          spans: [/'ca-central-1'/1/1 - /'ca-central-1'/1/1] [/'us-east-1'/1/1 - /'us-east-1'/1/1]

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_b_key"\nDETAIL: Key \(b\)=\(3\) already exists\.
INSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b) VALUES ('us-east-1', 2, 3, 2, 3)

# The conflict columns in an upsert should only include the primary key,
# not the region column.
# TODO(treilly): The constraint check for uniq_idx should use uniq_idx but due
# to stats issues w/ empty stats, partial indexes and multicol stats its not.
# Hopefully fixing #67583 (and possibly #67479) will resolve this.
query T retry
SELECT * FROM [EXPLAIN UPSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b) VALUES ('us-east-1', 2, 3, 2, 3)] OFFSET 2
----
·
• root
│
├── • upsert
│   │ into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
│   │ arbiter constraints: regional_by_row_table_pkey
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • cross join (left outer)
│               │
│               ├── • values
│               │     size: 6 columns, 1 row
│               │
│               └── • union all
│                   │ limit: 1
│                   │
│                   ├── • scan
│                   │     missing stats
│                   │     table: regional_by_row_table@regional_by_row_table_pkey
│                   │     spans: [/'ap-southeast-2'/2 - /'ap-southeast-2'/2]
│                   │
│                   └── • scan
│                         missing stats
│                         table: regional_by_row_table@regional_by_row_table_pkey
│                         spans: [/'ca-central-1'/2 - /'ca-central-1'/2] [/'us-east-1'/2 - /'us-east-1'/2]
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table@regional_by_row_table_b_key
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column5 = b)
│           │ pred: (upsert_pk != pk) OR (column1 != crdb_region)
│           │
│           └── • scan buffer
│                 label: buffer 1
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table@new_idx
│           │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (b > 0)) AND (column4 = a)
│           │ pred: (upsert_pk != pk) OR (column1 != crdb_region)
│           │
│           └── • filter
│               │ filter: column5 > 0
│               │
│               └── • scan buffer
│                     label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: regional_by_row_table@new_idx
            │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column4 = a)) AND (column5 = b)
            │ pred: (upsert_pk != pk) OR (column1 != crdb_region)
            │
            └── • scan buffer
                  label: buffer 1

# TODO(treilly): The constraint check for uniq_idx should use uniq_idx but due
# to stats issues w/ empty stats, partial indexes and multicol stats its not.
# Hopefully fixing #67583 (and possibly #67479) will resolve this.
query T retry
SELECT * FROM [EXPLAIN UPSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b)
VALUES ('us-east-1', 23, 24, 25, 26), ('ca-central-1', 30, 30, 31, 32)] OFFSET 2
----
·
• root
│
├── • upsert
│   │ into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
│   │ arbiter constraints: regional_by_row_table_pkey
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • lookup join (left outer)
│               │ table: regional_by_row_table@regional_by_row_table_pkey
│               │ equality cols are key
│               │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column2 = pk)
│               │ remote lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column2 = pk)
│               │ locking strength: for update
│               │
│               └── • render
│                   │
│                   └── • values
│                         size: 5 columns, 2 rows
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table@regional_by_row_table_b_key
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column5 = b)
│           │ pred: (upsert_pk != pk) OR (column1 != crdb_region)
│           │
│           └── • scan buffer
│                 label: buffer 1
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table@new_idx
│           │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (b > 0)) AND (column4 = a)
│           │ pred: (upsert_pk != pk) OR (column1 != crdb_region)
│           │
│           └── • filter
│               │ filter: column5 > 0
│               │
│               └── • scan buffer
│                     label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: regional_by_row_table@new_idx
            │ lookup condition: ((crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column4 = a)) AND (column5 = b)
            │ pred: (upsert_pk != pk) OR (column1 != crdb_region)
            │
            └── • scan buffer
                  label: buffer 1

query TIIIIIIIIT colnames,rowsort
SELECT * FROM (VALUES ('us-east-1', 23, 24, 25, 26), ('ca-central-1', 30, 30, 31, 32)) AS v(crdb_region, pk, pk2, a, b)
LEFT JOIN regional_by_row_table t ON v.pk = t.pk;
----
crdb_region   pk  pk2  a   b   pk    pk2   a     b     j
us-east-1     23  24   25  26  23    23    24    25    NULL
ca-central-1  30  30   31  32  NULL  NULL  NULL  NULL  NULL

# One row already exists, one row is new.
statement ok
UPSERT INTO regional_by_row_table (crdb_region, pk, pk2, a, b)
VALUES ('us-east-1', 23, 24, 25, 26), ('ca-central-1', 30, 30, 31, 32)

query TIIII colnames
SELECT crdb_region, pk, pk2, a, b FROM regional_by_row_table
ORDER BY pk
----
crdb_region     pk  pk2  a   b
ap-southeast-2  1   1    2   3
ap-southeast-2  4   4    5   6
ca-central-1    6   6    5   -5
ca-central-1    7   7    8   9
ca-central-1    10  10   11  12
us-east-1       20  20   21  22
us-east-1       23  24   25  26
ca-central-1    30  30   31  32

query T
SELECT create_statement FROM [SHOW CREATE TABLE regional_by_row_table]
----
CREATE TABLE public.regional_by_row_table (
  pk INT8 NOT NULL,
  pk2 INT8 NOT NULL,
  a INT8 NOT NULL,
  b INT8 NOT NULL,
  j JSONB NULL,
  crdb_region public.crdb_internal_region NOT VISIBLE NOT NULL DEFAULT default_to_database_primary_region(gateway_region())::public.crdb_internal_region,
  CONSTRAINT regional_by_row_table_pkey PRIMARY KEY (pk ASC),
  INDEX regional_by_row_table_a_idx (a ASC),
  UNIQUE INDEX regional_by_row_table_b_key (b ASC),
  INVERTED INDEX regional_by_row_table_j_idx (j),
  UNIQUE INDEX uniq_idx (a ASC) WHERE b > 0:::INT8,
  INDEX new_idx (a ASC, b ASC),
  UNIQUE INDEX unique_b_a (b ASC, a ASC),
  FAMILY fam_0_pk_pk2_a_b_j_crdb_region (pk, pk2, a, b, j, crdb_region)
) LOCALITY REGIONAL BY ROW

query TTB colnames
SELECT index_name, column_name, implicit FROM crdb_internal.index_columns
WHERE descriptor_name = 'regional_by_row_table' AND column_type = 'key'
ORDER BY 1, 2
----
index_name                   column_name  implicit
new_idx                      a            false
new_idx                      b            false
new_idx                      crdb_region  true
regional_by_row_table_a_idx  a            false
regional_by_row_table_a_idx  crdb_region  true
regional_by_row_table_b_key  b            false
regional_by_row_table_b_key  crdb_region  true
regional_by_row_table_j_idx  crdb_region  true
regional_by_row_table_j_idx  j            false
regional_by_row_table_pkey   crdb_region  true
regional_by_row_table_pkey   pk           false
uniq_idx                     a            false
uniq_idx                     crdb_region  true
unique_b_a                   a            false
unique_b_a                   b            false
unique_b_a                   crdb_region  true

# REGIONAL BY ROW AS

statement ok
CREATE TABLE regional_by_row_table_as (
  pk int PRIMARY KEY,
  a int,
  b int,
  crdb_region_col crdb_internal_region AS (
    CASE
      WHEN pk <= 10 THEN 'us-east-1'
      ELSE 'ap-southeast-2'
    END
  ) STORED,
  INDEX (a),
  UNIQUE (b),
  FAMILY (pk, a, b)
) LOCALITY REGIONAL BY ROW AS crdb_region_col

query TI rowsort
INSERT INTO regional_by_row_table_as (pk) VALUES (1), (10), (20)
RETURNING crdb_region_col, pk
----
us-east-1       1
us-east-1       10
ap-southeast-2  20

query IIIT colnames
SELECT * FROM regional_by_row_table_as ORDER BY pk
----
pk  a     b     crdb_region_col
1   NULL  NULL  us-east-1
10  NULL  NULL  us-east-1
20  NULL  NULL  ap-southeast-2


# We do not need uniqueness checks on pk since uniqueness can be inferred
# through the functional dependency between pk and the computed region column.
query T retry
SELECT * FROM [EXPLAIN INSERT INTO regional_by_row_table_as (pk, a, b) VALUES (1, 1, 1)] OFFSET 2
----
·
• insert fast path
  into: regional_by_row_table_as(pk, a, b, crdb_region_col)
  auto commit
  uniqueness check: regional_by_row_table_as@regional_by_row_table_as_b_key
  size: 5 columns, 1 row

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_as_pkey"\nDETAIL: Key \(pk\)=\(1\) already exists\.
INSERT INTO regional_by_row_table_as (pk, a, b) VALUES (1, 1, 1)

statement ok
INSERT INTO regional_by_row_table_as (pk, a, b) VALUES (30, 1, 1)

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_as_b_key"\nDETAIL: Key \(b\)=\(1\) already exists\.
INSERT INTO regional_by_row_table_as (pk, a, b) VALUES (2, 1, 1)

# Verify that we plan single-region scans for REGIONAL BY ROW tables with a computed region.
query T
SELECT * FROM [EXPLAIN SELECT * FROM regional_by_row_table_as WHERE pk = 10] OFFSET 2
----
·
• scan
  missing stats
  table: regional_by_row_table_as@regional_by_row_table_as_pkey
  spans: [/'us-east-1'/10 - /'us-east-1'/10]

subtest virtual_columns

statement ok
CREATE TABLE regional_by_row_table_virt (
  pk int PRIMARY KEY,
  a int NOT NULL,
  b int NOT NULL,
  v INT AS (a + b) VIRTUAL,
  UNIQUE (v),
  UNIQUE INDEX ((a + 10)),
  FAMILY (pk, a, b)
) LOCALITY REGIONAL BY ROW

# Uniqueness checks for virtual columns should be efficient.
query T retry
SELECT * FROM [EXPLAIN INSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (1, 1, 1)] OFFSET 2
----
·
• root
│
├── • insert
│   │ into: regional_by_row_table_virt(pk, a, b, v, crdb_region, crdb_internal_idx_expr)
│   │
│   └── • values
│         size: 7 columns, 1 row
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • scan
│                 missing stats
│                 table: regional_by_row_table_virt@regional_by_row_table_virt_pkey
│                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│                 limit: 1
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • index join
│               │ table: regional_by_row_table_virt@regional_by_row_table_virt_pkey
│               │
│               └── • limit
│                   │ count: 1
│                   │
│                   └── • filter
│                       │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
│                       │
│                       └── • scan
│                             missing stats
│                             table: regional_by_row_table_virt@regional_by_row_table_virt_v_key
│                             spans: [/'ap-southeast-2'/2 - /'ap-southeast-2'/2] [/'ca-central-1'/2 - /'ca-central-1'/2] [/'us-east-1'/2 - /'us-east-1'/2]
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • cross join
            │
            ├── • values
            │     size: 1 column, 1 row
            │
            └── • limit
                │ count: 1
                │
                └── • filter
                    │ filter: a = 1
                    │
                    └── • index join
                        │ table: regional_by_row_table_virt@regional_by_row_table_virt_pkey
                        │
                        └── • filter
                            │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
                            │
                            └── • scan
                                  missing stats
                                  table: regional_by_row_table_virt@regional_by_row_table_virt_expr_key
                                  spans: [/'ap-southeast-2'/11 - /'ap-southeast-2'/11] [/'ca-central-1'/11 - /'ca-central-1'/11] [/'us-east-1'/11 - /'us-east-1'/11]

query T retry
SELECT * FROM [EXPLAIN UPSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (1, 1, 1)] OFFSET 2
----
·
• root
│
├── • upsert
│   │ into: regional_by_row_table_virt(pk, a, b, v, crdb_region, crdb_internal_idx_expr)
│   │ arbiter constraints: regional_by_row_table_virt_pkey
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • render
│               │
│               └── • cross join (left outer)
│                   │
│                   ├── • values
│                   │     size: 6 columns, 1 row
│                   │
│                   └── • render
│                       │
│                       └── • union all
│                           │ limit: 1
│                           │
│                           ├── • scan
│                           │     missing stats
│                           │     table: regional_by_row_table_virt@regional_by_row_table_virt_pkey
│                           │     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│                           │
│                           └── • scan
│                                 missing stats
│                                 table: regional_by_row_table_virt@regional_by_row_table_virt_pkey
│                                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table_virt@regional_by_row_table_virt_v_key
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (v_comp = v)
│           │ pred: (upsert_pk != pk) OR (upsert_crdb_region != crdb_region)
│           │
│           └── • scan buffer
│                 label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: regional_by_row_table_virt@regional_by_row_table_virt_expr_key
            │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (crdb_internal_idx_expr_comp = crdb_internal_idx_expr)
            │ pred: (upsert_pk != pk) OR (upsert_crdb_region != crdb_region)
            │
            └── • scan buffer
                  label: buffer 1

statement ok
INSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (1, 1, 1)

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_virt_v_key"\nDETAIL: Key \(v\)=\(2\) already exists\.
INSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (2, 2, 0)

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_virt_v_key"\nDETAIL: Key \(v\)=\(2\) already exists\.
UPSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (2, 2, 0)

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_virt_expr_key"\nDETAIL: Key \(a \+ 10:::INT8\)=\(11\) already exists\.
INSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (2, 1, 3)

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_virt_expr_key"\nDETAIL: Key \(a \+ 10:::INT8\)=\(11\) already exists\.
UPSERT INTO regional_by_row_table_virt (pk, a, b) VALUES (2, 1, 3)

statement ok
CREATE TABLE regional_by_row_table_virt_partial (
  pk int PRIMARY KEY,
  a int NOT NULL,
  b int NOT NULL,
  v INT AS (a + b) VIRTUAL,
  UNIQUE INDEX v_a_gt_0 (v) WHERE a > 0,
  UNIQUE INDEX v_v_gt_0 (v) WHERE v > 0,
  UNIQUE INDEX a_plus_10_v_gt_0 ((a + 10)) WHERE v > 0,
  FAMILY (pk, a, b)
) LOCALITY REGIONAL BY ROW

# Uniqueness checks for virtual columns should be efficient.
query T retry
SELECT * FROM [EXPLAIN INSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (1, 1, 1)] OFFSET 2
----
·
• root
│
├── • insert
│   │ into: regional_by_row_table_virt_partial(pk, a, b, v, crdb_region, crdb_internal_idx_expr)
│   │
│   └── • values
│         size: 9 columns, 1 row
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • scan
│                 missing stats
│                 table: regional_by_row_table_virt_partial@regional_by_row_table_virt_partial_pkey
│                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│                 limit: 1
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join (right semi)
│           │
│           ├── • filter
│           │   │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
│           │   │
│           │   └── • scan
│           │         missing stats
│           │         table: regional_by_row_table_virt_partial@v_a_gt_0 (partial index)
│           │         spans: [/'ap-southeast-2'/2 - /'ap-southeast-2'/2] [/'ca-central-1'/2 - /'ca-central-1'/2] [/'us-east-1'/2 - /'us-east-1'/2]
│           │
│           └── • values
│                 size: 1 column, 1 row
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • cross join
│           │
│           ├── • values
│           │     size: 1 column, 1 row
│           │
│           └── • index join
│               │ table: regional_by_row_table_virt_partial@regional_by_row_table_virt_partial_pkey
│               │
│               └── • limit
│                   │ count: 1
│                   │
│                   └── • filter
│                       │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
│                       │
│                       └── • scan
│                             missing stats
│                             table: regional_by_row_table_virt_partial@v_v_gt_0 (partial index)
│                             spans: [/'ap-southeast-2'/2 - /'ap-southeast-2'/2] [/'ca-central-1'/2 - /'ca-central-1'/2] [/'us-east-1'/2 - /'us-east-1'/2]
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • cross join
            │
            ├── • values
            │     size: 1 column, 1 row
            │
            └── • limit
                │ count: 1
                │
                └── • filter
                    │ filter: (a = 1) AND (b > -1)
                    │
                    └── • index join
                        │ table: regional_by_row_table_virt_partial@regional_by_row_table_virt_partial_pkey
                        │
                        └── • filter
                            │ filter: (pk != 1) OR (crdb_region != 'ap-southeast-2')
                            │
                            └── • scan
                                  missing stats
                                  table: regional_by_row_table_virt_partial@v_a_gt_0 (partial index)
                                  spans: FULL SCAN (SOFT LIMIT)

query T retry
SELECT * FROM [EXPLAIN UPSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (1, 1, 1)] OFFSET 2
----
·
• root
│
├── • upsert
│   │ into: regional_by_row_table_virt_partial(pk, a, b, v, crdb_region, crdb_internal_idx_expr)
│   │ arbiter constraints: regional_by_row_table_virt_partial_pkey
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • render
│               │
│               └── • cross join (left outer)
│                   │
│                   ├── • values
│                   │     size: 6 columns, 1 row
│                   │
│                   └── • render
│                       │
│                       └── • union all
│                           │ limit: 1
│                           │
│                           ├── • scan
│                           │     missing stats
│                           │     table: regional_by_row_table_virt_partial@regional_by_row_table_virt_partial_pkey
│                           │     spans: [/'ap-southeast-2'/1 - /'ap-southeast-2'/1]
│                           │
│                           └── • scan
│                                 missing stats
│                                 table: regional_by_row_table_virt_partial@regional_by_row_table_virt_partial_pkey
│                                 spans: [/'ca-central-1'/1 - /'ca-central-1'/1] [/'us-east-1'/1 - /'us-east-1'/1]
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table_virt_partial@v_a_gt_0 (partial index)
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (v_comp = v)
│           │ pred: (upsert_pk != pk) OR (upsert_crdb_region != crdb_region)
│           │
│           └── • filter
│               │ filter: column2 > 0
│               │
│               └── • scan buffer
│                     label: buffer 1
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table_virt_partial@v_v_gt_0 (partial index)
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (v_comp = v)
│           │ pred: (upsert_pk != pk) OR (upsert_crdb_region != crdb_region)
│           │
│           └── • filter
│               │ filter: v_comp > 0
│               │
│               └── • scan buffer
│                     label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: regional_by_row_table_virt_partial@a_plus_10_v_gt_0 (partial index)
            │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (crdb_internal_idx_expr_comp = crdb_internal_idx_expr)
            │ pred: (upsert_pk != pk) OR (upsert_crdb_region != crdb_region)
            │
            └── • filter
                │ filter: v_comp > 0
                │
                └── • scan buffer
                      label: buffer 1

statement ok
INSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (1, 1, 1)

statement error pq: duplicate key value violates unique constraint "v_a_gt_0"\nDETAIL: Key \(v\)=\(2\) already exists\.
INSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (2, 3, -1)

statement error pq: duplicate key value violates unique constraint "v_v_gt_0"\nDETAIL: Key \(v\)=\(2\) already exists\.
INSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (2, -1, 3)

statement ok
INSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (3, -2, -2)

# No conflict because a <= 0 and v <= 0.
statement ok
INSERT INTO regional_by_row_table_virt_partial (pk, a, b) VALUES (4, -3, -1)

subtest regressions

# Regression test for #63109. UPSERT should not cause the error
# ERROR: missing "crdb_region" primary key column.
statement ok
CREATE DATABASE single_region_test_db PRIMARY REGION "ap-southeast-2";

statement ok
USE single_region_test_db;

statement ok
CREATE TABLE t63109 (a INT, b STRING);

statement ok
ALTER TABLE t63109 SET LOCALITY REGIONAL BY ROW;

statement ok
INSERT INTO t63109 VALUES (1, 'one');

statement ok
UPSERT INTO t63109 VALUES (1, 'two');
UPSERT INTO t63109 (crdb_region, a, b) VALUES ('ap-southeast-2', 1, 'three');
UPSERT INTO t63109 (a, b) VALUES (1, 'four');

# Regression test for #65064. We should always choose locality optimized scan
# even if the stats show zero rows.
statement ok
CREATE DATABASE db PRIMARY REGION "ca-central-1" REGIONS "ap-southeast-2", "us-east-1";

statement ok
USE db;

statement ok
CREATE TABLE t65064 (username STRING NOT NULL UNIQUE) LOCALITY REGIONAL BY ROW;

statement ok
ALTER TABLE t65064 INJECT STATISTICS '[
  {
    "columns": ["username"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 0,
    "distinct_count": 0
  }
]';

query T retry
SELECT * FROM [EXPLAIN SELECT * FROM t65064 WHERE username = 'kharris'] OFFSET 2
----
·
• union all
│ estimated row count: 1
│ limit: 1
│
├── • scan
│     estimated row count: 1 (100% of the table; stats collected <hidden> ago)
│     table: t65064@t65064_username_key
│     spans: [/'ap-southeast-2'/'kharris' - /'ap-southeast-2'/'kharris']
│
└── • scan
      estimated row count: 1 (100% of the table; stats collected <hidden> ago)
      table: t65064@t65064_username_key
      spans: [/'ca-central-1'/'kharris' - /'ca-central-1'/'kharris'] [/'us-east-1'/'kharris' - /'us-east-1'/'kharris']

# Regression test for #73024. Ensure that uniqueness checks actually check all
# regions.
statement ok
CREATE TABLE t73024 (p INT PRIMARY KEY) LOCALITY REGIONAL BY ROW;
INSERT INTO t73024 (crdb_region, p) VALUES ('us-east-1', 100);

query error duplicate key value violates unique constraint
INSERT INTO t73024 VALUES (100);

query I
SELECT * FROM t73024
----
100

##############################################
# Locality optimized scans with LIMIT clause #
##############################################
# In this section we are checking explains and tracing results of queries
# similar to those in pkg/sql/opt/xform/testdata/rules/scan and
# pkg/ccl/logictestccl/testdata/logic_test/regional_by_row, where rule firing
# and query results are checked.

statement ok
SET database = multi_region_test_db

# LIMIT clause enables locality optimized scan on a REGIONAL BY ROW table
query T retry
SELECT * FROM [
EXPLAIN SELECT
    pk, pk2, a, b, crdb_region
FROM
    regional_by_row_table
LIMIT
    1]
----
distribution: local
vectorized: true
·
• union all
│ limit: 1
│
├── • scan
│     missing stats
│     table: regional_by_row_table@regional_by_row_table_pkey
│     spans: [/'ap-southeast-2' - /'ap-southeast-2']
│     limit: 1
│
└── • scan
      missing stats
      table: regional_by_row_table@regional_by_row_table_pkey
      spans: [/'ca-central-1' - /'us-east-1']
      limit: 1

# Test partitioning on an index column
statement ok
CREATE TABLE regional_by_row_table_as4 (
    pk
        INT8 PRIMARY KEY,
    a
        INT8,
    crdb_region_col
        crdb_internal_region
        AS (
            CASE
            WHEN (a % 3) = 0 THEN 'ap-southeast-2'
            WHEN (a % 3) = 1 THEN 'ca-central-1'
            ELSE 'us-east-1'
            END
        ) VIRTUAL
        NOT NULL,
    INDEX a_idx (a),
    FAMILY (pk, a)
)
    LOCALITY REGIONAL BY ROW AS crdb_region_col

statement ok
INSERT
INTO
    regional_by_row_table_as4
SELECT
    g, g
FROM
    ROWS FROM (generate_series(1, 1000)) AS g (g)

statement ok
SET vectorize = "on"

query T retry
EXPLAIN(OPT) SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a BETWEEN 1 AND 100
        LIMIT
            10
    )
----
scalar-group-by
 ├── locality-optimized-search
 │    ├── scan regional_by_row_table_as4@a_idx
 │    │    ├── constraint: /12/11/10: [/'ap-southeast-2'/1 - /'ap-southeast-2'/100]
 │    │    ├── limit: 10
 │    │    └── flags: force-index=a_idx
 │    └── scan regional_by_row_table_as4@a_idx
 │         ├── constraint: /19/18/17
 │         │    ├── [/'ca-central-1'/1 - /'ca-central-1'/100]
 │         │    └── [/'us-east-1'/1 - /'us-east-1'/100]
 │         ├── limit: 10
 │         └── flags: force-index=a_idx
 └── aggregations
      └── count-rows

statement ok
SET database = multi_region_test_db;
SET TRACING = "on", kv, results;
SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a BETWEEN 1 AND 100
        LIMIT
            10
    );
SET TRACING = off

# If the rows are found in the local region, the other regions are not
# searched.
query T
SELECT
    message
FROM
    [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
WHERE
    message LIKE 'fetched:%' OR message LIKE 'output row%'
ORDER BY
    "ordinality" ASC
----
fetched: /regional_by_row_table_as4/a_idx/?/3/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/6/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/9/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/12/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/15/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/18/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/21/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/24/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/27/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/30/? -> <undecoded>
output row: [10]

statement ok
SET vectorize = off

statement ok
SET TRACING = "on", kv, results;
SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a BETWEEN 1 AND 100
        LIMIT
            10
    );
SET TRACING = off

statement ok
RESET vectorize

# If the rows are found in the local region, the other regions are not searched.
query T
SELECT
    message
FROM
    [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
WHERE
    message LIKE 'fetched:%' OR message LIKE 'output row%'
ORDER BY
    "ordinality" ASC
----
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/3/3 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/6/6 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/9/9 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/12/12 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/15/15 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/18/18 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/21/21 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/24/24 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/27/27 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/30/30 -> <undecoded>
output row: [10]

statement ok
SET vectorize = "on"

# Locality optimized scan with an IN list
query T retry
SELECT
    *
FROM
    [
        EXPLAIN (OPT)
            SELECT
                count(*)
            FROM
                (
                    SELECT
                        *
                    FROM
                        regional_by_row_table_as4@a_idx
                    WHERE
                        a
                        IN (1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15, 16, 17, 18,
                            18, 19, 22, 23, 24, 25, 28, 30, 33, 34, 39, 40)
                    LIMIT
                        5
                )
    ]
OFFSET
    2
----
 │    ├── scan regional_by_row_table_as4@a_idx
 │    │    ├── constraint: /13/12/11
 │    │    │    ├── [/'ap-southeast-2'/6 - /'ap-southeast-2'/6]
 │    │    │    ├── [/'ap-southeast-2'/12 - /'ap-southeast-2'/12]
 │    │    │    ├── [/'ap-southeast-2'/15 - /'ap-southeast-2'/15]
 │    │    │    ├── [/'ap-southeast-2'/18 - /'ap-southeast-2'/18]
 │    │    │    ├── [/'ap-southeast-2'/24 - /'ap-southeast-2'/24]
 │    │    │    ├── [/'ap-southeast-2'/30 - /'ap-southeast-2'/30]
 │    │    │    ├── [/'ap-southeast-2'/33 - /'ap-southeast-2'/33]
 │    │    │    └── [/'ap-southeast-2'/39 - /'ap-southeast-2'/39]
 │    │    ├── limit: 5
 │    │    └── flags: force-index=a_idx
 │    └── scan regional_by_row_table_as4@a_idx
 │         ├── constraint: /20/19/18
 │         │    ├── [/'ca-central-1'/1 - /'ca-central-1'/1]
 │         │    ├── [/'ca-central-1'/4 - /'ca-central-1'/4]
 │         │    ├── [/'ca-central-1'/10 - /'ca-central-1'/10]
 │         │    ├── [/'ca-central-1'/16 - /'ca-central-1'/16]
 │         │    ├── [/'ca-central-1'/19 - /'ca-central-1'/19]
 │         │    ├── [/'ca-central-1'/22 - /'ca-central-1'/22]
 │         │    ├── [/'ca-central-1'/25 - /'ca-central-1'/25]
 │         │    ├── [/'ca-central-1'/28 - /'ca-central-1'/28]
 │         │    ├── [/'ca-central-1'/34 - /'ca-central-1'/34]
 │         │    ├── [/'ca-central-1'/40 - /'ca-central-1'/40]
 │         │    ├── [/'us-east-1'/2 - /'us-east-1'/2]
 │         │    ├── [/'us-east-1'/5 - /'us-east-1'/5]
 │         │    ├── [/'us-east-1'/8 - /'us-east-1'/8]
 │         │    ├── [/'us-east-1'/11 - /'us-east-1'/11]
 │         │    ├── [/'us-east-1'/14 - /'us-east-1'/14]
 │         │    ├── [/'us-east-1'/17 - /'us-east-1'/17]
 │         │    └── [/'us-east-1'/23 - /'us-east-1'/23]
 │         ├── limit: 5
 │         └── flags: force-index=a_idx
 └── aggregations
      └── count-rows

statement ok
SET TRACING = "on", kv, results;
SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a
            IN (1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15, 16, 17, 18,
                18, 19, 22, 23, 24, 25, 28, 30, 33, 34, 39, 40)
        LIMIT
            5
    );
SET TRACING = off

statement ok
RESET vectorize

# If the rows are found in the local region, the other regions are not searched.
query T
SELECT
    message
FROM
    [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
WHERE
    message LIKE 'fetched:%' OR message LIKE 'output row%'
ORDER BY
    "ordinality" ASC
----
fetched: /regional_by_row_table_as4/a_idx/?/6/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/12/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/15/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/18/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/24/? -> <undecoded>
output row: [5]

statement ok
SET vectorize = off

statement ok
SET TRACING = "on", kv, results;
SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a
            IN (1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15, 16, 17, 18,
                18, 19, 22, 23, 24, 25, 28, 30, 33, 34, 39, 40)
        LIMIT
            5
    );
SET TRACING = off

statement ok
RESET vectorize

# If the rows are found in the local region, the other regions are not searched.
query T
SELECT
    message
FROM
    [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
WHERE
    message LIKE 'fetched:%' OR message LIKE 'output row%'
ORDER BY
    "ordinality" ASC
----
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/6/6 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/12/12 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/15/15 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/18/18 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/24/24 -> <undecoded>
output row: [5]

statement ok
SET vectorize = "on"

# Locality optimized scan with multiple range predicates
query T retry
SELECT
    *
FROM
    [
        EXPLAIN (OPT)
            SELECT
                count(*)
            FROM
                (
                    SELECT
                        *
                    FROM
                        regional_by_row_table_as4@a_idx
                    WHERE
                        a BETWEEN -1 AND 10
                        OR a BETWEEN 100 AND 110
                        OR a BETWEEN 990 AND 1010
                    LIMIT
                        9
                )
    ]
OFFSET
    2
----
 │    ├── scan regional_by_row_table_as4@a_idx
 │    │    ├── constraint: /13/12/11
 │    │    │    ├── [/'ap-southeast-2'/-1 - /'ap-southeast-2'/10]
 │    │    │    ├── [/'ap-southeast-2'/100 - /'ap-southeast-2'/110]
 │    │    │    └── [/'ap-southeast-2'/990 - /'ap-southeast-2'/1010]
 │    │    ├── limit: 9
 │    │    └── flags: force-index=a_idx
 │    └── scan regional_by_row_table_as4@a_idx
 │         ├── constraint: /20/19/18
 │         │    ├── [/'ca-central-1'/-1 - /'ca-central-1'/10]
 │         │    ├── [/'ca-central-1'/100 - /'ca-central-1'/110]
 │         │    ├── [/'ca-central-1'/990 - /'ca-central-1'/1010]
 │         │    ├── [/'us-east-1'/-1 - /'us-east-1'/10]
 │         │    ├── [/'us-east-1'/100 - /'us-east-1'/110]
 │         │    └── [/'us-east-1'/990 - /'us-east-1'/1010]
 │         ├── limit: 9
 │         └── flags: force-index=a_idx
 └── aggregations
      └── count-rows

statement ok
SET TRACING = "on", kv, results;
SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a BETWEEN -1 AND 10
            OR a BETWEEN 100 AND 110
            OR a BETWEEN 990 AND 1010
        LIMIT
            9
    );
SET TRACING = off

statement ok
RESET vectorize

# If the rows are found in the local region, the other regions are not searched.
query T
SELECT
    message
FROM
    [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
WHERE
    message LIKE 'fetched:%' OR message LIKE 'output row%'
ORDER BY
    "ordinality" ASC
----
fetched: /regional_by_row_table_as4/a_idx/?/3/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/6/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/9/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/102/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/105/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/108/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/990/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/993/? -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/?/996/? -> <undecoded>
output row: [9]

statement ok
SET vectorize = off

statement ok
SET TRACING = "on", kv, results;
SELECT
    count(*)
FROM
    (
        SELECT
            *
        FROM
            regional_by_row_table_as4@a_idx
        WHERE
            a BETWEEN -1 AND 10
            OR a BETWEEN 100 AND 110
            OR a BETWEEN 990 AND 1010
        LIMIT
            9
    );
SET TRACING = off

statement ok
RESET vectorize

# If the rows are found in the local region, the other regions are not searched.
query T
SELECT
    message
FROM
    [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
WHERE
    message LIKE 'fetched:%' OR message LIKE 'output row%'
ORDER BY
    "ordinality" ASC
----
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/3/3 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/6/6 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/9/9 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/102/102 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/105/105 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/108/108 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/990/990 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/993/993 -> <undecoded>
fetched: /regional_by_row_table_as4/a_idx/'ap-southeast-2'/996/996 -> <undecoded>
output row: [9]

statement ok
RESET vectorize

# REGIONAL BY ROW AS table with an explicit crdb_internal_region check
# constraint.
statement ok
CREATE TABLE regional_by_row_table_as1 (
  pk int PRIMARY KEY,
  a int,
  b int,
  crdb_region_col1 crdb_internal_region NOT NULL AS (
    CASE
      WHEN pk <= 10 THEN 'ca-central-1'
      ELSE 'us-east-1'
    END
  ) VIRTUAL CHECK(crdb_region_col1 BETWEEN 'ap-southeast-2' AND 'us-east-1'),
  crdb_region_col crdb_internal_region NOT NULL AS (
    CASE
      WHEN pk <= 1 THEN 'ca-central-1'
      ELSE 'us-east-1'
    END
  ) VIRTUAL,
  INDEX (a),
  UNIQUE (b),
  FAMILY (pk, a, b)
) LOCALITY REGIONAL BY ROW AS crdb_region_col1

statement ok
INSERT INTO regional_by_row_table_as1 (pk) VALUES (1), (2), (3), (10), (20)

# An extra crdb_region check constraint should still allow locality optimized scan.
query T retry
SELECT * FROM [EXPLAIN SELECT * FROM regional_by_row_table_as1 LIMIT 3] OFFSET 2
----
·
• render
│
└── • union all
    │ limit: 3
    │
    ├── • scan
    │     missing stats
    │     table: regional_by_row_table_as1@regional_by_row_table_as1_pkey
    │     spans: [/'ap-southeast-2' - /'ap-southeast-2']
    │     limit: 3
    │
    └── • scan
          missing stats
          table: regional_by_row_table_as1@regional_by_row_table_as1_pkey
          spans: [/'ca-central-1' - /'us-east-1']
          limit: 3

subtest index_recommendations

# Enable vectorize so we get consistent EXPLAIN output. We cannot use the
# OFFSET 2 strategy for these tests because that disables the index
# recommendation (index recommendations are only used when EXPLAIN is the
# root of the query tree).
statement ok
SET index_recommendations_enabled = true;
SET vectorize=on

statement ok
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name STRING NOT NULL,
  email STRING NOT NULL UNIQUE,
  INDEX (name)
) LOCALITY REGIONAL BY ROW

# Check that we don't recommend indexes that already exist.
query T retry
EXPLAIN INSERT INTO users (name, email)
VALUES ('Craig Roacher', 'craig@cockroachlabs.com')
----
distribution: local
vectorized: true
·
• insert fast path
  into: users(id, name, email, crdb_region)
  auto commit
  uniqueness check: users@users_email_key
  size: 5 columns, 1 row

statement ok
SET index_recommendations_enabled = false;
RESET vectorize

statement ok
DROP TABLE users;

subtest foreign_keys

statement ok
CREATE TABLE users (
    id         UUID   PRIMARY KEY DEFAULT gen_random_uuid(),
    id2        INT,
    username   STRING NOT NULL,
    UNIQUE INDEX id2_idx(id2),
    FAMILY (id, id2, username)
) LOCALITY REGIONAL BY ROW;

statement ok
CREATE TABLE user_settings (
    id      UUID   PRIMARY KEY DEFAULT gen_random_uuid(),
    id2     INT,
    user_id UUID   NOT NULL,
    value   STRING NOT NULL,
    INDEX(user_id),
    INDEX id2_idx(id2),
    FOREIGN KEY (user_id, crdb_region) REFERENCES users (id, crdb_region)
) LOCALITY REGIONAL BY ROW;

statement ok
CREATE TABLE user_settings_cascades (
    id      UUID   PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID   NOT NULL,
    value   STRING NOT NULL,
    INDEX(user_id),
    FOREIGN KEY (user_id, crdb_region) REFERENCES users (id, crdb_region) ON DELETE CASCADE ON UPDATE CASCADE
) LOCALITY REGIONAL BY ROW;

# With #69617, the following query is able to infer that the join condition
#   users.id = user_settings.user_id
# is equivalent to
#   users.id = user_settings.user_id AND
#   users.crdb_region = user_settings.crdb_region
# This allows the optimizer to plan a lookup join between users and
# user_settings and avoid visiting all regions.
query T retry
EXPLAIN SELECT users.crdb_region AS user_region, user_settings.crdb_region AS user_settings_region, *
  FROM users JOIN user_settings ON users.id = user_settings.user_id AND users.id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882';
----
distribution: local
vectorized: true
·
• lookup join
│ table: user_settings@user_settings_pkey
│ equality: (crdb_region, id) = (crdb_region, id)
│ equality cols are key
│
└── • lookup join
    │ table: user_settings@user_settings_user_id_idx
    │ equality: (crdb_region, id) = (crdb_region, user_id)
    │ pred: user_id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882'
    │
    └── • union all
        │ limit: 1
        │
        ├── • scan
        │     missing stats
        │     table: users@users_pkey
        │     spans: [/'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']
        │
        └── • scan
              missing stats
              table: users@users_pkey
              spans: [/'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882'] [/'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']

# A locality-optimized scan in a derived table with index join as the input to
# lookup join should propagate its Distribution to the lookup table if there is
# a crdb_region = crdb_region join term, causing lower costs and lookup join to
# be picked.
query T
EXPLAIN SELECT users_dt.crdb_region AS user_region, user_settings.crdb_region AS user_settings_region, *
  FROM (SELECT crdb_region, * FROM users@id2_idx LIMIT 1) users_dt JOIN user_settings ON
  users_dt.id2+1 = user_settings.id2 AND users_dt.id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882' AND
  users_dt.crdb_region = user_settings.crdb_region
----
distribution: local
vectorized: true
·
• lookup join
│ table: user_settings@user_settings_pkey
│ equality: (crdb_region, id) = (crdb_region, id)
│ equality cols are key
│
└── • lookup join
    │ table: user_settings@id2_idx
    │ equality: (crdb_region, column18) = (crdb_region, id2)
    │
    └── • render
        │
        └── • filter
            │ filter: id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882'
            │
            └── • index join
                │ table: users@users_pkey
                │
                └── • union all
                    │ limit: 1
                    │
                    ├── • scan
                    │     missing stats
                    │     table: users@id2_idx
                    │     spans: [/'ap-southeast-2' - /'ap-southeast-2']
                    │     limit: 1
                    │
                    └── • scan
                          missing stats
                          table: users@id2_idx
                          spans: [/'ca-central-1' - /'us-east-1']
                          limit: 1

# A locality-optimized scan in a derived table with an inequality `LookupExpr`
# should propagate the input table's Distribution to the lookup table if there
# is a crdb_region = crdb_region join term, causing lower costs and lookup join
# to be picked.
query T
EXPLAIN SELECT users_dt.crdb_region AS user_region, user_settings.crdb_region AS user_settings_region, *
  FROM (SELECT crdb_region, * FROM users@id2_idx LIMIT 1) users_dt JOIN user_settings ON users_dt.id2+1 > user_settings.id2 AND users_dt.id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882' and users_dt.crdb_region = user_settings.crdb_region
----
distribution: local
vectorized: true
·
• lookup join
│ table: user_settings@user_settings_pkey
│ equality: (crdb_region) = (crdb_region)
│ pred: column18 > id2
│
└── • render
    │
    └── • filter
        │ filter: id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882'
        │
        └── • index join
            │ table: users@users_pkey
            │
            └── • union all
                │ limit: 1
                │
                ├── • scan
                │     missing stats
                │     table: users@id2_idx
                │     spans: [/'ap-southeast-2' - /'ap-southeast-2']
                │     limit: 1
                │
                └── • scan
                      missing stats
                      table: users@id2_idx
                      spans: [/'ca-central-1' - /'us-east-1']
                      limit: 1

# An explicit join on the crdb_region column of both tables should be costed to
# prefer lookup join.
query T
EXPLAIN SELECT users.crdb_region AS user_region, user_settings.crdb_region AS user_settings_region, *
  FROM users JOIN user_settings ON users.crdb_region = user_settings.crdb_region AND users.id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882';
----
distribution: local
vectorized: true
·
• lookup join
│ table: user_settings@user_settings_pkey
│ equality: (crdb_region) = (crdb_region)
│
└── • union all
    │ limit: 1
    │
    ├── • scan
    │     missing stats
    │     table: users@users_pkey
    │     spans: [/'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']
    │
    └── • scan
          missing stats
          table: users@users_pkey
          spans: [/'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882'] [/'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']

# Ensure that the FK checks and cascades are efficient.
query T
EXPLAIN INSERT INTO user_settings (user_id, value) VALUES ('5ebfedee-0dcf-41e6-a315-5fa0b51b9882', 'foo')
----
distribution: local
vectorized: true
·
• insert fast path
  into: user_settings(id, id2, user_id, value, crdb_region)
  auto commit
  FK check: users@users_pkey
  size: 6 columns, 1 row

query T
EXPLAIN INSERT INTO user_settings_cascades (user_id, value) VALUES ('5ebfedee-0dcf-41e6-a315-5fa0b51b9882', 'foo')
----
distribution: local
vectorized: true
·
• insert fast path
  into: user_settings_cascades(id, user_id, value, crdb_region)
  auto commit
  FK check: users@users_pkey
  size: 5 columns, 1 row

query T retry
EXPLAIN DELETE FROM users WHERE id = '5ebfedee-0dcf-41e6-a315-5fa0b51b9882'
----
distribution: local
vectorized: true
·
• root
│
├── • delete
│   │ from: users
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • union all
│           │ limit: 1
│           │
│           ├── • scan
│           │     missing stats
│           │     table: users@users_pkey
│           │     spans: [/'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']
│           │
│           └── • scan
│                 missing stats
│                 table: users@users_pkey
│                 spans: [/'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882'] [/'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']
│
├── • fk-cascade
│   │ fk: user_settings_cascades_user_id_crdb_region_fkey
│   │
│   └── • delete
│       │ from: user_settings_cascades
│       │
│       └── • scan
│             missing stats
│             table: user_settings_cascades@user_settings_cascades_user_id_idx
│             spans: [/'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ap-southeast-2'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882'] [/'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'ca-central-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882'] [/'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882' - /'us-east-1'/'5ebfedee-0dcf-41e6-a315-5fa0b51b9882']
│             locking strength: for update
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: user_settings@user_settings_user_id_idx
            │ equality: (crdb_region, id) = (crdb_region, user_id)
            │
            └── • scan buffer
                  label: buffer 1

# Regression test for #88047
statement ok
CREATE TABLE t88047 (
  json_col JSONB NULL,
  notes STRING,
  region public.crdb_internal_region NOT NULL AS
  (CASE WHEN ((json_col->'loc':::STRING)->>'state':::STRING) IN ('AZ':::STRING, 'CA':::STRING, 'NV':::STRING) THEN 'ap-southeast-2':::public.crdb_internal_region
        WHEN ((json_col->'loc':::STRING)->>'state':::STRING) IN ('MI':::STRING, 'MN':::STRING, 'MO':::STRING) THEN 'ca-central-1':::public.crdb_internal_region
        WHEN ((json_col->'loc':::STRING)->>'state':::STRING) IN ('PA':::STRING, 'VT':::STRING, 'NY':::STRING) THEN 'us-east-1':::public.crdb_internal_region END) STORED,
  INVERTED INDEX t88047_inv_idx (json_col)
) LOCALITY REGIONAL BY ROW AS region

statement ok
INSERT INTO t88047(json_col, notes)
  VALUES ('{"loc": {"state": "PA"}}':::JSONB, 'Liberty Bell'),
         ('{"loc": {"state": "PA"}}':::JSONB, 'Rocky Balboa'),
         ('{"loc": {"state": "VT"}}':::JSONB, 'Maple Syrup'),
         ('{"loc": {"state": "NY"}}':::JSONB, 'Big Apple'),
         ('{"loc": {"state": "NY"}}':::JSONB, 'Statue of Liberty'),
         ('{"loc": {"state": "CA"}}':::JSONB, 'Golden Gate Bridge'),
         ('{"loc": {"state": "CA"}}':::JSONB, 'Yosemite'),
         ('{"loc": {"state": "MI"}}':::JSONB, 'Go Blue!');

# Expect to pick locality-optimized search from the inverted RBR index.
query T
EXPLAIN(OPT)
  SELECT * FROM t88047
WHERE json_col->'loc' @> '{"state":"NY"}'
  LIMIT 2
----
index-join t88047
 └── locality-optimized-search
      ├── scan t88047@t88047_inv_idx,inverted
      │    ├── constraint: /13: [/'ap-southeast-2' - /'ap-southeast-2']
      │    ├── inverted constraint: /19/14
      │    │    └── spans: ["loc"/"state"/"NY", "loc"/"state"/"NY"]
      │    └── limit: 2
      └── scan t88047@t88047_inv_idx,inverted
           ├── constraint: /22
           │    ├── [/'ca-central-1' - /'ca-central-1']
           │    └── [/'us-east-1' - /'us-east-1']
           ├── inverted constraint: /28/23
           │    └── spans: ["loc"/"state"/"NY", "loc"/"state"/"NY"]
           └── limit: 2

# Expect to see only rows from "state":"NY".
query TTT
SELECT * FROM t88047
WHERE json_col->'loc' @> '{"state":"NY"}'
ORDER BY 2
LIMIT 2
----
{"loc": {"state": "NY"}}  Big Apple          us-east-1
{"loc": {"state": "NY"}}  Statue of Liberty  us-east-1

statement ok
DROP INDEX t88047_inv_idx

# Expect to see only rows from "state":"NY" after inverted index is dropped.
query TTT
SELECT * FROM t88047
WHERE json_col->'loc' @> '{"state":"NY"}'
ORDER BY 2
LIMIT 2
----
{"loc": {"state": "NY"}}  Big Apple          us-east-1
{"loc": {"state": "NY"}}  Statue of Liberty  us-east-1

subtest rbr_input_to_lookup_join

statement ok
DROP TABLE IF EXISTS regional_by_row_table

statement ok
CREATE TABLE regional_by_row_table (
  pk int PRIMARY KEY,
  pk2 int NOT NULL,
  a int NOT NULL,
  b int NOT NULL,
  j JSON,
  INDEX (a),
  UNIQUE (b),
  INVERTED INDEX (j),
  FAMILY (pk, pk2, a, b)
) LOCALITY REGIONAL BY ROW

statement ok
DROP TABLE IF EXISTS regional_by_row_table_virt_partial

statement ok
CREATE TABLE regional_by_row_table_virt_partial (
  pk int PRIMARY KEY,
  a int NOT NULL,
  b int NOT NULL,
  v INT AS (a + b) VIRTUAL,
  UNIQUE INDEX v_a_gt_0 (v) WHERE a > 0,
  UNIQUE INDEX v_v_gt_0 (v) WHERE v > 0,
  UNIQUE INDEX a_plus_10_v_gt_0 ((a + 10)) WHERE v > 0,
  FAMILY (pk, a, b)
) LOCALITY REGIONAL BY ROW

# Locality-optimized search of inner lookup joins is cheaper than one
# locality-optimized join. The following should produce a
# locality-optimized-search of two lookup joins.
query T retry
EXPLAIN(OPT) SELECT * FROM regional_by_row_table t1, regional_by_row_table_virt_partial t2 WHERE t1.b = t2.pk LIMIT 1
----
limit
 ├── project
 │    ├── project
 │    │    └── locality-optimized-search
 │    │         ├── project
 │    │         │    └── inner-join (lookup regional_by_row_table_virt_partial)
 │    │         │         ├── lookup columns are key
 │    │         │         ├── scan regional_by_row_table [as=t1]
 │    │         │         │    └── constraint: /28/23: [/'ap-southeast-2' - /'ap-southeast-2']
 │    │         │         └── filters (true)
 │    │         └── project
 │    │              └── inner-join (lookup regional_by_row_table_virt_partial)
 │    │                   ├── lookup columns are key
 │    │                   ├── scan regional_by_row_table [as=t1]
 │    │                   │    └── constraint: /39/34: [/'ca-central-1' - /'us-east-1']
 │    │                   └── filters (true)
 │    └── projections
 │         └── regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b
 └── 1

# Locality-optimized search of semi lookup joins is cheaper than one
# locality-optimized join. The following should produce a
# locality-optimized-search of two lookup joins.
query T retry
EXPLAIN(OPT) SELECT * FROM regional_by_row_table t1 WHERE b IN
  (SELECT pk FROM regional_by_row_table_virt_partial t2) LIMIT 1
----
limit
 ├── locality-optimized-search
 │    ├── project
 │    │    └── semi-join (lookup regional_by_row_table_virt_partial)
 │    │         ├── lookup columns are key
 │    │         ├── scan regional_by_row_table [as=t1]
 │    │         │    └── constraint: /114/109: [/'ap-southeast-2' - /'ap-southeast-2']
 │    │         └── filters (true)
 │    └── project
 │         └── semi-join (lookup regional_by_row_table_virt_partial)
 │              ├── lookup columns are key
 │              ├── scan regional_by_row_table [as=t1]
 │              │    └── constraint: /125/120: [/'ca-central-1' - /'us-east-1']
 │              └── filters (true)
 └── 1

# Locality-optimized search of left outer lookup joins is valid, but is
# currently not picked because we don't pass a limit hint through a filter.
query T retry
EXPLAIN(OPT) SELECT t2.a, t2.b, t2.v, t1.b FROM regional_by_row_table_virt_partial t2 LEFT OUTER JOIN
  regional_by_row_table t1 ON t1.b = t2.pk WHERE t1.b IS NULL OR t1.b = 7 LIMIT 1
----
distribute
 └── project
      └── limit
           ├── select
           │    ├── project
           │    │    └── left-join (lookup regional_by_row_table@regional_by_row_table_b_key [as=t1])
           │    │         ├── lookup columns are key
           │    │         ├── project
           │    │         │    ├── scan regional_by_row_table_virt_partial
           │    │         │    │    ├── check constraint expressions
           │    │         │    │    │    └── regional_by_row_table_virt_partial.crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')
           │    │         │    │    ├── computed column expressions
           │    │         │    │    │    ├── v
           │    │         │    │    │    │    └── regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b
           │    │         │    │    │    └── crdb_internal_idx_expr
           │    │         │    │    │         └── regional_by_row_table_virt_partial.a + 10
           │    │         │    │    └── partial index predicates
           │    │         │    │         ├── v_a_gt_0: filters
           │    │         │    │         │    └── regional_by_row_table_virt_partial.a > 0
           │    │         │    │         ├── v_v_gt_0: filters
           │    │         │    │         │    └── (regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b) > 0
           │    │         │    │         └── a_plus_10_v_gt_0: filters
           │    │         │    │              └── (regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b) > 0
           │    │         │    └── projections
           │    │         │         └── regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b
           │    │         └── filters (true)
           │    └── filters
           │         └── (t1.b IS NULL) OR (t1.b = 7)
           └── 1

# Locality-optimized search of anti lookup joins is not supported and should
# not be picked.
query T retry
EXPLAIN(OPT) SELECT * FROM regional_by_row_table t1 WHERE b NOT IN
  (SELECT pk FROM regional_by_row_table_virt_partial t2) LIMIT 1
----
distribute
 └── limit
      ├── anti-join (hash)
      │    ├── scan regional_by_row_table [as=t1]
      │    │    └── check constraint expressions
      │    │         └── t1.crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')
      │    ├── scan regional_by_row_table_virt_partial
      │    │    ├── check constraint expressions
      │    │    │    └── regional_by_row_table_virt_partial.crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')
      │    │    ├── computed column expressions
      │    │    │    ├── v
      │    │    │    │    └── regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b
      │    │    │    └── crdb_internal_idx_expr
      │    │    │         └── regional_by_row_table_virt_partial.a + 10
      │    │    └── partial index predicates
      │    │         ├── v_a_gt_0: filters
      │    │         │    └── regional_by_row_table_virt_partial.a > 0
      │    │         ├── v_v_gt_0: filters
      │    │         │    └── (regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b) > 0
      │    │         └── a_plus_10_v_gt_0: filters
      │    │              └── (regional_by_row_table_virt_partial.a + regional_by_row_table_virt_partial.b) > 0
      │    └── filters
      │         └── t1.b = regional_by_row_table_virt_partial.pk
      └── 1

subtest groupByUnique

# GROUP BY unique column v doesn't allow non-aggregate expressions in the
# SELECT list because v is not marked as NOT NULL.
statement error pq: column "pk" must appear in the GROUP BY clause or be used in an aggregate function
SELECT pk, a, b FROM regional_by_row_table_virt GROUP BY v;

statement ok
ALTER TABLE regional_by_row_table_virt ALTER COLUMN v SET NOT NULL

# GROUP BY unique column v allows non-aggregate expressions in the
# SELECT list because v is marked as NOT NULL.
query III
SELECT pk, a, b FROM regional_by_row_table_virt GROUP BY v;
----
1  1  1

# GROUP BY unique index column "a" doesn't allow non-aggregate expressions in
# the SELECT list because "a" is not marked as NOT NULL.
statement error pq: column "pk" must appear in the GROUP BY clause or be used in an aggregate function
SELECT pk FROM regional_by_row_table_virt GROUP BY a;

statement ok
ALTER TABLE regional_by_row_table_virt ALTER COLUMN v SET NOT NULL

# GROUP BY unique index column a allows non-aggregate expressions in the
# SELECT list because v is marked as NOT NULL.
query I
SELECT pk FROM regional_by_row_table_virt GROUP BY v;
----
1

# GROUP BY unique expression index (a+10) doesn't currently allow non-aggregate
# expressions in the SELECT list. This could potentially be supported in the
# future. The index need not be an expression index if the GROUP BY expression
# can be proven to be monotonically increasing or decreasing.
statement error pq: column "pk" must appear in the GROUP BY clause or be used in an aggregate function
SELECT pk FROM regional_by_row_table_virt GROUP BY (a+10);

# Regression test for incorrectly setting bytes limit in the streamer on remote
# lookups (#108206).
statement ok
CREATE TABLE t108206_p (
  id INT PRIMARY KEY,
  p_id INT,
  INDEX (p_id),
  FAMILY (id, p_id)
) LOCALITY REGIONAL BY ROW;
CREATE TABLE t108206_c (
  c_id INT PRIMARY KEY,
  c_p_id INT,
  INDEX (c_p_id),
  FAMILY (c_id, c_p_id)
) LOCALITY REGIONAL BY ROW;
INSERT INTO t108206_p (crdb_region, id, p_id) VALUES ('ap-southeast-2', 1, 10), ('ca-central-1', 2, 20), ('us-east-1', 3, 30);
INSERT INTO t108206_c (crdb_region, c_id, c_p_id) VALUES ('ap-southeast-2', 10, 10), ('ca-central-1', 20, 20), ('us-east-1', 30, 30)

statement ok
SET tracing = on,kv,results; SELECT * FROM t108206_c WHERE EXISTS (SELECT * FROM t108206_p WHERE p_id = c_p_id) AND c_id = 20; SET tracing = off

# If the row is not found in the local region, the other regions are searched in
# parallel.
query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 OR message LIKE 'Scan%'
 ORDER BY ordinality ASC
----
Scan /Table/138/1/"@"/20/0
Scan /Table/138/1/"\x80"/20/0, /Table/138/1/"\xc0"/20/0
fetched: /t108206_c/t108206_c_pkey/?/20/c_p_id -> /20
Scan /Table/137/2/"@"/2{0-1}
Scan /Table/137/2/"\x80"/2{0-1}, /Table/137/2/"\xc0"/2{0-1}
fetched: /t108206_p/t108206_p_p_id_idx/'ca-central-1'/20/2 -> <undecoded>
output row: [20 20]

# Left join with locality optimized search enabled.
query T retry
SELECT * FROM [EXPLAIN (DISTSQL) SELECT * FROM t108206_c WHERE EXISTS (SELECT * FROM t108206_p WHERE p_id = c_p_id) AND c_id = 20] OFFSET 2
----
·
• lookup join (semi)
│ table: t108206_p@t108206_p_p_id_idx
│ lookup condition: (crdb_region = 'ap-southeast-2') AND (c_p_id = p_id)
│ remote lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (c_p_id = p_id)
│
└── • union all
    │ limit: 1
    │
    ├── • scan
    │     missing stats
    │     table: t108206_c@t108206_c_pkey
    │     spans: [/'ap-southeast-2'/20 - /'ap-southeast-2'/20]
    │
    └── • scan
          missing stats
          table: t108206_c@t108206_c_pkey
          spans: [/'ca-central-1'/20 - /'ca-central-1'/20] [/'us-east-1'/20 - /'us-east-1'/20]
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJysk1Fr6koQx9_vpxjmRb1scRPLRRYKlhq5KVZ7jXALVSRNpnZPYzZnd0Mtxe9-2Oix6tFyWk4eQjI7-9v__Gf2Dc33DAVGQT-4GsPf0BsNb-A-uLvtX4YDqHfDaBz912_AfoL1eNvn_8wS-P_fYBRAcOfyoH48q9hkFTOZwgUkM_fRgMtBF-rJOubzxhSGvV4UjMFHhrlKaRAvyKC4Rw-nDAutEjJGaRd6qxLCdImCM5R5UVoXnjJMlCYUb2ilzQgFjuOHjEYUp6SbHBmmZGOZVdhtEZ3t16x4pldkeKWycpEbAU4e2yhGhlERu2hzgpPJss0n2PR5k0Ocp-CBsk-kcbpiqEr7rsjYeE4ovJ0Swi4KvmJfq8L7g1V0NhWcVO0fqPZOqn4Xa0jLOIMyVzolTeme3unqSHkDdaaKpr9fWF8upAXvpDR-IM3_jKHXSuYbP1v7x45fCxLQD3pjiIKbEK6H4QDZ1uZia3NR2TmT6RIZ9pV6Lgv4pmQOKhdQ75zDBSxr57wmhOh4nHu8vRn5jg8X0Gk1kOGIFsoSZEd2u9u3rLV39zNY1pI94K_Ebc-Ldc91-jDTNJcqP2lk68DI1meMHJEpVG7ooMm_17Izz00DpXNaT5BRpU7oVqukyl3_DitQFUjJ2PWqv_4J82rJcydoihfbEd0leV8l8UOS_yGptUfiuyT_kNT6kHR-msSdY4-ZenFXWSDfPGdHXj8fdBviuXFti57US4V1Y25QPMaZIYY38TN1yZJeyFwaKxMUVpe0Wv31IwAA__-d1uWE

statement ok
SET vectorize=on

query T
EXPLAIN (VEC) SELECT * FROM child LEFT JOIN parent ON p_id = c_p_id WHERE c_id = 10
----
│
└ Node 1
  └ *rowexec.joinReader
    └ *colexec.limitOp
      └ *colexec.SerialUnorderedSynchronizer
        ├ *colfetcher.ColBatchScan
        └ *colfetcher.ColBatchScan

statement ok
RESET vectorize

statement ok
CREATE TABLE abc (
  id UUID PRIMARY KEY,
  id1 UUID NOT NULL,
  created_at TIMESTAMP NOT NULL,
  updated_at TIMESTAMP NOT NULL,
  id2 UUID NULL,
  INDEX (id1 ASC, id2 ASC)
) LOCALITY REGIONAL BY ROW;

statement ok
CREATE TABLE xyz (
  id UUID PRIMARY KEY,
  str STRING NOT NULL,
  abc_id UUID NOT NULL,
  id2 UUID NULL,
  FOREIGN KEY (abc_id) REFERENCES abc(id) ON DELETE CASCADE,
  INDEX (abc_id ASC, id2 ASC),
  INDEX (id2 ASC, str ASC, abc_id ASC)
) LOCALITY REGIONAL BY ROW;

statement ok
ALTER TABLE abc INJECT STATISTICS '[
  {
    "avg_size": 3000,
    "columns": ["id"],
    "distinct_count": 100,
    "row_count": 100,
    "created_at": "2018-01-01 1:00:00.00000+00:00"
  }
]';

statement ok
ALTER TABLE xyz INJECT STATISTICS '[
  {
    "avg_size": 3000,
    "columns": ["id"],
    "distinct_count": 100,
    "row_count": 100,
    "created_at": "2018-01-01 1:00:00.00000+00:00"
  }
]';

# Regression test for #105942.
query T retry
EXPLAIN SELECT
  xyz.str,
  abc.id,
  abc.id1,
  abc.id2,
  abc.created_at,
  abc.updated_at
FROM
  abc JOIN xyz ON
    xyz.abc_id = abc.id
    AND xyz.id2 = abc.id2
    AND xyz.crdb_region = abc.crdb_region
WHERE
  abc.id1 = '6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'
  AND abc.id2 = '68088706-02c6-47d1-b993-a421cd761f2b'
  AND abc.crdb_region = 'ap-southeast-2'
  AND xyz.crdb_region = 'ap-southeast-2';
----
distribution: local
vectorized: true
·
• lookup join
│ estimated row count: 1
│ table: xyz@xyz_id2_str_abc_id_idx
│ equality: (crdb_region, id2) = (crdb_region, id2)
│ pred: ((abc_id = id) AND (id2 = '68088706-02c6-47d1-b993-a421cd761f2b')) AND (crdb_region = 'ap-southeast-2')
│
└── • index join
    │ estimated row count: 0
    │ table: abc@abc_pkey
    │
    └── • scan
          estimated row count: 0 (0.37% of the table; stats collected <hidden> ago)
          table: abc@abc_id1_id2_idx
          spans: [/'ap-southeast-2'/'6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'/'68088706-02c6-47d1-b993-a421cd761f2b' - /'ap-southeast-2'/'6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'/'68088706-02c6-47d1-b993-a421cd761f2b']

# The following should use a string of 4 lookup/index joins with a cost under 200.
query T retry
EXPLAIN(opt,verbose) SELECT
  x.str,
  a.id1,
  a.id2,
  a.created_at,
  a.updated_at,
  b.id1,
  b.id2,
  b.created_at,
  b.updated_at
FROM
  abc a
  INNER JOIN xyz x ON
    x.abc_id = a.id
    AND x.id2 = a.id2
    AND x.crdb_region = a.crdb_region
  INNER JOIN abc b ON
    x.abc_id = b.id
    AND x.id2 = b.id2
    AND x.crdb_region = b.crdb_region
WHERE
  a.id1 = '6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'
  AND a.id2 = '68088706-02c6-47d1-b993-a421cd761f2b'
  AND a.crdb_region = 'ap-southeast-2'
  AND b.id1 = '6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'
  AND b.id2 = '68088706-02c6-47d1-b993-a421cd761f2b'
  AND b.crdb_region = 'ap-southeast-2'
  AND x.crdb_region = 'ap-southeast-2';
----
project
 ├── columns: str:12 id1:2 id2:5 created_at:3 updated_at:4 id1:21 id2:24 created_at:22 updated_at:23
 ├── immutable
 ├── stats: [rows=0.3666667]
 ├── cost: 45.3262257
 ├── fd: ()-->(2,5,21,24), (3)==(22), (22)==(3), (5)==(24), (24)==(5), (4)==(23), (23)==(4), (2)==(21), (21)==(2)
 ├── distribution: ap-southeast-2
 ├── prune: (2-5,12,21-24)
 └── inner-join (lookup xyz@xyz_id2_str_abc_id_idx [as=x])
      ├── columns: a.id:1 a.id1:2 a.created_at:3 a.updated_at:4 a.id2:5 a.crdb_region:6 str:12 abc_id:13 x.id2:14 x.crdb_region:15 b.id:20 b.id1:21 b.created_at:22 b.updated_at:23 b.id2:24 b.crdb_region:25
      ├── key columns: [6 5] = [15 14]
      ├── immutable
      ├── stats: [rows=0.3666667, distinct(13)=0.366667, null(13)=0, distinct(14)=0.366667, null(14)=0, distinct(15)=0.366667, null(15)=0, distinct(20)=0.366667, null(20)=0, distinct(24)=0.366667, null(24)=0, distinct(25)=0.366667, null(25)=0]
      ├── cost: 45.302559
      ├── fd: ()-->(2,5,6,14,15,21,24,25), (1)-->(3,4), (20)-->(22,23), (1)==(13,20), (13)==(1,20), (20)==(1,13), (5)==(14,24), (14)==(5,24), (24)==(5,14), (6)==(15,25), (15)==(6,25), (25)==(6,15), (2)==(21), (21)==(2), (3)==(22), (22)==(3), (4)==(23), (23)==(4)
      ├── distribution: ap-southeast-2
      ├── lookup table distribution: ap-southeast-2,ca-central-1,us-east-1
      ├── inner-join (lookup abc [as=b])
      │    ├── columns: a.id:1 a.id1:2 a.created_at:3 a.updated_at:4 a.id2:5 a.crdb_region:6 b.id:20 b.id1:21 b.created_at:22 b.updated_at:23 b.id2:24 b.crdb_region:25
      │    ├── key columns: [25 20] = [25 20]
      │    ├── lookup columns are key
      │    ├── immutable
      │    ├── stats: [rows=0.1344445, distinct(1)=0.134444, null(1)=0, distinct(2)=0.134444, null(2)=0, distinct(3)=0.134444, null(3)=0, distinct(4)=0.134444, null(4)=0, distinct(5)=0.134444, null(5)=0, distinct(6)=0.134444, null(6)=0, distinct(20)=0.134444, null(20)=0, distinct(21)=0.134444, null(21)=0, distinct(22)=0.134444, null(22)=0, distinct(23)=0.134444, null(23)=0, distinct(24)=0.134444, null(24)=0, distinct(25)=0.134444, null(25)=0]
      │    ├── cost: 34.9459129
      │    ├── key: (20)
      │    ├── fd: ()-->(2,5,6,21,24,25), (1)-->(3,4), (20)-->(22,23), (1)==(20), (20)==(1), (2)==(21), (21)==(2), (3)==(22), (22)==(3), (4)==(23), (23)==(4), (5)==(24), (24)==(5), (6)==(25), (25)==(6)
      │    ├── distribution: ap-southeast-2
      │    ├── lookup table distribution: ap-southeast-2,ca-central-1,us-east-1
      │    ├── interesting orderings: (+1 opt(2,5,6)) (+20 opt(21,24,25))
      │    ├── inner-join (lookup abc@abc_id1_id2_idx [as=b])
      │    │    ├── columns: a.id:1 a.id1:2 a.created_at:3 a.updated_at:4 a.id2:5 a.crdb_region:6 b.id:20 b.id1:21 b.id2:24 b.crdb_region:25
      │    │    ├── key columns: [6 2 5 1] = [25 21 24 20]
      │    │    ├── lookup columns are key
      │    │    ├── immutable
      │    │    ├── stats: [rows=0.003666667, distinct(1)=0.00366667, null(1)=0, distinct(2)=0.00366667, null(2)=0, distinct(5)=0.00366667, null(5)=0, distinct(6)=0.00366667, null(6)=0, distinct(20)=0.00366667, null(20)=0, distinct(21)=0.00366667, null(21)=0, distinct(24)=0.00366667, null(24)=0, distinct(25)=0.00366667, null(25)=0, distinct(21,24,25)=0.00366667, null(21,24,25)=0]
      │    │    ├── cost: 34.8283629
      │    │    ├── key: (20)
      │    │    ├── fd: ()-->(2,5,6,21,24,25), (1)-->(3,4), (6)==(25), (25)==(6), (2)==(21), (21)==(2), (5)==(24), (24)==(5), (1)==(20), (20)==(1)
      │    │    ├── distribution: ap-southeast-2
      │    │    ├── lookup table distribution: ap-southeast-2,ca-central-1,us-east-1
      │    │    ├── interesting orderings: (+(1|20) opt(2,5,6,21,24,25))
      │    │    ├── index-join abc
      │    │    │    ├── columns: a.id:1 a.id1:2 a.created_at:3 a.updated_at:4 a.id2:5 a.crdb_region:6
      │    │    │    ├── immutable
      │    │    │    ├── stats: [rows=0.3666667, distinct(1)=0.366667, null(1)=0, distinct(2)=0.366667, null(2)=0, distinct(3)=0.360675, null(3)=0, distinct(4)=0.360675, null(4)=0, distinct(5)=0.366667, null(5)=0, distinct(6)=0.366667, null(6)=0, distinct(2,5,6)=0.366667, null(2,5,6)=0]
      │    │    │    │   histogram(6)=  0      0.36667
      │    │    │    │                <--- 'ap-southeast-2'
      │    │    │    ├── cost: 33.2056672
      │    │    │    ├── key: (1)
      │    │    │    ├── fd: ()-->(2,5,6), (1)-->(3,4)
      │    │    │    ├── distribution: ap-southeast-2
      │    │    │    ├── prune: (1,3,4)
      │    │    │    ├── interesting orderings: (+1 opt(2,5,6))
      │    │    │    └── scan abc@abc_id1_id2_idx [as=a]
      │    │    │         ├── columns: a.id:1 a.id1:2 a.id2:5 a.crdb_region:6
      │    │    │         ├── constraint: /6/2/5/1: [/'ap-southeast-2'/'6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'/'68088706-02c6-47d1-b993-a421cd761f2b' - /'ap-southeast-2'/'6da4f356-e526-4b78-b9f9-bbb1a7fc12d6'/'68088706-02c6-47d1-b993-a421cd761f2b']
      │    │    │         ├── stats: [rows=0.3666667, distinct(1)=0.366667, null(1)=0, distinct(2)=0.366667, null(2)=0, distinct(5)=0.366667, null(5)=0, distinct(6)=0.366667, null(6)=0, distinct(2,5,6)=0.366667, null(2,5,6)=0]
      │    │    │         │   histogram(6)=  0      0.36667
      │    │    │         │                <--- 'ap-southeast-2'
      │    │    │         ├── cost: 25.430667
      │    │    │         ├── key: (1)
      │    │    │         ├── fd: ()-->(2,5,6)
      │    │    │         ├── distribution: ap-southeast-2
      │    │    │         └── interesting orderings: (+1 opt(2,5,6))
      │    │    └── filters
      │    │         ├── b.id2:24 = '68088706-02c6-47d1-b993-a421cd761f2b' [outer=(24), constraints=(/24: [/'68088706-02c6-47d1-b993-a421cd761f2b' - /'68088706-02c6-47d1-b993-a421cd761f2b']; tight), fd=()-->(24)]
      │    │         ├── b.crdb_region:25 = 'ap-southeast-2' [outer=(25), immutable, constraints=(/25: [/'ap-southeast-2' - /'ap-southeast-2']; tight), fd=()-->(25)]
      │    │         └── b.id1:21 = '6da4f356-e526-4b78-b9f9-bbb1a7fc12d6' [outer=(21), constraints=(/21: [/'6da4f356-e526-4b78-b9f9-bbb1a7fc12d6' - /'6da4f356-e526-4b78-b9f9-bbb1a7fc12d6']; tight), fd=()-->(21)]
      │    └── filters
      │         ├── a.created_at:3 = b.created_at:22 [outer=(3,22), constraints=(/3: (/NULL - ]; /22: (/NULL - ]), fd=(3)==(22), (22)==(3)]
      │         └── a.updated_at:4 = b.updated_at:23 [outer=(4,23), constraints=(/4: (/NULL - ]; /23: (/NULL - ]), fd=(4)==(23), (23)==(4)]
      └── filters
           ├── abc_id:13 = a.id:1 [outer=(1,13), constraints=(/1: (/NULL - ]; /13: (/NULL - ]), fd=(1)==(13), (13)==(1)]
           ├── x.id2:14 = '68088706-02c6-47d1-b993-a421cd761f2b' [outer=(14), constraints=(/14: [/'68088706-02c6-47d1-b993-a421cd761f2b' - /'68088706-02c6-47d1-b993-a421cd761f2b']; tight), fd=()-->(14)]
           └── x.crdb_region:15 = 'ap-southeast-2' [outer=(15), immutable, constraints=(/15: [/'ap-southeast-2' - /'ap-southeast-2']; tight), fd=()-->(15)]

subtest insertFastPathUnique

statement ok
SET database = multi_region_test_db

statement ok
CREATE TABLE users2 (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name STRING NOT NULL,
  email STRING NOT NULL UNIQUE,
  INDEX (name),
  FAMILY (id, name, email)
) LOCALITY REGIONAL BY ROW


# Single-row insert fast path which needs no special handling.
query T
EXPLAIN INSERT INTO users2 (crdb_region, name, email)
VALUES ('ap-southeast-2', 'Craig Roacher', 'craig@cockroachlabs.com')
----
distribution: local
vectorized: true
·
• insert fast path
  into: users2(id, name, email, crdb_region)
  auto commit
  uniqueness check: users2@users2_email_key
  size: 5 columns, 1 row

# Multi-row insert fast path uniqueness checks not currently supported.
query T
EXPLAIN INSERT INTO users2 (name, email)
VALUES ('Bill Roacher', 'bill@cockroachlabs.com'), ('Jill Roacher', 'jill@cockroachlabs.com')
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: users2(id, name, email, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • values
│                 size: 2 columns, 2 rows
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: users2@users2_email_key
            │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column2 = email)
            │ pred: (id_default != id) OR (crdb_region_default != crdb_region)
            │
            └── • scan buffer
                  estimated row count: 2
                  label: buffer 1

# Multi-row insert fast path uniqueness checks as a prepared statement not
# currently supported.
statement ok
PREPARE e1 AS EXPLAIN INSERT INTO users2 (name, email)
VALUES ($1, $2), ($3, $4)

query T nosort
EXECUTE e1 ('Bill Roacher', 'bill@cockroachlabs.com', 'Jo Roacher', 'jo@cockroachlabs.com')
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: users2(id, name, email, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • values
│                 size: 2 columns, 2 rows
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: users2@users2_email_key
            │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column2 = email)
            │ pred: (id_default != id) OR (crdb_region_default != crdb_region)
            │
            └── • scan buffer
                  estimated row count: 2
                  label: buffer 1

statement ok
SET experimental_enable_unique_without_index_constraints = true

statement ok
CREATE TABLE users3 (
  id UUID DEFAULT gen_random_uuid(),
  name STRING NOT NULL,
  email STRING NOT NULL,
  UNIQUE WITHOUT INDEX (email) WHERE email != name,
  INDEX (name),
  PRIMARY KEY (email, id),
  FAMILY (id, name, email)
) LOCALITY REGIONAL BY ROW

statement ok
RESET experimental_enable_unique_without_index_constraints

# Verify a partial UNIQUE WITHOUT INDEX with a predicate similar to the PK
# values check created in `buildInsertionCheck` to prevent rows from matching
# themselves doesn't mistakenly allow insert fast path.
query T
EXPLAIN INSERT INTO users3 (crdb_region, name, email)
VALUES ('ap-southeast-2', 'craig@cockroachlabs.com', 'craig@cockroachlabs.com')
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: users3(id, name, email, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • values
│             size: 5 columns, 1 row
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: users3@users3_pkey
            │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column3 = email)
            │ pred: ((id_default != id) OR (column1 != crdb_region)) AND (email != name)
            │
            └── • filter
                │ estimated row count: 0
                │ filter: column3 != column2
                │
                └── • scan buffer
                      estimated row count: 1
                      label: buffer 1

query T
EXPLAIN INSERT INTO multi_region_test_db.regional_by_row_table (pk, pk2, a, b) VALUES
(1, 1, 1, -5)
----
distribution: local
vectorized: true
·
• insert fast path
  into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
  auto commit
  uniqueness check: regional_by_row_table@regional_by_row_table_pkey
  uniqueness check: regional_by_row_table@regional_by_row_table_b_key
  size: 7 columns, 1 row

statement ok
INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES
  (1, 1, 1, -5)

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_b_key"\nDETAIL: Key \(b\)=\(-5\) already exists\.
INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES
  (16, 16, 15, -5)

statement ok
PREPARE s1 AS EXPLAIN INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES ($1, $2, $3, $4);

query T nosort
EXECUTE s1 (1, 1, 1, -5)
----
distribution: local
vectorized: true
·
• insert fast path
  into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
  auto commit
  uniqueness check: regional_by_row_table@regional_by_row_table_pkey
  uniqueness check: regional_by_row_table@regional_by_row_table_b_key
  size: 7 columns, 1 row

statement ok
PREPARE s2 AS INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES ($1, $2, $3, $4);

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_b_key"\nDETAIL: Key \(b\)=\(-5\) already exists\.
EXECUTE s2 (6, 7, 8, -5)

statement ok
PREPARE s3 AS EXPLAIN INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES ($1, $2, $3, $4), ($5, $6, $7, $8);

# Multi-row insert fast path uniqueness checks not yet supported.
query T nosort
EXECUTE s3 (7, 7, 7, 7, 6, 7, 8, -5)
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: regional_by_row_table(pk, pk2, a, b, j, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • values
│                 size: 4 columns, 2 rows
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: regional_by_row_table@regional_by_row_table_pkey
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column1 = pk)
│           │ pred: crdb_region_default != crdb_region
│           │
│           └── • scan buffer
│                 estimated row count: 2
│                 label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: regional_by_row_table@regional_by_row_table_b_key
            │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column4 = b)
            │ pred: (column1 != pk) OR (crdb_region_default != crdb_region)
            │
            └── • scan buffer
                  estimated row count: 2
                  label: buffer 1

statement ok
PREPARE s4 AS INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES ($1, $2, $3, $4), ($5, $6, $7, $8);

statement error pq: duplicate key value violates unique constraint "regional_by_row_table_b_key"\nDETAIL: Key \(b\)=\(-5\) already exists\.
EXECUTE s4 (7, 7, 7, 7, 6, 7, 8, -5)

statement ok
CREATE TABLE user_settings2 (
    id      UUID   PRIMARY KEY DEFAULT gen_random_uuid(),
    id2     INT,
    user_id UUID   NOT NULL,
    value   STRING NOT NULL,
    INDEX(user_id),
    UNIQUE INDEX id2_idx(id2),
    FOREIGN KEY (user_id, crdb_region) REFERENCES users (id, crdb_region),
    FAMILY (id, id2, user_id, value)
) LOCALITY REGIONAL BY ROW;

statement ok
CREATE TABLE user_settings3 (
    id      UUID   PRIMARY KEY DEFAULT gen_random_uuid(),
    id2     INT,
    user_id UUID   NOT NULL,
    value   STRING NOT NULL,
    INDEX(user_id),
    UNIQUE INDEX id2_idx(id2),
    FOREIGN KEY (user_id) REFERENCES users (id),
    FAMILY (id, id2, user_id, value)
) LOCALITY REGIONAL BY ROW;

# An insert with FK constraint requiring a WithScan should still allow
# insert fast path.
query T
EXPLAIN INSERT INTO user_settings2 (id2, user_id, value) VALUES (2, '5ebfedee-0dcf-41e6-a315-5fa0b51b9882', 'foo')
----
distribution: local
vectorized: true
·
• insert fast path
  into: user_settings2(id, id2, user_id, value, crdb_region)
  auto commit
  FK check: users@users_pkey
  uniqueness check: user_settings2@id2_idx
  size: 6 columns, 1 row

# An insert with FK constraint and uniqueness check inserting multiple rows
# is not supported by insert fast path.
query T
EXPLAIN
INSERT INTO user_settings2 (id2, user_id, value)
VALUES (2, '5ebfedee-0dcf-41e6-a315-5fa0b51b9882', 'foo'),
       (2, '5ebfedee-0dcf-41e6-a315-5fa0b51b9882', 'foo');
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: user_settings2(id, id2, user_id, value, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • values
│                 size: 3 columns, 2 rows
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: user_settings2@id2_idx
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column1 = id2)
│           │ pred: (id_default != id) OR (crdb_region_default != crdb_region)
│           │
│           └── • scan buffer
│                 estimated row count: 2
│                 label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (anti)
            │ table: users@users_pkey
            │ equality: (crdb_region_default, column2) = (crdb_region, id)
            │ equality cols are key
            │
            └── • scan buffer
                  estimated row count: 2
                  label: buffer 1

# Hash-sharded RBR table.
statement ok
CREATE TABLE hash_sharded_rbr_computed (
  region_id STRING(10) NOT NULL,
  my_uuid UUID NOT NULL,
  my_uuid2 UUID NOT NULL,
  another_id INT NOT NULL,
  row_ts TIMESTAMP NULL,
  crdb_region_col crdb_internal_region NOT VISIBLE NOT NULL AS (CASE WHEN substring(region_id, 1:::INT8, 4:::INT8) = 'east':::STRING THEN 'us-east-1':::crdb_internal_region WHEN substring(region_id, 1:::INT8, 2:::INT8) = 'ap':::STRING THEN 'ap-southeast-2':::crdb_internal_region ELSE 'ca-central-1':::crdb_internal_region END) STORED,
  CONSTRAINT "primary" PRIMARY KEY (region_id ASC) USING HASH,
  FAMILY (region_id, my_uuid, my_uuid2, another_id, row_ts, crdb_region_col)
) LOCALITY REGIONAL BY ROW AS crdb_region_col;

statement ok
CREATE UNIQUE INDEX idx_date ON hash_sharded_rbr_computed (row_ts ASC, another_id ASC) USING HASH

# Hash-sharded RBR table with unique hash-sharded index supports fast path.
query T retry
EXPLAIN INSERT
INTO
  hash_sharded_rbr_computed (region_id, my_uuid, my_uuid2, another_id, row_ts)
VALUES
  ('east1234', gen_random_uuid(), gen_random_uuid(), 1, TIMESTAMP '2016-01-25 10:10:10.555555')
----
distribution: local
vectorized: true
·
• insert fast path
  into: hash_sharded_rbr_computed(region_id, my_uuid, my_uuid2, another_id, row_ts, crdb_region_col, crdb_internal_region_id_shard_16, crdb_internal_another_id_row_ts_shard_16)
  auto commit
  uniqueness check: hash_sharded_rbr_computed@idx_date
  size: 11 columns, 1 row

# With an additional check constraint on the crdb_region column, insert fast
# path is still picked.
statement ok
CREATE TABLE hash_sharded_rbr_computed_check (
region_based_id STRING(10) NOT NULL,
my_uuid UUID NOT NULL,
my_uuid2 UUID NOT NULL,
another_id INT NOT NULL,
row_ts TIMESTAMP NULL,
geo_zone STRING NOT NULL,
crdb_region_col crdb_internal_region NOT VISIBLE NOT NULL AS (CASE WHEN substring(geo_zone, 1:::INT8, 4:::INT8) = 'east':::STRING THEN 'us-east-1':::crdb_internal_region WHEN substring(region_based_id, 1:::INT8, 2:::INT8) = 'ap':::STRING THEN 'ap-southeast-2':::crdb_internal_region ELSE 'ca-central-1':::crdb_internal_region END) STORED,
CONSTRAINT "primary" PRIMARY KEY (region_based_id ASC) USING HASH WITH (bucket_count=16),
CONSTRAINT c1 CHECK (crdb_region_col IN ('us-east-1':::crdb_internal_region, 'ap-southeast-2':::crdb_internal_region)),
FAMILY (region_based_id, my_uuid, my_uuid2, another_id, row_ts, geo_zone, crdb_region_col)
) LOCALITY REGIONAL BY ROW AS crdb_region_col;

statement ok
CREATE UNIQUE INDEX idx_date ON hash_sharded_rbr_computed_check (row_ts ASC, another_id ASC) USING HASH WITH (bucket_count=16)

# Hash-sharded RBR table with check constraint and unique hash-sharded index
# supports fast path.
query T
EXPLAIN INSERT
INTO
  hash_sharded_rbr_computed_check (region_based_id, geo_zone, my_uuid, my_uuid2, another_id, row_ts)
VALUES
  ('east1234', 'east1234', gen_random_uuid(), gen_random_uuid(), 1, TIMESTAMP '2016-01-25 10:10:10.555555')
----
distribution: local
vectorized: true
·
• insert fast path
  into: hash_sharded_rbr_computed_check(region_based_id, my_uuid, my_uuid2, another_id, row_ts, geo_zone, crdb_region_col, crdb_internal_region_based_id_shard_16, crdb_internal_another_id_row_ts_shard_16)
  auto commit
  uniqueness check: hash_sharded_rbr_computed_check@primary
  uniqueness check: hash_sharded_rbr_computed_check@idx_date
  size: 13 columns, 1 row

# Hash-sharded RBR table with a unique hash-sharded index does not currently
# support multi-row insert fast path.
query T
EXPLAIN INSERT
INTO
  hash_sharded_rbr_computed_check (region_based_id, geo_zone, my_uuid, my_uuid2, another_id, row_ts)
VALUES
  ('east1234', 'east1234', gen_random_uuid(), gen_random_uuid(), 1, TIMESTAMP '2016-01-25 10:10:10.555555'),
  ('east1235', 'east1234', gen_random_uuid(), gen_random_uuid(), 1, TIMESTAMP '2016-01-25 10:10:10.555555')
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: hash_sharded_rbr_computed_check(region_based_id, my_uuid, my_uuid2, another_id, row_ts, geo_zone, crdb_region_col, crdb_internal_region_based_id_shard_16, crdb_internal_another_id_row_ts_shard_16)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • render
│           │
│           └── • render
│               │
│               └── • values
│                     size: 6 columns, 2 rows
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: hash_sharded_rbr_computed_check@primary
│           │ lookup condition: ((crdb_region_col IN ('ap-southeast-2', 'us-east-1')) AND (crdb_internal_region_based_id_shard_16_eq = crdb_internal_region_based_id_shard_16)) AND (region_based_id = region_based_id)
│           │ pred: (crdb_region_col != crdb_region_col) OR (crdb_internal_region_based_id_shard_16 != crdb_internal_region_based_id_shard_16)
│           │
│           └── • render
│               │
│               └── • scan buffer
│                     estimated row count: 2
│                     label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (semi)
            │ table: hash_sharded_rbr_computed_check@idx_date
            │ lookup condition: (((crdb_region_col IN ('ap-southeast-2', 'us-east-1')) AND (crdb_internal_another_id_row_ts_shard_16_eq = crdb_internal_another_id_row_ts_shard_16)) AND (row_ts = row_ts)) AND (another_id = another_id)
            │ pred: ((region_based_id != region_based_id) OR (crdb_region_col != crdb_region_col)) OR (crdb_internal_region_based_id_shard_16 != crdb_internal_region_based_id_shard_16)
            │
            └── • render
                │
                └── • scan buffer
                      estimated row count: 2
                      label: buffer 1

# This case doesn't currently use insert fast path, but could.
# TODO(msirek): Support insert fast path for this case.
query T
EXPLAIN INSERT INTO user_settings3 (id2, user_id, value) VALUES (2, '5ebfedee-0dcf-41e6-a315-5fa0b51b9882', 'foo')
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: user_settings3(id, id2, user_id, value, crdb_region)
│   │
│   └── • buffer
│       │ label: buffer 1
│       │
│       └── • values
│             size: 6 columns, 1 row
│
├── • constraint-check
│   │
│   └── • error if rows
│       │
│       └── • lookup join (semi)
│           │ table: user_settings3@id2_idx
│           │ lookup condition: (crdb_region IN ('ap-southeast-2', 'ca-central-1', 'us-east-1')) AND (column1 = id2)
│           │ pred: (id_default != id) OR (crdb_region_default != crdb_region)
│           │
│           └── • scan buffer
│                 estimated row count: 1
│                 label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │
        └── • lookup join (anti)
            │ table: users@users_pkey
            │ equality cols are key
            │ lookup condition: (crdb_region IN ('ca-central-1', 'us-east-1')) AND (column2 = id)
            │
            └── • lookup join (anti)
                │ table: users@users_pkey
                │ equality cols are key
                │ lookup condition: (crdb_region = 'ap-southeast-2') AND (column2 = id)
                │
                └── • scan buffer
                      estimated row count: 1
                      label: buffer 1

statement ok
CREATE UNIQUE INDEX ON regional_by_row_table (b, a) USING HASH

# After adding a hash sharded unique index, fast path is still legal.
query T
SELECT * FROM [EXPLAIN INSERT INTO regional_by_row_table (pk, pk2, a, b) VALUES (1, 1, 1, 1)] OFFSET 2
----
·
• insert fast path
  into: regional_by_row_table(pk, pk2, a, b, j, crdb_region, crdb_internal_a_b_shard_16)
  auto commit
  uniqueness check: regional_by_row_table@regional_by_row_table_pkey
  uniqueness check: regional_by_row_table@regional_by_row_table_b_key
  uniqueness check: regional_by_row_table@regional_by_row_table_b_a_key
  size: 9 columns, 1 row
