PostgreSQL Source Code  git master
analyze.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.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 "rewrite/rewriteManip.h"
#include "utils/backend_status.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/queryjumble.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 ListtransformReturningList (ParseState *pstate, List *returningList)
 
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)
 
QuerytransformTopLevelStmt (ParseState *pstate, RawStmt *parseTree)
 
QuerytransformStmt (ParseState *pstate, Node *parseTree)
 
bool analyze_requires_snapshot (RawStmt *parseTree)
 
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)
 
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

◆ analyze_requires_snapshot()

bool analyze_requires_snapshot ( RawStmt parseTree)

Definition at line 430 of file analyze.c.

431 {
432  bool result;
433 
434  switch (nodeTag(parseTree->stmt))
435  {
436  /*
437  * Optimizable statements
438  */
439  case T_InsertStmt:
440  case T_DeleteStmt:
441  case T_UpdateStmt:
442  case T_MergeStmt:
443  case T_SelectStmt:
444  case T_PLAssignStmt:
445  result = true;
446  break;
447 
448  /*
449  * Special cases
450  */
451  case T_DeclareCursorStmt:
452  case T_ExplainStmt:
453  case T_CreateTableAsStmt:
454  /* yes, because we must analyze the contained statement */
455  result = true;
456  break;
457 
458  default:
459  /* other utility statements don't have any real parse analysis */
460  result = false;
461  break;
462  }
463 
464  return result;
465 }
#define nodeTag(nodeptr)
Definition: nodes.h:578
@ T_DeleteStmt
Definition: nodes.h:333
@ T_UpdateStmt
Definition: nodes.h:334
@ T_ExplainStmt
Definition: nodes.h:371
@ T_InsertStmt
Definition: nodes.h:332
@ T_CreateTableAsStmt
Definition: nodes.h:372
@ T_DeclareCursorStmt
Definition: nodes.h:400
@ T_PLAssignStmt
Definition: nodes.h:338
@ T_SelectStmt
Definition: nodes.h:336
@ T_MergeStmt
Definition: nodes.h:335
Node * stmt
Definition: parsenodes.h:1903

References nodeTag, RawStmt::stmt, T_CreateTableAsStmt, T_DeclareCursorStmt, T_DeleteStmt, T_ExplainStmt, T_InsertStmt, T_MergeStmt, T_PLAssignStmt, T_SelectStmt, and T_UpdateStmt.

Referenced by BuildCachedPlan(), 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 3396 of file analyze.c.

3399 {
3400  RowMarkClause *rc;
3401 
3402  Assert(strength != LCS_NONE); /* else caller error */
3403 
3404  /* If it's an explicit clause, make sure hasForUpdate gets set */
3405  if (!pushedDown)
3406  qry->hasForUpdate = true;
3407 
3408  /* Check for pre-existing entry for same rtindex */
3409  if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
3410  {
3411  /*
3412  * If the same RTE is specified with more than one locking strength,
3413  * use the strongest. (Reasonable, since you can't take both a shared
3414  * and exclusive lock at the same time; it'll end up being exclusive
3415  * anyway.)
3416  *
3417  * Similarly, if the same RTE is specified with more than one lock
3418  * wait policy, consider that NOWAIT wins over SKIP LOCKED, which in
3419  * turn wins over waiting for the lock (the default). This is a bit
3420  * more debatable but raising an error doesn't seem helpful. (Consider
3421  * for instance SELECT FOR UPDATE NOWAIT from a view that internally
3422  * contains a plain FOR UPDATE spec.) Having NOWAIT win over SKIP
3423  * LOCKED is reasonable since the former throws an error in case of
3424  * coming across a locked tuple, which may be undesirable in some
3425  * cases but it seems better than silently returning inconsistent
3426  * results.
3427  *
3428  * And of course pushedDown becomes false if any clause is explicit.
3429  */
3430  rc->strength = Max(rc->strength, strength);
3431  rc->waitPolicy = Max(rc->waitPolicy, waitPolicy);
3432  rc->pushedDown &= pushedDown;
3433  return;
3434  }
3435 
3436  /* Make a new RowMarkClause */
3437  rc = makeNode(RowMarkClause);
3438  rc->rti = rtindex;
3439  rc->strength = strength;
3440  rc->waitPolicy = waitPolicy;
3441  rc->pushedDown = pushedDown;
3442  qry->rowMarks = lappend(qry->rowMarks, rc);
3443 }
#define Max(x, y)
Definition: c.h:980
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:336
@ LCS_NONE
Definition: lockoptions.h:23
#define makeNode(_type_)
Definition: nodes.h:621
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
List * rowMarks
Definition: parsenodes.h:180
bool hasForUpdate
Definition: parsenodes.h:141
LockClauseStrength strength
Definition: parsenodes.h:1432
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1433

References Assert(), get_parse_rowmark(), Query::hasForUpdate, 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 1170 of file analyze.c.

1172 {
1173  List *result = NIL;
1174  int attno;
1175  Var *var;
1176  TargetEntry *te;
1177 
1178  /*
1179  * Note that resnos of the tlist must correspond to attnos of the
1180  * underlying relation, hence we need entries for dropped columns too.
1181  */
1182  for (attno = 0; attno < RelationGetNumberOfAttributes(targetrel); attno++)
1183  {
1184  Form_pg_attribute attr = TupleDescAttr(targetrel->rd_att, attno);
1185  char *name;
1186 
1187  if (attr->attisdropped)
1188  {
1189  /*
1190  * can't use atttypid here, but it doesn't really matter what type
1191  * the Const claims to be.
1192  */
1193  var = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
1194  name = NULL;
1195  }
1196  else
1197  {
1198  var = makeVar(exclRelIndex, attno + 1,
1199  attr->atttypid, attr->atttypmod,
1200  attr->attcollation,
1201  0);
1202  name = pstrdup(NameStr(attr->attname));
1203  }
1204 
1205  te = makeTargetEntry((Expr *) var,
1206  attno + 1,
1207  name,
1208  false);
1209 
1210  result = lappend(result, te);
1211  }
1212 
1213  /*
1214  * Add a whole-row-Var entry to support references to "EXCLUDED.*". Like
1215  * the other entries in the EXCLUDED tlist, its resno must match the Var's
1216  * varattno, else the wrong things happen while resolving references in
1217  * setrefs.c. This is against normal conventions for targetlists, but
1218  * it's okay since we don't use this as a real tlist.
1219  */
1220  var = makeVar(exclRelIndex, InvalidAttrNumber,
1221  targetrel->rd_rel->reltype,
1222  -1, InvalidOid, 0);
1223  te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true);
1224  result = lappend(result, te);
1225 
1226  return result;
1227 }
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:681
const char * name
Definition: encode.c:561
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:239
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:338
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
char * pstrdup(const char *in)
Definition: mcxt.c:1305
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define NIL
Definition: pg_list.h:65
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:495
Definition: pg_list.h:51
TupleDesc rd_att
Definition: rel.h:110
Form_pg_class rd_rel
Definition: rel.h:109
Definition: primnodes.h:196
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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 3143 of file analyze.c.

3144 {
3145  Assert(strength != LCS_NONE); /* else caller error */
3146 
3147  if (qry->setOperations)
3148  ereport(ERROR,
3149  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3150  /*------
3151  translator: %s is a SQL row locking clause such as FOR UPDATE */
3152  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
3153  LCS_asString(strength))));
3154  if (qry->distinctClause != NIL)
3155  ereport(ERROR,
3156  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3157  /*------
3158  translator: %s is a SQL row locking clause such as FOR UPDATE */
3159  errmsg("%s is not allowed with DISTINCT clause",
3160  LCS_asString(strength))));
3161  if (qry->groupClause != NIL || qry->groupingSets != NIL)
3162  ereport(ERROR,
3163  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3164  /*------
3165  translator: %s is a SQL row locking clause such as FOR UPDATE */
3166  errmsg("%s is not allowed with GROUP BY clause",
3167  LCS_asString(strength))));
3168  if (qry->havingQual != NULL)
3169  ereport(ERROR,
3170  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3171  /*------
3172  translator: %s is a SQL row locking clause such as FOR UPDATE */
3173  errmsg("%s is not allowed with HAVING clause",
3174  LCS_asString(strength))));
3175  if (qry->hasAggs)
3176  ereport(ERROR,
3177  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3178  /*------
3179  translator: %s is a SQL row locking clause such as FOR UPDATE */
3180  errmsg("%s is not allowed with aggregate functions",
3181  LCS_asString(strength))));
3182  if (qry->hasWindowFuncs)
3183  ereport(ERROR,
3184  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3185  /*------
3186  translator: %s is a SQL row locking clause such as FOR UPDATE */
3187  errmsg("%s is not allowed with window functions",
3188  LCS_asString(strength))));
3189  if (qry->hasTargetSRFs)
3190  ereport(ERROR,
3191  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3192  /*------
3193  translator: %s is a SQL row locking clause such as FOR UPDATE */
3194  errmsg("%s is not allowed with set-returning functions in the target list",
3195  LCS_asString(strength))));
3196 }
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3118
bool hasWindowFuncs
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:182
bool hasTargetSRFs
Definition: parsenodes.h:136
List * groupClause
Definition: parsenodes.h:163
Node * havingQual
Definition: parsenodes.h:168
bool hasAggs
Definition: parsenodes.h:134
List * groupingSets
Definition: parsenodes.h:166
List * distinctClause
Definition: parsenodes.h:172

References Assert(), Query::distinctClause, ereport, errcode(), errmsg(), ERROR, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasTargetSRFs, Query::hasWindowFuncs, 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 1240 of file analyze.c.

1241 {
1242  if (expr == NULL)
1243  return -1;
1244  if (IsA(expr, RowExpr))
1245  return list_length(((RowExpr *) expr)->args);
1246  if (IsA(expr, Var))
1247  {
1248  Var *var = (Var *) expr;
1249  AttrNumber attnum = var->varattno;
1250 
1251  if (attnum > 0 && var->vartype == RECORDOID)
1252  {
1253  RangeTblEntry *rte;
1254 
1255  rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
1256  if (rte->rtekind == RTE_SUBQUERY)
1257  {
1258  /* Subselect-in-FROM: examine sub-select's output expr */
1260  attnum);
1261 
1262  if (ste == NULL || ste->resjunk)
1263  return -1;
1264  expr = (Node *) ste->expr;
1265  if (IsA(expr, RowExpr))
1266  return list_length(((RowExpr *) expr)->args);
1267  }
1268  }
1269  }
1270  return -1;
1271 }
int16 AttrNumber
Definition: attnum.h:21
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
RangeTblEntry * GetRTEByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
@ RTE_SUBQUERY
Definition: parsenodes.h:999
int16 attnum
Definition: pg_attribute.h:83
static int list_length(const List *l)
Definition: pg_list.h:149
Definition: nodes.h:574
List * targetList
Definition: parsenodes.h:155
Query * subquery
Definition: parsenodes.h:1050
RTEKind rtekind
Definition: parsenodes.h:1015
Expr * expr
Definition: primnodes.h:1716
bool resjunk
Definition: primnodes.h:1723
Oid vartype
Definition: primnodes.h:202
AttrNumber varattno
Definition: primnodes.h:200
int varno
Definition: primnodes.h:198
Index varlevelsup
Definition: primnodes.h:205

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

Referenced by transformInsertRow().

◆ determineRecursiveColTypes()

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

Definition at line 2275 of file analyze.c.

2276 {
2277  Node *node;
2278  int leftmostRTI;
2279  Query *leftmostQuery;
2280  List *targetList;
2281  ListCell *left_tlist;
2282  ListCell *nrtl;
2283  int next_resno;
2284 
2285  /*
2286  * Find leftmost leaf SELECT
2287  */
2288  node = larg;
2289  while (node && IsA(node, SetOperationStmt))
2290  node = ((SetOperationStmt *) node)->larg;
2291  Assert(node && IsA(node, RangeTblRef));
2292  leftmostRTI = ((RangeTblRef *) node)->rtindex;
2293  leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
2294  Assert(leftmostQuery != NULL);
2295 
2296  /*
2297  * Generate dummy targetlist using column names of leftmost select and
2298  * dummy result expressions of the non-recursive term.
2299  */
2300  targetList = NIL;
2301  next_resno = 1;
2302 
2303  forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
2304  {
2305  TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
2306  TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
2307  char *colName;
2308  TargetEntry *tle;
2309 
2310  Assert(!lefttle->resjunk);
2311  colName = pstrdup(lefttle->resname);
2312  tle = makeTargetEntry(nrtle->expr,
2313  next_resno++,
2314  colName,
2315  false);
2316  targetList = lappend(targetList, tle);
2317  }
2318 
2319  /* Now build CTE's output column info using dummy targetlist */
2320  analyzeCTETargetList(pstate, pstate->p_parent_cte, targetList);
2321 }
void analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
Definition: parse_cte.c:545
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define lfirst(lc)
Definition: pg_list.h:169
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
CommonTableExpr * p_parent_cte
Definition: parse_node.h:192
List * p_rtable
Definition: parse_node.h:183
char * resname
Definition: primnodes.h:1718

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

Referenced by transformSetOperationTree().

◆ LCS_asString()

const char* LCS_asString ( LockClauseStrength  strength)

Definition at line 3118 of file analyze.c.

3119 {
3120  switch (strength)
3121  {
3122  case LCS_NONE:
3123  Assert(false);
3124  break;
3125  case LCS_FORKEYSHARE:
3126  return "FOR KEY SHARE";
3127  case LCS_FORSHARE:
3128  return "FOR SHARE";
3129  case LCS_FORNOKEYUPDATE:
3130  return "FOR NO KEY UPDATE";
3131  case LCS_FORUPDATE:
3132  return "FOR UPDATE";
3133  }
3134  return "FOR some"; /* shouldn't happen */
3135 }
@ 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 1897 of file analyze.c.

1898 {
1900  Oid sortop;
1901  Oid eqop;
1902  bool hashable;
1903 
1904  /* determine the eqop and optional sortop */
1905  get_sort_group_operators(rescoltype,
1906  false, true, false,
1907  &sortop, &eqop, NULL,
1908  &hashable);
1909 
1910  /*
1911  * The type cache doesn't believe that record is hashable (see
1912  * cache_record_field_properties()), but if the caller really needs hash
1913  * support, we can assume it does. Worst case, if any components of the
1914  * record don't support hashing, we will fail at execution.
1915  */
1916  if (require_hash && (rescoltype == RECORDOID || rescoltype == RECORDARRAYOID))
1917  hashable = true;
1918 
1919  /* we don't have a tlist yet, so can't assign sortgrouprefs */
1920  grpcl->tleSortGroupRef = 0;
1921  grpcl->eqop = eqop;
1922  grpcl->sortop = sortop;
1923  grpcl->nulls_first = false; /* OK with or without sortop */
1924  grpcl->hashable = hashable;
1925 
1926  return grpcl;
1927 }
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:192
unsigned int Oid
Definition: postgres_ext.h:31
Index tleSortGroupRef
Definition: parsenodes.h:1305

References SortGroupClause::eqop, get_sort_group_operators(), SortGroupClause::hashable, makeNode, SortGroupClause::nulls_first, 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 106 of file analyze.c.

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

References Assert(), free_parsestate(), IsQueryIdEnabled(), JumbleQuery(), make_parsestate(), ParseState::p_queryEnv, ParseState::p_sourcetext, pgstat_report_query_id(), post_parse_analyze_hook, Query::queryId, 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 146 of file analyze.c.

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

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, Query::queryId, 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 187 of file analyze.c.

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

References Assert(), free_parsestate(), IsQueryIdEnabled(), JumbleQuery(), make_parsestate(), ParseState::p_queryEnv, ParseState::p_sourcetext, pgstat_report_query_id(), post_parse_analyze_hook, Query::queryId, 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 223 of file analyze.c.

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

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().

◆ transformCallStmt()

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

Definition at line 2993 of file analyze.c.

