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