PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
analyze.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/queryjumble.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_cte.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_merge.h"
#include "parser/parse_oper.h"
#include "parser/parse_param.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "parser/parsetree.h"
#include "utils/backend_status.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for analyze.c:

Go to the source code of this file.

Functions

static QuerytransformOptionalSelectInto (ParseState *pstate, Node *parseTree)
 
static QuerytransformDeleteStmt (ParseState *pstate, DeleteStmt *stmt)
 
static QuerytransformInsertStmt (ParseState *pstate, InsertStmt *stmt)
 
static OnConflictExprtransformOnConflictClause (ParseState *pstate, OnConflictClause *onConflictClause)
 
static int count_rowexpr_columns (ParseState *pstate, Node *expr)
 
static QuerytransformSelectStmt (ParseState *pstate, SelectStmt *stmt)
 
static QuerytransformValuesClause (ParseState *pstate, SelectStmt *stmt)
 
static QuerytransformSetOperationStmt (ParseState *pstate, SelectStmt *stmt)
 
static NodetransformSetOperationTree (ParseState *pstate, SelectStmt *stmt, bool isTopLevel, List **targetlist)
 
static void determineRecursiveColTypes (ParseState *pstate, Node *larg, List *nrtargetlist)
 
static QuerytransformReturnStmt (ParseState *pstate, ReturnStmt *stmt)
 
static QuerytransformUpdateStmt (ParseState *pstate, UpdateStmt *stmt)
 
static QuerytransformPLAssignStmt (ParseState *pstate, PLAssignStmt *stmt)
 
static QuerytransformDeclareCursorStmt (ParseState *pstate, DeclareCursorStmt *stmt)
 
static QuerytransformExplainStmt (ParseState *pstate, ExplainStmt *stmt)
 
static QuerytransformCreateTableAsStmt (ParseState *pstate, CreateTableAsStmt *stmt)
 
static QuerytransformCallStmt (ParseState *pstate, CallStmt *stmt)
 
static void transformLockingClause (ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
 
Queryparse_analyze_fixedparams (RawStmt *parseTree, const char *sourceText, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
 
Queryparse_analyze_varparams (RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams, QueryEnvironment *queryEnv)
 
Queryparse_analyze_withcb (RawStmt *parseTree, const char *sourceText, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
 
Queryparse_sub_analyze (Node *parseTree, ParseState *parentParseState, CommonTableExpr *parentCTE, bool locked_from_parent, bool resolve_unknowns)
 
static void setQueryLocationAndLength (ParseState *pstate, Query *qry, Node *parseTree)
 
QuerytransformTopLevelStmt (ParseState *pstate, RawStmt *parseTree)
 
QuerytransformStmt (ParseState *pstate, Node *parseTree)
 
bool stmt_requires_parse_analysis (RawStmt *parseTree)
 
bool analyze_requires_snapshot (RawStmt *parseTree)
 
bool query_requires_rewrite_plan (Query *query)
 
ListtransformInsertRow (ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
 
ListBuildOnConflictExcludedTargetlist (Relation targetrel, Index exclRelIndex)
 
SortGroupClausemakeSortGroupClauseForSetOp (Oid rescoltype, bool require_hash)
 
ListtransformUpdateTargetList (ParseState *pstate, List *origTlist)
 
static void addNSItemForReturning (ParseState *pstate, const char *aliasname, VarReturningType returning_type)
 
void transformReturningClause (ParseState *pstate, Query *qry, ReturningClause *returningClause, ParseExprKind exprKind)
 
const char * LCS_asString (LockClauseStrength strength)
 
void CheckSelectLocking (Query *qry, LockClauseStrength strength)
 
void applyLockingClause (Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
 

Variables

post_parse_analyze_hook_type post_parse_analyze_hook = NULL
 

Function Documentation

◆ addNSItemForReturning()

static void addNSItemForReturning ( ParseState pstate,
const char *  aliasname,
VarReturningType  returning_type 
)
static

Definition at line 2690 of file analyze.c.

2692{
2693 List *colnames;
2694 int numattrs;
2695 ParseNamespaceColumn *nscolumns;
2696 ParseNamespaceItem *nsitem;
2697
2698 /* copy per-column data from the target relation */
2699 colnames = pstate->p_target_nsitem->p_rte->eref->colnames;
2700 numattrs = list_length(colnames);
2701
2702 nscolumns = (ParseNamespaceColumn *)
2703 palloc(numattrs * sizeof(ParseNamespaceColumn));
2704
2705 memcpy(nscolumns, pstate->p_target_nsitem->p_nscolumns,
2706 numattrs * sizeof(ParseNamespaceColumn));
2707
2708 /* mark all columns as returning OLD/NEW */
2709 for (int i = 0; i < numattrs; i++)
2710 nscolumns[i].p_varreturningtype = returning_type;
2711
2712 /* build the nsitem, copying most fields from the target relation */
2713 nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
2714 nsitem->p_names = makeAlias(aliasname, colnames);
2715 nsitem->p_rte = pstate->p_target_nsitem->p_rte;
2716 nsitem->p_rtindex = pstate->p_target_nsitem->p_rtindex;
2717 nsitem->p_perminfo = pstate->p_target_nsitem->p_perminfo;
2718 nsitem->p_nscolumns = nscolumns;
2719 nsitem->p_returning_type = returning_type;
2720
2721 /* add it to the query namespace as a table-only item */
2722 addNSItemToQuery(pstate, nsitem, false, true, false);
2723}
int i
Definition: isn.c:77
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:438
void * palloc(Size size)
Definition: mcxt.c:1940
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
static int list_length(const List *l)
Definition: pg_list.h:152
Definition: pg_list.h:54
RangeTblEntry * p_rte
Definition: parse_node.h:311
ParseNamespaceColumn * p_nscolumns
Definition: parse_node.h:315
RTEPermissionInfo * p_perminfo
Definition: parse_node.h:313
VarReturningType p_returning_type
Definition: parse_node.h:320
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:226

References addNSItemToQuery(), i, list_length(), makeAlias(), ParseNamespaceItem::p_names, ParseNamespaceItem::p_nscolumns, ParseNamespaceItem::p_perminfo, ParseNamespaceItem::p_returning_type, ParseNamespaceItem::p_rte, ParseNamespaceItem::p_rtindex, ParseState::p_target_nsitem, and palloc().

Referenced by transformReturningClause().

◆ analyze_requires_snapshot()

bool analyze_requires_snapshot ( RawStmt parseTree)

Definition at line 576 of file analyze.c.

577{
578 /*
579 * Currently, this should return true in exactly the same cases that
580 * stmt_requires_parse_analysis() does, so we just invoke that function
581 * rather than duplicating it. We keep the two entry points separate for
582 * clarity of callers, since from the callers' standpoint these are
583 * different conditions.
584 *
585 * While there may someday be a statement type for which transformStmt()
586 * does something nontrivial and yet no snapshot is needed for that
587 * processing, it seems likely that making such a choice would be fragile.
588 * If you want to install an exception, document the reasoning for it in a
589 * comment.
590 */
591 return stmt_requires_parse_analysis(parseTree);
592}
bool stmt_requires_parse_analysis(RawStmt *parseTree)
Definition: analyze.c:532

References stmt_requires_parse_analysis().

Referenced by BuildingPlanRequiresSnapshot(), exec_bind_message(), exec_parse_message(), and exec_simple_query().

◆ applyLockingClause()

void applyLockingClause ( Query qry,
Index  rtindex,
LockClauseStrength  strength,
LockWaitPolicy  waitPolicy,
bool  pushedDown 
)

Definition at line 3762 of file analyze.c.

3765{
3766 RowMarkClause *rc;
3767
3768 Assert(strength != LCS_NONE); /* else caller error */
3769
3770 /* If it's an explicit clause, make sure hasForUpdate gets set */
3771 if (!pushedDown)
3772 qry->hasForUpdate = true;
3773
3774 /* Check for pre-existing entry for same rtindex */
3775 if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
3776 {
3777 /*
3778 * If the same RTE is specified with more than one locking strength,
3779 * use the strongest. (Reasonable, since you can't take both a shared
3780 * and exclusive lock at the same time; it'll end up being exclusive
3781 * anyway.)
3782 *
3783 * Similarly, if the same RTE is specified with more than one lock
3784 * wait policy, consider that NOWAIT wins over SKIP LOCKED, which in
3785 * turn wins over waiting for the lock (the default). This is a bit
3786 * more debatable but raising an error doesn't seem helpful. (Consider
3787 * for instance SELECT FOR UPDATE NOWAIT from a view that internally
3788 * contains a plain FOR UPDATE spec.) Having NOWAIT win over SKIP
3789 * LOCKED is reasonable since the former throws an error in case of
3790 * coming across a locked tuple, which may be undesirable in some
3791 * cases but it seems better than silently returning inconsistent
3792 * results.
3793 *
3794 * And of course pushedDown becomes false if any clause is explicit.
3795 */
3796 rc->strength = Max(rc->strength, strength);
3797 rc->waitPolicy = Max(rc->waitPolicy, waitPolicy);
3798 rc->pushedDown &= pushedDown;
3799 return;
3800 }
3801
3802 /* Make a new RowMarkClause */
3803 rc = makeNode(RowMarkClause);
3804 rc->rti = rtindex;
3805 rc->strength = strength;
3806 rc->waitPolicy = waitPolicy;
3807 rc->pushedDown = pushedDown;
3808 qry->rowMarks = lappend(qry->rowMarks, rc);
3809}
#define Max(x, y)
Definition: c.h:969
Assert(PointerIsAligned(start, uint64))
List * lappend(List *list, void *datum)
Definition: list.c:339
@ LCS_NONE
Definition: lockoptions.h:23
#define makeNode(_type_)
Definition: nodes.h:161
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
List * rowMarks
Definition: parsenodes.h:228
LockClauseStrength strength
Definition: parsenodes.h:1594
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1595

References Assert(), get_parse_rowmark(), lappend(), LCS_NONE, makeNode, Max, RowMarkClause::pushedDown, Query::rowMarks, RowMarkClause::rti, RowMarkClause::strength, and RowMarkClause::waitPolicy.

Referenced by markQueryForLocking(), and transformLockingClause().

◆ BuildOnConflictExcludedTargetlist()

List * BuildOnConflictExcludedTargetlist ( Relation  targetrel,
Index  exclRelIndex 
)

Definition at line 1354 of file analyze.c.

1356{
1357 List *result = NIL;
1358 int attno;
1359 Var *var;
1360 TargetEntry *te;
1361
1362 /*
1363 * Note that resnos of the tlist must correspond to attnos of the
1364 * underlying relation, hence we need entries for dropped columns too.
1365 */
1366 for (attno = 0; attno < RelationGetNumberOfAttributes(targetrel); attno++)
1367 {
1368 Form_pg_attribute attr = TupleDescAttr(targetrel->rd_att, attno);
1369 char *name;
1370
1371 if (attr->attisdropped)
1372 {
1373 /*
1374 * can't use atttypid here, but it doesn't really matter what type
1375 * the Const claims to be.
1376 */
1377 var = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
1378 name = NULL;
1379 }
1380 else
1381 {
1382 var = makeVar(exclRelIndex, attno + 1,
1383 attr->atttypid, attr->atttypmod,
1384 attr->attcollation,
1385 0);
1386 name = pstrdup(NameStr(attr->attname));
1387 }
1388
1389 te = makeTargetEntry((Expr *) var,
1390 attno + 1,
1391 name,
1392 false);
1393
1394 result = lappend(result, te);
1395 }
1396
1397 /*
1398 * Add a whole-row-Var entry to support references to "EXCLUDED.*". Like
1399 * the other entries in the EXCLUDED tlist, its resno must match the Var's
1400 * varattno, else the wrong things happen while resolving references in
1401 * setrefs.c. This is against normal conventions for targetlists, but
1402 * it's okay since we don't use this as a real tlist.
1403 */
1404 var = makeVar(exclRelIndex, InvalidAttrNumber,
1405 targetrel->rd_rel->reltype,
1406 -1, InvalidOid, 0);
1407 te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true);
1408 result = lappend(result, te);
1409
1410 return result;
1411}
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:717
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:388
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:289
char * pstrdup(const char *in)
Definition: mcxt.c:2322
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:35
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:522
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
Definition: primnodes.h:262
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
const char * name

References InvalidAttrNumber, InvalidOid, lappend(), makeNullConst(), makeTargetEntry(), makeVar(), name, NameStr, NIL, pstrdup(), RelationData::rd_att, RelationData::rd_rel, RelationGetNumberOfAttributes, and TupleDescAttr().

Referenced by rewriteTargetView(), and transformOnConflictClause().

◆ CheckSelectLocking()

void CheckSelectLocking ( Query qry,
LockClauseStrength  strength 
)

Definition at line 3471 of file analyze.c.

3472{
3473 Assert(strength != LCS_NONE); /* else caller error */
3474
3475 if (qry->setOperations)
3476 ereport(ERROR,
3477 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3478 /*------
3479 translator: %s is a SQL row locking clause such as FOR UPDATE */
3480 errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
3481 LCS_asString(strength))));
3482 if (qry->distinctClause != NIL)
3483 ereport(ERROR,
3484 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3485 /*------
3486 translator: %s is a SQL row locking clause such as FOR UPDATE */
3487 errmsg("%s is not allowed with DISTINCT clause",
3488 LCS_asString(strength))));
3489 if (qry->groupClause != NIL || qry->groupingSets != NIL)
3490 ereport(ERROR,
3491 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3492 /*------
3493 translator: %s is a SQL row locking clause such as FOR UPDATE */
3494 errmsg("%s is not allowed with GROUP BY clause",
3495 LCS_asString(strength))));
3496 if (qry->havingQual != NULL)
3497 ereport(ERROR,
3498 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3499 /*------
3500 translator: %s is a SQL row locking clause such as FOR UPDATE */
3501 errmsg("%s is not allowed with HAVING clause",
3502 LCS_asString(strength))));
3503 if (qry->hasAggs)
3504 ereport(ERROR,
3505 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3506 /*------
3507 translator: %s is a SQL row locking clause such as FOR UPDATE */
3508 errmsg("%s is not allowed with aggregate functions",
3509 LCS_asString(strength))));
3510 if (qry->hasWindowFuncs)
3511 ereport(ERROR,
3512 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3513 /*------
3514 translator: %s is a SQL row locking clause such as FOR UPDATE */
3515 errmsg("%s is not allowed with window functions",
3516 LCS_asString(strength))));
3517 if (qry->hasTargetSRFs)
3518 ereport(ERROR,
3519 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3520 /*------
3521 translator: %s is a SQL row locking clause such as FOR UPDATE */
3522 errmsg("%s is not allowed with set-returning functions in the target list",
3523 LCS_asString(strength))));
3524}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3446
Node * setOperations
Definition: parsenodes.h:230
List * groupClause
Definition: parsenodes.h:211
Node * havingQual
Definition: parsenodes.h:216
List * groupingSets
Definition: parsenodes.h:214
List * distinctClause
Definition: parsenodes.h:220

References Assert(), Query::distinctClause, ereport, errcode(), errmsg(), ERROR, Query::groupClause, Query::groupingSets, Query::havingQual, LCS_asString(), LCS_NONE, NIL, and Query::setOperations.

Referenced by preprocess_rowmarks(), and transformLockingClause().

◆ count_rowexpr_columns()

static int count_rowexpr_columns ( ParseState pstate,
Node expr 
)
static

Definition at line 1424 of file analyze.c.

1425{
1426 if (expr == NULL)
1427 return -1;
1428 if (IsA(expr, RowExpr))
1429 return list_length(((RowExpr *) expr)->args);
1430 if (IsA(expr, Var))
1431 {
1432 Var *var = (Var *) expr;
1433 AttrNumber attnum = var->varattno;
1434
1435 if (attnum > 0 && var->vartype == RECORDOID)
1436 {
1437 RangeTblEntry *rte;
1438
1439 rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
1440 if (rte->rtekind == RTE_SUBQUERY)
1441 {
1442 /* Subselect-in-FROM: examine sub-select's output expr */
1444 attnum);
1445
1446 if (ste == NULL || ste->resjunk)
1447 return -1;
1448 expr = (Node *) ste->expr;
1449 if (IsA(expr, RowExpr))
1450 return list_length(((RowExpr *) expr)->args);
1451 }
1452 }
1453 }
1454 return -1;
1455}
int16 AttrNumber
Definition: attnum.h:21
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
RangeTblEntry * GetRTEByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
int16 attnum
Definition: pg_attribute.h:74
Definition: nodes.h:135
List * targetList
Definition: parsenodes.h:193
Query * subquery
Definition: parsenodes.h:1118
RTEKind rtekind
Definition: parsenodes.h:1061
Expr * expr
Definition: primnodes.h:2219
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Index varlevelsup
Definition: primnodes.h:294

References generate_unaccent_rules::args, attnum, TargetEntry::expr, get_tle_by_resno(), GetRTEByRangeTablePosn(), if(), IsA, list_length(), RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblEntry::subquery, Query::targetList, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by transformInsertRow().

◆ determineRecursiveColTypes()

static void determineRecursiveColTypes ( ParseState pstate,
Node larg,
List nrtargetlist 
)
static

Definition at line 2464 of file analyze.c.

2465{
2466 Node *node;
2467 int leftmostRTI;
2468 Query *leftmostQuery;
2469 List *targetList;
2470 ListCell *left_tlist;
2471 ListCell *nrtl;
2472 int next_resno;
2473
2474 /*
2475 * Find leftmost leaf SELECT
2476 */
2477 node = larg;
2478 while (node && IsA(node, SetOperationStmt))
2479 node = ((SetOperationStmt *) node)->larg;
2480 Assert(node && IsA(node, RangeTblRef));
2481 leftmostRTI = ((RangeTblRef *) node)->rtindex;
2482 leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
2483 Assert(leftmostQuery != NULL);
2484
2485 /*
2486 * Generate dummy targetlist using column names of leftmost select and
2487 * dummy result expressions of the non-recursive term.
2488 */
2489 targetList = NIL;
2490 next_resno = 1;
2491
2492 forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
2493 {
2494 TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
2495 TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
2496 char *colName;
2497 TargetEntry *tle;
2498
2499 Assert(!lefttle->resjunk);
2500 colName = pstrdup(lefttle->resname);
2501 tle = makeTargetEntry(nrtle->expr,
2502 next_resno++,
2503 colName,
2504 false);
2505 targetList = lappend(targetList, tle);
2506 }
2507
2508 /* Now build CTE's output column info using dummy targetlist */
2509 analyzeCTETargetList(pstate, pstate->p_parent_cte, targetList);
2510}
void analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
Definition: parse_cte.c:571
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define lfirst(lc)
Definition: pg_list.h:172
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
CommonTableExpr * p_parent_cte
Definition: parse_node.h:224
List * p_rtable
Definition: parse_node.h:212

References analyzeCTETargetList(), Assert(), TargetEntry::expr, forboth, IsA, lappend(), lfirst, makeTargetEntry(), NIL, ParseState::p_parent_cte, ParseState::p_rtable, pstrdup(), rt_fetch, and Query::targetList.

Referenced by transformSetOperationTree().

◆ LCS_asString()

const char * LCS_asString ( LockClauseStrength  strength)

Definition at line 3446 of file analyze.c.

3447{
3448 switch (strength)
3449 {
3450 case LCS_NONE:
3451 Assert(false);
3452 break;
3453 case LCS_FORKEYSHARE:
3454 return "FOR KEY SHARE";
3455 case LCS_FORSHARE:
3456 return "FOR SHARE";
3457 case LCS_FORNOKEYUPDATE:
3458 return "FOR NO KEY UPDATE";
3459 case LCS_FORUPDATE:
3460 return "FOR UPDATE";
3461 }
3462 return "FOR some"; /* shouldn't happen */
3463}
@ LCS_FORUPDATE
Definition: lockoptions.h:27
@ LCS_FORSHARE
Definition: lockoptions.h:25
@ LCS_FORKEYSHARE
Definition: lockoptions.h:24
@ LCS_FORNOKEYUPDATE
Definition: lockoptions.h:26

References Assert(), LCS_FORKEYSHARE, LCS_FORNOKEYUPDATE, LCS_FORSHARE, LCS_FORUPDATE, and LCS_NONE.

Referenced by CheckSelectLocking(), grouping_planner(), make_outerjoininfo(), transformDeclareCursorStmt(), transformLockingClause(), transformSetOperationStmt(), transformSetOperationTree(), and transformValuesClause().

◆ makeSortGroupClauseForSetOp()