2994 {
2995  List *targs;
2996  ListCell *lc;
2997  Node *node;
2998  FuncExpr *fexpr;
2999  HeapTuple proctup;
3000  Datum proargmodes;
3001  bool isNull;
3002  List *outargs = NIL;
3003  Query *result;
3004 
3005  /*
3006  * First, do standard parse analysis on the procedure call and its
3007  * arguments, allowing us to identify the called procedure.
3008  */
3009  targs = NIL;
3010  foreach(lc, stmt->funccall->args)
3011  {
3012  targs = lappend(targs, transformExpr(pstate,
3013  (Node *) lfirst(lc),
3015  }
3016 
3017  node = ParseFuncOrColumn(pstate,
3018  stmt->funccall->funcname,
3019  targs,
3020  pstate->p_last_srf,
3021  stmt->funccall,
3022  true,
3023  stmt->funccall->location);
3024 
3025  assign_expr_collations(pstate, node);
3026 
3027  fexpr = castNode(FuncExpr, node);
3028 
3029  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
3030  if (!HeapTupleIsValid(proctup))
3031  elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
3032 
3033  /*
3034  * Expand the argument list to deal with named-argument notation and
3035  * default arguments. For ordinary FuncExprs this'd be done during
3036  * planning, but a CallStmt doesn't go through planning, and there seems
3037  * no good reason not to do it here.
3038  */
3039  fexpr->args = expand_function_arguments(fexpr->args,
3040  true,
3041  fexpr->funcresulttype,
3042  proctup);
3043 
3044  /* Fetch proargmodes; if it's null, there are no output args */
3045  proargmodes = SysCacheGetAttr(PROCOID, proctup,
3046  Anum_pg_proc_proargmodes,
3047  &isNull);
3048  if (!isNull)
3049  {
3050  /*
3051  * Split the list into input arguments in fexpr->args and output
3052  * arguments in stmt->outargs. INOUT arguments appear in both lists.
3053  */
3054  ArrayType *arr;
3055  int numargs;
3056  char *argmodes;
3057  List *inargs;
3058  int i;
3059 
3060  arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
3061  numargs = list_length(fexpr->args);
3062  if (ARR_NDIM(arr) != 1 ||
3063  ARR_DIMS(arr)[0] != numargs ||
3064  ARR_HASNULL(arr) ||
3065  ARR_ELEMTYPE(arr) != CHAROID)
3066  elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
3067  numargs);
3068  argmodes = (char *) ARR_DATA_PTR(arr);
3069 
3070  inargs = NIL;
3071  i = 0;
3072  foreach(lc, fexpr->args)
3073  {
3074  Node *n = lfirst(lc);
3075 
3076  switch (argmodes[i])
3077  {
3078  case PROARGMODE_IN:
3079  case PROARGMODE_VARIADIC:
3080  inargs = lappend(inargs, n);
3081  break;
3082  case PROARGMODE_OUT:
3083  outargs = lappend(outargs, n);
3084  break;
3085  case PROARGMODE_INOUT:
3086  inargs = lappend(inargs, n);
3087  outargs = lappend(outargs, copyObject(n));
3088  break;
3089  default:
3090  /* note we don't support PROARGMODE_TABLE */
3091  elog(ERROR, "invalid argmode %c for procedure",
3092  argmodes[i]);
3093  break;
3094  }
3095  i++;
3096  }
3097  fexpr->args = inargs;
3098  }
3099 
3100  stmt->funcexpr = fexpr;
3101  stmt->outargs = outargs;
3102 
3103  ReleaseSysCache(proctup);
3104 
3105  /* represent the command as a utility Query */
3106  result = makeNode(Query);
3107  result->commandType = CMD_UTILITY;
3108  result->utilityStmt = (Node *) stmt;
3109 
3110  return result;
3111 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
List * expand_function_arguments(List *args, bool include_out_arguments, Oid result_type, HeapTuple func_tuple)
Definition: clauses.c:4056
#define elog(elevel,...)
Definition: elog.h:218
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int i
Definition: isn.c:73
#define copyObject(obj)
Definition: nodes.h:689
@ CMD_UTILITY
Definition: nodes.h:726
#define castNode(_type_, nodeptr)
Definition: nodes.h:642
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:112
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:80
uintptr_t Datum
Definition: postgres.h:411
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
FuncCall * funccall
Definition: parsenodes.h:3387
FuncExpr * funcexpr
Definition: parsenodes.h:3388
List * outargs
Definition: parsenodes.h:3389
int location
Definition: parsenodes.h:390
List * funcname
Definition: parsenodes.h:380
List * args
Definition: parsenodes.h:381
Oid funcid
Definition: primnodes.h:504
List * args
Definition: primnodes.h:512
Oid funcresulttype
Definition: primnodes.h:505
Node * p_last_srf
Definition: parse_node.h:215
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:129
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
@ PROCOID
Definition: syscache.h:79

References FuncCall::args, 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, CallStmt::funccall, CallStmt::funcexpr, FuncExpr::funcid, FuncCall::funcname, FuncExpr::funcresulttype, HeapTupleIsValid, i, lappend(), lfirst, list_length(), FuncCall::location, makeNode, NIL, ObjectIdGetDatum, CallStmt::outargs, ParseState::p_last_srf, ParseFuncOrColumn(), PROCOID, ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), transformExpr(), and Query::utilityStmt.

Referenced by transformStmt().

◆ transformCreateTableAsStmt()

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

Definition at line 2918 of file analyze.c.

2919 {
2920  Query *result;
2921  Query *query;
2922 
2923  /* transform contained query, not allowing SELECT INTO */
2924  query = transformStmt(pstate, stmt->query);
2925  stmt->query = (Node *) query;
2926 
2927  /* additional work needed for CREATE MATERIALIZED VIEW */
2928  if (stmt->objtype == OBJECT_MATVIEW)
2929  {
2930  /*
2931  * Prohibit a data-modifying CTE in the query used to create a
2932  * materialized view. It's not sufficiently clear what the user would
2933  * want to happen if the MV is refreshed or incrementally maintained.
2934  */
2935  if (query->hasModifyingCTE)
2936  ereport(ERROR,
2937  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2938  errmsg("materialized views must not use data-modifying statements in WITH")));
2939 
2940  /*
2941  * Check whether any temporary database objects are used in the
2942  * creation query. It would be hard to refresh data or incrementally
2943  * maintain it if a source disappeared.
2944  */
2945  if (isQueryUsingTempRelation(query))
2946  ereport(ERROR,
2947  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2948  errmsg("materialized views must not use temporary tables or views")));
2949 
2950  /*
2951  * A materialized view would either need to save parameters for use in
2952  * maintaining/loading the data or prohibit them entirely. The latter
2953  * seems safer and more sane.
2954  */
2955  if (query_contains_extern_params(query))
2956  ereport(ERROR,
2957  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2958  errmsg("materialized views may not be defined using bound parameters")));
2959 
2960  /*
2961  * For now, we disallow unlogged materialized views, because it seems
2962  * like a bad idea for them to just go to empty after a crash. (If we
2963  * could mark them as unpopulated, that would be better, but that
2964  * requires catalog changes which crash recovery can't presently
2965  * handle.)
2966  */
2967  if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
2968  ereport(ERROR,
2969  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2970  errmsg("materialized views cannot be unlogged")));
2971 
2972  /*
2973  * At runtime, we'll need a copy of the parsed-but-not-rewritten Query
2974  * for purposes of creating the view's ON SELECT rule. We stash that
2975  * in the IntoClause because that's where intorel_startup() can
2976  * conveniently get it from.
2977  */
2978  stmt->into->viewQuery = (Node *) copyObject(query);
2979  }
2980 
2981  /* represent the command as a utility Query */
2982  result = makeNode(Query);
2983  result->commandType = CMD_UTILITY;
2984  result->utilityStmt = (Node *) stmt;
2985 
2986  return result;
2987 }
bool query_contains_extern_params(Query *query)
Definition: parse_param.c:334
bool isQueryUsingTempRelation(Query *query)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2157
IntoClause * into
Definition: parsenodes.h:3765
ObjectType objtype
Definition: parsenodes.h:3766
Node * viewQuery
Definition: primnodes.h:127
RangeVar * rel
Definition: primnodes.h:121
bool hasModifyingCTE
Definition: parsenodes.h:140
char relpersistence
Definition: primnodes.h:71

References CMD_UTILITY, Query::commandType, copyObject, ereport, errcode(), errmsg(), ERROR, Query::hasModifyingCTE, CreateTableAsStmt::into, isQueryUsingTempRelation(), makeNode, OBJECT_MATVIEW, CreateTableAsStmt::objtype, CreateTableAsStmt::query, query_contains_extern_params(), IntoClause::rel, RangeVar::relpersistence, transformStmt(), Query::utilityStmt, and IntoClause::viewQuery.

Referenced by transformStmt().

◆ transformDeclareCursorStmt()

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

Definition at line 2801 of file analyze.c.

2802 {
2803  Query *result;
2804  Query *query;
2805 
2806  if ((stmt->options & CURSOR_OPT_SCROLL) &&
2807  (stmt->options & CURSOR_OPT_NO_SCROLL))
2808  ereport(ERROR,
2809  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2810  /* translator: %s is a SQL keyword */
2811  errmsg("cannot specify both %s and %s",
2812  "SCROLL", "NO SCROLL")));
2813 
2814  if ((stmt->options & CURSOR_OPT_ASENSITIVE) &&
2815  (stmt->options & CURSOR_OPT_INSENSITIVE))
2816  ereport(ERROR,
2817  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2818  /* translator: %s is a SQL keyword */
2819  errmsg("cannot specify both %s and %s",
2820  "ASENSITIVE", "INSENSITIVE")));
2821 
2822  /* Transform contained query, not allowing SELECT INTO */
2823  query = transformStmt(pstate, stmt->query);
2824  stmt->query = (Node *) query;
2825 
2826  /* Grammar should not have allowed anything but SELECT */
2827  if (!IsA(query, Query) ||
2828  query->commandType != CMD_SELECT)
2829  elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
2830 
2831  /*
2832  * We also disallow data-modifying WITH in a cursor. (This could be
2833  * allowed, but the semantics of when the updates occur might be
2834  * surprising.)
2835  */
2836  if (query->hasModifyingCTE)
2837  ereport(ERROR,
2838  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2839  errmsg("DECLARE CURSOR must not contain data-modifying statements in WITH")));
2840 
2841  /* FOR UPDATE and WITH HOLD are not compatible */
2842  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
2843  ereport(ERROR,
2844  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2845  /*------
2846  translator: %s is a SQL row locking clause such as FOR UPDATE */
2847  errmsg("DECLARE CURSOR WITH HOLD ... %s is not supported",
2849  linitial(query->rowMarks))->strength)),
2850  errdetail("Holdable cursors must be READ ONLY.")));
2851 
2852  /* FOR UPDATE and SCROLL are not compatible */
2853  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL))
2854  ereport(ERROR,
2855  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2856  /*------
2857  translator: %s is a SQL row locking clause such as FOR UPDATE */
2858  errmsg("DECLARE SCROLL CURSOR ... %s is not supported",
2860  linitial(query->rowMarks))->strength)),
2861  errdetail("Scrollable cursors must be READ ONLY.")));
2862 
2863  /* FOR UPDATE and INSENSITIVE are not compatible */
2864  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE))
2865  ereport(ERROR,
2866  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2867  /*------
2868  translator: %s is a SQL row locking clause such as FOR UPDATE */
2869  errmsg("DECLARE INSENSITIVE CURSOR ... %s is not valid",
2871  linitial(query->rowMarks))->strength)),
2872  errdetail("Insensitive cursors must be READ ONLY.")));
2873 
2874  /* represent the command as a utility Query */
2875  result = makeNode(Query);
2876  result->commandType = CMD_UTILITY;
2877  result->utilityStmt = (Node *) stmt;
2878 
2879  return result;
2880 }
int errdetail(const char *fmt,...)
Definition: elog.c:1037
@ CMD_SELECT
Definition: nodes.h:721
#define CURSOR_OPT_INSENSITIVE
Definition: parsenodes.h:3170
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3168
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:3172
#define CURSOR_OPT_ASENSITIVE
Definition: parsenodes.h:3171
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3169
#define linitial(l)
Definition: pg_list.h:174

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, Query::hasModifyingCTE, IsA, LCS_asString(), linitial, makeNode, NIL, DeclareCursorStmt::options, DeclareCursorStmt::query, Query::rowMarks, transformStmt(), and Query::utilityStmt.

Referenced by transformStmt().

◆ transformDeleteStmt()

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

Definition at line 472 of file analyze.c.

