PostgreSQL Source Code  git master
parse_cte.h File Reference
Include dependency graph for parse_cte.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ListtransformWithClause (ParseState *pstate, WithClause *withClause)
 
void analyzeCTETargetList (ParseState *pstate, CommonTableExpr *cte, List *tlist)
 

Function Documentation

◆ analyzeCTETargetList()

void analyzeCTETargetList ( ParseState pstate,
CommonTableExpr cte,
List tlist 
)

Definition at line 545 of file parse_cte.c.

References CommonTableExpr::aliascolnames, Assert, copyObject, CommonTableExpr::ctecolcollations, CommonTableExpr::ctecolnames, CommonTableExpr::ctecoltypes, CommonTableExpr::ctecoltypmods, CommonTableExpr::ctename, CommonTableExpr::cterecursive, ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), lappend(), lappend_int(), lappend_oid(), lfirst, list_length(), CommonTableExpr::location, makeString(), NIL, OidIsValid, parser_errposition(), pstrdup(), TargetEntry::resjunk, TargetEntry::resname, and TargetEntry::resno.

Referenced by analyzeCTE(), and determineRecursiveColTypes().

546 {
547  int numaliases;
548  int varattno;
549  ListCell *tlistitem;
550 
551  /* Not done already ... */
552  Assert(cte->ctecolnames == NIL);
553 
554  /*
555  * We need to determine column names, types, and collations. The alias
556  * column names override anything coming from the query itself. (Note:
557  * the SQL spec says that the alias list must be empty or exactly as long
558  * as the output column set; but we allow it to be shorter for consistency
559  * with Alias handling.)
560  */
561  cte->ctecolnames = copyObject(cte->aliascolnames);
562  cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
563  numaliases = list_length(cte->aliascolnames);
564  varattno = 0;
565  foreach(tlistitem, tlist)
566  {
567  TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
568  Oid coltype;
569  int32 coltypmod;
570  Oid colcoll;
571 
572  if (te->resjunk)
573  continue;
574  varattno++;
575  Assert(varattno == te->resno);
576  if (varattno > numaliases)
577  {
578  char *attrname;
579 
580  attrname = pstrdup(te->resname);
581  cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
582  }
583  coltype = exprType((Node *) te->expr);
584  coltypmod = exprTypmod((Node *) te->expr);
585  colcoll = exprCollation((Node *) te->expr);
586 
587  /*
588  * If the CTE is recursive, force the exposed column type of any
589  * "unknown" column to "text". We must deal with this here because
590  * we're called on the non-recursive term before there's been any
591  * attempt to force unknown output columns to some other type. We
592  * have to resolve unknowns before looking at the recursive term.
593  *
594  * The column might contain 'foo' COLLATE "bar", so don't override
595  * collation if it's already set.
596  */
597  if (cte->cterecursive && coltype == UNKNOWNOID)
598  {
599  coltype = TEXTOID;
600  coltypmod = -1; /* should be -1 already, but be sure */
601  if (!OidIsValid(colcoll))
602  colcoll = DEFAULT_COLLATION_OID;
603  }
604  cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
605  cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
606  cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
607  }
608  if (varattno < numaliases)
609  ereport(ERROR,
610  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
611  errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
612  cte->ctename, varattno, numaliases),
613  parser_errposition(pstate, cte->location)));
614 }
#define NIL
Definition: pg_list.h:65
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Definition: nodes.h:536
int errcode(int sqlerrcode)
Definition: elog.c:698
String * makeString(char *str)
Definition: value.c:51
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1457
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
signed int int32
Definition: c.h:429
bool resjunk
Definition: primnodes.h:1462
#define ERROR
Definition: elog.h:46
AttrNumber resno
Definition: primnodes.h:1456
List * ctecoltypmods
Definition: parsenodes.h:1526
List * lappend_int(List *list, int datum)
Definition: list.c:354
List * lappend(List *list, void *datum)
Definition: list.c:336
List * ctecolnames
Definition: parsenodes.h:1524
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1455
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
List * ctecoltypes
Definition: parsenodes.h:1525
int errmsg(const char *fmt,...)
Definition: elog.c:909
List * ctecolcollations
Definition: parsenodes.h:1527
#define copyObject(obj)
Definition: nodes.h:652
List * aliascolnames
Definition: parsenodes.h:1513

◆ transformWithClause()

List* transformWithClause ( ParseState pstate,
WithClause withClause 
)

Definition at line 109 of file parse_cte.c.

References analyzeCTE(), Assert, checkWellFormedRecursion(), CteItem::cte, CommonTableExpr::ctename, CommonTableExpr::ctequery, CommonTableExpr::cterecursive, CommonTableExpr::cterefcount, WithClause::ctes, ereport, errcode(), errmsg(), ERROR, for_each_cell, i, CteItem::id, IsA, CteState::items, lappend(), lfirst, list_copy(), list_delete_first(), list_length(), lnext(), CommonTableExpr::location, makeDependencyGraph(), NIL, CteState::numitems, ParseState::p_ctenamespace, ParseState::p_future_ctes, ParseState::p_hasModifyingCTE, palloc0(), parser_errposition(), CteState::pstate, and WithClause::recursive.

