exec-ddl
CREATE TABLE a (x INT PRIMARY KEY, y INT, s STRING, d DECIMAL NOT NULL, b BOOL, UNIQUE (s DESC, d))
----

exec-ddl
ALTER TABLE a INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 2
  },
    {
      "columns": ["y"],
      "created_at": "2018-01-01 1:00:00.00000+00:00",
      "row_count": 2000,
      "distinct_count": 2000,
      "avg_size": 3
    },
    {
      "columns": ["s"],
      "created_at": "2018-01-01 1:00:00.00000+00:00",
      "row_count": 2000,
      "distinct_count": 2000,
      "avg_size": 20
    },
    {
      "columns": ["d"],
      "created_at": "2018-01-01 1:00:00.00000+00:00",
      "row_count": 2000,
      "distinct_count": 2000,
      "avg_size": 5
    },
    {
      "columns": ["b"],
      "created_at": "2018-01-01 1:00:00.00000+00:00",
      "row_count": 2000,
      "distinct_count": 2000,
      "avg_size": 1
    }
]'
----

build
SELECT * FROM a
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=2000]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)~~>(1,2,5)
 └── scan a
      ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=2000]
      ├── key: (1)
      └── fd: (1)-->(2-7), (3,4)~~>(1,2,5-7)

# Check that boolean columns have distinct count 2 when there are no stats
# available.
build
SELECT * FROM a WHERE b
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool!null)
 ├── stats: [rows=1]
 ├── key: (1)
 ├── fd: ()-->(5), (1)-->(2-4), (3,4)~~>(1,2)
 └── select
      ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=1, distinct(5)=1, null(5)=0]
      ├── key: (1)
      ├── fd: ()-->(5), (1)-->(2-4,6,7), (3,4)~~>(1,2,6,7)
      ├── scan a
      │    ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(4)=2000, null(4)=0, distinct(5)=2000, null(5)=0]
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (3,4)~~>(1,2,5-7)
      └── filters
           └── b:5 [type=bool, outer=(5), constraints=(/5: [/true - /true]; tight), fd=()-->(5)]

exec-ddl
ALTER TABLE a INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 2
  },
  {
    "columns": ["x","y"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 5
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 1:30:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 400,
    "avg_size": 3
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 3000,
    "distinct_count": 500,
    "avg_size": 3
  },
  {
    "columns": ["s"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 3000,
    "distinct_count": 2,
    "avg_size": 20
  },
  {
    "columns": ["d"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 3000,
    "distinct_count": 2000,
    "avg_size": 5
  }
]'
----

build
SELECT * FROM a
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=3000]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)~~>(1,2,5)
 └── scan a
      ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=3000]
      ├── key: (1)
      └── fd: (1)-->(2-7), (3,4)~~>(1,2,5-7)

# Test constrained scan.
opt
SELECT s, x FROM a WHERE x > 0 AND x <= 100
----
scan a
 ├── columns: s:3(string) x:1(int!null)
 ├── constraint: /1: [/1 - /100]
 ├── cardinality: [0 - 100]
 ├── stats: [rows=100, distinct(1)=100, null(1)=0]
 ├── key: (1)
 └── fd: (1)-->(3)

# Test limited scan.
opt
SELECT s, x FROM a WHERE x > 5 AND x <= 10 LIMIT 2
----
scan a
 ├── columns: s:3(string) x:1(int!null)
 ├── constraint: /1: [/6 - /10]
 ├── limit: 2
 ├── stats: [rows=2]
 ├── key: (1)
 └── fd: (1)-->(3)

opt
SELECT count(*), y, x FROM a WHERE x > 0 AND x <= 100 GROUP BY x, y
----
group-by (streaming)
 ├── columns: count:8(int!null) y:2(int) x:1(int!null)
 ├── grouping columns: x:1(int!null)
 ├── internal-ordering: +1
 ├── cardinality: [0 - 100]
 ├── stats: [rows=100, distinct(1)=100, null(1)=0]
 ├── key: (1)
 ├── fd: (1)-->(2,8)
 ├── scan a
 │    ├── columns: x:1(int!null) y:2(int)
 │    ├── constraint: /1: [/1 - /100]
 │    ├── cardinality: [0 - 100]
 │    ├── stats: [rows=100, distinct(1)=100, null(1)=0]
 │    ├── key: (1)
 │    ├── fd: (1)-->(2)
 │    └── ordering: +1
 └── aggregations
      ├── count-rows [as=count_rows:8, type=int]
      └── const-agg [as=y:2, type=int, outer=(2)]
           └── y:2 [type=int]

# Test calculation of multi-column stats.
opt
SELECT y, s FROM a GROUP BY y, s
----
distinct-on
 ├── columns: y:2(int) s:3(string)
 ├── grouping columns: y:2(int) s:3(string)
 ├── stats: [rows=1000, distinct(2,3)=1000, null(2,3)=0]
 ├── key: (2,3)
 └── scan a
      ├── columns: y:2(int) s:3(string)
      └── stats: [rows=3000, distinct(2,3)=1000, null(2,3)=0]

opt
SELECT s, d, x FROM a WHERE (s <= 'aaa') OR (s >= 'bar' AND s <= 'foo')
----
scan a@a_s_d_key
 ├── columns: s:3(string!null) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4
 │    ├── [/'foo' - /'bar']
 │    └── [/'aaa' - /NULL)
 ├── stats: [rows=1500, distinct(3)=1, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)-->(1)

opt
SELECT s, d, x FROM a WHERE (s <= 'aaa') OR (s >= 'bar' AND s <= 'foo') OR s IS NULL
----
scan a@a_s_d_key
 ├── columns: s:3(string) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4
 │    ├── [/'foo' - /'bar']
 │    └── [/'aaa' - /NULL]
 ├── stats: [rows=1500, distinct(3)=1, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)~~>(1)

opt
SELECT s, d, x FROM a WHERE s IS NOT NULL
----
scan a@a_s_d_key
 ├── columns: s:3(string!null) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4: [ - /NULL)
 ├── stats: [rows=3000, distinct(3)=2, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)-->(1)

opt
SELECT s, d, x FROM a WHERE (s >= 'bar' AND s <= 'foo') OR (s >= 'foobar')
----
scan a@a_s_d_key
 ├── columns: s:3(string!null) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4
 │    ├── [ - /'foobar']
 │    └── [/'foo' - /'bar']
 ├── stats: [rows=1500, distinct(3)=1, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)-->(1)

opt
SELECT * FROM a WHERE ((s >= 'bar' AND s <= 'foo') OR (s >= 'foobar')) AND d > 5.0
----
select
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── immutable
 ├── stats: [rows=500, distinct(3)=1, null(3)=0, distinct(4)=500, null(4)=0, distinct(3,4)=500, null(3,4)=0]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 ├── scan a
 │    ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool)
 │    ├── stats: [rows=3000, distinct(1)=2000, null(1)=0, distinct(3)=2, null(3)=0, distinct(4)=2000, null(4)=0, distinct(3,4)=3000, null(3,4)=0]
 │    ├── key: (1)
 │    └── fd: (1)-->(2-5), (3,4)~~>(1,2,5)
 └── filters
      ├── ((s:3 >= 'bar') AND (s:3 <= 'foo')) OR (s:3 >= 'foobar') [type=bool, outer=(3), constraints=(/3: [/'bar' - /'foo'] [/'foobar' - ]; tight)]
      └── d:4 > 5.0 [type=bool, outer=(4), immutable, constraints=(/4: (/5.0 - ]; tight)]

opt
SELECT * FROM a WHERE ((s >= 'bar' AND s <= 'foo') OR (s >= 'foobar')) AND d <= 5.0 AND s IS NOT NULL
----
select
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── immutable
 ├── stats: [rows=500, distinct(3)=1, null(3)=0, distinct(4)=500, null(4)=0, distinct(3,4)=500, null(3,4)=0]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 ├── scan a
 │    ├── columns: x:1(int!null) y:2(int) s:3(string) d:4(decimal!null) b:5(bool)
 │    ├── stats: [rows=3000, distinct(1)=2000, null(1)=0, distinct(3)=2, null(3)=0, distinct(4)=2000, null(4)=0, distinct(3,4)=3000, null(3,4)=0]
 │    ├── key: (1)
 │    └── fd: (1)-->(2-5), (3,4)~~>(1,2,5)
 └── filters
      ├── (((s:3 >= 'bar') AND (s:3 <= 'foo')) OR (s:3 >= 'foobar')) AND (s:3 IS NOT NULL) [type=bool, outer=(3), constraints=(/3: [/'bar' - /'foo'] [/'foobar' - ]; tight)]
      └── d:4 <= 5.0 [type=bool, outer=(4), immutable, constraints=(/4: (/NULL - /5.0]; tight)]

# Bump up null counts.

exec-ddl
ALTER TABLE a INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 2
  },
  {
    "columns": ["x","y"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "null_count": 300,
    "avg_size": 5
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 1:30:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 401,
    "null_count": 800,
    "avg_size": 3
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 3000,
    "distinct_count": 501,
    "null_count": 1000,
    "avg_size": 3
  },
  {
    "columns": ["s"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 3000,
    "distinct_count": 3,
    "null_count": 1000,
    "avg_size": 20
  },
  {
    "columns": ["b"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 3000,
    "distinct_count": 3,
    "null_count": 1500,
    "avg_size": 1
  }
]'
----

# Test calculation of multi-column stats.
opt colstat=2 colstat=3 colstat=5 colstat=(2,3,5) colstat=(2,3) colstat=(3,5)
SELECT y,s,b FROM a
----
scan a
 ├── columns: y:2(int) s:3(string) b:5(bool)
 └── stats: [rows=3000, distinct(2)=501, null(2)=1000, distinct(3)=3, null(3)=1000, distinct(5)=3, null(5)=1500, distinct(2,3)=1503, null(2,3)=333.333, distinct(3,5)=9, null(3,5)=500, distinct(2,3,5)=3000, null(2,3,5)=166.667]

opt colstat=1 colstat=3 colstat=5 colstat=(1,3,5) colstat=(1,3) colstat=(3,5)
SELECT x,y,s FROM a
----
scan a
 ├── columns: x:1(int!null) y:2(int) s:3(string)
 ├── stats: [rows=3000, distinct(1)=2000, null(1)=0, distinct(3)=3, null(3)=1000, distinct(5)=3, null(5)=1500, distinct(1,3)=3000, null(1,3)=0, distinct(3,5)=9, null(3,5)=500, distinct(1,3,5)=3000, null(1,3,5)=0]
 ├── key: (1)
 └── fd: (1)-->(2,3)

opt
SELECT y, s FROM a GROUP BY y, s
----
distinct-on
 ├── columns: y:2(int) s:3(string)
 ├── grouping columns: y:2(int) s:3(string)
 ├── stats: [rows=1503, distinct(2,3)=1503, null(2,3)=1]
 ├── key: (2,3)
 └── scan a
      ├── columns: y:2(int) s:3(string)
      └── stats: [rows=3000, distinct(2,3)=1503, null(2,3)=333.333]

opt
SELECT s, d, x FROM a WHERE ((s <= 'aaa') OR (s >= 'bar' AND s <= 'foo')) AND s IS NOT NULL
----
scan a@a_s_d_key
 ├── columns: s:3(string!null) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4
 │    ├── [/'foo' - /'bar']
 │    └── [/'aaa' - /NULL)
 ├── stats: [rows=1000, distinct(3)=1, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)-->(1)

opt
SELECT s, d, x FROM a WHERE (s <= 'aaa') OR (s >= 'bar' AND s <= 'foo') OR s IS NULL
----
scan a@a_s_d_key
 ├── columns: s:3(string) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4
 │    ├── [/'foo' - /'bar']
 │    └── [/'aaa' - /NULL]
 ├── stats: [rows=1000, distinct(3)=1, null(3)=1000]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)~~>(1)

opt
SELECT s, d, x FROM a WHERE s IS NOT NULL
----
scan a@a_s_d_key
 ├── columns: s:3(string!null) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4: [ - /NULL)
 ├── stats: [rows=2000, distinct(3)=3, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)-->(1)

opt
SELECT s, d, x FROM a WHERE ((s >= 'bar' AND s <= 'foo') OR (s >= 'foobar')) AND s IS NOT NULL
----
scan a@a_s_d_key
 ├── columns: s:3(string!null) d:4(decimal!null) x:1(int!null)
 ├── constraint: /-3/4
 │    ├── [ - /'foobar']
 │    └── [/'foo' - /'bar']
 ├── stats: [rows=1000, distinct(3)=1, null(3)=0]
 ├── key: (1)
 └── fd: (1)-->(3,4), (3,4)-->(1)

opt
SELECT * FROM a WHERE ((s >= 'bar' AND s <= 'foo') OR (s >= 'foobar')) AND d <= 5.0 AND s IS NOT NULL
----
index-join a
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── immutable
 ├── stats: [rows=333.3333, distinct(3)=1, null(3)=0, distinct(4)=100, null(4)=0, distinct(3,4)=100, null(3,4)=0]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 └── select
      ├── columns: x:1(int!null) s:3(string!null) d:4(decimal!null)
      ├── immutable
      ├── stats: [rows=333.3333, distinct(4)=98.2658, null(4)=0]
      ├── key: (1)
      ├── fd: (1)-->(3,4), (3,4)-->(1)
      ├── scan a@a_s_d_key
      │    ├── columns: x:1(int!null) s:3(string!null) d:4(decimal!null)
      │    ├── constraint: /-3/4
      │    │    ├── [ - /'foobar'/5.0]
      │    │    └── [/'foo' - /'bar'/5.0]
      │    ├── stats: [rows=1000, distinct(1)=911.338, null(1)=0, distinct(3)=1, null(3)=0, distinct(4)=294.798, null(4)=0]
      │    ├── key: (1)
      │    └── fd: (1)-->(3,4), (3,4)-->(1)
      └── filters
           └── d:4 <= 5.0 [type=bool, outer=(4), immutable, constraints=(/4: (/NULL - /5.0]; tight)]

exec-ddl
CREATE TABLE abcde (
  a INT PRIMARY KEY,
  b INT,
  c STRING,
  d INT,
  e INT,
  INDEX bad(b, d),
  INDEX good(b, c, d)
)
----

# Regression test for #31929. Ensure that the good index is chosen.
opt
SELECT * FROM abcde WHERE b = 1 AND c LIKE '+1-1000%'
----
index-join abcde
 ├── columns: a:1(int!null) b:2(int!null) c:3(string!null) d:4(int) e:5(int)
 ├── stats: [rows=9.111111, distinct(2)=1, null(2)=0, distinct(3)=9.11111, null(3)=0, distinct(2,3)=9.11111, null(2,3)=0]
 ├── key: (1)
 ├── fd: ()-->(2), (1)-->(3-5)
 └── scan abcde@good
      ├── columns: a:1(int!null) b:2(int!null) c:3(string!null) d:4(int)
      ├── constraint: /2/3/4/1: [/1/'+1-1000' - /1/'+1-1001')
      ├── stats: [rows=9.111111, distinct(2)=1, null(2)=0, distinct(3)=9.11111, null(3)=0, distinct(2,3)=9.11111, null(2,3)=0]
      ├── key: (1)
      └── fd: ()-->(2), (1)-->(3,4)

exec-ddl
CREATE SEQUENCE seq
----

opt
SELECT * FROM seq
----
sequence-select seq
 ├── columns: last_value:1(int!null) log_cnt:2(int!null) is_called:3(bool!null)
 ├── cardinality: [1 - 1]
 ├── stats: [rows=1]
 ├── key: ()
 └── fd: ()-->(1-3)

exec-ddl
CREATE TABLE empty (x INT)
----

exec-ddl
ALTER TABLE empty INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 0,
    "distinct_count": 0
  }
]'
----

