statement ok
CREATE TABLE ab (a INT PRIMARY KEY, b INT);
INSERT INTO ab VALUES (1, 10), (2, 20), (3, 30), (4, 40);

statement ok
CREATE PROCEDURE p(OUT ret INT) LANGUAGE SQL AS $$
  WITH foo AS MATERIALIZED (SELECT 100) SELECT * FROM foo;
$$;

query I
CALL p(NULL);
----
100

statement ok
DROP PROCEDURE p;
CREATE PROCEDURE p(OUT ret INT) LANGUAGE SQL AS $$
  WITH foo AS MATERIALIZED (SELECT b FROM ab WHERE a = 3) SELECT * FROM foo;
$$;

query I
CALL p(NULL);
----
30

# Multiple references to the CTE.
statement ok
DROP PROCEDURE p;
CREATE PROCEDURE p(OUT ret INT) LANGUAGE SQL AS $$
  WITH foo (bar) AS (SELECT 1) SELECT foo.bar + foo2.bar FROM foo, foo foo2;
$$;

query I
CALL p(NULL);
----
2

# CTE with multiple branches.
statement ok
DROP PROCEDURE p;
CREATE PROCEDURE p(OUT ret INT) LANGUAGE SQL AS $$
  WITH foo (x) AS MATERIALIZED (SELECT 1),
  bar (x) AS MATERIALIZED (SELECT 2)
  SELECT foo.x + bar.x FROM foo, bar;
$$;

query I
CALL p(NULL);
----
3

# Nested CTE expressions.
statement ok
DROP PROCEDURE p;
CREATE PROCEDURE p(OUT ret INT) LANGUAGE SQL AS $$
  WITH foo (x) AS MATERIALIZED (SELECT 100)
  SELECT * FROM (
    WITH bar (x) AS MATERIALIZED (SELECT 200)
    SELECT foo.x + bar.x FROM foo, bar
  ) AS t;
$$;

query I
CALL p(NULL);
----
300

# Case with a CTE inside a subquery.
statement ok
DROP PROCEDURE p;
CREATE PROCEDURE p(OUT ret INT) LANGUAGE SQL AS $$
  SELECT (
    WITH foo AS MATERIALIZED (SELECT b FROM ab)
    SELECT * FROM foo
  );
$$;

# Avoid causing an error due to too many rows returned.
statement ok
DELETE FROM ab WHERE a > 1;

query I
CALL p(NULL);
----
10

statement ok
INSERT INTO ab VALUES (2, 20), (3, 30), (4, 40);

# Case with a recursive CTE.
statement ok
DROP PROCEDURE p;
CREATE PROCEDURE p(OUT res INT[]) LANGUAGE SQL AS $$
  WITH RECURSIVE foo (x, y) AS (
    SELECT a, b FROM ab WHERE a = 1
    UNION ALL
    SELECT a, b FROM ab WHERE a = (SELECT max(x) + 1 FROM foo)
  )
  SELECT array_agg(y) FROM foo;
$$;

query T
CALL p(NULL);
----
{10,20,30,40}
