diff options
Diffstat (limited to 'src/backend/parser/parse_cte.c')
-rw-r--r-- | src/backend/parser/parse_cte.c | 203 |
1 files changed, 103 insertions, 100 deletions
diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c index 7da578c22f..c18b4336ad 100644 --- a/src/backend/parser/parse_cte.c +++ b/src/backend/parser/parse_cte.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_cte.c,v 2.5 2009/01/01 17:23:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_cte.c,v 2.6 2009/06/11 14:49:00 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -25,7 +25,7 @@ typedef enum { RECURSION_OK, - RECURSION_NONRECURSIVETERM, /* inside the left-hand term */ + RECURSION_NONRECURSIVETERM, /* inside the left-hand term */ RECURSION_SUBLINK, /* inside a sublink */ RECURSION_OUTERJOIN, /* inside nullable side of an outer join */ RECURSION_INTERSECT, /* underneath INTERSECT (ALL) */ @@ -33,7 +33,7 @@ typedef enum } RecursionContext; /* Associated error messages --- each must have one %s for CTE name */ -static const char * const recursion_errormsgs[] = { +static const char *const recursion_errormsgs[] = { /* RECURSION_OK */ NULL, /* RECURSION_NONRECURSIVETERM */ @@ -56,10 +56,11 @@ static const char * const recursion_errormsgs[] = { */ typedef struct CteItem { - CommonTableExpr *cte; /* One CTE to examine */ - int id; /* Its ID number for dependencies */ - Node *non_recursive_term; /* Its nonrecursive part, if identified */ - Bitmapset *depends_on; /* CTEs depended on (not including self) */ + CommonTableExpr *cte; /* One CTE to examine */ + int id; /* Its ID number for dependencies */ + Node *non_recursive_term; /* Its nonrecursive part, if + * identified */ + Bitmapset *depends_on; /* CTEs depended on (not including self) */ } CteItem; /* CteState is what we need to pass around in the tree walkers */ @@ -67,7 +68,7 @@ typedef struct CteState { /* global state: */ ParseState *pstate; /* global parse state */ - CteItem *items; /* array of CTEs and extra data */ + CteItem *items; /* array of CTEs and extra data */ int numitems; /* number of CTEs */ /* working state during a tree walk: */ int curitem; /* index of item currently being examined */ @@ -94,8 +95,8 @@ static void checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate); /* * transformWithClause - - * Transform the list of WITH clause "common table expressions" into - * Query nodes. + * Transform the list of WITH clause "common table expressions" into + * Query nodes. * * The result is the list of transformed CTEs to be put into the output * Query. (This is in fact the same as the ending value of p_ctenamespace, @@ -111,11 +112,11 @@ transformWithClause(ParseState *pstate, WithClause *withClause) Assert(pstate->p_future_ctes == NIL); /* - * For either type of WITH, there must not be duplicate CTE names in - * the list. Check this right away so we needn't worry later. + * For either type of WITH, there must not be duplicate CTE names in the + * list. Check this right away so we needn't worry later. * - * Also, tentatively mark each CTE as non-recursive, and initialize - * its reference count to zero. + * Also, tentatively mark each CTE as non-recursive, and initialize its + * reference count to zero. */ foreach(lc, withClause->ctes) { @@ -129,8 +130,8 @@ transformWithClause(ParseState *pstate, WithClause *withClause) if (strcmp(cte->ctename, cte2->ctename) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_ALIAS), - errmsg("WITH query name \"%s\" specified more than once", - cte2->ctename), + errmsg("WITH query name \"%s\" specified more than once", + cte2->ctename), parser_errposition(pstate, cte2->location))); } @@ -141,12 +142,12 @@ transformWithClause(ParseState *pstate, WithClause *withClause) if (withClause->recursive) { /* - * For WITH RECURSIVE, we rearrange the list elements if needed - * to eliminate forward references. First, build a work array - * and set up the data structure needed by the tree walkers. + * For WITH RECURSIVE, we rearrange the list elements if needed to + * eliminate forward references. First, build a work array and set up + * the data structure needed by the tree walkers. */ - CteState cstate; - int i; + CteState cstate; + int i; cstate.pstate = pstate; cstate.numitems = list_length(withClause->ctes); @@ -171,10 +172,10 @@ transformWithClause(ParseState *pstate, WithClause *withClause) checkWellFormedRecursion(&cstate); /* - * Set up the ctenamespace for parse analysis. Per spec, all - * the WITH items are visible to all others, so stuff them all in - * before parse analysis. We build the list in safe processing - * order so that the planner can process the queries in sequence. + * Set up the ctenamespace for parse analysis. Per spec, all the WITH + * items are visible to all others, so stuff them all in before parse + * analysis. We build the list in safe processing order so that the + * planner can process the queries in sequence. */ for (i = 0; i < cstate.numitems; i++) { @@ -191,14 +192,14 @@ transformWithClause(ParseState *pstate, WithClause *withClause) CommonTableExpr *cte = cstate.items[i].cte; /* - * If it's recursive, we have to do a throwaway parse analysis - * of the non-recursive term in order to determine the set of - * output columns for the recursive CTE. + * If it's recursive, we have to do a throwaway parse analysis of + * the non-recursive term in order to determine the set of output + * columns for the recursive CTE. */ if (cte->cterecursive) { - Node *nrt; - Query *nrq; + Node *nrt; + Query *nrq; if (!cstate.items[i].non_recursive_term) elog(ERROR, "could not find non-recursive term for %s", @@ -216,11 +217,10 @@ transformWithClause(ParseState *pstate, WithClause *withClause) { /* * For non-recursive WITH, just analyze each CTE in sequence and then - * add it to the ctenamespace. This corresponds to the spec's - * definition of the scope of each WITH name. However, to allow - * error reports to be aware of the possibility of an erroneous - * reference, we maintain a list in p_future_ctes of the - * not-yet-visible CTEs. + * add it to the ctenamespace. This corresponds to the spec's + * definition of the scope of each WITH name. However, to allow error + * reports to be aware of the possibility of an erroneous reference, + * we maintain a list in p_future_ctes of the not-yet-visible CTEs. */ pstate->p_future_ctes = list_copy(withClause->ctes); @@ -232,7 +232,7 @@ transformWithClause(ParseState *pstate, WithClause *withClause) pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte); pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes); } - } + } return pstate->p_ctenamespace; } @@ -246,7 +246,7 @@ transformWithClause(ParseState *pstate, WithClause *withClause) static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte) { - Query *query; + Query *query; /* Analysis not done already */ Assert(IsA(cte->ctequery, SelectStmt)); @@ -268,7 +268,7 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("subquery in WITH cannot have SELECT INTO"), parser_errposition(pstate, - exprLocation((Node *) query->intoClause)))); + exprLocation((Node *) query->intoClause)))); if (!cte->cterecursive) { @@ -279,9 +279,9 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) { /* * Verify that the previously determined output column types match - * what the query really produced. We have to check this because - * the recursive term could have overridden the non-recursive term, - * and we don't have any easy way to fix that. + * what the query really produced. We have to check this because the + * recursive term could have overridden the non-recursive term, and we + * don't have any easy way to fix that. */ ListCell *lctlist, *lctyp, @@ -294,7 +294,7 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) foreach(lctlist, query->targetList) { TargetEntry *te = (TargetEntry *) lfirst(lctlist); - Node *texpr; + Node *texpr; if (te->resjunk) continue; @@ -310,7 +310,7 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) errmsg("recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall", cte->ctename, varattno, format_type_with_typemod(lfirst_oid(lctyp), - lfirst_int(lctypmod)), + lfirst_int(lctypmod)), format_type_with_typemod(exprType(texpr), exprTypmod(texpr))), errhint("Cast the output of the non-recursive term to the correct type."), @@ -318,7 +318,7 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) lctyp = lnext(lctyp); lctypmod = lnext(lctypmod); } - if (lctyp != NULL || lctypmod != NULL) /* shouldn't happen */ + if (lctyp != NULL || lctypmod != NULL) /* shouldn't happen */ elog(ERROR, "wrong number of output columns in WITH"); } } @@ -335,10 +335,10 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist) /* * We need to determine column names and types. The alias column names - * override anything coming from the query itself. (Note: the SQL spec - * says that the alias list must be empty or exactly as long as the - * output column set; but we allow it to be shorter for consistency - * with Alias handling.) + * override anything coming from the query itself. (Note: the SQL spec + * says that the alias list must be empty or exactly as long as the output + * column set; but we allow it to be shorter for consistency with Alias + * handling.) */ cte->ctecolnames = copyObject(cte->aliascolnames); cte->ctecoltypes = cte->ctecoltypmods = NIL; @@ -363,13 +363,14 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist) } coltype = exprType((Node *) te->expr); coltypmod = exprTypmod((Node *) te->expr); + /* * If the CTE is recursive, force the exposed column type of any - * "unknown" column to "text". This corresponds to the fact that - * SELECT 'foo' UNION SELECT 'bar' will ultimately produce text. - * We might see "unknown" as a result of an untyped literal in - * the non-recursive term's select list, and if we don't convert - * to text then we'll have a mismatch against the UNION result. + * "unknown" column to "text". This corresponds to the fact that + * SELECT 'foo' UNION SELECT 'bar' will ultimately produce text. We + * might see "unknown" as a result of an untyped literal in the + * non-recursive term's select list, and if we don't convert to text + * then we'll have a mismatch against the UNION result. */ if (cte->cterecursive && coltype == UNKNOWNOID) { @@ -426,21 +427,21 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) /* If unqualified name, might be a CTE reference */ if (!rv->schemaname) { - ListCell *lc; - int i; + ListCell *lc; + int i; /* ... but first see if it's captured by an inner WITH */ foreach(lc, cstate->innerwiths) { - List *withlist = (List *) lfirst(lc); - ListCell *lc2; + List *withlist = (List *) lfirst(lc); + ListCell *lc2; foreach(lc2, withlist) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2); if (strcmp(rv->relname, cte->ctename) == 0) - return false; /* yes, so bail out */ + return false; /* yes, so bail out */ } } @@ -451,7 +452,7 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) if (strcmp(rv->relname, cte->ctename) == 0) { - int myindex = cstate->curitem; + int myindex = cstate->curitem; if (i != myindex) { @@ -474,7 +475,7 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) if (IsA(node, SelectStmt)) { SelectStmt *stmt = (SelectStmt *) node; - ListCell *lc; + ListCell *lc; if (stmt->withClause) { @@ -482,8 +483,8 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) { /* * In the RECURSIVE case, all query names of the WITH are - * visible to all WITH items as well as the main query. - * So push them all on, process, pop them all off. + * visible to all WITH items as well as the main query. So + * push them all on, process, pop them all off. */ cstate->innerwiths = lcons(stmt->withClause->ctes, cstate->innerwiths); @@ -501,8 +502,8 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) else { /* - * In the non-RECURSIVE case, query names are visible to - * the WITH items after them and to the main query. + * In the non-RECURSIVE case, query names are visible to the + * WITH items after them and to the main query. */ ListCell *cell1; @@ -528,9 +529,9 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) if (IsA(node, WithClause)) { /* - * Prevent raw_expression_tree_walker from recursing directly into - * a WITH clause. We need that to happen only under the control - * of the code above. + * Prevent raw_expression_tree_walker from recursing directly into a + * WITH clause. We need that to happen only under the control of the + * code above. */ return false; } @@ -545,7 +546,8 @@ makeDependencyGraphWalker(Node *node, CteState *cstate) static void TopologicalSort(ParseState *pstate, CteItem *items, int numitems) { - int i, j; + int i, + j; /* for each position in sequence ... */ for (i = 0; i < numitems; i++) @@ -561,24 +563,25 @@ TopologicalSort(ParseState *pstate, CteItem *items, int numitems) if (j >= numitems) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("mutual recursion between WITH items is not implemented"), + errmsg("mutual recursion between WITH items is not implemented"), parser_errposition(pstate, items[i].cte->location))); /* - * Found one. Move it to front and remove it from every other - * item's dependencies. + * Found one. Move it to front and remove it from every other item's + * dependencies. */ if (i != j) { - CteItem tmp; - + CteItem tmp; + tmp = items[i]; items[i] = items[j]; items[j] = tmp; } + /* - * Items up through i are known to have no dependencies left, - * so we can skip them in this loop. + * Items up through i are known to have no dependencies left, so we + * can skip them in this loop. */ for (j = i + 1; j < numitems; j++) { @@ -600,9 +603,9 @@ checkWellFormedRecursion(CteState *cstate) for (i = 0; i < cstate->numitems; i++) { CommonTableExpr *cte = cstate->items[i].cte; - SelectStmt *stmt = (SelectStmt *) cte->ctequery; + SelectStmt *stmt = (SelectStmt *) cte->ctequery; - Assert(IsA(stmt, SelectStmt)); /* not analyzed yet */ + Assert(IsA(stmt, SelectStmt)); /* not analyzed yet */ /* Ignore items that weren't found to be recursive */ if (!cte->cterecursive) @@ -631,22 +634,22 @@ checkWellFormedRecursion(CteState *cstate) cstate->context = RECURSION_OK; checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate); Assert(cstate->innerwiths == NIL); - if (cstate->selfrefcount != 1) /* shouldn't happen */ + if (cstate->selfrefcount != 1) /* shouldn't happen */ elog(ERROR, "missing recursive reference"); /* - * Disallow ORDER BY and similar decoration atop the UNION. - * These don't make sense because it's impossible to figure out what - * they mean when we have only part of the recursive query's results. - * (If we did allow them, we'd have to check for recursive references + * Disallow ORDER BY and similar decoration atop the UNION. These + * don't make sense because it's impossible to figure out what they + * mean when we have only part of the recursive query's results. (If + * we did allow them, we'd have to check for recursive references * inside these subtrees.) */ if (stmt->sortClause) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ORDER BY in a recursive query is not implemented"), + errmsg("ORDER BY in a recursive query is not implemented"), parser_errposition(cstate->pstate, - exprLocation((Node *) stmt->sortClause)))); + exprLocation((Node *) stmt->sortClause)))); if (stmt->limitOffset) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -664,7 +667,7 @@ checkWellFormedRecursion(CteState *cstate) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"), parser_errposition(cstate->pstate, - exprLocation((Node *) stmt->lockingClause)))); + exprLocation((Node *) stmt->lockingClause)))); /* * Save non_recursive_term. @@ -690,21 +693,21 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate) /* If unqualified name, might be a CTE reference */ if (!rv->schemaname) { - ListCell *lc; + ListCell *lc; CommonTableExpr *mycte; /* ... but first see if it's captured by an inner WITH */ foreach(lc, cstate->innerwiths) { - List *withlist = (List *) lfirst(lc); - ListCell *lc2; + List *withlist = (List *) lfirst(lc); + ListCell *lc2; foreach(lc2, withlist) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2); if (strcmp(rv->relname, cte->ctename) == 0) - return false; /* yes, so bail out */ + return false; /* yes, so bail out */ } } @@ -735,7 +738,7 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate) if (IsA(node, SelectStmt)) { SelectStmt *stmt = (SelectStmt *) node; - ListCell *lc; + ListCell *lc; if (stmt->withClause) { @@ -743,8 +746,8 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate) { /* * In the RECURSIVE case, all query names of the WITH are - * visible to all WITH items as well as the main query. - * So push them all on, process, pop them all off. + * visible to all WITH items as well as the main query. So + * push them all on, process, pop them all off. */ cstate->innerwiths = lcons(stmt->withClause->ctes, cstate->innerwiths); @@ -760,8 +763,8 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate) else { /* - * In the non-RECURSIVE case, query names are visible to - * the WITH items after them and to the main query. + * In the non-RECURSIVE case, query names are visible to the + * WITH items after them and to the main query. */ ListCell *cell1; @@ -779,22 +782,22 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate) } } else - checkWellFormedSelectStmt(stmt, cstate); + checkWellFormedSelectStmt(stmt, cstate); /* We're done examining the SelectStmt */ return false; } if (IsA(node, WithClause)) { /* - * Prevent raw_expression_tree_walker from recursing directly into - * a WITH clause. We need that to happen only under the control - * of the code above. + * Prevent raw_expression_tree_walker from recursing directly into a + * WITH clause. We need that to happen only under the control of the + * code above. */ return false; } if (IsA(node, JoinExpr)) { - JoinExpr *j = (JoinExpr *) node; + JoinExpr *j = (JoinExpr *) node; switch (j->jointype) { @@ -835,7 +838,7 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate) } if (IsA(node, SubLink)) { - SubLink *sl = (SubLink *) node; + SubLink *sl = (SubLink *) node; /* * we intentionally override outer context, since subquery is |