# We should always estimate at least 1 row even if the stats have 0 rows.
opt
SELECT * FROM empty
----
scan empty
 ├── columns: x:1(int)
 └── stats: [rows=1]

# Regression test: previously, overflow when computing estimated distinct count
# here resulted in a row count of zero being estimated.
opt
SELECT x FROM a WHERE x >= -9223372036854775808 AND x <= 0 ORDER BY x LIMIT 10
----
scan a
 ├── columns: x:1(int!null)
 ├── constraint: /1: [/-9223372036854775808 - /0]
 ├── limit: 10
 ├── stats: [rows=10]
 ├── key: (1)
 └── ordering: +1

# Regression test for #37953.
exec-ddl
CREATE TABLE t37953 (
    a UUID NOT NULL,
    b FLOAT8 NOT NULL,
    c TIME NOT NULL,
    d UUID NOT NULL,
    e VARCHAR,
    f "char" NULL,
    g INT4 NOT NULL,
    h VARCHAR NULL,
    i REGPROC NULL,
    j FLOAT8 NOT NULL
)
----

norm
WITH
  subq (col0, col1)
    AS (
      SELECT
        tab1.g AS col0,
        CASE
        WHEN ilike_escape(
          regexp_replace(
            tab0.h,
            tab1.e,
            tab0.f,
            tab0.e::STRING
          ),
          tab1.f,
          ''
        )
        THEN true
        ELSE false
        END
          AS col1
      FROM
        t37953 AS tab0, t37953 AS tab1
      WHERE
        tab0.j IN (tab1.j,)
    )
SELECT
  1
FROM
  subq
WHERE
  subq.col1;
----
project
 ├── columns: "?column?":30(int!null)
 ├── immutable
 ├── stats: [rows=1.000001]
 ├── fd: ()-->(30)
 ├── select
 │    ├── columns: col1:29(bool!null)
 │    ├── immutable
 │    ├── stats: [rows=1.000001, distinct(29)=1, null(29)=0]
 │    ├── fd: ()-->(29)
 │    ├── project
 │    │    ├── columns: col1:29(bool)
 │    │    ├── immutable
 │    │    ├── stats: [rows=10000, distinct(29)=10000, null(29)=0]
 │    │    ├── inner-join (hash)
 │    │    │    ├── columns: tab0.e:5(varchar) tab0.f:6("char") tab0.h:8(varchar) tab0.j:10(float!null) tab1.e:18(varchar) tab1.f:19("char") tab1.j:23(float!null)
 │    │    │    ├── multiplicity: left-rows(one-or-more), right-rows(one-or-more)
 │    │    │    ├── stats: [rows=10000, distinct(10)=100, null(10)=0, distinct(23)=100, null(23)=0, distinct(5,6,8,18,19)=10000, null(5,6,8,18,19)=1e-06]
 │    │    │    ├── fd: (10)==(23), (23)==(10)
 │    │    │    ├── scan t37953 [as=tab0]
 │    │    │    │    ├── columns: tab0.e:5(varchar) tab0.f:6("char") tab0.h:8(varchar) tab0.j:10(float!null)
 │    │    │    │    └── stats: [rows=1000, distinct(10)=100, null(10)=0, distinct(5,6,8)=1000, null(5,6,8)=0.001]
 │    │    │    ├── scan t37953 [as=tab1]
 │    │    │    │    ├── columns: tab1.e:18(varchar) tab1.f:19("char") tab1.j:23(float!null)
 │    │    │    │    └── stats: [rows=1000, distinct(23)=100, null(23)=0, distinct(18,19)=1000, null(18,19)=0.1]
 │    │    │    └── filters
 │    │    │         └── tab0.j:10 = tab1.j:23 [type=bool, outer=(10,23), constraints=(/10: (/NULL - ]; /23: (/NULL - ]), fd=(10)==(23), (23)==(10)]
 │    │    └── projections
 │    │         └── CASE WHEN ilike_escape(regexp_replace(tab0.h:8, tab1.e:18, tab0.f:6, tab0.e:5::STRING), tab1.f:19, '') THEN true ELSE false END [as=col1:29, type=bool, outer=(5,6,8,18,19), immutable]
 │    └── filters
 │         └── col1:29 [type=bool, outer=(29), constraints=(/29: [/true - /true]; tight), fd=()-->(29)]
 └── projections
      └── 1 [as="?column?":30, type=int]

# ---------------------
# Tests with Histograms
# ---------------------

exec-ddl
CREATE TABLE hist (
  a INT,
  b DATE,
  c DECIMAL,
  d FLOAT,
  e TIMESTAMP,
  f TIMESTAMPTZ,
  g STRING,
  INDEX idx_a (a),
  INDEX idx_b (b),
  INDEX idx_c (c),
  INDEX idx_d (d),
  INDEX idx_e (e),
  INDEX idx_f (f),
  INDEX idx_g (g)
)
----

exec-ddl
ALTER TABLE hist INJECT STATISTICS '[
  {
    "columns": ["a"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 40,
    "avg_size": 2,
    "histo_col_type": "int",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "0"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 9, "upper_bound": "10"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 9, "upper_bound": "20"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 9, "upper_bound": "30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 9, "upper_bound": "40"}
    ]
  },
  {
    "columns": ["b"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 120,
    "avg_size": 6,
    "histo_col_type": "date",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "2018-06-30"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 29, "upper_bound": "2018-07-31"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 29, "upper_bound": "2018-08-31"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 29, "upper_bound": "2018-09-30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 29, "upper_bound": "2018-10-31"}
    ]
  },
  {
    "columns": ["c"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 45,
    "avg_size": 3,
    "histo_col_type": "decimal",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "0"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 9, "upper_bound": "10"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 10, "upper_bound": "20"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 11, "upper_bound": "30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 11, "upper_bound": "40"}
    ]
  },
  {
    "columns": ["d"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 45,
    "avg_size": 5,
    "histo_col_type": "float",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "0"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 9, "upper_bound": "10"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 10, "upper_bound": "20"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 11, "upper_bound": "30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 11, "upper_bound": "40"}
    ]
  },
  {
    "columns": ["e"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 200,
    "avg_size": 7,
    "histo_col_type": "timestamp",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "2018-06-30"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 49, "upper_bound": "2018-07-31"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 49, "upper_bound": "2018-08-31"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 49, "upper_bound": "2018-09-30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 49, "upper_bound": "2018-10-31"}
    ]
  },
  {
    "columns": ["f"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 200,
    "avg_size": 8,
    "histo_col_type": "timestamptz",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "2018-06-30"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 49, "upper_bound": "2018-07-31"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 49, "upper_bound": "2018-08-31"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 49, "upper_bound": "2018-09-30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 49, "upper_bound": "2018-10-31"}
    ]
  },
  {
    "columns": ["g"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 40,
    "avg_size": 10,
    "histo_col_type": "string",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "apple"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 9, "upper_bound": "banana"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 9, "upper_bound": "cherry"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 9, "upper_bound": "mango"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 9, "upper_bound": "pineapple"}
    ]
  }
]'
----

# An index join is worthwhile for a < 10.
opt
SELECT * FROM hist WHERE a < 10
----
index-join hist
 ├── columns: a:1(int!null) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── stats: [rows=90, distinct(1)=9, null(1)=0]
 │   histogram(1)=  0  0  80 10
 │                <--- 0 ---- 9
 └── scan hist@idx_a
      ├── columns: a:1(int!null) rowid:8(int!null)
      ├── constraint: /1/8: (/NULL - /9]
      ├── stats: [rows=90, distinct(1)=9, null(1)=0]
      │   histogram(1)=  0  0  80 10
      │                <--- 0 ---- 9
      ├── key: (8)
      └── fd: (8)-->(1)

# An index join is not worthwhile for a > 30.
opt
SELECT * FROM hist WHERE a > 30
----
select
 ├── columns: a:1(int!null) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── stats: [rows=400, distinct(1)=10, null(1)=0]
 │   histogram(1)=  0  0   360  40
 │                <--- 30 ----- 40
 ├── scan hist
 │    ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 │    └── stats: [rows=1000, distinct(1)=40, null(1)=0]
 │        histogram(1)=  0  0  90  10  180  20  270  30  360  40
 │                     <--- 0 ---- 10 ----- 20 ----- 30 ----- 40
 └── filters
      └── a:1 > 30 [type=bool, outer=(1), constraints=(/1: [/31 - ]; tight)]

opt
SELECT * FROM hist WHERE b > '2018-07-31'::DATE AND b < '2018-08-05'::DATE
----
index-join hist
 ├── columns: a:1(int) b:2(date!null) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── stats: [rows=24, distinct(2)=3.9, null(2)=0]
 │   histogram(2)=  0       0        18       6
 │                <--- '2018-07-31' ---- '2018-08-04'
 └── scan hist@idx_b
      ├── columns: b:2(date!null) rowid:8(int!null)
      ├── constraint: /2/8: [/'2018-08-01' - /'2018-08-04']
      ├── stats: [rows=24, distinct(2)=3.9, null(2)=0]
      │   histogram(2)=  0       0        18       6
      │                <--- '2018-07-31' ---- '2018-08-04'
      ├── key: (8)
      └── fd: (8)-->(2)

opt
SELECT * FROM hist WHERE c = 20 OR (c < 10)
----
index-join hist
 ├── columns: a:1(int) b:2(date) c:3(decimal!null) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── immutable
 ├── stats: [rows=110, distinct(3)=10, null(3)=0]
 │   histogram(3)=  0  0  90  0   0  20
 │                <--- 0 ---- 10 --- 20
 └── scan hist@idx_c
      ├── columns: c:3(decimal!null) rowid:8(int!null)
      ├── constraint: /3/8
      │    ├── (/NULL - /10)
      │    └── [/20 - /20]
      ├── stats: [rows=110, distinct(3)=10, null(3)=0]
      │   histogram(3)=  0  0  90  0   0  20
      │                <--- 0 ---- 10 --- 20
      ├── key: (8)
      └── fd: (8)-->(3)

