2 -- Tests for common table expressions (WITH query, ... SELECT ...)
5 WITH q1(x,y) AS (SELECT 1,2)
6 SELECT * FROM q1, q1 AS q2;
12 -- Multiple uses are evaluated only once
13 SELECT count(*) FROM (
14 WITH q1(x) AS (SELECT random() FROM generate_series(1, 5))
26 WITH RECURSIVE t(n) AS (
29 SELECT n+1 FROM t WHERE n < 100
37 WITH RECURSIVE t(n) AS (
40 SELECT n+1 FROM t WHERE n < 5
52 -- UNION DISTINCT requires hashable type
53 WITH RECURSIVE t(n) AS (
56 SELECT n+1::money FROM t WHERE n < 100::money
59 ERROR: could not implement recursive UNION
60 DETAIL: All column datatypes must be hashable.
62 CREATE RECURSIVE VIEW nums (n) AS
65 SELECT n+1 FROM nums WHERE n < 5;
76 CREATE OR REPLACE RECURSIVE VIEW nums (n) AS
79 SELECT n+1 FROM nums WHERE n < 6;
91 -- This is an infinite loop with UNION ALL, but not with UNION
92 WITH RECURSIVE t(n) AS (
103 -- This'd be an infinite loop, but outside query reads only as much as needed
104 WITH RECURSIVE t(n) AS (
108 SELECT * FROM t LIMIT 10;
123 -- UNION case should have same property
124 WITH RECURSIVE t(n) AS (
128 SELECT * FROM t LIMIT 10;
143 -- Test behavior with an unknown-type literal in the WITH
144 WITH q AS (SELECT 'foo' AS x)
145 SELECT x, pg_typeof(x) FROM q;
151 WITH RECURSIVE t(n) AS (
154 SELECT n || ' bar' FROM t WHERE length(n) < 20
156 SELECT n, pg_typeof(n) FROM t;
158 -------------------------+-----------
162 foo bar bar bar | text
163 foo bar bar bar bar | text
164 foo bar bar bar bar bar | text
167 -- In a perfect world, this would work and resolve the literal as int ...
168 -- but for now, we have to be content with resolving to text too soon.
169 WITH RECURSIVE t(n) AS (
172 SELECT n+1 FROM t WHERE n < 10
174 SELECT n, pg_typeof(n) FROM t;
175 ERROR: operator does not exist: text + integer
176 LINE 4: SELECT n+1 FROM t WHERE n < 10
178 HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
179 -- Deeply nested WITH caused a list-munging problem in v13
180 -- Detection of cross-references and self-references
181 WITH RECURSIVE w1(c1) AS
186 (WITH RECURSIVE w6(c6) AS
203 -- Detection of invalid self-references
204 WITH RECURSIVE outermost(x) AS (
206 UNION (WITH innermost1 AS (
208 UNION (WITH innermost2 AS (
210 UNION (WITH innermost3 AS (
212 UNION (WITH innermost4 AS (
214 UNION (WITH innermost5 AS (
216 UNION (WITH innermost6 AS
218 SELECT * FROM innermost6))
219 SELECT * FROM innermost5))
220 SELECT * FROM innermost4))
221 SELECT * FROM innermost3))
222 SELECT * FROM innermost2))
223 SELECT * FROM outermost
224 UNION SELECT * FROM innermost1)
226 SELECT * FROM outermost ORDER BY 1;
239 -- Some examples with a tree
241 -- department structure represented here is as follows:
243 -- ROOT-+->A-+->B-+->C
247 CREATE TEMP TABLE department (
248 id INTEGER PRIMARY KEY, -- department ID
249 parent_department INTEGER REFERENCES department, -- upper department ID
250 name TEXT -- department name
252 INSERT INTO department VALUES (0, NULL, 'ROOT');
253 INSERT INTO department VALUES (1, 0, 'A');
254 INSERT INTO department VALUES (2, 1, 'B');
255 INSERT INTO department VALUES (3, 2, 'C');
256 INSERT INTO department VALUES (4, 2, 'D');
257 INSERT INTO department VALUES (5, 0, 'E');
258 INSERT INTO department VALUES (6, 4, 'F');
259 INSERT INTO department VALUES (7, 5, 'G');
260 -- extract all departments under 'A'. Result should be A, B, C, D and F
261 WITH RECURSIVE subdepartment AS
263 -- non recursive term
264 SELECT name as root_name, * FROM department WHERE name = 'A'
267 SELECT sd.root_name, d.* FROM department AS d, subdepartment AS sd
268 WHERE d.parent_department = sd.id
270 SELECT * FROM subdepartment ORDER BY name;
271 root_name | id | parent_department | name
272 -----------+----+-------------------+------
280 -- extract all departments under 'A' with "level" number
281 WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
283 -- non recursive term
284 SELECT 1, * FROM department WHERE name = 'A'
287 SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
288 WHERE d.parent_department = sd.id
290 SELECT * FROM subdepartment ORDER BY name;
291 level | id | parent_department | name
292 -------+----+-------------------+------
300 -- extract all departments under 'A' with "level" number.
301 -- Only shows level 2 or more
302 WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
304 -- non recursive term
305 SELECT 1, * FROM department WHERE name = 'A'
308 SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
309 WHERE d.parent_department = sd.id
311 SELECT * FROM subdepartment WHERE level >= 2 ORDER BY name;
312 level | id | parent_department | name
313 -------+----+-------------------+------
320 -- "RECURSIVE" is ignored if the query has no self-reference
321 WITH RECURSIVE subdepartment AS
323 -- note lack of recursive UNION structure
324 SELECT * FROM department WHERE name = 'A'
326 SELECT * FROM subdepartment ORDER BY name;
327 id | parent_department | name
328 ----+-------------------+------
333 SELECT count(*) FROM (
334 WITH RECURSIVE t(n) AS (
335 SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 500
337 SELECT * FROM t) AS t WHERE n < (
338 SELECT count(*) FROM (
339 WITH RECURSIVE t(n) AS (
340 SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 100
342 SELECT * FROM t WHERE n < 50000
343 ) AS t WHERE n < 100);
349 -- use same CTE twice at different subquery levels
351 SELECT hundred, sum(ten) FROM tenk1 GROUP BY hundred
353 SELECT count(*) FROM q1 WHERE y > (SELECT sum(y)/100 FROM q1 qsub);
360 CREATE TEMPORARY VIEW vsubdepartment AS
361 WITH RECURSIVE subdepartment AS
363 -- non recursive term
364 SELECT * FROM department WHERE name = 'A'
367 SELECT d.* FROM department AS d, subdepartment AS sd
368 WHERE d.parent_department = sd.id
370 SELECT * FROM subdepartment;
371 SELECT * FROM vsubdepartment ORDER BY name;
372 id | parent_department | name
373 ----+-------------------+------
381 -- Check reverse listing
382 SELECT pg_get_viewdef('vsubdepartment'::regclass);
384 -----------------------------------------------
385 WITH RECURSIVE subdepartment AS ( +
386 SELECT department.id, +
387 department.parent_department, +
390 WHERE (department.name = 'A'::text)+
393 d.parent_department, +
397 WHERE (d.parent_department = sd.id)+
399 SELECT subdepartment.id, +
400 subdepartment.parent_department, +
405 SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
407 ---------------------------------------------
408 WITH RECURSIVE subdepartment AS ( +
409 SELECT department.id, +
410 department.parent_department, +
413 WHERE department.name = 'A'::text+
416 d.parent_department, +
420 WHERE d.parent_department = sd.id+
422 SELECT subdepartment.id, +
423 subdepartment.parent_department, +
428 -- Another reverse-listing example
429 CREATE VIEW sums_1_100 AS
430 WITH RECURSIVE t(n) AS (
433 SELECT n+1 FROM t WHERE n < 100
435 SELECT sum(n) FROM t;
437 View "public.sums_1_100"
438 Column | Type | Collation | Nullable | Default | Storage | Description
439 --------+--------+-----------+----------+---------+---------+-------------
440 sum | bigint | | | | plain |
442 WITH RECURSIVE t(n) AS (
449 SELECT sum(t.n) AS sum
452 -- corner case in which sub-WITH gets initialized first
453 with recursive q as (
454 select * from department
456 (with x as (select * from q)
459 select * from q limit 24;
460 id | parent_department | name
461 ----+-------------------+------
488 with recursive q as (
489 select * from department
491 (with recursive x as (
492 select * from department
494 (select * from q union all select * from x)
498 select * from q limit 32;
499 id | parent_department | name
500 ----+-------------------+------
535 -- recursive term has sub-UNION
536 WITH RECURSIVE t(i,j) AS (
539 SELECT t2.i, t.j+1 FROM
540 (SELECT 2 AS i UNION ALL SELECT 3 AS i) AS t2
541 JOIN t ON (t2.i = t.i+1))
551 -- different tree example
553 CREATE TEMPORARY TABLE tree(
554 id INTEGER PRIMARY KEY,
555 parent_id INTEGER REFERENCES tree(id)
558 VALUES (1, NULL), (2, 1), (3,1), (4,2), (5,2), (6,2), (7,3), (8,3),
559 (9,4), (10,4), (11,7), (12,7), (13,7), (14, 9), (15,11), (16,11);
561 -- get all paths from "second level" nodes to leaf nodes
563 WITH RECURSIVE t(id, path) AS (
564 VALUES(1,ARRAY[]::integer[])
566 SELECT tree.id, t.path || tree.id
567 FROM tree JOIN t ON (tree.parent_id = t.id)
569 SELECT t1.*, t2.* FROM t AS t1 JOIN t AS t2 ON
570 (t1.path[1] = t2.path[1] AND
571 array_upper(t1.path,1) = 1 AND
572 array_upper(t2.path,1) > 1)
573 ORDER BY t1.id, t2.id;
574 id | path | id | path
575 ----+------+----+-------------
579 2 | {2} | 9 | {2,4,9}
580 2 | {2} | 10 | {2,4,10}
581 2 | {2} | 14 | {2,4,9,14}
584 3 | {3} | 11 | {3,7,11}
585 3 | {3} | 12 | {3,7,12}
586 3 | {3} | 13 | {3,7,13}
587 3 | {3} | 15 | {3,7,11,15}
588 3 | {3} | 16 | {3,7,11,16}
592 WITH RECURSIVE t(id, path) AS (
593 VALUES(1,ARRAY[]::integer[])
595 SELECT tree.id, t.path || tree.id
596 FROM tree JOIN t ON (tree.parent_id = t.id)
598 SELECT t1.id, count(t2.*) FROM t AS t1 JOIN t AS t2 ON
599 (t1.path[1] = t2.path[1] AND
600 array_upper(t1.path,1) = 1 AND
601 array_upper(t2.path,1) > 1)
610 -- this variant tickled a whole-row-variable bug in 8.4devel
611 WITH RECURSIVE t(id, path) AS (
612 VALUES(1,ARRAY[]::integer[])
614 SELECT tree.id, t.path || tree.id
615 FROM tree JOIN t ON (tree.parent_id = t.id)
617 SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON
620 ----+-------------+--------------------
624 4 | {2,4} | (4,"{2,4}")
625 5 | {2,5} | (5,"{2,5}")
626 6 | {2,6} | (6,"{2,6}")
627 7 | {3,7} | (7,"{3,7}")
628 8 | {3,8} | (8,"{3,8}")
629 9 | {2,4,9} | (9,"{2,4,9}")
630 10 | {2,4,10} | (10,"{2,4,10}")
631 11 | {3,7,11} | (11,"{3,7,11}")
632 12 | {3,7,12} | (12,"{3,7,12}")
633 13 | {3,7,13} | (13,"{3,7,13}")
634 14 | {2,4,9,14} | (14,"{2,4,9,14}")
635 15 | {3,7,11,15} | (15,"{3,7,11,15}")
636 16 | {3,7,11,16} | (16,"{3,7,11,16}")
640 create temp table graph0( f int, t int, label text );
641 insert into graph0 values
642 (1, 2, 'arc 1 -> 2'),
643 (1, 3, 'arc 1 -> 3'),
644 (2, 3, 'arc 2 -> 3'),
645 (1, 4, 'arc 1 -> 4'),
646 (4, 5, 'arc 4 -> 5');
647 with recursive search_graph(f, t, label) as (
648 select * from graph0 g
651 from graph0 g, search_graph sg
653 ) search depth first by f, t set seq
654 select * from search_graph order by seq;
656 ---+---+------------+-------------------
657 1 | 2 | arc 1 -> 2 | {"(1,2)"}
658 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"}
659 1 | 3 | arc 1 -> 3 | {"(1,3)"}
660 1 | 4 | arc 1 -> 4 | {"(1,4)"}
661 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"}
662 2 | 3 | arc 2 -> 3 | {"(2,3)"}
663 4 | 5 | arc 4 -> 5 | {"(4,5)"}
666 with recursive search_graph(f, t, label) as (
667 select * from graph0 g
670 from graph0 g, search_graph sg
672 ) search depth first by f, t set seq
673 select * from search_graph order by seq;
675 ---+---+------------+-------------------
676 1 | 2 | arc 1 -> 2 | {"(1,2)"}
677 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"}
678 1 | 3 | arc 1 -> 3 | {"(1,3)"}
679 1 | 4 | arc 1 -> 4 | {"(1,4)"}
680 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"}
681 2 | 3 | arc 2 -> 3 | {"(2,3)"}
682 4 | 5 | arc 4 -> 5 | {"(4,5)"}
685 with recursive search_graph(f, t, label) as (
686 select * from graph0 g
689 from graph0 g, search_graph sg
691 ) search breadth first by f, t set seq
692 select * from search_graph order by seq;
694 ---+---+------------+---------
695 1 | 2 | arc 1 -> 2 | (0,1,2)
696 1 | 3 | arc 1 -> 3 | (0,1,3)
697 1 | 4 | arc 1 -> 4 | (0,1,4)
698 2 | 3 | arc 2 -> 3 | (0,2,3)
699 4 | 5 | arc 4 -> 5 | (0,4,5)
700 2 | 3 | arc 2 -> 3 | (1,2,3)
701 4 | 5 | arc 4 -> 5 | (1,4,5)
704 with recursive search_graph(f, t, label) as (
705 select * from graph0 g
708 from graph0 g, search_graph sg
710 ) search breadth first by f, t set seq
711 select * from search_graph order by seq;
713 ---+---+------------+---------
714 1 | 2 | arc 1 -> 2 | (0,1,2)
715 1 | 3 | arc 1 -> 3 | (0,1,3)
716 1 | 4 | arc 1 -> 4 | (0,1,4)
717 2 | 3 | arc 2 -> 3 | (0,2,3)
718 4 | 5 | arc 4 -> 5 | (0,4,5)
719 2 | 3 | arc 2 -> 3 | (1,2,3)
720 4 | 5 | arc 4 -> 5 | (1,4,5)
723 -- various syntax errors
724 with recursive search_graph(f, t, label) as (
725 select * from graph0 g
728 from graph0 g, search_graph sg
730 ) search depth first by foo, tar set seq
731 select * from search_graph;
732 ERROR: search column "foo" not in WITH query column list
733 LINE 7: ) search depth first by foo, tar set seq
735 with recursive search_graph(f, t, label) as (
736 select * from graph0 g
739 from graph0 g, search_graph sg
741 ) search depth first by f, t set label
742 select * from search_graph;
743 ERROR: search sequence column name "label" already used in WITH query column list
744 LINE 7: ) search depth first by f, t set label
746 with recursive search_graph(f, t, label) as (
747 select * from graph0 g
750 from graph0 g, search_graph sg
752 ) search depth first by f, t, f set seq
753 select * from search_graph;
754 ERROR: search column "f" specified more than once
755 LINE 7: ) search depth first by f, t, f set seq
757 with recursive search_graph(f, t, label) as (
758 select * from graph0 g
760 select * from graph0 g
763 from graph0 g, search_graph sg
765 ) search depth first by f, t set seq
766 select * from search_graph order by seq;
767 ERROR: with a SEARCH or CYCLE clause, the left side of the UNION must be a SELECT
768 with recursive search_graph(f, t, label) as (
769 select * from graph0 g
771 (select * from graph0 g
774 from graph0 g, search_graph sg
776 ) search depth first by f, t set seq
777 select * from search_graph order by seq;
778 ERROR: with a SEARCH or CYCLE clause, the right side of the UNION must be a SELECT
779 -- test ruleutils and view expansion
780 create temp view v_search as
781 with recursive search_graph(f, t, label) as (
782 select * from graph0 g
785 from graph0 g, search_graph sg
787 ) search depth first by f, t set seq
788 select f, t, label from search_graph;
789 select pg_get_viewdef('v_search');
791 ------------------------------------------------
792 WITH RECURSIVE search_graph(f, t, label) AS (+
804 ) SEARCH DEPTH FIRST BY f, t SET seq +
805 SELECT search_graph.f, +
811 select * from v_search;
824 -- test cycle detection
826 create temp table graph( f int, t int, label text );
827 insert into graph values
828 (1, 2, 'arc 1 -> 2'),
829 (1, 3, 'arc 1 -> 3'),
830 (2, 3, 'arc 2 -> 3'),
831 (1, 4, 'arc 1 -> 4'),
832 (4, 5, 'arc 4 -> 5'),
833 (5, 1, 'arc 5 -> 1');
834 with recursive search_graph(f, t, label, is_cycle, path) as (
835 select *, false, array[row(g.f, g.t)] from graph g
837 select g.*, row(g.f, g.t) = any(path), path || row(g.f, g.t)
838 from graph g, search_graph sg
839 where g.f = sg.t and not is_cycle
841 select * from search_graph;
842 f | t | label | is_cycle | path
843 ---+---+------------+----------+-------------------------------------------
844 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
845 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
846 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
847 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
848 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
849 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
850 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
851 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
852 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
853 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
854 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
855 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
856 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
857 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
858 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
859 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
860 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
861 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
862 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
863 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
864 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
865 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
866 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
867 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
868 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
871 -- UNION DISTINCT exercises row type hashing support
872 with recursive search_graph(f, t, label, is_cycle, path) as (
873 select *, false, array[row(g.f, g.t)] from graph g
875 select g.*, row(g.f, g.t) = any(path), path || row(g.f, g.t)
876 from graph g, search_graph sg
877 where g.f = sg.t and not is_cycle
879 select * from search_graph;
880 f | t | label | is_cycle | path
881 ---+---+------------+----------+-------------------------------------------
882 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
883 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
884 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
885 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
886 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
887 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
888 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
889 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
890 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
891 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
892 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
893 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
894 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
895 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
896 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
897 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
898 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
899 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
900 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
901 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
902 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
903 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
904 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
905 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
906 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
909 -- ordering by the path column has same effect as SEARCH DEPTH FIRST
910 with recursive search_graph(f, t, label, is_cycle, path) as (
911 select *, false, array[row(g.f, g.t)] from graph g
913 select g.*, row(g.f, g.t) = any(path), path || row(g.f, g.t)
914 from graph g, search_graph sg
915 where g.f = sg.t and not is_cycle
917 select * from search_graph order by path;
918 f | t | label | is_cycle | path
919 ---+---+------------+----------+-------------------------------------------
920 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
921 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
922 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
923 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
924 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
925 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
926 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
927 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
928 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
929 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
930 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
931 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
932 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
933 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
934 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
935 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
936 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
937 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
938 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
939 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
940 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
941 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
942 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
943 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
944 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
948 with recursive search_graph(f, t, label) as (
949 select * from graph g
952 from graph g, search_graph sg
954 ) cycle f, t set is_cycle using path
955 select * from search_graph;
956 f | t | label | is_cycle | path
957 ---+---+------------+----------+-------------------------------------------
958 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
959 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
960 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
961 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
962 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
963 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
964 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
965 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
966 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
967 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
968 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
969 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
970 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
971 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
972 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
973 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
974 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
975 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
976 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
977 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
978 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
979 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
980 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
981 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
982 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
985 with recursive search_graph(f, t, label) as (
986 select * from graph g
989 from graph g, search_graph sg
991 ) cycle f, t set is_cycle to 'Y' default 'N' using path
992 select * from search_graph;
993 f | t | label | is_cycle | path
994 ---+---+------------+----------+-------------------------------------------
995 1 | 2 | arc 1 -> 2 | N | {"(1,2)"}
996 1 | 3 | arc 1 -> 3 | N | {"(1,3)"}
997 2 | 3 | arc 2 -> 3 | N | {"(2,3)"}
998 1 | 4 | arc 1 -> 4 | N | {"(1,4)"}
999 4 | 5 | arc 4 -> 5 | N | {"(4,5)"}
1000 5 | 1 | arc 5 -> 1 | N | {"(5,1)"}
1001 1 | 2 | arc 1 -> 2 | N | {"(5,1)","(1,2)"}
1002 1 | 3 | arc 1 -> 3 | N | {"(5,1)","(1,3)"}
1003 1 | 4 | arc 1 -> 4 | N | {"(5,1)","(1,4)"}
1004 2 | 3 | arc 2 -> 3 | N | {"(1,2)","(2,3)"}
1005 4 | 5 | arc 4 -> 5 | N | {"(1,4)","(4,5)"}
1006 5 | 1 | arc 5 -> 1 | N | {"(4,5)","(5,1)"}
1007 1 | 2 | arc 1 -> 2 | N | {"(4,5)","(5,1)","(1,2)"}
1008 1 | 3 | arc 1 -> 3 | N | {"(4,5)","(5,1)","(1,3)"}
1009 1 | 4 | arc 1 -> 4 | N | {"(4,5)","(5,1)","(1,4)"}
1010 2 | 3 | arc 2 -> 3 | N | {"(5,1)","(1,2)","(2,3)"}
1011 4 | 5 | arc 4 -> 5 | N | {"(5,1)","(1,4)","(4,5)"}
1012 5 | 1 | arc 5 -> 1 | N | {"(1,4)","(4,5)","(5,1)"}
1013 1 | 2 | arc 1 -> 2 | N | {"(1,4)","(4,5)","(5,1)","(1,2)"}
1014 1 | 3 | arc 1 -> 3 | N | {"(1,4)","(4,5)","(5,1)","(1,3)"}
1015 1 | 4 | arc 1 -> 4 | Y | {"(1,4)","(4,5)","(5,1)","(1,4)"}
1016 2 | 3 | arc 2 -> 3 | N | {"(4,5)","(5,1)","(1,2)","(2,3)"}
1017 4 | 5 | arc 4 -> 5 | Y | {"(4,5)","(5,1)","(1,4)","(4,5)"}
1018 5 | 1 | arc 5 -> 1 | Y | {"(5,1)","(1,4)","(4,5)","(5,1)"}
1019 2 | 3 | arc 2 -> 3 | N | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
1024 graph(f, t, label) as (
1025 values (1, 2, 'arc 1 -> 2'),
1026 (1, 3, 'arc 1 -> 3'),
1027 (2, 3, 'arc 2 -> 3'),
1028 (1, 4, 'arc 1 -> 4'),
1029 (4, 5, 'arc 4 -> 5'),
1030 (5, 1, 'arc 5 -> 1')
1032 search_graph(f, t, label) as (
1033 select * from graph g
1036 from graph g, search_graph sg
1038 ) cycle f, t set is_cycle to true default false using path
1039 select f, t, label from search_graph;
1041 ---+---+------------
1070 with recursive a as (
1074 ) cycle b set c using p
1083 with recursive search_graph(f, t, label) as (
1084 select * from graph g
1087 from graph g, search_graph sg
1089 ) search depth first by f, t set seq
1090 cycle f, t set is_cycle using path
1091 select * from search_graph;
1092 f | t | label | seq | is_cycle | path
1093 ---+---+------------+-------------------------------------------+----------+-------------------------------------------
1094 1 | 2 | arc 1 -> 2 | {"(1,2)"} | f | {"(1,2)"}
1095 1 | 3 | arc 1 -> 3 | {"(1,3)"} | f | {"(1,3)"}
1096 2 | 3 | arc 2 -> 3 | {"(2,3)"} | f | {"(2,3)"}
1097 1 | 4 | arc 1 -> 4 | {"(1,4)"} | f | {"(1,4)"}
1098 4 | 5 | arc 4 -> 5 | {"(4,5)"} | f | {"(4,5)"}
1099 5 | 1 | arc 5 -> 1 | {"(5,1)"} | f | {"(5,1)"}
1100 1 | 2 | arc 1 -> 2 | {"(5,1)","(1,2)"} | f | {"(5,1)","(1,2)"}
1101 1 | 3 | arc 1 -> 3 | {"(5,1)","(1,3)"} | f | {"(5,1)","(1,3)"}
1102 1 | 4 | arc 1 -> 4 | {"(5,1)","(1,4)"} | f | {"(5,1)","(1,4)"}
1103 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"} | f | {"(1,2)","(2,3)"}
1104 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"} | f | {"(1,4)","(4,5)"}
1105 5 | 1 | arc 5 -> 1 | {"(4,5)","(5,1)"} | f | {"(4,5)","(5,1)"}
1106 1 | 2 | arc 1 -> 2 | {"(4,5)","(5,1)","(1,2)"} | f | {"(4,5)","(5,1)","(1,2)"}
1107 1 | 3 | arc 1 -> 3 | {"(4,5)","(5,1)","(1,3)"} | f | {"(4,5)","(5,1)","(1,3)"}
1108 1 | 4 | arc 1 -> 4 | {"(4,5)","(5,1)","(1,4)"} | f | {"(4,5)","(5,1)","(1,4)"}
1109 2 | 3 | arc 2 -> 3 | {"(5,1)","(1,2)","(2,3)"} | f | {"(5,1)","(1,2)","(2,3)"}
1110 4 | 5 | arc 4 -> 5 | {"(5,1)","(1,4)","(4,5)"} | f | {"(5,1)","(1,4)","(4,5)"}
1111 5 | 1 | arc 5 -> 1 | {"(1,4)","(4,5)","(5,1)"} | f | {"(1,4)","(4,5)","(5,1)"}
1112 1 | 2 | arc 1 -> 2 | {"(1,4)","(4,5)","(5,1)","(1,2)"} | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
1113 1 | 3 | arc 1 -> 3 | {"(1,4)","(4,5)","(5,1)","(1,3)"} | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
1114 1 | 4 | arc 1 -> 4 | {"(1,4)","(4,5)","(5,1)","(1,4)"} | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
1115 2 | 3 | arc 2 -> 3 | {"(4,5)","(5,1)","(1,2)","(2,3)"} | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
1116 4 | 5 | arc 4 -> 5 | {"(4,5)","(5,1)","(1,4)","(4,5)"} | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
1117 5 | 1 | arc 5 -> 1 | {"(5,1)","(1,4)","(4,5)","(5,1)"} | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
1118 2 | 3 | arc 2 -> 3 | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
1121 with recursive search_graph(f, t, label) as (
1122 select * from graph g
1125 from graph g, search_graph sg
1127 ) search breadth first by f, t set seq
1128 cycle f, t set is_cycle using path
1129 select * from search_graph;
1130 f | t | label | seq | is_cycle | path
1131 ---+---+------------+---------+----------+-------------------------------------------
1132 1 | 2 | arc 1 -> 2 | (0,1,2) | f | {"(1,2)"}
1133 1 | 3 | arc 1 -> 3 | (0,1,3) | f | {"(1,3)"}
1134 2 | 3 | arc 2 -> 3 | (0,2,3) | f | {"(2,3)"}
1135 1 | 4 | arc 1 -> 4 | (0,1,4) | f | {"(1,4)"}
1136 4 | 5 | arc 4 -> 5 | (0,4,5) | f | {"(4,5)"}
1137 5 | 1 | arc 5 -> 1 | (0,5,1) | f | {"(5,1)"}
1138 1 | 2 | arc 1 -> 2 | (1,1,2) | f | {"(5,1)","(1,2)"}
1139 1 | 3 | arc 1 -> 3 | (1,1,3) | f | {"(5,1)","(1,3)"}
1140 1 | 4 | arc 1 -> 4 | (1,1,4) | f | {"(5,1)","(1,4)"}
1141 2 | 3 | arc 2 -> 3 | (1,2,3) | f | {"(1,2)","(2,3)"}
1142 4 | 5 | arc 4 -> 5 | (1,4,5) | f | {"(1,4)","(4,5)"}
1143 5 | 1 | arc 5 -> 1 | (1,5,1) | f | {"(4,5)","(5,1)"}
1144 1 | 2 | arc 1 -> 2 | (2,1,2) | f | {"(4,5)","(5,1)","(1,2)"}
1145 1 | 3 | arc 1 -> 3 | (2,1,3) | f | {"(4,5)","(5,1)","(1,3)"}
1146 1 | 4 | arc 1 -> 4 | (2,1,4) | f | {"(4,5)","(5,1)","(1,4)"}
1147 2 | 3 | arc 2 -> 3 | (2,2,3) | f | {"(5,1)","(1,2)","(2,3)"}
1148 4 | 5 | arc 4 -> 5 | (2,4,5) | f | {"(5,1)","(1,4)","(4,5)"}
1149 5 | 1 | arc 5 -> 1 | (2,5,1) | f | {"(1,4)","(4,5)","(5,1)"}
1150 1 | 2 | arc 1 -> 2 | (3,1,2) | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
1151 1 | 3 | arc 1 -> 3 | (3,1,3) | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
1152 1 | 4 | arc 1 -> 4 | (3,1,4) | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
1153 2 | 3 | arc 2 -> 3 | (3,2,3) | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
1154 4 | 5 | arc 4 -> 5 | (3,4,5) | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
1155 5 | 1 | arc 5 -> 1 | (3,5,1) | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
1156 2 | 3 | arc 2 -> 3 | (4,2,3) | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
1159 -- various syntax errors
1160 with recursive search_graph(f, t, label) as (
1161 select * from graph g
1164 from graph g, search_graph sg
1166 ) cycle foo, tar set is_cycle using path
1167 select * from search_graph;
1168 ERROR: cycle column "foo" not in WITH query column list
1169 LINE 7: ) cycle foo, tar set is_cycle using path
1171 with recursive search_graph(f, t, label) as (
1172 select * from graph g
1175 from graph g, search_graph sg
1177 ) cycle f, t set is_cycle to true default 55 using path
1178 select * from search_graph;
1179 ERROR: CYCLE types boolean and integer cannot be matched
1180 LINE 7: ) cycle f, t set is_cycle to true default 55 using path
1182 with recursive search_graph(f, t, label) as (
1183 select * from graph g
1186 from graph g, search_graph sg
1188 ) cycle f, t set is_cycle to point '(1,1)' default point '(0,0)' using path
1189 select * from search_graph;
1190 ERROR: could not identify an equality operator for type point
1191 with recursive search_graph(f, t, label) as (
1192 select * from graph g
1195 from graph g, search_graph sg
1197 ) cycle f, t set label to true default false using path
1198 select * from search_graph;
1199 ERROR: cycle mark column name "label" already used in WITH query column list
1200 LINE 7: ) cycle f, t set label to true default false using path
1202 with recursive search_graph(f, t, label) as (
1203 select * from graph g
1206 from graph g, search_graph sg
1208 ) cycle f, t set is_cycle to true default false using label
1209 select * from search_graph;
1210 ERROR: cycle path column name "label" already used in WITH query column list
1211 LINE 7: ) cycle f, t set is_cycle to true default false using label
1213 with recursive search_graph(f, t, label) as (
1214 select * from graph g
1217 from graph g, search_graph sg
1219 ) cycle f, t set foo to true default false using foo
1220 select * from search_graph;
1221 ERROR: cycle mark column name and cycle path column name are the same
1222 LINE 7: ) cycle f, t set foo to true default false using foo
1224 with recursive search_graph(f, t, label) as (
1225 select * from graph g
1228 from graph g, search_graph sg
1230 ) cycle f, t, f set is_cycle to true default false using path
1231 select * from search_graph;
1232 ERROR: cycle column "f" specified more than once
1233 LINE 7: ) cycle f, t, f set is_cycle to true default false using pat...
1235 with recursive search_graph(f, t, label) as (
1236 select * from graph g
1239 from graph g, search_graph sg
1241 ) search depth first by f, t set foo
1242 cycle f, t set foo to true default false using path
1243 select * from search_graph;
1244 ERROR: search sequence column name and cycle mark column name are the same
1245 LINE 7: ) search depth first by f, t set foo
1247 with recursive search_graph(f, t, label) as (
1248 select * from graph g
1251 from graph g, search_graph sg
1253 ) search depth first by f, t set foo
1254 cycle f, t set is_cycle to true default false using foo
1255 select * from search_graph;
1256 ERROR: search sequence column name and cycle path column name are the same
1257 LINE 7: ) search depth first by f, t set foo
1259 -- test ruleutils and view expansion
1260 create temp view v_cycle1 as
1261 with recursive search_graph(f, t, label) as (
1262 select * from graph g
1265 from graph g, search_graph sg
1267 ) cycle f, t set is_cycle using path
1268 select f, t, label from search_graph;
1269 create temp view v_cycle2 as
1270 with recursive search_graph(f, t, label) as (
1271 select * from graph g
1274 from graph g, search_graph sg
1276 ) cycle f, t set is_cycle to 'Y' default 'N' using path
1277 select f, t, label from search_graph;
1278 select pg_get_viewdef('v_cycle1');
1280 ------------------------------------------------
1281 WITH RECURSIVE search_graph(f, t, label) AS (+
1292 WHERE (g.f = sg.t) +
1293 ) CYCLE f, t SET is_cycle USING path +
1294 SELECT search_graph.f, +
1296 search_graph.label +
1300 select pg_get_viewdef('v_cycle2');
1302 -----------------------------------------------------------------------------
1303 WITH RECURSIVE search_graph(f, t, label) AS ( +
1314 WHERE (g.f = sg.t) +
1315 ) CYCLE f, t SET is_cycle TO 'Y'::text DEFAULT 'N'::text USING path+
1316 SELECT search_graph.f, +
1318 search_graph.label +
1322 select * from v_cycle1;
1324 ---+---+------------
1352 select * from v_cycle2;
1354 ---+---+------------
1383 -- test multiple WITH queries
1386 y (id) AS (VALUES (1)),
1387 x (id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5)
1398 -- forward reference OK
1400 x(id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5),
1401 y(id) AS (values (1))
1414 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
1416 (VALUES (1) UNION ALL SELECT id+1 FROM y WHERE id < 10)
1417 SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
1434 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
1436 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 10)
1437 SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
1450 (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
1452 (SELECT * FROM x UNION ALL SELECT * FROM x),
1454 (SELECT * FROM x UNION ALL SELECT id+1 FROM z WHERE id < 10)
1489 (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
1491 (SELECT * FROM x UNION ALL SELECT * FROM x),
1493 (SELECT * FROM y UNION ALL SELECT id+1 FROM z WHERE id < 10)
1554 -- Test WITH attached to a data-modifying statement
1556 CREATE TEMPORARY TABLE y (a INTEGER);
1557 INSERT INTO y SELECT generate_series(1, 10);
1562 SELECT a+20 FROM t RETURNING *;
1605 UPDATE y SET a = y.a-10 FROM t WHERE y.a > 20 AND t.a = y.a RETURNING y.a;
1645 WITH RECURSIVE t(a) AS (
1648 SELECT a+1 FROM t WHERE a < 50
1650 DELETE FROM y USING t WHERE t.a = y.a RETURNING y.a;
1685 WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x)
1687 ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
1688 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x...
1690 WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FROM x)
1692 ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
1693 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FR...
1696 WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x)
1698 ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
1699 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x)
1701 WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM x)
1703 ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
1704 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM ...
1706 -- no non-recursive term
1707 WITH RECURSIVE x(n) AS (SELECT n FROM x)
1709 ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
1710 LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x)
1712 -- recursive term in the left hand side (strictly speaking, should allow this)
1713 WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
1715 ERROR: recursive reference to query "x" must not appear within its non-recursive term
1716 LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
1718 CREATE TEMPORARY TABLE y (a INTEGER);
1719 INSERT INTO y SELECT generate_series(1, 10);
1721 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
1723 SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10)
1725 ERROR: recursive reference to query "x" must not appear within an outer join
1726 LINE 3: SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10)
1729 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
1731 SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10)
1733 ERROR: recursive reference to query "x" must not appear within an outer join
1734 LINE 3: SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10)
1737 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
1739 SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10)
1741 ERROR: recursive reference to query "x" must not appear within an outer join
1742 LINE 3: SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10)
1745 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x
1746 WHERE n IN (SELECT * FROM x))
1748 ERROR: recursive reference to query "x" must not appear within a subquery
1749 LINE 2: WHERE n IN (SELECT * FROM x))
1751 -- aggregate functions
1752 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) FROM x)
1754 ERROR: aggregate functions are not allowed in a recursive query's recursive term
1755 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) F...
1757 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FROM x)
1759 ERROR: aggregate functions are not allowed in a recursive query's recursive term
1760 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FRO...
1763 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1)
1765 ERROR: ORDER BY in a recursive query is not implemented
1766 LINE 1: ...VE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1)
1769 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1)
1771 ERROR: OFFSET in a recursive query is not implemented
1772 LINE 1: ... AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1)
1775 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x FOR UPDATE)
1777 ERROR: FOR UPDATE/SHARE in a recursive query is not implemented
1778 -- target list has a recursive query name
1779 WITH RECURSIVE x(id) AS (values (1)
1781 SELECT (SELECT * FROM x) FROM x WHERE id < 5
1783 ERROR: recursive reference to query "x" must not appear within a subquery
1784 LINE 3: SELECT (SELECT * FROM x) FROM x WHERE id < 5
1786 -- mutual recursive query (not implemented)
1788 x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id < 5),
1789 y (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 5)
1791 ERROR: mutual recursion between WITH items is not implemented
1792 LINE 2: x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id ...
1794 -- non-linear recursion is not allowed
1795 WITH RECURSIVE foo(i) AS
1798 (SELECT i+1 FROM foo WHERE i < 10
1800 SELECT i+1 FROM foo WHERE i < 5)
1801 ) SELECT * FROM foo;
1802 ERROR: recursive reference to query "foo" must not appear more than once
1803 LINE 6: SELECT i+1 FROM foo WHERE i < 5)
1805 WITH RECURSIVE foo(i) AS
1809 (SELECT i+1 FROM foo WHERE i < 10
1811 SELECT i+1 FROM foo WHERE i < 5) AS t
1812 ) SELECT * FROM foo;
1813 ERROR: recursive reference to query "foo" must not appear more than once
1814 LINE 7: SELECT i+1 FROM foo WHERE i < 5) AS t
1816 WITH RECURSIVE foo(i) AS
1819 (SELECT i+1 FROM foo WHERE i < 10
1821 SELECT i+1 FROM foo WHERE i < 5)
1822 ) SELECT * FROM foo;
1823 ERROR: recursive reference to query "foo" must not appear within EXCEPT
1824 LINE 6: SELECT i+1 FROM foo WHERE i < 5)
1826 WITH RECURSIVE foo(i) AS
1829 (SELECT i+1 FROM foo WHERE i < 10
1831 SELECT i+1 FROM foo WHERE i < 5)
1832 ) SELECT * FROM foo;
1833 ERROR: recursive reference to query "foo" must not appear more than once
1834 LINE 6: SELECT i+1 FROM foo WHERE i < 5)
1836 -- Wrong type induced from non-recursive term
1837 WITH RECURSIVE foo(i) AS
1838 (SELECT i FROM (VALUES(1),(2)) t(i)
1840 SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
1842 ERROR: recursive query "foo" column 1 has type integer in non-recursive term but type numeric overall
1843 LINE 2: (SELECT i FROM (VALUES(1),(2)) t(i)
1845 HINT: Cast the output of the non-recursive term to the correct type.
1846 -- rejects different typmod, too (should we allow this?)
1847 WITH RECURSIVE foo(i) AS
1848 (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
1850 SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
1852 ERROR: recursive query "foo" column 1 has type numeric(3,0) in non-recursive term but type numeric overall
1853 LINE 2: (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
1855 HINT: Cast the output of the non-recursive term to the correct type.
1856 -- disallow OLD/NEW reference in CTE
1857 CREATE TEMPORARY TABLE x (n integer);
1858 CREATE RULE r2 AS ON UPDATE TO x DO INSTEAD
1859 WITH t AS (SELECT OLD.*) UPDATE y SET a = t.n FROM t;
1860 ERROR: cannot refer to OLD within WITH query
1862 -- test for bug #4902
1864 with cte(foo) as ( values(42) ) values((select foo from cte));
1870 with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q;
1876 -- test CTE referencing an outer-level variable (to see that changed-parameter
1877 -- signaling still works properly after fixing this bug)
1878 select ( with cte(foo) as ( values(f1) )
1879 select (select foo from cte) )
1890 select ( with cte(foo) as ( values(f1) )
1891 values((select foo from cte)) )
1903 -- test for nested-recursive-WITH bug
1905 WITH RECURSIVE t(j) AS (
1906 WITH RECURSIVE s(i) AS (
1909 SELECT i+1 FROM s WHERE i < 10
1913 SELECT j+1 FROM t WHERE j < 10
1976 -- test WITH attached to intermediate-level set operation
1978 WITH outermost(x) AS (
1980 UNION (WITH innermost as (SELECT 2)
1981 SELECT * FROM innermost
1984 SELECT * FROM outermost ORDER BY 1;
1992 WITH outermost(x) AS (
1994 UNION (WITH innermost as (SELECT 2)
1995 SELECT * FROM outermost -- fail
1996 UNION SELECT * FROM innermost)
1998 SELECT * FROM outermost ORDER BY 1;
1999 ERROR: relation "outermost" does not exist
2000 LINE 4: SELECT * FROM outermost
2002 DETAIL: There is a WITH item named "outermost", but it cannot be referenced from this part of the query.
2003 HINT: Use WITH RECURSIVE, or re-order the WITH items to remove forward references.
2004 WITH RECURSIVE outermost(x) AS (
2006 UNION (WITH innermost as (SELECT 2)
2007 SELECT * FROM outermost
2008 UNION SELECT * FROM innermost)
2010 SELECT * FROM outermost ORDER BY 1;
2017 WITH RECURSIVE outermost(x) AS (
2018 WITH innermost as (SELECT 2 FROM outermost) -- fail
2019 SELECT * FROM innermost
2020 UNION SELECT * from outermost
2022 SELECT * FROM outermost ORDER BY 1;
2023 ERROR: recursive reference to query "outermost" must not appear within a subquery
2024 LINE 2: WITH innermost as (SELECT 2 FROM outermost)
2027 -- This test will fail with the old implementation of PARAM_EXEC parameter
2028 -- assignment, because the "q1" Var passed down to A's targetlist subselect
2029 -- looks exactly like the "A.id" Var passed down to C's subselect, causing
2030 -- the old code to give them the same runtime PARAM_EXEC slot. But the
2031 -- lifespans of the two parameters overlap, thanks to B also reading A.
2034 A as ( select q2 as id, (select q1) as x from int8_tbl ),
2035 B as ( select id, row_number() over (partition by id) as r from A ),
2036 C as ( select A.id, array(select B.id from B where B.id = A.id) from A )
2039 -------------------+-------------------------------------
2041 4567890123456789 | {4567890123456789,4567890123456789}
2043 4567890123456789 | {4567890123456789,4567890123456789}
2044 -4567890123456789 | {-4567890123456789}
2048 -- Test CTEs read in non-initialization orders
2051 tab(id_key,link) AS (VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17)),
2052 iter (id_key, row_type, link) AS (
2053 SELECT 0, 'base', 17
2055 WITH remaining(id_key, row_type, link, min) AS (
2056 SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
2057 FROM tab INNER JOIN iter USING (link)
2058 WHERE tab.id_key > iter.id_key
2060 first_remaining AS (
2061 SELECT id_key, row_type, link
2066 SELECT tab.id_key, 'new'::text, tab.link
2067 FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
2068 WHERE e.row_type = 'false'
2070 SELECT * FROM first_remaining
2071 UNION ALL SELECT * FROM effect
2075 id_key | row_type | link
2076 --------+----------+------
2087 tab(id_key,link) AS (VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17)),
2088 iter (id_key, row_type, link) AS (
2089 SELECT 0, 'base', 17
2091 WITH remaining(id_key, row_type, link, min) AS (
2092 SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
2093 FROM tab INNER JOIN iter USING (link)
2094 WHERE tab.id_key > iter.id_key
2096 first_remaining AS (
2097 SELECT id_key, row_type, link
2102 SELECT tab.id_key, 'new'::text, tab.link
2103 FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
2104 WHERE e.row_type = 'false'
2106 SELECT * FROM first_remaining
2107 UNION ALL SELECT * FROM effect
2111 id_key | row_type | link
2112 --------+----------+------
2123 -- Data-modifying statements in WITH
2125 -- INSERT ... RETURNING
2181 -- UPDATE ... RETURNING
2237 -- DELETE ... RETURNING
2273 -- forward reference
2274 WITH RECURSIVE t AS (
2276 SELECT a+5 FROM t2 WHERE a > 5
2279 UPDATE y SET a=a-11 RETURNING *
2325 -- unconditional DO INSTEAD rule
2326 CREATE RULE y_rule AS ON DELETE TO y DO INSTEAD
2327 INSERT INTO y VALUES(42) RETURNING *;
2329 DELETE FROM y RETURNING *
2359 DROP RULE y_rule ON y;
2360 -- check merging of outer CTE with CTE in a rule action
2361 CREATE TEMP TABLE bug6051 AS
2362 select i from generate_series(1,3) as t(i);
2363 SELECT * FROM bug6051;
2371 WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
2372 INSERT INTO bug6051 SELECT * FROM t1;
2373 SELECT * FROM bug6051;
2381 CREATE TEMP TABLE bug6051_2 (i int);
2382 CREATE RULE bug6051_ins AS ON INSERT TO bug6051 DO INSTEAD
2383 INSERT INTO bug6051_2
2385 WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
2386 INSERT INTO bug6051 SELECT * FROM t1;
2387 SELECT * FROM bug6051;
2392 SELECT * FROM bug6051_2;
2400 -- a truly recursive CTE in the same list
2401 WITH RECURSIVE t(a) AS (
2404 SELECT a+1 FROM t WHERE a+1 < 5
2407 SELECT * FROM t RETURNING *
2409 SELECT * FROM t2 JOIN y USING (a) ORDER BY a;
2446 -- data-modifying WITH in a modifying statement
2452 INSERT INTO y SELECT -a FROM t RETURNING *;
2500 -- check that WITH query is run to completion even if outer query isn't
2502 UPDATE y SET a = a * 100 RETURNING *
2504 SELECT * FROM t LIMIT 10;
2546 -- data-modifying WITH containing INSERT...ON CONFLICT DO UPDATE
2547 CREATE TABLE withz AS SELECT i AS k, (i || ' v')::text v FROM generate_series(1, 16, 3) i;
2548 ALTER TABLE withz ADD UNIQUE (k);
2550 INSERT INTO withz SELECT i, 'insert'
2551 FROM generate_series(0, 16) i
2552 ON CONFLICT (k) DO UPDATE SET v = withz.v || ', now update'
2555 SELECT * FROM t JOIN y ON t.k = y.a ORDER BY a, k;
2562 -- Test EXCLUDED.* reference within CTE
2564 INSERT INTO withz VALUES(1, 5) ON CONFLICT (k) DO UPDATE SET v = EXCLUDED.v
2565 WHERE withz.k != EXCLUDED.k
2573 -- New query/snapshot demonstrates side-effects of previous query.
2574 SELECT * FROM withz ORDER BY k;
2576 ----+------------------
2587 10 | 10 v, now update
2590 13 | 13 v, now update
2593 16 | 16 v, now update
2597 -- Ensure subqueries within the update clause work, even if they
2598 -- reference outside values
2600 WITH aa AS (SELECT 1 a, 2 b)
2601 INSERT INTO withz VALUES(1, 'insert')
2602 ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
2603 WITH aa AS (SELECT 1 a, 2 b)
2604 INSERT INTO withz VALUES(1, 'insert')
2605 ON CONFLICT (k) DO UPDATE SET v = ' update' WHERE withz.k = (SELECT a FROM aa);
2606 WITH aa AS (SELECT 1 a, 2 b)
2607 INSERT INTO withz VALUES(1, 'insert')
2608 ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
2609 WITH aa AS (SELECT 'a' a, 'b' b UNION ALL SELECT 'a' a, 'b' b)
2610 INSERT INTO withz VALUES(1, 'insert')
2611 ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 'a' LIMIT 1);
2612 WITH aa AS (SELECT 1 a, 2 b)
2613 INSERT INTO withz VALUES(1, (SELECT b || ' insert' FROM aa WHERE a = 1 ))
2614 ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
2615 -- Update a row more than once, in different parts of a wCTE. That is
2616 -- an allowed, presumably very rare, edge case, but since it was
2617 -- broken in the past, having a test seems worthwhile.
2619 SELECT 2 k, 'Green' v),
2621 INSERT INTO withz VALUES(2, 'Blue') ON CONFLICT (k) DO
2622 UPDATE SET (k, v) = (SELECT k, v FROM simpletup WHERE simpletup.k = withz.k)
2624 INSERT INTO withz VALUES(2, 'Red') ON CONFLICT (k) DO
2625 UPDATE SET (k, v) = (SELECT k, v FROM upsert_cte WHERE upsert_cte.k = withz.k)
2632 -- check that run to completion happens in proper ordering
2634 INSERT INTO y SELECT generate_series(1, 3);
2635 CREATE TEMPORARY TABLE yy (a INTEGER);
2636 WITH RECURSIVE t1 AS (
2637 INSERT INTO y SELECT * FROM y RETURNING *
2639 INSERT INTO yy SELECT * FROM t1 RETURNING *
2666 WITH RECURSIVE t1 AS (
2667 INSERT INTO yy SELECT * FROM t2 RETURNING *
2669 INSERT INTO y SELECT * FROM y RETURNING *
2710 INSERT INTO y SELECT generate_series(1, 10);
2711 CREATE FUNCTION y_trigger() RETURNS trigger AS $$
2713 raise notice 'y_trigger: a = %', new.a;
2716 $$ LANGUAGE plpgsql;
2717 CREATE TRIGGER y_trig BEFORE INSERT ON y FOR EACH ROW
2718 EXECUTE PROCEDURE y_trigger();
2728 NOTICE: y_trigger: a = 21
2729 NOTICE: y_trigger: a = 22
2730 NOTICE: y_trigger: a = 23
2756 DROP TRIGGER y_trig ON y;
2757 CREATE TRIGGER y_trig AFTER INSERT ON y FOR EACH ROW
2758 EXECUTE PROCEDURE y_trigger();
2767 SELECT * FROM t LIMIT 1;
2768 NOTICE: y_trigger: a = 31
2769 NOTICE: y_trigger: a = 32
2770 NOTICE: y_trigger: a = 33
2797 DROP TRIGGER y_trig ON y;
2798 CREATE OR REPLACE FUNCTION y_trigger() RETURNS trigger AS $$
2800 raise notice 'y_trigger';
2803 $$ LANGUAGE plpgsql;
2804 CREATE TRIGGER y_trig AFTER INSERT ON y FOR EACH STATEMENT
2805 EXECUTE PROCEDURE y_trigger();
2847 DROP TRIGGER y_trig ON y;
2848 DROP FUNCTION y_trigger();
2849 -- WITH attached to inherited UPDATE or DELETE
2850 CREATE TEMP TABLE parent ( id int, val text );
2851 CREATE TEMP TABLE child1 ( ) INHERITS ( parent );
2852 CREATE TEMP TABLE child2 ( ) INHERITS ( parent );
2853 INSERT INTO parent VALUES ( 1, 'p1' );
2854 INSERT INTO child1 VALUES ( 11, 'c11' ),( 12, 'c12' );
2855 INSERT INTO child2 VALUES ( 23, 'c21' ),( 24, 'c22' );
2856 WITH rcte AS ( SELECT sum(id) AS totalid FROM parent )
2857 UPDATE parent SET id = id + totalid FROM rcte;
2858 SELECT * FROM parent;
2868 WITH wcte AS ( INSERT INTO child1 VALUES ( 42, 'new' ) RETURNING id AS newid )
2869 UPDATE parent SET id = id + newid FROM wcte;
2870 SELECT * FROM parent;
2881 WITH rcte AS ( SELECT max(id) AS maxid FROM parent )
2882 DELETE FROM parent USING rcte WHERE id = maxid;
2883 SELECT * FROM parent;
2893 WITH wcte AS ( INSERT INTO child2 VALUES ( 42, 'new2' ) RETURNING id AS newid )
2894 DELETE FROM parent USING wcte WHERE id = newid;
2895 SELECT * FROM parent;
2905 -- check EXPLAIN VERBOSE for a wCTE with RETURNING
2906 EXPLAIN (VERBOSE, COSTS OFF)
2907 WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 )
2908 DELETE FROM a USING wcte WHERE aa = q2;
2910 ------------------------------------------------------------
2912 Delete on public.a a_1
2913 Delete on public.b a_2
2914 Delete on public.c a_3
2915 Delete on public.d a_4
2917 -> Insert on public.int8_tbl
2920 Output: '42'::bigint, '47'::bigint
2922 Output: wcte.*, a.tableoid, a.ctid
2923 Hash Cond: (a.aa = wcte.q2)
2925 -> Seq Scan on public.a a_1
2926 Output: a_1.aa, a_1.tableoid, a_1.ctid
2927 -> Seq Scan on public.b a_2
2928 Output: a_2.aa, a_2.tableoid, a_2.ctid
2929 -> Seq Scan on public.c a_3
2930 Output: a_3.aa, a_3.tableoid, a_3.ctid
2931 -> Seq Scan on public.d a_4
2932 Output: a_4.aa, a_4.tableoid, a_4.ctid
2934 Output: wcte.*, wcte.q2
2936 Output: wcte.*, wcte.q2
2940 -- data-modifying WITH tries to use its own output
2941 WITH RECURSIVE t AS (
2946 ERROR: recursive query "t" must not contain data-modifying statements
2947 LINE 1: WITH RECURSIVE t AS (
2949 -- no RETURNING in a referenced data-modifying WITH
2951 INSERT INTO y VALUES(0)
2954 ERROR: WITH query "t" does not have a RETURNING clause
2955 LINE 4: SELECT * FROM t;
2957 -- data-modifying WITH allowed only at the top level
2959 WITH t AS (UPDATE y SET a=a+1 RETURNING *)
2962 ERROR: WITH clause containing a data-modifying statement must be at the top level
2963 LINE 2: WITH t AS (UPDATE y SET a=a+1 RETURNING *)
2965 -- most variants of rules aren't allowed
2966 CREATE RULE y_rule AS ON INSERT TO y WHERE a=0 DO INSTEAD DELETE FROM y;
2968 INSERT INTO y VALUES(0)
2971 ERROR: conditional DO INSTEAD rules are not supported for data-modifying statements in WITH
2972 CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTHING;
2974 INSERT INTO y VALUES(0)
2977 ERROR: DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH
2978 CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTIFY foo;
2980 INSERT INTO y VALUES(0)
2983 ERROR: DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH
2984 CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO ALSO NOTIFY foo;
2986 INSERT INTO y VALUES(0)
2989 ERROR: DO ALSO rules are not supported for data-modifying statements in WITH
2990 CREATE OR REPLACE RULE y_rule AS ON INSERT TO y
2991 DO INSTEAD (NOTIFY foo; NOTIFY bar);
2993 INSERT INTO y VALUES(0)
2996 ERROR: multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH
2997 DROP RULE y_rule ON y;
2998 -- check that parser lookahead for WITH doesn't cause any odd behavior
2999 create table foo (with baz); -- fail, WITH is a reserved word
3000 ERROR: syntax error at or near "with"
3001 LINE 1: create table foo (with baz);
3003 create table foo (with ordinality); -- fail, WITH is a reserved word
3004 ERROR: syntax error at or near "with"
3005 LINE 1: create table foo (with ordinality);
3007 with ordinality as (select 1 as x) select * from ordinality;
3013 -- check sane response to attempt to modify CTE relation
3014 WITH test AS (SELECT 42) INSERT INTO test VALUES (1);
3015 ERROR: relation "test" does not exist
3016 LINE 1: WITH test AS (SELECT 42) INSERT INTO test VALUES (1);
3018 -- check response to attempt to modify table with same name as a CTE (perhaps
3019 -- surprisingly it works, because CTEs don't hide tables from data-modifying
3021 create temp table test (i int);
3022 with test as (select 42) insert into test select * from test;