summaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_cte.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_cte.c')
-rw-r--r--src/backend/parser/parse_cte.c203
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