SortGroupClause * makeSortGroupClauseForSetOp ( Oid  rescoltype,
bool  require_hash 
)

Definition at line 2085 of file analyze.c.

2086{
2088 Oid sortop;
2089 Oid eqop;
2090 bool hashable;
2091
2092 /* determine the eqop and optional sortop */
2093 get_sort_group_operators(rescoltype,
2094 false, true, false,
2095 &sortop, &eqop, NULL,
2096 &hashable);
2097
2098 /*
2099 * The type cache doesn't believe that record is hashable (see
2100 * cache_record_field_properties()), but if the caller really needs hash
2101 * support, we can assume it does. Worst case, if any components of the
2102 * record don't support hashing, we will fail at execution.
2103 */
2104 if (require_hash && (rescoltype == RECORDOID || rescoltype == RECORDARRAYOID))
2105 hashable = true;
2106
2107 /* we don't have a tlist yet, so can't assign sortgrouprefs */
2108 grpcl->tleSortGroupRef = 0;
2109 grpcl->eqop = eqop;
2110 grpcl->sortop = sortop;
2111 grpcl->reverse_sort = false; /* Sort-op is "less than", or InvalidOid */
2112 grpcl->nulls_first = false; /* OK with or without sortop */
2113 grpcl->hashable = hashable;
2114
2115 return grpcl;
2116}
void get_sort_group_operators(Oid argtype, bool needLT, bool needEQ, bool needGT, Oid *ltOpr, Oid *eqOpr, Oid *gtOpr, bool *isHashable)
Definition: parse_oper.c:180
unsigned int Oid
Definition: postgres_ext.h:30
Index tleSortGroupRef
Definition: parsenodes.h:1452

References SortGroupClause::eqop, get_sort_group_operators(), makeNode, SortGroupClause::nulls_first, SortGroupClause::reverse_sort, SortGroupClause::sortop, and SortGroupClause::tleSortGroupRef.

Referenced by rewriteSearchAndCycle(), and transformSetOperationTree().

◆ parse_analyze_fixedparams()

Query * parse_analyze_fixedparams ( RawStmt parseTree,
const char *  sourceText,
const Oid paramTypes,
int  numParams,
QueryEnvironment queryEnv 
)

Definition at line 105 of file analyze.c.

108{
109 ParseState *pstate = make_parsestate(NULL);
110 Query *query;
111 JumbleState *jstate = NULL;
112
113 Assert(sourceText != NULL); /* required as of 8.4 */
114
115 pstate->p_sourcetext = sourceText;
116
117 if (numParams > 0)
118 setup_parse_fixed_parameters(pstate, paramTypes, numParams);
119
120 pstate->p_queryEnv = queryEnv;
121
122 query = transformTopLevelStmt(pstate, parseTree);
123
124 if (IsQueryIdEnabled())
125 jstate = JumbleQuery(query);
126
128 (*post_parse_analyze_hook) (pstate, query, jstate);
129
130 free_parsestate(pstate);
131
132 pgstat_report_query_id(query->queryId, false);
133
134 return query;
135}
void pgstat_report_query_id(uint64 query_id, bool force)
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:72
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
void setup_parse_fixed_parameters(ParseState *pstate, const Oid *paramTypes, int numParams)
Definition: parse_param.c:68
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:59
Query * transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree)
Definition: analyze.c:332
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:95
JumbleState * JumbleQuery(Query *query)
QueryEnvironment * p_queryEnv
Definition: parse_node.h:239
const char * p_sourcetext
Definition: parse_node.h:209

References Assert(), free_parsestate(), IsQueryIdEnabled(), JumbleQuery(), make_parsestate(), ParseState::p_queryEnv, ParseState::p_sourcetext, pgstat_report_query_id(), post_parse_analyze_hook, setup_parse_fixed_parameters(), and transformTopLevelStmt().

Referenced by DefineView(), and pg_analyze_and_rewrite_fixedparams().

◆ parse_analyze_varparams()

Query * parse_analyze_varparams ( RawStmt parseTree,
const char *  sourceText,
Oid **  paramTypes,
int *  numParams,
QueryEnvironment queryEnv 
)

Definition at line 145 of file analyze.c.

148{
149 ParseState *pstate = make_parsestate(NULL);
150 Query *query;
151 JumbleState *jstate = NULL;
152
153 Assert(sourceText != NULL); /* required as of 8.4 */
154
155 pstate->p_sourcetext = sourceText;
156
157 setup_parse_variable_parameters(pstate, paramTypes, numParams);
158
159 pstate->p_queryEnv = queryEnv;
160
161 query = transformTopLevelStmt(pstate, parseTree);
162
163 /* make sure all is well with parameter types */
164 check_variable_parameters(pstate, query);
165
166 if (IsQueryIdEnabled())
167 jstate = JumbleQuery(query);
168
170 (*post_parse_analyze_hook) (pstate, query, jstate);
171
172 free_parsestate(pstate);
173
174 pgstat_report_query_id(query->queryId, false);
175
176 return query;
177}
void check_variable_parameters(ParseState *pstate, Query *query)
Definition: parse_param.c:269
void setup_parse_variable_parameters(ParseState *pstate, Oid **paramTypes, int *numParams)
Definition: parse_param.c:84

References Assert(), check_variable_parameters(), free_parsestate(), IsQueryIdEnabled(), JumbleQuery(), make_parsestate(), ParseState::p_queryEnv, ParseState::p_sourcetext, pgstat_report_query_id(), post_parse_analyze_hook, setup_parse_variable_parameters(), and transformTopLevelStmt().

Referenced by pg_analyze_and_rewrite_varparams().

◆ parse_analyze_withcb()

Query * parse_analyze_withcb ( RawStmt parseTree,
const char *  sourceText,
ParserSetupHook  parserSetup,
void *  parserSetupArg,
QueryEnvironment queryEnv 
)

Definition at line 186 of file analyze.c.

190{
191 ParseState *pstate = make_parsestate(NULL);
192 Query *query;
193 JumbleState *jstate = NULL;
194
195 Assert(sourceText != NULL); /* required as of 8.4 */
196
197 pstate->p_sourcetext = sourceText;
198 pstate->p_queryEnv = queryEnv;
199 (*parserSetup) (pstate, parserSetupArg);
200
201 query = transformTopLevelStmt(pstate, parseTree);
202
203 if (IsQueryIdEnabled())
204 jstate = JumbleQuery(query);
205
207 (*post_parse_analyze_hook) (pstate, query, jstate);
208
209 free_parsestate(pstate);
210
211 pgstat_report_query_id(query->queryId, false);
212
213 return query;
214}

References Assert(), free_parsestate(), IsQueryIdEnabled(), JumbleQuery(), make_parsestate(), ParseState::p_queryEnv, ParseState::p_sourcetext, pgstat_report_query_id(), post_parse_analyze_hook, and transformTopLevelStmt().

Referenced by pg_analyze_and_rewrite_withcb().

◆ parse_sub_analyze()

Query * parse_sub_analyze ( Node parseTree,
ParseState parentParseState,
CommonTableExpr parentCTE,
bool  locked_from_parent,
bool  resolve_unknowns 
)

Definition at line 222 of file analyze.c.

226{
227 ParseState *pstate = make_parsestate(parentParseState);
228 Query *query;
229
230 pstate->p_parent_cte = parentCTE;
231 pstate->p_locked_from_parent = locked_from_parent;
232 pstate->p_resolve_unknowns = resolve_unknowns;
233
234 query = transformStmt(pstate, parseTree);
235
236 free_parsestate(pstate);
237
238 return query;
239}
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:396
bool p_locked_from_parent
Definition: parse_node.h:234
bool p_resolve_unknowns
Definition: parse_node.h:236

References free_parsestate(), make_parsestate(), ParseState::p_locked_from_parent, ParseState::p_parent_cte, ParseState::p_resolve_unknowns, and transformStmt().

Referenced by analyzeCTE(), transformRangeSubselect(), transformSetOperationTree(), and transformSubLink().

◆ query_requires_rewrite_plan()

bool query_requires_rewrite_plan ( Query query)

Definition at line 605 of file analyze.c.

606{
607 bool result;
608
609 if (query->commandType != CMD_UTILITY)
610 {
611 /* All optimizable statements require rewriting/planning */
612 result = true;
613 }
614 else
615 {
616 /* This list should match stmt_requires_parse_analysis() */
617 switch (nodeTag(query->utilityStmt))
618 {
619 case T_DeclareCursorStmt:
620 case T_ExplainStmt:
621 case T_CreateTableAsStmt:
622 case T_CallStmt:
623 result = true;
624 break;
625 default:
626 result = false;
627 break;
628 }
629 }
630 return result;
631}
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ CMD_UTILITY
Definition: nodes.h:276
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

References CMD_UTILITY, Query::commandType, nodeTag, and Query::utilityStmt.

Referenced by BuildingPlanRequiresSnapshot(), and StmtPlanRequiresRevalidation().

◆ setQueryLocationAndLength()

static void setQueryLocationAndLength ( ParseState pstate,
Query qry,
Node parseTree 
)
static

Definition at line 259 of file analyze.c.

260{
261 ParseLoc stmt_len = 0;
262
263 /*
264 * If there is no information about the top RawStmt's length, leave it at
265 * 0 to use the whole string.
266 */
267 if (pstate->p_stmt_len == 0)
268 return;
269
270 switch (nodeTag(parseTree))
271 {
272 case T_InsertStmt:
273 qry->stmt_location = ((InsertStmt *) parseTree)->stmt_location;
274 stmt_len = ((InsertStmt *) parseTree)->stmt_len;
275 break;
276
277 case T_DeleteStmt:
278 qry->stmt_location = ((DeleteStmt *) parseTree)->stmt_location;
279 stmt_len = ((DeleteStmt *) parseTree)->stmt_len;
280 break;
281
282 case T_UpdateStmt:
283 qry->stmt_location = ((UpdateStmt *) parseTree)->stmt_location;
284 stmt_len = ((UpdateStmt *) parseTree)->stmt_len;
285 break;
286
287 case T_MergeStmt:
288 qry->stmt_location = ((MergeStmt *) parseTree)->stmt_location;
289 stmt_len = ((MergeStmt *) parseTree)->stmt_len;
290 break;
291
292 case T_SelectStmt:
293 qry->stmt_location = ((SelectStmt *) parseTree)->stmt_location;
294 stmt_len = ((SelectStmt *) parseTree)->stmt_len;
295 break;
296
297 case T_PLAssignStmt:
298 qry->stmt_location = ((PLAssignStmt *) parseTree)->location;
299 break;
300
301 default:
302 qry->stmt_location = pstate->p_stmt_location;
303 break;
304 }
305
306 if (stmt_len > 0)
307 {
308 /* Statement's length is known, use it */
309 qry->stmt_len = stmt_len;
310 }
311 else
312 {
313 /*
314 * Compute the statement's length from the statement's location and
315 * the RawStmt's length and location.
316 */
317 qry->stmt_len = pstate->p_stmt_len - (qry->stmt_location - pstate->p_stmt_location);
318 }
319
320 /* The calculated statement length should be calculated as positive. */
321 Assert(qry->stmt_len >= 0);
322}
int ParseLoc
Definition: nodes.h:246
ParseLoc p_stmt_location
Definition: parse_node.h:210
ParseLoc p_stmt_len
Definition: parse_node.h:211
ParseLoc stmt_location
Definition: parsenodes.h:249

References Assert(), nodeTag, ParseState::p_stmt_len, ParseState::p_stmt_location, and Query::stmt_location.

Referenced by transformStmt().

◆ stmt_requires_parse_analysis()

bool stmt_requires_parse_analysis ( RawStmt parseTree)

Definition at line 532 of file analyze.c.

533{
534 bool result;
535
536 switch (nodeTag(parseTree->stmt))
537 {
538 /*
539 * Optimizable statements
540 */
541 case T_InsertStmt:
542 case T_DeleteStmt:
543 case T_UpdateStmt:
544 case T_MergeStmt:
545 case T_SelectStmt:
546 case T_ReturnStmt:
547 case T_PLAssignStmt:
548 result = true;
549 break;
550
551 /*
552 * Special cases
553 */
554 case T_DeclareCursorStmt:
555 case T_ExplainStmt:
556 case T_CreateTableAsStmt:
557 case T_CallStmt:
558 result = true;
559 break;
560
561 default:
562 /* all other statements just get wrapped in a CMD_UTILITY Query */
563 result = false;
564 break;
565 }
566
567 return result;
568}
Node * stmt
Definition: parsenodes.h:2071

References nodeTag, and RawStmt::stmt.

Referenced by analyze_requires_snapshot(), and StmtPlanRequiresRevalidation().

◆ transformCallStmt()

static Query * transformCallStmt ( ParseState pstate,
CallStmt stmt 
)
static

Definition at line 3321 of file analyze.c.

3322{
3323 List *targs;
3324 ListCell *lc;
3325 Node *node;
3326 FuncExpr *fexpr;
3327 HeapTuple proctup;
3328 Datum proargmodes;
3329 bool isNull;
3330 List *outargs = NIL;
3331 Query *result;
3332
3333 /*
3334 * First, do standard parse analysis on the procedure call and its
3335 * arguments, allowing us to identify the called procedure.
3336 */
3337 targs = NIL;
3338 foreach(lc, stmt->funccall->args)
3339 {
3340 targs = lappend(targs, transformExpr(pstate,
3341 (Node *) lfirst(lc),
3343 }
3344
3345 node = ParseFuncOrColumn(pstate,
3346 stmt->funccall->funcname,
3347 targs,
3348 pstate->p_last_srf,
3349 stmt->funccall,
3350 true,
3351 stmt->funccall->location);
3352
3353 assign_expr_collations(pstate, node);
3354
3355 fexpr = castNode(FuncExpr, node);
3356
3357 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
3358 if (!HeapTupleIsValid(proctup))
3359 elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
3360
3361 /*
3362 * Expand the argument list to deal with named-argument notation and
3363 * default arguments. For ordinary FuncExprs this'd be done during
3364 * planning, but a CallStmt doesn't go through planning, and there seems
3365 * no good reason not to do it here.
3366 */
3367 fexpr->args = expand_function_arguments(fexpr->args,
3368 true,
3369 fexpr->funcresulttype,
3370 proctup);
3371
3372 /* Fetch proargmodes; if it's null, there are no output args */
3373 proargmodes = SysCacheGetAttr(PROCOID, proctup,
3374 Anum_pg_proc_proargmodes,
3375 &isNull);
3376 if (!isNull)
3377 {
3378 /*
3379 * Split the list into input arguments in fexpr->args and output
3380 * arguments in stmt->outargs. INOUT arguments appear in both lists.
3381 */
3382 ArrayType *arr;
3383 int numargs;
3384 char *argmodes;
3385 List *inargs;
3386 int i;
3387
3388 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
3389 numargs = list_length(fexpr->args);
3390 if (ARR_NDIM(arr) != 1 ||
3391 ARR_DIMS(arr)[0] != numargs ||
3392 ARR_HASNULL(arr) ||
3393 ARR_ELEMTYPE(arr) != CHAROID)
3394 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
3395 numargs);
3396 argmodes = (char *) ARR_DATA_PTR(arr);
3397
3398 inargs = NIL;
3399 i = 0;
3400 foreach(lc, fexpr->args)
3401 {
3402 Node *n = lfirst(lc);
3403
3404 switch (argmodes[i])
3405 {
3406 case PROARGMODE_IN:
3407 case PROARGMODE_VARIADIC:
3408 inargs = lappend(inargs, n);
3409 break;
3410 case PROARGMODE_OUT:
3411 outargs = lappend(outargs, n);
3412 break;
3413 case PROARGMODE_INOUT:
3414 inargs = lappend(inargs, n);
3415 outargs = lappend(outargs, copyObject(n));
3416 break;
3417 default:
3418 /* note we don't support PROARGMODE_TABLE */
3419 elog(ERROR, "invalid argmode %c for procedure",
3420 argmodes[i]);
3421 break;
3422 }
3423 i++;
3424 }
3425 fexpr->args = inargs;
3426 }
3427
3428 stmt->funcexpr = fexpr;
3429 stmt->outargs = outargs;
3430
3431 ReleaseSysCache(proctup);
3432
3433 /* represent the command as a utility Query */
3434 result = makeNode(Query);
3435 result->commandType = CMD_UTILITY;
3436 result->utilityStmt = (Node *) stmt;
3437
3438 return result;
3439}
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
List * expand_function_arguments(List *args, bool include_out_arguments, Oid result_type, HeapTuple func_tuple)
Definition: clauses.c:4179
#define elog(elevel,...)
Definition: elog.h:226
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define stmt
Definition: indent_codes.h:59
#define copyObject(obj)
Definition: nodes.h:230
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:118
Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, Node *last_srf, FuncCall *fn, bool proc_call, int location)
Definition: parse_func.c:90
@ EXPR_KIND_CALL_ARGUMENT
Definition: parse_node.h:81
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
Oid funcid
Definition: primnodes.h:767
List * args
Definition: primnodes.h:785
Node * p_last_srf
Definition: parse_node.h:248
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600

References FuncExpr::args, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, assign_expr_collations(), castNode, CMD_UTILITY, Query::commandType, copyObject, DatumGetArrayTypeP, elog, ERROR, expand_function_arguments(), EXPR_KIND_CALL_ARGUMENT, FuncExpr::funcid, HeapTupleIsValid, i, lappend(), lfirst, list_length(), makeNode, NIL, ObjectIdGetDatum(), ParseState::p_last_srf, ParseFuncOrColumn(), ReleaseSysCache(), SearchSysCache1(), stmt, SysCacheGetAttr(), transformExpr(), and Query::utilityStmt.

Referenced by transformStmt().

◆ transformCreateTableAsStmt()

static Query * transformCreateTableAsStmt ( ParseState pstate,
CreateTableAsStmt stmt 
)
static

Definition at line 3246 of file analyze.c.

3247{
3248 Query *result;
3249 Query *query;
3250
3251 /* transform contained query, not allowing SELECT INTO */
3252 query = transformStmt(pstate, stmt->query);
3253 stmt->query = (Node *) query;
3254
3255 /* additional work needed for CREATE MATERIALIZED VIEW */
3256 if (stmt->objtype == OBJECT_MATVIEW)
3257 {
3258 /*
3259 * Prohibit a data-modifying CTE in the query used to create a
3260 * materialized view. It's not sufficiently clear what the user would
3261 * want to happen if the MV is refreshed or incrementally maintained.
3262 */
3263 if (query->hasModifyingCTE)
3264 ereport(ERROR,
3265 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3266 errmsg("materialized views must not use data-modifying statements in WITH")));
3267
3268 /*
3269 * Check whether any temporary database objects are used in the
3270 * creation query. It would be hard to refresh data or incrementally
3271 * maintain it if a source disappeared.
3272 */
3273 if (isQueryUsingTempRelation(query))
3274 ereport(ERROR,
3275 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3276 errmsg("materialized views must not use temporary tables or views")));
3277
3278 /*
3279 * A materialized view would either need to save parameters for use in
3280 * maintaining/loading the data or prohibit them entirely. The latter
3281 * seems safer and more sane.
3282 */
3284 ereport(ERROR,
3285 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3286 errmsg("materialized views may not be defined using bound parameters")));
3287
3288 /*
3289 * For now, we disallow unlogged materialized views, because it seems
3290 * like a bad idea for them to just go to empty after a crash. (If we
3291 * could mark them as unpopulated, that would be better, but that
3292 * requires catalog changes which crash recovery can't presently
3293 * handle.)
3294 */
3295 if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
3296 ereport(ERROR,
3297 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3298 errmsg("materialized views cannot be unlogged")));
3299
3300 /*
3301 * At runtime, we'll need a copy of the parsed-but-not-rewritten Query
3302 * for purposes of creating the view's ON SELECT rule. We stash that
3303 * in the IntoClause because that's where intorel_startup() can
3304 * conveniently get it from.
3305 */
3306 stmt->into->viewQuery = copyObject(query);
3307 }
3308
3309 /* represent the command as a utility Query */
3310 result = makeNode(Query);
3311 result->commandType = CMD_UTILITY;
3312 result->utilityStmt = (Node *) stmt;
3313
3314 return result;
3315}
bool query_contains_extern_params(Query *query)
Definition: parse_param.c:331
bool isQueryUsingTempRelation(Query *query)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2340

References CMD_UTILITY, Query::commandType, copyObject, ereport, errcode(), errmsg(), ERROR, isQueryUsingTempRelation(), makeNode, OBJECT_MATVIEW, query_contains_extern_params(), stmt, transformStmt(), and Query::utilityStmt.

