PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

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

Definition at line 352 of file parse_cte.c.

References CommonTableExpr::aliascolnames, Assert, copyObject(), CommonTableExpr::ctecolcollations, CommonTableExpr::ctecolnames, CommonTableExpr::ctecoltypes, CommonTableExpr::ctecoltypmods, CommonTableExpr::ctename, CommonTableExpr::cterecursive, DEFAULT_COLLATION_OID, 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, TargetEntry::resno, TEXTOID, and UNKNOWNOID.

Referenced by analyzeCTE(), and determineRecursiveColTypes().

353 {
354  int numaliases;
355  int varattno;
356  ListCell *tlistitem;
357 
358  /* Not done already ... */
359  Assert(cte->ctecolnames == NIL);
360 
361  /*
362  * We need to determine column names, types, and collations. The alias
363  * column names override anything coming from the query itself. (Note:
364  * the SQL spec says that the alias list must be empty or exactly as long
365  * as the output column set; but we allow it to be shorter for consistency
366  * with Alias handling.)
367  */
368  cte->ctecolnames = copyObject(cte->aliascolnames);
369  cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
370  numaliases = list_length(cte->aliascolnames);
371  varattno = 0;
372  foreach(tlistitem, tlist)
373  {
374  TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
375  Oid coltype;
376  int32 coltypmod;
377  Oid colcoll;
378 
379  if (te->resjunk)
380  continue;
381  varattno++;
382  Assert(varattno == te->resno);
383  if (varattno > numaliases)
384  {
385  char *attrname;
386 
387  attrname = pstrdup(te->resname);
388  cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
389  }
390  coltype = exprType((Node *) te->expr);
391  coltypmod = exprTypmod((Node *) te->expr);
392  colcoll = exprCollation((Node *) te->expr);
393 
394  /*
395  * If the CTE is recursive, force the exposed column type of any
396  * "unknown" column to "text". We must deal with this here because
397  * we're called on the non-recursive term before there's been any
398  * attempt to force unknown output columns to some other type. We
399  * have to resolve unknowns before looking at the recursive term.
400  *
401  * The column might contain 'foo' COLLATE "bar", so don't override
402  * collation if it's already set.
403  */
404  if (cte->cterecursive && coltype == UNKNOWNOID)
405  {
406  coltype = TEXTOID;
407  coltypmod = -1; /* should be -1 already, but be sure */
408  if (!OidIsValid(colcoll))
409  colcoll = DEFAULT_COLLATION_OID;
410  }
411  cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
412  cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
413  cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
414  }
415  if (varattno < numaliases)
416  ereport(ERROR,
417  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
418  errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
419  cte->ctename, varattno, numaliases),
420  parser_errposition(pstate, cte->location)));
421 }
Value * makeString(char *str)
Definition: value.c:53
#define NIL
Definition: pg_list.h:69
#define TEXTOID
Definition: pg_type.h:324
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:273
char * pstrdup(const char *in)
Definition: mcxt.c:1077
Definition: nodes.h:506
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1354
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:538
signed int int32
Definition: c.h:256
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
bool resjunk
Definition: primnodes.h:1359
#define ERROR
Definition: elog.h:43
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:74
AttrNumber resno
Definition: primnodes.h:1353
List * ctecoltypmods
Definition: parsenodes.h:1330
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend_int(List *list, int datum)
Definition: list.c:146
List * lappend(List *list, void *datum)
Definition: list.c:128
List * ctecolnames
Definition: parsenodes.h:1328
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1352
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:745
#define UNKNOWNOID
Definition: pg_type.h:427
List * ctecoltypes
Definition: parsenodes.h:1329
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * ctecolcollations
Definition: parsenodes.h:1331
List * aliascolnames
Definition: parsenodes.h:1320
List* transformWithClause ( ParseState pstate,
WithClause withClause 
)

Definition at line 105 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().

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