opt
SELECT * FROM hist WHERE c = 20 OR (c <= 10)
----
index-join hist
 ├── columns: a:1(int) b:2(date) c:3(decimal!null) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── immutable
 ├── stats: [rows=120, distinct(3)=11, null(3)=0]
 │   histogram(3)=  0  0  90  10  0  20
 │                <--- 0 ---- 10 --- 20
 └── scan hist@idx_c
      ├── columns: c:3(decimal!null) rowid:8(int!null)
      ├── constraint: /3/8
      │    ├── (/NULL - /10]
      │    └── [/20 - /20]
      ├── stats: [rows=120, distinct(3)=11, null(3)=0]
      │   histogram(3)=  0  0  90  10  0  20
      │                <--- 0 ---- 10 --- 20
      ├── key: (8)
      └── fd: (8)-->(3)

opt
SELECT * FROM hist WHERE (d >= 5 AND d < 12) OR d >= 40
----
index-join hist
 ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float!null) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── stats: [rows=131, distinct(4)=8.5, null(4)=0]
 │   histogram(4)=  0          0          45   10   36          0           0   40
 │                <--- 4.999999999999999 ---- 10.0 ---- 11.999999999999998 --- 40.0
 └── scan hist@idx_d
      ├── columns: d:4(float!null) rowid:8(int!null)
      ├── constraint: /4/8
      │    ├── [/5.0 - /11.999999999999998]
      │    └── [/40.0 - ]
      ├── stats: [rows=131, distinct(4)=8.5, null(4)=0]
      │   histogram(4)=  0          0          45   10   36          0           0   40
      │                <--- 4.999999999999999 ---- 10.0 ---- 11.999999999999998 --- 40.0
      ├── key: (8)
      └── fd: (8)-->(4)

opt
SELECT * FROM hist WHERE e < '2018-07-31 23:00:00'::TIMESTAMP
----
index-join hist
 ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float) e:5(timestamp!null) f:6(timestamptz) g:7(string)
 ├── stats: [rows=105.5645, distinct(5)=51.5148, null(5)=0]
 │   histogram(5)=  0            0            90           10            5.5645           6.7204e-14
 │                <--- '2018-06-30 00:00:00' ---- '2018-07-31 00:00:00' -------- '2018-07-31 22:59:59.999999'
 └── scan hist@idx_e
      ├── columns: e:5(timestamp!null) rowid:8(int!null)
      ├── constraint: /5/8: (/NULL - /'2018-07-31 22:59:59.999999']
      ├── stats: [rows=105.5645, distinct(5)=51.5148, null(5)=0]
      │   histogram(5)=  0            0            90           10            5.5645           6.7204e-14
      │                <--- '2018-06-30 00:00:00' ---- '2018-07-31 00:00:00' -------- '2018-07-31 22:59:59.999999'
      ├── key: (8)
      └── fd: (8)-->(5)

opt
SELECT * FROM hist WHERE f = '2019-10-30 23:00:00'::TIMESTAMPTZ
----
index-join hist
 ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz!null) g:7(string)
 ├── stats: [rows=2e-07, distinct(6)=2e-07, null(6)=0]
 │   histogram(6)=
 ├── fd: ()-->(6)
 └── scan hist@idx_f
      ├── columns: f:6(timestamptz!null) rowid:8(int!null)
      ├── constraint: /6/8: [/'2019-10-30 23:00:00+00' - /'2019-10-30 23:00:00+00']
      ├── stats: [rows=2e-07, distinct(6)=2e-07, null(6)=0]
      │   histogram(6)=
      ├── key: (8)
      └── fd: ()-->(6)

opt
SELECT * FROM hist WHERE g = 'mango' OR g = 'foo'
----
index-join hist
 ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string!null)
 ├── stats: [rows=60, distinct(7)=2, null(7)=0]
 │   histogram(7)=  0   30    0    30
 │                <--- 'foo' --- 'mango'
 └── scan hist@idx_g
      ├── columns: g:7(string!null) rowid:8(int!null)
      ├── constraint: /7/8
      │    ├── [/'foo' - /'foo']
      │    └── [/'mango' - /'mango']
      ├── stats: [rows=60, distinct(7)=2, null(7)=0]
      │   histogram(7)=  0   30    0    30
      │                <--- 'foo' --- 'mango'
      ├── key: (8)
      └── fd: (8)-->(7)

# Select the correct index depending on which predicate is more selective.
opt
SELECT * FROM hist WHERE (a = 10 OR a = 20) AND (b = '2018-08-31'::DATE OR b = '2018-09-30'::DATE)
----
select
 ├── columns: a:1(int!null) b:2(date!null) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── stats: [rows=4.632009, distinct(1)=2, null(1)=0, distinct(2)=2, null(2)=0, distinct(1,2)=3.80513, null(1,2)=0]
 │   histogram(1)=  0 1.544 0 3.088
 │                <--- 10 ---- 20 -
 │   histogram(2)=  0     1.8528     0     2.7792
 │                <--- '2018-08-31' --- '2018-09-30'
 ├── index-join hist
 │    ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 │    ├── stats: [rows=30]
 │    └── scan hist@idx_a
 │         ├── columns: a:1(int!null) rowid:8(int!null)
 │         ├── constraint: /1/8
 │         │    ├── [/10 - /10]
 │         │    └── [/20 - /20]
 │         ├── stats: [rows=30, distinct(1)=2, null(1)=0]
 │         │   histogram(1)=  0  10  0  20
 │         │                <--- 10 --- 20
 │         ├── key: (8)
 │         └── fd: (8)-->(1)
 └── filters
      └── (b:2 = '2018-08-31') OR (b:2 = '2018-09-30') [type=bool, outer=(2), constraints=(/2: [/'2018-08-31' - /'2018-08-31'] [/'2018-09-30' - /'2018-09-30']; tight)]

opt
SELECT * FROM hist WHERE (a = 30 OR a = 40) AND (b = '2018-06-30'::DATE OR b = '2018-07-31'::DATE)
----
select
 ├── columns: a:1(int!null) b:2(date!null) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 ├── stats: [rows=0.7000001, distinct(1)=0.7, null(1)=0, distinct(2)=0.7, null(2)=0, distinct(1,2)=0.7, null(1,2)=0]
 │   histogram(1)=  0 0.3  0 0.4
 │                <--- 30 --- 40
 │   histogram(2)=  0      0.7
 │                <--- '2018-07-31'
 ├── index-join hist
 │    ├── columns: a:1(int) b:2(date) c:3(decimal) d:4(float) e:5(timestamp) f:6(timestamptz) g:7(string)
 │    ├── stats: [rows=10]
 │    └── scan hist@idx_b
 │         ├── columns: b:2(date!null) rowid:8(int!null)
 │         ├── constraint: /2/8
 │         │    ├── [/'2018-06-30' - /'2018-06-30']
 │         │    └── [/'2018-07-31' - /'2018-07-31']
 │         ├── stats: [rows=10, distinct(2)=1, null(2)=0]
 │         │   histogram(2)=  0       10
 │         │                <--- '2018-07-31'
 │         ├── key: (8)
 │         └── fd: (8)-->(2)
 └── filters
      └── (a:1 = 30) OR (a:1 = 40) [type=bool, outer=(1), constraints=(/1: [/30 - /30] [/40 - /40]; tight)]

# Regression test for #47390. Histograms must be used with index constraints
# to choose the correct index.
exec-ddl
CREATE TABLE xyz (
  x INT,
  y INT,
  z INT,
  other INT,
  PRIMARY KEY(x, y),
  UNIQUE INDEX xyz_x_z_key (x, z),
  INDEX xyz_x_other_z (x, other DESC)
)
----

exec-ddl
ALTER TABLE xyz INJECT STATISTICS '[
  {
    "columns": ["x"],
    "distinct_count": 5,
    "null_count": 0,
    "row_count": 100,
    "created_at": "2020-01-01 0:00:00.00000+00:00"
  },
  {
    "columns": ["z"],
    "distinct_count": 100,
    "null_count": 0,
    "row_count": 100,
    "created_at": "2020-01-01 0:00:00.00000+00:00",
    "histo_col_type": "int",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "0"},
      {"num_eq": 0, "num_range": 100, "distinct_range": 100, "upper_bound": "1000"}
    ]
  },
  {
    "columns": ["other"],
    "distinct_count": 30,
    "null_count": 0,
    "row_count": 100,
    "created_at": "2020-01-01 0:00:00.00000+00:00",
    "histo_col_type": "int",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "0"},
      {"num_eq": 10, "num_range": 10, "distinct_range": 10, "upper_bound": "10"},
      {"num_eq": 20, "num_range": 20, "distinct_range": 20, "upper_bound": "20"},
      {"num_eq": 20, "num_range": 20, "distinct_range": 20, "upper_bound": "30"}
    ]
  }
]'
----

opt
SELECT * FROM xyz WHERE x=1 AND z>990
----
index-join xyz
 ├── columns: x:1(int!null) y:2(int!null) z:3(int!null) other:4(int)
 ├── stats: [rows=0.1801802, distinct(1)=0.18018, null(1)=0, distinct(3)=0.18018, null(3)=0, distinct(1,3)=0.18018, null(1,3)=0]
 │   histogram(3)=  0   0   0.18018   0
 │                <--- 990 --------- 1000
 ├── key: (2)
 ├── fd: ()-->(1), (2)-->(3,4), (3)-->(2,4)
 └── scan xyz@xyz_x_z_key
      ├── columns: x:1(int!null) y:2(int!null) z:3(int!null)
      ├── constraint: /1/3: [/1/991 - /1]
      ├── stats: [rows=0.1801802, distinct(1)=0.18018, null(1)=0, distinct(3)=0.18018, null(3)=0, distinct(1,3)=0.18018, null(1,3)=0]
      │   histogram(3)=  0   0   0.18018   0
      │                <--- 990 --------- 1000
      ├── key: (2)
      └── fd: ()-->(1), (2)-->(3), (3)-->(2)

opt
SELECT * FROM xyz WHERE x=1 AND z<990 AND (other=11 OR other=13)
----
select
 ├── columns: x:1(int!null) y:2(int!null) z:3(int!null) other:4(int!null)
 ├── stats: [rows=0.395996, distinct(1)=0.395996, null(1)=0, distinct(3)=0.395996, null(3)=0, distinct(4)=0.395996, null(4)=0, distinct(1,3,4)=0.395996, null(1,3,4)=0]
 │   histogram(3)=  0  0  0.3956 0.0004004
 │                <--- 0 ---------- 989 --
 │   histogram(4)=  0 0.198 0 0.198
 │                <--- 11 ---- 13 -
 ├── key: (2)
 ├── fd: ()-->(1), (2)-->(3,4), (3)-->(2,4)
 ├── index-join xyz
 │    ├── columns: x:1(int!null) y:2(int!null) z:3(int) other:4(int)
 │    ├── stats: [rows=0.4]
 │    ├── key: (2)
 │    ├── fd: ()-->(1), (2)-->(3,4), (1,3)~~>(2,4)
 │    └── scan xyz@xyz_x_other_z
 │         ├── columns: x:1(int!null) y:2(int!null) other:4(int!null)
 │         ├── constraint: /1/-4/2
 │         │    ├── [/1/13 - /1/13]
 │         │    └── [/1/11 - /1/11]
 │         ├── stats: [rows=0.4, distinct(1)=0.4, null(1)=0, distinct(4)=0.4, null(4)=0, distinct(1,4)=0.4, null(1,4)=0]
 │         │   histogram(4)=  0 0.2  0 0.2
 │         │                <--- 11 --- 13
 │         ├── key: (2)
 │         └── fd: ()-->(1), (2)-->(4)
 └── filters
      └── z:3 < 990 [type=bool, outer=(3), constraints=(/3: (/NULL - /989]; tight)]

# Regression test for #47742 and #47879. Make sure the first bucket always has
# NumRange=0, even after filtering.
exec-ddl
CREATE TABLE t47742 (a INT, b BOOL, INDEX b_idx (b DESC));
----

exec-ddl
ALTER TABLE t47742 INJECT STATISTICS '[
  {
    "name":"__auto__",
    "created_at":"2000-01-01 00:00:00+00:00",
    "columns":["b"],
    "row_count":200000,
    "distinct_count":56128,
    "null_count":27606,
    "histo_col_type":"BOOL",
    "histo_buckets":[{
      "num_eq":7975541041996628837,
      "num_range":0,
      "distinct_range":0,
      "upper_bound":"false"
    },
    {
      "num_eq":124065620125775458,
      "num_range":100000000000,
      "distinct_range":100000000000,
      "upper_bound":"true"
    }]
  }
]'
----