Referenced by transformDeleteStmt(), transformInsertStmt(), transformSelectStmt(), transformSetOperationStmt(), transformUpdateStmt(), and transformValuesClause().

110 {
111  ListCell *lc;
112 
113  /* Only one WITH clause per query level */
114  Assert(pstate->p_ctenamespace == NIL);
115  Assert(pstate->p_future_ctes == NIL);
116 
117  /*
118  * For either type of WITH, there must not be duplicate CTE names in the
119  * list. Check this right away so we needn't worry later.
120  *
121  * Also, tentatively mark each CTE as non-recursive, and initialize its
122  * reference count to zero, and set pstate->p_hasModifyingCTE if needed.
123  */
124  foreach(lc, withClause->ctes)
125  {
126  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
127  ListCell *rest;
128 
129  for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc))
130  {
131  CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
132 
133  if (strcmp(cte->ctename, cte2->ctename) == 0)
134  ereport(ERROR,
135  (errcode(ERRCODE_DUPLICATE_ALIAS),
136  errmsg("WITH query name \"%s\" specified more than once",
137  cte2->ctename),
138  parser_errposition(pstate, cte2->location)));
139  }
140 
141  cte->cterecursive = false;
142  cte->cterefcount = 0;
143 
144  if (!IsA(cte->ctequery, SelectStmt))
145  {
146  /* must be a data-modifying statement */
147  Assert(IsA(cte->ctequery, InsertStmt) ||
148  IsA(cte->ctequery, UpdateStmt) ||
149  IsA(cte->ctequery, DeleteStmt));
150 
151  pstate->p_hasModifyingCTE = true;
152  }
153  }
154 
155  if (withClause->recursive)
156  {
157  /*
158  * For WITH RECURSIVE, we rearrange the list elements if needed to
159  * eliminate forward references. First, build a work array and set up
160  * the data structure needed by the tree walkers.
161  */
162  CteState cstate;
163  int i;
164 
165  cstate.pstate = pstate;
166  cstate.numitems = list_length(withClause->ctes);
167  cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
168  i = 0;
169  foreach(lc, withClause->ctes)
170  {
171  cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
172  cstate.items[i].id = i;
173  i++;
174  }
175 
176  /*
177  * Find all the dependencies and sort the CteItems into a safe
178  * processing order. Also, mark CTEs that contain self-references.
179  */
180  makeDependencyGraph(&cstate);
181 
182  /*
183  * Check that recursive queries are well-formed.
184  */
185  checkWellFormedRecursion(&cstate);
186 
187  /*
188  * Set up the ctenamespace for parse analysis. Per spec, all the WITH
189  * items are visible to all others, so stuff them all in before parse
190  * analysis. We build the list in safe processing order so that the
191  * planner can process the queries in sequence.
192  */
193  for (i = 0; i < cstate.numitems; i++)
194  {
195  CommonTableExpr *cte = cstate.items[i].cte;
196 
197  pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
198  }
199 
200  /*
201  * Do parse analysis in the order determined by the topological sort.
202  */
203  for (i = 0; i < cstate.numitems; i++)
204  {
205  CommonTableExpr *cte = cstate.items[i].cte;
206 
207  analyzeCTE(pstate, cte);
208  }
209  }
210  else
211  {
212  /*
213  * For non-recursive WITH, just analyze each CTE in sequence and then
214  * add it to the ctenamespace. This corresponds to the spec's
215  * definition of the scope of each WITH name. However, to allow error
216  * reports to be aware of the possibility of an erroneous reference,
217  * we maintain a list in p_future_ctes of the not-yet-visible CTEs.
218  */
219  pstate->p_future_ctes = list_copy(withClause->ctes);
220 
221  foreach(lc, withClause->ctes)
222  {
223  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
224 
225  analyzeCTE(pstate, cte);
226  pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
227  pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
228  }
229  }
230 
231  return pstate->p_ctenamespace;
232 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
static void makeDependencyGraph(CteState *cstate)
Definition: parse_cte.c:622
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:417
int numitems
Definition: parse_cte.c:76
static void checkWellFormedRecursion(CteState *cstate)
Definition: parse_cte.c:824
List * list_copy(const List *oldlist)
Definition: list.c:1418
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
CommonTableExpr * cte
Definition: parse_cte.c:65
bool recursive
Definition: parsenodes.h:1437
bool p_hasModifyingCTE
Definition: parse_node.h:212
List * lappend(List *list, void *datum)
Definition: list.c:336
static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
Definition: parse_cte.c:241
List * p_future_ctes
Definition: parse_node.h:190
void * palloc0(Size size)
Definition: mcxt.c:1093
#define ereport(elevel,...)
Definition: elog.h:157
int id
Definition: parse_cte.c:66
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
List * p_ctenamespace
Definition: parse_node.h:189
CteItem * items
Definition: parse_cte.c:75
ParseState * pstate
Definition: parse_cte.c:74
List * list_delete_first(List *list)
Definition: list.c:875
List * ctes
Definition: parsenodes.h:1436