Referenced by transformStmt().

◆ transformDeclareCursorStmt()

static Query * transformDeclareCursorStmt ( ParseState pstate,
DeclareCursorStmt stmt 
)
static

Definition at line 3101 of file analyze.c.

3102{
3103 Query *result;
3104 Query *query;
3105
3106 if ((stmt->options & CURSOR_OPT_SCROLL) &&
3107 (stmt->options & CURSOR_OPT_NO_SCROLL))
3108 ereport(ERROR,
3109 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
3110 /* translator: %s is a SQL keyword */
3111 errmsg("cannot specify both %s and %s",
3112 "SCROLL", "NO SCROLL")));
3113
3114 if ((stmt->options & CURSOR_OPT_ASENSITIVE) &&
3115 (stmt->options & CURSOR_OPT_INSENSITIVE))
3116 ereport(ERROR,
3117 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
3118 /* translator: %s is a SQL keyword */
3119 errmsg("cannot specify both %s and %s",
3120 "ASENSITIVE", "INSENSITIVE")));
3121
3122 /* Transform contained query, not allowing SELECT INTO */
3123 query = transformStmt(pstate, stmt->query);
3124 stmt->query = (Node *) query;
3125
3126 /* Grammar should not have allowed anything but SELECT */
3127 if (!IsA(query, Query) ||
3128 query->commandType != CMD_SELECT)
3129 elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
3130
3131 /*
3132 * We also disallow data-modifying WITH in a cursor. (This could be
3133 * allowed, but the semantics of when the updates occur might be
3134 * surprising.)
3135 */
3136 if (query->hasModifyingCTE)
3137 ereport(ERROR,
3138 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3139 errmsg("DECLARE CURSOR must not contain data-modifying statements in WITH")));
3140
3141 /* FOR UPDATE and WITH HOLD are not compatible */
3142 if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
3143 ereport(ERROR,
3144 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3145 /*------
3146 translator: %s is a SQL row locking clause such as FOR UPDATE */
3147 errmsg("DECLARE CURSOR WITH HOLD ... %s is not supported",
3149 linitial(query->rowMarks))->strength)),
3150 errdetail("Holdable cursors must be READ ONLY.")));
3151
3152 /* FOR UPDATE and SCROLL are not compatible */
3153 if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL))
3154 ereport(ERROR,
3155 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3156 /*------
3157 translator: %s is a SQL row locking clause such as FOR UPDATE */
3158 errmsg("DECLARE SCROLL CURSOR ... %s is not supported",
3160 linitial(query->rowMarks))->strength)),
3161 errdetail("Scrollable cursors must be READ ONLY.")));
3162
3163 /* FOR UPDATE and INSENSITIVE are not compatible */
3164 if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE))
3165 ereport(ERROR,
3166 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
3167 /*------
3168 translator: %s is a SQL row locking clause such as FOR UPDATE */
3169 errmsg("DECLARE INSENSITIVE CURSOR ... %s is not valid",
3171 linitial(query->rowMarks))->strength)),
3172 errdetail("Insensitive cursors must be READ ONLY.")));
3173
3174 /* represent the command as a utility Query */
3175 result = makeNode(Query);
3176 result->commandType = CMD_UTILITY;
3177 result->utilityStmt = (Node *) stmt;
3178
3179 return result;
3180}
int errdetail(const char *fmt,...)
Definition: elog.c:1204
@ CMD_SELECT
Definition: nodes.h:271
#define CURSOR_OPT_INSENSITIVE
Definition: parsenodes.h:3378
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3376
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:3380
#define CURSOR_OPT_ASENSITIVE
Definition: parsenodes.h:3379
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3377
#define linitial(l)
Definition: pg_list.h:178

References CMD_SELECT, CMD_UTILITY, Query::commandType, CURSOR_OPT_ASENSITIVE, CURSOR_OPT_HOLD, CURSOR_OPT_INSENSITIVE, CURSOR_OPT_NO_SCROLL, CURSOR_OPT_SCROLL, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, IsA, LCS_asString(), linitial, makeNode, NIL, Query::rowMarks, stmt, transformStmt(), and Query::utilityStmt.

Referenced by transformStmt().

◆ transformDeleteStmt()

static Query * transformDeleteStmt ( ParseState pstate,
DeleteStmt stmt 
)
static

Definition at line 638 of file analyze.c.

