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 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)
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}
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:1699
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: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:32
ParseLoc location
Definition: parsenodes.h:1693
Definition: nodes.h:129
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 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 {
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)
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 */
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 {
225
226 analyzeCTE(pstate, cte);
227 pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
229 }
230 }
231
232 return pstate->p_ctenamespace;
233}
int i
Definition: isn.c:72
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:1347
#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:222
bool p_hasModifyingCTE
Definition: parse_node.h:246
List * p_future_ctes
Definition: parse_node.h:223
List * ctes
Definition: parsenodes.h:1604
bool recursive
Definition: parsenodes.h:1605

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