473 {
474  Query *qry = makeNode(Query);
475  ParseNamespaceItem *nsitem;
476  Node *qual;
477 
478  qry->commandType = CMD_DELETE;
479 
480  /* process the WITH clause independently of all else */
481  if (stmt->withClause)
482  {
483  qry->hasRecursive = stmt->withClause->recursive;
484  qry->cteList = transformWithClause(pstate, stmt->withClause);
485  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
486  }
487 
488  /* set up range table with just the result rel */
489  qry->resultRelation = setTargetTable(pstate, stmt->relation,
490  stmt->relation->inh,
491  true,
492  ACL_DELETE);
493  nsitem = pstate->p_target_nsitem;
494 
495  /* there's no DISTINCT in DELETE */
496  qry->distinctClause = NIL;
497 
498  /* subqueries in USING cannot access the result relation */
499  nsitem->p_lateral_only = true;
500  nsitem->p_lateral_ok = false;
501 
502  /*
503  * The USING clause is non-standard SQL syntax, and is equivalent in
504  * functionality to the FROM list that can be specified for UPDATE. The
505  * USING keyword is used rather than FROM because FROM is already a
506  * keyword in the DELETE syntax.
507  */
508  transformFromClause(pstate, stmt->usingClause);
509 
510  /* remaining clauses can reference the result relation normally */
511  nsitem->p_lateral_only = false;
512  nsitem->p_lateral_ok = true;
513 
514  qual = transformWhereClause(pstate, stmt->whereClause,
515  EXPR_KIND_WHERE, "WHERE");
516 
517  qry->returningList = transformReturningList(pstate, stmt->returningList);
518 
519  /* done building the range table and jointree */
520  qry->rtable = pstate->p_rtable;
521  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
522 
523  qry->hasSubLinks = pstate->p_hasSubLinks;
524  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
525  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
526  qry->hasAggs = pstate->p_hasAggs;
527 
528  assign_query_collations(pstate, qry);
529 
530  /* this must be done after collations, for reliable comparison of exprs */
531  if (pstate->p_hasAggs)
532  parseCheckAggregates(pstate, qry);
533 
534  return qry;
535 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:286
@ CMD_DELETE
Definition: nodes.h:724
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1062
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:113
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:177
void assign_query_collations(ParseState *pstate, Query *query)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:109
@ EXPR_KIND_WHERE
Definition: parse_node.h:46
#define ACL_DELETE
Definition: parsenodes.h:85
static List * transformReturningList(ParseState *pstate, List *returningList)
Definition: analyze.c:2495
WithClause * withClause
Definition: parsenodes.h:1943
Node * whereClause
Definition: parsenodes.h:1941
RangeVar * relation
Definition: parsenodes.h:1939
List * usingClause
Definition: parsenodes.h:1940
List * returningList
Definition: parsenodes.h:1942
bool p_hasTargetSRFs
Definition: parse_node.h:211
bool p_hasWindowFuncs
Definition: parse_node.h:210
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:194
bool p_hasModifyingCTE
Definition: parse_node.h:213
bool p_hasSubLinks
Definition: parse_node.h:212
List * p_joinlist
Definition: parse_node.h:185
bool p_hasAggs
Definition: parse_node.h:209
FromExpr * jointree
Definition: parsenodes.h:149
List * returningList
Definition: parsenodes.h:161
List * cteList
Definition: parsenodes.h:146
List * rtable
Definition: parsenodes.h:148
int resultRelation
Definition: parsenodes.h:131
bool hasRecursive
Definition: parsenodes.h:139
bool hasSubLinks
Definition: parsenodes.h:137
bool inh
Definition: primnodes.h:69
bool recursive
Definition: parsenodes.h:1448

References ACL_DELETE, assign_query_collations(), CMD_DELETE, Query::commandType, Query::cteList, Query::distinctClause, EXPR_KIND_WHERE, Query::hasAggs, Query::hasModifyingCTE, Query::hasRecursive, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, RangeVar::inh, 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_target_nsitem, parseCheckAggregates(), WithClause::recursive, DeleteStmt::relation, Query::resultRelation, Query::returningList, DeleteStmt::returningList, Query::rtable, setTargetTable(), transformFromClause(), transformReturningList(), transformWhereClause(), transformWithClause(), DeleteStmt::usingClause, DeleteStmt::whereClause, and DeleteStmt::withClause.

Referenced by transformStmt().

◆ transformExplainStmt()

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

Definition at line 2894 of file analyze.c.

2895 {
2896  Query *result;
2897 
2898  /* transform contained query, allowing SELECT INTO */
2899  stmt->query = (Node *) transformOptionalSelectInto(pstate, stmt->query);
2900 
2901  /* represent the command as a utility Query */
2902  result = makeNode(Query);
2903  result->commandType = CMD_UTILITY;
2904  result->utilityStmt = (Node *) stmt;
2905 
2906  return result;
2907 }
static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
Definition: analyze.c:274
Node * query
Definition: parsenodes.h:3744

References CMD_UTILITY, Query::commandType, makeNode, ExplainStmt::query, 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 962 of file analyze.c.

965 {
966  List *result;
967  ListCell *lc;
968  ListCell *icols;
969  ListCell *attnos;
970 
971  /*
972  * Check length of expr list. It must not have more expressions than
973  * there are target columns. We allow fewer, but only if no explicit
974  * columns list was given (the remaining columns are implicitly
975  * defaulted). Note we must check this *after* transformation because
976  * that could expand '*' into multiple items.
977  */
978  if (list_length(exprlist) > list_length(icolumns))
979  ereport(ERROR,
980  (errcode(ERRCODE_SYNTAX_ERROR),
981  errmsg("INSERT has more expressions than target columns"),
982  parser_errposition(pstate,
983  exprLocation(list_nth(exprlist,
984  list_length(icolumns))))));
985  if (stmtcols != NIL &&
986  list_length(exprlist) < list_length(icolumns))
987  {
988  /*
989  * We can get here for cases like INSERT ... SELECT (a,b,c) FROM ...
990  * where the user accidentally created a RowExpr instead of separate
991  * columns. Add a suitable hint if that seems to be the problem,
992  * because the main error message is quite misleading for this case.
993  * (If there's no stmtcols, you'll get something about data type
994  * mismatch, which is less misleading so we don't worry about giving a
995  * hint in that case.)
996  */
997  ereport(ERROR,
998  (errcode(ERRCODE_SYNTAX_ERROR),
999  errmsg("INSERT has more target columns than expressions"),
1000  ((list_length(exprlist) == 1 &&
1001  count_rowexpr_columns(pstate, linitial(exprlist)) ==
1002  list_length(icolumns)) ?
1003  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),
1004  parser_errposition(pstate,
1005  exprLocation(list_nth(icolumns,
1006  list_length(exprlist))))));
1007  }
1008 
1009  /*
1010  * Prepare columns for assignment to target table.
1011  */
1012  result = NIL;
1013  forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
1014  {
1015  Expr *expr = (Expr *) lfirst(lc);
1016  ResTarget *col = lfirst_node(ResTarget, icols);
1017  int attno = lfirst_int(attnos);
1018 
1019  expr = transformAssignedExpr(pstate, expr,
1021  col->name,
1022  attno,
1023  col->indirection,
1024  col->location);
1025 
1026  if (strip_indirection)
1027  {
1028  while (expr)
1029  {
1030  if (IsA(expr, FieldStore))
1031  {
1032  FieldStore *fstore = (FieldStore *) expr;
1033 
1034  expr = (Expr *) linitial(fstore->newvals);
1035  }
1036  else if (IsA(expr, SubscriptingRef))
1037  {
1038  SubscriptingRef *sbsref = (SubscriptingRef *) expr;
1039 
1040  if (sbsref->refassgnexpr == NULL)
1041  break;
1042 
1043  expr = sbsref->refassgnexpr;
1044  }
1045  else
1046  break;
1047  }
1048  }
1049 
1050  result = lappend(result, expr);
1051  }
1052 
1053  return result;
1054 }
int errhint(const char *fmt,...)
Definition: elog.c:1151
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1343
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
@ 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:454
static int count_rowexpr_columns(ParseState *pstate, Node *expr)
Definition: analyze.c:1240
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define lfirst_int(lc)
Definition: pg_list.h:170
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:491
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
List * newvals
Definition: primnodes.h:847
int location
Definition: parsenodes.h:474
List * indirection
Definition: parsenodes.h:472
char * name
Definition: parsenodes.h:471
Expr * refassgnexpr
Definition: primnodes.h:460

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 542 of file analyze.c.

543 {
544  Query *qry = makeNode(Query);
545  SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt;
546  List *exprList = NIL;
547  bool isGeneralSelect;
548  List *sub_rtable;
549  List *sub_namespace;
550  List *icolumns;
551  List *attrnos;
552  ParseNamespaceItem *nsitem;
553  RangeTblEntry *rte;
554  ListCell *icols;
555  ListCell *attnos;
556  ListCell *lc;
557  bool isOnConflictUpdate;
558  AclMode targetPerms;
559 
560  /* There can't be any outer WITH to worry about */
561  Assert(pstate->p_ctenamespace == NIL);
562 
563  qry->commandType = CMD_INSERT;
564  pstate->p_is_insert = true;
565 
566  /* process the WITH clause independently of all else */
567  if (stmt->withClause)
568  {
569  qry->hasRecursive = stmt->withClause->recursive;
570  qry->cteList = transformWithClause(pstate, stmt->withClause);
571  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
572  }
573 
574  qry->override = stmt->override;
575 
576  isOnConflictUpdate = (stmt->onConflictClause &&
578 
579  /*
580  * We have three cases to deal with: DEFAULT VALUES (selectStmt == NULL),
581  * VALUES list, or general SELECT input. We special-case VALUES, both for
582  * efficiency and so we can handle DEFAULT specifications.
583  *
584  * The grammar allows attaching ORDER BY, LIMIT, FOR UPDATE, or WITH to a
585  * VALUES clause. If we have any of those, treat it as a general SELECT;
586  * so it will work, but you can't use DEFAULT items together with those.
587  */
588  isGeneralSelect = (selectStmt && (selectStmt->valuesLists == NIL ||
589  selectStmt->sortClause != NIL ||
590  selectStmt->limitOffset != NULL ||
591  selectStmt->limitCount != NULL ||
592  selectStmt->lockingClause != NIL ||
593  selectStmt->withClause != NULL));
594 
595  /*
596  * If a non-nil rangetable/namespace was passed in, and we are doing
597  * INSERT/SELECT, arrange to pass the rangetable/namespace down to the
598  * SELECT. This can only happen if we are inside a CREATE RULE, and in
599  * that case we want the rule's OLD and NEW rtable entries to appear as
600  * part of the SELECT's rtable, not as outer references for it. (Kluge!)
601  * The SELECT's joinlist is not affected however. We must do this before
602  * adding the target table to the INSERT's rtable.
603  */
604  if (isGeneralSelect)
605  {
606  sub_rtable = pstate->p_rtable;
607  pstate->p_rtable = NIL;
608  sub_namespace = pstate->p_namespace;
609  pstate->p_namespace = NIL;
610  }
611  else
612  {
613  sub_rtable = NIL; /* not used, but keep compiler quiet */
614  sub_namespace = NIL;
615  }
616 
617  /*
618  * Must get write lock on INSERT target table before scanning SELECT, else
619  * we will grab the wrong kind of initial lock if the target table is also
620  * mentioned in the SELECT part. Note that the target table is not added
621  * to the joinlist or namespace.
622  */
623  targetPerms = ACL_INSERT;
624  if (isOnConflictUpdate)
625  targetPerms |= ACL_UPDATE;
626  qry->resultRelation = setTargetTable(pstate, stmt->relation,
627  false, false, targetPerms);
628 
629  /* Validate stmt->cols list, or build default list if no list given */
630  icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
631  Assert(list_length(icolumns) == list_length(attrnos));
632 
633  /*
634  * Determine which variant of INSERT we have.
635  */
636  if (selectStmt == NULL)
637  {
638  /*
639  * We have INSERT ... DEFAULT VALUES. We can handle this case by
640  * emitting an empty targetlist --- all columns will be defaulted when
641  * the planner expands the targetlist.
642  */
643  exprList = NIL;
644  }
645  else if (isGeneralSelect)
646  {
647  /*
648  * We make the sub-pstate a child of the outer pstate so that it can
649  * see any Param definitions supplied from above. Since the outer
650  * pstate's rtable and namespace are presently empty, there are no
651  * side-effects of exposing names the sub-SELECT shouldn't be able to
652  * see.
653  */
654  ParseState *sub_pstate = make_parsestate(pstate);
655  Query *selectQuery;
656 
657  /*
658  * Process the source SELECT.
659  *
660  * It is important that this be handled just like a standalone SELECT;
661  * otherwise the behavior of SELECT within INSERT might be different
662  * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
663  * bugs of just that nature...)
664  *
665  * The sole exception is that we prevent resolving unknown-type
666  * outputs as TEXT. This does not change the semantics since if the
667  * column type matters semantically, it would have been resolved to
668  * something else anyway. Doing this lets us resolve such outputs as
669  * the target column's type, which we handle below.
670  */
671  sub_pstate->p_rtable = sub_rtable;
672  sub_pstate->p_joinexprs = NIL; /* sub_rtable has no joins */
673  sub_pstate->p_namespace = sub_namespace;
674  sub_pstate->p_resolve_unknowns = false;
675 
676  selectQuery = transformStmt(sub_pstate, stmt->selectStmt);
677 
678  free_parsestate(sub_pstate);
679 
680  /* The grammar should have produced a SELECT */
681  if (!IsA(selectQuery, Query) ||
682  selectQuery->commandType != CMD_SELECT)
683  elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT");
684 
685  /*
686  * Make the source be a subquery in the INSERT's rangetable, and add
687  * it to the INSERT's joinlist (but not the namespace).
688  */
689  nsitem = addRangeTableEntryForSubquery(pstate,
690  selectQuery,
691  makeAlias("*SELECT*", NIL),
692  false,
693  false);
694  addNSItemToQuery(pstate, nsitem, true, false, false);
695 
696  /*----------
697  * Generate an expression list for the INSERT that selects all the
698  * non-resjunk columns from the subquery. (INSERT's tlist must be
699  * separate from the subquery's tlist because we may add columns,
700  * insert datatype coercions, etc.)
701  *
702  * HACK: unknown-type constants and params in the SELECT's targetlist
703  * are copied up as-is rather than being referenced as subquery
704  * outputs. This is to ensure that when we try to coerce them to
705  * the target column's datatype, the right things happen (see
706  * special cases in coerce_type). Otherwise, this fails:
707  * INSERT INTO foo SELECT 'bar', ... FROM baz
708  *----------
709  */
710  exprList = NIL;
711  foreach(lc, selectQuery->targetList)
712  {
713  TargetEntry *tle = (TargetEntry *) lfirst(lc);
714  Expr *expr;
715 
716  if (tle->resjunk)
717  continue;
718  if (tle->expr &&
719  (IsA(tle->expr, Const) || IsA(tle->expr, Param)) &&
720  exprType((Node *) tle->expr) == UNKNOWNOID)
721  expr = tle->expr;
722  else
723  {
724  Var *var = makeVarFromTargetEntry(nsitem->p_rtindex, tle);
725 
726  var->location = exprLocation((Node *) tle->expr);
727  expr = (Expr *) var;
728  }
729  exprList = lappend(exprList, expr);
730  }
731 
732  /* Prepare row for assignment to target table */
733  exprList = transformInsertRow(pstate, exprList,
734  stmt->cols,
735  icolumns, attrnos,
736  false);
737  }
738  else if (list_length(selectStmt->valuesLists) > 1)
739  {
740  /*
741  * Process INSERT ... VALUES with multiple VALUES sublists. We
742  * generate a VALUES RTE holding the transformed expression lists, and
743  * build up a targetlist containing Vars that reference the VALUES
744  * RTE.
745  */
746  List *exprsLists = NIL;
747  List *coltypes = NIL;
748  List *coltypmods = NIL;
749  List *colcollations = NIL;
750  int sublist_length = -1;
751  bool lateral = false;
752 
753  Assert(selectStmt->intoClause == NULL);
754 
755  foreach(lc, selectStmt->valuesLists)
756  {
757  List *sublist = (List *) lfirst(lc);
758 
759  /*
760  * Do basic expression transformation (same as a ROW() expr, but
761  * allow SetToDefault at top level)
762  */
763  sublist = transformExpressionList(pstate, sublist,
764  EXPR_KIND_VALUES, true);
765 
766  /*
767  * All the sublists must be the same length, *after*
768  * transformation (which might expand '*' into multiple items).
769  * The VALUES RTE can't handle anything different.
770  */
771  if (sublist_length < 0)
772  {
773  /* Remember post-transformation length of first sublist */
774  sublist_length = list_length(sublist);
775  }
776  else if (sublist_length != list_length(sublist))
777  {
778  ereport(ERROR,
779  (errcode(ERRCODE_SYNTAX_ERROR),
780  errmsg("VALUES lists must all be the same length"),
781  parser_errposition(pstate,
782  exprLocation((Node *) sublist))));
783  }
784 
785  /*
786  * Prepare row for assignment to target table. We process any
787  * indirection on the target column specs normally but then strip
788  * off the resulting field/array assignment nodes, since we don't
789  * want the parsed statement to contain copies of those in each
790  * VALUES row. (It's annoying to have to transform the
791  * indirection specs over and over like this, but avoiding it
792  * would take some really messy refactoring of
793  * transformAssignmentIndirection.)
794  */
795  sublist = transformInsertRow(pstate, sublist,
796  stmt->cols,
797  icolumns, attrnos,
798  true);
799 
800  /*
801  * We must assign collations now because assign_query_collations
802  * doesn't process rangetable entries. We just assign all the
803  * collations independently in each row, and don't worry about
804  * whether they are consistent vertically. The outer INSERT query
805  * isn't going to care about the collations of the VALUES columns,
806  * so it's not worth the effort to identify a common collation for
807  * each one here. (But note this does have one user-visible
808  * consequence: INSERT ... VALUES won't complain about conflicting
809  * explicit COLLATEs in a column, whereas the same VALUES
810  * construct in another context would complain.)
811  */
812  assign_list_collations(pstate, sublist);
813 
814  exprsLists = lappend(exprsLists, sublist);
815  }
816 
817  /*
818  * Construct column type/typmod/collation lists for the VALUES RTE.
819  * Every expression in each column has been coerced to the type/typmod
820  * of the corresponding target column or subfield, so it's sufficient
821  * to look at the exprType/exprTypmod of the first row. We don't care
822  * about the collation labeling, so just fill in InvalidOid for that.
823  */
824  foreach(lc, (List *) linitial(exprsLists))
825  {
826  Node *val = (Node *) lfirst(lc);
827 
828  coltypes = lappend_oid(coltypes, exprType(val));
829  coltypmods = lappend_int(coltypmods, exprTypmod(val));
830  colcollations = lappend_oid(colcollations, InvalidOid);
831  }
832 
833  /*
834  * Ordinarily there can't be any current-level Vars in the expression
835  * lists, because the namespace was empty ... but if we're inside
836  * CREATE RULE, then NEW/OLD references might appear. In that case we
837  * have to mark the VALUES RTE as LATERAL.
838  */
839  if (list_length(pstate->p_rtable) != 1 &&
840  contain_vars_of_level((Node *) exprsLists, 0))
841  lateral = true;
842 
843  /*
844  * Generate the VALUES RTE
845  */
846  nsitem = addRangeTableEntryForValues(pstate, exprsLists,
847  coltypes, coltypmods, colcollations,
848  NULL, lateral, true);
849  addNSItemToQuery(pstate, nsitem, true, false, false);
850 
851  /*
852  * Generate list of Vars referencing the RTE
853  */
854  exprList = expandNSItemVars(nsitem, 0, -1, NULL);
855 
856  /*
857  * Re-apply any indirection on the target column specs to the Vars
858  */
859  exprList = transformInsertRow(pstate, exprList,
860  stmt->cols,
861  icolumns, attrnos,
862  false);
863  }
864  else
865  {
866  /*
867  * Process INSERT ... VALUES with a single VALUES sublist. We treat
868  * this case separately for efficiency. The sublist is just computed
869  * directly as the Query's targetlist, with no VALUES RTE. So it
870  * works just like a SELECT without any FROM.
871  */
872  List *valuesLists = selectStmt->valuesLists;
873 
874  Assert(list_length(valuesLists) == 1);
875  Assert(selectStmt->intoClause == NULL);
876 
877  /*
878  * Do basic expression transformation (same as a ROW() expr, but allow
879  * SetToDefault at top level)
880  */
881  exprList = transformExpressionList(pstate,
882  (List *) linitial(valuesLists),
884  true);
885 
886  /* Prepare row for assignment to target table */
887  exprList = transformInsertRow(pstate, exprList,
888  stmt->cols,
889  icolumns, attrnos,
890  false);
891  }
892 
893  /*
894  * Generate query's target list using the computed list of expressions.
895  * Also, mark all the target columns as needing insert permissions.
896  */
897  rte = pstate->p_target_nsitem->p_rte;
898  qry->targetList = NIL;
899  Assert(list_length(exprList) <= list_length(icolumns));
900  forthree(lc, exprList, icols, icolumns, attnos, attrnos)
901  {
902  Expr *expr = (Expr *) lfirst(lc);
903  ResTarget *col = lfirst_node(ResTarget, icols);
904  AttrNumber attr_num = (AttrNumber) lfirst_int(attnos);
905  TargetEntry *tle;
906 
907  tle = makeTargetEntry(expr,
908  attr_num,
909  col->name,
910  false);
911  qry->targetList = lappend(qry->targetList, tle);
912 
913  rte->insertedCols = bms_add_member(rte->insertedCols,
915  }
916 
917  /*
918  * If we have any clauses yet to process, set the query namespace to
919  * contain only the target relation, removing any entries added in a
920  * sub-SELECT or VALUES list.
921  */
922  if (stmt->onConflictClause || stmt->returningList)
923  {
924  pstate->p_namespace = NIL;
925  addNSItemToQuery(pstate, pstate->p_target_nsitem,
926  false, true, true);
927  }
928 
929  /* Process ON CONFLICT, if any. */
930  if (stmt->onConflictClause)
932  stmt->onConflictClause);
933 
934  /* Process RETURNING, if any. */
935  if (stmt->returningList)
937  stmt->returningList);
938 
939  /* done building the range table and jointree */
940  qry->rtable = pstate->p_rtable;
941  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
942 
943  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
944  qry->hasSubLinks = pstate->p_hasSubLinks;
945 
946  assign_query_collations(pstate, qry);
947 
948  return qry;
949 }
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738
long val
Definition: informix.c:664
List * lappend_int(List *list, int datum)
Definition: list.c:354
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:388
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:104
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:286
@ ONCONFLICT_UPDATE
Definition: nodes.h:873
@ CMD_INSERT
Definition: nodes.h:723
void assign_list_collations(ParseState *pstate, List *exprs)
@ EXPR_KIND_VALUES
Definition: parse_node.h:65
@ EXPR_KIND_VALUES_SINGLE
Definition: parse_node.h:66
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
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 * expandNSItemVars(ParseNamespaceItem *nsitem, int sublevels_up, int location, List **colnames)
List * checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
List * transformExpressionList(ParseState *pstate, List *exprlist, ParseExprKind exprKind, bool allowDefault)
Definition: parse_target.c:222
#define ACL_INSERT
Definition: parsenodes.h:82
#define ACL_UPDATE
Definition: parsenodes.h:84
uint32 AclMode
Definition: parsenodes.h:80
static OnConflictExpr * transformOnConflictClause(ParseState *pstate, OnConflictClause *onConflictClause)
Definition: analyze.c:1061
List * transformInsertRow(ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
Definition: analyze.c:962
OnConflictClause * onConflictClause
Definition: parsenodes.h:1926
Node * selectStmt
Definition: parsenodes.h:1925
OverridingKind override
Definition: parsenodes.h:1929
WithClause * withClause
Definition: parsenodes.h:1928
RangeVar * relation
Definition: parsenodes.h:1923
List * cols
Definition: parsenodes.h:1924
List * returningList
Definition: parsenodes.h:1927
OnConflictAction action
Definition: parsenodes.h:1476
RangeTblEntry * p_rte
Definition: parse_node.h:269
List * p_ctenamespace
Definition: parse_node.h:190
List * p_namespace
Definition: parse_node.h:187
bool p_is_insert
Definition: parse_node.h:195
List * p_joinexprs
Definition: parse_node.h:184
OnConflictExpr * onConflict
Definition: parsenodes.h:159
OverridingKind override
Definition: parsenodes.h:157
List * sortClause
Definition: parsenodes.h:2028
IntoClause * intoClause
Definition: parsenodes.h:2005
Node * limitOffset
Definition: parsenodes.h:2029
List * lockingClause
Definition: parsenodes.h:2032
Node * limitCount
Definition: parsenodes.h:2030
List * valuesLists
Definition: parsenodes.h:2022
WithClause * withClause
Definition: parsenodes.h:2033
int location
Definition: primnodes.h:210
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:438

References ACL_INSERT, ACL_UPDATE, OnConflictClause::action, addNSItemToQuery(), addRangeTableEntryForSubquery(), Assert(), checkInsertTargets(), CMD_INSERT, CMD_SELECT, InsertStmt::cols, Query::commandType, Query::cteList, elog, ERROR, TargetEntry::expr, exprLocation(), exprType(), free_parsestate(), Query::hasModifyingCTE, Query::hasRecursive, IsA, lappend(), lfirst, SelectStmt::limitCount, SelectStmt::limitOffset, list_length(), Var::location, SelectStmt::lockingClause, make_parsestate(), makeAlias(), makeNode, makeVarFromTargetEntry(), NIL, ONCONFLICT_UPDATE, InsertStmt::onConflictClause, Query::override, InsertStmt::override, ParseState::p_ctenamespace, ParseState::p_hasModifyingCTE, ParseState::p_is_insert, ParseState::p_joinexprs, ParseState::p_namespace, ParseState::p_resolve_unknowns, ParseState::p_rtable, WithClause::recursive, InsertStmt::relation, TargetEntry::resjunk, Query::resultRelation, InsertStmt::selectStmt, setTargetTable(), SelectStmt::sortClause, Query::targetList, transformInsertRow(), transformStmt(), transformWithClause(), SelectStmt::valuesLists, InsertStmt::withClause, and SelectStmt::withClause.

Referenced by transformStmt().

◆ transformLockingClause()

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

Definition at line 3207 of file analyze.c.

3209 {
3210  List *lockedRels = lc->lockedRels;
3211  ListCell *l;
3212  ListCell *rt;
3213  Index i;
3214  LockingClause *allrels;
3215 
3216  CheckSelectLocking(qry, lc->strength);
3217 
3218  /* make a clause we can pass down to subqueries to select all rels */
3219  allrels = makeNode(LockingClause);
3220  allrels->lockedRels = NIL; /* indicates all rels */
3221  allrels->strength = lc->strength;
3222  allrels->waitPolicy = lc->waitPolicy;
3223 
3224  if (lockedRels == NIL)
3225  {
3226  /*
3227  * Lock all regular tables used in query and its subqueries. We
3228  * examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD
3229  * in rules. This is a bit of an abuse of a mostly-obsolete flag, but
3230  * it's convenient. We can't rely on the namespace mechanism that has
3231  * largely replaced inFromCl, since for example we need to lock
3232  * base-relation RTEs even if they are masked by upper joins.
3233  */
3234  i = 0;
3235  foreach(rt, qry->rtable)
3236  {
3237  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3238 
3239  ++i;
3240  if (!rte->inFromCl)
3241  continue;
3242  switch (rte->rtekind)
3243  {
3244  case RTE_RELATION:
3245  applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3246  pushedDown);
3248  break;
3249  case RTE_SUBQUERY:
3250  applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3251  pushedDown);
3252 
3253  /*
3254  * FOR UPDATE/SHARE of subquery is propagated to all of
3255  * subquery's rels, too. We could do this later (based on
3256  * the marking of the subquery RTE) but it is convenient
3257  * to have local knowledge in each query level about which
3258  * rels need to be opened with RowShareLock.
3259  */
3260  transformLockingClause(pstate, rte->subquery,
3261  allrels, true);
3262  break;
3263  default:
3264  /* ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE RTEs */
3265  break;
3266  }
3267  }
3268  }
3269  else
3270  {
3271  /*
3272  * Lock just the named tables. As above, we allow locking any base
3273  * relation regardless of alias-visibility rules, so we need to
3274  * examine inFromCl to exclude OLD/NEW.
3275  */
3276  foreach(l, lockedRels)
3277  {
3278  RangeVar *thisrel = (RangeVar *) lfirst(l);
3279 
3280  /* For simplicity we insist on unqualified alias names here */
3281  if (thisrel->catalogname || thisrel->schemaname)
3282  ereport(ERROR,
3283  (errcode(ERRCODE_SYNTAX_ERROR),
3284  /*------
3285  translator: %s is a SQL row locking clause such as FOR UPDATE */
3286  errmsg("%s must specify unqualified relation names",
3287  LCS_asString(lc->strength)),
3288  parser_errposition(pstate, thisrel->location)));
3289 
3290  i = 0;
3291  foreach(rt, qry->rtable)
3292  {
3293  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3294 
3295  ++i;
3296  if (!rte->inFromCl)
3297  continue;
3298  if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
3299  {
3300  switch (rte->rtekind)
3301  {
3302  case RTE_RELATION:
3303  applyLockingClause(qry, i, lc->strength,
3304  lc->waitPolicy, pushedDown);
3306  break;
3307  case RTE_SUBQUERY:
3308  applyLockingClause(qry, i, lc->strength,
3309  lc->waitPolicy, pushedDown);
3310  /* see comment above */
3311  transformLockingClause(pstate, rte->subquery,
3312  allrels, true);
3313  break;
3314  case RTE_JOIN:
3315  ereport(ERROR,
3316  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3317  /*------
3318  translator: %s is a SQL row locking clause such as FOR UPDATE */
3319  errmsg("%s cannot be applied to a join",
3320  LCS_asString(lc->strength)),
3321  parser_errposition(pstate, thisrel->location)));
3322  break;
3323  case RTE_FUNCTION:
3324  ereport(ERROR,
3325  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3326  /*------
3327  translator: %s is a SQL row locking clause such as FOR UPDATE */
3328  errmsg("%s cannot be applied to a function",
3329  LCS_asString(lc->strength)),
3330  parser_errposition(pstate, thisrel->location)));
3331  break;
3332  case RTE_TABLEFUNC:
3333  ereport(ERROR,
3334  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3335  /*------
3336  translator: %s is a SQL row locking clause such as FOR UPDATE */
3337  errmsg("%s cannot be applied to a table function",
3338  LCS_asString(lc->strength)),
3339  parser_errposition(pstate, thisrel->location)));
3340  break;
3341  case RTE_VALUES:
3342  ereport(ERROR,
3343  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3344  /*------
3345  translator: %s is a SQL row locking clause such as FOR UPDATE */
3346  errmsg("%s cannot be applied to VALUES",
3347  LCS_asString(lc->strength)),
3348  parser_errposition(pstate, thisrel->location)));
3349  break;
3350  case RTE_CTE:
3351  ereport(ERROR,
3352  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3353  /*------
3354  translator: %s is a SQL row locking clause such as FOR UPDATE */
3355  errmsg("%s cannot be applied to a WITH query",
3356  LCS_asString(lc->strength)),
3357  parser_errposition(pstate, thisrel->location)));
3358  break;
3359  case RTE_NAMEDTUPLESTORE:
3360  ereport(ERROR,
3361  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3362  /*------
3363  translator: %s is a SQL row locking clause such as FOR UPDATE */
3364  errmsg("%s cannot be applied to a named tuplestore",
3365  LCS_asString(lc->strength)),
3366  parser_errposition(pstate, thisrel->location)));
3367  break;
3368 
3369  /* Shouldn't be possible to see RTE_RESULT here */
3370 
3371  default:
3372  elog(ERROR, "unrecognized RTE type: %d",
3373  (int) rte->rtekind);
3374  break;
3375  }
3376  break; /* out of foreach loop */
3377  }
3378  }
3379  if (rt == NULL)
3380  ereport(ERROR,
3382  /*------
3383  translator: %s is a SQL row locking clause such as FOR UPDATE */
3384  errmsg("relation \"%s\" in %s clause not found in FROM clause",
3385  thisrel->relname,
3386  LCS_asString(lc->strength)),
3387  parser_errposition(pstate, thisrel->location)));
3388  }
3389  }
3390 }
unsigned int Index
Definition: c.h:549
@ RTE_JOIN
Definition: parsenodes.h:1000
@ RTE_CTE
Definition: parsenodes.h:1004
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1005
@ RTE_VALUES
Definition: parsenodes.h:1003
@ RTE_FUNCTION
Definition: parsenodes.h:1001
@ RTE_TABLEFUNC
Definition: parsenodes.h:1002
@ RTE_RELATION
Definition: parsenodes.h:998
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:99
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:3207
void CheckSelectLocking(Query *qry, LockClauseStrength strength)
Definition: analyze.c:3143
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3396
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:81
char * aliasname
Definition: primnodes.h:42
List * lockedRels
Definition: parsenodes.h:784
LockClauseStrength strength
Definition: parsenodes.h:785
LockWaitPolicy waitPolicy
Definition: parsenodes.h:786
AclMode requiredPerms
Definition: parsenodes.h:1165
Alias * eref
Definition: parsenodes.h:1161
int location
Definition: primnodes.h:73
char * relname
Definition: primnodes.h:68
char * catalogname
Definition: primnodes.h:66
char * schemaname
Definition: primnodes.h:67

