Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * analyze.c
4 : : * transform the raw parse tree into a query tree
5 : : *
6 : : * For optimizable statements, we are careful to obtain a suitable lock on
7 : : * each referenced table, and other modules of the backend preserve or
8 : : * re-obtain these locks before depending on the results. It is therefore
9 : : * okay to do significant semantic analysis of these statements. For
10 : : * utility commands, no locks are obtained here (and if they were, we could
11 : : * not be sure we'd still have them at execution). Hence the general rule
12 : : * for utility commands is to just dump them into a Query node untransformed.
13 : : * DECLARE CURSOR, EXPLAIN, and CREATE TABLE AS are exceptions because they
14 : : * contain optimizable statements, which we should transform.
15 : : *
16 : : *
17 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
18 : : * Portions Copyright (c) 1994, Regents of the University of California
19 : : *
20 : : * src/backend/parser/analyze.c
21 : : *
22 : : *-------------------------------------------------------------------------
23 : : */
24 : :
25 : : #include "postgres.h"
26 : :
27 : : #include "access/sysattr.h"
28 : : #include "catalog/dependency.h"
29 : : #include "catalog/pg_proc.h"
30 : : #include "catalog/pg_type.h"
31 : : #include "commands/defrem.h"
32 : : #include "miscadmin.h"
33 : : #include "nodes/makefuncs.h"
34 : : #include "nodes/nodeFuncs.h"
35 : : #include "nodes/queryjumble.h"
36 : : #include "optimizer/optimizer.h"
37 : : #include "parser/analyze.h"
38 : : #include "parser/parse_agg.h"
39 : : #include "parser/parse_clause.h"
40 : : #include "parser/parse_coerce.h"
41 : : #include "parser/parse_collate.h"
42 : : #include "parser/parse_cte.h"
43 : : #include "parser/parse_expr.h"
44 : : #include "parser/parse_func.h"
45 : : #include "parser/parse_merge.h"
46 : : #include "parser/parse_oper.h"
47 : : #include "parser/parse_param.h"
48 : : #include "parser/parse_relation.h"
49 : : #include "parser/parse_target.h"
50 : : #include "parser/parse_type.h"
51 : : #include "parser/parsetree.h"
52 : : #include "utils/backend_status.h"
53 : : #include "utils/builtins.h"
54 : : #include "utils/guc.h"
55 : : #include "utils/rel.h"
56 : : #include "utils/syscache.h"
57 : :
58 : :
59 : : /* Passthrough data for transformPLAssignStmtTarget */
60 : : typedef struct SelectStmtPassthrough
61 : : {
62 : : PLAssignStmt *stmt; /* the assignment statement */
63 : : Node *target; /* node representing the target variable */
64 : : List *indirection; /* indirection yet to be applied to target */
65 : : } SelectStmtPassthrough;
66 : :
67 : : /* Hook for plugins to get control at end of parse analysis */
68 : : post_parse_analyze_hook_type post_parse_analyze_hook = NULL;
69 : :
70 : : static Query *transformOptionalSelectInto(ParseState *pstate, Node *parseTree);
71 : : static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
72 : : static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
73 : : static OnConflictExpr *transformOnConflictClause(ParseState *pstate,
74 : : OnConflictClause *onConflictClause);
75 : : static int count_rowexpr_columns(ParseState *pstate, Node *expr);
76 : : static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt,
77 : : SelectStmtPassthrough *passthru);
78 : : static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
79 : : static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
80 : : static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
81 : : bool isTopLevel, List **targetlist);
82 : : static void determineRecursiveColTypes(ParseState *pstate,
83 : : Node *larg, List *nrtargetlist);
84 : : static Query *transformReturnStmt(ParseState *pstate, ReturnStmt *stmt);
85 : : static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
86 : : static Query *transformPLAssignStmt(ParseState *pstate,
87 : : PLAssignStmt *stmt);
88 : : static List *transformPLAssignStmtTarget(ParseState *pstate, List *tlist,
89 : : SelectStmtPassthrough *passthru);
90 : : static Query *transformDeclareCursorStmt(ParseState *pstate,
91 : : DeclareCursorStmt *stmt);
92 : : static Query *transformExplainStmt(ParseState *pstate,
93 : : ExplainStmt *stmt);
94 : : static Query *transformCreateTableAsStmt(ParseState *pstate,
95 : : CreateTableAsStmt *stmt);
96 : : static Query *transformCallStmt(ParseState *pstate,
97 : : CallStmt *stmt);
98 : : static void transformLockingClause(ParseState *pstate, Query *qry,
99 : : LockingClause *lc, bool pushedDown);
100 : : #ifdef DEBUG_NODE_TESTS_ENABLED
101 : : static bool test_raw_expression_coverage(Node *node, void *context);
102 : : #endif
103 : :
104 : :
105 : : /*
106 : : * parse_analyze_fixedparams
107 : : * Analyze a raw parse tree and transform it to Query form.
108 : : *
109 : : * Optionally, information about $n parameter types can be supplied.
110 : : * References to $n indexes not defined by paramTypes[] are disallowed.
111 : : *
112 : : * The result is a Query node. Optimizable statements require considerable
113 : : * transformation, while utility-type statements are simply hung off
114 : : * a dummy CMD_UTILITY Query node.
115 : : */
116 : : Query *
1383 peter@eisentraut.org 117 :CBC 394391 : parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText,
118 : : const Oid *paramTypes, int numParams,
119 : : QueryEnvironment *queryEnv)
120 : : {
8267 tgl@sss.pgh.pa.us 121 : 394391 : ParseState *pstate = make_parsestate(NULL);
122 : : Query *query;
1714 bruce@momjian.us 123 : 394391 : JumbleState *jstate = NULL;
124 : :
6032 125 [ - + ]: 394391 : Assert(sourceText != NULL); /* required as of 8.4 */
126 : :
7217 tgl@sss.pgh.pa.us 127 : 394391 : pstate->p_sourcetext = sourceText;
128 : :
5890 129 [ + + ]: 394391 : if (numParams > 0)
1383 peter@eisentraut.org 130 : 2065 : setup_parse_fixed_parameters(pstate, paramTypes, numParams);
131 : :
3182 kgrittn@postgresql.o 132 : 394391 : pstate->p_queryEnv = queryEnv;
133 : :
5020 tgl@sss.pgh.pa.us 134 : 394391 : query = transformTopLevelStmt(pstate, parseTree);
135 : :
1676 alvherre@alvh.no-ip. 136 [ + + ]: 390276 : if (IsQueryIdEnabled())
902 michael@paquier.xyz 137 : 72918 : jstate = JumbleQuery(query);
138 : :
5012 tgl@sss.pgh.pa.us 139 [ + + ]: 390276 : if (post_parse_analyze_hook)
1714 bruce@momjian.us 140 : 72861 : (*post_parse_analyze_hook) (pstate, query, jstate);
141 : :
6751 tgl@sss.pgh.pa.us 142 : 390276 : free_parsestate(pstate);
143 : :
1701 bruce@momjian.us 144 : 390276 : pgstat_report_query_id(query->queryId, false);
145 : :
6751 tgl@sss.pgh.pa.us 146 : 390276 : return query;
147 : : }
148 : :
149 : : /*
150 : : * parse_analyze_varparams
151 : : *
152 : : * This variant is used when it's okay to deduce information about $n
153 : : * symbol datatypes from context. The passed-in paramTypes[] array can
154 : : * be modified or enlarged (via repalloc).
155 : : */
156 : : Query *
3258 157 : 5205 : parse_analyze_varparams(RawStmt *parseTree, const char *sourceText,
158 : : Oid **paramTypes, int *numParams,
159 : : QueryEnvironment *queryEnv)
160 : : {
8267 161 : 5205 : ParseState *pstate = make_parsestate(NULL);
162 : : Query *query;
1714 bruce@momjian.us 163 : 5205 : JumbleState *jstate = NULL;
164 : :
6032 165 [ - + ]: 5205 : Assert(sourceText != NULL); /* required as of 8.4 */
166 : :
7217 tgl@sss.pgh.pa.us 167 : 5205 : pstate->p_sourcetext = sourceText;
168 : :
1383 peter@eisentraut.org 169 : 5205 : setup_parse_variable_parameters(pstate, paramTypes, numParams);
170 : :
171 : 5205 : pstate->p_queryEnv = queryEnv;
172 : :
5020 tgl@sss.pgh.pa.us 173 : 5205 : query = transformTopLevelStmt(pstate, parseTree);
174 : :
175 : : /* make sure all is well with parameter types */
5890 176 : 5197 : check_variable_parameters(pstate, query);
177 : :
1676 alvherre@alvh.no-ip. 178 [ + + ]: 5197 : if (IsQueryIdEnabled())
902 michael@paquier.xyz 179 : 262 : jstate = JumbleQuery(query);
180 : :
5012 tgl@sss.pgh.pa.us 181 [ + + ]: 5197 : if (post_parse_analyze_hook)
1714 bruce@momjian.us 182 : 262 : (*post_parse_analyze_hook) (pstate, query, jstate);
183 : :
6751 tgl@sss.pgh.pa.us 184 : 5197 : free_parsestate(pstate);
185 : :
1701 bruce@momjian.us 186 : 5197 : pgstat_report_query_id(query->queryId, false);
187 : :
6751 tgl@sss.pgh.pa.us 188 : 5197 : return query;
189 : : }
190 : :
191 : : /*
192 : : * parse_analyze_withcb
193 : : *
194 : : * This variant is used when the caller supplies their own parser callback to
195 : : * resolve parameters and possibly other things.
196 : : */
197 : : Query *
1378 peter@eisentraut.org 198 : 19749 : parse_analyze_withcb(RawStmt *parseTree, const char *sourceText,
199 : : ParserSetupHook parserSetup,
200 : : void *parserSetupArg,
201 : : QueryEnvironment *queryEnv)
202 : : {
203 : 19749 : ParseState *pstate = make_parsestate(NULL);
204 : : Query *query;
205 : 19749 : JumbleState *jstate = NULL;
206 : :
207 [ - + ]: 19749 : Assert(sourceText != NULL); /* required as of 8.4 */
208 : :
209 : 19749 : pstate->p_sourcetext = sourceText;
210 : 19749 : pstate->p_queryEnv = queryEnv;
211 : 19749 : (*parserSetup) (pstate, parserSetupArg);
212 : :
213 : 19749 : query = transformTopLevelStmt(pstate, parseTree);
214 : :
215 [ + + ]: 19687 : if (IsQueryIdEnabled())
902 michael@paquier.xyz 216 : 3765 : jstate = JumbleQuery(query);
217 : :
1378 peter@eisentraut.org 218 [ + + ]: 19687 : if (post_parse_analyze_hook)
219 : 3765 : (*post_parse_analyze_hook) (pstate, query, jstate);
220 : :
221 : 19687 : free_parsestate(pstate);
222 : :
223 : 19687 : pgstat_report_query_id(query->queryId, false);
224 : :
225 : 19687 : return query;
226 : : }
227 : :
228 : :
229 : : /*
230 : : * parse_sub_analyze
231 : : * Entry point for recursively analyzing a sub-statement.
232 : : */
233 : : Query *
5942 tgl@sss.pgh.pa.us 234 : 54189 : parse_sub_analyze(Node *parseTree, ParseState *parentParseState,
235 : : CommonTableExpr *parentCTE,
236 : : bool locked_from_parent,
237 : : bool resolve_unknowns)
238 : : {
9201 239 : 54189 : ParseState *pstate = make_parsestate(parentParseState);
240 : : Query *query;
241 : :
5942 242 : 54189 : pstate->p_parent_cte = parentCTE;
5894 243 : 54189 : pstate->p_locked_from_parent = locked_from_parent;
3247 244 : 54189 : pstate->p_resolve_unknowns = resolve_unknowns;
245 : :
6751 246 : 54189 : query = transformStmt(pstate, parseTree);
247 : :
248 : 54083 : free_parsestate(pstate);
249 : :
250 : 54083 : return query;
251 : : }
252 : :
253 : : /*
254 : : * transformTopLevelStmt -
255 : : * transform a Parse tree into a Query tree.
256 : : *
257 : : * This function is just responsible for transferring statement location data
258 : : * from the RawStmt into the finished Query.
259 : : */
260 : : Query *
3258 261 : 420813 : transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree)
262 : : {
263 : : Query *result;
264 : :
265 : : /* We're at top level, so allow SELECT INTO */
266 : 420813 : result = transformOptionalSelectInto(pstate, parseTree->stmt);
267 : :
187 michael@paquier.xyz 268 : 416625 : result->stmt_location = parseTree->stmt_location;
269 : 416625 : result->stmt_len = parseTree->stmt_len;
270 : :
3258 tgl@sss.pgh.pa.us 271 : 416625 : return result;
272 : : }
273 : :
274 : : /*
275 : : * transformOptionalSelectInto -
276 : : * If SELECT has INTO, convert it to CREATE TABLE AS.
277 : : *
278 : : * The only thing we do here that we don't do in transformStmt() is to
279 : : * convert SELECT ... INTO into CREATE TABLE AS. Since utility statements
280 : : * aren't allowed within larger statements, this is only allowed at the top
281 : : * of the parse tree, and so we only try it before entering the recursive
282 : : * transformStmt() processing.
283 : : */
284 : : static Query *
285 : 433156 : transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
286 : : {
5020 287 [ + + ]: 433156 : if (IsA(parseTree, SelectStmt))
288 : : {
289 : 187262 : SelectStmt *stmt = (SelectStmt *) parseTree;
290 : :
291 : : /* If it's a set-operation tree, drill down to leftmost SelectStmt */
292 [ + - + + ]: 192675 : while (stmt && stmt->op != SETOP_NONE)
293 : 5413 : stmt = stmt->larg;
2040 294 [ + - + - : 187262 : Assert(stmt && IsA(stmt, SelectStmt) && stmt->larg == NULL);
- + ]
295 : :
5020 296 [ + + ]: 187262 : if (stmt->intoClause)
297 : : {
298 : 53 : CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
299 : :
300 : 53 : ctas->query = parseTree;
301 : 53 : ctas->into = stmt->intoClause;
1984 michael@paquier.xyz 302 : 53 : ctas->objtype = OBJECT_TABLE;
5020 tgl@sss.pgh.pa.us 303 : 53 : ctas->is_select_into = true;
304 : :
305 : : /*
306 : : * Remove the intoClause from the SelectStmt. This makes it safe
307 : : * for transformSelectStmt to complain if it finds intoClause set
308 : : * (implying that the INTO appeared in a disallowed place).
309 : : */
310 : 53 : stmt->intoClause = NULL;
311 : :
312 : 53 : parseTree = (Node *) ctas;
313 : : }
314 : : }
315 : :
316 : 433156 : return transformStmt(pstate, parseTree);
317 : : }
318 : :
319 : : /*
320 : : * transformStmt -
321 : : * recursively transform a Parse tree into a Query tree.
322 : : */
323 : : Query *
6751 324 : 497710 : transformStmt(ParseState *pstate, Node *parseTree)
325 : : {
326 : : Query *result;
327 : :
328 : : #ifdef DEBUG_NODE_TESTS_ENABLED
329 : :
330 : : /*
331 : : * We apply debug_raw_expression_coverage_test testing to basic DML
332 : : * statements; we can't just run it on everything because
333 : : * raw_expression_tree_walker() doesn't claim to handle utility
334 : : * statements.
335 : : */
502 peter@eisentraut.org 336 [ - + ]: 497710 : if (Debug_raw_expression_coverage_test)
337 : : {
502 peter@eisentraut.org 338 [ # # ]:UBC 0 : switch (nodeTag(parseTree))
339 : : {
340 : 0 : case T_SelectStmt:
341 : : case T_InsertStmt:
342 : : case T_UpdateStmt:
343 : : case T_DeleteStmt:
344 : : case T_MergeStmt:
345 : 0 : (void) test_raw_expression_coverage(parseTree, NULL);
346 : 0 : break;
347 : 0 : default:
348 : 0 : break;
349 : : }
350 : : }
351 : : #endif /* DEBUG_NODE_TESTS_ENABLED */
352 : :
353 : : /*
354 : : * Caution: when changing the set of statement types that have non-default
355 : : * processing here, see also stmt_requires_parse_analysis() and
356 : : * analyze_requires_snapshot().
357 : : */
10327 bruce@momjian.us 358 [ + + + + :CBC 497710 : switch (nodeTag(parseTree))
+ + + + +
+ + + ]
359 : : {
360 : : /*
361 : : * Optimizable statements
362 : : */
10203 363 : 33349 : case T_InsertStmt:
6751 tgl@sss.pgh.pa.us 364 : 33349 : result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
10326 bruce@momjian.us 365 : 32632 : break;
366 : :
367 : 2275 : case T_DeleteStmt:
368 : 2275 : result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
369 : 2248 : break;
370 : :
10203 371 : 7338 : case T_UpdateStmt:
372 : 7338 : result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
10326 373 : 7286 : break;
374 : :
1359 alvherre@alvh.no-ip. 375 : 1053 : case T_MergeStmt:
376 : 1053 : result = transformMergeStmt(pstate, (MergeStmt *) parseTree);
377 : 1020 : break;
378 : :
10203 bruce@momjian.us 379 : 248598 : case T_SelectStmt:
380 : : {
7076 mail@joeconway.com 381 : 248598 : SelectStmt *n = (SelectStmt *) parseTree;
382 : :
383 [ + + ]: 248598 : if (n->valuesLists)
384 : 4277 : result = transformValuesClause(pstate, n);
385 [ + + ]: 244321 : else if (n->op == SETOP_NONE)
80 tgl@sss.pgh.pa.us 386 :GNC 237721 : result = transformSelectStmt(pstate, n, NULL);
387 : : else
7076 mail@joeconway.com 388 :CBC 6600 : result = transformSetOperationStmt(pstate, n);
389 : : }
10326 bruce@momjian.us 390 : 245159 : break;
391 : :
1714 peter@eisentraut.org 392 : 2485 : case T_ReturnStmt:
393 : 2485 : result = transformReturnStmt(pstate, (ReturnStmt *) parseTree);
394 : 2482 : break;
395 : :
1807 tgl@sss.pgh.pa.us 396 : 2851 : case T_PLAssignStmt:
397 : 2851 : result = transformPLAssignStmt(pstate,
398 : : (PLAssignStmt *) parseTree);
399 : 2838 : break;
400 : :
401 : : /*
402 : : * Special cases
403 : : */
6808 404 : 2263 : case T_DeclareCursorStmt:
405 : 2263 : result = transformDeclareCursorStmt(pstate,
406 : : (DeclareCursorStmt *) parseTree);
407 : 2252 : break;
408 : :
409 : 12343 : case T_ExplainStmt:
410 : 12343 : result = transformExplainStmt(pstate,
411 : : (ExplainStmt *) parseTree);
412 : 12336 : break;
413 : :
5020 414 : 1011 : case T_CreateTableAsStmt:
415 : 1011 : result = transformCreateTableAsStmt(pstate,
416 : : (CreateTableAsStmt *) parseTree);
417 : 1004 : break;
418 : :
2856 peter_e@gmx.net 419 : 256 : case T_CallStmt:
420 : 256 : result = transformCallStmt(pstate,
421 : : (CallStmt *) parseTree);
2829 422 : 240 : break;
423 : :
10326 bruce@momjian.us 424 : 183888 : default:
425 : :
426 : : /*
427 : : * other statements don't require any transformation; just return
428 : : * the original parsetree with a Query node plastered on top.
429 : : */
430 : 183888 : result = makeNode(Query);
431 : 183888 : result->commandType = CMD_UTILITY;
14 peter@eisentraut.org 432 :GNC 183888 : result->utilityStmt = parseTree;
10326 bruce@momjian.us 433 :CBC 183888 : break;
434 : : }
435 : :
436 : : /* Mark as original query until we learn differently */
8264 tgl@sss.pgh.pa.us 437 : 493385 : result->querySource = QSRC_ORIGINAL;
438 : 493385 : result->canSetTag = true;
439 : :
10327 bruce@momjian.us 440 : 493385 : return result;
441 : : }
442 : :
443 : : /*
444 : : * stmt_requires_parse_analysis
445 : : * Returns true if parse analysis will do anything non-trivial
446 : : * with the given raw parse tree.
447 : : *
448 : : * Generally, this should return true for any statement type for which
449 : : * transformStmt() does more than wrap a CMD_UTILITY Query around it.
450 : : * When it returns false, the caller can assume that there is no situation
451 : : * in which parse analysis of the raw statement could need to be re-done.
452 : : *
453 : : * Currently, since the rewriter and planner do nothing for CMD_UTILITY
454 : : * Queries, a false result means that the entire parse analysis/rewrite/plan
455 : : * pipeline will never need to be re-done. If that ever changes, callers
456 : : * will likely need adjustment.
457 : : */
458 : : bool
845 tgl@sss.pgh.pa.us 459 : 16754023 : stmt_requires_parse_analysis(RawStmt *parseTree)
460 : : {
461 : : bool result;
462 : :
3258 463 [ + + + ]: 16754023 : switch (nodeTag(parseTree->stmt))
464 : : {
465 : : /*
466 : : * Optimizable statements
467 : : */
6212 468 : 16304374 : case T_InsertStmt:
469 : : case T_DeleteStmt:
470 : : case T_UpdateStmt:
471 : : case T_MergeStmt:
472 : : case T_SelectStmt:
473 : : case T_ReturnStmt:
474 : : case T_PLAssignStmt:
475 : 16304374 : result = true;
476 : 16304374 : break;
477 : :
478 : : /*
479 : : * Special cases
480 : : */
481 : 25360 : case T_DeclareCursorStmt:
482 : : case T_ExplainStmt:
483 : : case T_CreateTableAsStmt:
484 : : case T_CallStmt:
485 : 25360 : result = true;
486 : 25360 : break;
487 : :
488 : 424289 : default:
489 : : /* all other statements just get wrapped in a CMD_UTILITY Query */
490 : 424289 : result = false;
491 : 424289 : break;
492 : : }
493 : :
494 : 16754023 : return result;
495 : : }
496 : :
497 : : /*
498 : : * analyze_requires_snapshot
499 : : * Returns true if a snapshot must be set before doing parse analysis
500 : : * on the given raw parse tree.
501 : : */
502 : : bool
845 503 : 370180 : analyze_requires_snapshot(RawStmt *parseTree)
504 : : {
505 : : /*
506 : : * Currently, this should return true in exactly the same cases that
507 : : * stmt_requires_parse_analysis() does, so we just invoke that function
508 : : * rather than duplicating it. We keep the two entry points separate for
509 : : * clarity of callers, since from the callers' standpoint these are
510 : : * different conditions.
511 : : *
512 : : * While there may someday be a statement type for which transformStmt()
513 : : * does something nontrivial and yet no snapshot is needed for that
514 : : * processing, it seems likely that making such a choice would be fragile.
515 : : * If you want to install an exception, document the reasoning for it in a
516 : : * comment.
517 : : */
518 : 370180 : return stmt_requires_parse_analysis(parseTree);
519 : : }
520 : :
521 : : /*
522 : : * query_requires_rewrite_plan()
523 : : * Returns true if rewriting or planning is non-trivial for this Query.
524 : : *
525 : : * This is much like stmt_requires_parse_analysis(), but applies one step
526 : : * further down the pipeline.
527 : : *
528 : : * We do not provide an equivalent of analyze_requires_snapshot(): callers
529 : : * can assume that any rewriting or planning activity needs a snapshot.
530 : : */
531 : : bool
258 532 : 251505 : query_requires_rewrite_plan(Query *query)
533 : : {
534 : : bool result;
535 : :
536 [ + - ]: 251505 : if (query->commandType != CMD_UTILITY)
537 : : {
538 : : /* All optimizable statements require rewriting/planning */
539 : 251505 : result = true;
540 : : }
541 : : else
542 : : {
543 : : /* This list should match stmt_requires_parse_analysis() */
258 tgl@sss.pgh.pa.us 544 [ # # ]:UBC 0 : switch (nodeTag(query->utilityStmt))
545 : : {
546 : 0 : case T_DeclareCursorStmt:
547 : : case T_ExplainStmt:
548 : : case T_CreateTableAsStmt:
549 : : case T_CallStmt:
550 : 0 : result = true;
551 : 0 : break;
552 : 0 : default:
553 : 0 : result = false;
554 : 0 : break;
555 : : }
556 : : }
258 tgl@sss.pgh.pa.us 557 :CBC 251505 : return result;
558 : : }
559 : :
560 : : /*
561 : : * transformDeleteStmt -
562 : : * transforms a Delete Statement
563 : : */
564 : : static Query *
10326 bruce@momjian.us 565 : 2275 : transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
566 : : {
567 : 2275 : Query *qry = makeNode(Query);
568 : : ParseNamespaceItem *nsitem;
569 : : Node *qual;
570 : :
10327 571 : 2275 : qry->commandType = CMD_DELETE;
572 : :
573 : : /* process the WITH clause independently of all else */
5541 tgl@sss.pgh.pa.us 574 [ + + ]: 2275 : if (stmt->withClause)
575 : : {
576 : 16 : qry->hasRecursive = stmt->withClause->recursive;
577 : 16 : qry->cteList = transformWithClause(pstate, stmt->withClause);
5408 578 : 16 : qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
579 : : }
580 : :
581 : : /* set up range table with just the result rel */
8670 582 : 4547 : qry->resultRelation = setTargetTable(pstate, stmt->relation,
3280 583 : 2275 : stmt->relation->inh,
584 : : true,
585 : : ACL_DELETE);
2175 586 : 2272 : nsitem = pstate->p_target_nsitem;
587 : :
588 : : /* there's no DISTINCT in DELETE */
9455 589 : 2272 : qry->distinctClause = NIL;
590 : :
591 : : /* subqueries in USING cannot access the result relation */
4361 592 : 2272 : nsitem->p_lateral_only = true;
4357 593 : 2272 : nsitem->p_lateral_ok = false;
594 : :
595 : : /*
596 : : * The USING clause is non-standard SQL syntax, and is equivalent in
597 : : * functionality to the FROM list that can be specified for UPDATE. The
598 : : * USING keyword is used rather than FROM because FROM is already a
599 : : * keyword in the DELETE syntax.
600 : : */
7558 neilc@samurai.com 601 : 2272 : transformFromClause(pstate, stmt->usingClause);
602 : :
603 : : /* remaining clauses can reference the result relation normally */
4361 tgl@sss.pgh.pa.us 604 : 2263 : nsitem->p_lateral_only = false;
4357 605 : 2263 : nsitem->p_lateral_ok = true;
606 : :
4876 607 : 2263 : qual = transformWhereClause(pstate, stmt->whereClause,
608 : : EXPR_KIND_WHERE, "WHERE");
609 : :
334 dean.a.rasheed@gmail 610 : 2251 : transformReturningClause(pstate, qry, stmt->returningClause,
611 : : EXPR_KIND_RETURNING);
612 : :
613 : : /* done building the range table and jointree */
10327 bruce@momjian.us 614 : 2248 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 615 : 2248 : qry->rteperminfos = pstate->p_rteperminfos;
9209 tgl@sss.pgh.pa.us 616 : 2248 : qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
617 : :
9528 618 : 2248 : qry->hasSubLinks = pstate->p_hasSubLinks;
6197 619 : 2248 : qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
3381 620 : 2248 : qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
5060 621 : 2248 : qry->hasAggs = pstate->p_hasAggs;
622 : :
5386 623 : 2248 : assign_query_collations(pstate, qry);
624 : :
625 : : /* this must be done after collations, for reliable comparison of exprs */
2525 rhodiumtoad@postgres 626 [ - + ]: 2248 : if (pstate->p_hasAggs)
2525 rhodiumtoad@postgres 627 :UBC 0 : parseCheckAggregates(pstate, qry);
628 : :
9203 tgl@sss.pgh.pa.us 629 :CBC 2248 : return qry;
630 : : }
631 : :
632 : : /*
633 : : * transformInsertStmt -
634 : : * transform an Insert Statement
635 : : */
636 : : static Query *
6751 637 : 33349 : transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
638 : : {
9647 639 : 33349 : Query *qry = makeNode(Query);
7076 mail@joeconway.com 640 : 33349 : SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt;
641 : 33349 : List *exprList = NIL;
642 : : bool isGeneralSelect;
643 : : List *sub_rtable;
644 : : List *sub_rteperminfos;
645 : : List *sub_namespace;
646 : : List *icolumns;
647 : : List *attrnos;
648 : : ParseNamespaceItem *nsitem;
649 : : RTEPermissionInfo *perminfo;
650 : : ListCell *icols;
651 : : ListCell *attnos;
652 : : ListCell *lc;
653 : : bool isOnConflictUpdate;
654 : : AclMode targetPerms;
655 : :
656 : : /* There can't be any outer WITH to worry about */
5541 tgl@sss.pgh.pa.us 657 [ - + ]: 33349 : Assert(pstate->p_ctenamespace == NIL);
658 : :
10327 bruce@momjian.us 659 : 33349 : qry->commandType = CMD_INSERT;
660 : 33349 : pstate->p_is_insert = true;
661 : :
662 : : /* process the WITH clause independently of all else */
5541 tgl@sss.pgh.pa.us 663 [ + + ]: 33349 : if (stmt->withClause)
664 : : {
665 : 152 : qry->hasRecursive = stmt->withClause->recursive;
666 : 152 : qry->cteList = transformWithClause(pstate, stmt->withClause);
5408 667 : 152 : qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
668 : : }
669 : :
3176 peter_e@gmx.net 670 : 33349 : qry->override = stmt->override;
671 : :
3875 andres@anarazel.de 672 [ + + ]: 34322 : isOnConflictUpdate = (stmt->onConflictClause &&
3100 tgl@sss.pgh.pa.us 673 [ + + ]: 973 : stmt->onConflictClause->action == ONCONFLICT_UPDATE);
674 : :
675 : : /*
676 : : * We have three cases to deal with: DEFAULT VALUES (selectStmt == NULL),
677 : : * VALUES list, or general SELECT input. We special-case VALUES, both for
678 : : * efficiency and so we can handle DEFAULT specifications.
679 : : *
680 : : * The grammar allows attaching ORDER BY, LIMIT, FOR UPDATE, or WITH to a
681 : : * VALUES clause. If we have any of those, treat it as a general SELECT;
682 : : * so it will work, but you can't use DEFAULT items together with those.
683 : : */
5554 684 [ + + + + ]: 57619 : isGeneralSelect = (selectStmt && (selectStmt->valuesLists == NIL ||
685 [ + - ]: 24270 : selectStmt->sortClause != NIL ||
686 [ + - ]: 24270 : selectStmt->limitOffset != NULL ||
687 [ + - ]: 24270 : selectStmt->limitCount != NULL ||
688 [ + - ]: 24270 : selectStmt->lockingClause != NIL ||
689 [ - + ]: 24270 : selectStmt->withClause != NULL));
690 : :
691 : : /*
692 : : * If a non-nil rangetable/namespace was passed in, and we are doing
693 : : * INSERT/SELECT, arrange to pass the rangetable/rteperminfos/namespace
694 : : * down to the SELECT. This can only happen if we are inside a CREATE
695 : : * RULE, and in that case we want the rule's OLD and NEW rtable entries to
696 : : * appear as part of the SELECT's rtable, not as outer references for it.
697 : : * (Kluge!) The SELECT's joinlist is not affected however. We must do
698 : : * this before adding the target table to the INSERT's rtable.
699 : : */
7076 mail@joeconway.com 700 [ + + ]: 33349 : if (isGeneralSelect)
701 : : {
9071 tgl@sss.pgh.pa.us 702 : 3679 : sub_rtable = pstate->p_rtable;
703 : 3679 : pstate->p_rtable = NIL;
1106 alvherre@alvh.no-ip. 704 : 3679 : sub_rteperminfos = pstate->p_rteperminfos;
705 : 3679 : pstate->p_rteperminfos = NIL;
4878 tgl@sss.pgh.pa.us 706 : 3679 : sub_namespace = pstate->p_namespace;
707 : 3679 : pstate->p_namespace = NIL;
708 : : }
709 : : else
710 : : {
9071 711 : 29670 : sub_rtable = NIL; /* not used, but keep compiler quiet */
1085 712 : 29670 : sub_rteperminfos = NIL;
4878 713 : 29670 : sub_namespace = NIL;
714 : : }
715 : :
716 : : /*
717 : : * Must get write lock on INSERT target table before scanning SELECT, else
718 : : * we will grab the wrong kind of initial lock if the target table is also
719 : : * mentioned in the SELECT part. Note that the target table is not added
720 : : * to the joinlist or namespace.
721 : : */
3875 andres@anarazel.de 722 : 33349 : targetPerms = ACL_INSERT;
723 [ + + ]: 33349 : if (isOnConflictUpdate)
724 : 671 : targetPerms |= ACL_UPDATE;
8670 tgl@sss.pgh.pa.us 725 : 33349 : qry->resultRelation = setTargetTable(pstate, stmt->relation,
726 : : false, false, targetPerms);
727 : :
728 : : /* Validate stmt->cols list, or build default list if no list given */
7076 mail@joeconway.com 729 : 33340 : icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
730 [ - + ]: 33316 : Assert(list_length(icolumns) == list_length(attrnos));
731 : :
732 : : /*
733 : : * Determine which variant of INSERT we have.
734 : : */
735 [ + + ]: 33316 : if (selectStmt == NULL)
736 : : {
737 : : /*
738 : : * We have INSERT ... DEFAULT VALUES. We can handle this case by
739 : : * emitting an empty targetlist --- all columns will be defaulted when
740 : : * the planner expands the targetlist.
741 : : */
742 : 5400 : exprList = NIL;
743 : : }
744 [ + + ]: 27916 : else if (isGeneralSelect)
745 : : {
746 : : /*
747 : : * We make the sub-pstate a child of the outer pstate so that it can
748 : : * see any Param definitions supplied from above. Since the outer
749 : : * pstate's rtable and namespace are presently empty, there are no
750 : : * side-effects of exposing names the sub-SELECT shouldn't be able to
751 : : * see.
752 : : */
8267 tgl@sss.pgh.pa.us 753 : 3679 : ParseState *sub_pstate = make_parsestate(pstate);
754 : : Query *selectQuery;
755 : :
756 : : /*
757 : : * Process the source SELECT.
758 : : *
759 : : * It is important that this be handled just like a standalone SELECT;
760 : : * otherwise the behavior of SELECT within INSERT might be different
761 : : * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
762 : : * bugs of just that nature...)
763 : : *
764 : : * The sole exception is that we prevent resolving unknown-type
765 : : * outputs as TEXT. This does not change the semantics since if the
766 : : * column type matters semantically, it would have been resolved to
767 : : * something else anyway. Doing this lets us resolve such outputs as
768 : : * the target column's type, which we handle below.
769 : : */
9071 770 : 3679 : sub_pstate->p_rtable = sub_rtable;
1106 alvherre@alvh.no-ip. 771 : 3679 : sub_pstate->p_rteperminfos = sub_rteperminfos;
6032 bruce@momjian.us 772 : 3679 : sub_pstate->p_joinexprs = NIL; /* sub_rtable has no joins */
1051 tgl@sss.pgh.pa.us 773 : 3679 : sub_pstate->p_nullingrels = NIL;
4878 774 : 3679 : sub_pstate->p_namespace = sub_namespace;
3247 775 : 3679 : sub_pstate->p_resolve_unknowns = false;
776 : :
6751 777 : 3679 : selectQuery = transformStmt(sub_pstate, stmt->selectStmt);
778 : :
779 : 3676 : free_parsestate(sub_pstate);
780 : :
781 : : /* The grammar should have produced a SELECT */
6315 782 [ + - ]: 3676 : if (!IsA(selectQuery, Query) ||
3258 783 [ - + ]: 3676 : selectQuery->commandType != CMD_SELECT)
6315 tgl@sss.pgh.pa.us 784 [ # # ]:UBC 0 : elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT");
785 : :
786 : : /*
787 : : * Make the source be a subquery in the INSERT's rangetable, and add
788 : : * it to the INSERT's joinlist (but not the namespace).
789 : : */
2175 tgl@sss.pgh.pa.us 790 :CBC 3676 : nsitem = addRangeTableEntryForSubquery(pstate,
791 : : selectQuery,
792 : : NULL,
793 : : false,
794 : : false);
795 : 3676 : addNSItemToQuery(pstate, nsitem, true, false, false);
796 : :
797 : : /*----------
798 : : * Generate an expression list for the INSERT that selects all the
799 : : * non-resjunk columns from the subquery. (INSERT's tlist must be
800 : : * separate from the subquery's tlist because we may add columns,
801 : : * insert datatype coercions, etc.)
802 : : *
803 : : * HACK: unknown-type constants and params in the SELECT's targetlist
804 : : * are copied up as-is rather than being referenced as subquery
805 : : * outputs. This is to ensure that when we try to coerce them to
806 : : * the target column's datatype, the right things happen (see
807 : : * special cases in coerce_type). Otherwise, this fails:
808 : : * INSERT INTO foo SELECT 'bar', ... FROM baz
809 : : *----------
810 : : */
7076 mail@joeconway.com 811 : 3676 : exprList = NIL;
812 [ + + + + : 12989 : foreach(lc, selectQuery->targetList)
+ + ]
813 : : {
814 : 9313 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
815 : : Expr *expr;
816 : :
7559 tgl@sss.pgh.pa.us 817 [ + + ]: 9313 : if (tle->resjunk)
9203 818 : 50 : continue;
8267 819 [ + - ]: 9263 : if (tle->expr &&
2040 820 [ + + + + : 11562 : (IsA(tle->expr, Const) || IsA(tle->expr, Param)) &&
+ + ]
8267 821 : 2299 : exprType((Node *) tle->expr) == UNKNOWNOID)
9203 822 : 703 : expr = tle->expr;
823 : : else
824 : : {
2175 825 : 8560 : Var *var = makeVarFromTargetEntry(nsitem->p_rtindex, tle);
826 : :
6279 827 : 8560 : var->location = exprLocation((Node *) tle->expr);
828 : 8560 : expr = (Expr *) var;
829 : : }
7076 mail@joeconway.com 830 : 9263 : exprList = lappend(exprList, expr);
831 : : }
832 : :
833 : : /* Prepare row for assignment to target table */
834 : 3676 : exprList = transformInsertRow(pstate, exprList,
835 : : stmt->cols,
836 : : icolumns, attrnos,
837 : : false);
838 : : }
839 [ + + ]: 24237 : else if (list_length(selectStmt->valuesLists) > 1)
840 : : {
841 : : /*
842 : : * Process INSERT ... VALUES with multiple VALUES sublists. We
843 : : * generate a VALUES RTE holding the transformed expression lists, and
844 : : * build up a targetlist containing Vars that reference the VALUES
845 : : * RTE.
846 : : */
847 : 2475 : List *exprsLists = NIL;
3295 tgl@sss.pgh.pa.us 848 : 2475 : List *coltypes = NIL;
849 : 2475 : List *coltypmods = NIL;
850 : 2475 : List *colcollations = NIL;
7076 mail@joeconway.com 851 : 2475 : int sublist_length = -1;
4867 tgl@sss.pgh.pa.us 852 : 2475 : bool lateral = false;
853 : :
5020 854 [ - + ]: 2475 : Assert(selectStmt->intoClause == NULL);
855 : :
7076 mail@joeconway.com 856 [ + - + + : 10819 : foreach(lc, selectStmt->valuesLists)
+ + ]
857 : : {
7013 bruce@momjian.us 858 : 8344 : List *sublist = (List *) lfirst(lc);
859 : :
860 : : /*
861 : : * Do basic expression transformation (same as a ROW() expr, but
862 : : * allow SetToDefault at top level)
863 : : */
3311 tgl@sss.pgh.pa.us 864 : 8344 : sublist = transformExpressionList(pstate, sublist,
865 : : EXPR_KIND_VALUES, true);
866 : :
867 : : /*
868 : : * All the sublists must be the same length, *after*
869 : : * transformation (which might expand '*' into multiple items).
870 : : * The VALUES RTE can't handle anything different.
871 : : */
7076 mail@joeconway.com 872 [ + + ]: 8344 : if (sublist_length < 0)
873 : : {
874 : : /* Remember post-transformation length of first sublist */
875 : 2475 : sublist_length = list_length(sublist);
876 : : }
877 [ - + ]: 5869 : else if (sublist_length != list_length(sublist))
878 : : {
7076 mail@joeconway.com 879 [ # # ]:UBC 0 : ereport(ERROR,
880 : : (errcode(ERRCODE_SYNTAX_ERROR),
881 : : errmsg("VALUES lists must all be the same length"),
882 : : parser_errposition(pstate,
883 : : exprLocation((Node *) sublist))));
884 : : }
885 : :
886 : : /*
887 : : * Prepare row for assignment to target table. We process any
888 : : * indirection on the target column specs normally but then strip
889 : : * off the resulting field/array assignment nodes, since we don't
890 : : * want the parsed statement to contain copies of those in each
891 : : * VALUES row. (It's annoying to have to transform the
892 : : * indirection specs over and over like this, but avoiding it
893 : : * would take some really messy refactoring of
894 : : * transformAssignmentIndirection.)
895 : : */
7076 mail@joeconway.com 896 :CBC 8344 : sublist = transformInsertRow(pstate, sublist,
897 : : stmt->cols,
898 : : icolumns, attrnos,
899 : : true);
900 : :
901 : : /*
902 : : * We must assign collations now because assign_query_collations
903 : : * doesn't process rangetable entries. We just assign all the
904 : : * collations independently in each row, and don't worry about
905 : : * whether they are consistent vertically. The outer INSERT query
906 : : * isn't going to care about the collations of the VALUES columns,
907 : : * so it's not worth the effort to identify a common collation for
908 : : * each one here. (But note this does have one user-visible
909 : : * consequence: INSERT ... VALUES won't complain about conflicting
910 : : * explicit COLLATEs in a column, whereas the same VALUES
911 : : * construct in another context would complain.)
912 : : */
5386 tgl@sss.pgh.pa.us 913 : 8344 : assign_list_collations(pstate, sublist);
914 : :
7076 mail@joeconway.com 915 : 8344 : exprsLists = lappend(exprsLists, sublist);
916 : : }
917 : :
918 : : /*
919 : : * Construct column type/typmod/collation lists for the VALUES RTE.
920 : : * Every expression in each column has been coerced to the type/typmod
921 : : * of the corresponding target column or subfield, so it's sufficient
922 : : * to look at the exprType/exprTypmod of the first row. We don't care
923 : : * about the collation labeling, so just fill in InvalidOid for that.
924 : : */
3295 tgl@sss.pgh.pa.us 925 [ + - + + : 7033 : foreach(lc, (List *) linitial(exprsLists))
+ + ]
926 : : {
927 : 4558 : Node *val = (Node *) lfirst(lc);
928 : :
929 : 4558 : coltypes = lappend_oid(coltypes, exprType(val));
930 : 4558 : coltypmods = lappend_int(coltypmods, exprTypmod(val));
931 : 4558 : colcollations = lappend_oid(colcollations, InvalidOid);
932 : : }
933 : :
934 : : /*
935 : : * Ordinarily there can't be any current-level Vars in the expression
936 : : * lists, because the namespace was empty ... but if we're inside
937 : : * CREATE RULE, then NEW/OLD references might appear. In that case we
938 : : * have to mark the VALUES RTE as LATERAL.
939 : : */
7076 940 [ + + + - ]: 2489 : if (list_length(pstate->p_rtable) != 1 &&
941 : 14 : contain_vars_of_level((Node *) exprsLists, 0))
4867 942 : 14 : lateral = true;
943 : :
944 : : /*
945 : : * Generate the VALUES RTE
946 : : */
2175 947 : 2475 : nsitem = addRangeTableEntryForValues(pstate, exprsLists,
948 : : coltypes, coltypmods, colcollations,
949 : : NULL, lateral, true);
950 : 2475 : addNSItemToQuery(pstate, nsitem, true, false, false);
951 : :
952 : : /*
953 : : * Generate list of Vars referencing the RTE
954 : : */
1051 955 : 2475 : exprList = expandNSItemVars(pstate, nsitem, 0, -1, NULL);
956 : :
957 : : /*
958 : : * Re-apply any indirection on the target column specs to the Vars
959 : : */
3422 960 : 2475 : exprList = transformInsertRow(pstate, exprList,
961 : : stmt->cols,
962 : : icolumns, attrnos,
963 : : false);
964 : : }
965 : : else
966 : : {
967 : : /*
968 : : * Process INSERT ... VALUES with a single VALUES sublist. We treat
969 : : * this case separately for efficiency. The sublist is just computed
970 : : * directly as the Query's targetlist, with no VALUES RTE. So it
971 : : * works just like a SELECT without any FROM.
972 : : */
7076 mail@joeconway.com 973 : 21762 : List *valuesLists = selectStmt->valuesLists;
974 : :
975 [ - + ]: 21762 : Assert(list_length(valuesLists) == 1);
5020 tgl@sss.pgh.pa.us 976 [ - + ]: 21762 : Assert(selectStmt->intoClause == NULL);
977 : :
978 : : /*
979 : : * Do basic expression transformation (same as a ROW() expr, but allow
980 : : * SetToDefault at top level)
981 : : */
7076 mail@joeconway.com 982 : 21762 : exprList = transformExpressionList(pstate,
4876 tgl@sss.pgh.pa.us 983 : 21762 : (List *) linitial(valuesLists),
984 : : EXPR_KIND_VALUES_SINGLE,
985 : : true);
986 : :
987 : : /* Prepare row for assignment to target table */
7076 mail@joeconway.com 988 : 21750 : exprList = transformInsertRow(pstate, exprList,
989 : : stmt->cols,
990 : : icolumns, attrnos,
991 : : false);
992 : : }
993 : :
994 : : /*
995 : : * Generate query's target list using the computed list of expressions.
996 : : * Also, mark all the target columns as needing insert permissions.
997 : : */
1106 alvherre@alvh.no-ip. 998 : 32686 : perminfo = pstate->p_target_nsitem->p_perminfo;
7076 mail@joeconway.com 999 : 32686 : qry->targetList = NIL;
2483 tgl@sss.pgh.pa.us 1000 [ - + ]: 32686 : Assert(list_length(exprList) <= list_length(icolumns));
1001 [ + + + + : 95118 : forthree(lc, exprList, icols, icolumns, attnos, attrnos)
+ + + + +
+ + + + +
+ - + - +
+ ]
1002 : : {
7013 bruce@momjian.us 1003 : 62432 : Expr *expr = (Expr *) lfirst(lc);
2483 tgl@sss.pgh.pa.us 1004 : 62432 : ResTarget *col = lfirst_node(ResTarget, icols);
1005 : 62432 : AttrNumber attr_num = (AttrNumber) lfirst_int(attnos);
1006 : : TargetEntry *tle;
1007 : :
7076 mail@joeconway.com 1008 : 62432 : tle = makeTargetEntry(expr,
1009 : : attr_num,
1010 : : col->name,
1011 : : false);
1012 : 62432 : qry->targetList = lappend(qry->targetList, tle);
1013 : :
1106 alvherre@alvh.no-ip. 1014 : 62432 : perminfo->insertedCols = bms_add_member(perminfo->insertedCols,
1015 : : attr_num - FirstLowInvalidHeapAttributeNumber);
1016 : : }
1017 : :
1018 : : /*
1019 : : * If we have any clauses yet to process, set the query namespace to
1020 : : * contain only the target relation, removing any entries added in a
1021 : : * sub-SELECT or VALUES list.
1022 : : */
334 dean.a.rasheed@gmail 1023 [ + + + + ]: 32686 : if (stmt->onConflictClause || stmt->returningClause)
1024 : : {
4878 tgl@sss.pgh.pa.us 1025 : 1465 : pstate->p_namespace = NIL;
2175 1026 : 1465 : addNSItemToQuery(pstate, pstate->p_target_nsitem,
1027 : : false, true, true);
1028 : : }
1029 : :
1030 : : /* Process ON CONFLICT, if any. */
1708 1031 [ + + ]: 32686 : if (stmt->onConflictClause)
1032 : 973 : qry->onConflict = transformOnConflictClause(pstate,
1033 : : stmt->onConflictClause);
1034 : :
1035 : : /* Process RETURNING, if any. */
334 dean.a.rasheed@gmail 1036 [ + + ]: 32656 : if (stmt->returningClause)
1037 : 639 : transformReturningClause(pstate, qry, stmt->returningClause,
1038 : : EXPR_KIND_RETURNING);
1039 : :
1040 : : /* done building the range table and jointree */
9203 tgl@sss.pgh.pa.us 1041 : 32632 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 1042 : 32632 : qry->rteperminfos = pstate->p_rteperminfos;
6751 tgl@sss.pgh.pa.us 1043 : 32632 : qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1044 : :
3381 1045 : 32632 : qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
6751 1046 : 32632 : qry->hasSubLinks = pstate->p_hasSubLinks;
1047 : :
5386 1048 : 32632 : assign_query_collations(pstate, qry);
1049 : :
6751 1050 : 32632 : return qry;
1051 : : }
1052 : :
1053 : : /*
1054 : : * Prepare an INSERT row for assignment to the target table.
1055 : : *
1056 : : * exprlist: transformed expressions for source values; these might come from
1057 : : * a VALUES row, or be Vars referencing a sub-SELECT or VALUES RTE output.
1058 : : * stmtcols: original target-columns spec for INSERT (we just test for NIL)
1059 : : * icolumns: effective target-columns spec (list of ResTarget)
1060 : : * attrnos: integer column numbers (must be same length as icolumns)
1061 : : * strip_indirection: if true, remove any field/array assignment nodes
1062 : : */
1063 : : List *
1064 : 36747 : transformInsertRow(ParseState *pstate, List *exprlist,
1065 : : List *stmtcols, List *icolumns, List *attrnos,
1066 : : bool strip_indirection)
1067 : : {
1068 : : List *result;
1069 : : ListCell *lc;
1070 : : ListCell *icols;
1071 : : ListCell *attnos;
1072 : :
1073 : : /*
1074 : : * Check length of expr list. It must not have more expressions than
1075 : : * there are target columns. We allow fewer, but only if no explicit
1076 : : * columns list was given (the remaining columns are implicitly
1077 : : * defaulted). Note we must check this *after* transformation because
1078 : : * that could expand '*' into multiple items.
1079 : : */
1080 [ + + ]: 36747 : if (list_length(exprlist) > list_length(icolumns))
1081 [ + - ]: 13 : ereport(ERROR,
1082 : : (errcode(ERRCODE_SYNTAX_ERROR),
1083 : : errmsg("INSERT has more expressions than target columns"),
1084 : : parser_errposition(pstate,
1085 : : exprLocation(list_nth(exprlist,
1086 : : list_length(icolumns))))));
1087 [ + + + + ]: 44819 : if (stmtcols != NIL &&
1088 : 8085 : list_length(exprlist) < list_length(icolumns))
1089 : : {
1090 : : /*
1091 : : * We can get here for cases like INSERT ... SELECT (a,b,c) FROM ...
1092 : : * where the user accidentally created a RowExpr instead of separate
1093 : : * columns. Add a suitable hint if that seems to be the problem,
1094 : : * because the main error message is quite misleading for this case.
1095 : : * (If there's no stmtcols, you'll get something about data type
1096 : : * mismatch, which is less misleading so we don't worry about giving a
1097 : : * hint in that case.)
1098 : : */
1099 [ + - - + : 6 : ereport(ERROR,
- - ]
1100 : : (errcode(ERRCODE_SYNTAX_ERROR),
1101 : : errmsg("INSERT has more target columns than expressions"),
1102 : : ((list_length(exprlist) == 1 &&
1103 : : count_rowexpr_columns(pstate, linitial(exprlist)) ==
1104 : : list_length(icolumns)) ?
1105 : : errhint("The insertion source is a row expression containing the same number of columns expected by the INSERT. Did you accidentally use extra parentheses?") : 0),
1106 : : parser_errposition(pstate,
1107 : : exprLocation(list_nth(icolumns,
1108 : : list_length(exprlist))))));
1109 : : }
1110 : :
1111 : : /*
1112 : : * Prepare columns for assignment to target table.
1113 : : */
1114 : 36728 : result = NIL;
2483 1115 [ + + + + : 117824 : forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
+ + + + +
+ + + + +
+ - + - +
+ ]
1116 : : {
6751 1117 : 81692 : Expr *expr = (Expr *) lfirst(lc);
2483 1118 : 81692 : ResTarget *col = lfirst_node(ResTarget, icols);
1119 : 81692 : int attno = lfirst_int(attnos);
1120 : :
6751 1121 : 81692 : expr = transformAssignedExpr(pstate, expr,
1122 : : EXPR_KIND_INSERT_TARGET,
1123 : 81692 : col->name,
1124 : : attno,
1125 : : col->indirection,
1126 : : col->location);
1127 : :
3422 1128 [ + + ]: 81096 : if (strip_indirection)
1129 : : {
1130 : : /*
1131 : : * We need to remove top-level FieldStores and SubscriptingRefs,
1132 : : * as well as any CoerceToDomain appearing above one of those ---
1133 : : * but not a CoerceToDomain that isn't above one of those.
1134 : : */
1135 [ + - ]: 17788 : while (expr)
1136 : : {
642 1137 : 17788 : Expr *subexpr = expr;
1138 : :
1139 [ + + ]: 17896 : while (IsA(subexpr, CoerceToDomain))
1140 : : {
1141 : 108 : subexpr = ((CoerceToDomain *) subexpr)->arg;
1142 : : }
1143 [ + + ]: 17788 : if (IsA(subexpr, FieldStore))
1144 : : {
1145 : 108 : FieldStore *fstore = (FieldStore *) subexpr;
1146 : :
3422 1147 : 108 : expr = (Expr *) linitial(fstore->newvals);
1148 : : }
642 1149 [ + + ]: 17680 : else if (IsA(subexpr, SubscriptingRef))
1150 : : {
1151 : 174 : SubscriptingRef *sbsref = (SubscriptingRef *) subexpr;
1152 : :
2510 alvherre@alvh.no-ip. 1153 [ - + ]: 174 : if (sbsref->refassgnexpr == NULL)
3422 tgl@sss.pgh.pa.us 1154 :UBC 0 : break;
1155 : :
2510 alvherre@alvh.no-ip. 1156 :CBC 174 : expr = sbsref->refassgnexpr;
1157 : : }
1158 : : else
3422 tgl@sss.pgh.pa.us 1159 : 17506 : break;
1160 : : }
1161 : : }
1162 : :
6751 1163 : 81096 : result = lappend(result, expr);
1164 : : }
1165 : :
1166 : 36132 : return result;
1167 : : }
1168 : :
1169 : : /*
1170 : : * transformOnConflictClause -
1171 : : * transforms an OnConflictClause in an INSERT
1172 : : */
1173 : : static OnConflictExpr *
3875 andres@anarazel.de 1174 : 973 : transformOnConflictClause(ParseState *pstate,
1175 : : OnConflictClause *onConflictClause)
1176 : : {
1708 tgl@sss.pgh.pa.us 1177 : 973 : ParseNamespaceItem *exclNSItem = NULL;
1178 : : List *arbiterElems;
1179 : : Node *arbiterWhere;
1180 : : Oid arbiterConstraint;
3875 andres@anarazel.de 1181 : 973 : List *onConflictSet = NIL;
1182 : 973 : Node *onConflictWhere = NULL;
1183 : 973 : int exclRelIndex = 0;
1184 : 973 : List *exclRelTlist = NIL;
1185 : : OnConflictExpr *result;
1186 : :
1187 : : /*
1188 : : * If this is ON CONFLICT ... UPDATE, first create the range table entry
1189 : : * for the EXCLUDED pseudo relation, so that that will be present while
1190 : : * processing arbiter expressions. (You can't actually reference it from
1191 : : * there, but this provides a useful error message if you try.)
1192 : : */
1193 [ + + ]: 973 : if (onConflictClause->action == ONCONFLICT_UPDATE)
1194 : : {
3727 1195 : 671 : Relation targetrel = pstate->p_target_relation;
1196 : : RangeTblEntry *exclRte;
1197 : :
2175 tgl@sss.pgh.pa.us 1198 : 671 : exclNSItem = addRangeTableEntryForRelation(pstate,
1199 : : targetrel,
1200 : : RowExclusiveLock,
1201 : : makeAlias("excluded", NIL),
1202 : : false, false);
1203 : 671 : exclRte = exclNSItem->p_rte;
1204 : 671 : exclRelIndex = exclNSItem->p_rtindex;
1205 : :
1206 : : /*
1207 : : * relkind is set to composite to signal that we're not dealing with
1208 : : * an actual relation, and no permission checks are required on it.
1209 : : * (We'll check the actual target relation, instead.)
1210 : : */
3727 andres@anarazel.de 1211 : 671 : exclRte->relkind = RELKIND_COMPOSITE_TYPE;
1212 : :
1213 : : /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
2691 tgl@sss.pgh.pa.us 1214 : 671 : exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
1215 : : exclRelIndex);
1216 : : }
1217 : :
1218 : : /* Process the arbiter clause, ON CONFLICT ON (...) */
1708 1219 : 973 : transformOnConflictArbiter(pstate, onConflictClause, &arbiterElems,
1220 : : &arbiterWhere, &arbiterConstraint);
1221 : :
1222 : : /* Process DO UPDATE */
1223 [ + + ]: 958 : if (onConflictClause->action == ONCONFLICT_UPDATE)
1224 : : {
1225 : : /*
1226 : : * Expressions in the UPDATE targetlist need to be handled like UPDATE
1227 : : * not INSERT. We don't need to save/restore this because all INSERT
1228 : : * expressions have been parsed already.
1229 : : */
1230 : 665 : pstate->p_is_insert = false;
1231 : :
1232 : : /*
1233 : : * Add the EXCLUDED pseudo relation to the query namespace, making it
1234 : : * available in the UPDATE subexpressions.
1235 : : */
2175 1236 : 665 : addNSItemToQuery(pstate, exclNSItem, false, true, true);
1237 : :
1238 : : /*
1239 : : * Now transform the UPDATE subexpressions.
1240 : : */
1241 : : onConflictSet =
3875 andres@anarazel.de 1242 : 665 : transformUpdateTargetList(pstate, onConflictClause->targetList);
1243 : :
1244 : 650 : onConflictWhere = transformWhereClause(pstate,
1245 : : onConflictClause->whereClause,
1246 : : EXPR_KIND_WHERE, "WHERE");
1247 : :
1248 : : /*
1249 : : * Remove the EXCLUDED pseudo relation from the query namespace, since
1250 : : * it's not supposed to be available in RETURNING. (Maybe someday we
1251 : : * could allow that, and drop this step.)
1252 : : */
1708 tgl@sss.pgh.pa.us 1253 [ - + ]: 650 : Assert((ParseNamespaceItem *) llast(pstate->p_namespace) == exclNSItem);
1254 : 650 : pstate->p_namespace = list_delete_last(pstate->p_namespace);
1255 : : }
1256 : :
1257 : : /* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */
3875 andres@anarazel.de 1258 : 943 : result = makeNode(OnConflictExpr);
1259 : :
1260 : 943 : result->action = onConflictClause->action;
1261 : 943 : result->arbiterElems = arbiterElems;
1262 : 943 : result->arbiterWhere = arbiterWhere;
1263 : 943 : result->constraint = arbiterConstraint;
1264 : 943 : result->onConflictSet = onConflictSet;
1265 : 943 : result->onConflictWhere = onConflictWhere;
1266 : 943 : result->exclRelIndex = exclRelIndex;
1267 : 943 : result->exclRelTlist = exclRelTlist;
1268 : :
1269 : 943 : return result;
1270 : : }
1271 : :
1272 : :
1273 : : /*
1274 : : * BuildOnConflictExcludedTargetlist
1275 : : * Create target list for the EXCLUDED pseudo-relation of ON CONFLICT,
1276 : : * representing the columns of targetrel with varno exclRelIndex.
1277 : : *
1278 : : * Note: Exported for use in the rewriter.
1279 : : */
1280 : : List *
2691 tgl@sss.pgh.pa.us 1281 : 743 : BuildOnConflictExcludedTargetlist(Relation targetrel,
1282 : : Index exclRelIndex)
1283 : : {
1284 : 743 : List *result = NIL;
1285 : : int attno;
1286 : : Var *var;
1287 : : TargetEntry *te;
1288 : :
1289 : : /*
1290 : : * Note that resnos of the tlist must correspond to attnos of the
1291 : : * underlying relation, hence we need entries for dropped columns too.
1292 : : */
1293 [ + + ]: 2640 : for (attno = 0; attno < RelationGetNumberOfAttributes(targetrel); attno++)
1294 : : {
1295 : 1897 : Form_pg_attribute attr = TupleDescAttr(targetrel->rd_att, attno);
1296 : : char *name;
1297 : :
1298 [ + + ]: 1897 : if (attr->attisdropped)
1299 : : {
1300 : : /*
1301 : : * can't use atttypid here, but it doesn't really matter what type
1302 : : * the Const claims to be.
1303 : : */
1304 : 32 : var = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
2646 1305 : 32 : name = NULL;
1306 : : }
1307 : : else
1308 : : {
2691 1309 : 1865 : var = makeVar(exclRelIndex, attno + 1,
1310 : : attr->atttypid, attr->atttypmod,
1311 : : attr->attcollation,
1312 : : 0);
1313 : 1865 : name = pstrdup(NameStr(attr->attname));
1314 : : }
1315 : :
1316 : 1897 : te = makeTargetEntry((Expr *) var,
1317 : 1897 : attno + 1,
1318 : : name,
1319 : : false);
1320 : :
1321 : 1897 : result = lappend(result, te);
1322 : : }
1323 : :
1324 : : /*
1325 : : * Add a whole-row-Var entry to support references to "EXCLUDED.*". Like
1326 : : * the other entries in the EXCLUDED tlist, its resno must match the Var's
1327 : : * varattno, else the wrong things happen while resolving references in
1328 : : * setrefs.c. This is against normal conventions for targetlists, but
1329 : : * it's okay since we don't use this as a real tlist.
1330 : : */
1331 : 743 : var = makeVar(exclRelIndex, InvalidAttrNumber,
1332 : 743 : targetrel->rd_rel->reltype,
1333 : : -1, InvalidOid, 0);
1334 : 743 : te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true);
1335 : 743 : result = lappend(result, te);
1336 : :
1337 : 743 : return result;
1338 : : }
1339 : :
1340 : :
1341 : : /*
1342 : : * count_rowexpr_columns -
1343 : : * get number of columns contained in a ROW() expression;
1344 : : * return -1 if expression isn't a RowExpr or a Var referencing one.
1345 : : *
1346 : : * This is currently used only for hint purposes, so we aren't terribly
1347 : : * tense about recognizing all possible cases. The Var case is interesting
1348 : : * because that's what we'll get in the INSERT ... SELECT (...) case.
1349 : : */
1350 : : static int
5568 tgl@sss.pgh.pa.us 1351 :UBC 0 : count_rowexpr_columns(ParseState *pstate, Node *expr)
1352 : : {
1353 [ # # ]: 0 : if (expr == NULL)
1354 : 0 : return -1;
1355 [ # # ]: 0 : if (IsA(expr, RowExpr))
1356 : 0 : return list_length(((RowExpr *) expr)->args);
1357 [ # # ]: 0 : if (IsA(expr, Var))
1358 : : {
1359 : 0 : Var *var = (Var *) expr;
1360 : 0 : AttrNumber attnum = var->varattno;
1361 : :
1362 [ # # # # ]: 0 : if (attnum > 0 && var->vartype == RECORDOID)
1363 : : {
1364 : : RangeTblEntry *rte;
1365 : :
1366 : 0 : rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
1367 [ # # ]: 0 : if (rte->rtekind == RTE_SUBQUERY)
1368 : : {
1369 : : /* Subselect-in-FROM: examine sub-select's output expr */
1370 : 0 : TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
1371 : : attnum);
1372 : :
1373 [ # # # # ]: 0 : if (ste == NULL || ste->resjunk)
1374 : 0 : return -1;
1375 : 0 : expr = (Node *) ste->expr;
1376 [ # # ]: 0 : if (IsA(expr, RowExpr))
1377 : 0 : return list_length(((RowExpr *) expr)->args);
1378 : : }
1379 : : }
1380 : : }
1381 : 0 : return -1;
1382 : : }
1383 : :
1384 : :
1385 : : /*
1386 : : * transformSelectStmt -
1387 : : * transforms a Select Statement
1388 : : *
1389 : : * This function is also used to transform the source expression of a
1390 : : * PLAssignStmt. In that usage, passthru is non-NULL and we need to
1391 : : * call transformPLAssignStmtTarget after the initial transformation of the
1392 : : * SELECT's targetlist. (We could generalize this into an arbitrary callback
1393 : : * function, but for now that would just be more notation with no benefit.)
1394 : : * All the rest is the same as a regular SelectStmt.
1395 : : *
1396 : : * Note: this covers only cases with no set operations and no VALUES lists;
1397 : : * see below for the other cases.
1398 : : */
1399 : : static Query *
80 tgl@sss.pgh.pa.us 1400 :GNC 240566 : transformSelectStmt(ParseState *pstate, SelectStmt *stmt,
1401 : : SelectStmtPassthrough *passthru)
1402 : : {
10326 bruce@momjian.us 1403 :CBC 240566 : Query *qry = makeNode(Query);
1404 : : Node *qual;
1405 : : ListCell *l;
1406 : :
10327 1407 : 240566 : qry->commandType = CMD_SELECT;
1408 : :
1409 : : /* process the WITH clause independently of all else */
6282 tgl@sss.pgh.pa.us 1410 [ + + ]: 240566 : if (stmt->withClause)
1411 : : {
1412 : 1295 : qry->hasRecursive = stmt->withClause->recursive;
1413 : 1295 : qry->cteList = transformWithClause(pstate, stmt->withClause);
5408 1414 : 1147 : qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1415 : : }
1416 : :
1417 : : /* Complain if we get called from someplace where INTO is not allowed */
5020 1418 [ + + ]: 240418 : if (stmt->intoClause)
1419 [ + - ]: 9 : ereport(ERROR,
1420 : : (errcode(ERRCODE_SYNTAX_ERROR),
1421 : : errmsg("SELECT ... INTO is not allowed here"),
1422 : : parser_errposition(pstate,
1423 : : exprLocation((Node *) stmt->intoClause))));
1424 : :
1425 : : /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
5786 1426 : 240409 : pstate->p_locking_clause = stmt->lockingClause;
1427 : :
1428 : : /* make WINDOW info available for window functions, too */
1429 : 240409 : pstate->p_windowdefs = stmt->windowClause;
1430 : :
1431 : : /* process the FROM clause */
9071 1432 : 240409 : transformFromClause(pstate, stmt->fromClause);
1433 : :
1434 : : /* transform targetlist */
4876 1435 : 240100 : qry->targetList = transformTargetList(pstate, stmt->targetList,
1436 : : EXPR_KIND_SELECT_TARGET);
1437 : :
1438 : : /*
1439 : : * If we're within a PLAssignStmt, do further transformation of the
1440 : : * targetlist; that has to happen before we consider sorting or grouping.
1441 : : * Otherwise, mark column origins (which are useless in a PLAssignStmt).
1442 : : */
80 tgl@sss.pgh.pa.us 1443 [ + + ]:GNC 237404 : if (passthru)
1444 : 2845 : qry->targetList = transformPLAssignStmtTarget(pstate, qry->targetList,
1445 : : passthru);
1446 : : else
1447 : 234559 : markTargetListOrigins(pstate, qry->targetList);
1448 : :
1449 : : /* transform WHERE */
4876 tgl@sss.pgh.pa.us 1450 :CBC 237397 : qual = transformWhereClause(pstate, stmt->whereClause,
1451 : : EXPR_KIND_WHERE, "WHERE");
1452 : :
1453 : : /* initial processing of HAVING clause is much like WHERE clause */
8202 1454 : 237343 : qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
1455 : : EXPR_KIND_HAVING, "HAVING");
1456 : :
1457 : : /*
1458 : : * Transform sorting/grouping stuff. Do ORDER BY first because both
1459 : : * transformGroupClause and transformDistinctClause need the results. Note
1460 : : * that these functions can also change the targetList, so it's passed to
1461 : : * them by reference.
1462 : : */
10327 bruce@momjian.us 1463 : 237340 : qry->sortClause = transformSortClause(pstate,
1464 : : stmt->sortClause,
1465 : : &qry->targetList,
1466 : : EXPR_KIND_ORDER_BY,
1467 : : false /* allow SQL92 rules */ );
1468 : :
8220 tgl@sss.pgh.pa.us 1469 : 474638 : qry->groupClause = transformGroupClause(pstate,
1470 : : stmt->groupClause,
78 tgl@sss.pgh.pa.us 1471 :GNC 237325 : stmt->groupByAll,
1472 : : &qry->groupingSets,
1473 : : &qry->targetList,
1474 : : qry->sortClause,
1475 : : EXPR_KIND_GROUP_BY,
1476 : : false /* allow SQL92 rules */ );
1734 tomas.vondra@postgre 1477 :CBC 237313 : qry->groupDistinct = stmt->groupDistinct;
78 tgl@sss.pgh.pa.us 1478 :GNC 237313 : qry->groupByAll = stmt->groupByAll;
1479 : :
6345 tgl@sss.pgh.pa.us 1480 [ + + ]:CBC 237313 : if (stmt->distinctClause == NIL)
1481 : : {
1482 : 235280 : qry->distinctClause = NIL;
1483 : 235280 : qry->hasDistinctOn = false;
1484 : : }
1485 [ + + ]: 2033 : else if (linitial(stmt->distinctClause) == NULL)
1486 : : {
1487 : : /* We had SELECT DISTINCT */
1488 : 1904 : qry->distinctClause = transformDistinctClause(pstate,
1489 : : &qry->targetList,
1490 : : qry->sortClause,
1491 : : false);
1492 : 1904 : qry->hasDistinctOn = false;
1493 : : }
1494 : : else
1495 : : {
1496 : : /* We had SELECT DISTINCT ON */
1497 : 129 : qry->distinctClause = transformDistinctOnClause(pstate,
1498 : : stmt->distinctClause,
1499 : : &qry->targetList,
1500 : : qry->sortClause);
1501 : 123 : qry->hasDistinctOn = true;
1502 : : }
1503 : :
1504 : : /* transform LIMIT */
8202 1505 : 237307 : qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1506 : : EXPR_KIND_OFFSET, "OFFSET",
1507 : : stmt->limitOption);
1508 : 237307 : qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1509 : : EXPR_KIND_LIMIT, "LIMIT",
1510 : : stmt->limitOption);
2079 alvherre@alvh.no-ip. 1511 : 237301 : qry->limitOption = stmt->limitOption;
1512 : :
1513 : : /* transform window clauses after we have seen all window functions */
6197 tgl@sss.pgh.pa.us 1514 : 237301 : qry->windowClause = transformWindowDefinitions(pstate,
1515 : : pstate->p_windowdefs,
1516 : : &qry->targetList);
1517 : :
1518 : : /* resolve any still-unresolved output columns as being type text */
3247 1519 [ + + ]: 237268 : if (pstate->p_resolve_unknowns)
1520 : 215850 : resolveTargetListUnknowns(pstate, qry->targetList);
1521 : :
8369 1522 : 237268 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 1523 : 237268 : qry->rteperminfos = pstate->p_rteperminfos;
8369 tgl@sss.pgh.pa.us 1524 : 237268 : qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
1525 : :
9647 1526 : 237268 : qry->hasSubLinks = pstate->p_hasSubLinks;
6197 1527 : 237268 : qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
3381 1528 : 237268 : qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
5060 1529 : 237268 : qry->hasAggs = pstate->p_hasAggs;
1530 : :
7170 1531 [ + + + + : 242729 : foreach(l, stmt->lockingClause)
+ + ]
1532 : : {
5893 1533 : 5482 : transformLockingClause(pstate, qry,
1534 : 5482 : (LockingClause *) lfirst(l), false);
1535 : : }
1536 : :
5386 1537 : 237247 : assign_query_collations(pstate, qry);
1538 : :
1539 : : /* this must be done after collations, for reliable comparison of exprs */
2525 rhodiumtoad@postgres 1540 [ + + + + : 237226 : if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
+ + + + ]
1541 : 21711 : parseCheckAggregates(pstate, qry);
1542 : :
9203 tgl@sss.pgh.pa.us 1543 : 237169 : return qry;
1544 : : }
1545 : :
1546 : : /*
1547 : : * transformValuesClause -
1548 : : * transforms a VALUES clause that's being used as a standalone SELECT
1549 : : *
1550 : : * We build a Query containing a VALUES RTE, rather as if one had written
1551 : : * SELECT * FROM (VALUES ...) AS "*VALUES*"
1552 : : */
1553 : : static Query *
7076 mail@joeconway.com 1554 : 4277 : transformValuesClause(ParseState *pstate, SelectStmt *stmt)
1555 : : {
1556 : 4277 : Query *qry = makeNode(Query);
1317 tgl@sss.pgh.pa.us 1557 : 4277 : List *exprsLists = NIL;
3295 1558 : 4277 : List *coltypes = NIL;
1559 : 4277 : List *coltypmods = NIL;
1560 : 4277 : List *colcollations = NIL;
6319 1561 : 4277 : List **colexprs = NULL;
7076 mail@joeconway.com 1562 : 4277 : int sublist_length = -1;
4867 tgl@sss.pgh.pa.us 1563 : 4277 : bool lateral = false;
1564 : : ParseNamespaceItem *nsitem;
1565 : : ListCell *lc;
1566 : : ListCell *lc2;
1567 : : int i;
1568 : :
7076 mail@joeconway.com 1569 : 4277 : qry->commandType = CMD_SELECT;
1570 : :
1571 : : /* Most SELECT stuff doesn't apply in a VALUES clause */
1572 [ - + ]: 4277 : Assert(stmt->distinctClause == NIL);
5020 tgl@sss.pgh.pa.us 1573 [ - + ]: 4277 : Assert(stmt->intoClause == NULL);
7076 mail@joeconway.com 1574 [ - + ]: 4277 : Assert(stmt->targetList == NIL);
1575 [ - + ]: 4277 : Assert(stmt->fromClause == NIL);
1576 [ - + ]: 4277 : Assert(stmt->whereClause == NULL);
1577 [ - + ]: 4277 : Assert(stmt->groupClause == NIL);
1578 [ - + ]: 4277 : Assert(stmt->havingClause == NULL);
6197 tgl@sss.pgh.pa.us 1579 [ - + ]: 4277 : Assert(stmt->windowClause == NIL);
7076 mail@joeconway.com 1580 [ - + ]: 4277 : Assert(stmt->op == SETOP_NONE);
1581 : :
1582 : : /* process the WITH clause independently of all else */
6282 tgl@sss.pgh.pa.us 1583 [ + + ]: 4277 : if (stmt->withClause)
1584 : : {
1585 : 30 : qry->hasRecursive = stmt->withClause->recursive;
1586 : 30 : qry->cteList = transformWithClause(pstate, stmt->withClause);
5408 1587 : 27 : qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1588 : : }
1589 : :
1590 : : /*
1591 : : * For each row of VALUES, transform the raw expressions.
1592 : : *
1593 : : * Note that the intermediate representation we build is column-organized
1594 : : * not row-organized. That simplifies the type and collation processing
1595 : : * below.
1596 : : */
7076 mail@joeconway.com 1597 [ + - + + : 15823 : foreach(lc, stmt->valuesLists)
+ + ]
1598 : : {
7013 bruce@momjian.us 1599 : 11553 : List *sublist = (List *) lfirst(lc);
1600 : :
1601 : : /*
1602 : : * Do basic expression transformation (same as a ROW() expr, but here
1603 : : * we disallow SetToDefault)
1604 : : */
3311 tgl@sss.pgh.pa.us 1605 : 11553 : sublist = transformExpressionList(pstate, sublist,
1606 : : EXPR_KIND_VALUES, false);
1607 : :
1608 : : /*
1609 : : * All the sublists must be the same length, *after* transformation
1610 : : * (which might expand '*' into multiple items). The VALUES RTE can't
1611 : : * handle anything different.
1612 : : */
7076 mail@joeconway.com 1613 [ + + ]: 11549 : if (sublist_length < 0)
1614 : : {
1615 : : /* Remember post-transformation length of first sublist */
1616 : 4270 : sublist_length = list_length(sublist);
1617 : : /* and allocate array for per-column lists */
6319 tgl@sss.pgh.pa.us 1618 : 4270 : colexprs = (List **) palloc0(sublist_length * sizeof(List *));
1619 : : }
7076 mail@joeconway.com 1620 [ - + ]: 7279 : else if (sublist_length != list_length(sublist))
1621 : : {
7076 mail@joeconway.com 1622 [ # # ]:UBC 0 : ereport(ERROR,
1623 : : (errcode(ERRCODE_SYNTAX_ERROR),
1624 : : errmsg("VALUES lists must all be the same length"),
1625 : : parser_errposition(pstate,
1626 : : exprLocation((Node *) sublist))));
1627 : : }
1628 : :
1629 : : /* Build per-column expression lists */
7076 mail@joeconway.com 1630 :CBC 11549 : i = 0;
1631 [ + + + + : 27689 : foreach(lc2, sublist)
+ + ]
1632 : : {
7013 bruce@momjian.us 1633 : 16140 : Node *col = (Node *) lfirst(lc2);
1634 : :
6319 tgl@sss.pgh.pa.us 1635 : 16140 : colexprs[i] = lappend(colexprs[i], col);
7076 mail@joeconway.com 1636 : 16140 : i++;
1637 : : }
1638 : :
1639 : : /* Release sub-list's cells to save memory */
5356 tgl@sss.pgh.pa.us 1640 : 11549 : list_free(sublist);
1641 : :
1642 : : /* Prepare an exprsLists element for this row */
1317 1643 : 11549 : exprsLists = lappend(exprsLists, NIL);
1644 : : }
1645 : :
1646 : : /*
1647 : : * Now resolve the common types of the columns, and coerce everything to
1648 : : * those types. Then identify the common typmod and common collation, if
1649 : : * any, of each column.
1650 : : *
1651 : : * We must do collation processing now because (1) assign_query_collations
1652 : : * doesn't process rangetable entries, and (2) we need to label the VALUES
1653 : : * RTE with column collations for use in the outer query. We don't
1654 : : * consider conflict of implicit collations to be an error here; instead
1655 : : * the column will just show InvalidOid as its collation, and you'll get a
1656 : : * failure later if that results in failure to resolve a collation.
1657 : : *
1658 : : * Note we modify the per-column expression lists in-place.
1659 : : */
7076 mail@joeconway.com 1660 [ + + ]: 9895 : for (i = 0; i < sublist_length; i++)
1661 : : {
1662 : : Oid coltype;
1663 : : int32 coltypmod;
1664 : : Oid colcoll;
1665 : :
5356 tgl@sss.pgh.pa.us 1666 : 5625 : coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
1667 : :
1668 [ + - + + : 21765 : foreach(lc, colexprs[i])
+ + ]
1669 : : {
1670 : 16140 : Node *col = (Node *) lfirst(lc);
1671 : :
1672 : 16140 : col = coerce_to_common_type(pstate, col, coltype, "VALUES");
383 peter@eisentraut.org 1673 : 16140 : lfirst(lc) = col;
1674 : : }
1675 : :
1876 1676 : 5625 : coltypmod = select_common_typmod(pstate, colexprs[i], coltype);
5356 tgl@sss.pgh.pa.us 1677 : 5625 : colcoll = select_common_collation(pstate, colexprs[i], true);
1678 : :
3295 1679 : 5625 : coltypes = lappend_oid(coltypes, coltype);
1680 : 5625 : coltypmods = lappend_int(coltypmods, coltypmod);
1681 : 5625 : colcollations = lappend_oid(colcollations, colcoll);
1682 : : }
1683 : :
1684 : : /*
1685 : : * Finally, rearrange the coerced expressions into row-organized lists.
1686 : : */
1317 1687 [ + + ]: 9895 : for (i = 0; i < sublist_length; i++)
1688 : : {
5356 1689 [ + - + + : 21765 : forboth(lc, colexprs[i], lc2, exprsLists)
+ - + + +
+ + - +
+ ]
1690 : : {
1691 : 16140 : Node *col = (Node *) lfirst(lc);
1692 : 16140 : List *sublist = lfirst(lc2);
1693 : :
1886 peter@eisentraut.org 1694 : 16140 : sublist = lappend(sublist, col);
1317 tgl@sss.pgh.pa.us 1695 : 16140 : lfirst(lc2) = sublist;
1696 : : }
5356 1697 : 5625 : list_free(colexprs[i]);
1698 : : }
1699 : :
1700 : : /*
1701 : : * Ordinarily there can't be any current-level Vars in the expression
1702 : : * lists, because the namespace was empty ... but if we're inside CREATE
1703 : : * RULE, then NEW/OLD references might appear. In that case we have to
1704 : : * mark the VALUES RTE as LATERAL.
1705 : : */
4867 1706 [ + + + - ]: 4274 : if (pstate->p_rtable != NIL &&
1707 : 4 : contain_vars_of_level((Node *) exprsLists, 0))
1708 : 4 : lateral = true;
1709 : :
1710 : : /*
1711 : : * Generate the VALUES RTE
1712 : : */
2175 1713 : 4270 : nsitem = addRangeTableEntryForValues(pstate, exprsLists,
1714 : : coltypes, coltypmods, colcollations,
1715 : : NULL, lateral, true);
1716 : 4270 : addNSItemToQuery(pstate, nsitem, true, true, true);
1717 : :
1718 : : /*
1719 : : * Generate a targetlist as though expanding "*"
1720 : : */
7076 mail@joeconway.com 1721 [ - + ]: 4270 : Assert(pstate->p_next_resno == 1);
1359 alvherre@alvh.no-ip. 1722 : 4270 : qry->targetList = expandNSItemAttrs(pstate, nsitem, 0, true, -1);
1723 : :
1724 : : /*
1725 : : * The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
1726 : : * VALUES, so cope.
1727 : : */
7076 mail@joeconway.com 1728 : 4270 : qry->sortClause = transformSortClause(pstate,
1729 : : stmt->sortClause,
1730 : : &qry->targetList,
1731 : : EXPR_KIND_ORDER_BY,
1732 : : false /* allow SQL92 rules */ );
1733 : :
1734 : 4270 : qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1735 : : EXPR_KIND_OFFSET, "OFFSET",
1736 : : stmt->limitOption);
1737 : 4270 : qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1738 : : EXPR_KIND_LIMIT, "LIMIT",
1739 : : stmt->limitOption);
2079 alvherre@alvh.no-ip. 1740 : 4270 : qry->limitOption = stmt->limitOption;
1741 : :
7076 mail@joeconway.com 1742 [ - + ]: 4270 : if (stmt->lockingClause)
7076 mail@joeconway.com 1743 [ # # ]:UBC 0 : ereport(ERROR,
1744 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1745 : : /*------
1746 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
1747 : : errmsg("%s cannot be applied to VALUES",
1748 : : LCS_asString(((LockingClause *)
1749 : : linitial(stmt->lockingClause))->strength))));
1750 : :
7076 mail@joeconway.com 1751 :CBC 4270 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 1752 : 4270 : qry->rteperminfos = pstate->p_rteperminfos;
7076 mail@joeconway.com 1753 : 4270 : qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1754 : :
1755 : 4270 : qry->hasSubLinks = pstate->p_hasSubLinks;
1756 : :
5386 tgl@sss.pgh.pa.us 1757 : 4270 : assign_query_collations(pstate, qry);
1758 : :
7076 mail@joeconway.com 1759 : 4270 : return qry;
1760 : : }
1761 : :
1762 : : /*
1763 : : * transformSetOperationStmt -
1764 : : * transforms a set-operations tree
1765 : : *
1766 : : * A set-operation tree is just a SELECT, but with UNION/INTERSECT/EXCEPT
1767 : : * structure to it. We must transform each leaf SELECT and build up a top-
1768 : : * level Query that contains the leaf SELECTs as subqueries in its rangetable.
1769 : : * The tree of set operations is converted into the setOperations field of
1770 : : * the top-level Query.
1771 : : */
1772 : : static Query *
8818 bruce@momjian.us 1773 : 6600 : transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
1774 : : {
9203 tgl@sss.pgh.pa.us 1775 : 6600 : Query *qry = makeNode(Query);
1776 : : SelectStmt *leftmostSelect;
1777 : : int leftmostRTI;
1778 : : Query *leftmostQuery;
1779 : : SetOperationStmt *sostmt;
1780 : : List *sortClause;
1781 : : Node *limitOffset;
1782 : : Node *limitCount;
1783 : : List *lockingClause;
1784 : : WithClause *withClause;
1785 : : Node *node;
1786 : : ListCell *left_tlist,
1787 : : *lct,
1788 : : *lcm,
1789 : : *lcc,
1790 : : *l;
1791 : : List *targetvars,
1792 : : *targetnames,
1793 : : *sv_namespace;
1794 : : int sv_rtable_length;
1795 : : ParseNamespaceItem *jnsitem;
1796 : : ParseNamespaceColumn *sortnscolumns;
1797 : : int sortcolindex;
1798 : : int tllen;
1799 : :
1800 : 6600 : qry->commandType = CMD_SELECT;
1801 : :
1802 : : /*
1803 : : * Find leftmost leaf SelectStmt. We currently only need to do this in
1804 : : * order to deliver a suitable error message if there's an INTO clause
1805 : : * there, implying the set-op tree is in a context that doesn't allow
1806 : : * INTO. (transformSetOperationTree would throw error anyway, but it
1807 : : * seems worth the trouble to throw a different error for non-leftmost
1808 : : * INTO, so we produce that error in transformSetOperationTree.)
1809 : : */
9172 1810 : 6600 : leftmostSelect = stmt->larg;
1811 [ + - + + ]: 9956 : while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
1812 : 3356 : leftmostSelect = leftmostSelect->larg;
1813 [ + - + - : 6600 : Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
- + ]
1814 : : leftmostSelect->larg == NULL);
5020 1815 [ - + ]: 6600 : if (leftmostSelect->intoClause)
5020 tgl@sss.pgh.pa.us 1816 [ # # ]:UBC 0 : ereport(ERROR,
1817 : : (errcode(ERRCODE_SYNTAX_ERROR),
1818 : : errmsg("SELECT ... INTO is not allowed here"),
1819 : : parser_errposition(pstate,
1820 : : exprLocation((Node *) leftmostSelect->intoClause))));
1821 : :
1822 : : /*
1823 : : * We need to extract ORDER BY and other top-level clauses here and not
1824 : : * let transformSetOperationTree() see them --- else it'll just recurse
1825 : : * right back here!
1826 : : */
9172 tgl@sss.pgh.pa.us 1827 :CBC 6600 : sortClause = stmt->sortClause;
1828 : 6600 : limitOffset = stmt->limitOffset;
1829 : 6600 : limitCount = stmt->limitCount;
7442 1830 : 6600 : lockingClause = stmt->lockingClause;
4886 1831 : 6600 : withClause = stmt->withClause;
1832 : :
9172 1833 : 6600 : stmt->sortClause = NIL;
1834 : 6600 : stmt->limitOffset = NULL;
1835 : 6600 : stmt->limitCount = NULL;
7170 1836 : 6600 : stmt->lockingClause = NIL;
4886 1837 : 6600 : stmt->withClause = NULL;
1838 : :
1839 : : /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
7442 1840 [ + + ]: 6600 : if (lockingClause)
8186 1841 [ + - ]: 3 : ereport(ERROR,
1842 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1843 : : /*------
1844 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
1845 : : errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1846 : : LCS_asString(((LockingClause *)
1847 : : linitial(lockingClause))->strength))));
1848 : :
1849 : : /* Process the WITH clause independently of all else */
4886 1850 [ + + ]: 6597 : if (withClause)
1851 : : {
1852 : 136 : qry->hasRecursive = withClause->recursive;
1853 : 136 : qry->cteList = transformWithClause(pstate, withClause);
1854 : 136 : qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1855 : : }
1856 : :
1857 : : /*
1858 : : * Recursively transform the components of the tree.
1859 : : */
3220 peter_e@gmx.net 1860 : 6597 : sostmt = castNode(SetOperationStmt,
1861 : : transformSetOperationTree(pstate, stmt, true, NULL));
1862 [ - + ]: 6561 : Assert(sostmt);
9172 tgl@sss.pgh.pa.us 1863 : 6561 : qry->setOperations = (Node *) sostmt;
1864 : :
1865 : : /*
1866 : : * Re-find leftmost SELECT (now it's a sub-query in rangetable)
1867 : : */
1868 : 6561 : node = sostmt->larg;
9203 1869 [ + - + + ]: 9908 : while (node && IsA(node, SetOperationStmt))
1870 : 3347 : node = ((SetOperationStmt *) node)->larg;
1871 [ + - - + ]: 6561 : Assert(node && IsA(node, RangeTblRef));
9172 1872 : 6561 : leftmostRTI = ((RangeTblRef *) node)->rtindex;
1873 : 6561 : leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
9203 1874 [ - + ]: 6561 : Assert(leftmostQuery != NULL);
1875 : :
1876 : : /*
1877 : : * Generate dummy targetlist for outer query using column names of
1878 : : * leftmost select and common datatypes/collations of topmost set
1879 : : * operation. Also make lists of the dummy vars and their names for use
1880 : : * in parsing ORDER BY.
1881 : : *
1882 : : * Note: we use leftmostRTI as the varno of the dummy variables. It
1883 : : * shouldn't matter too much which RT index they have, as long as they
1884 : : * have one that corresponds to a real RT entry; else funny things may
1885 : : * happen when the tree is mashed by rule rewriting.
1886 : : */
1887 : 6561 : qry->targetList = NIL;
8633 1888 : 6561 : targetvars = NIL;
9070 1889 : 6561 : targetnames = NIL;
1890 : : sortnscolumns = (ParseNamespaceColumn *)
2175 1891 : 6561 : palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
1892 : 6561 : sortcolindex = 0;
1893 : :
2483 1894 [ + + + + : 22800 : forfour(lct, sostmt->colTypes,
+ + + + +
+ + + + +
+ + + + +
- + - + -
+ + ]
1895 : : lcm, sostmt->colTypmods,
1896 : : lcc, sostmt->colCollations,
1897 : : left_tlist, leftmostQuery->targetList)
1898 : : {
7068 1899 : 16239 : Oid colType = lfirst_oid(lct);
1900 : 16239 : int32 colTypmod = lfirst_int(lcm);
5425 peter_e@gmx.net 1901 : 16239 : Oid colCollation = lfirst_oid(lcc);
7559 tgl@sss.pgh.pa.us 1902 : 16239 : TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
1903 : : char *colName;
1904 : : TargetEntry *tle;
1905 : : Var *var;
1906 : :
1907 [ - + ]: 16239 : Assert(!lefttle->resjunk);
1908 : 16239 : colName = pstrdup(lefttle->resname);
6282 1909 : 16239 : var = makeVar(leftmostRTI,
1910 : 16239 : lefttle->resno,
1911 : : colType,
1912 : : colTypmod,
1913 : : colCollation,
1914 : : 0);
1915 : 16239 : var->location = exprLocation((Node *) lefttle->expr);
1916 : 16239 : tle = makeTargetEntry((Expr *) var,
7559 1917 : 16239 : (AttrNumber) pstate->p_next_resno++,
1918 : : colName,
1919 : : false);
1920 : 16239 : qry->targetList = lappend(qry->targetList, tle);
6282 1921 : 16239 : targetvars = lappend(targetvars, var);
9070 1922 : 16239 : targetnames = lappend(targetnames, makeString(colName));
2175 1923 : 16239 : sortnscolumns[sortcolindex].p_varno = leftmostRTI;
1924 : 16239 : sortnscolumns[sortcolindex].p_varattno = lefttle->resno;
1925 : 16239 : sortnscolumns[sortcolindex].p_vartype = colType;
1926 : 16239 : sortnscolumns[sortcolindex].p_vartypmod = colTypmod;
1927 : 16239 : sortnscolumns[sortcolindex].p_varcollid = colCollation;
1928 : 16239 : sortnscolumns[sortcolindex].p_varnosyn = leftmostRTI;
1929 : 16239 : sortnscolumns[sortcolindex].p_varattnosyn = lefttle->resno;
1930 : 16239 : sortcolindex++;
1931 : : }
1932 : :
1933 : : /*
1934 : : * As a first step towards supporting sort clauses that are expressions
1935 : : * using the output columns, generate a namespace entry that makes the
1936 : : * output columns visible. A Join RTE node is handy for this, since we
1937 : : * can easily control the Vars generated upon matches.
1938 : : *
1939 : : * Note: we don't yet do anything useful with such cases, but at least
1940 : : * "ORDER BY upper(foo)" will draw the right error message rather than
1941 : : * "foo not found".
1942 : : */
6172 1943 : 6561 : sv_rtable_length = list_length(pstate->p_rtable);
1944 : :
2175 1945 : 6561 : jnsitem = addRangeTableEntryForJoin(pstate,
1946 : : targetnames,
1947 : : sortnscolumns,
1948 : : JOIN_INNER,
1949 : : 0,
1950 : : targetvars,
1951 : : NIL,
1952 : : NIL,
1953 : : NULL,
1954 : : NULL,
1955 : : false);
1956 : :
4878 1957 : 6561 : sv_namespace = pstate->p_namespace;
1958 : 6561 : pstate->p_namespace = NIL;
1959 : :
1960 : : /* add jnsitem to column namespace only */
2175 1961 : 6561 : addNSItemToQuery(pstate, jnsitem, false, false, true);
1962 : :
1963 : : /*
1964 : : * For now, we don't support resjunk sort clauses on the output of a
1965 : : * setOperation tree --- you can only use the SQL92-spec options of
1966 : : * selecting an output column by name or number. Enforce by checking that
1967 : : * transformSortClause doesn't add any items to tlist. Note, if changing
1968 : : * this, add_setop_child_rel_equivalences() will need to be updated.
1969 : : */
7870 neilc@samurai.com 1970 : 6561 : tllen = list_length(qry->targetList);
1971 : :
9203 tgl@sss.pgh.pa.us 1972 : 6561 : qry->sortClause = transformSortClause(pstate,
1973 : : sortClause,
1974 : : &qry->targetList,
1975 : : EXPR_KIND_ORDER_BY,
1976 : : false /* allow SQL92 rules */ );
1977 : :
1978 : : /* restore namespace, remove join RTE from rtable */
4878 1979 : 6558 : pstate->p_namespace = sv_namespace;
6172 1980 : 6558 : pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
1981 : :
7870 neilc@samurai.com 1982 [ - + ]: 6558 : if (tllen != list_length(qry->targetList))
8186 tgl@sss.pgh.pa.us 1983 [ # # ]:UBC 0 : ereport(ERROR,
1984 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1985 : : errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
1986 : : errdetail("Only result column names can be used, not expressions or functions."),
1987 : : errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
1988 : : parser_errposition(pstate,
1989 : : exprLocation(list_nth(qry->targetList, tllen)))));
1990 : :
8202 tgl@sss.pgh.pa.us 1991 :CBC 6558 : qry->limitOffset = transformLimitClause(pstate, limitOffset,
1992 : : EXPR_KIND_OFFSET, "OFFSET",
1993 : : stmt->limitOption);
1994 : 6558 : qry->limitCount = transformLimitClause(pstate, limitCount,
1995 : : EXPR_KIND_LIMIT, "LIMIT",
1996 : : stmt->limitOption);
2079 alvherre@alvh.no-ip. 1997 : 6558 : qry->limitOption = stmt->limitOption;
1998 : :
8369 tgl@sss.pgh.pa.us 1999 : 6558 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 2000 : 6558 : qry->rteperminfos = pstate->p_rteperminfos;
8369 tgl@sss.pgh.pa.us 2001 : 6558 : qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2002 : :
9203 2003 : 6558 : qry->hasSubLinks = pstate->p_hasSubLinks;
6197 2004 : 6558 : qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
3381 2005 : 6558 : qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
5060 2006 : 6558 : qry->hasAggs = pstate->p_hasAggs;
2007 : :
7170 2008 [ - + - - : 6558 : foreach(l, lockingClause)
- + ]
2009 : : {
5893 tgl@sss.pgh.pa.us 2010 :UBC 0 : transformLockingClause(pstate, qry,
2011 : 0 : (LockingClause *) lfirst(l), false);
2012 : : }
2013 : :
5386 tgl@sss.pgh.pa.us 2014 :CBC 6558 : assign_query_collations(pstate, qry);
2015 : :
2016 : : /* this must be done after collations, for reliable comparison of exprs */
2525 rhodiumtoad@postgres 2017 [ + - + - : 6558 : if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
+ - - + ]
2525 rhodiumtoad@postgres 2018 :UBC 0 : parseCheckAggregates(pstate, qry);
2019 : :
9203 tgl@sss.pgh.pa.us 2020 :CBC 6558 : return qry;
2021 : : }
2022 : :
2023 : : /*
2024 : : * Make a SortGroupClause node for a SetOperationStmt's groupClauses
2025 : : *
2026 : : * If require_hash is true, the caller is indicating that they need hash
2027 : : * support or they will fail. So look extra hard for hash support.
2028 : : */
2029 : : SortGroupClause *
1560 peter@eisentraut.org 2030 : 13595 : makeSortGroupClauseForSetOp(Oid rescoltype, bool require_hash)
2031 : : {
1779 2032 : 13595 : SortGroupClause *grpcl = makeNode(SortGroupClause);
2033 : : Oid sortop;
2034 : : Oid eqop;
2035 : : bool hashable;
2036 : :
2037 : : /* determine the eqop and optional sortop */
2038 : 13595 : get_sort_group_operators(rescoltype,
2039 : : false, true, false,
2040 : : &sortop, &eqop, NULL,
2041 : : &hashable);
2042 : :
2043 : : /*
2044 : : * The type cache doesn't believe that record is hashable (see
2045 : : * cache_record_field_properties()), but if the caller really needs hash
2046 : : * support, we can assume it does. Worst case, if any components of the
2047 : : * record don't support hashing, we will fail at execution.
2048 : : */
1560 2049 [ + + + + : 13595 : if (require_hash && (rescoltype == RECORDOID || rescoltype == RECORDARRAYOID))
+ + ]
2050 : 12 : hashable = true;
2051 : :
2052 : : /* we don't have a tlist yet, so can't assign sortgrouprefs */
1779 2053 : 13595 : grpcl->tleSortGroupRef = 0;
2054 : 13595 : grpcl->eqop = eqop;
2055 : 13595 : grpcl->sortop = sortop;
428 2056 : 13595 : grpcl->reverse_sort = false; /* Sort-op is "less than", or InvalidOid */
1779 2057 : 13595 : grpcl->nulls_first = false; /* OK with or without sortop */
2058 : 13595 : grpcl->hashable = hashable;
2059 : :
2060 : 13595 : return grpcl;
2061 : : }
2062 : :
2063 : : /*
2064 : : * transformSetOperationTree
2065 : : * Recursively transform leaves and internal nodes of a set-op tree
2066 : : *
2067 : : * In addition to returning the transformed node, if targetlist isn't NULL
2068 : : * then we return a list of its non-resjunk TargetEntry nodes. For a leaf
2069 : : * set-op node these are the actual targetlist entries; otherwise they are
2070 : : * dummy entries created to carry the type, typmod, collation, and location
2071 : : * (for error messages) of each output column of the set-op node. This info
2072 : : * is needed only during the internal recursion of this function, so outside
2073 : : * callers pass NULL for targetlist. Note: the reason for passing the
2074 : : * actual targetlist entries of a leaf node is so that upper levels can
2075 : : * replace UNKNOWN Consts with properly-coerced constants.
2076 : : */
2077 : : static Node *
6319 tgl@sss.pgh.pa.us 2078 : 26554 : transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
2079 : : bool isTopLevel, List **targetlist)
2080 : : {
2081 : : bool isLeaf;
2082 : :
9172 2083 [ + - - + ]: 26554 : Assert(stmt && IsA(stmt, SelectStmt));
2084 : :
2085 : : /* Guard against stack overflow due to overly complex set-expressions */
4783 2086 : 26554 : check_stack_depth();
2087 : :
2088 : : /*
2089 : : * Validity-check both leaf and internal SELECTs for disallowed ops.
2090 : : */
6808 2091 [ - + ]: 26554 : if (stmt->intoClause)
8186 tgl@sss.pgh.pa.us 2092 [ # # ]:UBC 0 : ereport(ERROR,
2093 : : (errcode(ERRCODE_SYNTAX_ERROR),
2094 : : errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
2095 : : parser_errposition(pstate,
2096 : : exprLocation((Node *) stmt->intoClause))));
2097 : :
2098 : : /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
7442 tgl@sss.pgh.pa.us 2099 [ - + ]:CBC 26554 : if (stmt->lockingClause)
8186 tgl@sss.pgh.pa.us 2100 [ # # ]:UBC 0 : ereport(ERROR,
2101 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2102 : : /*------
2103 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
2104 : : errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
2105 : : LCS_asString(((LockingClause *)
2106 : : linitial(stmt->lockingClause))->strength))));
2107 : :
2108 : : /*
2109 : : * If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
2110 : : * or WITH clauses attached, we need to treat it like a leaf node to
2111 : : * generate an independent sub-Query tree. Otherwise, it can be
2112 : : * represented by a SetOperationStmt node underneath the parent Query.
2113 : : */
9172 tgl@sss.pgh.pa.us 2114 [ + + ]:CBC 26554 : if (stmt->op == SETOP_NONE)
2115 : : {
2116 [ + - - + ]: 16544 : Assert(stmt->larg == NULL && stmt->rarg == NULL);
2117 : 16544 : isLeaf = true;
2118 : : }
2119 : : else
2120 : : {
2121 [ + - - + ]: 10010 : Assert(stmt->larg != NULL && stmt->rarg != NULL);
2122 [ + + + - : 10010 : if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
+ - ]
4886 2123 [ + - + + ]: 9998 : stmt->lockingClause || stmt->withClause)
9172 2124 : 30 : isLeaf = true;
2125 : : else
2126 : 9980 : isLeaf = false;
2127 : : }
2128 : :
2129 [ + + ]: 26554 : if (isLeaf)
2130 : : {
2131 : : /* Process leaf SELECT */
2132 : : Query *selectQuery;
2133 : : ParseNamespaceItem *nsitem;
2134 : : RangeTblRef *rtr;
2135 : : ListCell *tl;
2136 : :
2137 : : /*
2138 : : * Transform SelectStmt into a Query.
2139 : : *
2140 : : * This works the same as SELECT transformation normally would, except
2141 : : * that we prevent resolving unknown-type outputs as TEXT. This does
2142 : : * not change the subquery's semantics since if the column type
2143 : : * matters semantically, it would have been resolved to something else
2144 : : * anyway. Doing this lets us resolve such outputs using
2145 : : * select_common_type(), below.
2146 : : *
2147 : : * Note: previously transformed sub-queries don't affect the parsing
2148 : : * of this sub-query, because they are not in the toplevel pstate's
2149 : : * namespace list.
2150 : : */
3247 2151 : 16574 : selectQuery = parse_sub_analyze((Node *) stmt, pstate,
2152 : : NULL, false, false);
2153 : :
2154 : : /*
2155 : : * Check for bogus references to Vars on the current query level (but
2156 : : * upper-level references are okay). Normally this can't happen
2157 : : * because the namespace will be empty, but it could happen if we are
2158 : : * inside a rule.
2159 : : */
4878 2160 [ - + ]: 16559 : if (pstate->p_namespace)
2161 : : {
8342 tgl@sss.pgh.pa.us 2162 [ # # ]:UBC 0 : if (contain_vars_of_level((Node *) selectQuery, 1))
8186 2163 [ # # ]: 0 : ereport(ERROR,
2164 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2165 : : errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
2166 : : parser_errposition(pstate,
2167 : : locate_var_of_level((Node *) selectQuery, 1))));
2168 : : }
2169 : :
2170 : : /*
2171 : : * Extract a list of the non-junk TLEs for upper-level processing.
2172 : : */
5390 tgl@sss.pgh.pa.us 2173 [ + - ]:CBC 16559 : if (targetlist)
2174 : : {
2175 : 16559 : *targetlist = NIL;
2176 [ + + + + : 63979 : foreach(tl, selectQuery->targetList)
+ + ]
2177 : : {
2178 : 47420 : TargetEntry *tle = (TargetEntry *) lfirst(tl);
2179 : :
2180 [ + + ]: 47420 : if (!tle->resjunk)
2181 : 47414 : *targetlist = lappend(*targetlist, tle);
2182 : : }
2183 : : }
2184 : :
2185 : : /*
2186 : : * Make the leaf query be a subquery in the top-level rangetable.
2187 : : */
2175 2188 : 16559 : nsitem = addRangeTableEntryForSubquery(pstate,
2189 : : selectQuery,
2190 : : NULL,
2191 : : false,
2192 : : false);
2193 : :
2194 : : /*
2195 : : * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
2196 : : */
9203 2197 : 16559 : rtr = makeNode(RangeTblRef);
2175 2198 : 16559 : rtr->rtindex = nsitem->p_rtindex;
9203 2199 : 16559 : return (Node *) rtr;
2200 : : }
2201 : : else
2202 : : {
2203 : : /* Process an internal node (set operation node) */
9172 2204 : 9980 : SetOperationStmt *op = makeNode(SetOperationStmt);
2205 : : List *ltargetlist;
2206 : : List *rtargetlist;
2207 : : ListCell *ltl;
2208 : : ListCell *rtl;
2209 : : const char *context;
1314 2210 [ + + ]: 10592 : bool recursive = (pstate->p_parent_cte &&
2211 [ + + ]: 612 : pstate->p_parent_cte->cterecursive);
2212 : :
9172 2213 [ + + ]: 10344 : context = (stmt->op == SETOP_UNION ? "UNION" :
2214 [ + + ]: 364 : (stmt->op == SETOP_INTERSECT ? "INTERSECT" :
2215 : : "EXCEPT"));
2216 : :
2217 : 9980 : op->op = stmt->op;
2218 : 9980 : op->all = stmt->all;
2219 : :
2220 : : /*
2221 : : * Recursively transform the left child node.
2222 : : */
6319 2223 : 9980 : op->larg = transformSetOperationTree(pstate, stmt->larg,
2224 : : false,
2225 : : <argetlist);
2226 : :
2227 : : /*
2228 : : * If we are processing a recursive union query, now is the time to
2229 : : * examine the non-recursive term's output columns and mark the
2230 : : * containing CTE as having those result columns. We should do this
2231 : : * only at the topmost setop of the CTE, of course.
2232 : : */
1560 peter@eisentraut.org 2233 [ + + + + ]: 9977 : if (isTopLevel && recursive)
5390 tgl@sss.pgh.pa.us 2234 : 540 : determineRecursiveColTypes(pstate, op->larg, ltargetlist);
2235 : :
2236 : : /*
2237 : : * Recursively transform the right child node.
2238 : : */
6319 2239 : 9977 : op->rarg = transformSetOperationTree(pstate, stmt->rarg,
2240 : : false,
2241 : : &rtargetlist);
2242 : :
2243 : : /*
2244 : : * Verify that the two children have the same number of non-junk
2245 : : * columns, and determine the types of the merged output columns.
2246 : : */
5390 2247 [ - + ]: 9965 : if (list_length(ltargetlist) != list_length(rtargetlist))
8186 tgl@sss.pgh.pa.us 2248 [ # # ]:UBC 0 : ereport(ERROR,
2249 : : (errcode(ERRCODE_SYNTAX_ERROR),
2250 : : errmsg("each %s query must have the same number of columns",
2251 : : context),
2252 : : parser_errposition(pstate,
2253 : : exprLocation((Node *) rtargetlist))));
2254 : :
5390 tgl@sss.pgh.pa.us 2255 [ + + ]:CBC 9965 : if (targetlist)
2256 : 3383 : *targetlist = NIL;
9203 2257 : 9965 : op->colTypes = NIL;
7068 2258 : 9965 : op->colTypmods = NIL;
5425 peter_e@gmx.net 2259 : 9965 : op->colCollations = NIL;
6340 tgl@sss.pgh.pa.us 2260 : 9965 : op->groupClauses = NIL;
5390 2261 [ + + + + : 41068 : forboth(ltl, ltargetlist, rtl, rtargetlist)
+ + + + +
+ + - +
+ ]
2262 : : {
2263 : 31124 : TargetEntry *ltle = (TargetEntry *) lfirst(ltl);
2264 : 31124 : TargetEntry *rtle = (TargetEntry *) lfirst(rtl);
2265 : 31124 : Node *lcolnode = (Node *) ltle->expr;
2266 : 31124 : Node *rcolnode = (Node *) rtle->expr;
5844 2267 : 31124 : Oid lcoltype = exprType(lcolnode);
2268 : 31124 : Oid rcoltype = exprType(rcolnode);
2269 : : Node *bestexpr;
2270 : : int bestlocation;
2271 : : Oid rescoltype;
2272 : : int32 rescoltypmod;
2273 : : Oid rescolcoll;
2274 : :
2275 : : /* select common type, same as CASE et al */
6319 2276 : 31124 : rescoltype = select_common_type(pstate,
5844 2277 : 31124 : list_make2(lcolnode, rcolnode),
2278 : : context,
2279 : : &bestexpr);
5390 2280 : 31124 : bestlocation = exprLocation(bestexpr);
2281 : :
2282 : : /*
2283 : : * Verify the coercions are actually possible. If not, we'd fail
2284 : : * later anyway, but we want to fail now while we have sufficient
2285 : : * context to produce an error cursor position.
2286 : : *
2287 : : * For all non-UNKNOWN-type cases, we verify coercibility but we
2288 : : * don't modify the child's expression, for fear of changing the
2289 : : * child query's semantics.
2290 : : *
2291 : : * If a child expression is an UNKNOWN-type Const or Param, we
2292 : : * want to replace it with the coerced expression. This can only
2293 : : * happen when the child is a leaf set-op node. It's safe to
2294 : : * replace the expression because if the child query's semantics
2295 : : * depended on the type of this output column, it'd have already
2296 : : * coerced the UNKNOWN to something else. We want to do this
2297 : : * because (a) we want to verify that a Const is valid for the
2298 : : * target type, or resolve the actual type of an UNKNOWN Param,
2299 : : * and (b) we want to avoid unnecessary discrepancies between the
2300 : : * output type of the child query and the resolved target type.
2301 : : * Such a discrepancy would disable optimization in the planner.
2302 : : *
2303 : : * If it's some other UNKNOWN-type node, eg a Var, we do nothing
2304 : : * (knowing that coerce_to_common_type would fail). The planner
2305 : : * is sometimes able to fold an UNKNOWN Var to a constant before
2306 : : * it has to coerce the type, so failing now would just break
2307 : : * cases that might work.
2308 : : */
2309 [ + + ]: 31124 : if (lcoltype != UNKNOWNOID)
5386 2310 : 27932 : lcolnode = coerce_to_common_type(pstate, lcolnode,
2311 : : rescoltype, context);
2312 [ - + ]: 3192 : else if (IsA(lcolnode, Const) ||
5386 tgl@sss.pgh.pa.us 2313 [ # # ]:UBC 0 : IsA(lcolnode, Param))
2314 : : {
5386 tgl@sss.pgh.pa.us 2315 :CBC 3192 : lcolnode = coerce_to_common_type(pstate, lcolnode,
2316 : : rescoltype, context);
2317 : 3192 : ltle->expr = (Expr *) lcolnode;
2318 : : }
2319 : :
5390 2320 [ + + ]: 31124 : if (rcoltype != UNKNOWNOID)
5386 2321 : 27507 : rcolnode = coerce_to_common_type(pstate, rcolnode,
2322 : : rescoltype, context);
2323 [ - + ]: 3617 : else if (IsA(rcolnode, Const) ||
5386 tgl@sss.pgh.pa.us 2324 [ # # ]:UBC 0 : IsA(rcolnode, Param))
2325 : : {
5386 tgl@sss.pgh.pa.us 2326 :CBC 3617 : rcolnode = coerce_to_common_type(pstate, rcolnode,
2327 : : rescoltype, context);
2328 : 3614 : rtle->expr = (Expr *) rcolnode;
2329 : : }
2330 : :
1876 peter@eisentraut.org 2331 : 31121 : rescoltypmod = select_common_typmod(pstate,
2332 : 31121 : list_make2(lcolnode, rcolnode),
2333 : : rescoltype);
2334 : :
2335 : : /*
2336 : : * Select common collation. A common collation is required for
2337 : : * all set operators except UNION ALL; see SQL:2008 7.13 <query
2338 : : * expression> Syntax Rule 15c. (If we fail to identify a common
2339 : : * collation for a UNION ALL column, the colCollations element
2340 : : * will be set to InvalidOid, which may result in a runtime error
2341 : : * if something at a higher query level wants to use the column's
2342 : : * collation.)
2343 : : */
5386 tgl@sss.pgh.pa.us 2344 : 31121 : rescolcoll = select_common_collation(pstate,
3100 2345 : 31121 : list_make2(lcolnode, rcolnode),
2346 [ + + + + ]: 31121 : (op->op == SETOP_UNION && op->all));
2347 : :
2348 : : /* emit results */
7870 neilc@samurai.com 2349 : 31103 : op->colTypes = lappend_oid(op->colTypes, rescoltype);
7068 tgl@sss.pgh.pa.us 2350 : 31103 : op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
5425 peter_e@gmx.net 2351 : 31103 : op->colCollations = lappend_oid(op->colCollations, rescolcoll);
2352 : :
2353 : : /*
2354 : : * For all cases except UNION ALL, identify the grouping operators
2355 : : * (and, if available, sorting operators) that will be used to
2356 : : * eliminate duplicates.
2357 : : */
6340 tgl@sss.pgh.pa.us 2358 [ + + + + ]: 31103 : if (op->op != SETOP_UNION || !op->all)
2359 : : {
2360 : : ParseCallbackState pcbstate;
2361 : :
6315 2362 : 13583 : setup_parser_errposition_callback(&pcbstate, pstate,
2363 : : bestlocation);
2364 : :
2365 : : /*
2366 : : * If it's a recursive union, we need to require hashing
2367 : : * support.
2368 : : */
1779 peter@eisentraut.org 2369 : 13583 : op->groupClauses = lappend(op->groupClauses,
1560 2370 : 13583 : makeSortGroupClauseForSetOp(rescoltype, recursive));
2371 : :
6315 tgl@sss.pgh.pa.us 2372 : 13583 : cancel_parser_errposition_callback(&pcbstate);
2373 : : }
2374 : :
2375 : : /*
2376 : : * Construct a dummy tlist entry to return. We use a SetToDefault
2377 : : * node for the expression, since it carries exactly the fields
2378 : : * needed, but any other expression node type would do as well.
2379 : : */
5390 2380 [ + + ]: 31103 : if (targetlist)
2381 : : {
2382 : 14846 : SetToDefault *rescolnode = makeNode(SetToDefault);
2383 : : TargetEntry *restle;
2384 : :
2385 : 14846 : rescolnode->typeId = rescoltype;
2386 : 14846 : rescolnode->typeMod = rescoltypmod;
5386 2387 : 14846 : rescolnode->collation = rescolcoll;
5390 2388 : 14846 : rescolnode->location = bestlocation;
2389 : 14846 : restle = makeTargetEntry((Expr *) rescolnode,
2390 : : 0, /* no need to set resno */
2391 : : NULL,
2392 : : false);
2393 : 14846 : *targetlist = lappend(*targetlist, restle);
2394 : : }
2395 : : }
2396 : :
9203 2397 : 9944 : return (Node *) op;
2398 : : }
2399 : : }
2400 : :
2401 : : /*
2402 : : * Process the outputs of the non-recursive term of a recursive union
2403 : : * to set up the parent CTE's columns
2404 : : */
2405 : : static void
5390 2406 : 540 : determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
2407 : : {
2408 : : Node *node;
2409 : : int leftmostRTI;
2410 : : Query *leftmostQuery;
2411 : : List *targetList;
2412 : : ListCell *left_tlist;
2413 : : ListCell *nrtl;
2414 : : int next_resno;
2415 : :
2416 : : /*
2417 : : * Find leftmost leaf SELECT
2418 : : */
5942 2419 : 540 : node = larg;
2420 [ + - + + ]: 543 : while (node && IsA(node, SetOperationStmt))
2421 : 3 : node = ((SetOperationStmt *) node)->larg;
2422 [ + - - + ]: 540 : Assert(node && IsA(node, RangeTblRef));
2423 : 540 : leftmostRTI = ((RangeTblRef *) node)->rtindex;
2424 : 540 : leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
2425 [ - + ]: 540 : Assert(leftmostQuery != NULL);
2426 : :
2427 : : /*
2428 : : * Generate dummy targetlist using column names of leftmost select and
2429 : : * dummy result expressions of the non-recursive term.
2430 : : */
2431 : 540 : targetList = NIL;
2432 : 540 : next_resno = 1;
2433 : :
2483 2434 [ + - + + : 1673 : forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
+ - + + +
+ + - +
+ ]
2435 : : {
5390 2436 : 1133 : TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
5942 2437 : 1133 : TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
2438 : : char *colName;
2439 : : TargetEntry *tle;
2440 : :
2441 [ - + ]: 1133 : Assert(!lefttle->resjunk);
2442 : 1133 : colName = pstrdup(lefttle->resname);
5390 2443 : 1133 : tle = makeTargetEntry(nrtle->expr,
5942 2444 : 1133 : next_resno++,
2445 : : colName,
2446 : : false);
2447 : 1133 : targetList = lappend(targetList, tle);
2448 : : }
2449 : :
2450 : : /* Now build CTE's output column info using dummy targetlist */
2451 : 540 : analyzeCTETargetList(pstate, pstate->p_parent_cte, targetList);
2452 : 540 : }
2453 : :
2454 : :
2455 : : /*
2456 : : * transformReturnStmt -
2457 : : * transforms a return statement
2458 : : */
2459 : : static Query *
1714 peter@eisentraut.org 2460 : 2485 : transformReturnStmt(ParseState *pstate, ReturnStmt *stmt)
2461 : : {
2462 : 2485 : Query *qry = makeNode(Query);
2463 : :
2464 : 2485 : qry->commandType = CMD_SELECT;
2465 : 2485 : qry->isReturn = true;
2466 : :
2467 : 2485 : qry->targetList = list_make1(makeTargetEntry((Expr *) transformExpr(pstate, stmt->returnval, EXPR_KIND_SELECT_TARGET),
2468 : : 1, NULL, false));
2469 : :
2470 [ + - ]: 2482 : if (pstate->p_resolve_unknowns)
2471 : 2482 : resolveTargetListUnknowns(pstate, qry->targetList);
2472 : 2482 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 2473 : 2482 : qry->rteperminfos = pstate->p_rteperminfos;
1714 peter@eisentraut.org 2474 : 2482 : qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2475 : 2482 : qry->hasSubLinks = pstate->p_hasSubLinks;
2476 : 2482 : qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2477 : 2482 : qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2478 : 2482 : qry->hasAggs = pstate->p_hasAggs;
2479 : :
2480 : 2482 : assign_query_collations(pstate, qry);
2481 : :
2482 : 2482 : return qry;
2483 : : }
2484 : :
2485 : :
2486 : : /*
2487 : : * transformUpdateStmt -
2488 : : * transforms an update statement
2489 : : */
2490 : : static Query *
10203 bruce@momjian.us 2491 : 7338 : transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
2492 : : {
10326 2493 : 7338 : Query *qry = makeNode(Query);
2494 : : ParseNamespaceItem *nsitem;
2495 : : Node *qual;
2496 : :
10327 2497 : 7338 : qry->commandType = CMD_UPDATE;
3798 andres@anarazel.de 2498 : 7338 : pstate->p_is_insert = false;
2499 : :
2500 : : /* process the WITH clause independently of all else */
5541 tgl@sss.pgh.pa.us 2501 [ + + ]: 7338 : if (stmt->withClause)
2502 : : {
2503 : 38 : qry->hasRecursive = stmt->withClause->recursive;
2504 : 38 : qry->cteList = transformWithClause(pstate, stmt->withClause);
5408 2505 : 38 : qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
2506 : : }
2507 : :
8670 2508 : 14675 : qry->resultRelation = setTargetTable(pstate, stmt->relation,
3280 2509 : 7338 : stmt->relation->inh,
2510 : : true,
2511 : : ACL_UPDATE);
2175 2512 : 7337 : nsitem = pstate->p_target_nsitem;
2513 : :
2514 : : /* subqueries in FROM cannot access the result relation */
4361 2515 : 7337 : nsitem->p_lateral_only = true;
4357 2516 : 7337 : nsitem->p_lateral_ok = false;
2517 : :
2518 : : /*
2519 : : * the FROM clause is non-standard SQL syntax. We used to be able to do
2520 : : * this with REPLACE in POSTQUEL so we keep the feature.
2521 : : */
9071 2522 : 7337 : transformFromClause(pstate, stmt->fromClause);
2523 : :
2524 : : /* remaining clauses can reference the result relation normally */
4361 2525 : 7325 : nsitem->p_lateral_only = false;
4357 2526 : 7325 : nsitem->p_lateral_ok = true;
2527 : :
4876 2528 : 7325 : qual = transformWhereClause(pstate, stmt->whereClause,
2529 : : EXPR_KIND_WHERE, "WHERE");
2530 : :
334 dean.a.rasheed@gmail 2531 : 7319 : transformReturningClause(pstate, qry, stmt->returningClause,
2532 : : EXPR_KIND_RETURNING);
2533 : :
2534 : : /*
2535 : : * Now we are done with SELECT-like processing, and can get on with
2536 : : * transforming the target list to match the UPDATE target columns.
2537 : : */
3875 andres@anarazel.de 2538 : 7310 : qry->targetList = transformUpdateTargetList(pstate, stmt->targetList);
2539 : :
10327 bruce@momjian.us 2540 : 7286 : qry->rtable = pstate->p_rtable;
1106 alvherre@alvh.no-ip. 2541 : 7286 : qry->rteperminfos = pstate->p_rteperminfos;
9209 tgl@sss.pgh.pa.us 2542 : 7286 : qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2543 : :
3381 2544 : 7286 : qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
9226 2545 : 7286 : qry->hasSubLinks = pstate->p_hasSubLinks;
2546 : :
3875 andres@anarazel.de 2547 : 7286 : assign_query_collations(pstate, qry);
2548 : :
2549 : 7286 : return qry;
2550 : : }
2551 : :
2552 : : /*
2553 : : * transformUpdateTargetList -
2554 : : * handle SET clause in UPDATE/MERGE/INSERT ... ON CONFLICT UPDATE
2555 : : */
2556 : : List *
2557 : 8738 : transformUpdateTargetList(ParseState *pstate, List *origTlist)
2558 : : {
3860 bruce@momjian.us 2559 : 8738 : List *tlist = NIL;
2560 : : RTEPermissionInfo *target_perminfo;
2561 : : ListCell *orig_tl;
2562 : : ListCell *tl;
2563 : :
3875 andres@anarazel.de 2564 : 8738 : tlist = transformTargetList(pstate, origTlist,
2565 : : EXPR_KIND_UPDATE_SOURCE);
2566 : :
2567 : : /* Prepare to assign non-conflicting resnos to resjunk attributes */
2810 teodor@sigaev.ru 2568 [ + + ]: 8714 : if (pstate->p_next_resno <= RelationGetNumberOfAttributes(pstate->p_target_relation))
2569 : 7372 : pstate->p_next_resno = RelationGetNumberOfAttributes(pstate->p_target_relation) + 1;
2570 : :
2571 : : /* Prepare non-junk columns for assignment to target table */
1106 alvherre@alvh.no-ip. 2572 : 8714 : target_perminfo = pstate->p_target_nsitem->p_perminfo;
3875 andres@anarazel.de 2573 : 8714 : orig_tl = list_head(origTlist);
2574 : :
2575 [ + - + + : 19694 : foreach(tl, tlist)
+ + ]
2576 : : {
9647 tgl@sss.pgh.pa.us 2577 : 10998 : TargetEntry *tle = (TargetEntry *) lfirst(tl);
2578 : : ResTarget *origTarget;
2579 : : int attrno;
2580 : :
7559 2581 [ + + ]: 10998 : if (tle->resjunk)
2582 : : {
2583 : : /*
2584 : : * Resjunk nodes need no additional processing, but be sure they
2585 : : * have resnos that do not match any target columns; else rewriter
2586 : : * or planner might get confused. They don't need a resname
2587 : : * either.
2588 : : */
2589 : 69 : tle->resno = (AttrNumber) pstate->p_next_resno++;
2590 : 69 : tle->resname = NULL;
9647 2591 : 69 : continue;
2592 : : }
3875 andres@anarazel.de 2593 [ - + ]: 10929 : if (orig_tl == NULL)
9647 tgl@sss.pgh.pa.us 2594 [ # # ]:UBC 0 : elog(ERROR, "UPDATE target count mismatch --- internal error");
3172 tgl@sss.pgh.pa.us 2595 :CBC 10929 : origTarget = lfirst_node(ResTarget, orig_tl);
2596 : :
7208 2597 : 10929 : attrno = attnameAttNum(pstate->p_target_relation,
2598 : 10929 : origTarget->name, true);
2599 [ + + ]: 10929 : if (attrno == InvalidAttrNumber)
2600 [ + - + + : 12 : ereport(ERROR,
+ - ]
2601 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
2602 : : errmsg("column \"%s\" of relation \"%s\" does not exist",
2603 : : origTarget->name,
2604 : : RelationGetRelationName(pstate->p_target_relation)),
2605 : : (origTarget->indirection != NIL &&
2606 : : strcmp(origTarget->name, pstate->p_target_nsitem->p_names->aliasname) == 0) ?
2607 : : errhint("SET target columns cannot be qualified with the relation name.") : 0,
2608 : : parser_errposition(pstate, origTarget->location)));
2609 : :
9542 2610 : 10917 : updateTargetListEntry(pstate, tle, origTarget->name,
2611 : : attrno,
2612 : : origTarget->indirection,
2613 : : origTarget->location);
2614 : :
2615 : : /* Mark the target column as requiring update permissions */
1106 alvherre@alvh.no-ip. 2616 : 10911 : target_perminfo->updatedCols = bms_add_member(target_perminfo->updatedCols,
2617 : : attrno - FirstLowInvalidHeapAttributeNumber);
2618 : :
2346 tgl@sss.pgh.pa.us 2619 : 10911 : orig_tl = lnext(origTlist, orig_tl);
2620 : : }
3875 andres@anarazel.de 2621 [ - + ]: 8696 : if (orig_tl != NULL)
9647 tgl@sss.pgh.pa.us 2622 [ # # ]:UBC 0 : elog(ERROR, "UPDATE target count mismatch --- internal error");
2623 : :
2129 peter@eisentraut.org 2624 :CBC 8696 : return tlist;
2625 : : }
2626 : :
2627 : : /*
2628 : : * addNSItemForReturning -
2629 : : * add a ParseNamespaceItem for the OLD or NEW alias in RETURNING.
2630 : : */
2631 : : static void
334 dean.a.rasheed@gmail 2632 : 3125 : addNSItemForReturning(ParseState *pstate, const char *aliasname,
2633 : : VarReturningType returning_type)
2634 : : {
2635 : : List *colnames;
2636 : : int numattrs;
2637 : : ParseNamespaceColumn *nscolumns;
2638 : : ParseNamespaceItem *nsitem;
2639 : :
2640 : : /* copy per-column data from the target relation */
2641 : 3125 : colnames = pstate->p_target_nsitem->p_rte->eref->colnames;
2642 : 3125 : numattrs = list_length(colnames);
2643 : :
6 michael@paquier.xyz 2644 :GNC 3125 : nscolumns = palloc_array(ParseNamespaceColumn, numattrs);
2645 : :
334 dean.a.rasheed@gmail 2646 :CBC 3125 : memcpy(nscolumns, pstate->p_target_nsitem->p_nscolumns,
2647 : : numattrs * sizeof(ParseNamespaceColumn));
2648 : :
2649 : : /* mark all columns as returning OLD/NEW */
2650 [ + + ]: 12381 : for (int i = 0; i < numattrs; i++)
2651 : 9256 : nscolumns[i].p_varreturningtype = returning_type;
2652 : :
2653 : : /* build the nsitem, copying most fields from the target relation */
6 michael@paquier.xyz 2654 :GNC 3125 : nsitem = palloc_object(ParseNamespaceItem);
334 dean.a.rasheed@gmail 2655 :CBC 3125 : nsitem->p_names = makeAlias(aliasname, colnames);
2656 : 3125 : nsitem->p_rte = pstate->p_target_nsitem->p_rte;
2657 : 3125 : nsitem->p_rtindex = pstate->p_target_nsitem->p_rtindex;
2658 : 3125 : nsitem->p_perminfo = pstate->p_target_nsitem->p_perminfo;
2659 : 3125 : nsitem->p_nscolumns = nscolumns;
2660 : 3125 : nsitem->p_returning_type = returning_type;
2661 : :
2662 : : /* add it to the query namespace as a table-only item */
2663 : 3125 : addNSItemToQuery(pstate, nsitem, false, true, false);
2664 : 3125 : }
2665 : :
2666 : : /*
2667 : : * transformReturningClause -
2668 : : * handle a RETURNING clause in INSERT/UPDATE/DELETE/MERGE
2669 : : */
2670 : : void
2671 : 11247 : transformReturningClause(ParseState *pstate, Query *qry,
2672 : : ReturningClause *returningClause,
2673 : : ParseExprKind exprKind)
2674 : : {
2675 : 11247 : int save_nslen = list_length(pstate->p_namespace);
2676 : : int save_next_resno;
2677 : :
2678 [ + + ]: 11247 : if (returningClause == NULL)
2679 : 9650 : return; /* nothing to do */
2680 : :
2681 : : /*
2682 : : * Scan RETURNING WITH(...) options for OLD/NEW alias names. Complain if
2683 : : * there is any conflict with existing relations.
2684 : : */
2685 [ + + + + : 3230 : foreach_node(ReturningOption, option, returningClause->options)
+ + ]
2686 : : {
2687 [ + + - ]: 60 : switch (option->option)
2688 : : {
2689 : 27 : case RETURNING_OPTION_OLD:
2690 [ + + ]: 27 : if (qry->returningOldAlias != NULL)
2691 [ + - ]: 3 : ereport(ERROR,
2692 : : errcode(ERRCODE_SYNTAX_ERROR),
2693 : : /* translator: %s is OLD or NEW */
2694 : : errmsg("%s cannot be specified multiple times", "OLD"),
2695 : : parser_errposition(pstate, option->location));
2696 : 24 : qry->returningOldAlias = option->value;
2697 : 24 : break;
2698 : :
2699 : 33 : case RETURNING_OPTION_NEW:
2700 [ + + ]: 33 : if (qry->returningNewAlias != NULL)
2701 [ + - ]: 3 : ereport(ERROR,
2702 : : errcode(ERRCODE_SYNTAX_ERROR),
2703 : : /* translator: %s is OLD or NEW */
2704 : : errmsg("%s cannot be specified multiple times", "NEW"),
2705 : : parser_errposition(pstate, option->location));
2706 : 30 : qry->returningNewAlias = option->value;
2707 : 30 : break;
2708 : :
334 dean.a.rasheed@gmail 2709 :UBC 0 : default:
2710 [ # # ]: 0 : elog(ERROR, "unrecognized returning option: %d", option->option);
2711 : : }
2712 : :
334 dean.a.rasheed@gmail 2713 [ + + ]:CBC 54 : if (refnameNamespaceItem(pstate, NULL, option->value, -1, NULL) != NULL)
2714 [ + - ]: 6 : ereport(ERROR,
2715 : : errcode(ERRCODE_DUPLICATE_ALIAS),
2716 : : errmsg("table name \"%s\" specified more than once",
2717 : : option->value),
2718 : : parser_errposition(pstate, option->location));
2719 : :
2720 : 48 : addNSItemForReturning(pstate, option->value,
2721 [ + + ]: 48 : option->option == RETURNING_OPTION_OLD ?
2722 : : VAR_RETURNING_OLD : VAR_RETURNING_NEW);
2723 : : }
2724 : :
2725 : : /*
2726 : : * If OLD/NEW alias names weren't explicitly specified, use "old"/"new"
2727 : : * unless masked by existing relations.
2728 : : */
2729 [ + + + + ]: 3155 : if (qry->returningOldAlias == NULL &&
2730 : 1570 : refnameNamespaceItem(pstate, NULL, "old", -1, NULL) == NULL)
2731 : : {
2732 : 1540 : qry->returningOldAlias = "old";
2733 : 1540 : addNSItemForReturning(pstate, "old", VAR_RETURNING_OLD);
2734 : : }
2735 [ + + + + ]: 3152 : if (qry->returningNewAlias == NULL &&
2736 : 1567 : refnameNamespaceItem(pstate, NULL, "new", -1, NULL) == NULL)
2737 : : {
2738 : 1537 : qry->returningNewAlias = "new";
2739 : 1537 : addNSItemForReturning(pstate, "new", VAR_RETURNING_NEW);
2740 : : }
2741 : :
2742 : : /*
2743 : : * We need to assign resnos starting at one in the RETURNING list. Save
2744 : : * and restore the main tlist's value of p_next_resno, just in case
2745 : : * someone looks at it later (probably won't happen).
2746 : : */
7066 tgl@sss.pgh.pa.us 2747 : 1585 : save_next_resno = pstate->p_next_resno;
2748 : 1585 : pstate->p_next_resno = 1;
2749 : :
2750 : : /* transform RETURNING expressions identically to a SELECT targetlist */
334 dean.a.rasheed@gmail 2751 : 1585 : qry->returningList = transformTargetList(pstate,
2752 : : returningClause->exprs,
2753 : : exprKind);
2754 : :
2755 : : /*
2756 : : * Complain if the nonempty tlist expanded to nothing (which is possible
2757 : : * if it contains only a star-expansion of a zero-column table). If we
2758 : : * allow this, the parsed Query will look like it didn't have RETURNING,
2759 : : * with results that would probably surprise the user.
2760 : : */
2761 [ + + ]: 1564 : if (qry->returningList == NIL)
4385 tgl@sss.pgh.pa.us 2762 [ + - ]: 3 : ereport(ERROR,
2763 : : (errcode(ERRCODE_SYNTAX_ERROR),
2764 : : errmsg("RETURNING must have at least one column"),
2765 : : parser_errposition(pstate,
2766 : : exprLocation(linitial(returningClause->exprs)))));
2767 : :
2768 : : /* mark column origins */
334 dean.a.rasheed@gmail 2769 : 1561 : markTargetListOrigins(pstate, qry->returningList);
2770 : :
2771 : : /* resolve any still-unresolved output columns as being type text */
3247 tgl@sss.pgh.pa.us 2772 [ + - ]: 1561 : if (pstate->p_resolve_unknowns)
334 dean.a.rasheed@gmail 2773 : 1561 : resolveTargetListUnknowns(pstate, qry->returningList);
2774 : :
2775 : : /* restore state */
2776 : 1561 : pstate->p_namespace = list_truncate(pstate->p_namespace, save_nslen);
7066 tgl@sss.pgh.pa.us 2777 : 1561 : pstate->p_next_resno = save_next_resno;
2778 : : }
2779 : :
2780 : :
2781 : : /*
2782 : : * transformPLAssignStmt -
2783 : : * transform a PL/pgSQL assignment statement
2784 : : *
2785 : : * If there is no opt_indirection, the transformed statement looks like
2786 : : * "SELECT a_expr ...", except the expression has been cast to the type of
2787 : : * the target. With indirection, it's still a SELECT, but the expression will
2788 : : * incorporate FieldStore and/or assignment SubscriptingRef nodes to compute a
2789 : : * new value for a container-type variable represented by the target. The
2790 : : * expression references the target as the container source.
2791 : : */
2792 : : static Query *
1807 2793 : 2851 : transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
2794 : : {
2795 : : Query *qry;
2796 : 2851 : ColumnRef *cref = makeNode(ColumnRef);
2797 : 2851 : List *indirection = stmt->indirection;
2798 : 2851 : int nnames = stmt->nnames;
2799 : : Node *target;
2800 : : SelectStmtPassthrough passthru;
2801 : : bool save_resolve_unknowns;
2802 : :
2803 : : /*
2804 : : * First, construct a ColumnRef for the target variable. If the target
2805 : : * has more than one dotted name, we have to pull the extra names out of
2806 : : * the indirection list.
2807 : : */
2808 : 2851 : cref->fields = list_make1(makeString(stmt->name));
2809 : 2851 : cref->location = stmt->location;
2810 [ + + ]: 2851 : if (nnames > 1)
2811 : : {
2812 : : /* avoid munging the raw parsetree */
2813 : 201 : indirection = list_copy(indirection);
2814 [ + + + - ]: 409 : while (--nnames > 0 && indirection != NIL)
2815 : : {
2816 : 208 : Node *ind = (Node *) linitial(indirection);
2817 : :
2818 [ - + ]: 208 : if (!IsA(ind, String))
1807 tgl@sss.pgh.pa.us 2819 [ # # ]:UBC 0 : elog(ERROR, "invalid name count in PLAssignStmt");
1807 tgl@sss.pgh.pa.us 2820 :CBC 208 : cref->fields = lappend(cref->fields, ind);
2821 : 208 : indirection = list_delete_first(indirection);
2822 : : }
2823 : : }
2824 : :
2825 : : /*
2826 : : * Transform the target reference. Typically we will get back a Param
2827 : : * node, but there's no reason to be too picky about its type. (Note that
2828 : : * we must do this before calling transformSelectStmt. It's tempting to
2829 : : * do it inside transformPLAssignStmtTarget, but we need to do it before
2830 : : * adding any FROM tables to the pstate's namespace, else we might wrongly
2831 : : * resolve the target as a table column.)
2832 : : */
2833 : 2851 : target = transformExpr(pstate, (Node *) cref,
2834 : : EXPR_KIND_UPDATE_TARGET);
2835 : :
2836 : : /* Set up passthrough data for transformPLAssignStmtTarget */
80 tgl@sss.pgh.pa.us 2837 :GNC 2845 : passthru.stmt = stmt;
2838 : 2845 : passthru.target = target;
2839 : 2845 : passthru.indirection = indirection;
2840 : :
2841 : : /*
2842 : : * To avoid duplicating a lot of code, we use transformSelectStmt to do
2843 : : * almost all of the work. However, we need to do additional processing
2844 : : * on the SELECT's targetlist after it's been transformed, but before
2845 : : * possible addition of targetlist items for ORDER BY or GROUP BY.
2846 : : * transformSelectStmt knows it should call transformPLAssignStmtTarget if
2847 : : * it's passed a passthru argument.
2848 : : *
2849 : : * Also, disable resolution of unknown-type tlist items; PL/pgSQL wants to
2850 : : * deal with that itself.
2851 : : */
2852 : 2845 : save_resolve_unknowns = pstate->p_resolve_unknowns;
2853 : 2845 : pstate->p_resolve_unknowns = false;
2854 : 2845 : qry = transformSelectStmt(pstate, stmt->val, &passthru);
2855 : 2838 : pstate->p_resolve_unknowns = save_resolve_unknowns;
2856 : :
2857 : 2838 : return qry;
2858 : : }
2859 : :
2860 : : /*
2861 : : * Callback function to adjust a SELECT's tlist to make the output suitable
2862 : : * for assignment to a PLAssignStmt's target variable.
2863 : : *
2864 : : * Note: we actually modify the tle->expr in-place, but the function's API
2865 : : * is set up to not presume that.
2866 : : */
2867 : : static List *
2868 : 2845 : transformPLAssignStmtTarget(ParseState *pstate, List *tlist,
2869 : : SelectStmtPassthrough *passthru)
2870 : : {
2871 : 2845 : PLAssignStmt *stmt = passthru->stmt;
2872 : 2845 : Node *target = passthru->target;
2873 : 2845 : List *indirection = passthru->indirection;
2874 : : Oid targettype;
2875 : : int32 targettypmod;
2876 : : Oid targetcollation;
2877 : : TargetEntry *tle;
2878 : : Oid type_id;
2879 : :
2880 : 2845 : targettype = exprType(target);
2881 : 2845 : targettypmod = exprTypmod(target);
2882 : 2845 : targetcollation = exprCollation(target);
2883 : :
2884 : : /* we should have exactly one targetlist item */
1807 tgl@sss.pgh.pa.us 2885 [ + + ]:CBC 2845 : if (list_length(tlist) != 1)
2886 [ + - ]: 2 : ereport(ERROR,
2887 : : (errcode(ERRCODE_SYNTAX_ERROR),
2888 : : errmsg_plural("assignment source returned %d column",
2889 : : "assignment source returned %d columns",
2890 : : list_length(tlist),
2891 : : list_length(tlist))));
2892 : :
2893 : 2843 : tle = linitial_node(TargetEntry, tlist);
2894 : :
2895 : : /*
2896 : : * This next bit is similar to transformAssignedExpr; the key difference
2897 : : * is we use COERCION_PLPGSQL not COERCION_ASSIGNMENT.
2898 : : */
2899 : 2843 : type_id = exprType((Node *) tle->expr);
2900 : :
2901 : 2843 : pstate->p_expr_kind = EXPR_KIND_UPDATE_TARGET;
2902 : :
2903 [ + + ]: 2843 : if (indirection)
2904 : : {
2905 : 49 : tle->expr = (Expr *)
2906 : 54 : transformAssignmentIndirection(pstate,
2907 : : target,
2908 : 54 : stmt->name,
2909 : : false,
2910 : : targettype,
2911 : : targettypmod,
2912 : : targetcollation,
2913 : : indirection,
2914 : : list_head(indirection),
2915 : 54 : (Node *) tle->expr,
2916 : : COERCION_PLPGSQL,
2917 : : exprLocation(target));
2918 : : }
2919 [ + + + + ]: 2789 : else if (targettype != type_id &&
2920 [ + + + + ]: 808 : (targettype == RECORDOID || ISCOMPLEX(targettype)) &&
2921 [ + + ]: 225 : (type_id == RECORDOID || ISCOMPLEX(type_id)))
2922 : : {
2923 : : /*
2924 : : * Hack: do not let coerce_to_target_type() deal with inconsistent
2925 : : * composite types. Just pass the expression result through as-is,
2926 : : * and let the PL/pgSQL executor do the conversion its way. This is
2927 : : * rather bogus, but it's needed for backwards compatibility.
2928 : : */
2929 : : }
2930 : : else
2931 : : {
2932 : : /*
2933 : : * For normal non-qualified target column, do type checking and
2934 : : * coercion.
2935 : : */
2936 : 2606 : Node *orig_expr = (Node *) tle->expr;
2937 : :
2938 : 2606 : tle->expr = (Expr *)
2939 : 2606 : coerce_to_target_type(pstate,
2940 : : orig_expr, type_id,
2941 : : targettype, targettypmod,
2942 : : COERCION_PLPGSQL,
2943 : : COERCE_IMPLICIT_CAST,
2944 : : -1);
2945 : : /* With COERCION_PLPGSQL, this error is probably unreachable */
2946 [ - + ]: 2606 : if (tle->expr == NULL)
1807 tgl@sss.pgh.pa.us 2947 [ # # ]:UBC 0 : ereport(ERROR,
2948 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
2949 : : errmsg("variable \"%s\" is of type %s"
2950 : : " but expression is of type %s",
2951 : : stmt->name,
2952 : : format_type_be(targettype),
2953 : : format_type_be(type_id)),
2954 : : errhint("You will need to rewrite or cast the expression."),
2955 : : parser_errposition(pstate, exprLocation(orig_expr))));
2956 : : }
2957 : :
1807 tgl@sss.pgh.pa.us 2958 :CBC 2838 : pstate->p_expr_kind = EXPR_KIND_NONE;
2959 : :
80 tgl@sss.pgh.pa.us 2960 :GNC 2838 : return list_make1(tle);
2961 : : }
2962 : :
2963 : :
2964 : : /*
2965 : : * transformDeclareCursorStmt -
2966 : : * transform a DECLARE CURSOR Statement
2967 : : *
2968 : : * DECLARE CURSOR is like other utility statements in that we emit it as a
2969 : : * CMD_UTILITY Query node; however, we must first transform the contained
2970 : : * query. We used to postpone that until execution, but it's really necessary
2971 : : * to do it during the normal parse analysis phase to ensure that side effects
2972 : : * of parser hooks happen at the expected time.
2973 : : */
2974 : : static Query *
6808 tgl@sss.pgh.pa.us 2975 :CBC 2263 : transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
2976 : : {
2977 : : Query *result;
2978 : : Query *query;
2979 : :
2980 [ + + ]: 2263 : if ((stmt->options & CURSOR_OPT_SCROLL) &&
2981 [ - + ]: 120 : (stmt->options & CURSOR_OPT_NO_SCROLL))
6808 tgl@sss.pgh.pa.us 2982 [ # # ]:UBC 0 : ereport(ERROR,
2983 : : (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2984 : : /* translator: %s is a SQL keyword */
2985 : : errmsg("cannot specify both %s and %s",
2986 : : "SCROLL", "NO SCROLL")));
2987 : :
1714 peter@eisentraut.org 2988 [ - + ]:CBC 2263 : if ((stmt->options & CURSOR_OPT_ASENSITIVE) &&
1714 peter@eisentraut.org 2989 [ # # ]:UBC 0 : (stmt->options & CURSOR_OPT_INSENSITIVE))
2990 [ # # ]: 0 : ereport(ERROR,
2991 : : (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2992 : : /* translator: %s is a SQL keyword */
2993 : : errmsg("cannot specify both %s and %s",
2994 : : "ASENSITIVE", "INSENSITIVE")));
2995 : :
2996 : : /* Transform contained query, not allowing SELECT INTO */
3258 tgl@sss.pgh.pa.us 2997 :CBC 2263 : query = transformStmt(pstate, stmt->query);
2998 : 2252 : stmt->query = (Node *) query;
2999 : :
3000 : : /* Grammar should not have allowed anything but SELECT */
3001 [ + - ]: 2252 : if (!IsA(query, Query) ||
3002 [ - + ]: 2252 : query->commandType != CMD_SELECT)
6315 tgl@sss.pgh.pa.us 3003 [ # # ]:UBC 0 : elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
3004 : :
3005 : : /*
3006 : : * We also disallow data-modifying WITH in a cursor. (This could be
3007 : : * allowed, but the semantics of when the updates occur might be
3008 : : * surprising.)
3009 : : */
3258 tgl@sss.pgh.pa.us 3010 [ - + ]:CBC 2252 : if (query->hasModifyingCTE)
5408 tgl@sss.pgh.pa.us 3011 [ # # ]:UBC 0 : ereport(ERROR,
3012 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3013 : : errmsg("DECLARE CURSOR must not contain data-modifying statements in WITH")));
3014 : :
3015 : : /* FOR UPDATE and WITH HOLD are not compatible */
3258 tgl@sss.pgh.pa.us 3016 [ + + - + ]:CBC 2252 : if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
6808 tgl@sss.pgh.pa.us 3017 [ # # ]:UBC 0 : ereport(ERROR,
3018 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3019 : : /*------
3020 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3021 : : errmsg("DECLARE CURSOR WITH HOLD ... %s is not supported",
3022 : : LCS_asString(((RowMarkClause *)
3023 : : linitial(query->rowMarks))->strength)),
3024 : : errdetail("Holdable cursors must be READ ONLY.")));
3025 : :
3026 : : /* FOR UPDATE and SCROLL are not compatible */
3258 tgl@sss.pgh.pa.us 3027 [ + + - + ]:CBC 2252 : if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL))
6628 tgl@sss.pgh.pa.us 3028 [ # # ]:UBC 0 : ereport(ERROR,
3029 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3030 : : /*------
3031 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3032 : : errmsg("DECLARE SCROLL CURSOR ... %s is not supported",
3033 : : LCS_asString(((RowMarkClause *)
3034 : : linitial(query->rowMarks))->strength)),
3035 : : errdetail("Scrollable cursors must be READ ONLY.")));
3036 : :
3037 : : /* FOR UPDATE and INSENSITIVE are not compatible */
3258 tgl@sss.pgh.pa.us 3038 [ + + - + ]:CBC 2252 : if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE))
6628 tgl@sss.pgh.pa.us 3039 [ # # ]:UBC 0 : ereport(ERROR,
3040 : : (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
3041 : : /*------
3042 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3043 : : errmsg("DECLARE INSENSITIVE CURSOR ... %s is not valid",
3044 : : LCS_asString(((RowMarkClause *)
3045 : : linitial(query->rowMarks))->strength)),
3046 : : errdetail("Insensitive cursors must be READ ONLY.")));
3047 : :
3048 : : /* represent the command as a utility Query */
3258 tgl@sss.pgh.pa.us 3049 :CBC 2252 : result = makeNode(Query);
3050 : 2252 : result->commandType = CMD_UTILITY;
6808 3051 : 2252 : result->utilityStmt = (Node *) stmt;
3052 : :
3053 : 2252 : return result;
3054 : : }
3055 : :
3056 : :
3057 : : /*
3058 : : * transformExplainStmt -
3059 : : * transform an EXPLAIN Statement
3060 : : *
3061 : : * EXPLAIN is like other utility statements in that we emit it as a
3062 : : * CMD_UTILITY Query node; however, we must first transform the contained
3063 : : * query. We used to postpone that until execution, but it's really necessary
3064 : : * to do it during the normal parse analysis phase to ensure that side effects
3065 : : * of parser hooks happen at the expected time.
3066 : : */
3067 : : static Query *
3068 : 12343 : transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
3069 : : {
3070 : : Query *result;
998 3071 : 12343 : bool generic_plan = false;
3072 : 12343 : Oid *paramTypes = NULL;
3073 : 12343 : int numParams = 0;
3074 : :
3075 : : /*
3076 : : * If we have no external source of parameter definitions, and the
3077 : : * GENERIC_PLAN option is specified, then accept variable parameter
3078 : : * definitions (similarly to PREPARE, for example).
3079 : : */
3080 [ + + ]: 12343 : if (pstate->p_paramref_hook == NULL)
3081 : : {
3082 : : ListCell *lc;
3083 : :
3084 [ + + + + : 24120 : foreach(lc, stmt->options)
+ + ]
3085 : : {
3086 : 11786 : DefElem *opt = (DefElem *) lfirst(lc);
3087 : :
3088 [ + + ]: 11786 : if (strcmp(opt->defname, "generic_plan") == 0)
3089 : 9 : generic_plan = defGetBoolean(opt);
3090 : : /* don't "break", as we want the last value */
3091 : : }
3092 [ + + ]: 12334 : if (generic_plan)
3093 : 9 : setup_parse_variable_parameters(pstate, ¶mTypes, &numParams);
3094 : : }
3095 : :
3096 : : /* transform contained query, allowing SELECT INTO */
3258 3097 : 12343 : stmt->query = (Node *) transformOptionalSelectInto(pstate, stmt->query);
3098 : :
3099 : : /* make sure all is well with parameter types */
998 3100 [ + + ]: 12336 : if (generic_plan)
3101 : 9 : check_variable_parameters(pstate, (Query *) stmt->query);
3102 : :
3103 : : /* represent the command as a utility Query */
5020 3104 : 12336 : result = makeNode(Query);
3105 : 12336 : result->commandType = CMD_UTILITY;
3106 : 12336 : result->utilityStmt = (Node *) stmt;
3107 : :
3108 : 12336 : return result;
3109 : : }
3110 : :
3111 : :
3112 : : /*
3113 : : * transformCreateTableAsStmt -
3114 : : * transform a CREATE TABLE AS, SELECT ... INTO, or CREATE MATERIALIZED VIEW
3115 : : * Statement
3116 : : *
3117 : : * As with DECLARE CURSOR and EXPLAIN, transform the contained statement now.
3118 : : */
3119 : : static Query *
3120 : 1011 : transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
3121 : : {
3122 : : Query *result;
3123 : : Query *query;
3124 : :
3125 : : /* transform contained query, not allowing SELECT INTO */
4631 3126 : 1011 : query = transformStmt(pstate, stmt->query);
3127 : 1010 : stmt->query = (Node *) query;
3128 : :
3129 : : /* additional work needed for CREATE MATERIALIZED VIEW */
1984 michael@paquier.xyz 3130 [ + + ]: 1010 : if (stmt->objtype == OBJECT_MATVIEW)
3131 : : {
3132 : : ObjectAddress temp_object;
3133 : :
3134 : : /*
3135 : : * Prohibit a data-modifying CTE in the query used to create a
3136 : : * materialized view. It's not sufficiently clear what the user would
3137 : : * want to happen if the MV is refreshed or incrementally maintained.
3138 : : */
4631 tgl@sss.pgh.pa.us 3139 [ - + ]: 284 : if (query->hasModifyingCTE)
4631 tgl@sss.pgh.pa.us 3140 [ # # ]:UBC 0 : ereport(ERROR,
3141 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3142 : : errmsg("materialized views must not use data-modifying statements in WITH")));
3143 : :
3144 : : /*
3145 : : * Check whether any temporary database objects are used in the
3146 : : * creation query. It would be hard to refresh data or incrementally
3147 : : * maintain it if a source disappeared.
3148 : : */
22 tgl@sss.pgh.pa.us 3149 [ + + ]:GNC 284 : if (query_uses_temp_object(query, &temp_object))
4631 tgl@sss.pgh.pa.us 3150 [ + - ]:GBC 3 : ereport(ERROR,
3151 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3152 : : errmsg("materialized views must not use temporary objects"),
3153 : : errdetail("This view depends on temporary %s.",
3154 : : getObjectDescription(&temp_object, false))));
3155 : :
3156 : : /*
3157 : : * A materialized view would either need to save parameters for use in
3158 : : * maintaining/loading the data or prohibit them entirely. The latter
3159 : : * seems safer and more sane.
3160 : : */
4631 tgl@sss.pgh.pa.us 3161 [ - + ]:CBC 278 : if (query_contains_extern_params(query))
4631 tgl@sss.pgh.pa.us 3162 [ # # ]:UBC 0 : ereport(ERROR,
3163 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3164 : : errmsg("materialized views may not be defined using bound parameters")));
3165 : :
3166 : : /*
3167 : : * For now, we disallow unlogged materialized views, because it seems
3168 : : * like a bad idea for them to just go to empty after a crash. (If we
3169 : : * could mark them as unpopulated, that would be better, but that
3170 : : * requires catalog changes which crash recovery can't presently
3171 : : * handle.)
3172 : : */
4607 tgl@sss.pgh.pa.us 3173 [ - + ]:CBC 278 : if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
4607 tgl@sss.pgh.pa.us 3174 [ # # ]:UBC 0 : ereport(ERROR,
3175 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3176 : : errmsg("materialized views cannot be unlogged")));
3177 : :
3178 : : /*
3179 : : * At runtime, we'll need a copy of the parsed-but-not-rewritten Query
3180 : : * for purposes of creating the view's ON SELECT rule. We stash that
3181 : : * in the IntoClause because that's where intorel_startup() can
3182 : : * conveniently get it from.
3183 : : */
425 peter@eisentraut.org 3184 :CBC 278 : stmt->into->viewQuery = copyObject(query);
3185 : : }
3186 : :
3187 : : /* represent the command as a utility Query */
6808 tgl@sss.pgh.pa.us 3188 : 1004 : result = makeNode(Query);
3189 : 1004 : result->commandType = CMD_UTILITY;
3190 : 1004 : result->utilityStmt = (Node *) stmt;
3191 : :
3192 : 1004 : return result;
3193 : : }
3194 : :
3195 : : /*
3196 : : * transform a CallStmt
3197 : : */
3198 : : static Query *
2856 peter_e@gmx.net 3199 : 256 : transformCallStmt(ParseState *pstate, CallStmt *stmt)
3200 : : {
3201 : : List *targs;
3202 : : ListCell *lc;
3203 : : Node *node;
3204 : : FuncExpr *fexpr;
3205 : : HeapTuple proctup;
3206 : : Datum proargmodes;
3207 : : bool isNull;
1650 tgl@sss.pgh.pa.us 3208 : 256 : List *outargs = NIL;
3209 : : Query *result;
3210 : :
3211 : : /*
3212 : : * First, do standard parse analysis on the procedure call and its
3213 : : * arguments, allowing us to identify the called procedure.
3214 : : */
2856 peter_e@gmx.net 3215 : 256 : targs = NIL;
3216 [ + + + + : 636 : foreach(lc, stmt->funccall->args)
+ + ]
3217 : : {
3218 : 380 : targs = lappend(targs, transformExpr(pstate,
3219 : 380 : (Node *) lfirst(lc),
3220 : : EXPR_KIND_CALL_ARGUMENT));
3221 : : }
3222 : :
3223 : 256 : node = ParseFuncOrColumn(pstate,
3224 : 256 : stmt->funccall->funcname,
3225 : : targs,
3226 : : pstate->p_last_srf,
3227 : : stmt->funccall,
3228 : : true,
3229 : 256 : stmt->funccall->location);
3230 : :
2506 peter@eisentraut.org 3231 : 240 : assign_expr_collations(pstate, node);
3232 : :
1650 tgl@sss.pgh.pa.us 3233 : 240 : fexpr = castNode(FuncExpr, node);
3234 : :
3235 : 240 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
3236 [ - + ]: 240 : if (!HeapTupleIsValid(proctup))
1650 tgl@sss.pgh.pa.us 3237 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
3238 : :
3239 : : /*
3240 : : * Expand the argument list to deal with named-argument notation and
3241 : : * default arguments. For ordinary FuncExprs this'd be done during
3242 : : * planning, but a CallStmt doesn't go through planning, and there seems
3243 : : * no good reason not to do it here.
3244 : : */
1650 tgl@sss.pgh.pa.us 3245 :CBC 240 : fexpr->args = expand_function_arguments(fexpr->args,
3246 : : true,
3247 : : fexpr->funcresulttype,
3248 : : proctup);
3249 : :
3250 : : /* Fetch proargmodes; if it's null, there are no output args */
3251 : 240 : proargmodes = SysCacheGetAttr(PROCOID, proctup,
3252 : : Anum_pg_proc_proargmodes,
3253 : : &isNull);
3254 [ + + ]: 240 : if (!isNull)
3255 : : {
3256 : : /*
3257 : : * Split the list into input arguments in fexpr->args and output
3258 : : * arguments in stmt->outargs. INOUT arguments appear in both lists.
3259 : : */
3260 : : ArrayType *arr;
3261 : : int numargs;
3262 : : char *argmodes;
3263 : : List *inargs;
3264 : : int i;
3265 : :
3266 : 101 : arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
3267 : 101 : numargs = list_length(fexpr->args);
3268 [ + - ]: 101 : if (ARR_NDIM(arr) != 1 ||
3269 [ + - ]: 101 : ARR_DIMS(arr)[0] != numargs ||
3270 [ + - ]: 101 : ARR_HASNULL(arr) ||
3271 [ - + ]: 101 : ARR_ELEMTYPE(arr) != CHAROID)
1650 tgl@sss.pgh.pa.us 3272 [ # # ]:UBC 0 : elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
3273 : : numargs);
1650 tgl@sss.pgh.pa.us 3274 [ - + ]:CBC 101 : argmodes = (char *) ARR_DATA_PTR(arr);
3275 : :
3276 : 101 : inargs = NIL;
3277 : 101 : i = 0;
3278 [ + - + + : 338 : foreach(lc, fexpr->args)
+ + ]
3279 : : {
3280 : 237 : Node *n = lfirst(lc);
3281 : :
3282 [ + + + - ]: 237 : switch (argmodes[i])
3283 : : {
3284 : 78 : case PROARGMODE_IN:
3285 : : case PROARGMODE_VARIADIC:
3286 : 78 : inargs = lappend(inargs, n);
3287 : 78 : break;
3288 : 58 : case PROARGMODE_OUT:
3289 : 58 : outargs = lappend(outargs, n);
3290 : 58 : break;
3291 : 101 : case PROARGMODE_INOUT:
3292 : 101 : inargs = lappend(inargs, n);
3293 : 101 : outargs = lappend(outargs, copyObject(n));
3294 : 101 : break;
1650 tgl@sss.pgh.pa.us 3295 :UBC 0 : default:
3296 : : /* note we don't support PROARGMODE_TABLE */
3297 [ # # ]: 0 : elog(ERROR, "invalid argmode %c for procedure",
3298 : : argmodes[i]);
3299 : : break;
3300 : : }
1650 tgl@sss.pgh.pa.us 3301 :CBC 237 : i++;
3302 : : }
3303 : 101 : fexpr->args = inargs;
3304 : : }
3305 : :
3306 : 240 : stmt->funcexpr = fexpr;
3307 : 240 : stmt->outargs = outargs;
3308 : :
3309 : 240 : ReleaseSysCache(proctup);
3310 : :
3311 : : /* represent the command as a utility Query */
2856 peter_e@gmx.net 3312 : 240 : result = makeNode(Query);
3313 : 240 : result->commandType = CMD_UTILITY;
3314 : 240 : result->utilityStmt = (Node *) stmt;
3315 : :
3316 : 240 : return result;
3317 : : }
3318 : :
3319 : : /*
3320 : : * Produce a string representation of a LockClauseStrength value.
3321 : : * This should only be applied to valid values (not LCS_NONE).
3322 : : */
3323 : : const char *
4529 alvherre@alvh.no-ip. 3324 : 24 : LCS_asString(LockClauseStrength strength)
3325 : : {
3326 [ - - - + : 24 : switch (strength)
+ - ]
3327 : : {
3929 tgl@sss.pgh.pa.us 3328 :UBC 0 : case LCS_NONE:
3329 : 0 : Assert(false);
3330 : : break;
4529 alvherre@alvh.no-ip. 3331 : 0 : case LCS_FORKEYSHARE:
3332 : 0 : return "FOR KEY SHARE";
3333 : 0 : case LCS_FORSHARE:
3334 : 0 : return "FOR SHARE";
4529 alvherre@alvh.no-ip. 3335 :CBC 3 : case LCS_FORNOKEYUPDATE:
3336 : 3 : return "FOR NO KEY UPDATE";
3337 : 21 : case LCS_FORUPDATE:
3338 : 21 : return "FOR UPDATE";
3339 : : }
4242 bruce@momjian.us 3340 :UBC 0 : return "FOR some"; /* shouldn't happen */
3341 : : }
3342 : :
3343 : : /*
3344 : : * Check for features that are not supported with FOR [KEY] UPDATE/SHARE.
3345 : : *
3346 : : * exported so planner can check again after rewriting, query pullup, etc
3347 : : */
3348 : : void
4519 alvherre@alvh.no-ip. 3349 :CBC 12264 : CheckSelectLocking(Query *qry, LockClauseStrength strength)
3350 : : {
3100 tgl@sss.pgh.pa.us 3351 [ - + ]: 12264 : Assert(strength != LCS_NONE); /* else caller error */
3352 : :
9203 3353 [ - + ]: 12264 : if (qry->setOperations)
8186 tgl@sss.pgh.pa.us 3354 [ # # ]:UBC 0 : ereport(ERROR,
3355 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3356 : : /*------
3357 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3358 : : errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
3359 : : LCS_asString(strength))));
9455 tgl@sss.pgh.pa.us 3360 [ - + ]:CBC 12264 : if (qry->distinctClause != NIL)
8186 tgl@sss.pgh.pa.us 3361 [ # # ]:UBC 0 : ereport(ERROR,
3362 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3363 : : /*------
3364 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3365 : : errmsg("%s is not allowed with DISTINCT clause",
3366 : : LCS_asString(strength))));
1659 tgl@sss.pgh.pa.us 3367 [ + + + + ]:CBC 12264 : if (qry->groupClause != NIL || qry->groupingSets != NIL)
8186 3368 [ + - ]: 6 : ereport(ERROR,
3369 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3370 : : /*------
3371 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3372 : : errmsg("%s is not allowed with GROUP BY clause",
3373 : : LCS_asString(strength))));
7586 3374 [ - + ]: 12258 : if (qry->havingQual != NULL)
7586 tgl@sss.pgh.pa.us 3375 [ # # ]:UBC 0 : ereport(ERROR,
3376 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3377 : : /*------
3378 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3379 : : errmsg("%s is not allowed with HAVING clause",
3380 : : LCS_asString(strength))));
9822 vadim4o@yahoo.com 3381 [ + + ]:CBC 12258 : if (qry->hasAggs)
8186 tgl@sss.pgh.pa.us 3382 [ + - ]: 3 : ereport(ERROR,
3383 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3384 : : /*------
3385 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3386 : : errmsg("%s is not allowed with aggregate functions",
3387 : : LCS_asString(strength))));
6197 3388 [ - + ]: 12255 : if (qry->hasWindowFuncs)
6197 tgl@sss.pgh.pa.us 3389 [ # # ]:UBC 0 : ereport(ERROR,
3390 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3391 : : /*------
3392 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3393 : : errmsg("%s is not allowed with window functions",
3394 : : LCS_asString(strength))));
3381 tgl@sss.pgh.pa.us 3395 [ - + ]:CBC 12255 : if (qry->hasTargetSRFs)
5895 tgl@sss.pgh.pa.us 3396 [ # # ]:UBC 0 : ereport(ERROR,
3397 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3398 : : /*------
3399 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3400 : : errmsg("%s is not allowed with set-returning functions in the target list",
3401 : : LCS_asString(strength))));
9822 vadim4o@yahoo.com 3402 :CBC 12255 : }
3403 : :
3404 : : /*
3405 : : * Transform a FOR [KEY] UPDATE/SHARE clause
3406 : : *
3407 : : * This basically involves replacing names by integer relids.
3408 : : *
3409 : : * NB: if you need to change this, see also markQueryForLocking()
3410 : : * in rewriteHandler.c, and isLockedRefname() in parse_relation.c.
3411 : : */
3412 : : static void
5893 tgl@sss.pgh.pa.us 3413 : 5488 : transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
3414 : : bool pushedDown)
3415 : : {
7442 3416 : 5488 : List *lockedRels = lc->lockedRels;
3417 : : ListCell *l;
3418 : : ListCell *rt;
3419 : : Index i;
3420 : : LockingClause *allrels;
3421 : :
4519 alvherre@alvh.no-ip. 3422 : 5488 : CheckSelectLocking(qry, lc->strength);
3423 : :
3424 : : /* make a clause we can pass down to subqueries to select all rels */
7442 tgl@sss.pgh.pa.us 3425 : 5479 : allrels = makeNode(LockingClause);
7367 bruce@momjian.us 3426 : 5479 : allrels->lockedRels = NIL; /* indicates all rels */
4710 alvherre@alvh.no-ip. 3427 : 5479 : allrels->strength = lc->strength;
4088 3428 : 5479 : allrels->waitPolicy = lc->waitPolicy;
3429 : :
7442 tgl@sss.pgh.pa.us 3430 [ + + ]: 5479 : if (lockedRels == NIL)
3431 : : {
3432 : : /*
3433 : : * Lock all regular tables used in query and its subqueries. We
3434 : : * examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD
3435 : : * in rules. This is a bit of an abuse of a mostly-obsolete flag, but
3436 : : * it's convenient. We can't rely on the namespace mechanism that has
3437 : : * largely replaced inFromCl, since for example we need to lock
3438 : : * base-relation RTEs even if they are masked by upper joins.
3439 : : */
9209 3440 : 3667 : i = 0;
3441 [ + + + + : 7380 : foreach(rt, qry->rtable)
+ + ]
3442 : : {
3443 : 3713 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3444 : :
3445 : 3713 : ++i;
1580 3446 [ + + ]: 3713 : if (!rte->inFromCl)
3447 : 6 : continue;
8077 3448 [ + - + ]: 3707 : switch (rte->rtekind)
3449 : : {
3450 : 3692 : case RTE_RELATION:
3451 : : {
3452 : : RTEPermissionInfo *perminfo;
3453 : :
1106 alvherre@alvh.no-ip. 3454 : 3692 : applyLockingClause(qry, i,
3455 : : lc->strength,
3456 : : lc->waitPolicy,
3457 : : pushedDown);
3458 : 3692 : perminfo = getRTEPermissionInfo(qry->rteperminfos, rte);
3459 : 3692 : perminfo->requiredPerms |= ACL_SELECT_FOR_UPDATE;
3460 : : }
8077 tgl@sss.pgh.pa.us 3461 : 3692 : break;
8077 tgl@sss.pgh.pa.us 3462 :UBC 0 : case RTE_SUBQUERY:
4088 alvherre@alvh.no-ip. 3463 : 0 : applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3464 : : pushedDown);
3465 : :
3466 : : /*
3467 : : * FOR UPDATE/SHARE of subquery is propagated to all of
3468 : : * subquery's rels, too. We could do this later (based on
3469 : : * the marking of the subquery RTE) but it is convenient
3470 : : * to have local knowledge in each query level about which
3471 : : * rels need to be opened with RowShareLock.
3472 : : */
5893 tgl@sss.pgh.pa.us 3473 : 0 : transformLockingClause(pstate, rte->subquery,
3474 : : allrels, true);
8077 3475 : 0 : break;
8077 tgl@sss.pgh.pa.us 3476 :CBC 15 : default:
3477 : : /* ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE RTEs */
3478 : 15 : break;
3479 : : }
3480 : : }
3481 : : }
3482 : : else
3483 : : {
3484 : : /*
3485 : : * Lock just the named tables. As above, we allow locking any base
3486 : : * relation regardless of alias-visibility rules, so we need to
3487 : : * examine inFromCl to exclude OLD/NEW.
3488 : : */
7537 3489 [ + - + + : 3618 : foreach(l, lockedRels)
+ + ]
3490 : : {
6315 3491 : 1818 : RangeVar *thisrel = (RangeVar *) lfirst(l);
3492 : :
3493 : : /* For simplicity we insist on unqualified alias names here */
3494 [ + - - + ]: 1818 : if (thisrel->catalogname || thisrel->schemaname)
6315 tgl@sss.pgh.pa.us 3495 [ # # ]:UBC 0 : ereport(ERROR,
3496 : : (errcode(ERRCODE_SYNTAX_ERROR),
3497 : : /*------
3498 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3499 : : errmsg("%s must specify unqualified relation names",
3500 : : LCS_asString(lc->strength)),
3501 : : parser_errposition(pstate, thisrel->location)));
3502 : :
9209 tgl@sss.pgh.pa.us 3503 :CBC 1818 : i = 0;
3504 [ + - + + : 1992 : foreach(rt, qry->rtable)
+ + ]
3505 : : {
3506 : 1986 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
1245 dean.a.rasheed@gmail 3507 : 1986 : char *rtename = rte->eref->aliasname;
3508 : :
9209 tgl@sss.pgh.pa.us 3509 : 1986 : ++i;
1580 3510 [ + + ]: 1986 : if (!rte->inFromCl)
3511 : 12 : continue;
3512 : :
3513 : : /*
3514 : : * A join RTE without an alias is not visible as a relation
3515 : : * name and needs to be skipped (otherwise it might hide a
3516 : : * base relation with the same name), except if it has a USING
3517 : : * alias, which *is* visible.
3518 : : *
3519 : : * Subquery and values RTEs without aliases are never visible
3520 : : * as relation names and must always be skipped.
3521 : : */
1245 dean.a.rasheed@gmail 3522 [ + + ]: 1974 : if (rte->alias == NULL)
3523 : : {
3524 [ + + ]: 93 : if (rte->rtekind == RTE_JOIN)
3525 : : {
3526 [ + + ]: 37 : if (rte->join_using_alias == NULL)
3527 : 31 : continue;
3528 : 6 : rtename = rte->join_using_alias->aliasname;
3529 : : }
3530 [ + + ]: 56 : else if (rte->rtekind == RTE_SUBQUERY ||
3531 [ - + ]: 53 : rte->rtekind == RTE_VALUES)
1258 3532 : 3 : continue;
3533 : : }
3534 : :
3535 [ + + ]: 1940 : if (strcmp(rtename, thisrel->relname) == 0)
3536 : : {
8077 tgl@sss.pgh.pa.us 3537 [ + + + - : 1812 : switch (rte->rtekind)
- - - -
- ]
3538 : : {
3539 : 1800 : case RTE_RELATION:
3540 : : {
3541 : : RTEPermissionInfo *perminfo;
3542 : :
1106 alvherre@alvh.no-ip. 3543 : 1800 : applyLockingClause(qry, i,
3544 : : lc->strength,
3545 : : lc->waitPolicy,
3546 : : pushedDown);
3547 : 1800 : perminfo = getRTEPermissionInfo(qry->rteperminfos, rte);
3548 : 1800 : perminfo->requiredPerms |= ACL_SELECT_FOR_UPDATE;
3549 : : }
8077 tgl@sss.pgh.pa.us 3550 : 1800 : break;
3551 : 6 : case RTE_SUBQUERY:
4088 alvherre@alvh.no-ip. 3552 : 6 : applyLockingClause(qry, i, lc->strength,
3553 : : lc->waitPolicy, pushedDown);
3554 : : /* see comment above */
5893 tgl@sss.pgh.pa.us 3555 : 6 : transformLockingClause(pstate, rte->subquery,
3556 : : allrels, true);
8077 3557 : 6 : break;
3558 : 6 : case RTE_JOIN:
3559 [ + - ]: 6 : ereport(ERROR,
3560 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3561 : : /*------
3562 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3563 : : errmsg("%s cannot be applied to a join",
3564 : : LCS_asString(lc->strength)),
3565 : : parser_errposition(pstate, thisrel->location)));
3566 : : break;
8077 tgl@sss.pgh.pa.us 3567 :UBC 0 : case RTE_FUNCTION:
3568 [ # # ]: 0 : ereport(ERROR,
3569 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3570 : : /*------
3571 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3572 : : errmsg("%s cannot be applied to a function",
3573 : : LCS_asString(lc->strength)),
3574 : : parser_errposition(pstate, thisrel->location)));
3575 : : break;
3205 alvherre@alvh.no-ip. 3576 : 0 : case RTE_TABLEFUNC:
3577 [ # # ]: 0 : ereport(ERROR,
3578 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3579 : : /*------
3580 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3581 : : errmsg("%s cannot be applied to a table function",
3582 : : LCS_asString(lc->strength)),
3583 : : parser_errposition(pstate, thisrel->location)));
3584 : : break;
7076 mail@joeconway.com 3585 : 0 : case RTE_VALUES:
3586 [ # # ]: 0 : ereport(ERROR,
3587 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3588 : : /*------
3589 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3590 : : errmsg("%s cannot be applied to VALUES",
3591 : : LCS_asString(lc->strength)),
3592 : : parser_errposition(pstate, thisrel->location)));
3593 : : break;
6282 tgl@sss.pgh.pa.us 3594 : 0 : case RTE_CTE:
5894 3595 [ # # ]: 0 : ereport(ERROR,
3596 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3597 : : /*------
3598 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3599 : : errmsg("%s cannot be applied to a WITH query",
3600 : : LCS_asString(lc->strength)),
3601 : : parser_errposition(pstate, thisrel->location)));
3602 : : break;
3182 kgrittn@postgresql.o 3603 : 0 : case RTE_NAMEDTUPLESTORE:
3604 [ # # ]: 0 : ereport(ERROR,
3605 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3606 : : /*------
3607 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3608 : : errmsg("%s cannot be applied to a named tuplestore",
3609 : : LCS_asString(lc->strength)),
3610 : : parser_errposition(pstate, thisrel->location)));
3611 : : break;
3612 : :
3613 : : /* Shouldn't be possible to see RTE_RESULT here */
3614 : :
8077 tgl@sss.pgh.pa.us 3615 : 0 : default:
3616 [ # # ]: 0 : elog(ERROR, "unrecognized RTE type: %d",
3617 : : (int) rte->rtekind);
3618 : : break;
3619 : : }
8077 tgl@sss.pgh.pa.us 3620 :CBC 1806 : break; /* out of foreach loop */
3621 : : }
3622 : : }
7874 neilc@samurai.com 3623 [ + + ]: 1812 : if (rt == NULL)
8186 tgl@sss.pgh.pa.us 3624 [ + - ]: 6 : ereport(ERROR,
3625 : : (errcode(ERRCODE_UNDEFINED_TABLE),
3626 : : /*------
3627 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
3628 : : errmsg("relation \"%s\" in %s clause not found in FROM clause",
3629 : : thisrel->relname,
3630 : : LCS_asString(lc->strength)),
3631 : : parser_errposition(pstate, thisrel->location)));
3632 : : }
3633 : : }
7170 3634 : 5467 : }
3635 : :
3636 : : /*
3637 : : * Record locking info for a single rangetable item
3638 : : */
3639 : : void
5893 3640 : 5546 : applyLockingClause(Query *qry, Index rtindex,
3641 : : LockClauseStrength strength, LockWaitPolicy waitPolicy,
3642 : : bool pushedDown)
3643 : : {
3644 : : RowMarkClause *rc;
3645 : :
3100 3646 [ - + ]: 5546 : Assert(strength != LCS_NONE); /* else caller error */
3647 : :
3648 : : /* If it's an explicit clause, make sure hasForUpdate gets set */
5893 3649 [ + + ]: 5546 : if (!pushedDown)
3650 : 5496 : qry->hasForUpdate = true;
3651 : :
3652 : : /* Check for pre-existing entry for same rtindex */
5895 3653 [ - + ]: 5546 : if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
3654 : : {
3655 : : /*
3656 : : * If the same RTE is specified with more than one locking strength,
3657 : : * use the strongest. (Reasonable, since you can't take both a shared
3658 : : * and exclusive lock at the same time; it'll end up being exclusive
3659 : : * anyway.)
3660 : : *
3661 : : * Similarly, if the same RTE is specified with more than one lock
3662 : : * wait policy, consider that NOWAIT wins over SKIP LOCKED, which in
3663 : : * turn wins over waiting for the lock (the default). This is a bit
3664 : : * more debatable but raising an error doesn't seem helpful. (Consider
3665 : : * for instance SELECT FOR UPDATE NOWAIT from a view that internally
3666 : : * contains a plain FOR UPDATE spec.) Having NOWAIT win over SKIP
3667 : : * LOCKED is reasonable since the former throws an error in case of
3668 : : * coming across a locked tuple, which may be undesirable in some
3669 : : * cases but it seems better than silently returning inconsistent
3670 : : * results.
3671 : : *
3672 : : * And of course pushedDown becomes false if any clause is explicit.
3673 : : */
4710 alvherre@alvh.no-ip. 3674 :UBC 0 : rc->strength = Max(rc->strength, strength);
4088 3675 : 0 : rc->waitPolicy = Max(rc->waitPolicy, waitPolicy);
5893 tgl@sss.pgh.pa.us 3676 : 0 : rc->pushedDown &= pushedDown;
7170 3677 : 0 : return;
3678 : : }
3679 : :
3680 : : /* Make a new RowMarkClause */
7170 tgl@sss.pgh.pa.us 3681 :CBC 5546 : rc = makeNode(RowMarkClause);
3682 : 5546 : rc->rti = rtindex;
4710 alvherre@alvh.no-ip. 3683 : 5546 : rc->strength = strength;
4088 3684 : 5546 : rc->waitPolicy = waitPolicy;
5893 tgl@sss.pgh.pa.us 3685 : 5546 : rc->pushedDown = pushedDown;
7170 3686 : 5546 : qry->rowMarks = lappend(qry->rowMarks, rc);
3687 : : }
3688 : :
3689 : : #ifdef DEBUG_NODE_TESTS_ENABLED
3690 : : /*
3691 : : * Coverage testing for raw_expression_tree_walker().
3692 : : *
3693 : : * When enabled, we run raw_expression_tree_walker() over every DML statement
3694 : : * submitted to parse analysis. Without this provision, that function is only
3695 : : * applied in limited cases involving CTEs, and we don't really want to have
3696 : : * to test everything inside as well as outside a CTE.
3697 : : */
3698 : : static bool
3494 tgl@sss.pgh.pa.us 3699 :UBC 0 : test_raw_expression_coverage(Node *node, void *context)
3700 : : {
3701 [ # # ]: 0 : if (node == NULL)
3702 : 0 : return false;
3703 : 0 : return raw_expression_tree_walker(node,
3704 : : test_raw_expression_coverage,
3705 : : context);
3706 : : }
3707 : : #endif /* DEBUG_NODE_TESTS_ENABLED */
|