opt round-in-strings=5
SELECT a, b::string FROM t47742 WHERE b = true
----
project
 ├── columns: a:1(int) b:6(string!null)
 ├── immutable
 ├── stats: [rows=3063.5]
 ├── fd: ()-->(6)
 ├── index-join t47742
 │    ├── columns: a:1(int) t47742.b:2(bool!null)
 │    ├── stats: [rows=3063.5, distinct(2)=1, null(2)=0]
 │    │   histogram(2)=  0 3063.5
 │    │                <--- true
 │    ├── fd: ()-->(2)
 │    └── scan t47742@b_idx
 │         ├── columns: t47742.b:2(bool!null) rowid:3(int!null)
 │         ├── constraint: /-2/3: [/true - /true]
 │         ├── stats: [rows=3063.5, distinct(2)=1, null(2)=0]
 │         │   histogram(2)=  0 3063.5
 │         │                <--- true
 │         ├── key: (3)
 │         └── fd: ()-->(2)
 └── projections
      └── t47742.b:2::STRING [as=b:6, type=string, outer=(2), immutable]

# Multi-column stats tests.
exec-ddl
CREATE TABLE multi_col (
  a UUID,
  b BOOL,
  c INT,
  d STRING,
  e INT,
  f FLOAT,
  INDEX abcde_idx (a, b, c DESC, d, e),
  INDEX ce_idx (c, e),
  INDEX bad_idx (b, a DESC, d),
  INDEX def_idx (d, e, f),
  INDEX bef_idx (b, e, f)
)
----

