# LogicTest: local-opt

statement ok
CREATE TABLE t(x INT PRIMARY KEY)

statement ok
CREATE TABLE t2(x INT PRIMARY KEY)

# Check that if a mutation uses further processing, a spool is added.
query TTT
EXPLAIN WITH a AS (INSERT INTO t SELECT * FROM t2 RETURNING x)
        SELECT * FROM a LIMIT 1
----
limit                     ·         ·
 │                        count     1
 └── spool                ·         ·
      │                   limit     1
      └── run             ·         ·
           └── insert     ·         ·
                │         into      t(x)
                │         strategy  inserter
                └── scan  ·         ·
·                         table     t2@primary
·                         spans     ALL

query TTT
EXPLAIN WITH a AS (DELETE FROM t RETURNING x)
        SELECT * FROM a LIMIT 1
----
limit                     ·         ·
 │                        count     1
 └── spool                ·         ·
      │                   limit     1
      └── run             ·         ·
           └── delete     ·         ·
                │         from      t
                │         strategy  deleter
                └── scan  ·         ·
·                         table     t@primary
·                         spans     ALL


query TTT
EXPLAIN WITH a AS (UPDATE t SET x = x + 1 RETURNING x)
        SELECT * FROM a LIMIT 1
----
limit                          ·         ·
 │                             count     1
 └── spool                     ·         ·
      │                        limit     1
      └── run                  ·         ·
           └── update          ·         ·
                │              table     t
                │              set       x
                │              strategy  updater
                └── render     ·         ·
                     └── scan  ·         ·
·                              table     t@primary
·                              spans     ALL

query TTT
EXPLAIN WITH a AS (UPSERT INTO t VALUES (2), (3) RETURNING x)
        SELECT * FROM a LIMIT 1
----
limit                       ·         ·
 │                          count     1
 └── spool                  ·         ·
      │                     limit     1
      └── run               ·         ·
           └── upsert       ·         ·
                │           into      t(x)
                │           strategy  opt upserter
                └── values  ·         ·
·                           size      1 column, 2 rows

# Ditto all mutations, with the statement source syntax.
query TTT
EXPLAIN SELECT * FROM [INSERT INTO t SELECT * FROM t2 RETURNING x] LIMIT 1
----
limit                     ·         ·
 │                        count     1
 └── spool                ·         ·
      │                   limit     1
      └── run             ·         ·
           └── insert     ·         ·
                │         into      t(x)
                │         strategy  inserter
                └── scan  ·         ·
·                         table     t2@primary
·                         spans     ALL

query TTT
EXPLAIN SELECT * FROM [DELETE FROM t RETURNING x] LIMIT 1
----
limit                     ·         ·
 │                        count     1
 └── spool                ·         ·
      │                   limit     1
      └── run             ·         ·
           └── delete     ·         ·
                │         from      t
                │         strategy  deleter
                └── scan  ·         ·
·                         table     t@primary
·                         spans     ALL

query TTT
EXPLAIN SELECT * FROM [UPDATE t SET x = x + 1 RETURNING x] LIMIT 1
----
limit                          ·         ·
 │                             count     1
 └── spool                     ·         ·
      │                        limit     1
      └── run                  ·         ·
           └── update          ·         ·
                │              table     t
                │              set       x
                │              strategy  updater
                └── render     ·         ·
                     └── scan  ·         ·
·                              table     t@primary
·                              spans     ALL

query TTT
EXPLAIN SELECT * FROM [UPSERT INTO t VALUES (2), (3) RETURNING x] LIMIT 1
----
limit                       ·         ·
 │                          count     1
 └── spool                  ·         ·
      │                     limit     1
      └── run               ·         ·
           └── upsert       ·         ·
                │           into      t(x)
                │           strategy  opt upserter
                └── values  ·         ·
·                           size      1 column, 2 rows