References ACL_SELECT_FOR_UPDATE, Alias::aliasname, applyLockingClause(), RangeVar::catalogname, CheckSelectLocking(), elog, RangeTblEntry::eref, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, i, RangeTblEntry::inFromCl, LCS_asString(), lfirst, RangeVar::location, LockingClause::lockedRels, makeNode, NIL, parser_errposition(), RangeVar::relname, RangeTblEntry::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, and LockingClause::waitPolicy.

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

◆ transformOnConflictClause()

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

Definition at line 1061 of file analyze.c.

1063 {
1064  ParseNamespaceItem *exclNSItem = NULL;
1065  List *arbiterElems;
1066  Node *arbiterWhere;
1067  Oid arbiterConstraint;
1068  List *onConflictSet = NIL;
1069  Node *onConflictWhere = NULL;
1070  int exclRelIndex = 0;
1071  List *exclRelTlist = NIL;
1072  OnConflictExpr *result;
1073 
1074  /*
1075  * If this is ON CONFLICT ... UPDATE, first create the range table entry
1076  * for the EXCLUDED pseudo relation, so that that will be present while
1077  * processing arbiter expressions. (You can't actually reference it from
1078  * there, but this provides a useful error message if you try.)
1079  */
1080  if (onConflictClause->action == ONCONFLICT_UPDATE)
1081  {
1082  Relation targetrel = pstate->p_target_relation;
1083  RangeTblEntry *exclRte;
1084 
1085  exclNSItem = addRangeTableEntryForRelation(pstate,
1086  targetrel,
1088  makeAlias("excluded", NIL),
1089  false, false);
1090  exclRte = exclNSItem->p_rte;
1091  exclRelIndex = exclNSItem->p_rtindex;
1092 
1093  /*
1094  * relkind is set to composite to signal that we're not dealing with
1095  * an actual relation, and no permission checks are required on it.
1096  * (We'll check the actual target relation, instead.)
1097  */
1098  exclRte->relkind = RELKIND_COMPOSITE_TYPE;
1099  exclRte->requiredPerms = 0;
1100  /* other permissions fields in exclRte are already empty */
1101 
1102  /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
1103  exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
1104  exclRelIndex);
1105  }
1106 
1107  /* Process the arbiter clause, ON CONFLICT ON (...) */
1108  transformOnConflictArbiter(pstate, onConflictClause, &arbiterElems,
1109  &arbiterWhere, &arbiterConstraint);
1110 
1111  /* Process DO UPDATE */
1112  if (onConflictClause->action == ONCONFLICT_UPDATE)
1113  {
1114  /*
1115  * Expressions in the UPDATE targetlist need to be handled like UPDATE
1116  * not INSERT. We don't need to save/restore this because all INSERT
1117  * expressions have been parsed already.
1118  */
1119  pstate->p_is_insert = false;
1120 
1121  /*
1122  * Add the EXCLUDED pseudo relation to the query namespace, making it
1123  * available in the UPDATE subexpressions.
1124  */
1125  addNSItemToQuery(pstate, exclNSItem, false, true, true);
1126 
1127  /*
1128  * Now transform the UPDATE subexpressions.
1129  */
1130  onConflictSet =
1131  transformUpdateTargetList(pstate, onConflictClause->targetList);
1132 
1133  onConflictWhere = transformWhereClause(pstate,
1134  onConflictClause->whereClause,
1135  EXPR_KIND_WHERE, "WHERE");
1136 
1137  /*
1138  * Remove the EXCLUDED pseudo relation from the query namespace, since
1139  * it's not supposed to be available in RETURNING. (Maybe someday we
1140  * could allow that, and drop this step.)
1141  */
1142  Assert((ParseNamespaceItem *) llast(pstate->p_namespace) == exclNSItem);
1143  pstate->p_namespace = list_delete_last(pstate->p_namespace);
1144  }
1145 
1146  /* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */
1147  result = makeNode(OnConflictExpr);
1148 
1149  result->action = onConflictClause->action;
1150  result->arbiterElems = arbiterElems;
1151  result->arbiterWhere = arbiterWhere;
1152  result->constraint = arbiterConstraint;
1153  result->onConflictSet = onConflictSet;
1154  result->onConflictWhere = onConflictWhere;
1155  result->exclRelIndex = exclRelIndex;
1156  result->exclRelTlist = exclRelTlist;
1157 
1158  return result;
1159 }
List * list_delete_last(List *list)
Definition: list.c:916
#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:2423
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1170
#define llast(l)
Definition: pg_list.h:194
List * arbiterElems
Definition: primnodes.h:1844
OnConflictAction action
Definition: primnodes.h:1841
List * onConflictSet
Definition: primnodes.h:1850
List * exclRelTlist
Definition: primnodes.h:1853
Node * onConflictWhere
Definition: primnodes.h:1851
Node * arbiterWhere
Definition: primnodes.h:1846
Relation p_target_relation
Definition: parse_node.h:193

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, RangeTblEntry::relkind, RangeTblEntry::requiredPerms, RowExclusiveLock, OnConflictClause::targetList, transformOnConflictArbiter(), transformUpdateTargetList(), transformWhereClause(), and OnConflictClause::whereClause.

