PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 571 of file parse_cte.c.

572{
573 int numaliases;
574 int varattno;
575 ListCell *tlistitem;
576
577 /* Not done already ... */
578 Assert(cte->ctecolnames == NIL);
579
580 /*
581 * We need to determine column names, types, and collations. The alias
582 * column names override anything coming from the query itself. (Note:
583 * the SQL spec says that the alias list must be empty or exactly as long
584 * as the output column set; but we allow it to be shorter for consistency
585 * with Alias handling.)
586 */
587 cte->ctecolnames = copyObject(cte->aliascolnames);
588 cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
589 numaliases = list_length(cte->aliascolnames);
590 varattno = 0;
591 foreach(tlistitem, tlist)
592 {
593 TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
594 Oid coltype;
595 int32 coltypmod;
596 Oid colcoll;
597
598 if (te->resjunk)
599 continue;
600 varattno++;
601 Assert(varattno == te->resno);
602 if (varattno > numaliases)
603 {
604 char *attrname;
605
606 attrname = pstrdup(te->resname);
607 cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
608 }
609 coltype = exprType((Node *) te->expr);
610 coltypmod = exprTypmod((Node *) te->expr);
611 colcoll = exprCollation((Node *) te->expr);
612
613 /*
614 * If the CTE is recursive, force the exposed column type of any
615 * "unknown" column to "text". We must deal with this here because
616 * we're called on the non-recursive term before there's been any
617 * attempt to force unknown output columns to some other type. We
618 * have to resolve unknowns before looking at the recursive term.
619 *
620 * The column might contain 'foo' COLLATE "bar", so don't override
621 * collation if it's already set.
622 */
623 if (cte->cterecursive && coltype == UNKNOWNOID)
624 {
625 coltype = TEXTOID;
626 coltypmod = -1; /* should be -1 already, but be sure */
627 if (!OidIsValid(colcoll))
628 colcoll = DEFAULT_COLLATION_OID;
629 }
630 cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
631 cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
632 cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
633 }
634 if (varattno < numaliases)
636 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
637 errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
638 cte->ctename, varattno, numaliases),
639 parser_errposition(pstate, cte->location)));
640}
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Assert(PointerIsAligned(start, uint64))
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:2327
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
#define copyObject(obj)
Definition: nodes.h:230
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:30
ParseLoc location
Definition: parsenodes.h:1698
Definition: nodes.h:135
Expr * expr
Definition: primnodes.h:2219
AttrNumber resno
Definition: primnodes.h:2221
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 110 of file parse_cte.c.

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

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