statement ok
CREATE TABLE x(a) AS SELECT generate_series(1, 3)

statement ok
CREATE TABLE y(a) AS SELECT generate_series(2, 4)

query I rowsort
WITH t AS (SELECT a FROM y WHERE a < 3)
  SELECT * FROM x NATURAL JOIN t
----
2

query I
WITH t AS (SELECT * FROM y WHERE a < 3)
  SELECT * FROM x NATURAL JOIN t
----
2

# Using a CTE inside a subquery
query I rowsort
WITH t(x) AS (SELECT a FROM x)
  SELECT * FROM y WHERE a IN (SELECT x FROM t)
----
2
3

# Using a subquery inside a CTE
query I
SELECT * FROM x WHERE a IN
  (WITH t AS (SELECT * FROM y WHERE a < 3) SELECT * FROM t)
----
2

# Rename columns
query II rowsort
WITH t(b) AS (SELECT a FROM x) SELECT b, t.b FROM t
----
1 1
2 2
3 3

query BB
WITH t(a, b) AS (SELECT true a, false b)
  SELECT a, b FROM t
----
true  false

query BB
WITH t(b, a) AS (SELECT true a, false b)
  SELECT a, b FROM t
----
false  true

statement error WITH clause containing a data-modifying statement must be at the top level
SELECT (WITH foo AS (INSERT INTO y VALUES (1) RETURNING *) SELECT * FROM foo)

statement error WITH query name t specified more than once
WITH
    t AS (SELECT true),
    t AS (SELECT false)
SELECT * FROM t

query error source "t" has 1 columns available but 2 columns specified
WITH t(b, c) AS (SELECT a FROM x) SELECT b, t.b FROM t

# Ensure you can't reference the original table name
query error no data source matches prefix: x
WITH t AS (SELECT a FROM x) SELECT a, x.t FROM t

# Nested WITH, name shadowing
query I
WITH t(x) AS (WITH t(x) AS (SELECT 1) SELECT x * 10 FROM t) SELECT x + 2 FROM t
----
12

# CTEs with DMLs

query error pgcode 42P01 relation "t" does not exist
WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)

query I rowsort
WITH t AS (SELECT a FROM x) INSERT INTO x SELECT a + 20 FROM t RETURNING *
----
21
22
23

query I rowsort
SELECT * from x
----
1
2
3
21
22
23

query I rowsort
WITH t AS (
    UPDATE x SET a = a * 100 RETURNING a
)
SELECT * FROM t
----
100
200
300
2100
2200
2300

query I rowsort
SELECT * from x
----
100
200
300
2100
2200
2300

query I rowsort
WITH t AS (
    DELETE FROM x RETURNING a
)
SELECT * FROM t
----
100
200
300
2100
2200
2300

query I rowsort
SELECT * from x
----

# #22420: ensure okay error message for CTE clause without output columns
query error WITH clause "t" does not return any columns
WITH t AS (
    INSERT INTO x(a) VALUES(0)
)
SELECT * FROM t

# however if there are no side effects, no errors are required.
query I
WITH t AS (SELECT 1) SELECT 2
----
2

# Regression tests for #24303.

statement ok
CREATE TABLE a(x INT);

statement count 3
INSERT INTO a(x)
        (WITH b(z) AS (VALUES (1),(2),(3)) SELECT z+1 AS w FROM b)

statement count 1
INSERT INTO a(x)
      (WITH a(z) AS (VALUES (1)) SELECT z+1 AS w FROM a);

# When #24303 is fixed, the following query should succeed.
query error unimplemented: multiple WITH clauses in parentheses
(WITH woo AS (VALUES (1))
    (WITH waa AS (VALUES (2))
	   TABLE waa))


# When #24303 is fixed, the following query should fail with
# error "no such relation woo".
query error unimplemented: multiple WITH clauses in parentheses
(WITH woo AS (VALUES (1))
    (WITH waa AS (VALUES (2))
	   TABLE woo))

statement ok
CREATE TABLE lim(x) AS SELECT 0

# This is an oddity in PostgreSQL: even though the WITH clause
# occurs in the inside parentheses, the scope of the alias `lim`
# extends to the outer parentheses.
query I
((WITH lim(x) AS (SELECT 1) SELECT 123)
 LIMIT (
    SELECT x FROM lim -- intuitively this should refer to the real table lim defined above
                      -- and use LIMIT 0;
                      -- however, postgres flattens the inner WITH and outer LIMIT
                      -- at the same scope so the limit becomes 1.
 ))
