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

577 {
578  int numaliases;
579  int varattno;
580  ListCell *tlistitem;
581 
582  /* Not done already ... */
583  Assert(cte->ctecolnames == NIL);
584 
585  /*
586  * We need to determine column names, types, and collations. The alias
587  * column names override anything coming from the query itself. (Note:
588  * the SQL spec says that the alias list must be empty or exactly as long
589  * as the output column set; but we allow it to be shorter for consistency
590  * with Alias handling.)
591  */
592  cte->ctecolnames = copyObject(cte->aliascolnames);
593  cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
594  numaliases = list_length(cte->aliascolnames);
595  varattno = 0;
596  foreach(tlistitem, tlist)
597  {
598  TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
599  Oid coltype;
600  int32 coltypmod;
601  Oid colcoll;
602 
603  if (te->resjunk)
604  continue;
605  varattno++;
606  Assert(varattno == te->resno);
607  if (varattno > numaliases)
608  {
609  char *attrname;
610 
611  attrname = pstrdup(te->resname);
612  cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
613  }
614  coltype = exprType((Node *) te->expr);
615  coltypmod = exprTypmod((Node *) te->expr);
616  colcoll = exprCollation((Node *) te->expr);
617 
618  /*
619  * If the CTE is recursive, force the exposed column type of any
620  * "unknown" column to "text". We must deal with this here because
621  * we're called on the non-recursive term before there's been any
622  * attempt to force unknown output columns to some other type. We
623  * have to resolve unknowns before looking at the recursive term.
624  *
625  * The column might contain 'foo' COLLATE "bar", so don't override
626  * collation if it's already set.
627  */
628  if (cte->cterecursive && coltype == UNKNOWNOID)
629  {
630  coltype = TEXTOID;
631  coltypmod = -1; /* should be -1 already, but be sure */
632  if (!OidIsValid(colcoll))
633  colcoll = DEFAULT_COLLATION_OID;
634  }
635  cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
636  cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
637  cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
638  }
639  if (varattno < numaliases)
640  ereport(ERROR,
641  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
642  errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
643  cte->ctename, varattno, numaliases),
644  parser_errposition(pstate, cte->location)));
645 }
signed int int32
Definition: c.h:478
#define OidIsValid(objectId)
Definition: c.h:759
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_int(List *list, int datum)
Definition: list.c:356
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
char * pstrdup(const char *in)
Definition: mcxt.c:1624
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:266
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:764
#define copyObject(obj)
Definition: nodes.h:244
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
#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
Definition: nodes.h:129
Expr * expr
Definition: primnodes.h:1722
AttrNumber resno
Definition: primnodes.h:1724
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  /* MERGE is allowed by parser, but unimplemented. Reject for now */
130  if (IsA(cte->ctequery, MergeStmt))
131  ereport(ERROR,
132  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
133  errmsg("MERGE not supported in WITH query"),
134  parser_errposition(pstate, cte->location));
135 
136  for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc))
137  {
138  CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
139 
140  if (strcmp(cte->ctename, cte2->ctename) == 0)
141  ereport(ERROR,
142  (errcode(ERRCODE_DUPLICATE_ALIAS),
143  errmsg("WITH query name \"%s\" specified more than once",
144  cte2->ctename),
145  parser_errposition(pstate, cte2->location)));
146  }
147 
148  cte->cterecursive = false;
149  cte->cterefcount = 0;
150 
151  if (!IsA(cte->ctequery, SelectStmt))
152  {
153  /* must be a data-modifying statement */
154  Assert(IsA(cte->ctequery, InsertStmt) ||
155  IsA(cte->ctequery, UpdateStmt) ||
156  IsA(cte->ctequery, DeleteStmt));
157 
158  pstate->p_hasModifyingCTE = true;
159  }
160  }
161 
162  if (withClause->recursive)
163  {
164  /*
165  * For WITH RECURSIVE, we rearrange the list elements if needed to
166  * eliminate forward references. First, build a work array and set up
167  * the data structure needed by the tree walkers.
168  */
169  CteState cstate;
170  int i;
171 
172  cstate.pstate = pstate;
173  cstate.numitems = list_length(withClause->ctes);
174  cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
175  i = 0;
176  foreach(lc, withClause->ctes)
177  {
178  cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
179  cstate.items[i].id = i;
180  i++;
181  }
182 
183  /*
184  * Find all the dependencies and sort the CteItems into a safe
185  * processing order. Also, mark CTEs that contain self-references.
186  */
187  makeDependencyGraph(&cstate);
188 
189  /*
190  * Check that recursive queries are well-formed.
191  */
192  checkWellFormedRecursion(&cstate);
193 
194  /*
195  * Set up the ctenamespace for parse analysis. Per spec, all the WITH
196  * items are visible to all others, so stuff them all in before parse
197  * analysis. We build the list in safe processing order so that the
198  * planner can process the queries in sequence.
199  */
200  for (i = 0; i < cstate.numitems; i++)
201  {
202  CommonTableExpr *cte = cstate.items[i].cte;
203 
204  pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
205  }
206 
207  /*
208  * Do parse analysis in the order determined by the topological sort.
209  */
210  for (i = 0; i < cstate.numitems; i++)
211  {
212  CommonTableExpr *cte = cstate.items[i].cte;
213 
214  analyzeCTE(pstate, cte);
215  }
216  }
217  else
218  {
219  /*
220  * For non-recursive WITH, just analyze each CTE in sequence and then
221  * add it to the ctenamespace. This corresponds to the spec's
222  * definition of the scope of each WITH name. However, to allow error
223  * reports to be aware of the possibility of an erroneous reference,
224  * we maintain a list in p_future_ctes of the not-yet-visible CTEs.
225  */
226  pstate->p_future_ctes = list_copy(withClause->ctes);
227 
228  foreach(lc, withClause->ctes)
229  {
230  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
231 
232  analyzeCTE(pstate, cte);
233  pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
234  pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
235  }
236  }
237 
238  return pstate->p_ctenamespace;
239 }
int i
Definition: isn.c:73
List * list_copy(const List *oldlist)
Definition: list.c:1572
List * list_delete_first(List *list)
Definition: list.c:942
void * palloc0(Size size)
Definition: mcxt.c:1241
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
static void makeDependencyGraph(CteState *cstate)
Definition: parse_cte.c:653
static void checkWellFormedRecursion(CteState *cstate)
Definition: parse_cte.c:855
static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
Definition: parse_cte.c:248
#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:203
bool p_hasModifyingCTE
Definition: parse_node.h:226
List * p_future_ctes
Definition: parse_node.h:204
List * ctes
Definition: parsenodes.h:1548
bool recursive
Definition: parsenodes.h:1549

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().