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