----
123

# Ditto if table `lim` did not even exist.
statement ok
DROP TABLE lim

query I
((WITH lim(x) AS (SELECT 1) SELECT 123) LIMIT (SELECT x FROM lim))
----
123

# CTE with an ORDER BY.

statement ok
CREATE TABLE ab (a INT PRIMARY KEY, b INT)

statement ok
INSERT INTO ab VALUES (1, 2), (3, 4), (5, 6)

query I rowsort
WITH a AS (SELECT a FROM ab ORDER BY b) SELECT * FROM a
----
1
3
5

statement ok
CREATE TABLE x2(a) AS SELECT generate_series(1, 3)

statement ok
CREATE TABLE y2(b) AS SELECT generate_series(2, 4)

# Referencing a CTE multiple times.
query II rowsort
WITH t AS (SELECT b FROM y2) SELECT * FROM t JOIN t AS q ON true
----
2  2
2  3
2  4
3  2
3  3
3  4
4  2
4  3
4  4

query II rowsort
WITH
    one AS (SELECT a AS u FROM x2),
    two AS (SELECT b AS v FROM (SELECT b FROM y2 UNION ALL SELECT u FROM one))
SELECT
    *
FROM
    one JOIN two ON u = v
----
1  1
2  2
3  3
2  2
3  3

# Mutation CTEs that aren't referenced elsewhere in the query.
statement ok
CREATE TABLE z (c INT PRIMARY KEY);

query I
WITH foo AS (INSERT INTO z VALUES (10) RETURNING 1) SELECT 2
----
2

query I
SELECT * FROM z
----
10

query I
WITH foo AS (UPDATE z SET c = 20 RETURNING 1) SELECT 3
----
3

query I
SELECT * FROM z
----
20

query I
WITH foo AS (DELETE FROM z RETURNING 1) SELECT 4
----
4

query I
SELECT count(*) FROM z
----
0

# WITH and prepared statements.

statement ok
CREATE TABLE engineer (
    fellow BOOL NOT NULL, id INT4 NOT NULL, companyname VARCHAR(255) NOT NULL,
    PRIMARY KEY (id, companyname)
)

statement ok
PREPARE x (INT4, VARCHAR, INT4, VARCHAR) AS
  WITH ht_engineer (id, companyname) AS (
    SELECT id, companyname FROM (VALUES ($1, $2), ($3, $4)) AS ht (id, companyname)
  )
DELETE FROM engineer WHERE (id, companyname) IN (SELECT id, companyname FROM ht_engineer)

statement ok
EXECUTE x (1, 'fo', 2, 'bar')

statement ok
PREPARE z(int) AS WITH foo AS (SELECT * FROM x2 WHERE a = $1) SELECT * FROM foo

query I
EXECUTE z(1)
----
1

query I
EXECUTE z(2)
----
2

query I
EXECUTE z(3)
----
3

# WITH containing a placeholder that isn't referenced.

statement ok
PREPARE z2(int) AS WITH foo AS (SELECT * FROM x WHERE a = $1) SELECT * FROM x2 ORDER BY a

query I nosort
EXECUTE z2(1)
----
1
2
3

statement ok
PREPARE z3(int) AS WITH foo AS (SELECT $1) SELECT * FROM foo

query I
EXECUTE z3(3)
----
3

statement ok
PREPARE z4(int) AS WITH foo AS (SELECT $1), bar AS (SELECT * FROM foo) SELECT * FROM bar

query I
EXECUTE z4(3)
----
3

statement ok
PREPARE z5(int, int) AS WITH foo AS (SELECT $1), bar AS (SELECT $2) (SELECT * FROM foo) UNION ALL (SELECT * FROM bar)

query I rowsort
EXECUTE z5(3, 5)
----
3
5

statement ok
PREPARE z6(int) AS
    SELECT * FROM
    (VALUES (1), (2)) v(x),
    LATERAL (SELECT * FROM
      (WITH foo AS (SELECT $1 + x) SELECT * FROM foo)
    )

query II rowsort
EXECUTE z6(3)
----
1 4
2 5