639{
640 Query *qry = makeNode(Query);
641 ParseNamespaceItem *nsitem;
642 Node *qual;
643
644 qry->commandType = CMD_DELETE;
645
646 /* process the WITH clause independently of all else */
647 if (stmt->withClause)
648 {
649 qry->hasRecursive = stmt->withClause->recursive;
650 qry->cteList = transformWithClause(pstate, stmt->withClause);
651 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
652 }
653
654 /* set up range table with just the result rel */
655 qry->resultRelation = setTargetTable(pstate, stmt->relation,
656 stmt->relation->inh,
657 true,
658 ACL_DELETE);
659 nsitem = pstate->p_target_nsitem;
660
661 /* there's no DISTINCT in DELETE */
662 qry->distinctClause = NIL;
663
664 /* subqueries in USING cannot access the result relation */
665 nsitem->p_lateral_only = true;
666 nsitem->p_lateral_ok = false;
667
668 /*
669 * The USING clause is non-standard SQL syntax, and is equivalent in
670 * functionality to the FROM list that can be specified for UPDATE. The
671 * USING keyword is used rather than FROM because FROM is already a
672 * keyword in the DELETE syntax.
673 */
674 transformFromClause(pstate, stmt->usingClause);
675
676 /* remaining clauses can reference the result relation normally */
677 nsitem->p_lateral_only = false;
678 nsitem->p_lateral_ok = true;
679
680 qual = transformWhereClause(pstate, stmt->whereClause,
681 EXPR_KIND_WHERE, "WHERE");
682
683 transformReturningClause(pstate, qry, stmt->returningClause,
685
686 /* done building the range table and jointree */
687 qry->rtable = pstate->p_rtable;
688 qry->rteperminfos = pstate->p_rteperminfos;
689 qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
690
691 qry->hasSubLinks = pstate->p_hasSubLinks;
692 qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
693 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
694 qry->hasAggs = pstate->p_hasAggs;
695
696 assign_query_collations(pstate, qry);
697
698 /* this must be done after collations, for reliable comparison of exprs */
699 if (pstate->p_hasAggs)
700 parseCheckAggregates(pstate, qry);
701
702 return qry;
703}
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:336
@ CMD_DELETE
Definition: nodes.h:274
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1085
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:112
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:178
void assign_query_collations(ParseState *pstate, Query *query)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:110
@ EXPR_KIND_WHERE
Definition: parse_node.h:46
@ EXPR_KIND_RETURNING
Definition: parse_node.h:64
#define ACL_DELETE
Definition: parsenodes.h:79
void transformReturningClause(ParseState *pstate, Query *qry, ReturningClause *returningClause, ParseExprKind exprKind)
Definition: analyze.c:2730
bool p_hasTargetSRFs
Definition: parse_node.h:244
bool p_hasWindowFuncs
Definition: parse_node.h:243
bool p_hasModifyingCTE
Definition: parse_node.h:246
List * p_rteperminfos
Definition: parse_node.h:213
bool p_hasSubLinks
Definition: parse_node.h:245
List * p_joinlist
Definition: parse_node.h:217
bool p_hasAggs
Definition: parse_node.h:242
FromExpr * jointree
Definition: parsenodes.h:177
List * cteList
Definition: parsenodes.h:168
List * rtable
Definition: parsenodes.h:170

References ACL_DELETE, assign_query_collations(), CMD_DELETE, Query::commandType, Query::cteList, Query::distinctClause, EXPR_KIND_RETURNING, EXPR_KIND_WHERE, Query::jointree, makeFromExpr(), makeNode, NIL, ParseState::p_hasAggs, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_hasTargetSRFs, ParseState::p_hasWindowFuncs, ParseState::p_joinlist, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseState::p_rtable, ParseState::p_rteperminfos, ParseState::p_target_nsitem, parseCheckAggregates(), Query::rtable, setTargetTable(), stmt, transformFromClause(), transformReturningClause(), transformWhereClause(), and transformWithClause().

Referenced by transformStmt().

◆ transformExplainStmt()

static Query * transformExplainStmt ( ParseState pstate,
ExplainStmt stmt 
)
static

Definition at line 3194 of file analyze.c.

3195{
3196 Query *result;
3197 bool generic_plan = false;
3198 Oid *paramTypes = NULL;
3199 int numParams = 0;
3200
3201 /*
3202 * If we have no external source of parameter definitions, and the
3203 * GENERIC_PLAN option is specified, then accept variable parameter
3204 * definitions (similarly to PREPARE, for example).
3205 */
3206 if (pstate->p_paramref_hook == NULL)
3207 {
3208 ListCell *lc;
3209
3210 foreach(lc, stmt->options)
3211 {
3212 DefElem *opt = (DefElem *) lfirst(lc);
3213
3214 if (strcmp(opt->defname, "generic_plan") == 0)
3215 generic_plan = defGetBoolean(opt);
3216 /* don't "break", as we want the last value */
3217 }
3218 if (generic_plan)
3219 setup_parse_variable_parameters(pstate, &paramTypes, &numParams);
3220 }
3221
3222 /* transform contained query, allowing SELECT INTO */
3223 stmt->query = (Node *) transformOptionalSelectInto(pstate, stmt->query);
3224
3225 /* make sure all is well with parameter types */
3226 if (generic_plan)
3227 check_variable_parameters(pstate, (Query *) stmt->query);
3228
3229 /* represent the command as a utility Query */
3230 result = makeNode(Query);
3231 result->commandType = CMD_UTILITY;
3232 result->utilityStmt = (Node *) stmt;
3233
3234 return result;
3235}
bool defGetBoolean(DefElem *def)
Definition: define.c:94
static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
Definition: analyze.c:357
char * defname
Definition: parsenodes.h:826
ParseParamRefHook p_paramref_hook
Definition: parse_node.h:256

References check_variable_parameters(), CMD_UTILITY, Query::commandType, defGetBoolean(), DefElem::defname, lfirst, makeNode, ParseState::p_paramref_hook, setup_parse_variable_parameters(), stmt, transformOptionalSelectInto(), and Query::utilityStmt.

Referenced by transformStmt().

◆ transformInsertRow()

List * transformInsertRow ( ParseState pstate,
List exprlist,
List stmtcols,
List icolumns,
List attrnos,
bool  strip_indirection 
)

Definition at line 1137 of file analyze.c.

1140{
1141 List *result;
1142 ListCell *lc;
1143 ListCell *icols;
1144 ListCell *attnos;
1145
1146 /*
1147 * Check length of expr list. It must not have more expressions than
1148 * there are target columns. We allow fewer, but only if no explicit
1149 * columns list was given (the remaining columns are implicitly
1150 * defaulted). Note we must check this *after* transformation because
1151 * that could expand '*' into multiple items.
1152 */
1153 if (list_length(exprlist) > list_length(icolumns))
1154 ereport(ERROR,
1155 (errcode(ERRCODE_SYNTAX_ERROR),
1156 errmsg("INSERT has more expressions than target columns"),
1157 parser_errposition(pstate,
1158 exprLocation(list_nth(exprlist,
1159 list_length(icolumns))))));
1160 if (stmtcols != NIL &&
1161 list_length(exprlist) < list_length(icolumns))
1162 {
1163 /*
1164 * We can get here for cases like INSERT ... SELECT (a,b,c) FROM ...
1165 * where the user accidentally created a RowExpr instead of separate
1166 * columns. Add a suitable hint if that seems to be the problem,
1167 * because the main error message is quite misleading for this case.
1168 * (If there's no stmtcols, you'll get something about data type
1169 * mismatch, which is less misleading so we don't worry about giving a
1170 * hint in that case.)
1171 */
1172 ereport(ERROR,
1173 (errcode(ERRCODE_SYNTAX_ERROR),
1174 errmsg("INSERT has more target columns than expressions"),
1175 ((list_length(exprlist) == 1 &&
1176 count_rowexpr_columns(pstate, linitial(exprlist)) ==
1177 list_length(icolumns)) ?
1178 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),
1179 parser_errposition(pstate,
1180 exprLocation(list_nth(icolumns,
1181 list_length(exprlist))))));
1182 }
1183
1184 /*
1185 * Prepare columns for assignment to target table.
1186 */
1187 result = NIL;
1188 forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
1189 {
1190 Expr *expr = (Expr *) lfirst(lc);
1191 ResTarget *col = lfirst_node(ResTarget, icols);
1192 int attno = lfirst_int(attnos);
1193
1194 expr = transformAssignedExpr(pstate, expr,
1196 col->name,
1197 attno,
1198 col->indirection,
1199 col->location);
1200
1201 if (strip_indirection)
1202 {
1203 /*
1204 * We need to remove top-level FieldStores and SubscriptingRefs,
1205 * as well as any CoerceToDomain appearing above one of those ---
1206 * but not a CoerceToDomain that isn't above one of those.
1207 */
1208 while (expr)
1209 {
1210 Expr *subexpr = expr;
1211
1212 while (IsA(subexpr, CoerceToDomain))
1213 {
1214 subexpr = ((CoerceToDomain *) subexpr)->arg;
1215 }
1216 if (IsA(subexpr, FieldStore))
1217 {
1218 FieldStore *fstore = (FieldStore *) subexpr;
1219
1220 expr = (Expr *) linitial(fstore->newvals);
1221 }
1222 else if (IsA(subexpr, SubscriptingRef))
1223 {
1224 SubscriptingRef *sbsref = (SubscriptingRef *) subexpr;
1225
1226 if (sbsref->refassgnexpr == NULL)
1227 break;
1228
1229 expr = sbsref->refassgnexpr;
1230 }
1231 else
1232 break;
1233 }
1234 }
1235
1236 result = lappend(result, expr);
1237 }
1238
1239 return result;
1240}
int errhint(const char *fmt,...)
Definition: elog.c:1318
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1388
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
@ EXPR_KIND_INSERT_TARGET
Definition: parse_node.h:55
Expr * transformAssignedExpr(ParseState *pstate, Expr *expr, ParseExprKind exprKind, const char *colname, int attrno, List *indirection, int location)
Definition: parse_target.c:455
static int count_rowexpr_columns(ParseState *pstate, Node *expr)
Definition: analyze.c:1424
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define lfirst_int(lc)
Definition: pg_list.h:173
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:563
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
List * newvals
Definition: primnodes.h:1177
ParseLoc location
Definition: parsenodes.h:531
List * indirection
Definition: parsenodes.h:529
char * name
Definition: parsenodes.h:528
Expr * refassgnexpr
Definition: primnodes.h:720

References count_rowexpr_columns(), ereport, errcode(), errhint(), errmsg(), ERROR, EXPR_KIND_INSERT_TARGET, exprLocation(), forthree, ResTarget::indirection, IsA, lappend(), lfirst, lfirst_int, lfirst_node, linitial, list_length(), list_nth(), ResTarget::location, ResTarget::name, FieldStore::newvals, NIL, parser_errposition(), SubscriptingRef::refassgnexpr, and transformAssignedExpr().

Referenced by transformInsertStmt(), and transformMergeStmt().

◆ transformInsertStmt()

static Query * transformInsertStmt ( ParseState pstate,
InsertStmt stmt 
)
static

Definition at line 710 of file analyze.c.

711{
712 Query *qry = makeNode(Query);
713 SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt;
714 List *exprList = NIL;
715 bool isGeneralSelect;
716 List *sub_rtable;
717 List *sub_rteperminfos;
718 List *sub_namespace;
719 List *icolumns;
720 List *attrnos;
721 ParseNamespaceItem *nsitem;
722 RTEPermissionInfo *perminfo;
723 ListCell *icols;
724 ListCell *attnos;
725 ListCell *lc;
726 bool isOnConflictUpdate;
727 AclMode targetPerms;
728
729 /* There can't be any outer WITH to worry about */
730 Assert(pstate->p_ctenamespace == NIL);
731
732 qry->commandType = CMD_INSERT;
733 pstate->p_is_insert = true;
734
735 /* process the WITH clause independently of all else */
736 if (stmt->withClause)
737 {
738 qry->hasRecursive = stmt->withClause->recursive;
739 qry->cteList = transformWithClause(pstate, stmt->withClause);
740 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
741 }
742
743 qry->override = stmt->override;
744
745 isOnConflictUpdate = (stmt->onConflictClause &&
746 stmt->onConflictClause->action == ONCONFLICT_UPDATE);
747
748 /*
749 * We have three cases to deal with: DEFAULT VALUES (selectStmt == NULL),
750 * VALUES list, or general SELECT input. We special-case VALUES, both for
751 * efficiency and so we can handle DEFAULT specifications.
752 *
753 * The grammar allows attaching ORDER BY, LIMIT, FOR UPDATE, or WITH to a
754 * VALUES clause. If we have any of those, treat it as a general SELECT;
755 * so it will work, but you can't use DEFAULT items together with those.
756 */
757 isGeneralSelect = (selectStmt && (selectStmt->valuesLists == NIL ||
758 selectStmt->sortClause != NIL ||
759 selectStmt->limitOffset != NULL ||
760 selectStmt->limitCount != NULL ||
761 selectStmt->lockingClause != NIL ||
762 selectStmt->withClause != NULL));
763
764 /*
765 * If a non-nil rangetable/namespace was passed in, and we are doing
766 * INSERT/SELECT, arrange to pass the rangetable/rteperminfos/namespace
767 * down to the SELECT. This can only happen if we are inside a CREATE
768 * RULE, and in that case we want the rule's OLD and NEW rtable entries to
769 * appear as part of the SELECT's rtable, not as outer references for it.
770 * (Kluge!) The SELECT's joinlist is not affected however. We must do
771 * this before adding the target table to the INSERT's rtable.
772 */
773 if (isGeneralSelect)
774 {
775 sub_rtable = pstate->p_rtable;
776 pstate->p_rtable = NIL;
777 sub_rteperminfos = pstate->p_rteperminfos;
778 pstate->p_rteperminfos = NIL;
779 sub_namespace = pstate->p_namespace;
780 pstate->p_namespace = NIL;
781 }
782 else
783 {
784 sub_rtable = NIL; /* not used, but keep compiler quiet */
785 sub_rteperminfos = NIL;
786 sub_namespace = NIL;
787 }
788
789 /*
790 * Must get write lock on INSERT target table before scanning SELECT, else
791 * we will grab the wrong kind of initial lock if the target table is also
792 * mentioned in the SELECT part. Note that the target table is not added
793 * to the joinlist or namespace.
794 */
795 targetPerms = ACL_INSERT;
796 if (isOnConflictUpdate)
797 targetPerms |= ACL_UPDATE;
798 qry->resultRelation = setTargetTable(pstate, stmt->relation,
799 false, false, targetPerms);
800
801 /* Validate stmt->cols list, or build default list if no list given */
802 icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
803 Assert(list_length(icolumns) == list_length(attrnos));
804
805 /*
806 * Determine which variant of INSERT we have.
807 */
808 if (selectStmt == NULL)
809 {
810 /*
811 * We have INSERT ... DEFAULT VALUES. We can handle this case by
812 * emitting an empty targetlist --- all columns will be defaulted when
813 * the planner expands the targetlist.
814 */
815 exprList = NIL;
816 }
817 else if (isGeneralSelect)
818 {
819 /*
820 * We make the sub-pstate a child of the outer pstate so that it can
821 * see any Param definitions supplied from above. Since the outer
822 * pstate's rtable and namespace are presently empty, there are no
823 * side-effects of exposing names the sub-SELECT shouldn't be able to
824 * see.
825 */
826 ParseState *sub_pstate = make_parsestate(pstate);
827 Query *selectQuery;
828
829 /*
830 * Process the source SELECT.
831 *
832 * It is important that this be handled just like a standalone SELECT;
833 * otherwise the behavior of SELECT within INSERT might be different
834 * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
835 * bugs of just that nature...)
836 *
837 * The sole exception is that we prevent resolving unknown-type
838 * outputs as TEXT. This does not change the semantics since if the
839 * column type matters semantically, it would have been resolved to
840 * something else anyway. Doing this lets us resolve such outputs as
841 * the target column's type, which we handle below.
842 */
843 sub_pstate->p_rtable = sub_rtable;
844 sub_pstate->p_rteperminfos = sub_rteperminfos;
845 sub_pstate->p_joinexprs = NIL; /* sub_rtable has no joins */
846 sub_pstate->p_nullingrels = NIL;
847 sub_pstate->p_namespace = sub_namespace;
848 sub_pstate->p_resolve_unknowns = false;
849
850 selectQuery = transformStmt(sub_pstate, stmt->selectStmt);
851
852 free_parsestate(sub_pstate);
853
854 /* The grammar should have produced a SELECT */
855 if (!IsA(selectQuery, Query) ||
856 selectQuery->commandType != CMD_SELECT)
857 elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT");
858
859 /*
860 * Make the source be a subquery in the INSERT's rangetable, and add
861 * it to the INSERT's joinlist (but not the namespace).
862 */
863 nsitem = addRangeTableEntryForSubquery(pstate,
864 selectQuery,
865 makeAlias("*SELECT*", NIL),
866 false,
867 false);
868 addNSItemToQuery(pstate, nsitem, true, false, false);
869
870 /*----------
871 * Generate an expression list for the INSERT that selects all the
872 * non-resjunk columns from the subquery. (INSERT's tlist must be
873 * separate from the subquery's tlist because we may add columns,
874 * insert datatype coercions, etc.)
875 *
876 * HACK: unknown-type constants and params in the SELECT's targetlist
877 * are copied up as-is rather than being referenced as subquery
878 * outputs. This is to ensure that when we try to coerce them to
879 * the target column's datatype, the right things happen (see
880 * special cases in coerce_type). Otherwise, this fails:
881 * INSERT INTO foo SELECT 'bar', ... FROM baz
882 *----------
883 */
884 exprList = NIL;
885 foreach(lc, selectQuery->targetList)
886 {
887 TargetEntry *tle = (TargetEntry *) lfirst(lc);
888 Expr *expr;
889
890 if (tle->resjunk)
891 continue;
892 if (tle->expr &&
893 (IsA(tle->expr, Const) || IsA(tle->expr, Param)) &&
894 exprType((Node *) tle->expr) == UNKNOWNOID)
895 expr = tle->expr;
896 else
897 {
898 Var *var = makeVarFromTargetEntry(nsitem->p_rtindex, tle);
899
900 var->location = exprLocation((Node *) tle->expr);
901 expr = (Expr *) var;
902 }
903 exprList = lappend(exprList, expr);
904 }
905
906 /* Prepare row for assignment to target table */
907 exprList = transformInsertRow(pstate, exprList,
908 stmt->cols,
909 icolumns, attrnos,
910 false);
911 }
912 else if (list_length(selectStmt->valuesLists) > 1)
913 {
914 /*
915 * Process INSERT ... VALUES with multiple VALUES sublists. We
916 * generate a VALUES RTE holding the transformed expression lists, and
917 * build up a targetlist containing Vars that reference the VALUES
918 * RTE.
919 */
920 List *exprsLists = NIL;
921 List *coltypes = NIL;
922 List *coltypmods = NIL;
923 List *colcollations = NIL;
924 int sublist_length = -1;
925 bool lateral = false;
926
927 Assert(selectStmt->intoClause == NULL);
928
929 foreach(lc, selectStmt->valuesLists)
930 {
931 List *sublist = (List *) lfirst(lc);
932
933 /*
934 * Do basic expression transformation (same as a ROW() expr, but
935 * allow SetToDefault at top level)
936 */
937 sublist = transformExpressionList(pstate, sublist,
938 EXPR_KIND_VALUES, true);
939
940 /*
941 * All the sublists must be the same length, *after*
942 * transformation (which might expand '*' into multiple items).
943 * The VALUES RTE can't handle anything different.
944 */
945 if (sublist_length < 0)
946 {
947 /* Remember post-transformation length of first sublist */
948 sublist_length = list_length(sublist);
949 }
950 else if (sublist_length != list_length(sublist))
951 {
953 (errcode(ERRCODE_SYNTAX_ERROR),
954 errmsg("VALUES lists must all be the same length"),
955 parser_errposition(pstate,
956 exprLocation((Node *) sublist))));
957 }
958
959 /*
960 * Prepare row for assignment to target table. We process any
961 * indirection on the target column specs normally but then strip
962 * off the resulting field/array assignment nodes, since we don't
963 * want the parsed statement to contain copies of those in each
964 * VALUES row. (It's annoying to have to transform the
965 * indirection specs over and over like this, but avoiding it
966 * would take some really messy refactoring of
967 * transformAssignmentIndirection.)
968 */
969 sublist = transformInsertRow(pstate, sublist,
970 stmt->cols,
971 icolumns, attrnos,
972 true);
973
974 /*
975 * We must assign collations now because assign_query_collations
976 * doesn't process rangetable entries. We just assign all the
977 * collations independently in each row, and don't worry about
978 * whether they are consistent vertically. The outer INSERT query
979 * isn't going to care about the collations of the VALUES columns,
980 * so it's not worth the effort to identify a common collation for
981 * each one here. (But note this does have one user-visible
982 * consequence: INSERT ... VALUES won't complain about conflicting
983 * explicit COLLATEs in a column, whereas the same VALUES
984 * construct in another context would complain.)
985 */
986 assign_list_collations(pstate, sublist);
987
988 exprsLists = lappend(exprsLists, sublist);
989 }
990
991 /*
992 * Construct column type/typmod/collation lists for the VALUES RTE.
993 * Every expression in each column has been coerced to the type/typmod
994 * of the corresponding target column or subfield, so it's sufficient
995 * to look at the exprType/exprTypmod of the first row. We don't care
996 * about the collation labeling, so just fill in InvalidOid for that.
997 */
998 foreach(lc, (List *) linitial(exprsLists))
999 {
1000 Node *val = (Node *) lfirst(lc);
1001
1002 coltypes = lappend_oid(coltypes, exprType(val));
1003 coltypmods = lappend_int(coltypmods, exprTypmod(val));
1004 colcollations = lappend_oid(colcollations, InvalidOid);
1005 }
1006
1007 /*
1008 * Ordinarily there can't be any current-level Vars in the expression
1009 * lists, because the namespace was empty ... but if we're inside
1010 * CREATE RULE, then NEW/OLD references might appear. In that case we
1011 * have to mark the VALUES RTE as LATERAL.
1012 */
1013 if (list_length(pstate->p_rtable) != 1 &&
1014 contain_vars_of_level((Node *) exprsLists, 0))
1015 lateral = true;
1016
1017 /*
1018 * Generate the VALUES RTE
1019 */
1020 nsitem = addRangeTableEntryForValues(pstate, exprsLists,
1021 coltypes, coltypmods, colcollations,
1022 NULL, lateral, true);
1023 addNSItemToQuery(pstate, nsitem, true, false, false);
1024
1025 /*
1026 * Generate list of Vars referencing the RTE
1027 */
1028 exprList = expandNSItemVars(pstate, nsitem, 0, -1, NULL);
1029
1030 /*
1031 * Re-apply any indirection on the target column specs to the Vars
1032 */
1033 exprList = transformInsertRow(pstate, exprList,
1034 stmt->cols,
1035 icolumns, attrnos,
1036 false);
1037 }
1038 else
1039 {
1040 /*
1041 * Process INSERT ... VALUES with a single VALUES sublist. We treat
1042 * this case separately for efficiency. The sublist is just computed
1043 * directly as the Query's targetlist, with no VALUES RTE. So it
1044 * works just like a SELECT without any FROM.
1045 */
1046 List *valuesLists = selectStmt->valuesLists;
1047
1048 Assert(list_length(valuesLists) == 1);
1049 Assert(selectStmt->intoClause == NULL);
1050
1051 /*
1052 * Do basic expression transformation (same as a ROW() expr, but allow
1053 * SetToDefault at top level)
1054 */
1055 exprList = transformExpressionList(pstate,
1056 (List *) linitial(valuesLists),
1058 true);
1059
1060 /* Prepare row for assignment to target table */
1061 exprList = transformInsertRow(pstate, exprList,
1062 stmt->cols,
1063 icolumns, attrnos,
1064 false);
1065 }
1066
1067 /*
1068 * Generate query's target list using the computed list of expressions.
1069 * Also, mark all the target columns as needing insert permissions.
1070 */
1071 perminfo = pstate->p_target_nsitem->p_perminfo;
1072 qry->targetList = NIL;
1073 Assert(list_length(exprList) <= list_length(icolumns));
1074 forthree(lc, exprList, icols, icolumns, attnos, attrnos)
1075 {
1076 Expr *expr = (Expr *) lfirst(lc);
1077 ResTarget *col = lfirst_node(ResTarget, icols);
1078 AttrNumber attr_num = (AttrNumber) lfirst_int(attnos);
1079 TargetEntry *tle;
1080
1081 tle = makeTargetEntry(expr,
1082 attr_num,
1083 col->name,
1084 false);
1085 qry->targetList = lappend(qry->targetList, tle);
1086
1087 perminfo->insertedCols = bms_add_member(perminfo->insertedCols,
1089 }
1090
1091 /*
1092 * If we have any clauses yet to process, set the query namespace to
1093 * contain only the target relation, removing any entries added in a
1094 * sub-SELECT or VALUES list.
1095 */
1096 if (stmt->onConflictClause || stmt->returningClause)
1097 {
1098 pstate->p_namespace = NIL;
1099 addNSItemToQuery(pstate, pstate->p_target_nsitem,
1100 false, true, true);
1101 }
1102
1103 /* Process ON CONFLICT, if any. */
1104 if (stmt->onConflictClause)
1106 stmt->onConflictClause);
1107
1108 /* Process RETURNING, if any. */
1109 if (stmt->returningClause)
1110 transformReturningClause(pstate, qry, stmt->returningClause,
1112
1113 /* done building the range table and jointree */
1114 qry->rtable = pstate->p_rtable;
1115 qry->rteperminfos = pstate->p_rteperminfos;
1116 qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1117
1118 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1119 qry->hasSubLinks = pstate->p_hasSubLinks;
1120
1121 assign_query_collations(pstate, qry);
1122
1123 return qry;
1124}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
long val
Definition: informix.c:689
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:107
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
@ ONCONFLICT_UPDATE
Definition: nodes.h:426
@ CMD_INSERT
Definition: nodes.h:273
void assign_list_collations(ParseState *pstate, List *exprs)
@ EXPR_KIND_VALUES
Definition: parse_node.h:66
@ EXPR_KIND_VALUES_SINGLE
Definition: parse_node.h:67
List * expandNSItemVars(ParseState *pstate, ParseNamespaceItem *nsitem, int sublevels_up, int location, List **colnames)
ParseNamespaceItem * addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, bool lateral, bool inFromCl)
ParseNamespaceItem * addRangeTableEntryForValues(ParseState *pstate, List *exprs, List *coltypes, List *coltypmods, List *colcollations, Alias *alias, bool lateral, bool inFromCl)
List * transformExpressionList(ParseState *pstate, List *exprlist, ParseExprKind exprKind, bool allowDefault)
Definition: parse_target.c:220
List * checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_UPDATE
Definition: parsenodes.h:78
static OnConflictExpr * transformOnConflictClause(ParseState *pstate, OnConflictClause *onConflictClause)
Definition: analyze.c:1247
List * transformInsertRow(ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
Definition: analyze.c:1137
List * p_ctenamespace
Definition: parse_node.h:222
List * p_nullingrels
Definition: parse_node.h:216
List * p_namespace
Definition: parse_node.h:219
bool p_is_insert
Definition: parse_node.h:228
List * p_joinexprs
Definition: parse_node.h:215
OnConflictExpr * onConflict
Definition: parsenodes.h:198
List * sortClause
Definition: parsenodes.h:2205
IntoClause * intoClause
Definition: parsenodes.h:2182
Node * limitOffset
Definition: parsenodes.h:2206
List * lockingClause
Definition: parsenodes.h:2209
Node * limitCount
Definition: parsenodes.h:2207
List * valuesLists
Definition: parsenodes.h:2199
WithClause * withClause
Definition: parsenodes.h:2210
ParseLoc location
Definition: primnodes.h:310
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:444

References ACL_INSERT, ACL_UPDATE, addNSItemToQuery(), addRangeTableEntryForSubquery(), Assert(), checkInsertTargets(), CMD_INSERT, CMD_SELECT, Query::commandType, Query::cteList, elog, ERROR, TargetEntry::expr, exprLocation(), exprType(), free_parsestate(), IsA, lappend(), lfirst, SelectStmt::limitCount, SelectStmt::limitOffset, list_length(), Var::location, SelectStmt::lockingClause, make_parsestate(), makeAlias(), makeNode, makeVarFromTargetEntry(), NIL, ONCONFLICT_UPDATE, ParseState::p_ctenamespace, ParseState::p_hasModifyingCTE, ParseState::p_is_insert, ParseState::p_joinexprs, ParseState::p_namespace, ParseState::p_nullingrels, ParseState::p_resolve_unknowns, ParseState::p_rtable, ParseState::p_rteperminfos, setTargetTable(), SelectStmt::sortClause, stmt, Query::targetList, transformInsertRow(), transformStmt(), transformWithClause(), SelectStmt::valuesLists, and SelectStmt::withClause.

Referenced by transformStmt().

◆ transformLockingClause()

static void transformLockingClause ( ParseState pstate,
Query qry,
LockingClause lc,
bool  pushedDown 
)
static

Definition at line 3535 of file analyze.c.

3537{
3538 List *lockedRels = lc->lockedRels;
3539 ListCell *l;
3540 ListCell *rt;
3541 Index i;
3542 LockingClause *allrels;
3543
3544 CheckSelectLocking(qry, lc->strength);
3545
3546 /* make a clause we can pass down to subqueries to select all rels */
3547 allrels = makeNode(LockingClause);
3548 allrels->lockedRels = NIL; /* indicates all rels */
3549 allrels->strength = lc->strength;
3550 allrels->waitPolicy = lc->waitPolicy;
3551
3552 if (lockedRels == NIL)
3553 {
3554 /*
3555 * Lock all regular tables used in query and its subqueries. We
3556 * examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD
3557 * in rules. This is a bit of an abuse of a mostly-obsolete flag, but
3558 * it's convenient. We can't rely on the namespace mechanism that has
3559 * largely replaced inFromCl, since for example we need to lock
3560 * base-relation RTEs even if they are masked by upper joins.
3561 */
3562 i = 0;
3563 foreach(rt, qry->rtable)
3564 {
3565 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3566
3567 ++i;
3568 if (!rte->inFromCl)
3569 continue;
3570 switch (rte->rtekind)
3571 {
3572 case RTE_RELATION:
3573 {
3574 RTEPermissionInfo *perminfo;
3575
3576 applyLockingClause(qry, i,
3577 lc->strength,
3578 lc->waitPolicy,
3579 pushedDown);
3580 perminfo = getRTEPermissionInfo(qry->rteperminfos, rte);
3582 }
3583 break;
3584 case RTE_SUBQUERY:
3585 applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3586 pushedDown);
3587
3588 /*
3589 * FOR UPDATE/SHARE of subquery is propagated to all of
3590 * subquery's rels, too. We could do this later (based on
3591 * the marking of the subquery RTE) but it is convenient
3592 * to have local knowledge in each query level about which
3593 * rels need to be opened with RowShareLock.
3594 */
3595 transformLockingClause(pstate, rte->subquery,
3596 allrels, true);
3597 break;
3598 default:
3599 /* ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE RTEs */
3600 break;
3601 }
3602 }
3603 }
3604 else
3605 {
3606 /*
3607 * Lock just the named tables. As above, we allow locking any base
3608 * relation regardless of alias-visibility rules, so we need to
3609 * examine inFromCl to exclude OLD/NEW.
3610 */
3611 foreach(l, lockedRels)
3612 {
3613 RangeVar *thisrel = (RangeVar *) lfirst(l);
3614
3615 /* For simplicity we insist on unqualified alias names here */
3616 if (thisrel->catalogname || thisrel->schemaname)
3617 ereport(ERROR,
3618 (errcode(ERRCODE_SYNTAX_ERROR),
3619 /*------
3620 translator: %s is a SQL row locking clause such as FOR UPDATE */
3621 errmsg("%s must specify unqualified relation names",
3622 LCS_asString(lc->strength)),
3623 parser_errposition(pstate, thisrel->location)));
3624
3625 i = 0;
3626 foreach(rt, qry->rtable)
3627 {
3628 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3629 char *rtename = rte->eref->aliasname;
3630
3631 ++i;
3632 if (!rte->inFromCl)
3633 continue;
3634
3635 /*
3636 * A join RTE without an alias is not visible as a relation
3637 * name and needs to be skipped (otherwise it might hide a
3638 * base relation with the same name), except if it has a USING
3639 * alias, which *is* visible.
3640 *
3641 * Subquery and values RTEs without aliases are never visible
3642 * as relation names and must always be skipped.
3643 */
3644 if (rte->alias == NULL)
3645 {
3646 if (rte->rtekind == RTE_JOIN)
3647 {
3648 if (rte->join_using_alias == NULL)
3649 continue;
3650 rtename = rte->join_using_alias->aliasname;
3651 }
3652 else if (rte->rtekind == RTE_SUBQUERY ||
3653 rte->rtekind == RTE_VALUES)
3654 continue;
3655 }
3656
3657 if (strcmp(rtename, thisrel->relname) == 0)
3658 {
3659 switch (rte->rtekind)
3660 {
3661 case RTE_RELATION:
3662 {
3663 RTEPermissionInfo *perminfo;
3664
3665 applyLockingClause(qry, i,
3666 lc->strength,
3667 lc->waitPolicy,
3668 pushedDown);
3669 perminfo = getRTEPermissionInfo(qry->rteperminfos, rte);
3671 }
3672 break;
3673 case RTE_SUBQUERY:
3674 applyLockingClause(qry, i, lc->strength,
3675 lc->waitPolicy, pushedDown);
3676 /* see comment above */
3677 transformLockingClause(pstate, rte->subquery,
3678 allrels, true);
3679 break;
3680 case RTE_JOIN:
3681 ereport(ERROR,
3682 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3683 /*------
3684 translator: %s is a SQL row locking clause such as FOR UPDATE */
3685 errmsg("%s cannot be applied to a join",
3686 LCS_asString(lc->strength)),
3687 parser_errposition(pstate, thisrel->location)));
3688 break;
3689 case RTE_FUNCTION:
3690 ereport(ERROR,
3691 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3692 /*------
3693 translator: %s is a SQL row locking clause such as FOR UPDATE */
3694 errmsg("%s cannot be applied to a function",
3695 LCS_asString(lc->strength)),
3696 parser_errposition(pstate, thisrel->location)));
3697 break;
3698 case RTE_TABLEFUNC:
3699 ereport(ERROR,
3700 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3701 /*------
3702 translator: %s is a SQL row locking clause such as FOR UPDATE */
3703 errmsg("%s cannot be applied to a table function",
3704 LCS_asString(lc->strength)),
3705 parser_errposition(pstate, thisrel->location)));
3706 break;
3707 case RTE_VALUES:
3708 ereport(ERROR,
3709 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3710 /*------
3711 translator: %s is a SQL row locking clause such as FOR UPDATE */
3712 errmsg("%s cannot be applied to VALUES",
3713 LCS_asString(lc->strength)),
3714 parser_errposition(pstate, thisrel->location)));
3715 break;
3716 case RTE_CTE:
3717 ereport(ERROR,
3718 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3719 /*------
3720 translator: %s is a SQL row locking clause such as FOR UPDATE */
3721 errmsg("%s cannot be applied to a WITH query",
3722 LCS_asString(lc->strength)),
3723 parser_errposition(pstate, thisrel->location)));
3724 break;
3726 ereport(ERROR,
3727 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3728 /*------
3729 translator: %s is a SQL row locking clause such as FOR UPDATE */
3730 errmsg("%s cannot be applied to a named tuplestore",
3731 LCS_asString(lc->strength)),
3732 parser_errposition(pstate, thisrel->location)));
3733 break;
3734
3735 /* Shouldn't be possible to see RTE_RESULT here */
3736
3737 default:
3738 elog(ERROR, "unrecognized RTE type: %d",
3739 (int) rte->rtekind);
3740 break;
3741 }
3742 break; /* out of foreach loop */
3743 }
3744 }
3745 if (rt == NULL)
3746 ereport(ERROR,
3748 /*------
3749 translator: %s is a SQL row locking clause such as FOR UPDATE */
3750 errmsg("relation \"%s\" in %s clause not found in FROM clause",
3751 thisrel->relname,
3752 LCS_asString(lc->strength)),
3753 parser_errposition(pstate, thisrel->location)));
3754 }
3755 }
3756}
unsigned int Index
Definition: c.h:585
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_JOIN
Definition: parsenodes.h:1028
@ RTE_CTE
Definition: parsenodes.h:1032
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1033
@ RTE_VALUES
Definition: parsenodes.h:1031
@ RTE_FUNCTION
Definition: parsenodes.h:1029
@ RTE_TABLEFUNC
Definition: parsenodes.h:1030
@ RTE_RELATION
Definition: parsenodes.h:1026
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:94
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:3535
void CheckSelectLocking(Query *qry, LockClauseStrength strength)
Definition: analyze.c:3471
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3762
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
List * lockedRels
Definition: parsenodes.h:845
LockClauseStrength strength
Definition: parsenodes.h:846
LockWaitPolicy waitPolicy
Definition: parsenodes.h:847
AclMode requiredPerms
Definition: parsenodes.h:1305
char * relname
Definition: primnodes.h:83
char * catalogname
Definition: primnodes.h:77
ParseLoc location
Definition: primnodes.h:95
char * schemaname
Definition: primnodes.h:80