◆ transformOptionalSelectInto()

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

Definition at line 274 of file analyze.c.

275 {
276  if (IsA(parseTree, SelectStmt))
277  {
278  SelectStmt *stmt = (SelectStmt *) parseTree;
279 
280  /* If it's a set-operation tree, drill down to leftmost SelectStmt */
281  while (stmt && stmt->op != SETOP_NONE)
282  stmt = stmt->larg;
283  Assert(stmt && IsA(stmt, SelectStmt) && stmt->larg == NULL);
284 
285  if (stmt->intoClause)
286  {
288 
289  ctas->query = parseTree;
290  ctas->into = stmt->intoClause;
291  ctas->objtype = OBJECT_TABLE;
292  ctas->is_select_into = true;
293 
294  /*
295  * Remove the intoClause from the SelectStmt. This makes it safe
296  * for transformSelectStmt to complain if it finds intoClause set
297  * (implying that the INTO appeared in a disallowed place).
298  */
299  stmt->intoClause = NULL;
300 
301  parseTree = (Node *) ctas;
302  }
303  }
304 
305  return transformStmt(pstate, parseTree);
306 }
@ SETOP_NONE
Definition: parsenodes.h:1990
@ OBJECT_TABLE
Definition: parsenodes.h:2175
struct SelectStmt * larg
Definition: parsenodes.h:2040
SetOperation op
Definition: parsenodes.h:2038

References Assert(), CreateTableAsStmt::into, SelectStmt::intoClause, CreateTableAsStmt::is_select_into, IsA, SelectStmt::larg, makeNode, OBJECT_TABLE, CreateTableAsStmt::objtype, SelectStmt::op, CreateTableAsStmt::query, SETOP_NONE, and transformStmt().

Referenced by transformExplainStmt(), and transformTopLevelStmt().

◆ transformPLAssignStmt()

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

Definition at line 2553 of file analyze.c.

2554 {
2555  Query *qry = makeNode(Query);
2556  ColumnRef *cref = makeNode(ColumnRef);
2557  List *indirection = stmt->indirection;
2558  int nnames = stmt->nnames;
2559  SelectStmt *sstmt = stmt->val;
2560  Node *target;
2561  Oid targettype;
2562  int32 targettypmod;
2563  Oid targetcollation;
2564  List *tlist;
2565  TargetEntry *tle;
2566  Oid type_id;
2567  Node *qual;
2568  ListCell *l;
2569 
2570  /*
2571  * First, construct a ColumnRef for the target variable. If the target
2572  * has more than one dotted name, we have to pull the extra names out of
2573  * the indirection list.
2574  */
2575  cref->fields = list_make1(makeString(stmt->name));
2576  cref->location = stmt->location;
2577  if (nnames > 1)
2578  {
2579  /* avoid munging the raw parsetree */
2580  indirection = list_copy(indirection);
2581  while (--nnames > 0 && indirection != NIL)
2582  {
2583  Node *ind = (Node *) linitial(indirection);
2584 
2585  if (!IsA(ind, String))
2586  elog(ERROR, "invalid name count in PLAssignStmt");
2587  cref->fields = lappend(cref->fields, ind);
2588  indirection = list_delete_first(indirection);
2589  }
2590  }
2591 
2592  /*
2593  * Transform the target reference. Typically we will get back a Param
2594  * node, but there's no reason to be too picky about its type.
2595  */
2596  target = transformExpr(pstate, (Node *) cref,
2598  targettype = exprType(target);
2599  targettypmod = exprTypmod(target);
2600  targetcollation = exprCollation(target);
2601 
2602  /*
2603  * The rest mostly matches transformSelectStmt, except that we needn't
2604  * consider WITH or INTO, and we build a targetlist our own way.
2605  */
2606  qry->commandType = CMD_SELECT;
2607  pstate->p_is_insert = false;
2608 
2609  /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
2610  pstate->p_locking_clause = sstmt->lockingClause;
2611 
2612  /* make WINDOW info available for window functions, too */
2613  pstate->p_windowdefs = sstmt->windowClause;
2614 
2615  /* process the FROM clause */
2616  transformFromClause(pstate, sstmt->fromClause);
2617 
2618  /* initially transform the targetlist as if in SELECT */
2619  tlist = transformTargetList(pstate, sstmt->targetList,
2621 
2622  /* we should have exactly one targetlist item */
2623  if (list_length(tlist) != 1)
2624  ereport(ERROR,
2625  (errcode(ERRCODE_SYNTAX_ERROR),
2626  errmsg_plural("assignment source returned %d column",
2627  "assignment source returned %d columns",
2628  list_length(tlist),
2629  list_length(tlist))));
2630 
2631  tle = linitial_node(TargetEntry, tlist);
2632 
2633  /*
2634  * This next bit is similar to transformAssignedExpr; the key difference
2635  * is we use COERCION_PLPGSQL not COERCION_ASSIGNMENT.
2636  */
2637  type_id = exprType((Node *) tle->expr);
2638 
2640 
2641  if (indirection)
2642  {
2643  tle->expr = (Expr *)
2645  target,
2646  stmt->name,
2647  false,
2648  targettype,
2649  targettypmod,
2650  targetcollation,
2651  indirection,
2652  list_head(indirection),
2653  (Node *) tle->expr,
2655  exprLocation(target));
2656  }
2657  else if (targettype != type_id &&
2658  (targettype == RECORDOID || ISCOMPLEX(targettype)) &&
2659  (type_id == RECORDOID || ISCOMPLEX(type_id)))
2660  {
2661  /*
2662  * Hack: do not let coerce_to_target_type() deal with inconsistent
2663  * composite types. Just pass the expression result through as-is,
2664  * and let the PL/pgSQL executor do the conversion its way. This is
2665  * rather bogus, but it's needed for backwards compatibility.
2666  */
2667  }
2668  else
2669  {
2670  /*
2671  * For normal non-qualified target column, do type checking and
2672  * coercion.
2673  */
2674  Node *orig_expr = (Node *) tle->expr;
2675 
2676  tle->expr = (Expr *)
2677  coerce_to_target_type(pstate,
2678  orig_expr, type_id,
2679  targettype, targettypmod,
2682  -1);
2683  /* With COERCION_PLPGSQL, this error is probably unreachable */
2684  if (tle->expr == NULL)
2685  ereport(ERROR,
2686  (errcode(ERRCODE_DATATYPE_MISMATCH),
2687  errmsg("variable \"%s\" is of type %s"
2688  " but expression is of type %s",
2689  stmt->name,
2690  format_type_be(targettype),
2691  format_type_be(type_id)),
2692  errhint("You will need to rewrite or cast the expression."),
2693  parser_errposition(pstate, exprLocation(orig_expr))));
2694  }
2695 
2696  pstate->p_expr_kind = EXPR_KIND_NONE;
2697 
2698  qry->targetList = list_make1(tle);
2699 
2700  /* transform WHERE */
2701  qual = transformWhereClause(pstate, sstmt->whereClause,
2702  EXPR_KIND_WHERE, "WHERE");
2703 
2704  /* initial processing of HAVING clause is much like WHERE clause */
2705  qry->havingQual = transformWhereClause(pstate, sstmt->havingClause,
2706  EXPR_KIND_HAVING, "HAVING");
2707 
2708  /*
2709  * Transform sorting/grouping stuff. Do ORDER BY first because both
2710  * transformGroupClause and transformDistinctClause need the results. Note
2711  * that these functions can also change the targetList, so it's passed to
2712  * them by reference.
2713  */
2714  qry->sortClause = transformSortClause(pstate,
2715  sstmt->sortClause,
2716  &qry->targetList,
2718  false /* allow SQL92 rules */ );
2719 
2720  qry->groupClause = transformGroupClause(pstate,
2721  sstmt->groupClause,
2722  &qry->groupingSets,
2723  &qry->targetList,
2724  qry->sortClause,
2726  false /* allow SQL92 rules */ );
2727 
2728  if (sstmt->distinctClause == NIL)
2729  {
2730  qry->distinctClause = NIL;
2731  qry->hasDistinctOn = false;
2732  }
2733  else if (linitial(sstmt->distinctClause) == NULL)
2734  {
2735  /* We had SELECT DISTINCT */
2737  &qry->targetList,
2738  qry->sortClause,
2739  false);
2740  qry->hasDistinctOn = false;
2741  }
2742  else
2743  {
2744  /* We had SELECT DISTINCT ON */
2746  sstmt->distinctClause,
2747  &qry->targetList,
2748  qry->sortClause);
2749  qry->hasDistinctOn = true;
2750  }
2751 
2752  /* transform LIMIT */
2753  qry->limitOffset = transformLimitClause(pstate, sstmt->limitOffset,
2754  EXPR_KIND_OFFSET, "OFFSET",
2755  sstmt->limitOption);
2756  qry->limitCount = transformLimitClause(pstate, sstmt->limitCount,
2757  EXPR_KIND_LIMIT, "LIMIT",
2758  sstmt->limitOption);
2759  qry->limitOption = sstmt->limitOption;
2760 
2761  /* transform window clauses after we have seen all window functions */
2763  pstate->p_windowdefs,
2764  &qry->targetList);
2765 
2766  qry->rtable = pstate->p_rtable;
2767  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2768 
2769  qry->hasSubLinks = pstate->p_hasSubLinks;
2770  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2771  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2772  qry->hasAggs = pstate->p_hasAggs;
2773 
2774  foreach(l, sstmt->lockingClause)
2775  {
2776  transformLockingClause(pstate, qry,
2777  (LockingClause *) lfirst(l), false);
2778  }
2779 
2780  assign_query_collations(pstate, qry);
2781 
2782  /* this must be done after collations, for reliable comparison of exprs */
2783  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
2784  parseCheckAggregates(pstate, qry);
2785 
2786  return qry;
2787 }
signed int int32
Definition: c.h:429
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1014
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
List * list_copy(const List *oldlist)
Definition: list.c:1532
List * list_delete_first(List *list)
Definition: list.c:902
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
List * transformWindowDefinitions(ParseState *pstate, List *windowdefs, List **targetlist)
List * transformDistinctOnClause(ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
Node * transformLimitClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName, LimitOption limitOption)
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
List * transformGroupClause(ParseState *pstate, List *grouplist, List **groupingSets, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99)
List * transformDistinctClause(ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
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
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:123
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:685
#define ISCOMPLEX(typeid)
Definition: parse_type.h:58
#define linitial_node(type, l)
Definition: pg_list.h:177
#define list_make1(x1)
Definition: pg_list.h:206
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:494
@ COERCION_PLPGSQL
Definition: primnodes.h:474
int location
Definition: parsenodes.h:253
List * fields
Definition: parsenodes.h:252
SelectStmt * val
Definition: parsenodes.h:2107
List * indirection
Definition: parsenodes.h:2105
ParseExprKind p_expr_kind
Definition: parse_node.h:197
List * p_windowdefs
Definition: parse_node.h:196
List * p_locking_clause
Definition: parse_node.h:200
Node * limitCount
Definition: parsenodes.h:177
Node * limitOffset
Definition: parsenodes.h:176
bool hasDistinctOn
Definition: parsenodes.h:138
LimitOption limitOption
Definition: parsenodes.h:178
List * windowClause
Definition: parsenodes.h:170
List * sortClause
Definition: parsenodes.h:174
LimitOption limitOption
Definition: parsenodes.h:2031
List * targetList
Definition: parsenodes.h:2006
List * fromClause
Definition: parsenodes.h:2007
List * groupClause
Definition: parsenodes.h:2009
Node * havingClause
Definition: parsenodes.h:2011
List * windowClause
Definition: parsenodes.h:2012
List * distinctClause
Definition: parsenodes.h:2003
Node * whereClause
Definition: parsenodes.h:2008
Definition: value.h:58
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, Query::hasAggs, Query::hasDistinctOn, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, SelectStmt::havingClause, Query::havingQual, PLAssignStmt::indirection, 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, PLAssignStmt::location, SelectStmt::lockingClause, makeFromExpr(), makeNode, makeString(), PLAssignStmt::name, NIL, PLAssignStmt::nnames, 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_windowdefs, parseCheckAggregates(), parser_errposition(), Query::rtable, Query::sortClause, SelectStmt::sortClause, Query::targetList, SelectStmt::targetList, transformAssignmentIndirection(), transformDistinctClause(), transformDistinctOnClause(), transformExpr(), transformFromClause(), transformGroupClause(), transformLimitClause(), transformLockingClause(), transformSortClause(), transformTargetList(), transformWhereClause(), transformWindowDefinitions(), PLAssignStmt::val, SelectStmt::whereClause, Query::windowClause, and SelectStmt::windowClause.

Referenced by transformStmt().

◆ transformReturningList()

static List * transformReturningList ( ParseState pstate,
List returningList 
)
static

Definition at line 2495 of file analyze.c.

2496 {
2497  List *rlist;
2498  int save_next_resno;
2499 
2500  if (returningList == NIL)
2501  return NIL; /* nothing to do */
2502 
2503  /*
2504  * We need to assign resnos starting at one in the RETURNING list. Save
2505  * and restore the main tlist's value of p_next_resno, just in case
2506  * someone looks at it later (probably won't happen).
2507  */
2508  save_next_resno = pstate->p_next_resno;
2509  pstate->p_next_resno = 1;
2510 
2511  /* transform RETURNING identically to a SELECT targetlist */
2512  rlist = transformTargetList(pstate, returningList, EXPR_KIND_RETURNING);
2513 
2514  /*
2515  * Complain if the nonempty tlist expanded to nothing (which is possible
2516  * if it contains only a star-expansion of a zero-column table). If we
2517  * allow this, the parsed Query will look like it didn't have RETURNING,
2518  * with results that would probably surprise the user.
2519  */
2520  if (rlist == NIL)
2521  ereport(ERROR,
2522  (errcode(ERRCODE_SYNTAX_ERROR),
2523  errmsg("RETURNING must have at least one column"),
2524  parser_errposition(pstate,
2525  exprLocation(linitial(returningList)))));
2526 
2527  /* mark column origins */
2528  markTargetListOrigins(pstate, rlist);
2529 
2530  /* resolve any still-unresolved output columns as being type text */
2531  if (pstate->p_resolve_unknowns)
2532  resolveTargetListUnknowns(pstate, rlist);
2533 
2534  /* restore state */
2535  pstate->p_next_resno = save_next_resno;
2536 
2537  return rlist;
2538 }
@ EXPR_KIND_RETURNING
Definition: parse_node.h:64
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
Definition: parse_target.c:290
void markTargetListOrigins(ParseState *pstate, List *targetlist)
Definition: parse_target.c:320
int p_next_resno
Definition: parse_node.h:198

References ereport, errcode(), errmsg(), ERROR, EXPR_KIND_RETURNING, exprLocation(), linitial, markTargetListOrigins(), NIL, ParseState::p_next_resno, ParseState::p_resolve_unknowns, parser_errposition(), resolveTargetListUnknowns(), and transformTargetList().

Referenced by transformDeleteStmt(), and transformUpdateStmt().

◆ transformReturnStmt()

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

Definition at line 2329 of file analyze.c.

2330 {
2331  Query *qry = makeNode(Query);
2332 
2333  qry->commandType = CMD_SELECT;
2334  qry->isReturn = true;
2335 
2337  1, NULL, false));
2338 
2339  if (pstate->p_resolve_unknowns)
2340  resolveTargetListUnknowns(pstate, qry->targetList);
2341  qry->rtable = pstate->p_rtable;
2342  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2343  qry->hasSubLinks = pstate->p_hasSubLinks;
2344  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2345  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2346  qry->hasAggs = pstate->p_hasAggs;
2347 
2348  assign_query_collations(pstate, qry);
2349 
2350  return qry;
2351 }
bool isReturn
Definition: parsenodes.h:144
Node * returnval
Definition: parsenodes.h:2089

References assign_query_collations(), CMD_SELECT, Query::commandType, EXPR_KIND_SELECT_TARGET, Query::hasAggs, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::isReturn, 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, resolveTargetListUnknowns(), ReturnStmt::returnval, Query::rtable, Query::targetList, and transformExpr().

Referenced by transformStmt().

◆ transformSelectStmt()

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

Definition at line 1282 of file analyze.c.