# Check that a spool is also inserted for other processings than LIMIT.
query TTT
EXPLAIN SELECT count(*) FROM [INSERT INTO t SELECT * FROM t2 RETURNING x]
----
group                          ·            ·
 │                             aggregate 0  count_rows()
 │                             scalar       ·
 └── spool                     ·            ·
      └── render               ·            ·
           └── run             ·            ·
                └── insert     ·            ·
                     │         into         t(x)
                     │         strategy     inserter
                     └── scan  ·            ·
·                              table        t2@primary
·                              spans        ALL

query TTT
EXPLAIN SELECT * FROM [INSERT INTO t SELECT * FROM t2 RETURNING x], t
----
hash-join                 ·         ·
 │                        type      cross
 ├── spool                ·         ·
 │    └── run             ·         ·
 │         └── insert     ·         ·
 │              │         into      t(x)
 │              │         strategy  inserter
 │              └── scan  ·         ·
 │                        table     t2@primary
 │                        spans     ALL
 └── scan                 ·         ·
·                         table     t@primary
·                         spans     ALL

# Check that if a spool is already added at some level, then it is not added
# again at levels below.
# TODO(andyk): This optimization is not part of CBO yet.
query TTT
EXPLAIN WITH a AS (INSERT INTO t SELECT * FROM t2 RETURNING x),
             b AS (INSERT INTO t SELECT x+1 FROM a RETURNING x)
        SELECT * FROM b LIMIT 1
----
limit                                         ·         ·
 │                                            count     1
 └── spool                                    ·         ·
      │                                       limit     1
      └── run                                 ·         ·
           └── insert                         ·         ·
                │                             into      t(x)
                │                             strategy  inserter
                └── spool                     ·         ·
                     └── render               ·         ·
                          └── run             ·         ·
                               └── insert     ·         ·
                                    │         into      t(x)
                                    │         strategy  inserter
                                    └── scan  ·         ·
·                                             table     t2@primary
·                                             spans     ALL

# Check that no spool is inserted if a top-level render is elided.
query TTT
EXPLAIN SELECT * FROM [INSERT INTO t SELECT * FROM t2 RETURNING x]
----
run             ·         ·
 └── insert     ·         ·
      │         into      t(x)
      │         strategy  inserter
      └── scan  ·         ·
·               table     t2@primary
·               spans     ALL

# Check that no spool is used for a top-level INSERT, but
# sub-INSERTs still get a spool.
query TTT
EXPLAIN INSERT INTO t SELECT x+1 FROM [INSERT INTO t SELECT * FROM t2 RETURNING x]
----
count                               ·         ·
 └── insert                         ·         ·
      │                             into      t(x)
      │                             strategy  inserter
      └── spool                     ·         ·
           └── render               ·         ·
                └── run             ·         ·
                     └── insert     ·         ·
                          │         into      t(x)
                          │         strategy  inserter
                          └── scan  ·         ·
·                                   table     t2@primary
·                                   spans     ALL

# Check that simple computations using RETURNING get their spool pulled up.
query TTT
EXPLAIN SELECT * FROM [INSERT INTO t SELECT * FROM t2 RETURNING x+10] WHERE @1 < 3 LIMIT 10
----
render                              ·         ·
 └── limit                          ·         ·
      │                             count     10
      └── spool                     ·         ·
           │                        limit     10
           └── filter               ·         ·
                │                   filter    x < -7
                └── run             ·         ·
                     └── insert     ·         ·
                          │         into      t(x)
                          │         strategy  inserter
                          └── scan  ·         ·
·                                   table     t2@primary
·                                   spans     ALL

# Check that a pulled up spool gets elided at the top level.
query TTT
EXPLAIN SELECT * FROM [INSERT INTO t SELECT * FROM t2 RETURNING x+10] WHERE @1 < 3
----
render                    ·         ·
 └── filter               ·         ·
      │                   filter    x < -7
      └── run             ·         ·
           └── insert     ·         ·
                │         into      t(x)
                │         strategy  inserter
                └── scan  ·         ·
·                         table     t2@primary
·                         spans     ALL