References ACL_SELECT_FOR_UPDATE, applyLockingClause(), RangeVar::catalogname, CheckSelectLocking(), elog, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, getRTEPermissionInfo(), i, LCS_asString(), lfirst, RangeVar::location, LockingClause::lockedRels, makeNode, NIL, parser_errposition(), RangeVar::relname, RTEPermissionInfo::requiredPerms, Query::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeVar::schemaname, LockingClause::strength, RangeTblEntry::subquery, transformLockingClause(), and LockingClause::waitPolicy.

Referenced by transformLockingClause(), transformPLAssignStmt(), transformSelectStmt(), and transformSetOperationStmt().

◆ transformOnConflictClause()

static OnConflictExpr * transformOnConflictClause ( ParseState pstate,
OnConflictClause onConflictClause 
)
static

Definition at line 1247 of file analyze.c.

1249{
1250 ParseNamespaceItem *exclNSItem = NULL;
1251 List *arbiterElems;
1252 Node *arbiterWhere;
1253 Oid arbiterConstraint;
1254 List *onConflictSet = NIL;
1255 Node *onConflictWhere = NULL;
1256 int exclRelIndex = 0;
1257 List *exclRelTlist = NIL;
1258 OnConflictExpr *result;
1259
1260 /*
1261 * If this is ON CONFLICT ... UPDATE, first create the range table entry
1262 * for the EXCLUDED pseudo relation, so that that will be present while
1263 * processing arbiter expressions. (You can't actually reference it from
1264 * there, but this provides a useful error message if you try.)
1265 */
1266 if (onConflictClause->action == ONCONFLICT_UPDATE)
1267 {
1268 Relation targetrel = pstate->p_target_relation;
1269 RangeTblEntry *exclRte;
1270
1271 exclNSItem = addRangeTableEntryForRelation(pstate,
1272 targetrel,
1274 makeAlias("excluded", NIL),
1275 false, false);
1276 exclRte = exclNSItem->p_rte;
1277 exclRelIndex = exclNSItem->p_rtindex;
1278
1279 /*
1280 * relkind is set to composite to signal that we're not dealing with
1281 * an actual relation, and no permission checks are required on it.
1282 * (We'll check the actual target relation, instead.)
1283 */
1284 exclRte->relkind = RELKIND_COMPOSITE_TYPE;
1285
1286 /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
1287 exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
1288 exclRelIndex);
1289 }
1290
1291 /* Process the arbiter clause, ON CONFLICT ON (...) */
1292 transformOnConflictArbiter(pstate, onConflictClause, &arbiterElems,
1293 &arbiterWhere, &arbiterConstraint);
1294
1295 /* Process DO UPDATE */
1296 if (onConflictClause->action == ONCONFLICT_UPDATE)
1297 {
1298 /*
1299 * Expressions in the UPDATE targetlist need to be handled like UPDATE
1300 * not INSERT. We don't need to save/restore this because all INSERT
1301 * expressions have been parsed already.
1302 */
1303 pstate->p_is_insert = false;
1304
1305 /*
1306 * Add the EXCLUDED pseudo relation to the query namespace, making it
1307 * available in the UPDATE subexpressions.
1308 */
1309 addNSItemToQuery(pstate, exclNSItem, false, true, true);
1310
1311 /*
1312 * Now transform the UPDATE subexpressions.
1313 */
1314 onConflictSet =
1315 transformUpdateTargetList(pstate, onConflictClause->targetList);
1316
1317 onConflictWhere = transformWhereClause(pstate,
1318 onConflictClause->whereClause,
1319 EXPR_KIND_WHERE, "WHERE");
1320
1321 /*
1322 * Remove the EXCLUDED pseudo relation from the query namespace, since
1323 * it's not supposed to be available in RETURNING. (Maybe someday we
1324 * could allow that, and drop this step.)
1325 */
1326 Assert((ParseNamespaceItem *) llast(pstate->p_namespace) == exclNSItem);
1327 pstate->p_namespace = list_delete_last(pstate->p_namespace);
1328 }
1329
1330 /* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */
1331 result = makeNode(OnConflictExpr);
1332
1333 result->action = onConflictClause->action;
1334 result->arbiterElems = arbiterElems;
1335 result->arbiterWhere = arbiterWhere;
1336 result->constraint = arbiterConstraint;
1337 result->onConflictSet = onConflictSet;
1338 result->onConflictWhere = onConflictWhere;
1339 result->exclRelIndex = exclRelIndex;
1340 result->exclRelTlist = exclRelTlist;
1341
1342 return result;
1343}
List * list_delete_last(List *list)
Definition: list.c:957
#define RowExclusiveLock
Definition: lockdefs.h:38
void transformOnConflictArbiter(ParseState *pstate, OnConflictClause *onConflictClause, List **arbiterExpr, Node **arbiterWhere, Oid *constraint)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
List * transformUpdateTargetList(ParseState *pstate, List *origTlist)
Definition: analyze.c:2615
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1354
#define llast(l)
Definition: pg_list.h:198
OnConflictAction action
Definition: parsenodes.h:1638
List * arbiterElems
Definition: primnodes.h:2356
OnConflictAction action
Definition: primnodes.h:2353
List * onConflictSet
Definition: primnodes.h:2362
List * exclRelTlist
Definition: primnodes.h:2365
Node * onConflictWhere
Definition: primnodes.h:2363
Node * arbiterWhere
Definition: primnodes.h:2358
Relation p_target_relation
Definition: parse_node.h:225

References OnConflictClause::action, OnConflictExpr::action, addNSItemToQuery(), addRangeTableEntryForRelation(), OnConflictExpr::arbiterElems, OnConflictExpr::arbiterWhere, Assert(), BuildOnConflictExcludedTargetlist(), OnConflictExpr::constraint, OnConflictExpr::exclRelIndex, OnConflictExpr::exclRelTlist, EXPR_KIND_WHERE, list_delete_last(), llast, makeAlias(), makeNode, NIL, ONCONFLICT_UPDATE, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, ParseState::p_is_insert, ParseState::p_namespace, ParseNamespaceItem::p_rte, ParseNamespaceItem::p_rtindex, ParseState::p_target_relation, RowExclusiveLock, OnConflictClause::targetList, transformOnConflictArbiter(), transformUpdateTargetList(), transformWhereClause(), and OnConflictClause::whereClause.

◆ transformOptionalSelectInto()

static Query * transformOptionalSelectInto ( ParseState pstate,
Node parseTree 
)
static

Definition at line 357 of file analyze.c.

358{
359 if (IsA(parseTree, SelectStmt))
360 {
361 SelectStmt *stmt = (SelectStmt *) parseTree;
362
363 /* If it's a set-operation tree, drill down to leftmost SelectStmt */
364 while (stmt && stmt->op != SETOP_NONE)
365 stmt = stmt->larg;
366 Assert(stmt && IsA(stmt, SelectStmt) && stmt->larg == NULL);
367
368 if (stmt->intoClause)
369 {
371
372 ctas->query = parseTree;
373 ctas->into = stmt->intoClause;
374 ctas->objtype = OBJECT_TABLE;
375 ctas->is_select_into = true;
376
377 /*
378 * Remove the intoClause from the SelectStmt. This makes it safe
379 * for transformSelectStmt to complain if it finds intoClause set
380 * (implying that the INTO appeared in a disallowed place).
381 */
382 stmt->intoClause = NULL;
383
384 parseTree = (Node *) ctas;
385 }
386 }
387
388 return transformStmt(pstate, parseTree);
389}
@ SETOP_NONE
Definition: parsenodes.h:2167
@ OBJECT_TABLE
Definition: parsenodes.h:2358
IntoClause * into
Definition: parsenodes.h:3988
ObjectType objtype
Definition: parsenodes.h:3989

References Assert(), CreateTableAsStmt::into, CreateTableAsStmt::is_select_into, IsA, makeNode, OBJECT_TABLE, CreateTableAsStmt::objtype, CreateTableAsStmt::query, SETOP_NONE, stmt, and transformStmt().

Referenced by transformExplainStmt(), and transformTopLevelStmt().

◆ transformPLAssignStmt()

static Query * transformPLAssignStmt ( ParseState pstate,
PLAssignStmt stmt 
)
static

Definition at line 2852 of file analyze.c.

2853{
2854 Query *qry = makeNode(Query);
2855 ColumnRef *cref = makeNode(ColumnRef);
2856 List *indirection = stmt->indirection;
2857 int nnames = stmt->nnames;
2858 SelectStmt *sstmt = stmt->val;
2859 Node *target;
2860 Oid targettype;
2861 int32 targettypmod;
2862 Oid targetcollation;
2863 List *tlist;
2864 TargetEntry *tle;
2865 Oid type_id;
2866 Node *qual;
2867 ListCell *l;
2868
2869 /*
2870 * First, construct a ColumnRef for the target variable. If the target
2871 * has more than one dotted name, we have to pull the extra names out of
2872 * the indirection list.
2873 */
2874 cref->fields = list_make1(makeString(stmt->name));
2875 cref->location = stmt->location;
2876 if (nnames > 1)
2877 {
2878 /* avoid munging the raw parsetree */
2879 indirection = list_copy(indirection);
2880 while (--nnames > 0 && indirection != NIL)
2881 {
2882 Node *ind = (Node *) linitial(indirection);
2883
2884 if (!IsA(ind, String))
2885 elog(ERROR, "invalid name count in PLAssignStmt");
2886 cref->fields = lappend(cref->fields, ind);
2887 indirection = list_delete_first(indirection);
2888 }
2889 }
2890
2891 /*
2892 * Transform the target reference. Typically we will get back a Param
2893 * node, but there's no reason to be too picky about its type.
2894 */
2895 target = transformExpr(pstate, (Node *) cref,
2897 targettype = exprType(target);
2898 targettypmod = exprTypmod(target);
2899 targetcollation = exprCollation(target);
2900
2901 /*
2902 * The rest mostly matches transformSelectStmt, except that we needn't
2903 * consider WITH or INTO, and we build a targetlist our own way.
2904 */
2905 qry->commandType = CMD_SELECT;
2906 pstate->p_is_insert = false;
2907
2908 /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
2909 pstate->p_locking_clause = sstmt->lockingClause;
2910
2911 /* make WINDOW info available for window functions, too */
2912 pstate->p_windowdefs = sstmt->windowClause;
2913
2914 /* process the FROM clause */
2915 transformFromClause(pstate, sstmt->fromClause);
2916
2917 /* initially transform the targetlist as if in SELECT */
2918 tlist = transformTargetList(pstate, sstmt->targetList,
2920
2921 /* we should have exactly one targetlist item */
2922 if (list_length(tlist) != 1)
2923 ereport(ERROR,
2924 (errcode(ERRCODE_SYNTAX_ERROR),
2925 errmsg_plural("assignment source returned %d column",
2926 "assignment source returned %d columns",
2927 list_length(tlist),
2928 list_length(tlist))));
2929
2930 tle = linitial_node(TargetEntry, tlist);
2931
2932 /*
2933 * This next bit is similar to transformAssignedExpr; the key difference
2934 * is we use COERCION_PLPGSQL not COERCION_ASSIGNMENT.
2935 */
2936 type_id = exprType((Node *) tle->expr);
2937
2939
2940 if (indirection)
2941 {
2942 tle->expr = (Expr *)
2944 target,
2945 stmt->name,
2946 false,
2947 targettype,
2948 targettypmod,
2949 targetcollation,
2950 indirection,
2951 list_head(indirection),
2952 (Node *) tle->expr,
2954 exprLocation(target));
2955 }
2956 else if (targettype != type_id &&
2957 (targettype == RECORDOID || ISCOMPLEX(targettype)) &&
2958 (type_id == RECORDOID || ISCOMPLEX(type_id)))
2959 {
2960 /*
2961 * Hack: do not let coerce_to_target_type() deal with inconsistent
2962 * composite types. Just pass the expression result through as-is,
2963 * and let the PL/pgSQL executor do the conversion its way. This is
2964 * rather bogus, but it's needed for backwards compatibility.
2965 */
2966 }
2967 else
2968 {
2969 /*
2970 * For normal non-qualified target column, do type checking and
2971 * coercion.
2972 */
2973 Node *orig_expr = (Node *) tle->expr;
2974
2975 tle->expr = (Expr *)
2976 coerce_to_target_type(pstate,
2977 orig_expr, type_id,
2978 targettype, targettypmod,
2981 -1);
2982 /* With COERCION_PLPGSQL, this error is probably unreachable */
2983 if (tle->expr == NULL)
2984 ereport(ERROR,
2985 (errcode(ERRCODE_DATATYPE_MISMATCH),
2986 errmsg("variable \"%s\" is of type %s"
2987 " but expression is of type %s",
2988 stmt->name,
2989 format_type_be(targettype),
2990 format_type_be(type_id)),
2991 errhint("You will need to rewrite or cast the expression."),
2992 parser_errposition(pstate, exprLocation(orig_expr))));
2993 }
2994
2995 pstate->p_expr_kind = EXPR_KIND_NONE;
2996
2997 qry->targetList = list_make1(tle);
2998
2999 /* transform WHERE */
3000 qual = transformWhereClause(pstate, sstmt->whereClause,
3001 EXPR_KIND_WHERE, "WHERE");
3002
3003 /* initial processing of HAVING clause is much like WHERE clause */
3004 qry->havingQual = transformWhereClause(pstate, sstmt->havingClause,
3005 EXPR_KIND_HAVING, "HAVING");
3006
3007 /*
3008 * Transform sorting/grouping stuff. Do ORDER BY first because both
3009 * transformGroupClause and transformDistinctClause need the results. Note
3010 * that these functions can also change the targetList, so it's passed to
3011 * them by reference.
3012 */
3013 qry->sortClause = transformSortClause(pstate,
3014 sstmt->sortClause,
3015 &qry->targetList,
3017 false /* allow SQL92 rules */ );
3018
3019 qry->groupClause = transformGroupClause(pstate,
3020 sstmt->groupClause,
3021 &qry->groupingSets,
3022 &qry->targetList,
3023 qry->sortClause,
3025 false /* allow SQL92 rules */ );
3026
3027 if (sstmt->distinctClause == NIL)
3028 {
3029 qry->distinctClause = NIL;
3030 qry->hasDistinctOn = false;
3031 }
3032 else if (linitial(sstmt->distinctClause) == NULL)
3033 {
3034 /* We had SELECT DISTINCT */
3036 &qry->targetList,
3037 qry->sortClause,
3038 false);
3039 qry->hasDistinctOn = false;
3040 }
3041 else
3042 {
3043 /* We had SELECT DISTINCT ON */
3045 sstmt->distinctClause,
3046 &qry->targetList,
3047 qry->sortClause);
3048 qry->hasDistinctOn = true;
3049 }
3050
3051 /* transform LIMIT */
3052 qry->limitOffset = transformLimitClause(pstate, sstmt->limitOffset,
3053 EXPR_KIND_OFFSET, "OFFSET",
3054 sstmt->limitOption);
3055 qry->limitCount = transformLimitClause(pstate, sstmt->limitCount,
3056 EXPR_KIND_LIMIT, "LIMIT",
3057 sstmt->limitOption);
3058 qry->limitOption = sstmt->limitOption;
3059
3060 /* transform window clauses after we have seen all window functions */
3062 pstate->p_windowdefs,
3063 &qry->targetList);
3064
3065 qry->rtable = pstate->p_rtable;
3066 qry->rteperminfos = pstate->p_rteperminfos;
3067 qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
3068
3069 qry->hasSubLinks = pstate->p_hasSubLinks;
3070 qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
3071 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
3072 qry->hasAggs = pstate->p_hasAggs;
3073
3074 foreach(l, sstmt->lockingClause)
3075 {
3076 transformLockingClause(pstate, qry,
3077 (LockingClause *) lfirst(l), false);
3078 }
3079
3080 assign_query_collations(pstate, qry);
3081
3082 /* this must be done after collations, for reliable comparison of exprs */
3083 if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
3084 parseCheckAggregates(pstate, qry);
3085
3086 return qry;
3087}
int32_t int32
Definition: c.h:498
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1181
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
List * list_delete_first(List *list)
Definition: list.c:943
List * list_copy(const List *oldlist)
Definition: list.c:1573
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
List * transformGroupClause(ParseState *pstate, List *grouplist, List **groupingSets, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99)
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
List * transformDistinctOnClause(ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
List * transformWindowDefinitions(ParseState *pstate, List *windowdefs, List **targetlist)
List * transformDistinctClause(ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
Node * transformLimitClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName, LimitOption limitOption)
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
@ EXPR_KIND_ORDER_BY
Definition: parse_node.h:60
@ EXPR_KIND_OFFSET
Definition: parse_node.h:63
@ EXPR_KIND_HAVING
Definition: parse_node.h:47
@ EXPR_KIND_LIMIT
Definition: parse_node.h:62
@ EXPR_KIND_UPDATE_TARGET
Definition: parse_node.h:57
@ EXPR_KIND_SELECT_TARGET
Definition: parse_node.h:54
@ EXPR_KIND_NONE
Definition: parse_node.h:40
@ EXPR_KIND_GROUP_BY
Definition: parse_node.h:59
Node * transformAssignmentIndirection(ParseState *pstate, Node *basenode, const char *targetName, bool targetIsSubscripting, Oid targetTypeId, int32 targetTypMod, Oid targetCollation, List *indirection, ListCell *indirection_cell, Node *rhs, CoercionContext ccontext, int location)
Definition: parse_target.c:686
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:121
#define ISCOMPLEX(typeid)
Definition: parse_type.h:59
#define linitial_node(type, l)
Definition: pg_list.h:181
#define list_make1(x1)
Definition: pg_list.h:212
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_PLPGSQL
Definition: primnodes.h:733
ParseLoc location
Definition: parsenodes.h:306
List * fields
Definition: parsenodes.h:305
ParseExprKind p_expr_kind
Definition: parse_node.h:230
List * p_windowdefs
Definition: parse_node.h:229
List * p_locking_clause
Definition: parse_node.h:233
Node * limitCount
Definition: parsenodes.h:225
Node * limitOffset
Definition: parsenodes.h:224
LimitOption limitOption
Definition: parsenodes.h:226
List * windowClause
Definition: parsenodes.h:218
List * sortClause
Definition: parsenodes.h:222
LimitOption limitOption
Definition: parsenodes.h:2208
List * targetList
Definition: parsenodes.h:2183
List * fromClause
Definition: parsenodes.h:2184
List * groupClause
Definition: parsenodes.h:2186
Node * havingClause
Definition: parsenodes.h:2188
List * windowClause
Definition: parsenodes.h:2189
List * distinctClause
Definition: parsenodes.h:2180
Node * whereClause
Definition: parsenodes.h:2185
Definition: value.h:64
String * makeString(char *str)
Definition: value.c:63

References assign_query_collations(), CMD_SELECT, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_PLPGSQL, Query::commandType, Query::distinctClause, SelectStmt::distinctClause, elog, ereport, errcode(), errhint(), errmsg(), errmsg_plural(), ERROR, TargetEntry::expr, EXPR_KIND_GROUP_BY, EXPR_KIND_HAVING, EXPR_KIND_LIMIT, EXPR_KIND_NONE, EXPR_KIND_OFFSET, EXPR_KIND_ORDER_BY, EXPR_KIND_SELECT_TARGET, EXPR_KIND_UPDATE_TARGET, EXPR_KIND_WHERE, exprCollation(), exprLocation(), exprType(), exprTypmod(), ColumnRef::fields, format_type_be(), SelectStmt::fromClause, Query::groupClause, SelectStmt::groupClause, Query::groupingSets, SelectStmt::havingClause, Query::havingQual, IsA, ISCOMPLEX, Query::jointree, lappend(), lfirst, Query::limitCount, SelectStmt::limitCount, Query::limitOffset, SelectStmt::limitOffset, Query::limitOption, SelectStmt::limitOption, linitial, linitial_node, list_copy(), list_delete_first(), list_head(), list_length(), list_make1, ColumnRef::location, SelectStmt::lockingClause, makeFromExpr(), makeNode, makeString(), NIL, ParseState::p_expr_kind, ParseState::p_hasAggs, ParseState::p_hasSubLinks, ParseState::p_hasTargetSRFs, ParseState::p_hasWindowFuncs, ParseState::p_is_insert, ParseState::p_joinlist, ParseState::p_locking_clause, ParseState::p_rtable, ParseState::p_rteperminfos, ParseState::p_windowdefs, parseCheckAggregates(), parser_errposition(), Query::rtable, Query::sortClause, SelectStmt::sortClause, stmt, Query::targetList, SelectStmt::targetList, transformAssignmentIndirection(), transformDistinctClause(), transformDistinctOnClause(), transformExpr(), transformFromClause(), transformGroupClause(), transformLimitClause(), transformLockingClause(), transformSortClause(), transformTargetList(), transformWhereClause(), transformWindowDefinitions(), SelectStmt::whereClause, Query::windowClause, and SelectStmt::windowClause.

Referenced by transformStmt().

◆ transformReturningClause()

void transformReturningClause ( ParseState pstate,
Query qry,
ReturningClause returningClause,
ParseExprKind  exprKind 
)

Definition at line 2730 of file analyze.c.

2733{
2734 int save_nslen = list_length(pstate->p_namespace);
2735 int save_next_resno;
2736
2737 if (returningClause == NULL)
2738 return; /* nothing to do */
2739
2740 /*
2741 * Scan RETURNING WITH(...) options for OLD/NEW alias names. Complain if
2742 * there is any conflict with existing relations.
2743 */
2744 foreach_node(ReturningOption, option, returningClause->options)
2745 {
2746 switch (option->option)
2747 {
2749 if (qry->returningOldAlias != NULL)
2750 ereport(ERROR,
2751 errcode(ERRCODE_SYNTAX_ERROR),
2752 /* translator: %s is OLD or NEW */
2753 errmsg("%s cannot be specified multiple times", "OLD"),
2754 parser_errposition(pstate, option->location));
2755 qry->returningOldAlias = option->value;
2756 break;
2757
2759 if (qry->returningNewAlias != NULL)
2760 ereport(ERROR,
2761 errcode(ERRCODE_SYNTAX_ERROR),
2762 /* translator: %s is OLD or NEW */
2763 errmsg("%s cannot be specified multiple times", "NEW"),
2764 parser_errposition(pstate, option->location));
2765 qry->returningNewAlias = option->value;
2766 break;
2767
2768 default:
2769 elog(ERROR, "unrecognized returning option: %d", option->option);
2770 }
2771
2772 if (refnameNamespaceItem(pstate, NULL, option->value, -1, NULL) != NULL)
2773 ereport(ERROR,
2774 errcode(ERRCODE_DUPLICATE_ALIAS),
2775 errmsg("table name \"%s\" specified more than once",
2776 option->value),
2777 parser_errposition(pstate, option->location));
2778
2779 addNSItemForReturning(pstate, option->value,
2780 option->option == RETURNING_OPTION_OLD ?
2782 }
2783
2784 /*
2785 * If OLD/NEW alias names weren't explicitly specified, use "old"/"new"
2786 * unless masked by existing relations.
2787 */
2788 if (qry->returningOldAlias == NULL &&
2789 refnameNamespaceItem(pstate, NULL, "old", -1, NULL) == NULL)
2790 {
2791 qry->returningOldAlias = "old";
2793 }
2794 if (qry->returningNewAlias == NULL &&
2795 refnameNamespaceItem(pstate, NULL, "new", -1, NULL) == NULL)
2796 {
2797 qry->returningNewAlias = "new";
2799 }
2800
2801 /*
2802 * We need to assign resnos starting at one in the RETURNING list. Save
2803 * and restore the main tlist's value of p_next_resno, just in case
2804 * someone looks at it later (probably won't happen).
2805 */
2806 save_next_resno = pstate->p_next_resno;
2807 pstate->p_next_resno = 1;
2808
2809 /* transform RETURNING expressions identically to a SELECT targetlist */
2810 qry->returningList = transformTargetList(pstate,
2811 returningClause->exprs,
2812 exprKind);
2813
2814 /*
2815 * Complain if the nonempty tlist expanded to nothing (which is possible
2816 * if it contains only a star-expansion of a zero-column table). If we
2817 * allow this, the parsed Query will look like it didn't have RETURNING,
2818 * with results that would probably surprise the user.
2819 */
2820 if (qry->returningList == NIL)
2821 ereport(ERROR,
2822 (errcode(ERRCODE_SYNTAX_ERROR),
2823 errmsg("RETURNING must have at least one column"),
2824 parser_errposition(pstate,
2825 exprLocation(linitial(returningClause->exprs)))));
2826
2827 /* mark column origins */
2829
2830 /* resolve any still-unresolved output columns as being type text */
2831 if (pstate->p_resolve_unknowns)
2833
2834 /* restore state */
2835 pstate->p_namespace = list_truncate(pstate->p_namespace, save_nslen);
2836 pstate->p_next_resno = save_next_resno;
2837}
List * list_truncate(List *list, int new_size)
Definition: list.c:631
ParseNamespaceItem * refnameNamespaceItem(ParseState *pstate, const char *schemaname, const char *refname, int location, int *sublevels_up)
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
Definition: parse_target.c:288
void markTargetListOrigins(ParseState *pstate, List *targetlist)
Definition: parse_target.c:318
@ RETURNING_OPTION_NEW
Definition: parsenodes.h:1752
@ RETURNING_OPTION_OLD
Definition: parsenodes.h:1751
static void addNSItemForReturning(ParseState *pstate, const char *aliasname, VarReturningType returning_type)
Definition: analyze.c:2690
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
@ VAR_RETURNING_OLD
Definition: primnodes.h:257
@ VAR_RETURNING_NEW
Definition: primnodes.h:258
int p_next_resno
Definition: parse_node.h:231
List * returningList
Definition: parsenodes.h:209

References addNSItemForReturning(), elog, ereport, errcode(), errmsg(), ERROR, exprLocation(), ReturningClause::exprs, foreach_node, linitial, list_length(), list_truncate(), markTargetListOrigins(), NIL, ReturningClause::options, ParseState::p_namespace, ParseState::p_next_resno, ParseState::p_resolve_unknowns, parser_errposition(), refnameNamespaceItem(), resolveTargetListUnknowns(), RETURNING_OPTION_NEW, RETURNING_OPTION_OLD, Query::returningList, transformTargetList(), VAR_RETURNING_NEW, and VAR_RETURNING_OLD.

Referenced by transformDeleteStmt(), transformMergeStmt(), and transformUpdateStmt().

◆ transformReturnStmt()

static Query * transformReturnStmt ( ParseState pstate,
ReturnStmt stmt 
)
static

Definition at line 2518 of file analyze.c.

2519{
2520 Query *qry = makeNode(Query);
2521
2522 qry->commandType = CMD_SELECT;
2523 qry->isReturn = true;
2524
2526 1, NULL, false));
2527
2528 if (pstate->p_resolve_unknowns)
2530 qry->rtable = pstate->p_rtable;
2531 qry->rteperminfos = pstate->p_rteperminfos;
2532 qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2533 qry->hasSubLinks = pstate->p_hasSubLinks;
2534 qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2535 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2536 qry->hasAggs = pstate->p_hasAggs;
2537
2538 assign_query_collations(pstate, qry);
2539
2540 return qry;
2541}