opt
SELECT * FROM multi_col
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND c = 5
AND d = 'foo'
AND e > 10 AND e <= 20
AND f > 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.07568148, distinct(1)=0.0756815, null(1)=0, distinct(2)=0.0756815, null(2)=0, distinct(3)=0.0756815, null(3)=0, distinct(4)=0.0756815, null(4)=0, distinct(5)=0.0756815, null(5)=0, distinct(6)=0.0756815, null(6)=0, distinct(5,6)=0.0756815, null(5,6)=0, distinct(1-4)=0.0756815, null(1-4)=0, distinct(1-6)=0.0756815, null(1-6)=0]
 ├── fd: ()-->(1-4)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=0.08109049]
 │    ├── fd: ()-->(1-4)
 │    └── scan multi_col@abcde_idx
 │         ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) rowid:7(int!null)
 │         ├── constraint: /1/2/-3/4/5/7: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/true/5/'foo'/11 - /'37685f26-4b07-40ba-9bbf-42916ed9bc61'/true/5/'foo'/20]
 │         ├── stats: [rows=0.08109049, distinct(1)=0.0810905, null(1)=0, distinct(2)=0.0810905, null(2)=0, distinct(3)=0.0810905, null(3)=0, distinct(4)=0.0810905, null(4)=0, distinct(5)=0.0810905, null(5)=0, distinct(1-4)=0.0810905, null(1-4)=0, distinct(1-5)=0.0810905, null(1-5)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(1-4), (7)-->(5)
 └── filters
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

# Make sure stats estimates are as expected when forcing the other indexes.
opt
SELECT * FROM multi_col@ce_idx
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND c = 5
AND d = 'foo'
AND e > 10 AND e <= 20
AND f > 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.07568148, distinct(1)=0.0756815, null(1)=0, distinct(2)=0.0756815, null(2)=0, distinct(3)=0.0756815, null(3)=0, distinct(4)=0.0756815, null(4)=0, distinct(5)=0.0756815, null(5)=0, distinct(6)=0.0756815, null(6)=0, distinct(5,6)=0.0756815, null(5,6)=0, distinct(1-4)=0.0756815, null(1-4)=0, distinct(1-6)=0.0756815, null(1-6)=0]
 ├── fd: ()-->(1-4)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=9.1]
 │    ├── fd: ()-->(3)
 │    └── scan multi_col@ce_idx
 │         ├── columns: c:3(int!null) e:5(int!null) rowid:7(int!null)
 │         ├── constraint: /3/5/7: [/5/11 - /5/20]
 │         ├── flags: force-index=ce_idx
 │         ├── stats: [rows=9.1, distinct(3)=1, null(3)=0, distinct(5)=9.1, null(5)=0, distinct(3,5)=9.1, null(3,5)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(3), (7)-->(5)
 └── filters
      ├── a:1 = '37685f26-4b07-40ba-9bbf-42916ed9bc61' [type=bool, outer=(1), constraints=(/1: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61' - /'37685f26-4b07-40ba-9bbf-42916ed9bc61']; tight), fd=()-->(1)]
      ├── b:2 [type=bool, outer=(2), constraints=(/2: [/true - /true]; tight), fd=()-->(2)]
      ├── d:4 = 'foo' [type=bool, outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)]
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

opt
SELECT * FROM multi_col@bad_idx
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND c = 5
AND d = 'foo'
AND e > 10 AND e <= 20
AND f > 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.07568148, distinct(1)=0.0756815, null(1)=0, distinct(2)=0.0756815, null(2)=0, distinct(3)=0.0756815, null(3)=0, distinct(4)=0.0756815, null(4)=0, distinct(5)=0.0756815, null(5)=0, distinct(6)=0.0756815, null(6)=0, distinct(5,6)=0.0756815, null(5,6)=0, distinct(1-4)=0.0756815, null(1-4)=0, distinct(1-6)=0.0756815, null(1-6)=0]
 ├── fd: ()-->(1-4)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=0.90585]
 │    ├── fd: ()-->(1,2,4)
 │    └── scan multi_col@bad_idx
 │         ├── columns: a:1(uuid!null) b:2(bool!null) d:4(string!null) rowid:7(int!null)
 │         ├── constraint: /2/-1/4/7: [/true/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'foo' - /true/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'foo']
 │         ├── flags: force-index=bad_idx
 │         ├── stats: [rows=0.90585, distinct(1)=0.90585, null(1)=0, distinct(2)=0.90585, null(2)=0, distinct(4)=0.90585, null(4)=0, distinct(1,2,4)=0.90585, null(1,2,4)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(1,2,4)
 └── filters
      ├── (e:5 > 10) AND (e:5 <= 20) [type=bool, outer=(5), constraints=(/5: [/11 - /20]; tight)]
      ├── c:3 = 5 [type=bool, outer=(3), constraints=(/3: [/5 - /5]; tight), fd=()-->(3)]
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

opt
SELECT * FROM multi_col@def_idx
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND c = 5
AND d = 'foo'
AND e > 10 AND e <= 20
AND f > 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.07568148, distinct(1)=0.0756815, null(1)=0, distinct(2)=0.0756815, null(2)=0, distinct(3)=0.0756815, null(3)=0, distinct(4)=0.0756815, null(4)=0, distinct(5)=0.0756815, null(5)=0, distinct(6)=0.0756815, null(6)=0, distinct(5,6)=0.0756815, null(5,6)=0, distinct(1-4)=0.0756815, null(1-4)=0, distinct(1-6)=0.0756815, null(1-6)=0]
 ├── fd: ()-->(1-4)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=3.391172]
 │    ├── fd: ()-->(4)
 │    └── select
 │         ├── columns: d:4(string!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── stats: [rows=3.391172, distinct(6)=2.91209, null(6)=0]
 │         ├── key: (7)
 │         ├── fd: ()-->(4), (7)-->(5,6)
 │         ├── scan multi_col@def_idx
 │         │    ├── columns: d:4(string!null) e:5(int!null) f:6(float) rowid:7(int!null)
 │         │    ├── constraint: /4/5/6/7: [/'foo'/11/5e-324 - /'foo'/20]
 │         │    ├── flags: force-index=def_idx
 │         │    ├── stats: [rows=9.1, distinct(4)=1, null(4)=0, distinct(5)=9.1, null(5)=0, distinct(6)=8.73626, null(6)=0.091, distinct(7)=9.1, null(7)=0, distinct(4,5)=9.1, null(4,5)=0]
 │         │    ├── key: (7)
 │         │    └── fd: ()-->(4), (7)-->(5,6)
 │         └── filters
 │              └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]
 └── filters
      ├── a:1 = '37685f26-4b07-40ba-9bbf-42916ed9bc61' [type=bool, outer=(1), constraints=(/1: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61' - /'37685f26-4b07-40ba-9bbf-42916ed9bc61']; tight), fd=()-->(1)]
      ├── b:2 [type=bool, outer=(2), constraints=(/2: [/true - /true]; tight), fd=()-->(2)]
      └── c:3 = 5 [type=bool, outer=(3), constraints=(/3: [/5 - /5]; tight), fd=()-->(3)]

# A different combination of predicates.
opt
SELECT * FROM multi_col
WHERE b = true
AND c = 5
AND e IN (1, 3, 5, 7, 9)
AND f > 0
----
select
 ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.21615, distinct(2)=0.21615, null(2)=0, distinct(3)=0.21615, null(3)=0, distinct(5)=0.21615, null(5)=0, distinct(6)=0.21615, null(6)=0, distinct(2,3)=0.21615, null(2,3)=0, distinct(5,6)=0.21615, null(5,6)=0, distinct(2,3,5,6)=0.21615, null(2,3,5,6)=0]
 ├── fd: ()-->(2,3)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=4.554054]
 │    ├── fd: ()-->(3)
 │    └── scan multi_col@ce_idx
 │         ├── columns: c:3(int!null) e:5(int!null) rowid:7(int!null)
 │         ├── constraint: /3/5/7
 │         │    ├── [/5/1 - /5/1]
 │         │    ├── [/5/3 - /5/3]
 │         │    ├── [/5/5 - /5/5]
 │         │    ├── [/5/7 - /5/7]
 │         │    └── [/5/9 - /5/9]
 │         ├── stats: [rows=4.554054, distinct(3)=1, null(3)=0, distinct(5)=4.55405, null(5)=0, distinct(3,5)=4.55405, null(3,5)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(3), (7)-->(5)
 └── filters
      ├── b:2 [type=bool, outer=(2), constraints=(/2: [/true - /true]; tight), fd=()-->(2)]
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

# Force the alternate index.
opt
SELECT * FROM multi_col@bef_idx
WHERE b = true
AND c = 5
AND e IN (1, 3, 5, 7, 9)
AND f > 0
----
select
 ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.21615, distinct(2)=0.21615, null(2)=0, distinct(3)=0.21615, null(3)=0, distinct(5)=0.21615, null(5)=0, distinct(6)=0.21615, null(6)=0, distinct(2,3)=0.21615, null(2,3)=0, distinct(5,6)=0.21615, null(5,6)=0, distinct(2,3,5,6)=0.21615, null(2,3,5,6)=0]
 ├── fd: ()-->(2,3)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=8.250001]
 │    ├── fd: ()-->(2)
 │    └── scan multi_col@bef_idx
 │         ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── constraint: /2/5/6/7
 │         │    ├── [/true/1/5e-324 - /true/1]
 │         │    ├── [/true/3/5e-324 - /true/3]
 │         │    ├── [/true/5/5e-324 - /true/5]
 │         │    ├── [/true/7/5e-324 - /true/7]
 │         │    └── [/true/9/5e-324 - /true/9]
 │         ├── flags: force-index=bef_idx
 │         ├── stats: [rows=8.250001, distinct(2)=1, null(2)=0, distinct(5)=5, null(5)=0, distinct(6)=8.25, null(6)=0, distinct(2,5,6)=8.25, null(2,5,6)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(2), (7)-->(5,6)
 └── filters
      └── c:3 = 5 [type=bool, outer=(3), constraints=(/3: [/5 - /5]; tight), fd=()-->(3)]

# Now inject some stats ane see how the estimates change.
exec-ddl
ALTER TABLE multi_col INJECT STATISTICS '[
  {
      "columns": [
          "a"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000,
      "avg_size": 1
  },
  {
      "columns": [
          "a",
          "b"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "a",
          "b",
          "c"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "a",
          "b",
          "c",
          "d"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "a",
          "b",
          "c",
          "d",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "c"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 100,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 1000,
      "row_count": 10000,
      "avg_size": 3
  },
  {
      "columns": [
          "c",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 1000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 100,
      "row_count": 10000
  },
  {
      "columns": [
          "b"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 3,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 5000,
      "row_count": 10000,
      "avg_size": 2
  },
  {
      "columns": [
          "b",
          "a",
          "d"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "b",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 200,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 1000,
      "row_count": 10000
  },
  {
      "columns": [
          "b",
          "e",
          "f"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 9000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 50,
      "row_count": 10000
  },
  {
      "columns": [
          "d"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000,
      "avg_size": 4
  },
  {
      "columns": [
          "d",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 200,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "d",
          "e",
          "f"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 100,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 1000,
      "row_count": 10000,
      "avg_size": 5
  },
  {
      "columns": [
          "f"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 5000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 100,
      "row_count": 10000,
      "avg_size": 6
  }
]'
----

opt
SELECT * FROM multi_col
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND c = 5
AND d = 'foo'
AND e > 10 AND e <= 20
AND f > 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=7.819546e-06, distinct(1)=7.81955e-06, null(1)=0, distinct(2)=7.81955e-06, null(2)=0, distinct(3)=7.81955e-06, null(3)=0, distinct(4)=7.81955e-06, null(4)=0, distinct(5)=7.81955e-06, null(5)=0, distinct(6)=7.81955e-06, null(6)=0, distinct(5,6)=7.81955e-06, null(5,6)=0, distinct(1-4)=7.81955e-06, null(1-4)=0, distinct(1-6)=7.81955e-06, null(1-6)=0]
 ├── fd: ()-->(1-4)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=2.166116e-05]
 │    ├── fd: ()-->(1-4)
 │    └── scan multi_col@abcde_idx
 │         ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) rowid:7(int!null)
 │         ├── constraint: /1/2/-3/4/5/7: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/true/5/'foo'/11 - /'37685f26-4b07-40ba-9bbf-42916ed9bc61'/true/5/'foo'/20]
 │         ├── stats: [rows=2.166116e-05, distinct(1)=2.16612e-05, null(1)=0, distinct(2)=2.16612e-05, null(2)=0, distinct(3)=2.16612e-05, null(3)=0, distinct(4)=2.16612e-05, null(4)=0, distinct(5)=2.16612e-05, null(5)=0, distinct(1-4)=2.16612e-05, null(1-4)=0, distinct(1-5)=2.16612e-05, null(1-5)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(1-4), (7)-->(5)
 └── filters
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

# A different combination of predicates.
opt
SELECT * FROM multi_col
WHERE b = true
AND c = 5
AND e IN (1, 3, 5, 7, 9)
AND f > 0
----
select
 ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.3409783, distinct(2)=0.340978, null(2)=0, distinct(3)=0.340978, null(3)=0, distinct(5)=0.340978, null(5)=0, distinct(6)=0.340978, null(6)=0, distinct(2,3)=0.340978, null(2,3)=0, distinct(5,6)=0.340978, null(5,6)=0, distinct(2,3,5,6)=0.340978, null(2,3,5,6)=0]
 ├── fd: ()-->(2,3)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=37.5075]
 │    ├── fd: ()-->(2)
 │    └── scan multi_col@bef_idx
 │         ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── constraint: /2/5/6/7
 │         │    ├── [/true/1/5e-324 - /true/1]
 │         │    ├── [/true/3/5e-324 - /true/3]
 │         │    ├── [/true/5/5e-324 - /true/5]
 │         │    ├── [/true/7/5e-324 - /true/7]
 │         │    └── [/true/9/5e-324 - /true/9]
 │         ├── stats: [rows=37.5075, distinct(2)=1, null(2)=0, distinct(5)=5, null(5)=0, distinct(6)=37.5075, null(6)=0, distinct(2,5,6)=37.5075, null(2,5,6)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(2), (7)-->(5,6)
 └── filters
      └── c:3 = 5 [type=bool, outer=(3), constraints=(/3: [/5 - /5]; tight), fd=()-->(3)]

# Force the alternate index.
opt
SELECT * FROM multi_col@bef_idx
WHERE b = true
AND c = 5
AND e IN (1, 3, 5, 7, 9)
AND f > 0
----
select
 ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.3409783, distinct(2)=0.340978, null(2)=0, distinct(3)=0.340978, null(3)=0, distinct(5)=0.340978, null(5)=0, distinct(6)=0.340978, null(6)=0, distinct(2,3)=0.340978, null(2,3)=0, distinct(5,6)=0.340978, null(5,6)=0, distinct(2,3,5,6)=0.340978, null(2,3,5,6)=0]
 ├── fd: ()-->(2,3)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=37.5075]
 │    ├── fd: ()-->(2)
 │    └── scan multi_col@bef_idx
 │         ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── constraint: /2/5/6/7
 │         │    ├── [/true/1/5e-324 - /true/1]
 │         │    ├── [/true/3/5e-324 - /true/3]
 │         │    ├── [/true/5/5e-324 - /true/5]
 │         │    ├── [/true/7/5e-324 - /true/7]
 │         │    └── [/true/9/5e-324 - /true/9]
 │         ├── flags: force-index=bef_idx
 │         ├── stats: [rows=37.5075, distinct(2)=1, null(2)=0, distinct(5)=5, null(5)=0, distinct(6)=37.5075, null(6)=0, distinct(2,5,6)=37.5075, null(2,5,6)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(2), (7)-->(5,6)
 └── filters
      └── c:3 = 5 [type=bool, outer=(3), constraints=(/3: [/5 - /5]; tight), fd=()-->(3)]

# Include histograms.
exec-ddl
ALTER TABLE multi_col INJECT STATISTICS '[
  {
      "columns": [
          "a"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000,
      "avg_size": 1
  },
  {
      "columns": [
          "a",
          "b"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "a",
          "b",
          "c"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "a",
          "b",
          "c",
          "d"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "a",
          "b",
          "c",
          "d",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "c"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 100,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 1000,
      "row_count": 10000,
      "avg_size": 3
  },
  {
      "columns": [
          "c",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 1000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 100,
      "row_count": 10000
  },
  {
      "columns": [
          "b"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 3,
      "histo_col_type": "BOOL",
      "histo_buckets":[{
        "num_eq":1,
        "num_range":0,
        "distinct_range":0,
        "upper_bound":"false"
      },
      {
        "num_eq":4999,
        "num_range":0,
        "distinct_range":0,
        "upper_bound":"true"
      }],
      "name": "__auto__",
      "null_count": 5000,
      "row_count": 10000,
      "avg_size": 2
  },
  {
      "columns": [
          "b",
          "a",
          "d"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "b",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 200,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 1000,
      "row_count": 10000
  },
  {
      "columns": [
          "b",
          "e",
          "f"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 9000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 50,
      "row_count": 10000
  },
  {
      "columns": [
          "d"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10,
      "avg_size": 4,
      "histo_col_type": "STRING",
      "histo_buckets":[{
        "num_eq":1,
        "num_range":0,
        "distinct_range":0,
        "upper_bound":"bar"
      },
      {
        "num_eq":1,
        "num_range":2,
        "distinct_range":2,
        "upper_bound":"baz"
      },
      {
        "num_eq":1,
        "num_range":1,
        "distinct_range":1,
        "upper_bound":"boo"
      },
      {
        "num_eq":9990,
        "num_range":2,
        "distinct_range":1,
        "upper_bound":"foo"
      },
      {
        "num_eq":1,
        "num_range":1,
        "distinct_range":1,
        "upper_bound":"foobar"
      }],
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "d",
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 200,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "d",
          "e",
          "f"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 10000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 0,
      "row_count": 10000
  },
  {
      "columns": [
          "e"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 100,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 1000,
      "row_count": 10000,
      "avg_size": 5
  },
  {
      "columns": [
          "f"
      ],
      "created_at": "2020-05-14 22:50:19.864085+00:00",
      "distinct_count": 5000,
      "histo_col_type": "",
      "name": "__auto__",
      "null_count": 100,
      "row_count": 10000,
      "avg_size": 6
  }
]'
----

opt
SELECT * FROM multi_col
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND c = 5
AND d = 'foo'
AND e > 10 AND e <= 20
AND f > 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.0001372273, distinct(1)=0.000137227, null(1)=0, distinct(2)=0.000137227, null(2)=0, distinct(3)=0.000137227, null(3)=0, distinct(4)=0.000137227, null(4)=0, distinct(5)=0.000137227, null(5)=0, distinct(6)=0.000137227, null(6)=0, distinct(5,6)=0.000137227, null(5,6)=0, distinct(1-4)=0.000137227, null(1-4)=0, distinct(1-6)=0.000137227, null(1-6)=0]
 │   histogram(2)=  0 0.00013723
 │                <----- true --
 │   histogram(4)=  0 0.00013723
 │                <---- 'foo' --
 ├── fd: ()-->(1-4)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=0.0004137274]
 │    ├── fd: ()-->(1-4)
 │    └── scan multi_col@abcde_idx
 │         ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int!null) d:4(string!null) e:5(int!null) rowid:7(int!null)
 │         ├── constraint: /1/2/-3/4/5/7: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/true/5/'foo'/11 - /'37685f26-4b07-40ba-9bbf-42916ed9bc61'/true/5/'foo'/20]
 │         ├── stats: [rows=0.0004137274, distinct(1)=0.000413727, null(1)=0, distinct(2)=0.000413727, null(2)=0, distinct(3)=0.000413727, null(3)=0, distinct(4)=0.000413727, null(4)=0, distinct(5)=0.000413727, null(5)=0, distinct(1-4)=0.000413727, null(1-4)=0, distinct(1-5)=0.000413727, null(1-5)=0]
 │         │   histogram(2)=  0 0.00041373
 │         │                <----- true --
 │         │   histogram(4)=  0 0.00041373
 │         │                <---- 'foo' --
 │         ├── key: (7)
 │         └── fd: ()-->(1-4), (7)-->(5)
 └── filters
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

# A different combination of predicates.
opt
SELECT * FROM multi_col
WHERE b = true
AND c = 5
AND e IN (1, 3, 5, 7, 9)
AND f > 0
----
select
 ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.6818192, distinct(2)=0.681819, null(2)=0, distinct(3)=0.681819, null(3)=0, distinct(5)=0.681819, null(5)=0, distinct(6)=0.681819, null(6)=0, distinct(2,3)=0.681819, null(2,3)=0, distinct(5,6)=0.681819, null(5,6)=0, distinct(2,3,5,6)=0.681819, null(2,3,5,6)=0]
 │   histogram(2)=  0 0.68182
 │                <--- true -
 ├── fd: ()-->(2,3)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=44.29647]
 │    ├── fd: ()-->(3)
 │    └── scan multi_col@ce_idx
 │         ├── columns: c:3(int!null) e:5(int!null) rowid:7(int!null)
 │         ├── constraint: /3/5/7
 │         │    ├── [/5/1 - /5/1]
 │         │    ├── [/5/3 - /5/3]
 │         │    ├── [/5/5 - /5/5]
 │         │    ├── [/5/7 - /5/7]
 │         │    └── [/5/9 - /5/9]
 │         ├── stats: [rows=44.29647, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(3,5)=5, null(3,5)=0]
 │         ├── key: (7)
 │         └── fd: ()-->(3), (7)-->(5)
 └── filters
      ├── b:2 [type=bool, outer=(2), constraints=(/2: [/true - /true]; tight), fd=()-->(2)]
      └── f:6 > 0.0 [type=bool, outer=(6), constraints=(/6: [/5e-324 - ]; tight)]

# Force the alternate index.
opt
SELECT * FROM multi_col@bef_idx
WHERE b = true
AND c = 5
AND e IN (1, 3, 5, 7, 9)
AND f > 0
----
select
 ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null)
 ├── stats: [rows=0.6818192, distinct(2)=0.681819, null(2)=0, distinct(3)=0.681819, null(3)=0, distinct(5)=0.681819, null(5)=0, distinct(6)=0.681819, null(6)=0, distinct(2,3)=0.681819, null(2,3)=0, distinct(5,6)=0.681819, null(5,6)=0, distinct(2,3,5,6)=0.681819, null(2,3,5,6)=0]
 │   histogram(2)=  0 0.68182
 │                <--- true -
 ├── fd: ()-->(2,3)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=75]
 │    ├── fd: ()-->(2)
 │    └── scan multi_col@bef_idx
 │         ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── constraint: /2/5/6/7
 │         │    ├── [/true/1/5e-324 - /true/1]
 │         │    ├── [/true/3/5e-324 - /true/3]
 │         │    ├── [/true/5/5e-324 - /true/5]
 │         │    ├── [/true/7/5e-324 - /true/7]
 │         │    └── [/true/9/5e-324 - /true/9]
 │         ├── flags: force-index=bef_idx
 │         ├── stats: [rows=75, distinct(2)=1, null(2)=0, distinct(5)=5, null(5)=0, distinct(6)=75, null(6)=0, distinct(2,5,6)=75, null(2,5,6)=0]
 │         │   histogram(2)=  0   75
 │         │                <--- true
 │         ├── key: (7)
 │         └── fd: ()-->(2), (7)-->(5,6)
 └── filters
      └── c:3 = 5 [type=bool, outer=(3), constraints=(/3: [/5 - /5]; tight), fd=()-->(3)]

# A different combination of predicates, with four different combinations of
# values for b and d.

opt
SELECT * FROM multi_col@bef_idx
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND d = 'foo'
AND e = 5
AND f = 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=2e-06, distinct(1)=2e-06, null(1)=0, distinct(2)=2e-06, null(2)=0, distinct(4)=2e-06, null(4)=0, distinct(5)=2e-06, null(5)=0, distinct(6)=2e-06, null(6)=0, distinct(1,2,4-6)=2e-06, null(1,2,4-6)=0]
 │   histogram(2)=  0 2e-06
 │                <--- true
 │   histogram(4)=  0  2e-06
 │                <--- 'foo'
 ├── fd: ()-->(1,2,4-6)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=0.1826204]
 │    ├── fd: ()-->(2,5,6)
 │    └── scan multi_col@bef_idx
 │         ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── constraint: /2/5/6/7: [/true/5/0.0 - /true/5/0.0]
 │         ├── flags: force-index=bef_idx
 │         ├── stats: [rows=0.1826204, distinct(2)=0.18262, null(2)=0, distinct(5)=0.18262, null(5)=0, distinct(6)=0.18262, null(6)=0, distinct(2,5,6)=0.18262, null(2,5,6)=0]
 │         │   histogram(2)=  0 0.18262
 │         │                <--- true -
 │         ├── key: (7)
 │         └── fd: ()-->(2,5,6)
 └── filters
      ├── a:1 = '37685f26-4b07-40ba-9bbf-42916ed9bc61' [type=bool, outer=(1), constraints=(/1: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61' - /'37685f26-4b07-40ba-9bbf-42916ed9bc61']; tight), fd=()-->(1)]
      └── d:4 = 'foo' [type=bool, outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)]

opt
SELECT * FROM multi_col
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = true
AND d = 'bar'
AND e = 5
AND f = 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=2e-06, distinct(1)=2e-06, null(1)=0, distinct(2)=2e-06, null(2)=0, distinct(4)=2e-06, null(4)=0, distinct(5)=2e-06, null(5)=0, distinct(6)=2e-06, null(6)=0, distinct(1,2,4-6)=2e-06, null(1,2,4-6)=0]
 │   histogram(2)=  0 2e-06
 │                <--- true
 │   histogram(4)=  0  2e-06
 │                <--- 'bar'
 ├── fd: ()-->(1,2,4-6)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=2.80036e-06]
 │    ├── fd: ()-->(4-6)
 │    └── scan multi_col@def_idx
 │         ├── columns: d:4(string!null) e:5(int!null) f:6(float!null) rowid:7(int!null)
 │         ├── constraint: /4/5/6/7: [/'bar'/5/0.0 - /'bar'/5/0.0]
 │         ├── stats: [rows=2.80036e-06, distinct(4)=2.80036e-06, null(4)=0, distinct(5)=2.80036e-06, null(5)=0, distinct(6)=2.80036e-06, null(6)=0, distinct(4-6)=2.80036e-06, null(4-6)=0]
 │         │   histogram(4)=  0 2.8004e-06
 │         │                <---- 'bar' --
 │         ├── key: (7)
 │         └── fd: ()-->(4-6)
 └── filters
      ├── a:1 = '37685f26-4b07-40ba-9bbf-42916ed9bc61' [type=bool, outer=(1), constraints=(/1: [/'37685f26-4b07-40ba-9bbf-42916ed9bc61' - /'37685f26-4b07-40ba-9bbf-42916ed9bc61']; tight), fd=()-->(1)]
      └── b:2 [type=bool, outer=(2), constraints=(/2: [/true - /true]; tight), fd=()-->(2)]