1283 {
1284  Query *qry = makeNode(Query);
1285  Node *qual;
1286  ListCell *l;
1287 
1288  qry->commandType = CMD_SELECT;
1289 
1290  /* process the WITH clause independently of all else */
1291  if (stmt->withClause)
1292  {
1293  qry->hasRecursive = stmt->withClause->recursive;
1294  qry->cteList = transformWithClause(pstate, stmt->withClause);
1295  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1296  }
1297 
1298  /* Complain if we get called from someplace where INTO is not allowed */
1299  if (stmt->intoClause)
1300  ereport(ERROR,
1301  (errcode(ERRCODE_SYNTAX_ERROR),
1302  errmsg("SELECT ... INTO is not allowed here"),
1303  parser_errposition(pstate,
1304  exprLocation((Node *) stmt->intoClause))));
1305 
1306  /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
1307  pstate->p_locking_clause = stmt->lockingClause;
1308 
1309  /* make WINDOW info available for window functions, too */
1310  pstate->p_windowdefs = stmt->windowClause;
1311 
1312  /* process the FROM clause */
1313  transformFromClause(pstate, stmt->fromClause);
1314 
1315  /* transform targetlist */
1316  qry->targetList = transformTargetList(pstate, stmt->targetList,
1318 
1319  /* mark column origins */
1320  markTargetListOrigins(pstate, qry->targetList);
1321 
1322  /* transform WHERE */
1323  qual = transformWhereClause(pstate, stmt->whereClause,
1324  EXPR_KIND_WHERE, "WHERE");
1325 
1326  /* initial processing of HAVING clause is much like WHERE clause */
1327  qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
1328  EXPR_KIND_HAVING, "HAVING");
1329 
1330  /*
1331  * Transform sorting/grouping stuff. Do ORDER BY first because both
1332  * transformGroupClause and transformDistinctClause need the results. Note
1333  * that these functions can also change the targetList, so it's passed to
1334  * them by reference.
1335  */
1336  qry->sortClause = transformSortClause(pstate,
1337  stmt->sortClause,
1338  &qry->targetList,
1340  false /* allow SQL92 rules */ );
1341 
1342  qry->groupClause = transformGroupClause(pstate,
1343  stmt->groupClause,
1344  &qry->groupingSets,
1345  &qry->targetList,
1346  qry->sortClause,
1348  false /* allow SQL92 rules */ );
1349  qry->groupDistinct = stmt->groupDistinct;
1350 
1351  if (stmt->distinctClause == NIL)
1352  {
1353  qry->distinctClause = NIL;
1354  qry->hasDistinctOn = false;
1355  }
1356  else if (linitial(stmt->distinctClause) == NULL)
1357  {
1358  /* We had SELECT DISTINCT */
1360  &qry->targetList,
1361  qry->sortClause,
1362  false);
1363  qry->hasDistinctOn = false;
1364  }
1365  else
1366  {
1367  /* We had SELECT DISTINCT ON */
1369  stmt->distinctClause,
1370  &qry->targetList,
1371  qry->sortClause);
1372  qry->hasDistinctOn = true;
1373  }
1374 
1375  /* transform LIMIT */
1376  qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1377  EXPR_KIND_OFFSET, "OFFSET",
1378  stmt->limitOption);
1379  qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1380  EXPR_KIND_LIMIT, "LIMIT",
1381  stmt->limitOption);
1382  qry->limitOption = stmt->limitOption;
1383 
1384  /* transform window clauses after we have seen all window functions */
1386  pstate->p_windowdefs,
1387  &qry->targetList);
1388 
1389  /* resolve any still-unresolved output columns as being type text */
1390  if (pstate->p_resolve_unknowns)
1391  resolveTargetListUnknowns(pstate, qry->targetList);
1392 
1393  qry->rtable = pstate->p_rtable;
1394  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
1395 
1396  qry->hasSubLinks = pstate->p_hasSubLinks;
1397  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1398  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1399  qry->hasAggs = pstate->p_hasAggs;
1400 
1401  foreach(l, stmt->lockingClause)
1402  {
1403  transformLockingClause(pstate, qry,
1404  (LockingClause *) lfirst(l), false);
1405  }
1406 
1407  assign_query_collations(pstate, qry);
1408 
1409  /* this must be done after collations, for reliable comparison of exprs */
1410  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1411  parseCheckAggregates(pstate, qry);
1412 
1413  return qry;
1414 }
bool groupDistinct
Definition: parsenodes.h:164
bool groupDistinct
Definition: parsenodes.h:2010

References assign_query_collations(), CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, SelectStmt::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(), SelectStmt::fromClause, Query::groupClause, SelectStmt::groupClause, Query::groupDistinct, SelectStmt::groupDistinct, Query::groupingSets, Query::hasAggs, Query::hasDistinctOn, Query::hasModifyingCTE, Query::hasRecursive, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, SelectStmt::havingClause, Query::havingQual, SelectStmt::intoClause, Query::jointree, lfirst, Query::limitCount, SelectStmt::limitCount, Query::limitOffset, SelectStmt::limitOffset, Query::limitOption, SelectStmt::limitOption, linitial, SelectStmt::lockingClause, 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_windowdefs, parseCheckAggregates(), parser_errposition(), WithClause::recursive, resolveTargetListUnknowns(), Query::rtable, Query::sortClause, SelectStmt::sortClause, Query::targetList, SelectStmt::targetList, transformDistinctClause(), transformDistinctOnClause(), transformFromClause(), transformGroupClause(), transformLimitClause(), transformLockingClause(), transformSortClause(), transformTargetList(), transformWhereClause(), transformWindowDefinitions(), transformWithClause(), SelectStmt::whereClause, Query::windowClause, SelectStmt::windowClause, and SelectStmt::withClause.

Referenced by transformStmt().

◆ transformSetOperationStmt()

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

Definition at line 1642 of file analyze.c.

1643 {
1644  Query *qry = makeNode(Query);
1645  SelectStmt *leftmostSelect;
1646  int leftmostRTI;
1647  Query *leftmostQuery;
1648  SetOperationStmt *sostmt;
1649  List *sortClause;
1650  Node *limitOffset;
1651  Node *limitCount;
1652  List *lockingClause;
1653  WithClause *withClause;
1654  Node *node;
1655  ListCell *left_tlist,
1656  *lct,
1657  *lcm,
1658  *lcc,
1659  *l;
1660  List *targetvars,
1661  *targetnames,
1662  *sv_namespace;
1663  int sv_rtable_length;
1664  ParseNamespaceItem *jnsitem;
1665  ParseNamespaceColumn *sortnscolumns;
1666  int sortcolindex;
1667  int tllen;
1668 
1669  qry->commandType = CMD_SELECT;
1670 
1671  /*
1672  * Find leftmost leaf SelectStmt. We currently only need to do this in
1673  * order to deliver a suitable error message if there's an INTO clause
1674  * there, implying the set-op tree is in a context that doesn't allow
1675  * INTO. (transformSetOperationTree would throw error anyway, but it
1676  * seems worth the trouble to throw a different error for non-leftmost
1677  * INTO, so we produce that error in transformSetOperationTree.)
1678  */
1679  leftmostSelect = stmt->larg;
1680  while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
1681  leftmostSelect = leftmostSelect->larg;
1682  Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
1683  leftmostSelect->larg == NULL);
1684  if (leftmostSelect->intoClause)
1685  ereport(ERROR,
1686  (errcode(ERRCODE_SYNTAX_ERROR),
1687  errmsg("SELECT ... INTO is not allowed here"),
1688  parser_errposition(pstate,
1689  exprLocation((Node *) leftmostSelect->intoClause))));
1690 
1691  /*
1692  * We need to extract ORDER BY and other top-level clauses here and not
1693  * let transformSetOperationTree() see them --- else it'll just recurse
1694  * right back here!
1695  */
1696  sortClause = stmt->sortClause;
1697  limitOffset = stmt->limitOffset;
1698  limitCount = stmt->limitCount;
1699  lockingClause = stmt->lockingClause;
1700  withClause = stmt->withClause;
1701 
1702  stmt->sortClause = NIL;
1703  stmt->limitOffset = NULL;
1704  stmt->limitCount = NULL;
1705  stmt->lockingClause = NIL;
1706  stmt->withClause = NULL;
1707 
1708  /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1709  if (lockingClause)
1710  ereport(ERROR,
1711  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1712  /*------
1713  translator: %s is a SQL row locking clause such as FOR UPDATE */
1714  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1716  linitial(lockingClause))->strength))));
1717 
1718  /* Process the WITH clause independently of all else */
1719  if (withClause)
1720  {
1721  qry->hasRecursive = withClause->recursive;
1722  qry->cteList = transformWithClause(pstate, withClause);
1723  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1724  }
1725 
1726  /*
1727  * Recursively transform the components of the tree.
1728  */
1729  sostmt = castNode(SetOperationStmt,
1730  transformSetOperationTree(pstate, stmt, true, NULL));
1731  Assert(sostmt);
1732  qry->setOperations = (Node *) sostmt;
1733 
1734  /*
1735  * Re-find leftmost SELECT (now it's a sub-query in rangetable)
1736  */
1737  node = sostmt->larg;
1738  while (node && IsA(node, SetOperationStmt))
1739  node = ((SetOperationStmt *) node)->larg;
1740  Assert(node && IsA(node, RangeTblRef));
1741  leftmostRTI = ((RangeTblRef *) node)->rtindex;
1742  leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
1743  Assert(leftmostQuery != NULL);
1744 
1745  /*
1746  * Generate dummy targetlist for outer query using column names of
1747  * leftmost select and common datatypes/collations of topmost set
1748  * operation. Also make lists of the dummy vars and their names for use
1749  * in parsing ORDER BY.
1750  *
1751  * Note: we use leftmostRTI as the varno of the dummy variables. It
1752  * shouldn't matter too much which RT index they have, as long as they
1753  * have one that corresponds to a real RT entry; else funny things may
1754  * happen when the tree is mashed by rule rewriting.
1755  */
1756  qry->targetList = NIL;
1757  targetvars = NIL;
1758  targetnames = NIL;
1759  sortnscolumns = (ParseNamespaceColumn *)
1760  palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
1761  sortcolindex = 0;
1762 
1763  forfour(lct, sostmt->colTypes,
1764  lcm, sostmt->colTypmods,
1765  lcc, sostmt->colCollations,
1766  left_tlist, leftmostQuery->targetList)
1767  {
1768  Oid colType = lfirst_oid(lct);
1769  int32 colTypmod = lfirst_int(lcm);
1770  Oid colCollation = lfirst_oid(lcc);
1771  TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
1772  char *colName;
1773  TargetEntry *tle;
1774  Var *var;
1775 
1776  Assert(!lefttle->resjunk);
1777  colName = pstrdup(lefttle->resname);
1778  var = makeVar(leftmostRTI,
1779  lefttle->resno,
1780  colType,
1781  colTypmod,
1782  colCollation,
1783  0);
1784  var->location = exprLocation((Node *) lefttle->expr);
1785  tle = makeTargetEntry((Expr *) var,
1786  (AttrNumber) pstate->p_next_resno++,
1787  colName,
1788  false);
1789  qry->targetList = lappend(qry->targetList, tle);
1790  targetvars = lappend(targetvars, var);
1791  targetnames = lappend(targetnames, makeString(colName));
1792  sortnscolumns[sortcolindex].p_varno = leftmostRTI;
1793  sortnscolumns[sortcolindex].p_varattno = lefttle->resno;
1794  sortnscolumns[sortcolindex].p_vartype = colType;
1795  sortnscolumns[sortcolindex].p_vartypmod = colTypmod;
1796  sortnscolumns[sortcolindex].p_varcollid = colCollation;
1797  sortnscolumns[sortcolindex].p_varnosyn = leftmostRTI;
1798  sortnscolumns[sortcolindex].p_varattnosyn = lefttle->resno;
1799  sortcolindex++;
1800  }
1801 
1802  /*
1803  * As a first step towards supporting sort clauses that are expressions
1804  * using the output columns, generate a namespace entry that makes the
1805  * output columns visible. A Join RTE node is handy for this, since we
1806  * can easily control the Vars generated upon matches.
1807  *
1808  * Note: we don't yet do anything useful with such cases, but at least
1809  * "ORDER BY upper(foo)" will draw the right error message rather than
1810  * "foo not found".
1811  */
1812  sv_rtable_length = list_length(pstate->p_rtable);
1813 
1814  jnsitem = addRangeTableEntryForJoin(pstate,
1815  targetnames,
1816  sortnscolumns,
1817  JOIN_INNER,
1818  0,
1819  targetvars,
1820  NIL,
1821  NIL,
1822  NULL,
1823  NULL,
1824  false);
1825 
1826  sv_namespace = pstate->p_namespace;
1827  pstate->p_namespace = NIL;
1828 
1829  /* add jnsitem to column namespace only */
1830  addNSItemToQuery(pstate, jnsitem, false, false, true);
1831 
1832  /*
1833  * For now, we don't support resjunk sort clauses on the output of a
1834  * setOperation tree --- you can only use the SQL92-spec options of
1835  * selecting an output column by name or number. Enforce by checking that
1836  * transformSortClause doesn't add any items to tlist.
1837  */
1838  tllen = list_length(qry->targetList);
1839 
1840  qry->sortClause = transformSortClause(pstate,
1841  sortClause,
1842  &qry->targetList,
1844  false /* allow SQL92 rules */ );
1845 
1846  /* restore namespace, remove join RTE from rtable */
1847  pstate->p_namespace = sv_namespace;
1848  pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
1849 
1850  if (tllen != list_length(qry->targetList))
1851  ereport(ERROR,
1852  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1853  errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
1854  errdetail("Only result column names can be used, not expressions or functions."),
1855  errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
1856  parser_errposition(pstate,
1857  exprLocation(list_nth(qry->targetList, tllen)))));
1858 
1859  qry->limitOffset = transformLimitClause(pstate, limitOffset,
1860  EXPR_KIND_OFFSET, "OFFSET",
1861  stmt->limitOption);
1862  qry->limitCount = transformLimitClause(pstate, limitCount,
1863  EXPR_KIND_LIMIT, "LIMIT",
1864  stmt->limitOption);
1865  qry->limitOption = stmt->limitOption;
1866 
1867  qry->rtable = pstate->p_rtable;
1868  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1869 
1870  qry->hasSubLinks = pstate->p_hasSubLinks;
1871  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1872  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1873  qry->hasAggs = pstate->p_hasAggs;
1874 
1875  foreach(l, lockingClause)
1876  {
1877  transformLockingClause(pstate, qry,
1878  (LockingClause *) lfirst(l), false);
1879  }
1880 
1881  assign_query_collations(pstate, qry);
1882 
1883  /* this must be done after collations, for reliable comparison of exprs */
1884  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1885  parseCheckAggregates(pstate, qry);
1886 
1887  return qry;
1888 }
List * list_truncate(List *list, int new_size)
Definition: list.c:610
void * palloc0(Size size)
Definition: mcxt.c:1099
@ JOIN_INNER
Definition: nodes.h:749
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:1944
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:503
#define lfirst_oid(lc)
Definition: pg_list.h:171
AttrNumber p_varattno
Definition: parse_node.h:303
AttrNumber p_varattnosyn
Definition: parse_node.h:308
List * colCollations
Definition: parsenodes.h:2077
AttrNumber resno
Definition: primnodes.h:1717

References addNSItemToQuery(), addRangeTableEntryForJoin(), Assert(), assign_query_collations(), castNode, CMD_SELECT, SetOperationStmt::colCollations, SetOperationStmt::colTypes, SetOperationStmt::colTypmods, 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::hasAggs, Query::hasModifyingCTE, Query::hasRecursive, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, SelectStmt::intoClause, IsA, JOIN_INNER, Query::jointree, lappend(), SelectStmt::larg, SetOperationStmt::larg, LCS_asString(), lfirst, lfirst_int, lfirst_oid, Query::limitCount, SelectStmt::limitCount, Query::limitOffset, SelectStmt::limitOffset, Query::limitOption, SelectStmt::limitOption, linitial, list_length(), list_nth(), list_truncate(), Var::location, SelectStmt::lockingClause, 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, 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::resjunk, TargetEntry::resname, TargetEntry::resno, rt_fetch, Query::rtable, SETOP_NONE, Query::setOperations, Query::sortClause, SelectStmt::sortClause, Query::targetList, transformLimitClause(), transformLockingClause(), transformSetOperationTree(), transformSortClause(), transformWithClause(), and SelectStmt::withClause.

Referenced by transformStmt().

◆ transformSetOperationTree()

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

Definition at line 1944 of file analyze.c.