References assign_query_collations(), CMD_SELECT, Query::commandType, EXPR_KIND_SELECT_TARGET, Query::jointree, list_make1, makeFromExpr(), makeNode, makeTargetEntry(), ParseState::p_hasAggs, ParseState::p_hasSubLinks, ParseState::p_hasTargetSRFs, ParseState::p_hasWindowFuncs, ParseState::p_joinlist, ParseState::p_resolve_unknowns, ParseState::p_rtable, ParseState::p_rteperminfos, resolveTargetListUnknowns(), Query::rtable, stmt, Query::targetList, and transformExpr().

Referenced by transformStmt().

◆ transformSelectStmt()

static Query * transformSelectStmt ( ParseState pstate,
SelectStmt stmt 
)
static

Definition at line 1466 of file analyze.c.

1467{
1468 Query *qry = makeNode(Query);
1469 Node *qual;
1470 ListCell *l;
1471
1472 qry->commandType = CMD_SELECT;
1473
1474 /* process the WITH clause independently of all else */
1475 if (stmt->withClause)
1476 {
1477 qry->hasRecursive = stmt->withClause->recursive;
1478 qry->cteList = transformWithClause(pstate, stmt->withClause);
1479 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1480 }
1481
1482 /* Complain if we get called from someplace where INTO is not allowed */
1483 if (stmt->intoClause)
1484 ereport(ERROR,
1485 (errcode(ERRCODE_SYNTAX_ERROR),
1486 errmsg("SELECT ... INTO is not allowed here"),
1487 parser_errposition(pstate,
1488 exprLocation((Node *) stmt->intoClause))));
1489
1490 /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
1491 pstate->p_locking_clause = stmt->lockingClause;
1492
1493 /* make WINDOW info available for window functions, too */
1494 pstate->p_windowdefs = stmt->windowClause;
1495
1496 /* process the FROM clause */
1497 transformFromClause(pstate, stmt->fromClause);
1498
1499 /* transform targetlist */
1500 qry->targetList = transformTargetList(pstate, stmt->targetList,
1502
1503 /* mark column origins */
1504 markTargetListOrigins(pstate, qry->targetList);
1505
1506 /* transform WHERE */
1507 qual = transformWhereClause(pstate, stmt->whereClause,
1508 EXPR_KIND_WHERE, "WHERE");
1509
1510 /* initial processing of HAVING clause is much like WHERE clause */
1511 qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
1512 EXPR_KIND_HAVING, "HAVING");
1513
1514 /*
1515 * Transform sorting/grouping stuff. Do ORDER BY first because both
1516 * transformGroupClause and transformDistinctClause need the results. Note
1517 * that these functions can also change the targetList, so it's passed to
1518 * them by reference.
1519 */
1520 qry->sortClause = transformSortClause(pstate,
1521 stmt->sortClause,
1522 &qry->targetList,
1524 false /* allow SQL92 rules */ );
1525
1526 qry->groupClause = transformGroupClause(pstate,
1527 stmt->groupClause,
1528 &qry->groupingSets,
1529 &qry->targetList,
1530 qry->sortClause,
1532 false /* allow SQL92 rules */ );
1533 qry->groupDistinct = stmt->groupDistinct;
1534
1535 if (stmt->distinctClause == NIL)
1536 {
1537 qry->distinctClause = NIL;
1538 qry->hasDistinctOn = false;
1539 }
1540 else if (linitial(stmt->distinctClause) == NULL)
1541 {
1542 /* We had SELECT DISTINCT */
1544 &qry->targetList,
1545 qry->sortClause,
1546 false);
1547 qry->hasDistinctOn = false;
1548 }
1549 else
1550 {
1551 /* We had SELECT DISTINCT ON */
1553 stmt->distinctClause,
1554 &qry->targetList,
1555 qry->sortClause);
1556 qry->hasDistinctOn = true;
1557 }
1558
1559 /* transform LIMIT */
1560 qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1561 EXPR_KIND_OFFSET, "OFFSET",
1562 stmt->limitOption);
1563 qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1564 EXPR_KIND_LIMIT, "LIMIT",
1565 stmt->limitOption);
1566 qry->limitOption = stmt->limitOption;
1567
1568 /* transform window clauses after we have seen all window functions */
1570 pstate->p_windowdefs,
1571 &qry->targetList);
1572
1573 /* resolve any still-unresolved output columns as being type text */
1574 if (pstate->p_resolve_unknowns)
1576
1577 qry->rtable = pstate->p_rtable;
1578 qry->rteperminfos = pstate->p_rteperminfos;
1579 qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
1580
1581 qry->hasSubLinks = pstate->p_hasSubLinks;
1582 qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1583 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1584 qry->hasAggs = pstate->p_hasAggs;
1585
1586 foreach(l, stmt->lockingClause)
1587 {
1588 transformLockingClause(pstate, qry,
1589 (LockingClause *) lfirst(l), false);
1590 }
1591
1592 assign_query_collations(pstate, qry);
1593
1594 /* this must be done after collations, for reliable comparison of exprs */
1595 if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1596 parseCheckAggregates(pstate, qry);
1597
1598 return qry;
1599}
bool groupDistinct
Definition: parsenodes.h:212

References assign_query_collations(), CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_GROUP_BY, EXPR_KIND_HAVING, EXPR_KIND_LIMIT, EXPR_KIND_OFFSET, EXPR_KIND_ORDER_BY, EXPR_KIND_SELECT_TARGET, EXPR_KIND_WHERE, exprLocation(), Query::groupClause, Query::groupDistinct, Query::groupingSets, Query::havingQual, Query::jointree, lfirst, Query::limitCount, Query::limitOffset, Query::limitOption, linitial, makeFromExpr(), makeNode, markTargetListOrigins(), NIL, ParseState::p_hasAggs, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_hasTargetSRFs, ParseState::p_hasWindowFuncs, ParseState::p_joinlist, ParseState::p_locking_clause, ParseState::p_resolve_unknowns, ParseState::p_rtable, ParseState::p_rteperminfos, ParseState::p_windowdefs, parseCheckAggregates(), parser_errposition(), resolveTargetListUnknowns(), Query::rtable, Query::sortClause, stmt, Query::targetList, transformDistinctClause(), transformDistinctOnClause(), transformFromClause(), transformGroupClause(), transformLimitClause(), transformLockingClause(), transformSortClause(), transformTargetList(), transformWhereClause(), transformWindowDefinitions(), transformWithClause(), and Query::windowClause.

Referenced by transformStmt().

◆ transformSetOperationStmt()

static Query * transformSetOperationStmt ( ParseState pstate,
SelectStmt stmt 
)
static

Definition at line 1828 of file analyze.c.

1829{
1830 Query *qry = makeNode(Query);
1831 SelectStmt *leftmostSelect;
1832 int leftmostRTI;
1833 Query *leftmostQuery;
1834 SetOperationStmt *sostmt;
1835 List *sortClause;
1836 Node *limitOffset;
1837 Node *limitCount;
1838 List *lockingClause;
1839 WithClause *withClause;
1840 Node *node;
1841 ListCell *left_tlist,
1842 *lct,
1843 *lcm,
1844 *lcc,
1845 *l;
1846 List *targetvars,
1847 *targetnames,
1848 *sv_namespace;
1849 int sv_rtable_length;
1850 ParseNamespaceItem *jnsitem;
1851 ParseNamespaceColumn *sortnscolumns;
1852 int sortcolindex;
1853 int tllen;
1854
1855 qry->commandType = CMD_SELECT;
1856
1857 /*
1858 * Find leftmost leaf SelectStmt. We currently only need to do this in
1859 * order to deliver a suitable error message if there's an INTO clause
1860 * there, implying the set-op tree is in a context that doesn't allow
1861 * INTO. (transformSetOperationTree would throw error anyway, but it
1862 * seems worth the trouble to throw a different error for non-leftmost
1863 * INTO, so we produce that error in transformSetOperationTree.)
1864 */
1865 leftmostSelect = stmt->larg;
1866 while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
1867 leftmostSelect = leftmostSelect->larg;
1868 Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
1869 leftmostSelect->larg == NULL);
1870 if (leftmostSelect->intoClause)
1871 ereport(ERROR,
1872 (errcode(ERRCODE_SYNTAX_ERROR),
1873 errmsg("SELECT ... INTO is not allowed here"),
1874 parser_errposition(pstate,
1875 exprLocation((Node *) leftmostSelect->intoClause))));
1876
1877 /*
1878 * We need to extract ORDER BY and other top-level clauses here and not
1879 * let transformSetOperationTree() see them --- else it'll just recurse
1880 * right back here!
1881 */
1882 sortClause = stmt->sortClause;
1883 limitOffset = stmt->limitOffset;
1884 limitCount = stmt->limitCount;
1885 lockingClause = stmt->lockingClause;
1886 withClause = stmt->withClause;
1887
1888 stmt->sortClause = NIL;
1889 stmt->limitOffset = NULL;
1890 stmt->limitCount = NULL;
1891 stmt->lockingClause = NIL;
1892 stmt->withClause = NULL;
1893
1894 /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1895 if (lockingClause)
1896 ereport(ERROR,
1897 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1898 /*------
1899 translator: %s is a SQL row locking clause such as FOR UPDATE */
1900 errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1902 linitial(lockingClause))->strength))));
1903
1904 /* Process the WITH clause independently of all else */
1905 if (withClause)
1906 {
1907 qry->hasRecursive = withClause->recursive;
1908 qry->cteList = transformWithClause(pstate, withClause);
1909 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1910 }
1911
1912 /*
1913 * Recursively transform the components of the tree.
1914 */
1915 sostmt = castNode(SetOperationStmt,
1916 transformSetOperationTree(pstate, stmt, true, NULL));
1917 Assert(sostmt);
1918 qry->setOperations = (Node *) sostmt;
1919
1920 /*
1921 * Re-find leftmost SELECT (now it's a sub-query in rangetable)
1922 */
1923 node = sostmt->larg;
1924 while (node && IsA(node, SetOperationStmt))
1925 node = ((SetOperationStmt *) node)->larg;
1926 Assert(node && IsA(node, RangeTblRef));
1927 leftmostRTI = ((RangeTblRef *) node)->rtindex;
1928 leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
1929 Assert(leftmostQuery != NULL);
1930
1931 /*
1932 * Generate dummy targetlist for outer query using column names of
1933 * leftmost select and common datatypes/collations of topmost set
1934 * operation. Also make lists of the dummy vars and their names for use
1935 * in parsing ORDER BY.
1936 *
1937 * Note: we use leftmostRTI as the varno of the dummy variables. It
1938 * shouldn't matter too much which RT index they have, as long as they
1939 * have one that corresponds to a real RT entry; else funny things may
1940 * happen when the tree is mashed by rule rewriting.
1941 */
1942 qry->targetList = NIL;
1943 targetvars = NIL;
1944 targetnames = NIL;
1945 sortnscolumns = (ParseNamespaceColumn *)
1946 palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
1947 sortcolindex = 0;
1948
1949 forfour(lct, sostmt->colTypes,
1950 lcm, sostmt->colTypmods,
1951 lcc, sostmt->colCollations,
1952 left_tlist, leftmostQuery->targetList)
1953 {
1954 Oid colType = lfirst_oid(lct);
1955 int32 colTypmod = lfirst_int(lcm);
1956 Oid colCollation = lfirst_oid(lcc);
1957 TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
1958 char *colName;
1959 TargetEntry *tle;
1960 Var *var;
1961
1962 Assert(!lefttle->resjunk);
1963 colName = pstrdup(lefttle->resname);
1964 var = makeVar(leftmostRTI,
1965 lefttle->resno,
1966 colType,
1967 colTypmod,
1968 colCollation,
1969 0);
1970 var->location = exprLocation((Node *) lefttle->expr);
1971 tle = makeTargetEntry((Expr *) var,
1972 (AttrNumber) pstate->p_next_resno++,
1973 colName,
1974 false);
1975 qry->targetList = lappend(qry->targetList, tle);
1976 targetvars = lappend(targetvars, var);
1977 targetnames = lappend(targetnames, makeString(colName));
1978 sortnscolumns[sortcolindex].p_varno = leftmostRTI;
1979 sortnscolumns[sortcolindex].p_varattno = lefttle->resno;
1980 sortnscolumns[sortcolindex].p_vartype = colType;
1981 sortnscolumns[sortcolindex].p_vartypmod = colTypmod;
1982 sortnscolumns[sortcolindex].p_varcollid = colCollation;
1983 sortnscolumns[sortcolindex].p_varnosyn = leftmostRTI;
1984 sortnscolumns[sortcolindex].p_varattnosyn = lefttle->resno;
1985 sortcolindex++;
1986 }
1987
1988 /*
1989 * As a first step towards supporting sort clauses that are expressions
1990 * using the output columns, generate a namespace entry that makes the
1991 * output columns visible. A Join RTE node is handy for this, since we
1992 * can easily control the Vars generated upon matches.
1993 *
1994 * Note: we don't yet do anything useful with such cases, but at least
1995 * "ORDER BY upper(foo)" will draw the right error message rather than
1996 * "foo not found".
1997 */
1998 sv_rtable_length = list_length(pstate->p_rtable);
1999
2000 jnsitem = addRangeTableEntryForJoin(pstate,
2001 targetnames,
2002 sortnscolumns,
2003 JOIN_INNER,
2004 0,
2005 targetvars,
2006 NIL,
2007 NIL,
2008 NULL,
2009 NULL,
2010 false);
2011
2012 sv_namespace = pstate->p_namespace;
2013 pstate->p_namespace = NIL;
2014
2015 /* add jnsitem to column namespace only */
2016 addNSItemToQuery(pstate, jnsitem, false, false, true);
2017
2018 /*
2019 * For now, we don't support resjunk sort clauses on the output of a
2020 * setOperation tree --- you can only use the SQL92-spec options of
2021 * selecting an output column by name or number. Enforce by checking that
2022 * transformSortClause doesn't add any items to tlist. Note, if changing
2023 * this, add_setop_child_rel_equivalences() will need to be updated.
2024 */
2025 tllen = list_length(qry->targetList);
2026
2027 qry->sortClause = transformSortClause(pstate,
2028 sortClause,
2029 &qry->targetList,
2031 false /* allow SQL92 rules */ );
2032
2033 /* restore namespace, remove join RTE from rtable */
2034 pstate->p_namespace = sv_namespace;
2035 pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
2036
2037 if (tllen != list_length(qry->targetList))
2038 ereport(ERROR,
2039 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2040 errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
2041 errdetail("Only result column names can be used, not expressions or functions."),
2042 errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
2043 parser_errposition(pstate,
2044 exprLocation(list_nth(qry->targetList, tllen)))));
2045
2046 qry->limitOffset = transformLimitClause(pstate, limitOffset,
2047 EXPR_KIND_OFFSET, "OFFSET",
2048 stmt->limitOption);
2049 qry->limitCount = transformLimitClause(pstate, limitCount,
2050 EXPR_KIND_LIMIT, "LIMIT",
2051 stmt->limitOption);
2052 qry->limitOption = stmt->limitOption;
2053
2054 qry->rtable = pstate->p_rtable;
2055 qry->rteperminfos = pstate->p_rteperminfos;
2056 qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2057
2058 qry->hasSubLinks = pstate->p_hasSubLinks;
2059 qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2060 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2061 qry->hasAggs = pstate->p_hasAggs;
2062
2063 foreach(l, lockingClause)
2064 {
2065 transformLockingClause(pstate, qry,
2066 (LockingClause *) lfirst(l), false);
2067 }
2068
2069 assign_query_collations(pstate, qry);
2070
2071 /* this must be done after collations, for reliable comparison of exprs */
2072 if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
2073 parseCheckAggregates(pstate, qry);
2074
2075 return qry;
2076}
void * palloc0(Size size)
Definition: mcxt.c:1970
@ JOIN_INNER
Definition: nodes.h:299
struct ParseNamespaceColumn ParseNamespaceColumn
Definition: parse_node.h:25
ParseNamespaceItem * addRangeTableEntryForJoin(ParseState *pstate, List *colnames, ParseNamespaceColumn *nscolumns, JoinType jointype, int nummergedcols, List *aliasvars, List *leftcols, List *rightcols, Alias *join_using_alias, Alias *alias, bool inFromCl)
static Node * transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, bool isTopLevel, List **targetlist)
Definition: analyze.c:2133
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:575
#define lfirst_oid(lc)
Definition: pg_list.h:174
AttrNumber p_varattno
Definition: parse_node.h:347
AttrNumber p_varattnosyn
Definition: parse_node.h:353
struct SelectStmt * larg
Definition: parsenodes.h:2217
SetOperation op
Definition: parsenodes.h:2215
AttrNumber resno
Definition: primnodes.h:2221
bool recursive
Definition: parsenodes.h:1610