opt
SELECT * FROM multi_col
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = false
AND d = 'bar'
AND e = 5
AND f = 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=2e-06, distinct(1)=2e-06, null(1)=0, distinct(2)=2e-06, null(2)=0, distinct(4)=2e-06, null(4)=0, distinct(5)=2e-06, null(5)=0, distinct(6)=2e-06, null(6)=0, distinct(1,2,4-6)=2e-06, null(1,2,4-6)=0]
 │   histogram(2)=  0  2e-06
 │                <--- false
 │   histogram(4)=  0  2e-06
 │                <--- 'bar'
 ├── fd: ()-->(1,2,4-6)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=2e-06]
 │    ├── fd: ()-->(1,2,4)
 │    └── scan multi_col@bad_idx
 │         ├── columns: a:1(uuid!null) b:2(bool!null) d:4(string!null) rowid:7(int!null)
 │         ├── constraint: /2/-1/4/7: [/false/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'bar' - /false/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'bar']
 │         ├── stats: [rows=2e-06, distinct(1)=2e-06, null(1)=0, distinct(2)=2e-06, null(2)=0, distinct(4)=2e-06, null(4)=0, distinct(1,2,4)=2e-06, null(1,2,4)=0]
 │         │   histogram(2)=  0  2e-06
 │         │                <--- false
 │         │   histogram(4)=  0  2e-06
 │         │                <--- 'bar'
 │         ├── key: (7)
 │         └── fd: ()-->(1,2,4)
 └── filters
      ├── e:5 = 5 [type=bool, outer=(5), constraints=(/5: [/5 - /5]; tight), fd=()-->(5)]
      └── f:6 = 0.0 [type=bool, outer=(6), constraints=(/6: [/0.0 - /0.0]; tight), fd=()-->(6)]

opt
SELECT * FROM multi_col
WHERE a = '37685f26-4b07-40ba-9bbf-42916ed9bc61'
AND b = false
AND d = 'foo'
AND e = 5
AND f = 0
----
select
 ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null)
 ├── stats: [rows=2e-06, distinct(1)=2e-06, null(1)=0, distinct(2)=2e-06, null(2)=0, distinct(4)=2e-06, null(4)=0, distinct(5)=2e-06, null(5)=0, distinct(6)=2e-06, null(6)=0, distinct(1,2,4-6)=2e-06, null(1,2,4-6)=0]
 │   histogram(2)=  0  2e-06
 │                <--- false
 │   histogram(4)=  0  2e-06
 │                <--- 'foo'
 ├── fd: ()-->(1,2,4-6)
 ├── index-join multi_col
 │    ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float)
 │    ├── stats: [rows=0.0001009]
 │    ├── fd: ()-->(1,2,4)
 │    └── scan multi_col@bad_idx
 │         ├── columns: a:1(uuid!null) b:2(bool!null) d:4(string!null) rowid:7(int!null)
 │         ├── constraint: /2/-1/4/7: [/false/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'foo' - /false/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'foo']
 │         ├── stats: [rows=0.0001009, distinct(1)=0.0001009, null(1)=0, distinct(2)=0.0001009, null(2)=0, distinct(4)=0.0001009, null(4)=0, distinct(1,2,4)=0.0001009, null(1,2,4)=0]
 │         │   histogram(2)=  0 0.0001009
 │         │                <---- false -
 │         │   histogram(4)=  0 0.0001009
 │         │                <---- 'foo' -
 │         ├── key: (7)
 │         └── fd: ()-->(1,2,4)
 └── filters
      ├── e:5 = 5 [type=bool, outer=(5), constraints=(/5: [/5 - /5]; tight), fd=()-->(5)]
      └── f:6 = 0.0 [type=bool, outer=(6), constraints=(/6: [/0.0 - /0.0]; tight), fd=()-->(6)]

# Regression test for #50409.
exec-ddl
CREATE TABLE t (
  x int primary key,
  y int,
  z int,
  s string,
  index (y),
  index (s)
)
----

exec-ddl
ALTER TABLE t INJECT STATISTICS'[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 1000
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 1:30:00.00000+00:00",
    "row_count": 1000,
    "null_count": 500,
    "distinct_count": 500
  }
]'
----

# The row count estimate of the scan should be approximately 2, to account for
# the selectivity of the predicate on x. If the selectivity of x is ignored,
# the row count estimate rises to 501 (and the index join is no longer chosen).
opt disable=SplitDisjunction
SELECT * FROM t WHERE (y IS NULL AND x = 5) OR y = 5
----
index-join t
 ├── columns: x:1(int!null) y:2(int) z:3(int) s:4(string)
 ├── stats: [rows=167.0007, distinct(2)=2, null(2)=167.001]
 ├── key: (1)
 ├── fd: (1)-->(2-4)
 └── scan t@t_y_idx
      ├── columns: x:1(int!null) y:2(int)
      ├── constraint: /2/1
      │    ├── [/NULL/5 - /NULL/5]
      │    └── [/5 - /5]
      ├── stats: [rows=1.502004, distinct(1)=1.502, null(1)=0, distinct(2)=1.502, null(2)=1.502]
      ├── key: (1)
      └── fd: (1)-->(2)

opt
SELECT * FROM t WHERE (s >= 'a' AND s <= 'b') OR  (s >= 'c' AND s <= 'd') OR (s >= 'e' AND s <= 'f')
----
index-join t
 ├── columns: x:1(int!null) y:2(int) z:3(int) s:4(string!null)
 ├── stats: [rows=111.1111, distinct(4)=11.1111, null(4)=0]
 ├── key: (1)
 ├── fd: (1)-->(2-4)
 └── scan t@t_s_idx
      ├── columns: x:1(int!null) s:4(string!null)
      ├── constraint: /4/1
      │    ├── [/'a' - /'b']
      │    ├── [/'c' - /'d']
      │    └── [/'e' - /'f']
      ├── stats: [rows=111.1111, distinct(4)=11.1111, null(4)=0]
      ├── key: (1)
      └── fd: (1)-->(4)

# Regression test for #73106. Ensure we don't get the error "estimated row count
# must be non-zero".
exec-ddl
CREATE TABLE tab (
  geom GEOMETRY NOT NULL,
  INVERTED INDEX (geom ASC)
)
----

exec-ddl
ALTER TABLE tab INJECT STATISTICS '[
  {
    "columns": ["geom"],
    "created_at": "2000-01-01 00:00:00+00:00",
    "distinct_count": 7673676,
    "histo_buckets": [
      {
        "distinct_range": 0,
        "num_eq": 0,
        "num_range": 0,
        "upper_bound": "\\\\x42fdffffffffffffffff01c1f3f5e7590b574e41f15b57b0682314"
      }
    ],
    "histo_col_type": "BYTES",
    "name": "__auto__",
    "null_count": 0,
    "row_count": 20000000
  }
]'
----

opt
SELECT * FROM tab
WHERE st_coveredby(geom, 'POINT(1 1)':::GEOMETRY)
----
select
 ├── columns: geom:1(geometry!null)
 ├── immutable
 ├── stats: [rows=2222222, distinct(1)=2.22222e+06, null(1)=0]
 ├── index-join tab
 │    ├── columns: geom:1(geometry!null)
 │    ├── stats: [rows=1]
 │    └── inverted-filter
 │         ├── columns: rowid:2(int!null)
 │         ├── inverted expression: /5
 │         │    ├── tight: false, unique: false
 │         │    └── union spans
 │         │         ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"]
 │         │         ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00")
 │         │         └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"]
 │         ├── pre-filterer expression
 │         │    └── st_covers('0101000000000000000000F03F000000000000F03F', geom:1) [type=bool]
 │         ├── stats: [rows=1]
 │         ├── key: (2)
 │         └── scan tab@tab_geom_idx,inverted
 │              ├── columns: rowid:2(int!null) geom_inverted_key:5(encodedkey!null)
 │              ├── inverted constraint: /5/2
 │              │    └── spans
 │              │         ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"]
 │              │         ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00")
 │              │         └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"]
 │              └── stats: [rows=1, distinct(2)=1, null(2)=0, distinct(5)=1, null(5)=0]
 │                  histogram(5)=
 └── filters
      └── st_coveredby(geom:1, '0101000000000000000000F03F000000000000F03F') [type=bool, outer=(1), immutable, constraints=(/1: (/NULL - ])]

# Regression test for #76485. Ensure that we do not estimate 0 rows
# when filtering a histogram with a multi-column span.

exec-ddl
CREATE TABLE t76485 (
  a INT,
  b INT,
  c STRING,
  INDEX (a, c),
  INDEX (a, b, c)
)
----

exec-ddl
ALTER TABLE t76485 INJECT STATISTICS '[
    {
        "columns": [
            "a"
        ],
        "created_at": "2022-02-12 23:43:16.318153",
        "distinct_count": 10,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 0,
                "num_range": 0,
                "upper_bound": "10"
            },
            {
                "distinct_range": 9,
                "num_eq": 10000,
                "num_range": 9,
                "upper_bound": "20"
            }
        ],
        "histo_col_type": "INT8",
        "histo_version": 1,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 10009
    }
]'
----

opt
SELECT * FROM t76485 WHERE a = 20 AND b = 30 AND c < 'foo';
----
scan t76485@t76485_a_b_c_idx
 ├── columns: a:1(int!null) b:2(int!null) c:3(string!null)
 ├── constraint: /1/2/3/4: (/20/30/NULL - /20/30/'foo')
 ├── stats: [rows=3.270595, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=3.2706, null(3)=0, distinct(1,2)=1, null(1,2)=0, distinct(1-3)=3.2706, null(1-3)=0]
 │   histogram(1)=  0 3.2706
 │                <---- 20 -
 └── fd: ()-->(1,2)