# Recursive CTE example from postgres docs.
query T
WITH RECURSIVE t(n) AS (
    VALUES (1)
  UNION ALL
    SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t
----
5050

# Similar example where many duplicate rows are generated but we use UNION to
# deduplicate them.
query T
WITH RECURSIVE t(n) AS (
    VALUES (1)
  UNION
    SELECT n+y FROM t, (VALUES (1), (2)) AS v(y) WHERE n < 99
)
SELECT sum(n) FROM t
----
5050

# Test where initial query has duplicate columns.
query II rowsort
WITH RECURSIVE cte(a, b) AS (
    SELECT 0, 0
  UNION ALL
    SELECT a+1, b+10 FROM cte WHERE a < 5
) SELECT * FROM cte;
----
0  0
1  10
2  20
3  30
4  40
5  50

# Test where recursive query has duplicate columns.
query II rowsort
WITH RECURSIVE cte(a, b) AS (
    SELECT 0, 1
  UNION ALL
    SELECT a+1, a+1 FROM cte WHERE a < 5
) SELECT * FROM cte;
----
0  1
1  1
2  2
3  3
4  4
5  5

# Recursive CTE examples adapted from
# https://malisper.me/generating-fractals-with-postgres-escape-time-fractals.
query T
WITH RECURSIVE points AS (
  SELECT i::float * 0.05 AS r, j::float * 0.05 AS c
  FROM generate_series(-20, 20) AS a (i), generate_series(-40, 20) AS b (j)
), iterations AS (
     SELECT r,
            c,
            0.0::float AS zr,
            0.0::float AS zc,
            0 AS iteration
     FROM points
   UNION ALL
     SELECT r,
            c,
            zr*zr - zc*zc + c AS zr,
            2*zr*zc + r AS zc,
            iteration+1 AS iteration
     FROM iterations WHERE zr*zr + zc*zc < 4 AND iteration < 20
), final_iteration AS (
  SELECT * FROM iterations WHERE iteration = 20
), marked_points AS (
   SELECT r,
          c,
          (CASE WHEN EXISTS (SELECT 1 FROM final_iteration i WHERE p.r = i.r AND p.c = i.c)
                THEN 'oo' ELSE '··' END) AS marker FROM points p
), lines AS (
   SELECT r, string_agg(marker, '' ORDER BY c ASC) AS r_text
   FROM marked_points
   GROUP BY r
) SELECT string_agg(r_text, E'\n' ORDER BY r DESC) FROM lines
----
················································································oo········································
············································································oo············································
··········································································oooo············································
······································································oo··oooo············································
········································································oooooooo··········································
······································································oooooooooooo········································
········································································oooooooo··········································
··························································oo····oooooooooooooooooooo··oo··································
··························································oooo··oooooooooooooooooooooooo··································
··························································oooooooooooooooooooooooooooooooooooooo··························
··························································oooooooooooooooooooooooooooooooooooooo··························
····················································oooooooooooooooooooooooooooooooooooooooooo····························
······················································oooooooooooooooooooooooooooooooooooooooo····························
····················································oooooooooooooooooooooooooooooooooooooooooooooo························
··································oo····oo··········oooooooooooooooooooooooooooooooooooooooooooo··························
··································oooooooooooo······oooooooooooooooooooooooooooooooooooooooooooo··························
··································oooooooooooooo····oooooooooooooooooooooooooooooooooooooooooooooo························
································oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo························
······························oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··························
··························oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo····························
··oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo······························
··························oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo····························
······························oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··························
································oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo························
··································oooooooooooooo····oooooooooooooooooooooooooooooooooooooooooooooo························
··································oooooooooooo······oooooooooooooooooooooooooooooooooooooooooooo··························
··································oo····oo··········oooooooooooooooooooooooooooooooooooooooooooo··························
····················································oooooooooooooooooooooooooooooooooooooooooooooo························
······················································oooooooooooooooooooooooooooooooooooooooo····························
····················································oooooooooooooooooooooooooooooooooooooooooo····························
··························································oooooooooooooooooooooooooooooooooooooo··························
··························································oooooooooooooooooooooooooooooooooooooo··························
··························································oooo··oooooooooooooooooooooooo··································
··························································oo····oooooooooooooooooooo··oo··································
········································································oooooooo··········································
······································································oooooooooooo········································
········································································oooooooo··········································
······································································oo··oooo············································
··········································································oooo············································
············································································oo············································
················································································oo········································

query T
WITH RECURSIVE points AS (
  SELECT i::float * 0.05 AS r, j::float * 0.05 AS c
  FROM generate_series(-20, 20) AS a (i), generate_series(-30, 30) AS b (j)
), iterations AS (
   SELECT r, c, c::float AS zr, r::float AS zc, 0 AS iteration FROM points
   UNION ALL
   SELECT r, c, zr*zr - zc*zc + 1 - 1.61803398875 AS zr, 2*zr*zc AS zc, iteration+1 AS iteration
   FROM iterations WHERE zr*zr + zc*zc < 4 AND iteration < 20
), final_iteration AS (
  SELECT * FROM iterations WHERE iteration = 20
), marked_points AS (
   SELECT r, c, (CASE WHEN EXISTS (SELECT 1 FROM final_iteration i WHERE p.r = i.r AND p.c = i.c)
                  THEN 'oo'
                  ELSE '··'
                  END) AS marker
   FROM points p
), rows AS (
   SELECT r, string_agg(marker, '' ORDER BY c ASC) AS r_text
   FROM marked_points
   GROUP BY r
) SELECT string_agg(r_text, E'\n' ORDER BY r DESC) FROM rows
----
··························································································································
··························································································································
····························································oo····························································
····························································oo····························································
························································oooooooooo························································
························································oooooooooo························································
························································oooooooooo························································
··············································oo··oooooooooooooooooooooo··oo··············································
··············································oooooooooooooooooooooooooooooo··············································
············································oooooooooooooooooooooooooooooooooo············································
··········································oooooooooooooooooooooooooooooooooooooo··········································
························oooo····oo········oooooooooooooooooooooooooooooooooooooo········oo····oooo························
························oooooooooooooo····oooooooooooooooooooooooooooooooooooooo····oooooooooooooo························
······················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo······················
····················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo····················
··················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··················
··················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··················
··········oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··········
··········oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··········
······oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo······
····oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo····
······oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo······
··········oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··········
··········oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··········
··················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··················
··················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo··················
····················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo····················
······················oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo······················
························oooooooooooooo····oooooooooooooooooooooooooooooooooooooo····oooooooooooooo························
························oooo····oo········oooooooooooooooooooooooooooooooooooooo········oo····oooo························
··········································oooooooooooooooooooooooooooooooooooooo··········································
············································oooooooooooooooooooooooooooooooooo············································
··············································oooooooooooooooooooooooooooooo··············································
··············································oo··oooooooooooooooooooooo··oo··············································
························································oooooooooo························································
························································oooooooooo························································
························································oooooooooo························································
····························································oo····························································
····························································oo····························································
··························································································································
··························································································································

# Test that we deduplicate rows from the initial expression.
query II rowsort
WITH RECURSIVE cte(a, b) AS (
    VALUES (2, 2), (1, 1), (1, 2), (1, 1), (1, 3), (1, 2), (2, 2)
  UNION
    SELECT a+10, b+10 FROM cte WHERE a < 20
) SELECT * FROM cte;
----
2   2
1   1
1   2
1   3
12  12
11  11
11  12
11  13
22  22
21  21
21  22
21  23

# Test that we deduplicate rows from a single iteration.
query II rowsort
WITH RECURSIVE cte(a, b) AS (
    VALUES (1, 1), (1, 2), (2, 2)
  UNION
    SELECT 4-a, 4-a FROM cte
) SELECT * FROM cte;
----
1  1
1  2
2  2
3  3

# Test that we deduplicate rows across iterations.
query II rowsort
WITH RECURSIVE cte(a, b) AS (
    VALUES (1, 1), (1, 2), (2, 2)
  UNION
    SELECT (a+i) % 4, (b+1-i) % 4 FROM cte, (VALUES (0), (1)) AS v(i)
) SELECT * FROM cte;
----
1  1
1  2
2  2
2  1
1  3
2  3
3  2
3  1
1  0
2  0
3  3
0  2
0  1
3  0
0  3
0  0


# Regression test for #45869 (CTE inside recursive CTE).
query T rowsort
WITH RECURSIVE x(a) AS (
    VALUES ('a'), ('b')
  UNION ALL
    (WITH z AS (SELECT * FROM x)
      SELECT z.a || z1.a AS a FROM z CROSS JOIN z AS z1 WHERE length(z.a) < 3
    )
)
SELECT * FROM x
----
a
b
aa
ba
ab
bb
aaaa
baaa
abaa
bbaa
aaba
baba
abba
bbba
aaab
baab
abab
bbab
aabb
babb
abbb
bbbb

# Regression test for #53951: placeholder inside a recursive CTE.
statement ok
PREPARE
  ctestmt
AS
  (WITH RECURSIVE cte (x) AS (VALUES (1) UNION ALL SELECT x + $1 FROM cte WHERE x < 50) SELECT * FROM cte)

query I rowsort
EXECUTE ctestmt (10)
----
1
11
21
31
41
51

# Verify that the query inside the CTE can refer to an outer CTE.
statement ok
DROP TABLE IF EXISTS ab

statement ok
CREATE TABLE ab (a INT PRIMARY KEY, b INT)

statement ok
INSERT INTO ab VALUES (1,1)

query I rowsort
WITH
  cte1 AS MATERIALIZED (SELECT a FROM ab WHERE a = b)
SELECT * FROM
  (
    WITH RECURSIVE
      cte2 (x) AS (SELECT 1 UNION ALL SELECT x + a FROM cte2, cte1 WHERE x < 10)
    SELECT * FROM cte2
  )
----
1
2
3
4
5
6
7
8
9
10

# Test CTE with order-by projection (#55196).
statement ok
CREATE TABLE xy (x INT, y INT);
INSERT INTO xy VALUES (1,1),(1,2),(2,1),(2,2);

query I rowsort
WITH cte AS (SELECT x*10+y FROM xy ORDER BY x+y LIMIT 3) SELECT * FROM cte
----
11
12
21

# Test for recursive CTE which needs a cast in the initial expression.
statement ok
CREATE TABLE graph_node (
  id VARCHAR(16) PRIMARY KEY,
  parent VARCHAR(16)
)

statement ok
INSERT INTO graph_node (id, parent) VALUES
  ('A', null),
  ('B', 'A'),
  ('C', 'B'),
  ('D', 'C')

# The recursive query seed column types must match the output columns types.
query error pgcode 42804 recursive query \"nodes\" column 1 has type string in non-recursive term but type varchar overall
WITH RECURSIVE nodes AS (
  SELECT 'A' AS id
  UNION ALL
  SELECT graph_node.id FROM graph_node JOIN nodes ON graph_node.parent = nodes.id
)
SELECT * FROM nodes

# The recursive query seed column types must match the output columns types.
query error pgcode 42804 recursive query \"foo\" column 1 has type int in non-recursive term but type decimal overall
WITH RECURSIVE foo(i) AS
    (SELECT i FROM (VALUES(1),(2)) t(i)
    UNION ALL
    SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
SELECT * FROM foo

# Tests with correlated CTEs.
statement ok
INSERT INTO x SELECT generate_series(1, 3)

query II rowsort
SELECT y.a, (
  WITH foo AS MATERIALIZED (SELECT x.a FROM x WHERE x.a = y.a)
  SELECT * FROM foo
) FROM y
----
2  2
3  3
4  NULL

query II rowsort
SELECT * FROM
  (VALUES (1), (2), (10)) AS v(x),
  LATERAL (WITH foo AS MATERIALIZED (SELECT a FROM y WHERE y.a <= x) SELECT * FROM foo)
----
2   2
10  2
10  3
10  4

# Tests with multiple mutation CTEs on different tables. These testcases vary
# the type of mutation as well as the input to the mutation subquery and
# the main query (sometimes another CTE, sometimes the table being mutated,
# sometimes a different table).

statement ok
CREATE TABLE r (i INT PRIMARY KEY);
CREATE TABLE s (i INT PRIMARY KEY);
INSERT INTO r VALUES (0)

# Multiple CTEs inserting into different tables.
query I rowsort
WITH
  t AS (INSERT INTO r VALUES (1) RETURNING i),
  u AS (INSERT INTO s SELECT * FROM r RETURNING i)
SELECT i FROM s
----

query I rowsort
SELECT i FROM r
----
0
1

query I rowsort
SELECT i FROM s
----
0

# Multiple CTEs deleting from different tables.
query I rowsort
WITH
  t AS (DELETE FROM r WHERE i IN (SELECT i FROM s) RETURNING i),
  u AS (DELETE FROM s WHERE i IN (SELECT i FROM t) RETURNING i)
SELECT i FROM r WHERE i IN (SELECT i FROM s)
----
0

query I rowsort
SELECT i FROM r
----
1

query I rowsort
SELECT i FROM s
----

# Multiple CTEs upserting into different tables. The first CTE will perform both
# a no-op update due to a conflict, and an insert. The second CTE will perform
# two inserts.
query I rowsort
WITH
  t AS (UPSERT INTO r VALUES (0), (1) RETURNING i),
  u AS (UPSERT INTO s SELECT * FROM t RETURNING i)
SELECT i FROM r UNION ALL SELECT i FROM t
----
0
1
1

query I rowsort
SELECT i FROM r
----
0
1

query I rowsort
SELECT i FROM s
----
0
1

# Multiple CTEs updating different tables. Both CTEs will update two rows.
query I rowsort
WITH
  t AS (UPDATE r SET i = i + 2 RETURNING i),
  u AS (UPDATE s SET i = -r.i FROM r WHERE s.i < r.i RETURNING s.i)
SELECT i FROM u
----
-1

query I rowsort
SELECT i FROM r
----
2
3

query I rowsort
SELECT i FROM s
----
-1
1

# Multiple CTEs inserting into different tables. The second CTE will update two
# rows instead of inserting, due to conflicts.
query II rowsort
WITH
  t AS (INSERT INTO r SELECT i FROM s ON CONFLICT (i) DO UPDATE SET i = r.i + 2 RETURNING r.i),
  u AS (INSERT INTO s SELECT i FROM t ON CONFLICT (i) DO UPDATE SET i = s.i - 2 RETURNING s.i)
SELECT * FROM r, u
----
2 -3
2 -1
3 -3
3 -1

query I rowsort
SELECT i FROM r
----
-1
1
2
3

query I rowsort
SELECT i FROM s
----
-3
-1

# Tests with multiple mutations on the same table, modifying different rows.
# These testcases vary the type of mutation, but use a common form of: mutation
# CTE followed by main mutation which reads from the CTE.

statement ok
CREATE TABLE t (i INT PRIMARY KEY, j INT, INDEX (j));
INSERT INTO t VALUES (0, 0)

# Multiple inserts of different rows into the same table.
query II rowsort
WITH
  u AS (INSERT INTO t VALUES (1, 1) RETURNING *)
INSERT INTO t SELECT i + 1, j + 1 FROM u RETURNING *
----
2 2

query II rowsort
SELECT * FROM t
----
0 0
1 1
2 2

# For INSERT ON CONFLICT, UPSERT, UPDATE, and DELETE we must explicitly allow
# statements with multiple mutations to the same table, due to issue
# 70731. These statements are safe to execute because the mutations modify
# different rows.
statement ok
SET CLUSTER SETTING sql.multiple_modifications_of_table.enabled = true

# Multiple deletes of different rows from the same table. The CTE will delete
# one row and the main query will delete one row.
query II rowsort
WITH
  u AS (DELETE FROM t WHERE i = 0 RETURNING *)
DELETE FROM t WHERE i IN (SELECT i + 1 FROM u) RETURNING *
----
1 1

query II rowsort
SELECT * FROM t
----
2 2

# Multiple upserts of different rows into the same table. The CTE will update
# one row and insert one row. The main query will insert two rows.
query II rowsort
WITH
  u AS (UPSERT INTO t VALUES (2, 3), (4, 5) RETURNING *)
UPSERT INTO t SELECT i + 4, j + 4 FROM u RETURNING *
----
6 7
8 9

query II rowsort
SELECT * FROM t
----
2 3
4 5
6 7
8 9

# Multiple updates of different rows in the same table. The CTE will update one
# row and the main query will update the rest of the rows.
query IIII rowsort
WITH
  u AS (UPDATE t SET j = j + 1 WHERE i = 2 RETURNING *)
UPDATE t SET j = 99 FROM u WHERE t.i != u.i RETURNING *
----
4 99 2 4
6 99 2 4
8 99 2 4

query II rowsort
SELECT * FROM t
----
2 4
4 99
6 99
8 99

# Multiple inserts of different rows into the same table. The CTE will update
# all rows due to conflicts. The main query will then insert one new row.
query II rowsort
WITH
  u AS (INSERT INTO t SELECT i, j - 1 FROM t ON CONFLICT (i) DO UPDATE SET j = 100 RETURNING *)
INSERT INTO t SELECT sum_int(i), sum_int(j) FROM u ON CONFLICT (i) DO UPDATE SET j = 1 RETURNING *
----
20 400

query II rowsort
SELECT * FROM t
----
2 100
4 100
6 100
8 100
20 400

# Check for corruption. (There should be none!)
query TTTTTTTT
EXPERIMENTAL SCRUB TABLE t WITH OPTIONS INDEX ALL
----

statement ok
RESET CLUSTER SETTING sql.multiple_modifications_of_table.enabled

# Multiple mutations can also be explicitly allowed with a session setting.
statement ok
SET enable_multiple_modifications_of_table = true

# Multiple updates of different rows in the same table.
query II rowsort
WITH
  u1 AS (UPDATE t SET j = j - 40 WHERE i < 20 RETURNING *),
  u2 AS (UPDATE t SET j = j + 40 WHERE i >= 20 RETURNING *)
TABLE u1 UNION ALL TABLE u2
----
2 60
4 60
6 60
8 60
20 440

# Check for corruption.
query TTTTTTTT
EXPERIMENTAL SCRUB TABLE t WITH OPTIONS INDEX ALL
----

statement ok
RESET enable_multiple_modifications_of_table

# Tests with multiple mutations on the same table, modifying the same
# rows. These testcases vary the type of mutation and the form. All should fail
# with an error. When issue 70731 is fixed, some might no longer fail.

statement ok
CREATE TABLE u (i INT PRIMARY KEY, j INT, INDEX (j));
INSERT INTO u VALUES (0, 0)

# Multiple inserts of the same row into the same table. Should always fail.
query error pgcode 23505 duplicate key value violates unique constraint
WITH
  v AS (INSERT INTO u VALUES (1, 1) RETURNING *)
INSERT INTO u SELECT * FROM v

query II
SELECT i, j FROM u@u_pkey
----
0 0

query II
SELECT i, j FROM u@u_j_idx
----
0 0

# Multiple upserts of the same row. Might succeed after issue 70731 is fixed,
# depending on the implementation, but should not cause corruption.
query error pgcode 0A000 multiple mutations of the same table
WITH
  v AS (UPSERT INTO u VALUES (0, 1) RETURNING *),
  w AS (UPSERT INTO u SELECT i, j + 1 FROM v RETURNING *)
SELECT * FROM w

query II
SELECT i, j FROM u@u_pkey
----
0 0

query II
SELECT i, j FROM u@u_j_idx
----
0 0

# Multiple updates of the same row. Might succeed after issue 70731 is fixed,
# depending on the implementation, but should not cause corruption. The order of
# CTE execution is not necessarily defined here.
query error pgcode 0A000 multiple mutations of the same table
WITH
  v AS (UPDATE u SET j = 3 WHERE i = 0 RETURNING *),
  w AS (UPDATE u SET j = 4 WHERE i = 0 RETURNING *)
SELECT * FROM u

query II
SELECT i, j FROM u@u_pkey
----
0 0

query II
SELECT i, j FROM u@u_j_idx
----
0 0

# Multiple updates of the same row. Might succeed after issue 70731 is fixed,
# depending on the implementation, but should not cause corruption. The order of
# CTE execution should be deterministic.
query error pgcode 0A000 multiple mutations of the same table
WITH
  v AS (UPDATE u SET j = 5 WHERE i = 0 RETURNING *),
  w AS (UPDATE u SET j = v.j + 1 FROM v WHERE u.i = v.i RETURNING *)
SELECT * FROM w

query II
SELECT i, j FROM u@u_pkey
----
0 0

query II
SELECT i, j FROM u@u_j_idx
----
0 0

# Multiple inserts of the same row into the same table, most should become
# updates due to conflicts. Might succeed after issue 70731 is fixed.
query error pgcode 0A000 multiple mutations of the same table
WITH
  v AS (INSERT INTO u VALUES (0, 42), (1, 42) ON CONFLICT (i) DO UPDATE SET j = 52 RETURNING *)
INSERT INTO u SELECT i, j + 1 FROM v ON CONFLICT (i) DO UPDATE SET j = v.j + 100 RETURNING *

query II
SELECT i, j FROM u@u_pkey
----
0 0

query II
SELECT i, j FROM u@u_j_idx
----
0 0

# Multiple deletes of the same row. Might succeed after issue 70731 is fixed,
# though the order of CTE execution is undefined.
query error pgcode 0A000 multiple mutations of the same table
WITH
  v AS (DELETE FROM u ORDER BY i LIMIT 1 RETURNING *),
  w AS (DELETE FROM u ORDER BY i LIMIT 2 RETURNING *)
SELECT * FROM w

query II
SELECT i, j FROM u@u_pkey
----
0 0

query II
SELECT i, j FROM u@u_j_idx
----
0 0

# Check for corruption. (There should be none!)
query TTTTTTTT
EXPERIMENTAL SCRUB TABLE u WITH OPTIONS INDEX ALL
----

# Example pulled from a blog post.
# https://malisper.me/the-missing-postgres-scan-the-loose-index-scan
statement ok
CREATE TABLE ints (n BIGINT, INDEX (n));

statement ok
INSERT INTO ints
VALUES (1), (1), (1), (2), (4), (4), (4), (4), (5), (5),
  (6), (7), (7), (7), (8), (9), (9), (9), (9), (9);

query I
WITH RECURSIVE temp (i) AS (
  (SELECT n FROM ints ORDER BY n ASC LIMIT 1)
UNION ALL (
  SELECT n FROM temp,
    LATERAL (
      SELECT n
      FROM ints
      WHERE n > i
      ORDER BY n ASC
      LIMIT 1
    ) sub
  )
)
SELECT count(*) FROM temp;
----
8

query I rowsort
WITH RECURSIVE temp (i) AS (
  (SELECT n FROM ints ORDER BY n ASC LIMIT 1)
UNION ALL (
  SELECT n FROM temp,
    LATERAL (
      SELECT n
      FROM ints
      WHERE n > i
      ORDER BY n ASC
      LIMIT 1
    ) sub
  )
)
SELECT * FROM temp;
----
1
2
4
5
6
7
8
9

# Added limit to the recursive branch.
query I
WITH RECURSIVE temp (i) AS (
  (SELECT n FROM ints ORDER BY n ASC LIMIT 1)
UNION ALL (
  SELECT n FROM temp,
    LATERAL (
      SELECT n
      FROM ints
      WHERE n > i
      ORDER BY n ASC
      LIMIT 1
    ) sub LIMIT 1
  )
)
SELECT count(*) FROM temp;
----
8

query I rowsort
WITH RECURSIVE temp (i) AS (
  (SELECT n FROM ints ORDER BY n ASC LIMIT 1)
UNION ALL (
  SELECT n FROM temp,
    LATERAL (
      SELECT n
      FROM ints
      WHERE n > i
      ORDER BY n ASC
      LIMIT 1
    ) sub LIMIT 1
  )
)
SELECT * FROM temp;
----
1
2
4
5
6
7
8
9

# Regression test for #95360. A NOT MATERIALIZED CTE should not be inlined if it
# has a mutation.
statement ok
CREATE TABLE t95360 (a INT, b INT)

# Note: The correlated subquery with a UNION ALL forces the optimizer to use an
# apply-join, which would execute the INSERT once for each row in v if the
# INSERT was inlined.
statement ok
WITH insVals AS NOT MATERIALIZED (INSERT INTO t95360 VALUES (1, 10) RETURNING a)
SELECT * FROM (VALUES (1), (2), (3)) v(a)
WHERE EXISTS (SELECT * FROM insVals WHERE a = v.a UNION ALL SELECT a FROM (VALUES (4)) w(a) WHERE a = v.a)

query II
SELECT * FROM t95360
----
1  10

# Regression tests for #93370. Do not convert a non-recursive CTE
# that uses UNION ALL and WITH RECURSIVE to UNION.
query I rowsort
WITH RECURSIVE
   x(id) AS
     (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
   y(id) AS
     (SELECT * FROM x UNION ALL SELECT * FROM x)
 SELECT * FROM y
----
1
2
3
1
2
3

statement ok
CREATE TABLE t93370 (i INT);
INSERT INTO t93370 VALUES (1), (2), (3)

query I rowsort
WITH RECURSIVE
   y(id) AS (SELECT * FROM t93370 UNION ALL SELECT * FROM t93370)
 SELECT * FROM y
----
1
2
3
1
2
3

# Regression test for #100561.
statement ok
CREATE TABLE t100561a (a INT);
CREATE TABLE t100561b (k INT PRIMARY KEY, b INT);
INSERT INTO t100561b VALUES (1, NULL)

# Control: a query with a subquery.
query II
SELECT t3.c2, t3.c1 FROM (
  SELECT t2.b AS c1, t2.k AS c2 FROM t100561a t1 FULL OUTER JOIN t100561b t2 ON true
) AS t3, t100561b t2
WHERE t3.c2 = t2.k
----
1  NULL

# A query like the one above, rewritten with a CTE, should produce the same
# result.
query II
WITH t3(c1, c2) AS (
  SELECT t2.b AS c1, t2.k AS c2 FROM t100561a t1 FULL OUTER JOIN t100561b t2 ON true
)
SELECT t3.c2, t3.c1 FROM t3, t100561b t2
WHERE t3.c2 = t2.k
----
1  NULL