References addNSItemToQuery(), addRangeTableEntryForJoin(), Assert(), assign_query_collations(), castNode, CMD_SELECT, Query::commandType, Query::cteList, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, TargetEntry::expr, EXPR_KIND_LIMIT, EXPR_KIND_OFFSET, EXPR_KIND_ORDER_BY, exprLocation(), forfour, Query::groupClause, Query::groupingSets, Query::havingQual, SelectStmt::intoClause, IsA, JOIN_INNER, Query::jointree, lappend(), SelectStmt::larg, SetOperationStmt::larg, LCS_asString(), lfirst, lfirst_int, lfirst_oid, Query::limitCount, Query::limitOffset, Query::limitOption, linitial, list_length(), list_nth(), list_truncate(), Var::location, makeFromExpr(), makeNode, makeString(), makeTargetEntry(), makeVar(), NIL, SelectStmt::op, ParseState::p_hasAggs, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_hasTargetSRFs, ParseState::p_hasWindowFuncs, ParseState::p_joinlist, ParseState::p_namespace, ParseState::p_next_resno, ParseState::p_rtable, ParseState::p_rteperminfos, ParseNamespaceColumn::p_varattno, ParseNamespaceColumn::p_varattnosyn, ParseNamespaceColumn::p_varcollid, ParseNamespaceColumn::p_varno, ParseNamespaceColumn::p_varnosyn, ParseNamespaceColumn::p_vartype, ParseNamespaceColumn::p_vartypmod, palloc0(), parseCheckAggregates(), parser_errposition(), pstrdup(), WithClause::recursive, TargetEntry::resno, rt_fetch, Query::rtable, SETOP_NONE, Query::setOperations, Query::sortClause, stmt, Query::targetList, transformLimitClause(), transformLockingClause(), transformSetOperationTree(), transformSortClause(), and transformWithClause().

Referenced by transformStmt().

◆ transformSetOperationTree()

static Node * transformSetOperationTree ( ParseState pstate,
SelectStmt stmt,
bool  isTopLevel,
List **  targetlist 
)
static

Definition at line 2133 of file analyze.c.

2135{
2136 bool isLeaf;
2137
2139
2140 /* Guard against stack overflow due to overly complex set-expressions */
2142
2143 /*
2144 * Validity-check both leaf and internal SELECTs for disallowed ops.
2145 */
2146 if (stmt->intoClause)
2147 ereport(ERROR,
2148 (errcode(ERRCODE_SYNTAX_ERROR),
2149 errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
2150 parser_errposition(pstate,
2151 exprLocation((Node *) stmt->intoClause))));
2152
2153 /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
2154 if (stmt->lockingClause)
2155 ereport(ERROR,
2156 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2157 /*------
2158 translator: %s is a SQL row locking clause such as FOR UPDATE */
2159 errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
2161 linitial(stmt->lockingClause))->strength))));
2162
2163 /*
2164 * If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
2165 * or WITH clauses attached, we need to treat it like a leaf node to
2166 * generate an independent sub-Query tree. Otherwise, it can be
2167 * represented by a SetOperationStmt node underneath the parent Query.
2168 */
2169 if (stmt->op == SETOP_NONE)
2170 {
2171 Assert(stmt->larg == NULL && stmt->rarg == NULL);
2172 isLeaf = true;
2173 }
2174 else
2175 {
2176 Assert(stmt->larg != NULL && stmt->rarg != NULL);
2177 if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
2178 stmt->lockingClause || stmt->withClause)
2179 isLeaf = true;
2180 else
2181 isLeaf = false;
2182 }
2183
2184 if (isLeaf)
2185 {
2186 /* Process leaf SELECT */
2187 Query *selectQuery;
2188 char selectName[32];
2189 ParseNamespaceItem *nsitem;
2190 RangeTblRef *rtr;
2191 ListCell *tl;
2192
2193 /*
2194 * Transform SelectStmt into a Query.
2195 *
2196 * This works the same as SELECT transformation normally would, except
2197 * that we prevent resolving unknown-type outputs as TEXT. This does
2198 * not change the subquery's semantics since if the column type
2199 * matters semantically, it would have been resolved to something else
2200 * anyway. Doing this lets us resolve such outputs using
2201 * select_common_type(), below.
2202 *
2203 * Note: previously transformed sub-queries don't affect the parsing
2204 * of this sub-query, because they are not in the toplevel pstate's
2205 * namespace list.
2206 */
2207 selectQuery = parse_sub_analyze((Node *) stmt, pstate,
2208 NULL, false, false);
2209
2210 /*
2211 * Check for bogus references to Vars on the current query level (but
2212 * upper-level references are okay). Normally this can't happen
2213 * because the namespace will be empty, but it could happen if we are
2214 * inside a rule.
2215 */
2216 if (pstate->p_namespace)
2217 {
2218 if (contain_vars_of_level((Node *) selectQuery, 1))
2219 ereport(ERROR,
2220 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2221 errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
2222 parser_errposition(pstate,
2223 locate_var_of_level((Node *) selectQuery, 1))));
2224 }
2225
2226 /*
2227 * Extract a list of the non-junk TLEs for upper-level processing.
2228 */
2229 if (targetlist)
2230 {
2231 *targetlist = NIL;
2232 foreach(tl, selectQuery->targetList)
2233 {
2234 TargetEntry *tle = (TargetEntry *) lfirst(tl);
2235
2236 if (!tle->resjunk)
2237 *targetlist = lappend(*targetlist, tle);
2238 }
2239 }
2240
2241 /*
2242 * Make the leaf query be a subquery in the top-level rangetable.
2243 */
2244 snprintf(selectName, sizeof(selectName), "*SELECT* %d",
2245 list_length(pstate->p_rtable) + 1);
2246 nsitem = addRangeTableEntryForSubquery(pstate,
2247 selectQuery,
2248 makeAlias(selectName, NIL),
2249 false,
2250 false);
2251
2252 /*
2253 * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
2254 */
2255 rtr = makeNode(RangeTblRef);
2256 rtr->rtindex = nsitem->p_rtindex;
2257 return (Node *) rtr;
2258 }
2259 else
2260 {
2261 /* Process an internal node (set operation node) */
2263 List *ltargetlist;
2264 List *rtargetlist;
2265 ListCell *ltl;
2266 ListCell *rtl;
2267 const char *context;
2268 bool recursive = (pstate->p_parent_cte &&
2269 pstate->p_parent_cte->cterecursive);
2270
2271 context = (stmt->op == SETOP_UNION ? "UNION" :
2272 (stmt->op == SETOP_INTERSECT ? "INTERSECT" :
2273 "EXCEPT"));
2274
2275 op->op = stmt->op;
2276 op->all = stmt->all;
2277
2278 /*
2279 * Recursively transform the left child node.
2280 */
2281 op->larg = transformSetOperationTree(pstate, stmt->larg,
2282 false,
2283 &ltargetlist);
2284
2285 /*
2286 * If we are processing a recursive union query, now is the time to
2287 * examine the non-recursive term's output columns and mark the
2288 * containing CTE as having those result columns. We should do this
2289 * only at the topmost setop of the CTE, of course.
2290 */
2291 if (isTopLevel && recursive)
2292 determineRecursiveColTypes(pstate, op->larg, ltargetlist);
2293
2294 /*
2295 * Recursively transform the right child node.
2296 */
2297 op->rarg = transformSetOperationTree(pstate, stmt->rarg,
2298 false,
2299 &rtargetlist);
2300
2301 /*
2302 * Verify that the two children have the same number of non-junk
2303 * columns, and determine the types of the merged output columns.
2304 */
2305 if (list_length(ltargetlist) != list_length(rtargetlist))
2306 ereport(ERROR,
2307 (errcode(ERRCODE_SYNTAX_ERROR),
2308 errmsg("each %s query must have the same number of columns",
2309 context),
2310 parser_errposition(pstate,
2311 exprLocation((Node *) rtargetlist))));
2312
2313 if (targetlist)
2314 *targetlist = NIL;
2315 op->colTypes = NIL;
2316 op->colTypmods = NIL;
2317 op->colCollations = NIL;
2318 op->groupClauses = NIL;
2319 forboth(ltl, ltargetlist, rtl, rtargetlist)
2320 {
2321 TargetEntry *ltle = (TargetEntry *) lfirst(ltl);
2322 TargetEntry *rtle = (TargetEntry *) lfirst(rtl);
2323 Node *lcolnode = (Node *) ltle->expr;
2324 Node *rcolnode = (Node *) rtle->expr;
2325 Oid lcoltype = exprType(lcolnode);
2326 Oid rcoltype = exprType(rcolnode);
2327 Node *bestexpr;
2328 int bestlocation;
2329 Oid rescoltype;
2330 int32 rescoltypmod;
2331 Oid rescolcoll;
2332
2333 /* select common type, same as CASE et al */
2334 rescoltype = select_common_type(pstate,
2335 list_make2(lcolnode, rcolnode),
2336 context,
2337 &bestexpr);
2338 bestlocation = exprLocation(bestexpr);
2339
2340 /*
2341 * Verify the coercions are actually possible. If not, we'd fail
2342 * later anyway, but we want to fail now while we have sufficient
2343 * context to produce an error cursor position.
2344 *
2345 * For all non-UNKNOWN-type cases, we verify coercibility but we
2346 * don't modify the child's expression, for fear of changing the
2347 * child query's semantics.
2348 *
2349 * If a child expression is an UNKNOWN-type Const or Param, we
2350 * want to replace it with the coerced expression. This can only
2351 * happen when the child is a leaf set-op node. It's safe to
2352 * replace the expression because if the child query's semantics
2353 * depended on the type of this output column, it'd have already
2354 * coerced the UNKNOWN to something else. We want to do this
2355 * because (a) we want to verify that a Const is valid for the
2356 * target type, or resolve the actual type of an UNKNOWN Param,
2357 * and (b) we want to avoid unnecessary discrepancies between the
2358 * output type of the child query and the resolved target type.
2359 * Such a discrepancy would disable optimization in the planner.
2360 *
2361 * If it's some other UNKNOWN-type node, eg a Var, we do nothing
2362 * (knowing that coerce_to_common_type would fail). The planner
2363 * is sometimes able to fold an UNKNOWN Var to a constant before
2364 * it has to coerce the type, so failing now would just break
2365 * cases that might work.
2366 */
2367 if (lcoltype != UNKNOWNOID)
2368 lcolnode = coerce_to_common_type(pstate, lcolnode,
2369 rescoltype, context);
2370 else if (IsA(lcolnode, Const) ||
2371 IsA(lcolnode, Param))
2372 {
2373 lcolnode = coerce_to_common_type(pstate, lcolnode,
2374 rescoltype, context);
2375 ltle->expr = (Expr *) lcolnode;
2376 }
2377
2378 if (rcoltype != UNKNOWNOID)
2379 rcolnode = coerce_to_common_type(pstate, rcolnode,
2380 rescoltype, context);
2381 else if (IsA(rcolnode, Const) ||
2382 IsA(rcolnode, Param))
2383 {
2384 rcolnode = coerce_to_common_type(pstate, rcolnode,
2385 rescoltype, context);
2386 rtle->expr = (Expr *) rcolnode;
2387 }
2388
2389 rescoltypmod = select_common_typmod(pstate,
2390 list_make2(lcolnode, rcolnode),
2391 rescoltype);
2392
2393 /*
2394 * Select common collation. A common collation is required for
2395 * all set operators except UNION ALL; see SQL:2008 7.13 <query
2396 * expression> Syntax Rule 15c. (If we fail to identify a common
2397 * collation for a UNION ALL column, the colCollations element
2398 * will be set to InvalidOid, which may result in a runtime error
2399 * if something at a higher query level wants to use the column's
2400 * collation.)
2401 */
2402 rescolcoll = select_common_collation(pstate,
2403 list_make2(lcolnode, rcolnode),
2404 (op->op == SETOP_UNION && op->all));
2405
2406 /* emit results */
2407 op->colTypes = lappend_oid(op->colTypes, rescoltype);
2408 op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
2409 op->colCollations = lappend_oid(op->colCollations, rescolcoll);
2410
2411 /*
2412 * For all cases except UNION ALL, identify the grouping operators
2413 * (and, if available, sorting operators) that will be used to
2414 * eliminate duplicates.
2415 */
2416 if (op->op != SETOP_UNION || !op->all)
2417 {
2418 ParseCallbackState pcbstate;
2419
2420 setup_parser_errposition_callback(&pcbstate, pstate,
2421 bestlocation);
2422
2423 /*
2424 * If it's a recursive union, we need to require hashing
2425 * support.
2426 */
2427 op->groupClauses = lappend(op->groupClauses,
2428 makeSortGroupClauseForSetOp(rescoltype, recursive));
2429
2431 }
2432
2433 /*
2434 * Construct a dummy tlist entry to return. We use a SetToDefault
2435 * node for the expression, since it carries exactly the fields
2436 * needed, but any other expression node type would do as well.
2437 */
2438 if (targetlist)
2439 {
2440 SetToDefault *rescolnode = makeNode(SetToDefault);
2441 TargetEntry *restle;
2442
2443 rescolnode->typeId = rescoltype;
2444 rescolnode->typeMod = rescoltypmod;
2445 rescolnode->collation = rescolcoll;
2446 rescolnode->location = bestlocation;
2447 restle = makeTargetEntry((Expr *) rescolnode,
2448 0, /* no need to set resno */
2449 NULL,
2450 false);
2451 *targetlist = lappend(*targetlist, restle);
2452 }
2453 }
2454
2455 return (Node *) op;
2456 }
2457}
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
int32 select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
Oid select_common_type(ParseState *pstate, List *exprs, const char *context, Node **which_expr)
Oid select_common_collation(ParseState *pstate, List *exprs, bool none_ok)
void cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
Definition: parse_node.c:156
void setup_parser_errposition_callback(ParseCallbackState *pcbstate, ParseState *pstate, int location)
Definition: parse_node.c:140
@ SETOP_INTERSECT
Definition: parsenodes.h:2169
@ SETOP_UNION
Definition: parsenodes.h:2168
SortGroupClause * makeSortGroupClauseForSetOp(Oid rescoltype, bool require_hash)
Definition: analyze.c:2085
static void determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
Definition: analyze.c:2464
Query * parse_sub_analyze(Node *parseTree, ParseState *parentParseState, CommonTableExpr *parentCTE, bool locked_from_parent, bool resolve_unknowns)
Definition: analyze.c:222
#define list_make2(x1, x2)
Definition: pg_list.h:214
#define snprintf
Definition: port.h:239
void check_stack_depth(void)
Definition: stack_depth.c:95
SetOperation op
Definition: parsenodes.h:2247
ParseLoc location
Definition: primnodes.h:2083
int locate_var_of_level(Node *node, int levelsup)
Definition: var.c:555