exec-ddl
CREATE TABLE a_check (
  x INT8 PRIMARY KEY,
  y INT8,
  s STRING NOT NULL CHECK (s IN ('a', 'b', 'c', 'd')),
  d DECIMAL NOT NULL,
  b BOOL,
  UNIQUE (s DESC, d)
)
----

exec-ddl
ALTER TABLE a_check INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 2
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 3
  },
  {
    "columns": ["d"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 5
  },
  {
    "columns": ["b"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 1
  }
]'
----

build
SELECT * FROM a_check WHERE s >= 'a'
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=2000]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 └── select
      ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=2000, distinct(3)=4, null(3)=0]
      │   histogram(3)=  0  500  0  500  0  500  0  500
      │                <--- 'a' --- 'b' --- 'c' --- 'd'
      ├── key: (1)
      ├── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      ├── scan a_check
      │    ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── check constraint expressions
      │    │    └── s:3 IN ('a', 'b', 'c', 'd') [type=bool, outer=(3), constraints=(/3: [/'a' - /'a'] [/'b' - /'b'] [/'c' - /'c'] [/'d' - /'d']; tight)]
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(3)=4, null(3)=0, distinct(4)=2000, null(4)=0]
      │    │   histogram(3)=  0  500  0  500  0  500  0  500
      │    │                <--- 'a' --- 'b' --- 'c' --- 'd'
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      └── filters
           └── s:3 >= 'a' [type=bool, outer=(3), constraints=(/3: [/'a' - ]; tight)]

build
SELECT * FROM a_check WHERE s > 'a'
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=1500]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 └── select
      ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=1500, distinct(3)=3, null(3)=0]
      │   histogram(3)=  0  500  0  500  0  500
      │                <--- 'b' --- 'c' --- 'd'
      ├── key: (1)
      ├── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      ├── scan a_check
      │    ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── check constraint expressions
      │    │    └── s:3 IN ('a', 'b', 'c', 'd') [type=bool, outer=(3), constraints=(/3: [/'a' - /'a'] [/'b' - /'b'] [/'c' - /'c'] [/'d' - /'d']; tight)]
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(3)=4, null(3)=0, distinct(4)=2000, null(4)=0]
      │    │   histogram(3)=  0  500  0  500  0  500  0  500
      │    │                <--- 'a' --- 'b' --- 'c' --- 'd'
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      └── filters
           └── s:3 > 'a' [type=bool, outer=(3), constraints=(/3: [/e'a\x00' - ]; tight)]

build
SELECT * FROM a_check WHERE s < 'a'
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=4e-07]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 └── select
      ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=4e-07, distinct(3)=4e-07, null(3)=0]
      │   histogram(3)=
      ├── key: (1)
      ├── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      ├── scan a_check
      │    ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── check constraint expressions
      │    │    └── s:3 IN ('a', 'b', 'c', 'd') [type=bool, outer=(3), constraints=(/3: [/'a' - /'a'] [/'b' - /'b'] [/'c' - /'c'] [/'d' - /'d']; tight)]
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(3)=4, null(3)=0, distinct(4)=2000, null(4)=0]
      │    │   histogram(3)=  0  500  0  500  0  500  0  500
      │    │                <--- 'a' --- 'b' --- 'c' --- 'd'
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      └── filters
           └── s:3 < 'a' [type=bool, outer=(3), constraints=(/3: (/NULL - /'a'); tight)]

exec-ddl
ALTER TABLE a_check INJECT STATISTICS '[
  {
    "columns": ["s"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 10,
    "avg_size": 2
  }
]'
----

# After injecting stats on the check constraint column, the manufactured
# histogram seen in the output of the above test should be gone.
build
SELECT * FROM a_check WHERE s < 'a'
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=666.6667]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 └── select
      ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=666.6667, distinct(3)=3.33333, null(3)=0]
      ├── key: (1)
      ├── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      ├── scan a_check
      │    ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── check constraint expressions
      │    │    └── s:3 IN ('a', 'b', 'c', 'd') [type=bool, outer=(3), constraints=(/3: [/'a' - /'a'] [/'b' - /'b'] [/'c' - /'c'] [/'d' - /'d']; tight)]
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(3)=10, null(3)=0, distinct(4)=200, null(4)=0]
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      └── filters
           └── s:3 < 'a' [type=bool, outer=(3), constraints=(/3: (/NULL - /'a'); tight)]

exec-ddl
CREATE TABLE a_check2 (
  x INT8 PRIMARY KEY,
  y INT8,
  s STRING NOT NULL CHECK (s = 'a' OR s = 'b' OR s = 'c' OR s = 'd'),
  d DECIMAL NOT NULL,
  b BOOL,
  UNIQUE (s DESC, d)
)
----

exec-ddl
ALTER TABLE a_check2 INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 2
  },
  {
    "columns": ["y"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 3
  },
  {
    "columns": ["d"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 5
  },
  {
    "columns": ["b"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 1
  }
]'
----

# We should be able to generate stats from ORed check constraints, the same as
# from an IN expression.
build
SELECT * FROM a_check2 WHERE s > 'a'
----
project
 ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=1500]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (3,4)-->(1,2,5)
 └── select
      ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=1500, distinct(3)=3, null(3)=0]
      │   histogram(3)=  0  500  0  500  0  500
      │                <--- 'b' --- 'c' --- 'd'
      ├── key: (1)
      ├── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      ├── scan a_check2
      │    ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── check constraint expressions
      │    │    └── (((s:3 = 'a') OR (s:3 = 'b')) OR (s:3 = 'c')) OR (s:3 = 'd') [type=bool, outer=(3), constraints=(/3: [/'a' - /'a'] [/'b' - /'b'] [/'c' - /'c'] [/'d' - /'d']; tight)]
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(3)=4, null(3)=0, distinct(4)=2000, null(4)=0]
      │    │   histogram(3)=  0  500  0  500  0  500  0  500
      │    │                <--- 'a' --- 'b' --- 'c' --- 'd'
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (3,4)-->(1,2,5-7)
      └── filters
           └── s:3 > 'a' [type=bool, outer=(3), constraints=(/3: [/e'a\x00' - ]; tight)]

exec-ddl
CREATE TABLE a_check_int_IN_LIST (
  x INT8 PRIMARY KEY NOT NULL CHECK (x in (1,2,3,4,5,6,7,8,9,10)),
  y INT8 NOT NULL CHECK (y in (1,2,3,4)),
  s STRING NOT NULL,
  d DECIMAL NOT NULL,
  b BOOL,
  UNIQUE (y DESC, d)
)
----

exec-ddl
ALTER TABLE a_check_int_IN_LIST INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 2
  },
  {
    "columns": ["d"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 5
  },
  {
    "columns": ["b"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 2000,
    "distinct_count": 2000,
    "avg_size": 1
  }
]'
----

build
SELECT * FROM a_check_int_IN_LIST WHERE y >= 3
----
project
 ├── columns: x:1(int!null) y:2(int!null) s:3(string!null) d:4(decimal!null) b:5(bool)
 ├── stats: [rows=1000]
 ├── key: (1)
 ├── fd: (1)-->(2-5), (2,4)-->(1,3,5)
 └── select
      ├── columns: x:1(int!null) y:2(int!null) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── stats: [rows=1000, distinct(2)=2, null(2)=0]
      │   histogram(2)=  0 500 0 500
      │                <--- 3 --- 4
      ├── key: (1)
      ├── fd: (1)-->(2-7), (2,4)-->(1,3,5-7)
      ├── scan a_check_int_in_list
      │    ├── columns: x:1(int!null) y:2(int!null) s:3(string!null) d:4(decimal!null) b:5(bool) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── check constraint expressions
      │    │    ├── x:1 IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) [type=bool, outer=(1), constraints=(/1: [/1 - /1] [/2 - /2] [/3 - /3] [/4 - /4] [/5 - /5] [/6 - /6] [/7 - /7] [/8 - /8] [/9 - /9] [/10 - /10]; tight)]
      │    │    └── y:2 IN (1, 2, 3, 4) [type=bool, outer=(2), constraints=(/2: [/1 - /1] [/2 - /2] [/3 - /3] [/4 - /4]; tight)]
      │    ├── stats: [rows=2000, distinct(1)=2000, null(1)=0, distinct(2)=4, null(2)=0, distinct(3)=200, null(3)=0, distinct(4)=2000, null(4)=0]
      │    │   histogram(2)=  0 500 0 500 0 500 0 500
      │    │                <--- 1 --- 2 --- 3 --- 4
      │    ├── key: (1)
      │    └── fd: (1)-->(2-7), (2,4)-->(1,3,5-7)
      └── filters
           └── y:2 >= 3 [type=bool, outer=(2), constraints=(/2: [/3 - ]; tight)]

exec-ddl
CREATE TABLE a_check_hash (
  i INT,
  crdb_internal_a_shard_8 INT4 NOT VISIBLE NOT NULL CHECK (crdb_internal_a_shard_8 IN (0,1,2,3,4,5,6,7))
                               AS (mod(fnv32(crdb_internal.datums_to_bytes(i)), 8:::INT8)) VIRTUAL,
  j int,
  PRIMARY KEY(crdb_internal_a_shard_8, i))
----

exec-ddl
ALTER TABLE a_check_hash INJECT STATISTICS '[
  {
    "columns": ["i"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 100,
    "avg_size": 2
  }
]'
----

build
SELECT * FROM a_check_hash WHERE crdb_internal_a_shard_8 > 6
----
project
 ├── columns: i:1(int!null) j:3(int)
 ├── stats: [rows=125]
 ├── key: (1)
 ├── fd: (1)-->(3)
 └── select
      ├── columns: i:1(int!null) crdb_internal_a_shard_8:2(int4!null) j:3(int) crdb_internal_mvcc_timestamp:4(decimal) tableoid:5(oid)
      ├── stats: [rows=125, distinct(2)=1, null(2)=0]
      │   histogram(2)=  0 125
      │                <--- 7
      ├── key: (1)
      ├── fd: (1,2)-->(3-5), (1)-->(2)
      ├── scan a_check_hash
      │    ├── columns: i:1(int!null) crdb_internal_a_shard_8:2(int4!null) j:3(int) crdb_internal_mvcc_timestamp:4(decimal) tableoid:5(oid)
      │    ├── check constraint expressions
      │    │    └── crdb_internal_a_shard_8:2 IN (0, 1, 2, 3, 4, 5, 6, 7) [type=bool, outer=(2), constraints=(/2: [/0 - /0] [/1 - /1] [/2 - /2] [/3 - /3] [/4 - /4] [/5 - /5] [/6 - /6] [/7 - /7]; tight)]
      │    ├── computed column expressions
      │    │    └── crdb_internal_a_shard_8:2
      │    │         └── assignment-cast: INT4 [type=int4]
      │    │              └── mod(fnv32(crdb_internal.datums_to_bytes(i:1)), 8) [type=int]
      │    ├── stats: [rows=1000, distinct(1)=100, null(1)=0, distinct(2)=8, null(2)=0]
      │    │   histogram(2)=  0 125 0 125 0 125 0 125 0 125 0 125 0 125 0 125
      │    │                <--- 0 --- 1 --- 2 --- 3 --- 4 --- 5 --- 6 --- 7
      │    ├── key: (1)
      │    └── fd: (1,2)-->(3-5), (1)-->(2)
      └── filters
           └── crdb_internal_a_shard_8:2 > 6 [type=bool, outer=(2), constraints=(/2: [/7 - ]; tight)]

exec-ddl
DROP TABLE abcde
----

# Regression test for #67966. Ensure that histograms and multi-column stats
# are combined so as to choose the correct index.
exec-ddl
CREATE TABLE abcde (
	start_time TIMESTAMPTZ NOT NULL DEFAULT now():::TIMESTAMPTZ,
	a INT8 NULL,
	b INT8 NOT NULL,
	c INT2 NOT NULL,
	d DECIMAL(1) NOT NULL,
	e INT4 NOT NULL,
	id UUID NOT NULL DEFAULT gen_random_uuid(),
	CONSTRAINT "primary" PRIMARY KEY (e ASC, id ASC),
	INDEX abcde_e_b_d_idx (e ASC, b ASC, d ASC),
	INDEX abcde_e_c_b_d_a_start_time (e ASC, c ASC, b ASC, d ASC, a ASC, start_time ASC)
)
----

