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 570 of file parse_cte.c.

571 {
572  int numaliases;
573  int varattno;
574  ListCell *tlistitem;
575 
576  /* Not done already ... */
577  Assert(cte->ctecolnames == NIL);
578 
579  /*
580  * We need to determine column names, types, and collations. The alias
581  * column names override anything coming from the query itself. (Note:
582  * the SQL spec says that the alias list must be empty or exactly as long
583  * as the output column set; but we allow it to be shorter for consistency
584  * with Alias handling.)
585  */
586  cte->ctecolnames = copyObject(cte->aliascolnames);
587  cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
588  numaliases = list_length(cte->aliascolnames);
589  varattno = 0;
590  foreach(tlistitem, tlist)
591  {
592  TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
593  Oid coltype;
594  int32 coltypmod;
595  Oid colcoll;
596 
597  if (te->resjunk)
598  continue;
599  varattno++;
600  Assert(varattno == te->resno);
601  if (varattno > numaliases)
602  {
603  char *attrname;
604 
605  attrname = pstrdup(te->resname);
606  cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
607  }
608  coltype = exprType((Node *) te->expr);
609  coltypmod = exprTypmod((Node *) te->expr);
610  colcoll = exprCollation((Node *) te->expr);
611 
612  /*
613  * If the CTE is recursive, force the exposed column type of any
614  * "unknown" column to "text". We must deal with this here because
615  * we're called on the non-recursive term before there's been any
616  * attempt to force unknown output columns to some other type. We
617  * have to resolve unknowns before looking at the recursive term.
618  *
619  * The column might contain 'foo' COLLATE "bar", so don't override
620  * collation if it's already set.
621  */
622  if (cte->cterecursive && coltype == UNKNOWNOID)
623  {
624  coltype = TEXTOID;
625  coltypmod = -1; /* should be -1 already, but be sure */
626  if (!OidIsValid(colcoll))
627  colcoll = DEFAULT_COLLATION_OID;
628  }
629  cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
630  cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
631  cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
632  }
633  if (varattno < numaliases)
634  ereport(ERROR,
635  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
636  errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
637  cte->ctename, varattno, numaliases),
638  parser_errposition(pstate, cte->location)));
639 }
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
char * pstrdup(const char *in)
Definition: mcxt.c:1695
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
#define copyObject(obj)
Definition: nodes.h:224
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
unsigned int Oid
Definition: postgres_ext.h:31
ParseLoc location
Definition: parsenodes.h:1689
Definition: nodes.h:129
Expr * expr
Definition: primnodes.h:2162
AttrNumber resno
Definition: primnodes.h:2164
String * makeString(char *str)
Definition: value.c:63

References Assert, copyObject, CommonTableExpr::ctename, 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(), and TargetEntry::resno.

Referenced by analyzeCTE(), and determineRecursiveColTypes().

◆ transformWithClause()

List* transformWithClause ( ParseState pstate,
WithClause withClause 
)

Definition at line 109 of file parse_cte.c.

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  IsA(cte->ctequery, MergeStmt));
151 
152  pstate->p_hasModifyingCTE = true;
153  }
154  }
155 
156  if (withClause->recursive)
157  {
158  /*
159  * For WITH RECURSIVE, we rearrange the list elements if needed to
160  * eliminate forward references. First, build a work array and set up
161  * the data structure needed by the tree walkers.
162  */
163  CteState cstate;
164  int i;
165 
166  cstate.pstate = pstate;
167  cstate.numitems = list_length(withClause->ctes);
168  cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
169  i = 0;
170  foreach(lc, withClause->ctes)
171  {
172  cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
173  cstate.items[i].id = i;
174  i++;
175  }
176 
177  /*
178  * Find all the dependencies and sort the CteItems into a safe
179  * processing order. Also, mark CTEs that contain self-references.
180  */
181  makeDependencyGraph(&cstate);
182 
183  /*
184  * Check that recursive queries are well-formed.
185  */
186  checkWellFormedRecursion(&cstate);
187 
188  /*
189  * Set up the ctenamespace for parse analysis. Per spec, all the WITH
190  * items are visible to all others, so stuff them all in before parse
191  * analysis. We build the list in safe processing order so that the
192  * planner can process the queries in sequence.
193  */
194  for (i = 0; i < cstate.numitems; i++)
195  {
196  CommonTableExpr *cte = cstate.items[i].cte;
197 
198  pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
199  }
200 
201  /*
202  * Do parse analysis in the order determined by the topological sort.
203  */
204  for (i = 0; i < cstate.numitems; i++)
205  {
206  CommonTableExpr *cte = cstate.items[i].cte;
207 
208  analyzeCTE(pstate, cte);
209  }
210  }
211  else
212  {
213  /*
214  * For non-recursive WITH, just analyze each CTE in sequence and then
215  * add it to the ctenamespace. This corresponds to the spec's
216  * definition of the scope of each WITH name. However, to allow error
217  * reports to be aware of the possibility of an erroneous reference,
218  * we maintain a list in p_future_ctes of the not-yet-visible CTEs.
219  */
220  pstate->p_future_ctes = list_copy(withClause->ctes);
221 
222  foreach(lc, withClause->ctes)
223  {
224  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
225 
226  analyzeCTE(pstate, cte);
227  pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
228  pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
229  }
230  }
231 
232  return pstate->p_ctenamespace;
233 }
int i
Definition: isn.c:73
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * list_delete_first(List *list)
Definition: list.c:943
void * palloc0(Size size)
Definition: mcxt.c:1346
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
static void makeDependencyGraph(CteState *cstate)
Definition: parse_cte.c:647
static void checkWellFormedRecursion(CteState *cstate)
Definition: parse_cte.c:849
static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
Definition: parse_cte.c:242
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:438
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
int id
Definition: parse_cte.c:66
CommonTableExpr * cte
Definition: parse_cte.c:65
ParseState * pstate
Definition: parse_cte.c:74
int numitems
Definition: parse_cte.c:76
CteItem * items
Definition: parse_cte.c:75
List * p_ctenamespace
Definition: parse_node.h:204
bool p_hasModifyingCTE
Definition: parse_node.h:227
List * p_future_ctes
Definition: parse_node.h:205
List * ctes
Definition: parsenodes.h:1600
bool recursive
Definition: parsenodes.h:1601

References analyzeCTE(), Assert, checkWellFormedRecursion(), CteItem::cte, CommonTableExpr::ctename, CommonTableExpr::ctequery, 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(), transformMergeStmt(), transformSelectStmt(), transformSetOperationStmt(), transformUpdateStmt(), and transformValuesClause().