References addRangeTableEntryForSubquery(), SetOperationStmt::all, Assert(), cancel_parser_errposition_callback(), check_stack_depth(), coerce_to_common_type(), contain_vars_of_level(), determineRecursiveColTypes(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprLocation(), exprType(), forboth, IsA, lappend(), lappend_int(), lappend_oid(), SetOperationStmt::larg, LCS_asString(), lfirst, linitial, list_length(), list_make2, locate_var_of_level(), SetToDefault::location, makeAlias(), makeNode, makeSortGroupClauseForSetOp(), makeTargetEntry(), NIL, SetOperationStmt::op, ParseState::p_namespace, ParseState::p_parent_cte, ParseState::p_rtable, ParseNamespaceItem::p_rtindex, parse_sub_analyze(), parser_errposition(), SetOperationStmt::rarg, RangeTblRef::rtindex, select_common_collation(), select_common_type(), select_common_typmod(), SETOP_INTERSECT, SETOP_NONE, SETOP_UNION, setup_parser_errposition_callback(), snprintf, stmt, Query::targetList, transformSetOperationTree(), and SetToDefault::typeId.

Referenced by transformSetOperationStmt(), and transformSetOperationTree().

◆ transformStmt()

Query * transformStmt ( ParseState pstate,
Node parseTree 
)

Definition at line 396 of file analyze.c.

397{
398 Query *result;
399
400#ifdef DEBUG_NODE_TESTS_ENABLED
401
402 /*
403 * We apply debug_raw_expression_coverage_test testing to basic DML
404 * statements; we can't just run it on everything because
405 * raw_expression_tree_walker() doesn't claim to handle utility
406 * statements.
407 */
408 if (Debug_raw_expression_coverage_test)
409 {
410 switch (nodeTag(parseTree))
411 {
412 case T_SelectStmt:
413 case T_InsertStmt:
414 case T_UpdateStmt:
415 case T_DeleteStmt:
416 case T_MergeStmt:
417 (void) test_raw_expression_coverage(parseTree, NULL);
418 break;
419 default:
420 break;
421 }
422 }
423#endif /* DEBUG_NODE_TESTS_ENABLED */
424
425 /*
426 * Caution: when changing the set of statement types that have non-default
427 * processing here, see also stmt_requires_parse_analysis() and
428 * analyze_requires_snapshot().
429 */
430 switch (nodeTag(parseTree))
431 {
432 /*
433 * Optimizable statements
434 */
435 case T_InsertStmt:
436 result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
437 break;
438
439 case T_DeleteStmt:
440 result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
441 break;
442
443 case T_UpdateStmt:
444 result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
445 break;
446
447 case T_MergeStmt:
448 result = transformMergeStmt(pstate, (MergeStmt *) parseTree);
449 break;
450
451 case T_SelectStmt:
452 {
453 SelectStmt *n = (SelectStmt *) parseTree;
454
455 if (n->valuesLists)
456 result = transformValuesClause(pstate, n);
457 else if (n->op == SETOP_NONE)
458 result = transformSelectStmt(pstate, n);
459 else
460 result = transformSetOperationStmt(pstate, n);
461 }
462 break;
463
464 case T_ReturnStmt:
465 result = transformReturnStmt(pstate, (ReturnStmt *) parseTree);
466 break;
467
468 case T_PLAssignStmt:
469 result = transformPLAssignStmt(pstate,
470 (PLAssignStmt *) parseTree);
471 break;
472
473 /*
474 * Special cases
475 */
476 case T_DeclareCursorStmt:
477 result = transformDeclareCursorStmt(pstate,
478 (DeclareCursorStmt *) parseTree);
479 break;
480
481 case T_ExplainStmt:
482 result = transformExplainStmt(pstate,
483 (ExplainStmt *) parseTree);
484 break;
485
486 case T_CreateTableAsStmt:
487 result = transformCreateTableAsStmt(pstate,
488 (CreateTableAsStmt *) parseTree);
489 break;
490
491 case T_CallStmt:
492 result = transformCallStmt(pstate,
493 (CallStmt *) parseTree);
494 break;
495
496 default:
497
498 /*
499 * other statements don't require any transformation; just return
500 * the original parsetree with a Query node plastered on top.
501 */
502 result = makeNode(Query);
503 result->commandType = CMD_UTILITY;
504 result->utilityStmt = (Node *) parseTree;
505 break;
506 }
507
508 /* Mark as original query until we learn differently */
509 result->querySource = QSRC_ORIGINAL;
510 result->canSetTag = true;
511 setQueryLocationAndLength(pstate, result, parseTree);
512
513 return result;
514}
Query * transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
Definition: parse_merge.c:107
@ QSRC_ORIGINAL
Definition: parsenodes.h:36
static void setQueryLocationAndLength(ParseState *pstate, Query *qry, Node *parseTree)
Definition: analyze.c:259
static Query * transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
Definition: analyze.c:638
static Query * transformReturnStmt(ParseState *pstate, ReturnStmt *stmt)
Definition: analyze.c:2518
static Query * transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
Definition: analyze.c:2852
static Query * transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
Definition: analyze.c:3246
static Query * transformCallStmt(ParseState *pstate, CallStmt *stmt)
Definition: analyze.c:3321
static Query * transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1828
static Query * transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
Definition: analyze.c:2549
static Query * transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1466
static Query * transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
Definition: analyze.c:3194
static Query * transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
Definition: analyze.c:3101
static Query * transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
Definition: analyze.c:710
static Query * transformValuesClause(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1609

References CMD_UTILITY, Query::commandType, makeNode, nodeTag, SelectStmt::op, QSRC_ORIGINAL, SETOP_NONE, setQueryLocationAndLength(), transformCallStmt(), transformCreateTableAsStmt(), transformDeclareCursorStmt(), transformDeleteStmt(), transformExplainStmt(), transformInsertStmt(), transformMergeStmt(), transformPLAssignStmt(), transformReturnStmt(), transformSelectStmt(), transformSetOperationStmt(), transformUpdateStmt(), transformValuesClause(), Query::utilityStmt, and SelectStmt::valuesLists.

Referenced by interpret_AS_clause(), parse_sub_analyze(), transformCreateTableAsStmt(), transformDeclareCursorStmt(), transformInsertStmt(), transformJsonArrayQueryConstructor(), transformOptionalSelectInto(), and transformRuleStmt().

◆ transformTopLevelStmt()

Query * transformTopLevelStmt ( ParseState pstate,
RawStmt parseTree 
)

Definition at line 332 of file analyze.c.

333{
334 Query *result;
335
336 /* Store RawStmt's length and location in pstate */
337 pstate->p_stmt_len = parseTree->stmt_len;
338 pstate->p_stmt_location = parseTree->stmt_location;
339
340 /* We're at top level, so allow SELECT INTO */
341 result = transformOptionalSelectInto(pstate, parseTree->stmt);
342
343 return result;
344}
ParseLoc stmt_location
Definition: parsenodes.h:2072
ParseLoc stmt_len
Definition: parsenodes.h:2073

References ParseState::p_stmt_len, ParseState::p_stmt_location, RawStmt::stmt, RawStmt::stmt_len, RawStmt::stmt_location, and transformOptionalSelectInto().

Referenced by inline_function(), parse_analyze_fixedparams(), parse_analyze_varparams(), and parse_analyze_withcb().

◆ transformUpdateStmt()

static Query * transformUpdateStmt ( ParseState pstate,
UpdateStmt stmt 
)
static

Definition at line 2549 of file analyze.c.

2550{
2551 Query *qry = makeNode(Query);
2552 ParseNamespaceItem *nsitem;
2553 Node *qual;
2554
2555 qry->commandType = CMD_UPDATE;
2556 pstate->p_is_insert = false;
2557
2558 /* process the WITH clause independently of all else */
2559 if (stmt->withClause)
2560 {
2561 qry->hasRecursive = stmt->withClause->recursive;
2562 qry->cteList = transformWithClause(pstate, stmt->withClause);
2563 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
2564 }
2565
2566 qry->resultRelation = setTargetTable(pstate, stmt->relation,
2567 stmt->relation->inh,
2568 true,
2569 ACL_UPDATE);
2570 nsitem = pstate->p_target_nsitem;
2571
2572 /* subqueries in FROM cannot access the result relation */
2573 nsitem->p_lateral_only = true;
2574 nsitem->p_lateral_ok = false;
2575
2576 /*
2577 * the FROM clause is non-standard SQL syntax. We used to be able to do
2578 * this with REPLACE in POSTQUEL so we keep the feature.
2579 */
2580 transformFromClause(pstate, stmt->fromClause);
2581
2582 /* remaining clauses can reference the result relation normally */
2583 nsitem->p_lateral_only = false;
2584 nsitem->p_lateral_ok = true;
2585
2586 qual = transformWhereClause(pstate, stmt->whereClause,
2587 EXPR_KIND_WHERE, "WHERE");
2588
2589 transformReturningClause(pstate, qry, stmt->returningClause,
2591
2592 /*
2593 * Now we are done with SELECT-like processing, and can get on with
2594 * transforming the target list to match the UPDATE target columns.
2595 */
2596 qry->targetList = transformUpdateTargetList(pstate, stmt->targetList);
2597
2598 qry->rtable = pstate->p_rtable;
2599 qry->rteperminfos = pstate->p_rteperminfos;
2600 qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2601
2602 qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2603 qry->hasSubLinks = pstate->p_hasSubLinks;
2604
2605 assign_query_collations(pstate, qry);
2606
2607 return qry;
2608}
@ CMD_UPDATE
Definition: nodes.h:272

References ACL_UPDATE, assign_query_collations(), CMD_UPDATE, Query::commandType, Query::cteList, EXPR_KIND_RETURNING, EXPR_KIND_WHERE, Query::jointree, makeFromExpr(), makeNode, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_hasTargetSRFs, ParseState::p_is_insert, ParseState::p_joinlist, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseState::p_rtable, ParseState::p_rteperminfos, ParseState::p_target_nsitem, Query::rtable, setTargetTable(), stmt, Query::targetList, transformFromClause(), transformReturningClause(), transformUpdateTargetList(), transformWhereClause(), and transformWithClause().

Referenced by transformStmt().

◆ transformUpdateTargetList()

List * transformUpdateTargetList ( ParseState pstate,
List origTlist 
)

Definition at line 2615 of file analyze.c.

2616{
2617 List *tlist = NIL;
2618 RTEPermissionInfo *target_perminfo;
2619 ListCell *orig_tl;
2620 ListCell *tl;
2621
2622 tlist = transformTargetList(pstate, origTlist,
2624
2625 /* Prepare to assign non-conflicting resnos to resjunk attributes */
2628
2629 /* Prepare non-junk columns for assignment to target table */
2630 target_perminfo = pstate->p_target_nsitem->p_perminfo;
2631 orig_tl = list_head(origTlist);
2632
2633 foreach(tl, tlist)
2634 {
2635 TargetEntry *tle = (TargetEntry *) lfirst(tl);
2636 ResTarget *origTarget;
2637 int attrno;
2638
2639 if (tle->resjunk)
2640 {
2641 /*
2642 * Resjunk nodes need no additional processing, but be sure they
2643 * have resnos that do not match any target columns; else rewriter
2644 * or planner might get confused. They don't need a resname
2645 * either.
2646 */
2647 tle->resno = (AttrNumber) pstate->p_next_resno++;
2648 tle->resname = NULL;
2649 continue;
2650 }
2651 if (orig_tl == NULL)
2652 elog(ERROR, "UPDATE target count mismatch --- internal error");
2653 origTarget = lfirst_node(ResTarget, orig_tl);
2654
2655 attrno = attnameAttNum(pstate->p_target_relation,
2656 origTarget->name, true);
2657 if (attrno == InvalidAttrNumber)
2658 ereport(ERROR,
2659 (errcode(ERRCODE_UNDEFINED_COLUMN),
2660 errmsg("column \"%s\" of relation \"%s\" does not exist",
2661 origTarget->name,
2663 (origTarget->indirection != NIL &&
2664 strcmp(origTarget->name, pstate->p_target_nsitem->p_names->aliasname) == 0) ?
2665 errhint("SET target columns cannot be qualified with the relation name.") : 0,
2666 parser_errposition(pstate, origTarget->location)));
2667
2668 updateTargetListEntry(pstate, tle, origTarget->name,
2669 attrno,
2670 origTarget->indirection,
2671 origTarget->location);
2672
2673 /* Mark the target column as requiring update permissions */
2674 target_perminfo->updatedCols = bms_add_member(target_perminfo->updatedCols,
2676
2677 orig_tl = lnext(origTlist, orig_tl);
2678 }
2679 if (orig_tl != NULL)
2680 elog(ERROR, "UPDATE target count mismatch --- internal error");
2681
2682 return tlist;
2683}
@ EXPR_KIND_UPDATE_SOURCE
Definition: parse_node.h:56
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
void updateTargetListEntry(ParseState *pstate, TargetEntry *tle, char *colname, int attrno, List *indirection, int location)
Definition: parse_target.c:622
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define RelationGetRelationName(relation)
Definition: rel.h:550
char * aliasname
Definition: primnodes.h:51
Bitmapset * updatedCols
Definition: parsenodes.h:1309

References Alias::aliasname, attnameAttNum(), bms_add_member(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, EXPR_KIND_UPDATE_SOURCE, FirstLowInvalidHeapAttributeNumber, ResTarget::indirection, InvalidAttrNumber, lfirst, lfirst_node, list_head(), lnext(), ResTarget::location, ResTarget::name, NIL, ParseNamespaceItem::p_names, ParseState::p_next_resno, ParseNamespaceItem::p_perminfo, ParseState::p_target_nsitem, ParseState::p_target_relation, parser_errposition(), RelationGetNumberOfAttributes, RelationGetRelationName, TargetEntry::resno, transformTargetList(), RTEPermissionInfo::updatedCols, and updateTargetListEntry().

Referenced by transformMergeStmt(), transformOnConflictClause(), and transformUpdateStmt().

◆ transformValuesClause()

static Query * transformValuesClause ( ParseState pstate,
SelectStmt stmt 
)
static

Definition at line 1609 of file analyze.c.

1610{
1611 Query *qry = makeNode(Query);
1612 List *exprsLists = NIL;
1613 List *coltypes = NIL;
1614 List *coltypmods = NIL;
1615 List *colcollations = NIL;
1616 List **colexprs = NULL;
1617 int sublist_length = -1;
1618 bool lateral = false;
1619 ParseNamespaceItem *nsitem;
1620 ListCell *lc;
1621 ListCell *lc2;
1622 int i;
1623
1624 qry->commandType = CMD_SELECT;
1625
1626 /* Most SELECT stuff doesn't apply in a VALUES clause */
1627 Assert(stmt->distinctClause == NIL);
1628 Assert(stmt->intoClause == NULL);
1629 Assert(stmt->targetList == NIL);
1630 Assert(stmt->fromClause == NIL);
1631 Assert(stmt->whereClause == NULL);
1632 Assert(stmt->groupClause == NIL);
1633 Assert(stmt->havingClause == NULL);
1634 Assert(stmt->windowClause == NIL);
1635 Assert(stmt->op == SETOP_NONE);
1636
1637 /* process the WITH clause independently of all else */
1638 if (stmt->withClause)
1639 {
1640 qry->hasRecursive = stmt->withClause->recursive;
1641 qry->cteList = transformWithClause(pstate, stmt->withClause);
1642 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1643 }
1644
1645 /*
1646 * For each row of VALUES, transform the raw expressions.
1647 *
1648 * Note that the intermediate representation we build is column-organized
1649 * not row-organized. That simplifies the type and collation processing
1650 * below.
1651 */
1652 foreach(lc, stmt->valuesLists)
1653 {
1654 List *sublist = (List *) lfirst(lc);
1655
1656 /*
1657 * Do basic expression transformation (same as a ROW() expr, but here
1658 * we disallow SetToDefault)
1659 */
1660 sublist = transformExpressionList(pstate, sublist,
1661 EXPR_KIND_VALUES, false);
1662
1663 /*
1664 * All the sublists must be the same length, *after* transformation
1665 * (which might expand '*' into multiple items). The VALUES RTE can't
1666 * handle anything different.
1667 */
1668 if (sublist_length < 0)
1669 {
1670 /* Remember post-transformation length of first sublist */
1671 sublist_length = list_length(sublist);
1672 /* and allocate array for per-column lists */
1673 colexprs = (List **) palloc0(sublist_length * sizeof(List *));
1674 }
1675 else if (sublist_length != list_length(sublist))
1676 {
1677 ereport(ERROR,
1678 (errcode(ERRCODE_SYNTAX_ERROR),
1679 errmsg("VALUES lists must all be the same length"),
1680 parser_errposition(pstate,
1681 exprLocation((Node *) sublist))));
1682 }
1683
1684 /* Build per-column expression lists */
1685 i = 0;
1686 foreach(lc2, sublist)
1687 {
1688 Node *col = (Node *) lfirst(lc2);
1689
1690 colexprs[i] = lappend(colexprs[i], col);
1691 i++;
1692 }
1693
1694 /* Release sub-list's cells to save memory */
1695 list_free(sublist);
1696
1697 /* Prepare an exprsLists element for this row */
1698 exprsLists = lappend(exprsLists, NIL);
1699 }
1700
1701 /*
1702 * Now resolve the common types of the columns, and coerce everything to
1703 * those types. Then identify the common typmod and common collation, if
1704 * any, of each column.
1705 *
1706 * We must do collation processing now because (1) assign_query_collations
1707 * doesn't process rangetable entries, and (2) we need to label the VALUES
1708 * RTE with column collations for use in the outer query. We don't
1709 * consider conflict of implicit collations to be an error here; instead
1710 * the column will just show InvalidOid as its collation, and you'll get a
1711 * failure later if that results in failure to resolve a collation.
1712 *
1713 * Note we modify the per-column expression lists in-place.
1714 */
1715 for (i = 0; i < sublist_length; i++)
1716 {
1717 Oid coltype;
1718 int32 coltypmod;
1719 Oid colcoll;
1720
1721 coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
1722
1723 foreach(lc, colexprs[i])
1724 {
1725 Node *col = (Node *) lfirst(lc);
1726
1727 col = coerce_to_common_type(pstate, col, coltype, "VALUES");
1728 lfirst(lc) = col;
1729 }
1730
1731 coltypmod = select_common_typmod(pstate, colexprs[i], coltype);
1732 colcoll = select_common_collation(pstate, colexprs[i], true);
1733
1734 coltypes = lappend_oid(coltypes, coltype);
1735 coltypmods = lappend_int(coltypmods, coltypmod);
1736 colcollations = lappend_oid(colcollations, colcoll);
1737 }
1738
1739 /*
1740 * Finally, rearrange the coerced expressions into row-organized lists.
1741 */
1742 for (i = 0; i < sublist_length; i++)
1743 {
1744 forboth(lc, colexprs[i], lc2, exprsLists)
1745 {
1746 Node *col = (Node *) lfirst(lc);
1747 List *sublist = lfirst(lc2);
1748
1749 sublist = lappend(sublist, col);
1750 lfirst(lc2) = sublist;
1751 }
1752 list_free(colexprs[i]);
1753 }
1754
1755 /*
1756 * Ordinarily there can't be any current-level Vars in the expression
1757 * lists, because the namespace was empty ... but if we're inside CREATE
1758 * RULE, then NEW/OLD references might appear. In that case we have to
1759 * mark the VALUES RTE as LATERAL.
1760 */
1761 if (pstate->p_rtable != NIL &&
1762 contain_vars_of_level((Node *) exprsLists, 0))
1763 lateral = true;
1764
1765 /*
1766 * Generate the VALUES RTE
1767 */
1768 nsitem = addRangeTableEntryForValues(pstate, exprsLists,
1769 coltypes, coltypmods, colcollations,
1770 NULL, lateral, true);
1771 addNSItemToQuery(pstate, nsitem, true, true, true);
1772
1773 /*
1774 * Generate a targetlist as though expanding "*"
1775 */
1776 Assert(pstate->p_next_resno == 1);
1777 qry->targetList = expandNSItemAttrs(pstate, nsitem, 0, true, -1);
1778
1779 /*
1780 * The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
1781 * VALUES, so cope.
1782 */
1783 qry->sortClause = transformSortClause(pstate,
1784 stmt->sortClause,
1785 &qry->targetList,
1787 false /* allow SQL92 rules */ );
1788
1789 qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1790 EXPR_KIND_OFFSET, "OFFSET",
1791 stmt->limitOption);
1792 qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1793 EXPR_KIND_LIMIT, "LIMIT",
1794 stmt->limitOption);
1795 qry->limitOption = stmt->limitOption;
1796
1797 if (stmt->lockingClause)
1798 ereport(ERROR,
1799 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1800 /*------
1801 translator: %s is a SQL row locking clause such as FOR UPDATE */
1802 errmsg("%s cannot be applied to VALUES",
1804 linitial(stmt->lockingClause))->strength))));
1805
1806 qry->rtable = pstate->p_rtable;
1807 qry->rteperminfos = pstate->p_rteperminfos;
1808 qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1809
1810 qry->hasSubLinks = pstate->p_hasSubLinks;
1811
1812 assign_query_collations(pstate, qry);
1813
1814 return qry;
1815}
void list_free(List *list)
Definition: list.c:1546
List * expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem, int sublevels_up, bool require_col_privs, int location)

References addNSItemToQuery(), addRangeTableEntryForValues(), Assert(), assign_query_collations(), CMD_SELECT, coerce_to_common_type(), Query::commandType, contain_vars_of_level(), Query::cteList, ereport, errcode(), errmsg(), ERROR, expandNSItemAttrs(), EXPR_KIND_LIMIT, EXPR_KIND_OFFSET, EXPR_KIND_ORDER_BY, EXPR_KIND_VALUES, exprLocation(), forboth, i, Query::jointree, lappend(), lappend_int(), lappend_oid(), LCS_asString(), lfirst, Query::limitCount, Query::limitOffset, Query::limitOption, linitial, list_free(), list_length(), makeFromExpr(), makeNode, NIL, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_joinlist, ParseState::p_next_resno, ParseState::p_rtable, ParseState::p_rteperminfos, palloc0(), parser_errposition(), Query::rtable, select_common_collation(), select_common_type(), select_common_typmod(), SETOP_NONE, Query::sortClause, stmt, Query::targetList, transformExpressionList(), transformLimitClause(), transformSortClause(), and transformWithClause().

Referenced by transformStmt().

Variable Documentation

◆ post_parse_analyze_hook