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