diff options
author | Peter Eisentraut | 2013-02-01 03:31:58 +0000 |
---|---|---|
committer | Peter Eisentraut | 2013-02-01 03:31:58 +0000 |
commit | 583905269378bf41c24585773885b1e226a998ce (patch) | |
tree | 0e71e7a73c716f1b6fc00840af5642dd73fd2878 /src | |
parent | b1980f6d03f79ab57da8f32aa8cd9677dbe1d58f (diff) |
Add CREATE RECURSIVE VIEW syntax
This is specified in the SQL standard. The CREATE RECURSIVE VIEW
specification is transformed into a normal CREATE VIEW statement with a
WITH RECURSIVE clause.
reviewed by Abhijit Menon-Sen and Stephen Frost
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/parser/gram.y | 85 | ||||
-rw-r--r-- | src/test/regress/expected/with.out | 30 | ||||
-rw-r--r-- | src/test/regress/sql/with.sql | 15 |
3 files changed, 130 insertions, 0 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a2078ec95e..342b796424 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -164,6 +164,7 @@ static void SplitColQualList(List *qualList, static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); +static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %} @@ -7839,6 +7840,30 @@ ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions n->options = $8; $$ = (Node *) n; } + | CREATE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions + AS SelectStmt + { + ViewStmt *n = makeNode(ViewStmt); + n->view = $5; + n->view->relpersistence = $2; + n->aliases = $7; + n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $11); + n->replace = false; + n->options = $9; + $$ = (Node *) n; + } + | CREATE OR REPLACE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions + AS SelectStmt + { + ViewStmt *n = makeNode(ViewStmt); + n->view = $7; + n->view->relpersistence = $4; + n->aliases = $9; + n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $13); + n->replace = true; + n->options = $11; + $$ = (Node *) n; + } ; opt_check_option: @@ -13570,6 +13595,66 @@ processCASbits(int cas_bits, int location, const char *constrType, } } +/*---------- + * Recursive view transformation + * + * Convert + * + * CREATE RECURSIVE VIEW relname (aliases) AS query + * + * to + * + * CREATE VIEW relname (aliases) AS + * WITH RECURSIVE relname (aliases) AS (query) + * SELECT aliases FROM relname + * + * Actually, just the WITH ... part, which is then inserted into the original + * view definition as the query. + * ---------- + */ +static Node * +makeRecursiveViewSelect(char *relname, List *aliases, Node *query) +{ + SelectStmt *s = makeNode(SelectStmt); + WithClause *w = makeNode(WithClause); + CommonTableExpr *cte = makeNode(CommonTableExpr); + List *tl = NIL; + ListCell *lc; + + /* create common table expression */ + cte->ctename = relname; + cte->aliascolnames = aliases; + cte->ctequery = query; + cte->location = -1; + + /* create WITH clause and attach CTE */ + w->recursive = true; + w->ctes = list_make1(cte); + w->location = -1; + + /* create target list for the new SELECT from the alias list of the + * recursive view specification */ + foreach (lc, aliases) + { + ResTarget *rt = makeNode(ResTarget); + + rt->name = NULL; + rt->indirection = NIL; + rt->val = makeColumnRef(strVal(lfirst(lc)), NIL, -1, 0); + rt->location = -1; + + tl = lappend(tl, rt); + } + + /* create new SELECT combining WITH clause, target list, and fake FROM + * clause */ + s->withClause = w; + s->targetList = tl; + s->fromClause = list_make1(makeRangeVar(NULL, relname, -1)); + + return (Node *) s; +} + /* parser_init() * Initialize to parse one query string */ diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index b98ca630ee..272118f7b7 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -49,6 +49,36 @@ SELECT * FROM t; 5 (5 rows) +-- recursive view +CREATE RECURSIVE VIEW nums (n) AS + VALUES (1) +UNION ALL + SELECT n+1 FROM nums WHERE n < 5; +SELECT * FROM nums; + n +--- + 1 + 2 + 3 + 4 + 5 +(5 rows) + +CREATE OR REPLACE RECURSIVE VIEW nums (n) AS + VALUES (1) +UNION ALL + SELECT n+1 FROM nums WHERE n < 6; +SELECT * FROM nums; + n +--- + 1 + 2 + 3 + 4 + 5 + 6 +(6 rows) + -- This is an infinite loop with UNION ALL, but not with UNION WITH RECURSIVE t(n) AS ( SELECT 1 diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index 4ff852736b..c716369957 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -31,6 +31,21 @@ UNION ALL ) SELECT * FROM t; +-- recursive view +CREATE RECURSIVE VIEW nums (n) AS + VALUES (1) +UNION ALL + SELECT n+1 FROM nums WHERE n < 5; + +SELECT * FROM nums; + +CREATE OR REPLACE RECURSIVE VIEW nums (n) AS + VALUES (1) +UNION ALL + SELECT n+1 FROM nums WHERE n < 6; + +SELECT * FROM nums; + -- This is an infinite loop with UNION ALL, but not with UNION WITH RECURSIVE t(n) AS ( SELECT 1 |