1946 {
1947  bool isLeaf;
1948 
1949  Assert(stmt && IsA(stmt, SelectStmt));
1950 
1951  /* Guard against stack overflow due to overly complex set-expressions */
1953 
1954  /*
1955  * Validity-check both leaf and internal SELECTs for disallowed ops.
1956  */
1957  if (stmt->intoClause)
1958  ereport(ERROR,
1959  (errcode(ERRCODE_SYNTAX_ERROR),
1960  errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
1961  parser_errposition(pstate,
1962  exprLocation((Node *) stmt->intoClause))));
1963 
1964  /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1965  if (stmt->lockingClause)
1966  ereport(ERROR,
1967  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1968  /*------
1969  translator: %s is a SQL row locking clause such as FOR UPDATE */
1970  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1972  linitial(stmt->lockingClause))->strength))));
1973 
1974  /*
1975  * If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
1976  * or WITH clauses attached, we need to treat it like a leaf node to
1977  * generate an independent sub-Query tree. Otherwise, it can be
1978  * represented by a SetOperationStmt node underneath the parent Query.
1979  */
1980  if (stmt->op == SETOP_NONE)
1981  {
1982  Assert(stmt->larg == NULL && stmt->rarg == NULL);
1983  isLeaf = true;
1984  }
1985  else
1986  {
1987  Assert(stmt->larg != NULL && stmt->rarg != NULL);
1988  if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
1989  stmt->lockingClause || stmt->withClause)
1990  isLeaf = true;
1991  else
1992  isLeaf = false;
1993  }
1994 
1995  if (isLeaf)
1996  {
1997  /* Process leaf SELECT */
1998  Query *selectQuery;
1999  char selectName[32];
2000  ParseNamespaceItem *nsitem;
2001  RangeTblRef *rtr;
2002  ListCell *tl;
2003 
2004  /*
2005  * Transform SelectStmt into a Query.
2006  *
2007  * This works the same as SELECT transformation normally would, except
2008  * that we prevent resolving unknown-type outputs as TEXT. This does
2009  * not change the subquery's semantics since if the column type
2010  * matters semantically, it would have been resolved to something else
2011  * anyway. Doing this lets us resolve such outputs using
2012  * select_common_type(), below.
2013  *
2014  * Note: previously transformed sub-queries don't affect the parsing
2015  * of this sub-query, because they are not in the toplevel pstate's
2016  * namespace list.
2017  */
2018  selectQuery = parse_sub_analyze((Node *) stmt, pstate,
2019  NULL, false, false);
2020 
2021  /*
2022  * Check for bogus references to Vars on the current query level (but
2023  * upper-level references are okay). Normally this can't happen
2024  * because the namespace will be empty, but it could happen if we are
2025  * inside a rule.
2026  */
2027  if (pstate->p_namespace)
2028  {
2029  if (contain_vars_of_level((Node *) selectQuery, 1))
2030  ereport(ERROR,
2031  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2032  errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
2033  parser_errposition(pstate,
2034  locate_var_of_level((Node *) selectQuery, 1))));
2035  }
2036 
2037  /*
2038  * Extract a list of the non-junk TLEs for upper-level processing.
2039  */
2040  if (targetlist)
2041  {
2042  *targetlist = NIL;
2043  foreach(tl, selectQuery->targetList)
2044  {
2045  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2046 
2047  if (!tle->resjunk)
2048  *targetlist = lappend(*targetlist, tle);
2049  }
2050  }
2051 
2052  /*
2053  * Make the leaf query be a subquery in the top-level rangetable.
2054  */
2055  snprintf(selectName, sizeof(selectName), "*SELECT* %d",
2056  list_length(pstate->p_rtable) + 1);
2057  nsitem = addRangeTableEntryForSubquery(pstate,
2058  selectQuery,
2059  makeAlias(selectName, NIL),
2060  false,
2061  false);
2062 
2063  /*
2064  * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
2065  */
2066  rtr = makeNode(RangeTblRef);
2067  rtr->rtindex = nsitem->p_rtindex;
2068  return (Node *) rtr;
2069  }
2070  else
2071  {
2072  /* Process an internal node (set operation node) */
2074  List *ltargetlist;
2075  List *rtargetlist;
2076  ListCell *ltl;
2077  ListCell *rtl;
2078  const char *context;
2079  bool recursive = (pstate->p_parent_cte &&
2080  pstate->p_parent_cte->cterecursive);
2081 
2082  context = (stmt->op == SETOP_UNION ? "UNION" :
2083  (stmt->op == SETOP_INTERSECT ? "INTERSECT" :
2084  "EXCEPT"));
2085 
2086  op->op = stmt->op;
2087  op->all = stmt->all;
2088 
2089  /*
2090  * Recursively transform the left child node.
2091  */
2092  op->larg = transformSetOperationTree(pstate, stmt->larg,
2093  false,
2094  &ltargetlist);
2095 
2096  /*
2097  * If we are processing a recursive union query, now is the time to
2098  * examine the non-recursive term's output columns and mark the
2099  * containing CTE as having those result columns. We should do this
2100  * only at the topmost setop of the CTE, of course.
2101  */
2102  if (isTopLevel && recursive)
2103  determineRecursiveColTypes(pstate, op->larg, ltargetlist);
2104 
2105  /*
2106  * Recursively transform the right child node.
2107  */
2108  op->rarg = transformSetOperationTree(pstate, stmt->rarg,
2109  false,
2110  &rtargetlist);
2111 
2112  /*
2113  * Verify that the two children have the same number of non-junk
2114  * columns, and determine the types of the merged output columns.
2115  */
2116  if (list_length(ltargetlist) != list_length(rtargetlist))
2117  ereport(ERROR,
2118  (errcode(ERRCODE_SYNTAX_ERROR),
2119  errmsg("each %s query must have the same number of columns",
2120  context),
2121  parser_errposition(pstate,
2122  exprLocation((Node *) rtargetlist))));
2123 
2124  if (targetlist)
2125  *targetlist = NIL;
2126  op->colTypes = NIL;
2127  op->colTypmods = NIL;
2128  op->colCollations = NIL;
2129  op->groupClauses = NIL;
2130  forboth(ltl, ltargetlist, rtl, rtargetlist)
2131  {
2132  TargetEntry *ltle = (TargetEntry *) lfirst(ltl);
2133  TargetEntry *rtle = (TargetEntry *) lfirst(rtl);
2134  Node *lcolnode = (Node *) ltle->expr;
2135  Node *rcolnode = (Node *) rtle->expr;
2136  Oid lcoltype = exprType(lcolnode);
2137  Oid rcoltype = exprType(rcolnode);
2138  Node *bestexpr;
2139  int bestlocation;
2140  Oid rescoltype;
2141  int32 rescoltypmod;
2142  Oid rescolcoll;
2143 
2144  /* select common type, same as CASE et al */
2145  rescoltype = select_common_type(pstate,
2146  list_make2(lcolnode, rcolnode),
2147  context,
2148  &bestexpr);
2149  bestlocation = exprLocation(bestexpr);
2150 
2151  /*
2152  * Verify the coercions are actually possible. If not, we'd fail
2153  * later anyway, but we want to fail now while we have sufficient
2154  * context to produce an error cursor position.
2155  *
2156  * For all non-UNKNOWN-type cases, we verify coercibility but we
2157  * don't modify the child's expression, for fear of changing the
2158  * child query's semantics.
2159  *
2160  * If a child expression is an UNKNOWN-type Const or Param, we
2161  * want to replace it with the coerced expression. This can only
2162  * happen when the child is a leaf set-op node. It's safe to
2163  * replace the expression because if the child query's semantics
2164  * depended on the type of this output column, it'd have already
2165  * coerced the UNKNOWN to something else. We want to do this
2166  * because (a) we want to verify that a Const is valid for the
2167  * target type, or resolve the actual type of an UNKNOWN Param,
2168  * and (b) we want to avoid unnecessary discrepancies between the
2169  * output type of the child query and the resolved target type.
2170  * Such a discrepancy would disable optimization in the planner.
2171  *
2172  * If it's some other UNKNOWN-type node, eg a Var, we do nothing
2173  * (knowing that coerce_to_common_type would fail). The planner
2174  * is sometimes able to fold an UNKNOWN Var to a constant before
2175  * it has to coerce the type, so failing now would just break
2176  * cases that might work.
2177  */
2178  if (lcoltype != UNKNOWNOID)
2179  lcolnode = coerce_to_common_type(pstate, lcolnode,
2180  rescoltype, context);
2181  else if (IsA(lcolnode, Const) ||
2182  IsA(lcolnode, Param))
2183  {
2184  lcolnode = coerce_to_common_type(pstate, lcolnode,
2185  rescoltype, context);
2186  ltle->expr = (Expr *) lcolnode;
2187  }
2188 
2189  if (rcoltype != UNKNOWNOID)
2190  rcolnode = coerce_to_common_type(pstate, rcolnode,
2191  rescoltype, context);
2192  else if (IsA(rcolnode, Const) ||
2193  IsA(rcolnode, Param))
2194  {
2195  rcolnode = coerce_to_common_type(pstate, rcolnode,
2196  rescoltype, context);
2197  rtle->expr = (Expr *) rcolnode;
2198  }
2199 
2200  rescoltypmod = select_common_typmod(pstate,
2201  list_make2(lcolnode, rcolnode),
2202  rescoltype);
2203 
2204  /*
2205  * Select common collation. A common collation is required for
2206  * all set operators except UNION ALL; see SQL:2008 7.13 <query
2207  * expression> Syntax Rule 15c. (If we fail to identify a common
2208  * collation for a UNION ALL column, the colCollations element
2209  * will be set to InvalidOid, which may result in a runtime error
2210  * if something at a higher query level wants to use the column's
2211  * collation.)
2212  */
2213  rescolcoll = select_common_collation(pstate,
2214  list_make2(lcolnode, rcolnode),
2215  (op->op == SETOP_UNION && op->all));
2216 
2217  /* emit results */
2218  op->colTypes = lappend_oid(op->colTypes, rescoltype);
2219  op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
2220  op->colCollations = lappend_oid(op->colCollations, rescolcoll);
2221 
2222  /*
2223  * For all cases except UNION ALL, identify the grouping operators
2224  * (and, if available, sorting operators) that will be used to
2225  * eliminate duplicates.
2226  */
2227  if (op->op != SETOP_UNION || !op->all)
2228  {
2229  ParseCallbackState pcbstate;
2230 
2231  setup_parser_errposition_callback(&pcbstate, pstate,
2232  bestlocation);
2233 
2234  /*
2235  * If it's a recursive union, we need to require hashing
2236  * support.
2237  */
2238  op->groupClauses = lappend(op->groupClauses,
2239  makeSortGroupClauseForSetOp(rescoltype, recursive));
2240 
2242  }
2243 
2244  /*
2245  * Construct a dummy tlist entry to return. We use a SetToDefault
2246  * node for the expression, since it carries exactly the fields
2247  * needed, but any other expression node type would do as well.
2248  */
2249  if (targetlist)
2250  {
2251  SetToDefault *rescolnode = makeNode(SetToDefault);
2252  TargetEntry *restle;
2253 
2254  rescolnode->typeId = rescoltype;
2255  rescolnode->typeMod = rescoltypmod;
2256  rescolnode->collation = rescolcoll;
2257  rescolnode->location = bestlocation;
2258  restle = makeTargetEntry((Expr *) rescolnode,
2259  0, /* no need to set resno */
2260  NULL,
2261  false);
2262  *targetlist = lappend(*targetlist, restle);
2263  }
2264  }
2265 
2266  return (Node *) op;
2267  }
2268 }
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:160
void setup_parser_errposition_callback(ParseCallbackState *pcbstate, ParseState *pstate, int location)
Definition: parse_node.c:144
@ SETOP_INTERSECT
Definition: parsenodes.h:1992
@ SETOP_UNION
Definition: parsenodes.h:1991
Query * parse_sub_analyze(Node *parseTree, ParseState *parentParseState, CommonTableExpr *parentCTE, bool locked_from_parent, bool resolve_unknowns)
Definition: analyze.c:223
static void determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
Definition: analyze.c:2275
SortGroupClause * makeSortGroupClauseForSetOp(Oid rescoltype, bool require_hash)
Definition: analyze.c:1897
#define list_make2(x1, x2)
Definition: pg_list.h:208
#define snprintf
Definition: port.h:225
void check_stack_depth(void)
Definition: postgres.c:3500
struct SelectStmt * rarg
Definition: parsenodes.h:2041
SetOperation op
Definition: parsenodes.h:2068
int32 typeMod
Definition: primnodes.h:1603
int locate_var_of_level(Node *node, int levelsup)
Definition: var.c:506