exec-ddl
ALTER TABLE abcde INJECT STATISTICS '[
    {
        "columns": [
            "e"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 2,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 8473077,
                "num_range": 0,
                "upper_bound": "3"
            },
            {
                "distinct_range": 0,
                "num_eq": 1798,
                "num_range": 0,
                "upper_bound": "5"
            }
        ],
        "histo_col_type": "INT4",
        "histo_version": 1,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "id"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 8474875,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "id"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 8466498,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "start_time"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7822288,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 2000,
                "num_range": 0,
                "upper_bound": "2001-05-15 00:55:32.317+00:00"
            },
            {
                "distinct_range": 7782286,
                "num_eq": 2000,
                "num_range": 8428875,
                "upper_bound": "2021-12-04 09:24:00.692+00:00"
            },
            {
                "distinct_range": 40000,
                "num_eq": 2000,
                "num_range": 40000,
                "upper_bound": "2022-02-12 10:29:50.632+00:00"
            }
        ],
        "histo_col_type": "TIMESTAMPTZ",
        "histo_version": 1,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "start_time"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7643961,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "b"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 127991,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 2000,
                "num_range": 0,
                "upper_bound": "10"
            },
            {
                "distinct_range": 127989,
                "num_eq": 2000,
                "num_range": 8470875,
                "upper_bound": "10000000"
            }
        ],
        "histo_col_type": "INT8",
        "histo_version": 1,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "b"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 127003,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "d"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 9,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 1000000,
                "num_range": 0,
                "upper_bound": "1"
            },
            {
                "distinct_range": 8,
                "num_eq": 1000000,
                "num_range": 6474875,
                "upper_bound": "9"
            }
        ],
        "histo_col_type": "DECIMAL(1)",
        "histo_version": 1,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "b",
            "d"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 127240,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "a"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 52092,
        "name": "__auto__",
        "null_count": 8010611,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "d"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 19,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "c"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 4,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 2292693,
                "num_range": 0,
                "upper_bound": "2"
            },
            {
                "distinct_range": 0.6666666666666666,
                "num_eq": 129470,
                "num_range": 1,
                "upper_bound": "4"
            },
            {
                "distinct_range": 0.3333333333333333,
                "num_eq": 6052711,
                "num_range": 0,
                "upper_bound": "6"
            }
        ],
        "histo_col_type": "INT2",
        "histo_version": 1,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "c"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 8,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "c",
            "start_time"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7721692,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "start_time",
            "b"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7633757,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "start_time",
            "b",
            "d"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7729900,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "c",
            "b"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 236874,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "c",
            "b",
            "d"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 236072,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "c",
            "b",
            "d",
            "a"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 285557,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "c",
            "b",
            "d",
            "a",
            "start_time"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7762600,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "b",
            "d",
            "c",
            "start_time"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 7765002,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    },
    {
        "columns": [
            "e",
            "a"
        ],
        "created_at": "2022-02-16 21:43:36.877981",
        "distinct_count": 51682,
        "name": "__auto__",
        "null_count": 0,
        "row_count": 8474875
    }
]';
----

opt
SELECT
  *
FROM
  abcde
WHERE
  b = 10
  AND d = 1
  AND c IN (6, 4)
  AND a IS NULL
  AND e IN (1, 2, 3, 4, 5, 6, 6, 7, 8)
  AND start_time BETWEEN '2022-02-04 19:25:25.356+00:00' AND '2022-02-11 19:25:25.356+00:00'
ORDER BY
  start_time DESC
LIMIT
  1000
----
top-k
 ├── columns: start_time:1(timestamptz!null) a:2(int) b:3(int!null) c:4(int2!null) d:5(decimal!null) e:6(int4!null) id:7(uuid!null)
 ├── internal-ordering: -1 opt(2,3,5)
 ├── k: 1000
 ├── cardinality: [0 - 1000]
 ├── immutable
 ├── stats: [rows=0.07759788]
 ├── key: (6,7)
 ├── fd: ()-->(2,3,5), (6,7)-->(1,4)
 ├── ordering: -1 opt(2,3,5) [actual: -1]
 └── scan abcde@abcde_e_c_b_d_a_start_time
      ├── columns: start_time:1(timestamptz!null) a:2(int) b:3(int!null) c:4(int2!null) d:5(decimal!null) e:6(int4!null) id:7(uuid!null)
      ├── constraint: /6/4/3/5/2/1/7
      │    ├── [/1/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /1/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/1/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /1/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/2/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /2/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/2/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /2/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/3/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /3/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/3/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /3/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/4/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /4/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/4/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /4/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/5/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /5/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/5/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /5/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/6/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /6/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/6/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /6/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/7/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /7/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/7/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /7/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    ├── [/8/4/10/1/NULL/'2022-02-04 19:25:25.356+00' - /8/4/10/1/NULL/'2022-02-11 19:25:25.356+00']
      │    └── [/8/6/10/1/NULL/'2022-02-04 19:25:25.356+00' - /8/6/10/1/NULL/'2022-02-11 19:25:25.356+00']
      ├── immutable
      ├── stats: [rows=0.07759788, distinct(1)=0.0775979, null(1)=0, distinct(2)=0.0775979, null(2)=0.0775979, distinct(3)=0.0775979, null(3)=0, distinct(4)=0.0775979, null(4)=0, distinct(5)=0.0775979, null(5)=0, distinct(6)=0.0775979, null(6)=0, distinct(1,4)=0.0775979, null(1,4)=0, distinct(2,3,5)=0.0775979, null(2,3,5)=0, distinct(1-5)=0.0775979, null(1-5)=0]
      │   histogram(1)=  0                 0                 0.077598           1.283e-16
      │                <--- '2022-02-04 19:25:25.355999+00' ---------- '2022-02-11 19:25:25.356+00'
      │   histogram(3)=  0 0.077598
      │                <----- 10 --
      │   histogram(4)=  0 0.0016251 0 0.075973
      │                <------ 4 -------- 6 ---
      │   histogram(5)=  0 0.077598
      │                <----- 1 ---
      │   histogram(6)=  0 0.077581 0 1.6463e-05
      │                <----- 3 --------- 5 ----
      ├── key: (6,7)
      └── fd: ()-->(2,3,5), (6,7)-->(1,4)

# Test that a statistic with a histogram followed in time by a statistic
# without a histogram does not cause the optimizer to use the old statistic
# incorrectly just because it has a histogram.

exec-ddl
CREATE TABLE trunc (x INT PRIMARY KEY)
----

exec-ddl
ALTER TABLE trunc INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 1000,
    "distinct_count": 40,
    "avg_size": 2,
    "histo_col_type": "int",
    "histo_buckets": [
      {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "0"},
      {"num_eq": 10, "num_range": 90, "distinct_range": 9, "upper_bound": "10"},
      {"num_eq": 20, "num_range": 180, "distinct_range": 9, "upper_bound": "20"},
      {"num_eq": 30, "num_range": 270, "distinct_range": 9, "upper_bound": "30"},
      {"num_eq": 40, "num_range": 360, "distinct_range": 9, "upper_bound": "40"}
    ]
  },
  {
    "columns": ["x"],
    "created_at": "2018-01-01 2:00:00.00000+00:00",
    "row_count": 0,
    "distinct_count": 0,
    "avg_size": 0
  }
]'
----

# The following explain should have no histogram in it.
build
SELECT * FROM trunc WHERE x < 10
----
project
 ├── columns: x:1(int!null)
 ├── stats: [rows=1]
 ├── key: (1)
 └── select
      ├── columns: x:1(int!null) crdb_internal_mvcc_timestamp:2(decimal) tableoid:3(oid)
      ├── stats: [rows=1, distinct(1)=1, null(1)=0]
      ├── key: (1)
      ├── fd: (1)-->(2,3)
      ├── scan trunc
      │    ├── columns: x:1(int!null) crdb_internal_mvcc_timestamp:2(decimal) tableoid:3(oid)
      │    ├── stats: [rows=1, distinct(1)=1, null(1)=0]
      │    ├── key: (1)
      │    └── fd: (1)-->(2,3)
      └── filters
           └── x:1 < 10 [type=bool, outer=(1), constraints=(/1: (/NULL - /9]; tight)]

# Tests for when stats are stale.

exec-ddl
CREATE TABLE stale (
  w STRING PRIMARY KEY,
  x STRING,
  y STRING,
  z STRING,
  UNIQUE (x, y),
  INDEX (x, z)
)
----

exec-ddl
ALTER TABLE stale INJECT STATISTICS '[
    {
        "avg_size": 7,
        "columns": [
            "x"
        ],
        "created_at": "2023-03-08 01:51:41.258198",
        "distinct_count": 10,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo1"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo10"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo2"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo3"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo4"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo5"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo6"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo7"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo8"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "foo9"
            }
        ],
        "histo_col_type": "STRING",
        "histo_version": 2,
        "null_count": 0,
        "row_count": 110
    },
    {
        "avg_size": 16,
        "columns": [
            "x",
            "y"
        ],
        "created_at": "2023-03-08 01:51:41.258198",
        "distinct_count": 110,
        "histo_col_type": "",
        "null_count": 0,
        "row_count": 110
    },
    {
        "avg_size": 13,
        "columns": [
            "x",
            "z"
        ],
        "created_at": "2023-03-08 01:51:41.258198",
        "distinct_count": 10,
        "histo_col_type": "",
        "null_count": 0,
        "row_count": 110
    },
    {
        "avg_size": 9,
        "columns": [
            "y"
        ],
        "created_at": "2023-03-08 01:51:41.258198",
        "distinct_count": 11,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1000"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1001"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1002"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1003"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1004"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1005"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1006"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1007"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1008"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1009"
            },
            {
                "distinct_range": 0,
                "num_eq": 10,
                "num_range": 0,
                "upper_bound": "bar1010"
            }
        ],
        "histo_col_type": "STRING",
        "histo_version": 2,
        "null_count": 0,
        "row_count": 110
    },
    {
        "avg_size": 7,
        "columns": [
            "z"
        ],
        "created_at": "2023-03-08 01:51:41.258198",
        "distinct_count": 10,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz1"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz10"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz2"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz3"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz4"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz5"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz6"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz7"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz8"
            },
            {
                "distinct_range": 0,
                "num_eq": 11,
                "num_range": 0,
                "upper_bound": "baz9"
            }
        ],
        "histo_col_type": "STRING",
        "histo_version": 2,
        "null_count": 0,
        "row_count": 110
    }
]'
----

# When optimizer_always_use_histograms is disabled, we may choose the non-unique
# index.
opt set=optimizer_always_use_histograms=false
SELECT * FROM stale WHERE x = 'bar1' AND (y = 'bar1000' OR y = 'bar1001') LIMIT 1
----
limit
 ├── columns: w:1(string!null) x:2(string!null) y:3(string!null) z:4(string)
 ├── cardinality: [0 - 1]
 ├── stats: [rows=1]
 ├── key: ()
 ├── fd: ()-->(1-4)
 ├── select
 │    ├── columns: w:1(string!null) x:2(string!null) y:3(string!null) z:4(string)
 │    ├── cardinality: [0 - 2]
 │    ├── stats: [rows=2, distinct(2)=1, null(2)=0, distinct(3)=2, null(3)=0, distinct(2,3)=2, null(2,3)=0]
 │    ├── key: (1)
 │    ├── fd: ()-->(2), (1)-->(3,4), (3)-->(1,4)
 │    ├── limit hint: 1.00
 │    ├── index-join stale
 │    │    ├── columns: w:1(string!null) x:2(string) y:3(string) z:4(string)
 │    │    ├── stats: [rows=2.2e-08]
 │    │    ├── key: (1)
 │    │    ├── fd: ()-->(2), (1)-->(3,4), (2,3)~~>(1,4)
 │    │    ├── limit hint: 0.00
 │    │    └── scan stale@stale_x_z_idx
 │    │         ├── columns: w:1(string!null) x:2(string!null) z:4(string)
 │    │         ├── constraint: /2/4/1: [/'bar1' - /'bar1']
 │    │         ├── stats: [rows=2.2e-08, distinct(2)=2.2e-08, null(2)=0]
 │    │         │   histogram(2)=
 │    │         ├── key: (1)
 │    │         ├── fd: ()-->(2), (1)-->(4)
 │    │         └── limit hint: 0.00
 │    └── filters
 │         └── (y:3 = 'bar1000') OR (y:3 = 'bar1001') [type=bool, outer=(3), constraints=(/3: [/'bar1000' - /'bar1000'] [/'bar1001' - /'bar1001']; tight)]
 └── 1 [type=int]

# When optimizer_always_use_histograms is enabled, we should choose the unique
# index.
opt set=optimizer_always_use_histograms=true
SELECT * FROM stale WHERE x = 'bar1' AND (y = 'bar1000' OR y = 'bar1001') LIMIT 1
----
index-join stale
 ├── columns: w:1(string!null) x:2(string!null) y:3(string!null) z:4(string)
 ├── cardinality: [0 - 1]
 ├── stats: [rows=2.2e-08]
 ├── key: ()
 ├── fd: ()-->(1-4)
 └── scan stale@stale_x_y_key
      ├── columns: w:1(string!null) x:2(string!null) y:3(string!null)
      ├── constraint: /2/3
      │    ├── [/'bar1'/'bar1000' - /'bar1'/'bar1000']
      │    └── [/'bar1'/'bar1001' - /'bar1'/'bar1001']
      ├── limit: 1
      ├── stats: [rows=2.2e-08]
      ├── key: ()
      └── fd: ()-->(1-3)