References addRangeTableEntryForSubquery(), SelectStmt::all, SetOperationStmt::all, Assert(), cancel_parser_errposition_callback(), check_stack_depth(), coerce_to_common_type(), SetOperationStmt::colCollations, SetToDefault::collation, SetOperationStmt::colTypes, SetOperationStmt::colTypmods, contain_vars_of_level(), CommonTableExpr::cterecursive, determineRecursiveColTypes(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprLocation(), exprType(), forboth, SetOperationStmt::groupClauses, SelectStmt::intoClause, IsA, lappend(), lappend_int(), lappend_oid(), SelectStmt::larg, SetOperationStmt::larg, LCS_asString(), lfirst, SelectStmt::limitCount, SelectStmt::limitOffset, linitial, list_length(), list_make2, locate_var_of_level(), SetToDefault::location, SelectStmt::lockingClause, makeAlias(), makeNode, makeSortGroupClauseForSetOp(), makeTargetEntry(), NIL, SelectStmt::op, SetOperationStmt::op, ParseState::p_namespace, ParseState::p_parent_cte, ParseState::p_rtable, ParseNamespaceItem::p_rtindex, parse_sub_analyze(), parser_errposition(), SelectStmt::rarg, SetOperationStmt::rarg, TargetEntry::resjunk, RangeTblRef::rtindex, select_common_collation(), select_common_type(), select_common_typmod(), SETOP_INTERSECT, SETOP_NONE, SETOP_UNION, setup_parser_errposition_callback(), snprintf, SelectStmt::sortClause, Query::targetList, SetToDefault::typeId, SetToDefault::typeMod, and SelectStmt::withClause.

Referenced by transformSetOperationStmt().

◆ transformStmt()

Query* transformStmt ( ParseState pstate,
Node parseTree 
)

Definition at line 313 of file analyze.c.

314 {
315  Query *result;
316 
317  /*
318  * We apply RAW_EXPRESSION_COVERAGE_TEST testing to basic DML statements;
319  * we can't just run it on everything because raw_expression_tree_walker()
320  * doesn't claim to handle utility statements.
321  */
322 #ifdef RAW_EXPRESSION_COVERAGE_TEST
323  switch (nodeTag(parseTree))
324  {
325  case T_SelectStmt:
326  case T_InsertStmt:
327  case T_UpdateStmt:
328  case T_DeleteStmt:
329  case T_MergeStmt:
330  (void) test_raw_expression_coverage(parseTree, NULL);
331  break;
332  default:
333  break;
334  }
335 #endif /* RAW_EXPRESSION_COVERAGE_TEST */
336 
337  switch (nodeTag(parseTree))
338  {
339  /*
340  * Optimizable statements
341  */
342  case T_InsertStmt:
343  result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
344  break;
345 
346  case T_DeleteStmt:
347  result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
348  break;
349 
350  case T_UpdateStmt:
351  result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
352  break;
353 
354  case T_MergeStmt:
355  result = transformMergeStmt(pstate, (MergeStmt *) parseTree);
356  break;
357 
358  case T_SelectStmt:
359  {
360  SelectStmt *n = (SelectStmt *) parseTree;
361 
362  if (n->valuesLists)
363  result = transformValuesClause(pstate, n);
364  else if (n->op == SETOP_NONE)
365  result = transformSelectStmt(pstate, n);
366  else
367  result = transformSetOperationStmt(pstate, n);
368  }
369  break;
370 
371  case T_ReturnStmt:
372  result = transformReturnStmt(pstate, (ReturnStmt *) parseTree);
373  break;
374 
375  case T_PLAssignStmt:
376  result = transformPLAssignStmt(pstate,
377  (PLAssignStmt *) parseTree);
378  break;
379 
380  /*
381  * Special cases
382  */
383  case T_DeclareCursorStmt:
384  result = transformDeclareCursorStmt(pstate,
385  (DeclareCursorStmt *) parseTree);
386  break;
387 
388  case T_ExplainStmt:
389  result = transformExplainStmt(pstate,
390  (ExplainStmt *) parseTree);
391  break;
392 
393  case T_CreateTableAsStmt:
394  result = transformCreateTableAsStmt(pstate,
395  (CreateTableAsStmt *) parseTree);
396  break;
397 
398  case T_CallStmt:
399  result = transformCallStmt(pstate,
400  (CallStmt *) parseTree);
401  break;
402 
403  default:
404 
405  /*
406  * other statements don't require any transformation; just return
407  * the original parsetree with a Query node plastered on top.
408  */
409  result = makeNode(Query);
410  result->commandType = CMD_UTILITY;
411  result->utilityStmt = (Node *) parseTree;
412  break;
413  }
414 
415  /* Mark as original query until we learn differently */
416  result->querySource = QSRC_ORIGINAL;
417  result->canSetTag = true;
418 
419  return result;
420 }
@ T_ReturnStmt
Definition: nodes.h:337
@ T_CallStmt
Definition: nodes.h:447
Query * transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
Definition: parse_merge.c:96
@ QSRC_ORIGINAL
Definition: parsenodes.h:42
static Query * transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
Definition: analyze.c:472
static Query * transformReturnStmt(ParseState *pstate, ReturnStmt *stmt)
Definition: analyze.c:2329
static Query * transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
Definition: analyze.c:2553
static Query * transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
Definition: analyze.c:2918
static Query * transformCallStmt(ParseState *pstate, CallStmt *stmt)
Definition: analyze.c:2993
static Query * transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1642
static Query * transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
Definition: analyze.c:2359
static Query * transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1282
static Query * transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
Definition: analyze.c:2894
static Query * transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
Definition: analyze.c:2801
static Query * transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
Definition: analyze.c:542
static Query * transformValuesClause(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1424
bool canSetTag
Definition: parsenodes.h:127
QuerySource querySource
Definition: parsenodes.h:123

References Query::canSetTag, CMD_UTILITY, Query::commandType, makeNode, nodeTag, SelectStmt::op, QSRC_ORIGINAL, Query::querySource, SETOP_NONE, T_CallStmt, T_CreateTableAsStmt, T_DeclareCursorStmt, T_DeleteStmt, T_ExplainStmt, T_InsertStmt, T_MergeStmt, T_PLAssignStmt, T_ReturnStmt, T_SelectStmt, T_UpdateStmt, 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 250 of file analyze.c.

251 {
252  Query *result;
253 
254  /* We're at top level, so allow SELECT INTO */
255  result = transformOptionalSelectInto(pstate, parseTree->stmt);
256 
257  result->stmt_location = parseTree->stmt_location;
258  result->stmt_len = parseTree->stmt_len;
259 
260  return result;
261 }
int stmt_location
Definition: parsenodes.h:197
int stmt_len
Definition: parsenodes.h:198
int stmt_len
Definition: parsenodes.h:1905
int stmt_location
Definition: parsenodes.h:1904

References RawStmt::stmt, Query::stmt_len, RawStmt::stmt_len, Query::stmt_location, 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 2359 of file analyze.c.

2360 {
2361  Query *qry = makeNode(Query);
2362  ParseNamespaceItem *nsitem;
2363  Node *qual;
2364 
2365  qry->commandType = CMD_UPDATE;
2366  pstate->p_is_insert = false;
2367 
2368  /* process the WITH clause independently of all else */
2369  if (stmt->withClause)
2370  {
2371  qry->hasRecursive = stmt->withClause->recursive;
2372  qry->cteList = transformWithClause(pstate, stmt->withClause);
2373  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
2374  }
2375 
2376  qry->resultRelation = setTargetTable(pstate, stmt->relation,
2377  stmt->relation->inh,
2378  true,
2379  ACL_UPDATE);
2380  nsitem = pstate->p_target_nsitem;
2381 
2382  /* subqueries in FROM cannot access the result relation */
2383  nsitem->p_lateral_only = true;
2384  nsitem->p_lateral_ok = false;
2385 
2386  /*
2387  * the FROM clause is non-standard SQL syntax. We used to be able to do
2388  * this with REPLACE in POSTQUEL so we keep the feature.
2389  */
2390  transformFromClause(pstate, stmt->fromClause);
2391 
2392  /* remaining clauses can reference the result relation normally */
2393  nsitem->p_lateral_only = false;
2394  nsitem->p_lateral_ok = true;
2395 
2396  qual = transformWhereClause(pstate, stmt->whereClause,
2397  EXPR_KIND_WHERE, "WHERE");
2398 
2399  qry->returningList = transformReturningList(pstate, stmt->returningList);
2400 
2401  /*
2402  * Now we are done with SELECT-like processing, and can get on with
2403  * transforming the target list to match the UPDATE target columns.
2404  */
2405  qry->targetList = transformUpdateTargetList(pstate, stmt->targetList);
2406 
2407  qry->rtable = pstate->p_rtable;
2408  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2409 
2410  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2411  qry->hasSubLinks = pstate->p_hasSubLinks;
2412 
2413  assign_query_collations(pstate, qry);
2414 
2415  return qry;
2416 }
@ CMD_UPDATE
Definition: nodes.h:722
List * targetList
Definition: parsenodes.h:1954
List * returningList
Definition: parsenodes.h:1957
List * fromClause
Definition: parsenodes.h:1956
Node * whereClause
Definition: parsenodes.h:1955
RangeVar * relation
Definition: parsenodes.h:1953
WithClause * withClause
Definition: parsenodes.h:1958

References ACL_UPDATE, assign_query_collations(), CMD_UPDATE, Query::commandType, Query::cteList, EXPR_KIND_WHERE, UpdateStmt::fromClause, Query::hasModifyingCTE, Query::hasRecursive, Query::hasSubLinks, Query::hasTargetSRFs, RangeVar::inh, 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_target_nsitem, WithClause::recursive, UpdateStmt::relation, Query::resultRelation, Query::returningList, UpdateStmt::returningList, Query::rtable, setTargetTable(), Query::targetList, UpdateStmt::targetList, transformFromClause(), transformReturningList(), transformUpdateTargetList(), transformWhereClause(), transformWithClause(), UpdateStmt::whereClause, and UpdateStmt::withClause.

Referenced by transformStmt().

◆ transformUpdateTargetList()

List* transformUpdateTargetList ( ParseState pstate,
List origTlist 
)

Definition at line 2423 of file analyze.c.

2424 {
2425  List *tlist = NIL;
2426  RangeTblEntry *target_rte;
2427  ListCell *orig_tl;
2428  ListCell *tl;
2429 
2430  tlist = transformTargetList(pstate, origTlist,
2432 
2433  /* Prepare to assign non-conflicting resnos to resjunk attributes */
2436 
2437  /* Prepare non-junk columns for assignment to target table */
2438  target_rte = pstate->p_target_nsitem->p_rte;
2439  orig_tl = list_head(origTlist);
2440 
2441  foreach(tl, tlist)
2442  {
2443  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2444  ResTarget *origTarget;
2445  int attrno;
2446 
2447  if (tle->resjunk)
2448  {
2449  /*
2450  * Resjunk nodes need no additional processing, but be sure they
2451  * have resnos that do not match any target columns; else rewriter
2452  * or planner might get confused. They don't need a resname
2453  * either.
2454  */
2455  tle->resno = (AttrNumber) pstate->p_next_resno++;
2456  tle->resname = NULL;
2457  continue;
2458  }
2459  if (orig_tl == NULL)
2460  elog(ERROR, "UPDATE target count mismatch --- internal error");
2461  origTarget = lfirst_node(ResTarget, orig_tl);
2462 
2463  attrno = attnameAttNum(pstate->p_target_relation,
2464  origTarget->name, true);
2465  if (attrno == InvalidAttrNumber)
2466  ereport(ERROR,
2467  (errcode(ERRCODE_UNDEFINED_COLUMN),
2468  errmsg("column \"%s\" of relation \"%s\" does not exist",
2469  origTarget->name,
2471  parser_errposition(pstate, origTarget->location)));
2472 
2473  updateTargetListEntry(pstate, tle, origTarget->name,
2474  attrno,
2475  origTarget->indirection,
2476  origTarget->location);
2477 
2478  /* Mark the target column as requiring update permissions */
2479  target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
2481 
2482  orig_tl = lnext(origTlist, orig_tl);
2483  }
2484  if (orig_tl != NULL)
2485  elog(ERROR, "UPDATE target count mismatch --- internal error");
2486 
2487  return tlist;
2488 }
@ 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:621
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define RelationGetRelationName(relation)
Definition: rel.h:523
Bitmapset * updatedCols
Definition: parsenodes.h:1169

References attnameAttNum(), bms_add_member(), elog, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_UPDATE_SOURCE, FirstLowInvalidHeapAttributeNumber, ResTarget::indirection, InvalidAttrNumber, lfirst, lfirst_node, list_head(), lnext(), ResTarget::location, ResTarget::name, NIL, ParseState::p_next_resno, ParseNamespaceItem::p_rte, ParseState::p_target_nsitem, ParseState::p_target_relation, parser_errposition(), RelationGetNumberOfAttributes, RelationGetRelationName, TargetEntry::resjunk, TargetEntry::resname, TargetEntry::resno, transformTargetList(), RangeTblEntry::updatedCols, and updateTargetListEntry().

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

◆ transformValuesClause()

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

Definition at line 1424 of file analyze.c.

1425 {
1426  Query *qry = makeNode(Query);
1427  List *exprsLists = NIL;
1428  List *coltypes = NIL;
1429  List *coltypmods = NIL;
1430  List *colcollations = NIL;
1431  List **colexprs = NULL;
1432  int sublist_length = -1;
1433  bool lateral = false;
1434  ParseNamespaceItem *nsitem;
1435  ListCell *lc;
1436  ListCell *lc2;
1437  int i;
1438 
1439  qry->commandType = CMD_SELECT;
1440 
1441  /* Most SELECT stuff doesn't apply in a VALUES clause */
1442  Assert(stmt->distinctClause == NIL);
1443  Assert(stmt->intoClause == NULL);
1444  Assert(stmt->targetList == NIL);
1445  Assert(stmt->fromClause == NIL);
1446  Assert(stmt->whereClause == NULL);
1447  Assert(stmt->groupClause == NIL);
1448  Assert(stmt->havingClause == NULL);
1449  Assert(stmt->windowClause == NIL);
1450  Assert(stmt->op == SETOP_NONE);
1451 
1452  /* process the WITH clause independently of all else */
1453  if (stmt->withClause)
1454  {
1455  qry->hasRecursive = stmt->withClause->recursive;
1456  qry->cteList = transformWithClause(pstate, stmt->withClause);
1457  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1458  }
1459 
1460  /*
1461  * For each row of VALUES, transform the raw expressions.
1462  *
1463  * Note that the intermediate representation we build is column-organized
1464  * not row-organized. That simplifies the type and collation processing
1465  * below.
1466  */
1467  foreach(lc, stmt->valuesLists)
1468  {
1469  List *sublist = (List *) lfirst(lc);
1470 
1471  /*
1472  * Do basic expression transformation (same as a ROW() expr, but here
1473  * we disallow SetToDefault)
1474  */
1475  sublist = transformExpressionList(pstate, sublist,
1476  EXPR_KIND_VALUES, false);
1477 
1478  /*
1479  * All the sublists must be the same length, *after* transformation
1480  * (which might expand '*' into multiple items). The VALUES RTE can't
1481  * handle anything different.
1482  */
1483  if (sublist_length < 0)
1484  {
1485  /* Remember post-transformation length of first sublist */
1486  sublist_length = list_length(sublist);
1487  /* and allocate array for per-column lists */
1488  colexprs = (List **) palloc0(sublist_length * sizeof(List *));
1489  }
1490  else if (sublist_length != list_length(sublist))
1491  {
1492  ereport(ERROR,
1493  (errcode(ERRCODE_SYNTAX_ERROR),
1494  errmsg("VALUES lists must all be the same length"),
1495  parser_errposition(pstate,
1496  exprLocation((Node *) sublist))));
1497  }
1498 
1499  /* Build per-column expression lists */
1500  i = 0;
1501  foreach(lc2, sublist)
1502  {
1503  Node *col = (Node *) lfirst(lc2);
1504 
1505  colexprs[i] = lappend(colexprs[i], col);
1506  i++;
1507  }
1508 
1509  /* Release sub-list's cells to save memory */
1510  list_free(sublist);
1511 
1512  /* Prepare an exprsLists element for this row */
1513  exprsLists = lappend(exprsLists, NIL);
1514  }
1515 
1516  /*
1517  * Now resolve the common types of the columns, and coerce everything to
1518  * those types. Then identify the common typmod and common collation, if
1519  * any, of each column.
1520  *
1521  * We must do collation processing now because (1) assign_query_collations
1522  * doesn't process rangetable entries, and (2) we need to label the VALUES
1523  * RTE with column collations for use in the outer query. We don't
1524  * consider conflict of implicit collations to be an error here; instead
1525  * the column will just show InvalidOid as its collation, and you'll get a
1526  * failure later if that results in failure to resolve a collation.
1527  *
1528  * Note we modify the per-column expression lists in-place.
1529  */
1530  for (i = 0; i < sublist_length; i++)
1531  {
1532  Oid coltype;
1533  int32 coltypmod;
1534  Oid colcoll;
1535 
1536  coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
1537 
1538  foreach(lc, colexprs[i])
1539  {
1540  Node *col = (Node *) lfirst(lc);
1541 
1542  col = coerce_to_common_type(pstate, col, coltype, "VALUES");
1543  lfirst(lc) = (void *) col;
1544  }
1545 
1546  coltypmod = select_common_typmod(pstate, colexprs[i], coltype);
1547  colcoll = select_common_collation(pstate, colexprs[i], true);
1548 
1549  coltypes = lappend_oid(coltypes, coltype);
1550  coltypmods = lappend_int(coltypmods, coltypmod);
1551  colcollations = lappend_oid(colcollations, colcoll);
1552  }
1553 
1554  /*
1555  * Finally, rearrange the coerced expressions into row-organized lists.
1556  */
1557  for (i = 0; i < sublist_length; i++)
1558  {
1559  forboth(lc, colexprs[i], lc2, exprsLists)
1560  {
1561  Node *col = (Node *) lfirst(lc);
1562  List *sublist = lfirst(lc2);
1563 
1564  sublist = lappend(sublist, col);
1565  lfirst(lc2) = sublist;
1566  }
1567  list_free(colexprs[i]);
1568  }
1569 
1570  /*
1571  * Ordinarily there can't be any current-level Vars in the expression
1572  * lists, because the namespace was empty ... but if we're inside CREATE
1573  * RULE, then NEW/OLD references might appear. In that case we have to
1574  * mark the VALUES RTE as LATERAL.
1575  */
1576  if (pstate->p_rtable != NIL &&
1577  contain_vars_of_level((Node *) exprsLists, 0))
1578  lateral = true;
1579 
1580  /*
1581  * Generate the VALUES RTE
1582  */
1583  nsitem = addRangeTableEntryForValues(pstate, exprsLists,
1584  coltypes, coltypmods, colcollations,
1585  NULL, lateral, true);
1586  addNSItemToQuery(pstate, nsitem, true, true, true);
1587 
1588  /*
1589  * Generate a targetlist as though expanding "*"
1590  */
1591  Assert(pstate->p_next_resno == 1);
1592  qry->targetList = expandNSItemAttrs(pstate, nsitem, 0, true, -1);
1593 
1594  /*
1595  * The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
1596  * VALUES, so cope.
1597  */
1598  qry->sortClause = transformSortClause(pstate,
1599  stmt->sortClause,
1600  &qry->targetList,
1602  false /* allow SQL92 rules */ );
1603 
1604  qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1605  EXPR_KIND_OFFSET, "OFFSET",
1606  stmt->limitOption);
1607  qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1608  EXPR_KIND_LIMIT, "LIMIT",
1609  stmt->limitOption);
1610  qry->limitOption = stmt->limitOption;
1611 
1612  if (stmt->lockingClause)
1613  ereport(ERROR,
1614  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1615  /*------
1616  translator: %s is a SQL row locking clause such as FOR UPDATE */
1617  errmsg("%s cannot be applied to VALUES",
1619  linitial(stmt->lockingClause))->strength))));
1620 
1621  qry->rtable = pstate->p_rtable;
1622  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1623 
1624  qry->hasSubLinks = pstate->p_hasSubLinks;
1625 
1626  assign_query_collations(pstate, qry);
1627 
1628  return qry;
1629 }
void list_free(List *list)
Definition: list.c:1505
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, SelectStmt::distinctClause, ereport, errcode(), errmsg(), ERROR, expandNSItemAttrs(), EXPR_KIND_LIMIT, EXPR_KIND_OFFSET, EXPR_KIND_ORDER_BY, EXPR_KIND_VALUES, exprLocation(), forboth, SelectStmt::fromClause, SelectStmt::groupClause, Query::hasModifyingCTE, Query::hasRecursive, Query::hasSubLinks, SelectStmt::havingClause, i, SelectStmt::intoClause, Query::jointree, lappend(), lappend_int(), lappend_oid(), LCS_asString(), lfirst, Query::limitCount, SelectStmt::limitCount, Query::limitOffset, SelectStmt::limitOffset, Query::limitOption, SelectStmt::limitOption, linitial, list_free(), list_length(), SelectStmt::lockingClause, makeFromExpr(), makeNode, NIL, SelectStmt::op, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_joinlist, ParseState::p_next_resno, ParseState::p_rtable, palloc0(), parser_errposition(), WithClause::recursive, Query::rtable, select_common_collation(), select_common_type(), select_common_typmod(), SETOP_NONE, Query::sortClause, SelectStmt::sortClause, Query::targetList, SelectStmt::targetList, transformExpressionList(), transformLimitClause(), transformSortClause(), transformWithClause(), SelectStmt::valuesLists, SelectStmt::whereClause, SelectStmt::windowClause, and SelectStmt::withClause.

Referenced by transformStmt().

Variable Documentation

◆ post_parse_analyze_hook