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_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 ListtransformInsertRow (ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
 
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 ListtransformUpdateTargetList (ParseState *pstate, List *targetList)
 
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 (RawStmt *parseTree, const char *sourceText, Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
 
Queryparse_analyze_varparams (RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams)
 
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)
 
ListBuildOnConflictExcludedTargetlist (Relation targetrel, Index exclRelIndex)
 
SortGroupClausemakeSortGroupClauseForSetOp (Oid rescoltype)
 
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 388 of file analyze.c.

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

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

389 {
390  bool result;
391 
392  switch (nodeTag(parseTree->stmt))
393  {
394  /*
395  * Optimizable statements
396  */
397  case T_InsertStmt:
398  case T_DeleteStmt:
399  case T_UpdateStmt:
400  case T_SelectStmt:
401  case T_PLAssignStmt:
402  result = true;
403  break;
404 
405  /*
406  * Special cases
407  */
408  case T_DeclareCursorStmt:
409  case T_ExplainStmt:
410  case T_CreateTableAsStmt:
411  /* yes, because we must analyze the contained statement */
412  result = true;
413  break;
414 
415  default:
416  /* other utility statements don't have any real parse analysis */
417  result = false;
418  break;
419  }
420 
421  return result;
422 }
Node * stmt
Definition: parsenodes.h:1560
#define nodeTag(nodeptr)
Definition: nodes.h:544

◆ applyLockingClause()

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

Definition at line 3328 of file analyze.c.

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

Referenced by markQueryForLocking(), and transformLockingClause().

3331 {
3332  RowMarkClause *rc;
3333 
3334  Assert(strength != LCS_NONE); /* else caller error */
3335 
3336  /* If it's an explicit clause, make sure hasForUpdate gets set */
3337  if (!pushedDown)
3338  qry->hasForUpdate = true;
3339 
3340  /* Check for pre-existing entry for same rtindex */
3341  if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
3342  {
3343  /*
3344  * If the same RTE is specified with more than one locking strength,
3345  * use the strongest. (Reasonable, since you can't take both a shared
3346  * and exclusive lock at the same time; it'll end up being exclusive
3347  * anyway.)
3348  *
3349  * Similarly, if the same RTE is specified with more than one lock
3350  * wait policy, consider that NOWAIT wins over SKIP LOCKED, which in
3351  * turn wins over waiting for the lock (the default). This is a bit
3352  * more debatable but raising an error doesn't seem helpful. (Consider
3353  * for instance SELECT FOR UPDATE NOWAIT from a view that internally
3354  * contains a plain FOR UPDATE spec.) Having NOWAIT win over SKIP
3355  * LOCKED is reasonable since the former throws an error in case of
3356  * coming across a locked tuple, which may be undesirable in some
3357  * cases but it seems better than silently returning inconsistent
3358  * results.
3359  *
3360  * And of course pushedDown becomes false if any clause is explicit.
3361  */
3362  rc->strength = Max(rc->strength, strength);
3363  rc->waitPolicy = Max(rc->waitPolicy, waitPolicy);
3364  rc->pushedDown &= pushedDown;
3365  return;
3366  }
3367 
3368  /* Make a new RowMarkClause */
3369  rc = makeNode(RowMarkClause);
3370  rc->rti = rtindex;
3371  rc->strength = strength;
3372  rc->waitPolicy = waitPolicy;
3373  rc->pushedDown = pushedDown;
3374  qry->rowMarks = lappend(qry->rowMarks, rc);
3375 }
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
List * rowMarks
Definition: parsenodes.h:175
LockClauseStrength strength
Definition: parsenodes.h:1409
List * lappend(List *list, void *datum)
Definition: list.c:336
#define Max(x, y)
Definition: c.h:980
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1410
bool hasForUpdate
Definition: parsenodes.h:140

◆ BuildOnConflictExcludedTargetlist()

List* BuildOnConflictExcludedTargetlist ( Relation  targetrel,
Index  exclRelIndex 
)

Definition at line 1127 of file analyze.c.

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

1129 {
1130  List *result = NIL;
1131  int attno;
1132  Var *var;
1133  TargetEntry *te;
1134 
1135  /*
1136  * Note that resnos of the tlist must correspond to attnos of the
1137  * underlying relation, hence we need entries for dropped columns too.
1138  */
1139  for (attno = 0; attno < RelationGetNumberOfAttributes(targetrel); attno++)
1140  {
1141  Form_pg_attribute attr = TupleDescAttr(targetrel->rd_att, attno);
1142  char *name;
1143 
1144  if (attr->attisdropped)
1145  {
1146  /*
1147  * can't use atttypid here, but it doesn't really matter what type
1148  * the Const claims to be.
1149  */
1150  var = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
1151  name = NULL;
1152  }
1153  else
1154  {
1155  var = makeVar(exclRelIndex, attno + 1,
1156  attr->atttypid, attr->atttypmod,
1157  attr->attcollation,
1158  0);
1159  name = pstrdup(NameStr(attr->attname));
1160  }
1161 
1162  te = makeTargetEntry((Expr *) var,
1163  attno + 1,
1164  name,
1165  false);
1166 
1167  result = lappend(result, te);
1168  }
1169 
1170  /*
1171  * Add a whole-row-Var entry to support references to "EXCLUDED.*". Like
1172  * the other entries in the EXCLUDED tlist, its resno must match the Var's
1173  * varattno, else the wrong things happen while resolving references in
1174  * setrefs.c. This is against normal conventions for targetlists, but
1175  * it's okay since we don't use this as a real tlist.
1176  */
1177  var = makeVar(exclRelIndex, InvalidAttrNumber,
1178  targetrel->rd_rel->reltype,
1179  -1, InvalidOid, 0);
1180  te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true);
1181  result = lappend(result, te);
1182 
1183  return result;
1184 }
#define NIL
Definition: pg_list.h:65
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:483
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Form_pg_class rd_rel
Definition: rel.h:109
Definition: primnodes.h:186
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:336
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
const char * name
Definition: encode.c:515
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:681
Definition: pg_list.h:50

◆ CheckSelectLocking()

void CheckSelectLocking ( Query qry,
LockClauseStrength  strength 
)

Definition at line 3090 of file analyze.c.

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

3091 {
3092  Assert(strength != LCS_NONE); /* else caller error */
3093 
3094  if (qry->setOperations)
3095  ereport(ERROR,
3096  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3097  /*------
3098  translator: %s is a SQL row locking clause such as FOR UPDATE */
3099  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
3100  LCS_asString(strength))));
3101  if (qry->distinctClause != NIL)
3102  ereport(ERROR,
3103  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3104  /*------
3105  translator: %s is a SQL row locking clause such as FOR UPDATE */
3106  errmsg("%s is not allowed with DISTINCT clause",
3107  LCS_asString(strength))));
3108  if (qry->groupClause != NIL || qry->groupingSets != NIL)
3109  ereport(ERROR,
3110  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3111  /*------
3112  translator: %s is a SQL row locking clause such as FOR UPDATE */
3113  errmsg("%s is not allowed with GROUP BY clause",
3114  LCS_asString(strength))));
3115  if (qry->havingQual != NULL)
3116  ereport(ERROR,
3117  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3118  /*------
3119  translator: %s is a SQL row locking clause such as FOR UPDATE */
3120  errmsg("%s is not allowed with HAVING clause",
3121  LCS_asString(strength))));
3122  if (qry->hasAggs)
3123  ereport(ERROR,
3124  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3125  /*------
3126  translator: %s is a SQL row locking clause such as FOR UPDATE */
3127  errmsg("%s is not allowed with aggregate functions",
3128  LCS_asString(strength))));
3129  if (qry->hasWindowFuncs)
3130  ereport(ERROR,
3131  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3132  /*------
3133  translator: %s is a SQL row locking clause such as FOR UPDATE */
3134  errmsg("%s is not allowed with window functions",
3135  LCS_asString(strength))));
3136  if (qry->hasTargetSRFs)
3137  ereport(ERROR,
3138  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3139  /*------
3140  translator: %s is a SQL row locking clause such as FOR UPDATE */
3141  errmsg("%s is not allowed with set-returning functions in the target list",
3142  LCS_asString(strength))));
3143 }
#define NIL
Definition: pg_list.h:65
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3065
bool hasAggs
Definition: parsenodes.h:133
List * groupingSets
Definition: parsenodes.h:161
int errcode(int sqlerrcode)
Definition: elog.c:698
List * distinctClause
Definition: parsenodes.h:167
#define ERROR
Definition: elog.h:46
#define ereport(elevel,...)
Definition: elog.h:157
bool hasTargetSRFs
Definition: parsenodes.h:135
#define Assert(condition)
Definition: c.h:804
bool hasWindowFuncs
Definition: parsenodes.h:134
Node * setOperations
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:909
Node * havingQual
Definition: parsenodes.h:163

◆ count_rowexpr_columns()

static int count_rowexpr_columns ( ParseState pstate,
Node expr 
)
static

Definition at line 1197 of file analyze.c.

References generate_unaccent_rules::args, attnum, TargetEntry::expr, get_tle_by_resno(), GetRTEByRangeTablePosn(), 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().

1198 {
1199  if (expr == NULL)
1200  return -1;
1201  if (IsA(expr, RowExpr))
1202  return list_length(((RowExpr *) expr)->args);
1203  if (IsA(expr, Var))
1204  {
1205  Var *var = (Var *) expr;
1206  AttrNumber attnum = var->varattno;
1207 
1208  if (attnum > 0 && var->vartype == RECORDOID)
1209  {
1210  RangeTblEntry *rte;
1211 
1212  rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
1213  if (rte->rtekind == RTE_SUBQUERY)
1214  {
1215  /* Subselect-in-FROM: examine sub-select's output expr */
1217  attnum);
1218 
1219  if (ste == NULL || ste->resjunk)
1220  return -1;
1221  expr = (Node *) ste->expr;
1222  if (IsA(expr, RowExpr))
1223  return list_length(((RowExpr *) expr)->args);
1224  }
1225  }
1226  }
1227  return -1;
1228 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Index varlevelsup
Definition: primnodes.h:196
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
List * targetList
Definition: parsenodes.h:150
bool resjunk
Definition: primnodes.h:1461
Oid vartype
Definition: primnodes.h:193
Index varno
Definition: primnodes.h:189
RangeTblEntry * GetRTEByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
int16 attnum
Definition: pg_attribute.h:83
Expr * expr
Definition: primnodes.h:1454
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
int16 AttrNumber
Definition: attnum.h:21

◆ determineRecursiveColTypes()

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

Definition at line 2222 of file analyze.c.

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

2223 {
2224  Node *node;
2225  int leftmostRTI;
2226  Query *leftmostQuery;
2227  List *targetList;
2228  ListCell *left_tlist;
2229  ListCell *nrtl;
2230  int next_resno;
2231 
2232  /*
2233  * Find leftmost leaf SELECT
2234  */
2235  node = larg;
2236  while (node && IsA(node, SetOperationStmt))
2237  node = ((SetOperationStmt *) node)->larg;
2238  Assert(node && IsA(node, RangeTblRef));
2239  leftmostRTI = ((RangeTblRef *) node)->rtindex;
2240  leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
2241  Assert(leftmostQuery != NULL);
2242 
2243  /*
2244  * Generate dummy targetlist using column names of leftmost select and
2245  * dummy result expressions of the non-recursive term.
2246  */
2247  targetList = NIL;
2248  next_resno = 1;
2249 
2250  forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
2251  {
2252  TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
2253  TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
2254  char *colName;
2255  TargetEntry *tle;
2256 
2257  Assert(!lefttle->resjunk);
2258  colName = pstrdup(lefttle->resname);
2259  tle = makeTargetEntry(nrtle->expr,
2260  next_resno++,
2261  colName,
2262  false);
2263  targetList = lappend(targetList, tle);
2264  }
2265 
2266  /* Now build CTE's output column info using dummy targetlist */
2267  analyzeCTETargetList(pstate, pstate->p_parent_cte, targetList);
2268 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
void analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
Definition: parse_cte.c:545
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Definition: nodes.h:539
char * resname
Definition: primnodes.h:1456
CommonTableExpr * p_parent_cte
Definition: parse_node.h:191
List * targetList
Definition: parsenodes.h:150
bool resjunk
Definition: primnodes.h:1461
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lappend(List *list, void *datum)
Definition: list.c:336
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1454
Definition: pg_list.h:50
List * p_rtable
Definition: parse_node.h:182

◆ LCS_asString()

const char* LCS_asString ( LockClauseStrength  strength)

Definition at line 3065 of file analyze.c.

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

3066 {
3067  switch (strength)
3068  {
3069  case LCS_NONE:
3070  Assert(false);
3071  break;
3072  case LCS_FORKEYSHARE:
3073  return "FOR KEY SHARE";
3074  case LCS_FORSHARE:
3075  return "FOR SHARE";
3076  case LCS_FORNOKEYUPDATE:
3077  return "FOR NO KEY UPDATE";
3078  case LCS_FORUPDATE:
3079  return "FOR UPDATE";
3080  }
3081  return "FOR some"; /* shouldn't happen */
3082 }
#define Assert(condition)
Definition: c.h:804

◆ makeSortGroupClauseForSetOp()

SortGroupClause* makeSortGroupClauseForSetOp ( Oid  rescoltype)

Definition at line 1857 of file analyze.c.

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

Referenced by rewriteSearchAndCycle(), and transformSetOperationTree().

1858 {
1860  Oid sortop;
1861  Oid eqop;
1862  bool hashable;
1863 
1864  /* determine the eqop and optional sortop */
1865  get_sort_group_operators(rescoltype,
1866  false, true, false,
1867  &sortop, &eqop, NULL,
1868  &hashable);
1869 
1870  /* we don't have a tlist yet, so can't assign sortgrouprefs */
1871  grpcl->tleSortGroupRef = 0;
1872  grpcl->eqop = eqop;
1873  grpcl->sortop = sortop;
1874  grpcl->nulls_first = false; /* OK with or without sortop */
1875  grpcl->hashable = hashable;
1876 
1877  return grpcl;
1878 }
Index tleSortGroupRef
Definition: parsenodes.h:1283
unsigned int Oid
Definition: postgres_ext.h:31
#define makeNode(_type_)
Definition: nodes.h:587
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

◆ parse_analyze()

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

Definition at line 110 of file analyze.c.

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

Referenced by DefineView(), and pg_analyze_and_rewrite().

113 {
114  ParseState *pstate = make_parsestate(NULL);
115  Query *query;
116  JumbleState *jstate = NULL;
117 
118  Assert(sourceText != NULL); /* required as of 8.4 */
119 
120  pstate->p_sourcetext = sourceText;
121 
122  if (numParams > 0)
123  parse_fixed_parameters(pstate, paramTypes, numParams);
124 
125  pstate->p_queryEnv = queryEnv;
126 
127  query = transformTopLevelStmt(pstate, parseTree);
128 
129  if (IsQueryIdEnabled())
130  jstate = JumbleQuery(query, sourceText);
131 
133  (*post_parse_analyze_hook) (pstate, query, jstate);
134 
135  free_parsestate(pstate);
136 
137  pgstat_report_query_id(query->queryId, false);
138 
139  return query;
140 }
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:78
QueryEnvironment * p_queryEnv
Definition: parse_node.h:205
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
const char * p_sourcetext
Definition: parse_node.h:181
void pgstat_report_query_id(uint64 query_id, bool force)
#define Assert(condition)
Definition: c.h:804
void parse_fixed_parameters(ParseState *pstate, Oid *paramTypes, int numParams)
Definition: parse_param.c:67
Query * transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree)
Definition: analyze.c:213
JumbleState * JumbleQuery(Query *query, const char *querytext)
Definition: queryjumble.c:101
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:58

◆ parse_analyze_varparams()

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

Definition at line 150 of file analyze.c.

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

Referenced by exec_parse_message(), and PrepareQuery().

152 {
153  ParseState *pstate = make_parsestate(NULL);
154  Query *query;
155  JumbleState *jstate = NULL;
156 
157  Assert(sourceText != NULL); /* required as of 8.4 */
158 
159  pstate->p_sourcetext = sourceText;
160 
161  parse_variable_parameters(pstate, paramTypes, numParams);
162 
163  query = transformTopLevelStmt(pstate, parseTree);
164 
165  /* make sure all is well with parameter types */
166  check_variable_parameters(pstate, query);
167 
168  if (IsQueryIdEnabled())
169  jstate = JumbleQuery(query, sourceText);
170 
172  (*post_parse_analyze_hook) (pstate, query, jstate);
173 
174  free_parsestate(pstate);
175 
176  pgstat_report_query_id(query->queryId, false);
177 
178  return query;
179 }
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:78
void parse_variable_parameters(ParseState *pstate, Oid **paramTypes, int *numParams)
Definition: parse_param.c:83
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
const char * p_sourcetext
Definition: parse_node.h:181
void pgstat_report_query_id(uint64 query_id, bool force)
#define Assert(condition)
Definition: c.h:804
Query * transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree)
Definition: analyze.c:213
void check_variable_parameters(ParseState *pstate, Query *query)
Definition: parse_param.c:272
JumbleState * JumbleQuery(Query *query, const char *querytext)
Definition: queryjumble.c:101
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:58

◆ parse_sub_analyze()

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

Definition at line 186 of file analyze.c.

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

190 {
191  ParseState *pstate = make_parsestate(parentParseState);
192  Query *query;
193 
194  pstate->p_parent_cte = parentCTE;
195  pstate->p_locked_from_parent = locked_from_parent;
196  pstate->p_resolve_unknowns = resolve_unknowns;
197 
198  query = transformStmt(pstate, parseTree);
199 
200  free_parsestate(pstate);
201 
202  return query;
203 }
CommonTableExpr * p_parent_cte
Definition: parse_node.h:191
bool p_locked_from_parent
Definition: parse_node.h:200
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
bool p_resolve_unknowns
Definition: parse_node.h:202
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:276
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77

◆ transformCallStmt()

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

Definition at line 2940 of file analyze.c.

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

2941 {
2942  List *targs;
2943  ListCell *lc;
2944  Node *node;
2945  FuncExpr *fexpr;
2946  HeapTuple proctup;
2947  Datum proargmodes;
2948  bool isNull;
2949  List *outargs = NIL;
2950  Query *result;
2951 
2952  /*
2953  * First, do standard parse analysis on the procedure call and its
2954  * arguments, allowing us to identify the called procedure.
2955  */
2956  targs = NIL;
2957  foreach(lc, stmt->funccall->args)
2958  {
2959  targs = lappend(targs, transformExpr(pstate,
2960  (Node *) lfirst(lc),
2962  }
2963 
2964  node = ParseFuncOrColumn(pstate,
2965  stmt->funccall->funcname,
2966  targs,
2967  pstate->p_last_srf,
2968  stmt->funccall,
2969  true,
2970  stmt->funccall->location);
2971 
2972  assign_expr_collations(pstate, node);
2973 
2974  fexpr = castNode(FuncExpr, node);
2975 
2976  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2977  if (!HeapTupleIsValid(proctup))
2978  elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
2979 
2980  /*
2981  * Expand the argument list to deal with named-argument notation and
2982  * default arguments. For ordinary FuncExprs this'd be done during
2983  * planning, but a CallStmt doesn't go through planning, and there seems
2984  * no good reason not to do it here.
2985  */
2986  fexpr->args = expand_function_arguments(fexpr->args,
2987  true,
2988  fexpr->funcresulttype,
2989  proctup);
2990 
2991  /* Fetch proargmodes; if it's null, there are no output args */
2992  proargmodes = SysCacheGetAttr(PROCOID, proctup,
2993  Anum_pg_proc_proargmodes,
2994  &isNull);
2995  if (!isNull)
2996  {
2997  /*
2998  * Split the list into input arguments in fexpr->args and output
2999  * arguments in stmt->outargs. INOUT arguments appear in both lists.
3000  */
3001  ArrayType *arr;
3002  int numargs;
3003  char *argmodes;
3004  List *inargs;
3005  int i;
3006 
3007  arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
3008  numargs = list_length(fexpr->args);
3009  if (ARR_NDIM(arr) != 1 ||
3010  ARR_DIMS(arr)[0] != numargs ||
3011  ARR_HASNULL(arr) ||
3012  ARR_ELEMTYPE(arr) != CHAROID)
3013  elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
3014  numargs);
3015  argmodes = (char *) ARR_DATA_PTR(arr);
3016 
3017  inargs = NIL;
3018  i = 0;
3019  foreach(lc, fexpr->args)
3020  {
3021  Node *n = lfirst(lc);
3022 
3023  switch (argmodes[i])
3024  {
3025  case PROARGMODE_IN:
3026  case PROARGMODE_VARIADIC:
3027  inargs = lappend(inargs, n);
3028  break;
3029  case PROARGMODE_OUT:
3030  outargs = lappend(outargs, n);
3031  break;
3032  case PROARGMODE_INOUT:
3033  inargs = lappend(inargs, n);
3034  outargs = lappend(outargs, copyObject(n));
3035  break;
3036  default:
3037  /* note we don't support PROARGMODE_TABLE */
3038  elog(ERROR, "invalid argmode %c for procedure",
3039  argmodes[i]);
3040  break;
3041  }
3042  i++;
3043  }
3044  fexpr->args = inargs;
3045  }
3046 
3047  stmt->funcexpr = fexpr;
3048  stmt->outargs = outargs;
3049 
3050  ReleaseSysCache(proctup);
3051 
3052  /* represent the command as a utility Query */
3053  result = makeNode(Query);
3054  result->commandType = CMD_UTILITY;
3055  result->utilityStmt = (Node *) stmt;
3056 
3057  return result;
3058 }
Oid funcresulttype
Definition: primnodes.h:496
#define NIL
Definition: pg_list.h:65
List * args
Definition: primnodes.h:503
FuncExpr * funcexpr
Definition: parsenodes.h:3026
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
FuncCall * funccall
Definition: parsenodes.h:3025
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
Definition: nodes.h:539
int location
Definition: parsenodes.h:371
Node * utilityStmt
Definition: parsenodes.h:128
void assign_expr_collations(ParseState *pstate, Node *expr)
Oid funcid
Definition: primnodes.h:495
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, Node *last_srf, FuncCall *fn, bool proc_call, int location)
Definition: parse_func.c:90
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define ARR_HASNULL(a)
Definition: array.h:284
List * lappend(List *list, void *datum)
Definition: list.c:336
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
Node * p_last_srf
Definition: parse_node.h:214
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
List * outargs
Definition: parsenodes.h:3027
CmdType commandType
Definition: parsenodes.h:120
#define makeNode(_type_)
Definition: nodes.h:587
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:169
List * args
Definition: parsenodes.h:362
static int list_length(const List *l)
Definition: pg_list.h:149
#define ARR_NDIM(a)
Definition: array.h:283
#define elog(elevel,...)
Definition: elog.h:232
int i
List * expand_function_arguments(List *args, bool include_out_arguments, Oid result_type, HeapTuple func_tuple)
Definition: clauses.c:3976
List * funcname
Definition: parsenodes.h:361
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define DatumGetArrayTypeP(X)
Definition: array.h:254

◆ transformCreateTableAsStmt()

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

Definition at line 2865 of file analyze.c.

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

2866 {
2867  Query *result;
2868  Query *query;
2869 
2870  /* transform contained query, not allowing SELECT INTO */
2871  query = transformStmt(pstate, stmt->query);
2872  stmt->query = (Node *) query;
2873 
2874  /* additional work needed for CREATE MATERIALIZED VIEW */
2875  if (stmt->objtype == OBJECT_MATVIEW)
2876  {
2877  /*
2878  * Prohibit a data-modifying CTE in the query used to create a
2879  * materialized view. It's not sufficiently clear what the user would
2880  * want to happen if the MV is refreshed or incrementally maintained.
2881  */
2882  if (query->hasModifyingCTE)
2883  ereport(ERROR,
2884  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2885  errmsg("materialized views must not use data-modifying statements in WITH")));
2886 
2887  /*
2888  * Check whether any temporary database objects are used in the
2889  * creation query. It would be hard to refresh data or incrementally
2890  * maintain it if a source disappeared.
2891  */
2892  if (isQueryUsingTempRelation(query))
2893  ereport(ERROR,
2894  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2895  errmsg("materialized views must not use temporary tables or views")));
2896 
2897  /*
2898  * A materialized view would either need to save parameters for use in
2899  * maintaining/loading the data or prohibit them entirely. The latter
2900  * seems safer and more sane.
2901  */
2902  if (query_contains_extern_params(query))
2903  ereport(ERROR,
2904  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2905  errmsg("materialized views may not be defined using bound parameters")));
2906 
2907  /*
2908  * For now, we disallow unlogged materialized views, because it seems
2909  * like a bad idea for them to just go to empty after a crash. (If we
2910  * could mark them as unpopulated, that would be better, but that
2911  * requires catalog changes which crash recovery can't presently
2912  * handle.)
2913  */
2914  if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
2915  ereport(ERROR,
2916  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2917  errmsg("materialized views cannot be unlogged")));
2918 
2919  /*
2920  * At runtime, we'll need a copy of the parsed-but-not-rewritten Query
2921  * for purposes of creating the view's ON SELECT rule. We stash that
2922  * in the IntoClause because that's where intorel_startup() can
2923  * conveniently get it from.
2924  */
2925  stmt->into->viewQuery = (Node *) copyObject(query);
2926  }
2927 
2928  /* represent the command as a utility Query */
2929  result = makeNode(Query);
2930  result->commandType = CMD_UTILITY;
2931  result->utilityStmt = (Node *) stmt;
2932 
2933  return result;
2934 }
bool isQueryUsingTempRelation(Query *query)
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
Node * utilityStmt
Definition: parsenodes.h:128
ObjectType objtype
Definition: parsenodes.h:3398
#define ERROR
Definition: elog.h:46
Node * viewQuery
Definition: primnodes.h:118
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:276
#define ereport(elevel,...)
Definition: elog.h:157
IntoClause * into
Definition: parsenodes.h:3397
CmdType commandType
Definition: parsenodes.h:120
#define makeNode(_type_)
Definition: nodes.h:587
bool query_contains_extern_params(Query *query)
Definition: parse_param.c:334
char relpersistence
Definition: primnodes.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:909
RangeVar * rel
Definition: primnodes.h:112
bool hasModifyingCTE
Definition: parsenodes.h:139
#define copyObject(obj)
Definition: nodes.h:655

◆ transformDeclareCursorStmt()

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

Definition at line 2748 of file analyze.c.

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

2749 {
2750  Query *result;
2751  Query *query;
2752 
2753  if ((stmt->options & CURSOR_OPT_SCROLL) &&
2754  (stmt->options & CURSOR_OPT_NO_SCROLL))
2755  ereport(ERROR,
2756  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2757  /* translator: %s is a SQL keyword */
2758  errmsg("cannot specify both %s and %s",
2759  "SCROLL", "NO SCROLL")));
2760 
2761  if ((stmt->options & CURSOR_OPT_ASENSITIVE) &&
2762  (stmt->options & CURSOR_OPT_INSENSITIVE))
2763  ereport(ERROR,
2764  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2765  /* translator: %s is a SQL keyword */
2766  errmsg("cannot specify both %s and %s",
2767  "ASENSITIVE", "INSENSITIVE")));
2768 
2769  /* Transform contained query, not allowing SELECT INTO */
2770  query = transformStmt(pstate, stmt->query);
2771  stmt->query = (Node *) query;
2772 
2773  /* Grammar should not have allowed anything but SELECT */
2774  if (!IsA(query, Query) ||
2775  query->commandType != CMD_SELECT)
2776  elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
2777 
2778  /*
2779  * We also disallow data-modifying WITH in a cursor. (This could be
2780  * allowed, but the semantics of when the updates occur might be
2781  * surprising.)
2782  */
2783  if (query->hasModifyingCTE)
2784  ereport(ERROR,
2785  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2786  errmsg("DECLARE CURSOR must not contain data-modifying statements in WITH")));
2787 
2788  /* FOR UPDATE and WITH HOLD are not compatible */
2789  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
2790  ereport(ERROR,
2791  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2792  /*------
2793  translator: %s is a SQL row locking clause such as FOR UPDATE */
2794  errmsg("DECLARE CURSOR WITH HOLD ... %s is not supported",
2796  linitial(query->rowMarks))->strength)),
2797  errdetail("Holdable cursors must be READ ONLY.")));
2798 
2799  /* FOR UPDATE and SCROLL are not compatible */
2800  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL))
2801  ereport(ERROR,
2802  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2803  /*------
2804  translator: %s is a SQL row locking clause such as FOR UPDATE */
2805  errmsg("DECLARE SCROLL CURSOR ... %s is not supported",
2807  linitial(query->rowMarks))->strength)),
2808  errdetail("Scrollable cursors must be READ ONLY.")));
2809 
2810  /* FOR UPDATE and INSENSITIVE are not compatible */
2811  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE))
2812  ereport(ERROR,
2813  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2814  /*------
2815  translator: %s is a SQL row locking clause such as FOR UPDATE */
2816  errmsg("DECLARE INSENSITIVE CURSOR ... %s is not valid",
2818  linitial(query->rowMarks))->strength)),
2819  errdetail("Insensitive cursors must be READ ONLY.")));
2820 
2821  /* represent the command as a utility Query */
2822  result = makeNode(Query);
2823  result->commandType = CMD_UTILITY;
2824  result->utilityStmt = (Node *) stmt;
2825 
2826  return result;
2827 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3065
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2811
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
#define CURSOR_OPT_INSENSITIVE
Definition: parsenodes.h:2809
List * rowMarks
Definition: parsenodes.h:175
Node * utilityStmt
Definition: parsenodes.h:128
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2808
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
#define CURSOR_OPT_ASENSITIVE
Definition: parsenodes.h:2810
int errdetail(const char *fmt,...)
Definition: elog.c:1042
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:276
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
#define makeNode(_type_)
Definition: nodes.h:587
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2807
bool hasModifyingCTE
Definition: parsenodes.h:139

◆ transformDeleteStmt()

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

Definition at line 429 of file analyze.c.

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

430 {
431  Query *qry = makeNode(Query);
432  ParseNamespaceItem *nsitem;
433  Node *qual;
434 
435  qry->commandType = CMD_DELETE;
436 
437  /* process the WITH clause independently of all else */
438  if (stmt->withClause)
439  {
440  qry->hasRecursive = stmt->withClause->recursive;
441  qry->cteList = transformWithClause(pstate, stmt->withClause);
442  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
443  }
444 
445  /* set up range table with just the result rel */
446  qry->resultRelation = setTargetTable(pstate, stmt->relation,
447  stmt->relation->inh,
448  true,
449  ACL_DELETE);
450  nsitem = pstate->p_target_nsitem;
451 
452  /* there's no DISTINCT in DELETE */
453  qry->distinctClause = NIL;
454 
455  /* subqueries in USING cannot access the result relation */
456  nsitem->p_lateral_only = true;
457  nsitem->p_lateral_ok = false;
458 
459  /*
460  * The USING clause is non-standard SQL syntax, and is equivalent in
461  * functionality to the FROM list that can be specified for UPDATE. The
462  * USING keyword is used rather than FROM because FROM is already a
463  * keyword in the DELETE syntax.
464  */
465  transformFromClause(pstate, stmt->usingClause);
466 
467  /* remaining clauses can reference the result relation normally */
468  nsitem->p_lateral_only = false;
469  nsitem->p_lateral_ok = true;
470 
471  qual = transformWhereClause(pstate, stmt->whereClause,
472  EXPR_KIND_WHERE, "WHERE");
473 
474  qry->returningList = transformReturningList(pstate, stmt->returningList);
475 
476  /* done building the range table and jointree */
477  qry->rtable = pstate->p_rtable;
478  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
479 
480  qry->hasSubLinks = pstate->p_hasSubLinks;
481  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
482  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
483  qry->hasAggs = pstate->p_hasAggs;
484 
485  assign_query_collations(pstate, qry);
486 
487  /* this must be done after collations, for reliable comparison of exprs */
488  if (pstate->p_hasAggs)
489  parseCheckAggregates(pstate, qry);
490 
491  return qry;
492 }
#define NIL
Definition: pg_list.h:65
bool p_hasSubLinks
Definition: parse_node.h:211
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
RangeVar * relation
Definition: parsenodes.h:1596
FromExpr * jointree
Definition: parsenodes.h:148
bool hasAggs
Definition: parsenodes.h:133
int resultRelation
Definition: parsenodes.h:130
bool p_hasTargetSRFs
Definition: parse_node.h:210
Definition: nodes.h:539
#define ACL_DELETE
Definition: parsenodes.h:85
bool p_hasAggs
Definition: parse_node.h:208
static List * transformReturningList(ParseState *pstate, List *returningList)
Definition: analyze.c:2442
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:193
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1059
bool p_hasWindowFuncs
Definition: parse_node.h:209
bool hasRecursive
Definition: parsenodes.h:138
WithClause * withClause
Definition: parsenodes.h:1600
List * returningList
Definition: parsenodes.h:1599
List * rtable
Definition: parsenodes.h:147
List * distinctClause
Definition: parsenodes.h:167
bool recursive
Definition: parsenodes.h:1425
List * returningList
Definition: parsenodes.h:156
bool p_hasModifyingCTE
Definition: parse_node.h:212
bool inh
Definition: primnodes.h:69
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:113
Node * whereClause
Definition: parsenodes.h:1598
List * usingClause
Definition: parsenodes.h:1597
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:177
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
#define makeNode(_type_)
Definition: nodes.h:587
bool hasWindowFuncs
Definition: parsenodes.h:134
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:109
List * cteList
Definition: parsenodes.h:145
bool hasSubLinks
Definition: parsenodes.h:136
void assign_query_collations(ParseState *pstate, Query *query)
List * p_joinlist
Definition: parse_node.h:184
bool hasModifyingCTE
Definition: parsenodes.h:139
List * p_rtable
Definition: parse_node.h:182

◆ transformExplainStmt()

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

Definition at line 2841 of file analyze.c.

References CMD_UTILITY, Query::commandType, makeNode, ExplainStmt::query, transformOptionalSelectInto(), and Query::utilityStmt.

Referenced by transformStmt().

2842 {
2843  Query *result;
2844 
2845  /* transform contained query, allowing SELECT INTO */
2846  stmt->query = (Node *) transformOptionalSelectInto(pstate, stmt->query);
2847 
2848  /* represent the command as a utility Query */
2849  result = makeNode(Query);
2850  result->commandType = CMD_UTILITY;
2851  result->utilityStmt = (Node *) stmt;
2852 
2853  return result;
2854 }
Definition: nodes.h:539
Node * utilityStmt
Definition: parsenodes.h:128
Node * query
Definition: parsenodes.h:3376
CmdType commandType
Definition: parsenodes.h:120
#define makeNode(_type_)
Definition: nodes.h:587
static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
Definition: analyze.c:237

◆ transformInsertRow()

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

Definition at line 919 of file analyze.c.

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

922 {
923  List *result;
924  ListCell *lc;
925  ListCell *icols;
926  ListCell *attnos;
927 
928  /*
929  * Check length of expr list. It must not have more expressions than
930  * there are target columns. We allow fewer, but only if no explicit
931  * columns list was given (the remaining columns are implicitly
932  * defaulted). Note we must check this *after* transformation because
933  * that could expand '*' into multiple items.
934  */
935  if (list_length(exprlist) > list_length(icolumns))
936  ereport(ERROR,
937  (errcode(ERRCODE_SYNTAX_ERROR),
938  errmsg("INSERT has more expressions than target columns"),
939  parser_errposition(pstate,
940  exprLocation(list_nth(exprlist,
941  list_length(icolumns))))));
942  if (stmtcols != NIL &&
943  list_length(exprlist) < list_length(icolumns))
944  {
945  /*
946  * We can get here for cases like INSERT ... SELECT (a,b,c) FROM ...
947  * where the user accidentally created a RowExpr instead of separate
948  * columns. Add a suitable hint if that seems to be the problem,
949  * because the main error message is quite misleading for this case.
950  * (If there's no stmtcols, you'll get something about data type
951  * mismatch, which is less misleading so we don't worry about giving a
952  * hint in that case.)
953  */
954  ereport(ERROR,
955  (errcode(ERRCODE_SYNTAX_ERROR),
956  errmsg("INSERT has more target columns than expressions"),
957  ((list_length(exprlist) == 1 &&
958  count_rowexpr_columns(pstate, linitial(exprlist)) ==
959  list_length(icolumns)) ?
960  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),
961  parser_errposition(pstate,
962  exprLocation(list_nth(icolumns,
963  list_length(exprlist))))));
964  }
965 
966  /*
967  * Prepare columns for assignment to target table.
968  */
969  result = NIL;
970  forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
971  {
972  Expr *expr = (Expr *) lfirst(lc);
973  ResTarget *col = lfirst_node(ResTarget, icols);
974  int attno = lfirst_int(attnos);
975 
976  expr = transformAssignedExpr(pstate, expr,
978  col->name,
979  attno,
980  col->indirection,
981  col->location);
982 
983  if (strip_indirection)
984  {
985  while (expr)
986  {
987  if (IsA(expr, FieldStore))
988  {
989  FieldStore *fstore = (FieldStore *) expr;
990 
991  expr = (Expr *) linitial(fstore->newvals);
992  }
993  else if (IsA(expr, SubscriptingRef))
994  {
995  SubscriptingRef *sbsref = (SubscriptingRef *) expr;
996 
997  if (sbsref->refassgnexpr == NULL)
998  break;
999 
1000  expr = sbsref->refassgnexpr;
1001  }
1002  else
1003  break;
1004  }
1005  }
1006 
1007  result = lappend(result, expr);
1008  }
1009 
1010  return result;
1011 }
List * indirection
Definition: parsenodes.h:453
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
int errhint(const char *fmt,...)
Definition: elog.c:1156
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
Expr * transformAssignedExpr(ParseState *pstate, Expr *expr, ParseExprKind exprKind, const char *colname, int attrno, List *indirection, int location)
Definition: parse_target.c:455
char * name
Definition: parsenodes.h:452
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:491
static int count_rowexpr_columns(ParseState *pstate, Node *expr)
Definition: analyze.c:1197
int errcode(int sqlerrcode)
Definition: elog.c:698
int location
Definition: parsenodes.h:455
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
#define lfirst_node(type, lc)
Definition: pg_list.h:172
List * newvals
Definition: primnodes.h:838
List * lappend(List *list, void *datum)
Definition: list.c:336
#define ereport(elevel,...)
Definition: elog.h:157
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
Expr * refassgnexpr
Definition: primnodes.h:451
int errmsg(const char *fmt,...)
Definition: elog.c:909
Definition: pg_list.h:50

◆ transformInsertStmt()

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

Definition at line 499 of file analyze.c.

References ACL_INSERT, ACL_UPDATE, OnConflictClause::action, addNSItemToQuery(), addRangeTableEntryForSubquery(), addRangeTableEntryForValues(), Assert, assign_list_collations(), assign_query_collations(), bms_add_member(), checkInsertTargets(), CMD_INSERT, CMD_SELECT, InsertStmt::cols, Query::commandType, contain_vars_of_level(), Query::cteList, elog, ereport, errcode(), errmsg(), ERROR, expandNSItemVars(), TargetEntry::expr, EXPR_KIND_VALUES, EXPR_KIND_VALUES_SINGLE, exprLocation(), exprType(), exprTypmod(), FirstLowInvalidHeapAttributeNumber, forthree, free_parsestate(), Query::hasModifyingCTE, Query::hasRecursive, InvalidOid, IsA, lappend(), lappend_int(), lappend_oid(), lfirst, lfirst_int, lfirst_node, SelectStmt::limitCount, SelectStmt::limitOffset, linitial, list_length(), Var::location, SelectStmt::lockingClause, make_parsestate(), makeAlias(), makeFromExpr(), makeNode, makeTargetEntry(), makeVarFromTargetEntry(), ResTarget::name, 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, parser_errposition(), WithClause::recursive, InsertStmt::relation, TargetEntry::resjunk, Query::resultRelation, InsertStmt::selectStmt, setTargetTable(), SelectStmt::sortClause, Query::targetList, transformExpressionList(), transformInsertRow(), transformOnConflictClause(), transformReturningList(), transformStmt(), transformWithClause(), val, SelectStmt::valuesLists, InsertStmt::withClause, and SelectStmt::withClause.

Referenced by transformStmt().

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

◆ transformLockingClause()

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

Definition at line 3154 of file analyze.c.

References ACL_SELECT_FOR_UPDATE, Alias::aliasname, applyLockingClause(), RangeVar::catalogname, CheckSelectLocking(), elog, RangeTblEntry::eref, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, i, 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().

3156 {
3157  List *lockedRels = lc->lockedRels;
3158  ListCell *l;
3159  ListCell *rt;
3160  Index i;
3161  LockingClause *allrels;
3162 
3163  CheckSelectLocking(qry, lc->strength);
3164 
3165  /* make a clause we can pass down to subqueries to select all rels */
3166  allrels = makeNode(LockingClause);
3167  allrels->lockedRels = NIL; /* indicates all rels */
3168  allrels->strength = lc->strength;
3169  allrels->waitPolicy = lc->waitPolicy;
3170 
3171  if (lockedRels == NIL)
3172  {
3173  /* all regular tables used in query */
3174  i = 0;
3175  foreach(rt, qry->rtable)
3176  {
3177  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3178 
3179  ++i;
3180  switch (rte->rtekind)
3181  {
3182  case RTE_RELATION:
3183  applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3184  pushedDown);
3186  break;
3187  case RTE_SUBQUERY:
3188  applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3189  pushedDown);
3190 
3191  /*
3192  * FOR UPDATE/SHARE of subquery is propagated to all of
3193  * subquery's rels, too. We could do this later (based on
3194  * the marking of the subquery RTE) but it is convenient
3195  * to have local knowledge in each query level about which
3196  * rels need to be opened with RowShareLock.
3197  */
3198  transformLockingClause(pstate, rte->subquery,
3199  allrels, true);
3200  break;
3201  default:
3202  /* ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE RTEs */
3203  break;
3204  }
3205  }
3206  }
3207  else
3208  {
3209  /* just the named tables */
3210  foreach(l, lockedRels)
3211  {
3212  RangeVar *thisrel = (RangeVar *) lfirst(l);
3213 
3214  /* For simplicity we insist on unqualified alias names here */
3215  if (thisrel->catalogname || thisrel->schemaname)
3216  ereport(ERROR,
3217  (errcode(ERRCODE_SYNTAX_ERROR),
3218  /*------
3219  translator: %s is a SQL row locking clause such as FOR UPDATE */
3220  errmsg("%s must specify unqualified relation names",
3221  LCS_asString(lc->strength)),
3222  parser_errposition(pstate, thisrel->location)));
3223 
3224  i = 0;
3225  foreach(rt, qry->rtable)
3226  {
3227  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3228 
3229  ++i;
3230  if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
3231  {
3232  switch (rte->rtekind)
3233  {
3234  case RTE_RELATION:
3235  applyLockingClause(qry, i, lc->strength,
3236  lc->waitPolicy, pushedDown);
3238  break;
3239  case RTE_SUBQUERY:
3240  applyLockingClause(qry, i, lc->strength,
3241  lc->waitPolicy, pushedDown);
3242  /* see comment above */
3243  transformLockingClause(pstate, rte->subquery,
3244  allrels, true);
3245  break;
3246  case RTE_JOIN:
3247  ereport(ERROR,
3248  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3249  /*------
3250  translator: %s is a SQL row locking clause such as FOR UPDATE */
3251  errmsg("%s cannot be applied to a join",
3252  LCS_asString(lc->strength)),
3253  parser_errposition(pstate, thisrel->location)));
3254  break;
3255  case RTE_FUNCTION:
3256  ereport(ERROR,
3257  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3258  /*------
3259  translator: %s is a SQL row locking clause such as FOR UPDATE */
3260  errmsg("%s cannot be applied to a function",
3261  LCS_asString(lc->strength)),
3262  parser_errposition(pstate, thisrel->location)));
3263  break;
3264  case RTE_TABLEFUNC:
3265  ereport(ERROR,
3266  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3267  /*------
3268  translator: %s is a SQL row locking clause such as FOR UPDATE */
3269  errmsg("%s cannot be applied to a table function",
3270  LCS_asString(lc->strength)),
3271  parser_errposition(pstate, thisrel->location)));
3272  break;
3273  case RTE_VALUES:
3274  ereport(ERROR,
3275  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3276  /*------
3277  translator: %s is a SQL row locking clause such as FOR UPDATE */
3278  errmsg("%s cannot be applied to VALUES",
3279  LCS_asString(lc->strength)),
3280  parser_errposition(pstate, thisrel->location)));
3281  break;
3282  case RTE_CTE:
3283  ereport(ERROR,
3284  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3285  /*------
3286  translator: %s is a SQL row locking clause such as FOR UPDATE */
3287  errmsg("%s cannot be applied to a WITH query",
3288  LCS_asString(lc->strength)),
3289  parser_errposition(pstate, thisrel->location)));
3290  break;
3291  case RTE_NAMEDTUPLESTORE:
3292  ereport(ERROR,
3293  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3294  /*------
3295  translator: %s is a SQL row locking clause such as FOR UPDATE */
3296  errmsg("%s cannot be applied to a named tuplestore",
3297  LCS_asString(lc->strength)),
3298  parser_errposition(pstate, thisrel->location)));
3299  break;
3300 
3301  /* Shouldn't be possible to see RTE_RESULT here */
3302 
3303  default:
3304  elog(ERROR, "unrecognized RTE type: %d",
3305  (int) rte->rtekind);
3306  break;
3307  }
3308  break; /* out of foreach loop */
3309  }
3310  }
3311  if (rt == NULL)
3312  ereport(ERROR,
3314  /*------
3315  translator: %s is a SQL row locking clause such as FOR UPDATE */
3316  errmsg("relation \"%s\" in %s clause not found in FROM clause",
3317  thisrel->relname,
3318  LCS_asString(lc->strength)),
3319  parser_errposition(pstate, thisrel->location)));
3320  }
3321  }
3322 }
List * lockedRels
Definition: parsenodes.h:764
#define NIL
Definition: pg_list.h:65
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:3154
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3065
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
int errcode(int sqlerrcode)
Definition: elog.c:698
AclMode requiredPerms
Definition: parsenodes.h:1145
char * schemaname
Definition: primnodes.h:67
int location
Definition: primnodes.h:73
char * relname
Definition: primnodes.h:68
void CheckSelectLocking(Query *qry, LockClauseStrength strength)
Definition: analyze.c:3090
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
LockClauseStrength strength
Definition: parsenodes.h:765
unsigned int Index
Definition: c.h:549
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:587
#define lfirst(lc)
Definition: pg_list.h:169
char * aliasname
Definition: primnodes.h:42
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:98
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
Alias * eref
Definition: parsenodes.h:1141
Definition: pg_list.h:50
LockWaitPolicy waitPolicy
Definition: parsenodes.h:766
char * catalogname
Definition: primnodes.h:66
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3328

◆ transformOnConflictClause()

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

Definition at line 1018 of file analyze.c.

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.

Referenced by transformInsertStmt().

1020 {
1021  ParseNamespaceItem *exclNSItem = NULL;
1022  List *arbiterElems;
1023  Node *arbiterWhere;
1024  Oid arbiterConstraint;
1025  List *onConflictSet = NIL;
1026  Node *onConflictWhere = NULL;
1027  int exclRelIndex = 0;
1028  List *exclRelTlist = NIL;
1029  OnConflictExpr *result;
1030 
1031  /*
1032  * If this is ON CONFLICT ... UPDATE, first create the range table entry
1033  * for the EXCLUDED pseudo relation, so that that will be present while
1034  * processing arbiter expressions. (You can't actually reference it from
1035  * there, but this provides a useful error message if you try.)
1036  */
1037  if (onConflictClause->action == ONCONFLICT_UPDATE)
1038  {
1039  Relation targetrel = pstate->p_target_relation;
1040  RangeTblEntry *exclRte;
1041 
1042  exclNSItem = addRangeTableEntryForRelation(pstate,
1043  targetrel,
1045  makeAlias("excluded", NIL),
1046  false, false);
1047  exclRte = exclNSItem->p_rte;
1048  exclRelIndex = exclNSItem->p_rtindex;
1049 
1050  /*
1051  * relkind is set to composite to signal that we're not dealing with
1052  * an actual relation, and no permission checks are required on it.
1053  * (We'll check the actual target relation, instead.)
1054  */
1055  exclRte->relkind = RELKIND_COMPOSITE_TYPE;
1056  exclRte->requiredPerms = 0;
1057  /* other permissions fields in exclRte are already empty */
1058 
1059  /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
1060  exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
1061  exclRelIndex);
1062  }
1063 
1064  /* Process the arbiter clause, ON CONFLICT ON (...) */
1065  transformOnConflictArbiter(pstate, onConflictClause, &arbiterElems,
1066  &arbiterWhere, &arbiterConstraint);
1067 
1068  /* Process DO UPDATE */
1069  if (onConflictClause->action == ONCONFLICT_UPDATE)
1070  {
1071  /*
1072  * Expressions in the UPDATE targetlist need to be handled like UPDATE
1073  * not INSERT. We don't need to save/restore this because all INSERT
1074  * expressions have been parsed already.
1075  */
1076  pstate->p_is_insert = false;
1077 
1078  /*
1079  * Add the EXCLUDED pseudo relation to the query namespace, making it
1080  * available in the UPDATE subexpressions.
1081  */
1082  addNSItemToQuery(pstate, exclNSItem, false, true, true);
1083 
1084  /*
1085  * Now transform the UPDATE subexpressions.
1086  */
1087  onConflictSet =
1088  transformUpdateTargetList(pstate, onConflictClause->targetList);
1089 
1090  onConflictWhere = transformWhereClause(pstate,
1091  onConflictClause->whereClause,
1092  EXPR_KIND_WHERE, "WHERE");
1093 
1094  /*
1095  * Remove the EXCLUDED pseudo relation from the query namespace, since
1096  * it's not supposed to be available in RETURNING. (Maybe someday we
1097  * could allow that, and drop this step.)
1098  */
1099  Assert((ParseNamespaceItem *) llast(pstate->p_namespace) == exclNSItem);
1100  pstate->p_namespace = list_delete_last(pstate->p_namespace);
1101  }
1102 
1103  /* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */
1104  result = makeNode(OnConflictExpr);
1105 
1106  result->action = onConflictClause->action;
1107  result->arbiterElems = arbiterElems;
1108  result->arbiterWhere = arbiterWhere;
1109  result->constraint = arbiterConstraint;
1110  result->onConflictSet = onConflictSet;
1111  result->onConflictWhere = onConflictWhere;
1112  result->exclRelIndex = exclRelIndex;
1113  result->exclRelTlist = exclRelTlist;
1114 
1115  return result;
1116 }
#define NIL
Definition: pg_list.h:65
static List * transformUpdateTargetList(ParseState *pstate, List *targetList)
Definition: analyze.c:2370
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1127
#define llast(l)
Definition: pg_list.h:194
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Definition: nodes.h:539
void transformOnConflictArbiter(ParseState *pstate, OnConflictClause *onConflictClause, List **arbiterExpr, Node **arbiterWhere, Oid *constraint)
AclMode requiredPerms
Definition: parsenodes.h:1145
unsigned int Oid
Definition: postgres_ext.h:31
List * arbiterElems
Definition: primnodes.h:1582
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
RangeTblEntry * p_rte
Definition: parse_node.h:268
List * p_namespace
Definition: parse_node.h:186
List * exclRelTlist
Definition: primnodes.h:1591
#define RowExclusiveLock
Definition: lockdefs.h:38
List * list_delete_last(List *list)
Definition: list.c:892
OnConflictAction action
Definition: primnodes.h:1579
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
Node * arbiterWhere
Definition: primnodes.h:1584
Relation p_target_relation
Definition: parse_node.h:192
bool p_is_insert
Definition: parse_node.h:194
List * onConflictSet
Definition: primnodes.h:1588
Node * onConflictWhere
Definition: primnodes.h:1589
OnConflictAction action
Definition: parsenodes.h:1453
Definition: pg_list.h:50

◆ transformOptionalSelectInto()

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

Definition at line 237 of file analyze.c.

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

238 {
239  if (IsA(parseTree, SelectStmt))
240  {
241  SelectStmt *stmt = (SelectStmt *) parseTree;
242 
243  /* If it's a set-operation tree, drill down to leftmost SelectStmt */
244  while (stmt && stmt->op != SETOP_NONE)
245  stmt = stmt->larg;
246  Assert(stmt && IsA(stmt, SelectStmt) && stmt->larg == NULL);
247 
248  if (stmt->intoClause)
249  {
251 
252  ctas->query = parseTree;
253  ctas->into = stmt->intoClause;
254  ctas->objtype = OBJECT_TABLE;
255  ctas->is_select_into = true;
256 
257  /*
258  * Remove the intoClause from the SelectStmt. This makes it safe
259  * for transformSelectStmt to complain if it finds intoClause set
260  * (implying that the INTO appeared in a disallowed place).
261  */
262  stmt->intoClause = NULL;
263 
264  parseTree = (Node *) ctas;
265  }
266  }
267 
268  return transformStmt(pstate, parseTree);
269 }
struct SelectStmt * larg
Definition: parsenodes.h:1683
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
IntoClause * intoClause
Definition: parsenodes.h:1648
Definition: nodes.h:539
ObjectType objtype
Definition: parsenodes.h:3398
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:276
SetOperation op
Definition: parsenodes.h:1681
IntoClause * into
Definition: parsenodes.h:3397
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804

◆ transformPLAssignStmt()

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

Definition at line 2500 of file analyze.c.

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

2501 {
2502  Query *qry = makeNode(Query);
2503  ColumnRef *cref = makeNode(ColumnRef);
2504  List *indirection = stmt->indirection;
2505  int nnames = stmt->nnames;
2506  SelectStmt *sstmt = stmt->val;
2507  Node *target;
2508  Oid targettype;
2509  int32 targettypmod;
2510  Oid targetcollation;
2511  List *tlist;
2512  TargetEntry *tle;
2513  Oid type_id;
2514  Node *qual;
2515  ListCell *l;
2516 
2517  /*
2518  * First, construct a ColumnRef for the target variable. If the target
2519  * has more than one dotted name, we have to pull the extra names out of
2520  * the indirection list.
2521  */
2522  cref->fields = list_make1(makeString(stmt->name));
2523  cref->location = stmt->location;
2524  if (nnames > 1)
2525  {
2526  /* avoid munging the raw parsetree */
2527  indirection = list_copy(indirection);
2528  while (--nnames > 0 && indirection != NIL)
2529  {
2530  Node *ind = (Node *) linitial(indirection);
2531 
2532  if (!IsA(ind, String))
2533  elog(ERROR, "invalid name count in PLAssignStmt");
2534  cref->fields = lappend(cref->fields, ind);
2535  indirection = list_delete_first(indirection);
2536  }
2537  }
2538 
2539  /*
2540  * Transform the target reference. Typically we will get back a Param
2541  * node, but there's no reason to be too picky about its type.
2542  */
2543  target = transformExpr(pstate, (Node *) cref,
2545  targettype = exprType(target);
2546  targettypmod = exprTypmod(target);
2547  targetcollation = exprCollation(target);
2548 
2549  /*
2550  * The rest mostly matches transformSelectStmt, except that we needn't
2551  * consider WITH or INTO, and we build a targetlist our own way.
2552  */
2553  qry->commandType = CMD_SELECT;
2554  pstate->p_is_insert = false;
2555 
2556  /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
2557  pstate->p_locking_clause = sstmt->lockingClause;
2558 
2559  /* make WINDOW info available for window functions, too */
2560  pstate->p_windowdefs = sstmt->windowClause;
2561 
2562  /* process the FROM clause */
2563  transformFromClause(pstate, sstmt->fromClause);
2564 
2565  /* initially transform the targetlist as if in SELECT */
2566  tlist = transformTargetList(pstate, sstmt->targetList,
2568 
2569  /* we should have exactly one targetlist item */
2570  if (list_length(tlist) != 1)
2571  ereport(ERROR,
2572  (errcode(ERRCODE_SYNTAX_ERROR),
2573  errmsg_plural("assignment source returned %d column",
2574  "assignment source returned %d columns",
2575  list_length(tlist),
2576  list_length(tlist))));
2577 
2578  tle = linitial_node(TargetEntry, tlist);
2579 
2580  /*
2581  * This next bit is similar to transformAssignedExpr; the key difference
2582  * is we use COERCION_PLPGSQL not COERCION_ASSIGNMENT.
2583  */
2584  type_id = exprType((Node *) tle->expr);
2585 
2587 
2588  if (indirection)
2589  {
2590  tle->expr = (Expr *)
2592  target,
2593  stmt->name,
2594  false,
2595  targettype,
2596  targettypmod,
2597  targetcollation,
2598  indirection,
2599  list_head(indirection),
2600  (Node *) tle->expr,
2602  exprLocation(target));
2603  }
2604  else if (targettype != type_id &&
2605  (targettype == RECORDOID || ISCOMPLEX(targettype)) &&
2606  (type_id == RECORDOID || ISCOMPLEX(type_id)))
2607  {
2608  /*
2609  * Hack: do not let coerce_to_target_type() deal with inconsistent
2610  * composite types. Just pass the expression result through as-is,
2611  * and let the PL/pgSQL executor do the conversion its way. This is
2612  * rather bogus, but it's needed for backwards compatibility.
2613  */
2614  }
2615  else
2616  {
2617  /*
2618  * For normal non-qualified target column, do type checking and
2619  * coercion.
2620  */
2621  Node *orig_expr = (Node *) tle->expr;
2622 
2623  tle->expr = (Expr *)
2624  coerce_to_target_type(pstate,
2625  orig_expr, type_id,
2626  targettype, targettypmod,
2629  -1);
2630  /* With COERCION_PLPGSQL, this error is probably unreachable */
2631  if (tle->expr == NULL)
2632  ereport(ERROR,
2633  (errcode(ERRCODE_DATATYPE_MISMATCH),
2634  errmsg("variable \"%s\" is of type %s"
2635  " but expression is of type %s",
2636  stmt->name,
2637  format_type_be(targettype),
2638  format_type_be(type_id)),
2639  errhint("You will need to rewrite or cast the expression."),
2640  parser_errposition(pstate, exprLocation(orig_expr))));
2641  }
2642 
2643  pstate->p_expr_kind = EXPR_KIND_NONE;
2644 
2645  qry->targetList = list_make1(tle);
2646 
2647  /* transform WHERE */
2648  qual = transformWhereClause(pstate, sstmt->whereClause,
2649  EXPR_KIND_WHERE, "WHERE");
2650 
2651  /* initial processing of HAVING clause is much like WHERE clause */
2652  qry->havingQual = transformWhereClause(pstate, sstmt->havingClause,
2653  EXPR_KIND_HAVING, "HAVING");
2654 
2655  /*
2656  * Transform sorting/grouping stuff. Do ORDER BY first because both
2657  * transformGroupClause and transformDistinctClause need the results. Note
2658  * that these functions can also change the targetList, so it's passed to
2659  * them by reference.
2660  */
2661  qry->sortClause = transformSortClause(pstate,
2662  sstmt->sortClause,
2663  &qry->targetList,
2665  false /* allow SQL92 rules */ );
2666 
2667  qry->groupClause = transformGroupClause(pstate,
2668  sstmt->groupClause,
2669  &qry->groupingSets,
2670  &qry->targetList,
2671  qry->sortClause,
2673  false /* allow SQL92 rules */ );
2674 
2675  if (sstmt->distinctClause == NIL)
2676  {
2677  qry->distinctClause = NIL;
2678  qry->hasDistinctOn = false;
2679  }
2680  else if (linitial(sstmt->distinctClause) == NULL)
2681  {
2682  /* We had SELECT DISTINCT */
2684  &qry->targetList,
2685  qry->sortClause,
2686  false);
2687  qry->hasDistinctOn = false;
2688  }
2689  else
2690  {
2691  /* We had SELECT DISTINCT ON */
2693  sstmt->distinctClause,
2694  &qry->targetList,
2695  qry->sortClause);
2696  qry->hasDistinctOn = true;
2697  }
2698 
2699  /* transform LIMIT */
2700  qry->limitOffset = transformLimitClause(pstate, sstmt->limitOffset,
2701  EXPR_KIND_OFFSET, "OFFSET",
2702  sstmt->limitOption);
2703  qry->limitCount = transformLimitClause(pstate, sstmt->limitCount,
2704  EXPR_KIND_LIMIT, "LIMIT",
2705  sstmt->limitOption);
2706  qry->limitOption = sstmt->limitOption;
2707 
2708  /* transform window clauses after we have seen all window functions */
2710  pstate->p_windowdefs,
2711  &qry->targetList);
2712 
2713  qry->rtable = pstate->p_rtable;
2714  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2715 
2716  qry->hasSubLinks = pstate->p_hasSubLinks;
2717  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2718  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2719  qry->hasAggs = pstate->p_hasAggs;
2720 
2721  foreach(l, sstmt->lockingClause)
2722  {
2723  transformLockingClause(pstate, qry,
2724  (LockingClause *) lfirst(l), false);
2725  }
2726 
2727  assign_query_collations(pstate, qry);
2728 
2729  /* this must be done after collations, for reliable comparison of exprs */
2730  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
2731  parseCheckAggregates(pstate, qry);
2732 
2733  return qry;
2734 }
Value * makeString(char *str)
Definition: value.c:53
Node * limitOffset
Definition: parsenodes.h:171
#define NIL
Definition: pg_list.h:65
LimitOption limitOption
Definition: parsenodes.h:1674
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:3154
bool p_hasSubLinks
Definition: parse_node.h:211
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
int errhint(const char *fmt,...)
Definition: elog.c:1156
List * sortClause
Definition: parsenodes.h:169
List * transformDistinctOnClause(ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
List * fromClause
Definition: parsenodes.h:1650
FromExpr * jointree
Definition: parsenodes.h:148
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1019
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
Node * limitOffset
Definition: parsenodes.h:1672
bool hasAggs
Definition: parsenodes.h:133
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
bool p_hasTargetSRFs
Definition: parse_node.h:210
List * indirection
Definition: parsenodes.h:1748
List * groupingSets
Definition: parsenodes.h:161
List * list_copy(const List *oldlist)
Definition: list.c:1418
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
bool p_hasAggs
Definition: parse_node.h:208
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
SelectStmt * val
Definition: parsenodes.h:1750
unsigned int Oid
Definition: postgres_ext.h:31
#define linitial_node(type, l)
Definition: pg_list.h:177
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1059
bool hasDistinctOn
Definition: parsenodes.h:137
signed int int32
Definition: c.h:429
List * windowClause
Definition: parsenodes.h:165
List * targetList
Definition: parsenodes.h:150
bool p_hasWindowFuncs
Definition: parse_node.h:209
int location
Definition: parsenodes.h:248
#define list_make1(x1)
Definition: pg_list.h:206
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:123
List * distinctClause
Definition: parsenodes.h:1646
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
List * distinctClause
Definition: parsenodes.h:167
#define ERROR
Definition: elog.h:46
Node * transformLimitClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName, LimitOption limitOption)
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
List * p_windowdefs
Definition: parse_node.h:195
Node * limitCount
Definition: parsenodes.h:172
List * sortClause
Definition: parsenodes.h:1671
List * targetList
Definition: parsenodes.h:1649
List * transformGroupClause(ParseState *pstate, List *grouplist, List **groupingSets, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99)
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
List * p_locking_clause
Definition: parse_node.h:199
List * lockingClause
Definition: parsenodes.h:1675
List * lappend(List *list, void *datum)
Definition: list.c:336
LimitOption limitOption
Definition: parsenodes.h:173
List * transformWindowDefinitions(ParseState *pstate, List *windowdefs, List **targetlist)
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:113
ParseExprKind p_expr_kind
Definition: parse_node.h:196
List * windowClause
Definition: parsenodes.h:1655
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
#define makeNode(_type_)
Definition: nodes.h:587
#define lfirst(lc)
Definition: pg_list.h:169
bool hasWindowFuncs
Definition: parsenodes.h:134
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
Expr * expr
Definition: primnodes.h:1454
#define ISCOMPLEX(typeid)
Definition: parse_type.h:58
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
List * groupClause
Definition: parsenodes.h:1652
List * groupClause
Definition: parsenodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool hasSubLinks
Definition: parsenodes.h:136
void assign_query_collations(ParseState *pstate, Query *query)
Node * havingClause
Definition: parsenodes.h:1654
#define elog(elevel,...)
Definition: elog.h:232
bool p_is_insert
Definition: parse_node.h:194
List * p_joinlist
Definition: parse_node.h:184
List * transformDistinctClause(ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
Node * havingQual
Definition: parsenodes.h:163
Definition: pg_list.h:50
Node * transformAssignmentIndirection(ParseState *pstate, Node *basenode, const char *targetName, bool targetIsSubscripting, Oid targetTypeId, int32 targetTypMod, Oid targetCollation, List *indirection, ListCell *indirection_cell, Node *rhs, CoercionContext ccontext, int location)
Definition: parse_target.c:686
Node * limitCount
Definition: parsenodes.h:1673
List * fields
Definition: parsenodes.h:247
Node * whereClause
Definition: parsenodes.h:1651
List * list_delete_first(List *list)
Definition: list.c:875
List * p_rtable
Definition: parse_node.h:182

◆ transformReturningList()

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

Definition at line 2442 of file analyze.c.

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(), transformInsertStmt(), and transformUpdateStmt().

2443 {
2444  List *rlist;
2445  int save_next_resno;
2446 
2447  if (returningList == NIL)
2448  return NIL; /* nothing to do */
2449 
2450  /*
2451  * We need to assign resnos starting at one in the RETURNING list. Save
2452  * and restore the main tlist's value of p_next_resno, just in case
2453  * someone looks at it later (probably won't happen).
2454  */
2455  save_next_resno = pstate->p_next_resno;
2456  pstate->p_next_resno = 1;
2457 
2458  /* transform RETURNING identically to a SELECT targetlist */
2459  rlist = transformTargetList(pstate, returningList, EXPR_KIND_RETURNING);
2460 
2461  /*
2462  * Complain if the nonempty tlist expanded to nothing (which is possible
2463  * if it contains only a star-expansion of a zero-column table). If we
2464  * allow this, the parsed Query will look like it didn't have RETURNING,
2465  * with results that would probably surprise the user.
2466  */
2467  if (rlist == NIL)
2468  ereport(ERROR,
2469  (errcode(ERRCODE_SYNTAX_ERROR),
2470  errmsg("RETURNING must have at least one column"),
2471  parser_errposition(pstate,
2472  exprLocation(linitial(returningList)))));
2473 
2474  /* mark column origins */
2475  markTargetListOrigins(pstate, rlist);
2476 
2477  /* resolve any still-unresolved output columns as being type text */
2478  if (pstate->p_resolve_unknowns)
2479  resolveTargetListUnknowns(pstate, rlist);
2480 
2481  /* restore state */
2482  pstate->p_next_resno = save_next_resno;
2483 
2484  return rlist;
2485 }
#define NIL
Definition: pg_list.h:65
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
int errcode(int sqlerrcode)
Definition: elog.c:698
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:123
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
bool p_resolve_unknowns
Definition: parse_node.h:202
int p_next_resno
Definition: parse_node.h:197
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
Definition: parse_target.c:291
#define ereport(elevel,...)
Definition: elog.h:157
void markTargetListOrigins(ParseState *pstate, List *targetlist)
Definition: parse_target.c:321
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
int errmsg(const char *fmt,...)
Definition: elog.c:909
Definition: pg_list.h:50

◆ transformReturnStmt()

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

Definition at line 2276 of file analyze.c.

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

2277 {
2278  Query *qry = makeNode(Query);
2279 
2280  qry->commandType = CMD_SELECT;
2281  qry->isReturn = true;
2282 
2284  1, NULL, false));
2285 
2286  if (pstate->p_resolve_unknowns)
2287  resolveTargetListUnknowns(pstate, qry->targetList);
2288  qry->rtable = pstate->p_rtable;
2289  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2290  qry->hasSubLinks = pstate->p_hasSubLinks;
2291  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2292  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2293  qry->hasAggs = pstate->p_hasAggs;
2294 
2295  assign_query_collations(pstate, qry);
2296 
2297  return qry;
2298 }
bool p_hasSubLinks
Definition: parse_node.h:211
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
FromExpr * jointree
Definition: parsenodes.h:148
bool hasAggs
Definition: parsenodes.h:133
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
bool p_hasTargetSRFs
Definition: parse_node.h:210
bool p_hasAggs
Definition: parse_node.h:208
List * targetList
Definition: parsenodes.h:150
bool p_hasWindowFuncs
Definition: parse_node.h:209
Node * returnval
Definition: parsenodes.h:1732
#define list_make1(x1)
Definition: pg_list.h:206
List * rtable
Definition: parsenodes.h:147
bool p_resolve_unknowns
Definition: parse_node.h:202
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
bool isReturn
Definition: parsenodes.h:143
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
Definition: parse_target.c:291
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
#define makeNode(_type_)
Definition: nodes.h:587
bool hasWindowFuncs
Definition: parsenodes.h:134
bool hasSubLinks
Definition: parsenodes.h:136
void assign_query_collations(ParseState *pstate, Query *query)
List * p_joinlist
Definition: parse_node.h:184
List * p_rtable
Definition: parse_node.h:182

◆ transformSelectStmt()

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

Definition at line 1239 of file analyze.c.

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

1240 {
1241  Query *qry = makeNode(Query);
1242  Node *qual;
1243  ListCell *l;
1244 
1245  qry->commandType = CMD_SELECT;
1246 
1247  /* process the WITH clause independently of all else */
1248  if (stmt->withClause)
1249  {
1250  qry->hasRecursive = stmt->withClause->recursive;
1251  qry->cteList = transformWithClause(pstate, stmt->withClause);
1252  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1253  }
1254 
1255  /* Complain if we get called from someplace where INTO is not allowed */
1256  if (stmt->intoClause)
1257  ereport(ERROR,
1258  (errcode(ERRCODE_SYNTAX_ERROR),
1259  errmsg("SELECT ... INTO is not allowed here"),
1260  parser_errposition(pstate,
1261  exprLocation((Node *) stmt->intoClause))));
1262 
1263  /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
1264  pstate->p_locking_clause = stmt->lockingClause;
1265 
1266  /* make WINDOW info available for window functions, too */
1267  pstate->p_windowdefs = stmt->windowClause;
1268 
1269  /* process the FROM clause */
1270  transformFromClause(pstate, stmt->fromClause);
1271 
1272  /* transform targetlist */
1273  qry->targetList = transformTargetList(pstate, stmt->targetList,
1275 
1276  /* mark column origins */
1277  markTargetListOrigins(pstate, qry->targetList);
1278 
1279  /* transform WHERE */
1280  qual = transformWhereClause(pstate, stmt->whereClause,
1281  EXPR_KIND_WHERE, "WHERE");
1282 
1283  /* initial processing of HAVING clause is much like WHERE clause */
1284  qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
1285  EXPR_KIND_HAVING, "HAVING");
1286 
1287  /*
1288  * Transform sorting/grouping stuff. Do ORDER BY first because both
1289  * transformGroupClause and transformDistinctClause need the results. Note
1290  * that these functions can also change the targetList, so it's passed to
1291  * them by reference.
1292  */
1293  qry->sortClause = transformSortClause(pstate,
1294  stmt->sortClause,
1295  &qry->targetList,
1297  false /* allow SQL92 rules */ );
1298 
1299  qry->groupClause = transformGroupClause(pstate,
1300  stmt->groupClause,
1301  &qry->groupingSets,
1302  &qry->targetList,
1303  qry->sortClause,
1305  false /* allow SQL92 rules */ );
1306  qry->groupDistinct = stmt->groupDistinct;
1307 
1308  if (stmt->distinctClause == NIL)
1309  {
1310  qry->distinctClause = NIL;
1311  qry->hasDistinctOn = false;
1312  }
1313  else if (linitial(stmt->distinctClause) == NULL)
1314  {
1315  /* We had SELECT DISTINCT */
1317  &qry->targetList,
1318  qry->sortClause,
1319  false);
1320  qry->hasDistinctOn = false;
1321  }
1322  else
1323  {
1324  /* We had SELECT DISTINCT ON */
1326  stmt->distinctClause,
1327  &qry->targetList,
1328  qry->sortClause);
1329  qry->hasDistinctOn = true;
1330  }
1331 
1332  /* transform LIMIT */
1333  qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1334  EXPR_KIND_OFFSET, "OFFSET",
1335  stmt->limitOption);
1336  qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1337  EXPR_KIND_LIMIT, "LIMIT",
1338  stmt->limitOption);
1339  qry->limitOption = stmt->limitOption;
1340 
1341  /* transform window clauses after we have seen all window functions */
1343  pstate->p_windowdefs,
1344  &qry->targetList);
1345 
1346  /* resolve any still-unresolved output columns as being type text */
1347  if (pstate->p_resolve_unknowns)
1348  resolveTargetListUnknowns(pstate, qry->targetList);
1349 
1350  qry->rtable = pstate->p_rtable;
1351  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
1352 
1353  qry->hasSubLinks = pstate->p_hasSubLinks;
1354  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1355  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1356  qry->hasAggs = pstate->p_hasAggs;
1357 
1358  foreach(l, stmt->lockingClause)
1359  {
1360  transformLockingClause(pstate, qry,
1361  (LockingClause *) lfirst(l), false);
1362  }
1363 
1364  assign_query_collations(pstate, qry);
1365 
1366  /* this must be done after collations, for reliable comparison of exprs */
1367  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1368  parseCheckAggregates(pstate, qry);
1369 
1370  return qry;
1371 }
Node * limitOffset
Definition: parsenodes.h:171
#define NIL
Definition: pg_list.h:65
LimitOption limitOption
Definition: parsenodes.h:1674
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:3154
bool p_hasSubLinks
Definition: parse_node.h:211
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
List * sortClause
Definition: parsenodes.h:169
List * transformDistinctOnClause(ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
IntoClause * intoClause
Definition: parsenodes.h:1648
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
List * fromClause
Definition: parsenodes.h:1650
FromExpr * jointree
Definition: parsenodes.h:148
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
Node * limitOffset
Definition: parsenodes.h:1672
bool hasAggs
Definition: parsenodes.h:133
bool groupDistinct
Definition: parsenodes.h:159
bool p_hasTargetSRFs
Definition: parse_node.h:210
List * groupingSets
Definition: parsenodes.h:161
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
bool p_hasAggs
Definition: parse_node.h:208
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1059
bool hasDistinctOn
Definition: parsenodes.h:137
List * windowClause
Definition: parsenodes.h:165
List * targetList
Definition: parsenodes.h:150
bool p_hasWindowFuncs
Definition: parse_node.h:209
bool hasRecursive
Definition: parsenodes.h:138
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:123
List * distinctClause
Definition: parsenodes.h:1646
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
List * distinctClause
Definition: parsenodes.h:167
#define ERROR
Definition: elog.h:46
Node * transformLimitClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName, LimitOption limitOption)
List * p_windowdefs
Definition: parse_node.h:195
bool p_resolve_unknowns
Definition: parse_node.h:202
Node * limitCount
Definition: parsenodes.h:172
List * sortClause
Definition: parsenodes.h:1671
List * targetList
Definition: parsenodes.h:1649
List * transformGroupClause(ParseState *pstate, List *grouplist, List **groupingSets, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99)
List * p_locking_clause
Definition: parse_node.h:199
bool recursive
Definition: parsenodes.h:1425
List * lockingClause
Definition: parsenodes.h:1675
bool p_hasModifyingCTE
Definition: parse_node.h:212
LimitOption limitOption
Definition: parsenodes.h:173
List * transformWindowDefinitions(ParseState *pstate, List *windowdefs, List **targetlist)
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
Definition: parse_target.c:291
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:113
List * windowClause
Definition: parsenodes.h:1655
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
#define makeNode(_type_)
Definition: nodes.h:587
#define lfirst(lc)
Definition: pg_list.h:169
bool hasWindowFuncs
Definition: parsenodes.h:134
void markTargetListOrigins(ParseState *pstate, List *targetlist)
Definition: parse_target.c:321
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:109
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
List * groupClause
Definition: parsenodes.h:1652
List * cteList
Definition: parsenodes.h:145
List * groupClause
Definition: parsenodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool hasSubLinks
Definition: parsenodes.h:136
void assign_query_collations(ParseState *pstate, Query *query)
Node * havingClause
Definition: parsenodes.h:1654
List * p_joinlist
Definition: parse_node.h:184
bool hasModifyingCTE
Definition: parsenodes.h:139
WithClause * withClause
Definition: parsenodes.h:1676
List * transformDistinctClause(ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
Node * havingQual
Definition: parsenodes.h:163
bool groupDistinct
Definition: parsenodes.h:1653
Node * limitCount
Definition: parsenodes.h:1673
Node * whereClause
Definition: parsenodes.h:1651
List * p_rtable
Definition: parse_node.h:182

◆ transformSetOperationStmt()

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

Definition at line 1605 of file analyze.c.

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

1606 {
1607  Query *qry = makeNode(Query);
1608  SelectStmt *leftmostSelect;
1609  int leftmostRTI;
1610  Query *leftmostQuery;
1611  SetOperationStmt *sostmt;
1612  List *sortClause;
1613  Node *limitOffset;
1614  Node *limitCount;
1615  List *lockingClause;
1616  WithClause *withClause;
1617  Node *node;
1618  ListCell *left_tlist,
1619  *lct,
1620  *lcm,
1621  *lcc,
1622  *l;
1623  List *targetvars,
1624  *targetnames,
1625  *sv_namespace;
1626  int sv_rtable_length;
1627  ParseNamespaceItem *jnsitem;
1628  ParseNamespaceColumn *sortnscolumns;
1629  int sortcolindex;
1630  int tllen;
1631 
1632  qry->commandType = CMD_SELECT;
1633 
1634  /*
1635  * Find leftmost leaf SelectStmt. We currently only need to do this in
1636  * order to deliver a suitable error message if there's an INTO clause
1637  * there, implying the set-op tree is in a context that doesn't allow
1638  * INTO. (transformSetOperationTree would throw error anyway, but it
1639  * seems worth the trouble to throw a different error for non-leftmost
1640  * INTO, so we produce that error in transformSetOperationTree.)
1641  */
1642  leftmostSelect = stmt->larg;
1643  while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
1644  leftmostSelect = leftmostSelect->larg;
1645  Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
1646  leftmostSelect->larg == NULL);
1647  if (leftmostSelect->intoClause)
1648  ereport(ERROR,
1649  (errcode(ERRCODE_SYNTAX_ERROR),
1650  errmsg("SELECT ... INTO is not allowed here"),
1651  parser_errposition(pstate,
1652  exprLocation((Node *) leftmostSelect->intoClause))));
1653 
1654  /*
1655  * We need to extract ORDER BY and other top-level clauses here and not
1656  * let transformSetOperationTree() see them --- else it'll just recurse
1657  * right back here!
1658  */
1659  sortClause = stmt->sortClause;
1660  limitOffset = stmt->limitOffset;
1661  limitCount = stmt->limitCount;
1662  lockingClause = stmt->lockingClause;
1663  withClause = stmt->withClause;
1664 
1665  stmt->sortClause = NIL;
1666  stmt->limitOffset = NULL;
1667  stmt->limitCount = NULL;
1668  stmt->lockingClause = NIL;
1669  stmt->withClause = NULL;
1670 
1671  /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1672  if (lockingClause)
1673  ereport(ERROR,
1674  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1675  /*------
1676  translator: %s is a SQL row locking clause such as FOR UPDATE */
1677  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1679  linitial(lockingClause))->strength))));
1680 
1681  /* Process the WITH clause independently of all else */
1682  if (withClause)
1683  {
1684  qry->hasRecursive = withClause->recursive;
1685  qry->cteList = transformWithClause(pstate, withClause);
1686  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1687  }
1688 
1689  /*
1690  * Recursively transform the components of the tree.
1691  */
1692  sostmt = castNode(SetOperationStmt,
1693  transformSetOperationTree(pstate, stmt, true, NULL));
1694  Assert(sostmt);
1695  qry->setOperations = (Node *) sostmt;
1696 
1697  /*
1698  * Re-find leftmost SELECT (now it's a sub-query in rangetable)
1699  */
1700  node = sostmt->larg;
1701  while (node && IsA(node, SetOperationStmt))
1702  node = ((SetOperationStmt *) node)->larg;
1703  Assert(node && IsA(node, RangeTblRef));
1704  leftmostRTI = ((RangeTblRef *) node)->rtindex;
1705  leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
1706  Assert(leftmostQuery != NULL);
1707 
1708  /*
1709  * Generate dummy targetlist for outer query using column names of
1710  * leftmost select and common datatypes/collations of topmost set
1711  * operation. Also make lists of the dummy vars and their names for use
1712  * in parsing ORDER BY.
1713  *
1714  * Note: we use leftmostRTI as the varno of the dummy variables. It
1715  * shouldn't matter too much which RT index they have, as long as they
1716  * have one that corresponds to a real RT entry; else funny things may
1717  * happen when the tree is mashed by rule rewriting.
1718  */
1719  qry->targetList = NIL;
1720  targetvars = NIL;
1721  targetnames = NIL;
1722  sortnscolumns = (ParseNamespaceColumn *)
1723  palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
1724  sortcolindex = 0;
1725 
1726  forfour(lct, sostmt->colTypes,
1727  lcm, sostmt->colTypmods,
1728  lcc, sostmt->colCollations,
1729  left_tlist, leftmostQuery->targetList)
1730  {
1731  Oid colType = lfirst_oid(lct);
1732  int32 colTypmod = lfirst_int(lcm);
1733  Oid colCollation = lfirst_oid(lcc);
1734  TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
1735  char *colName;
1736  TargetEntry *tle;
1737  Var *var;
1738 
1739  Assert(!lefttle->resjunk);
1740  colName = pstrdup(lefttle->resname);
1741  var = makeVar(leftmostRTI,
1742  lefttle->resno,
1743  colType,
1744  colTypmod,
1745  colCollation,
1746  0);
1747  var->location = exprLocation((Node *) lefttle->expr);
1748  tle = makeTargetEntry((Expr *) var,
1749  (AttrNumber) pstate->p_next_resno++,
1750  colName,
1751  false);
1752  qry->targetList = lappend(qry->targetList, tle);
1753  targetvars = lappend(targetvars, var);
1754  targetnames = lappend(targetnames, makeString(colName));
1755  sortnscolumns[sortcolindex].p_varno = leftmostRTI;
1756  sortnscolumns[sortcolindex].p_varattno = lefttle->resno;
1757  sortnscolumns[sortcolindex].p_vartype = colType;
1758  sortnscolumns[sortcolindex].p_vartypmod = colTypmod;
1759  sortnscolumns[sortcolindex].p_varcollid = colCollation;
1760  sortnscolumns[sortcolindex].p_varnosyn = leftmostRTI;
1761  sortnscolumns[sortcolindex].p_varattnosyn = lefttle->resno;
1762  sortcolindex++;
1763  }
1764 
1765  /*
1766  * As a first step towards supporting sort clauses that are expressions
1767  * using the output columns, generate a namespace entry that makes the
1768  * output columns visible. A Join RTE node is handy for this, since we
1769  * can easily control the Vars generated upon matches.
1770  *
1771  * Note: we don't yet do anything useful with such cases, but at least
1772  * "ORDER BY upper(foo)" will draw the right error message rather than
1773  * "foo not found".
1774  */
1775  sv_rtable_length = list_length(pstate->p_rtable);
1776 
1777  jnsitem = addRangeTableEntryForJoin(pstate,
1778  targetnames,
1779  sortnscolumns,
1780  JOIN_INNER,
1781  0,
1782  targetvars,
1783  NIL,
1784  NIL,
1785  NULL,
1786  NULL,
1787  false);
1788 
1789  sv_namespace = pstate->p_namespace;
1790  pstate->p_namespace = NIL;
1791 
1792  /* add jnsitem to column namespace only */
1793  addNSItemToQuery(pstate, jnsitem, false, false, true);
1794 
1795  /*
1796  * For now, we don't support resjunk sort clauses on the output of a
1797  * setOperation tree --- you can only use the SQL92-spec options of
1798  * selecting an output column by name or number. Enforce by checking that
1799  * transformSortClause doesn't add any items to tlist.
1800  */
1801  tllen = list_length(qry->targetList);
1802 
1803  qry->sortClause = transformSortClause(pstate,
1804  sortClause,
1805  &qry->targetList,
1807  false /* allow SQL92 rules */ );
1808 
1809  /* restore namespace, remove join RTE from rtable */
1810  pstate->p_namespace = sv_namespace;
1811  pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
1812 
1813  if (tllen != list_length(qry->targetList))
1814  ereport(ERROR,
1815  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1816  errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
1817  errdetail("Only result column names can be used, not expressions or functions."),
1818  errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
1819  parser_errposition(pstate,
1820  exprLocation(list_nth(qry->targetList, tllen)))));
1821 
1822  qry->limitOffset = transformLimitClause(pstate, limitOffset,
1823  EXPR_KIND_OFFSET, "OFFSET",
1824  stmt->limitOption);
1825  qry->limitCount = transformLimitClause(pstate, limitCount,
1826  EXPR_KIND_LIMIT, "LIMIT",
1827  stmt->limitOption);
1828  qry->limitOption = stmt->limitOption;
1829 
1830  qry->rtable = pstate->p_rtable;
1831  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1832 
1833  qry->hasSubLinks = pstate->p_hasSubLinks;
1834  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1835  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1836  qry->hasAggs = pstate->p_hasAggs;
1837 
1838  foreach(l, lockingClause)
1839  {
1840  transformLockingClause(pstate, qry,
1841  (LockingClause *) lfirst(l), false);
1842  }
1843 
1844  assign_query_collations(pstate, qry);
1845 
1846  /* this must be done after collations, for reliable comparison of exprs */
1847  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1848  parseCheckAggregates(pstate, qry);
1849 
1850  return qry;
1851 }
Value * makeString(char *str)
Definition: value.c:53
struct ParseNamespaceColumn ParseNamespaceColumn
Definition: parse_node.h:25
Node * limitOffset
Definition: parsenodes.h:171
#define NIL
Definition: pg_list.h:65
struct SelectStmt * larg
Definition: parsenodes.h:1683
LimitOption limitOption
Definition: parsenodes.h:1674
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:3154
bool p_hasSubLinks
Definition: parse_node.h:211
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3065
int errhint(const char *fmt,...)
Definition: elog.c:1156
List * sortClause
Definition: parsenodes.h:169
IntoClause * intoClause
Definition: parsenodes.h:1648
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
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)
FromExpr * jointree
Definition: parsenodes.h:148
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
Node * limitOffset
Definition: parsenodes.h:1672
char * pstrdup(const char *in)
Definition: mcxt.c:1299
bool hasAggs
Definition: parsenodes.h:133
List * list_truncate(List *list, int new_size)
Definition: list.c:600
bool p_hasTargetSRFs
Definition: parse_node.h:210
List * groupingSets
Definition: parsenodes.h:161
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
bool p_hasAggs
Definition: parse_node.h:208
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1456
Definition: primnodes.h:186
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1059
signed int int32
Definition: c.h:429
List * targetList
Definition: parsenodes.h:150
bool p_hasWindowFuncs
Definition: parse_node.h:209
bool hasRecursive
Definition: parsenodes.h:138
bool resjunk
Definition: primnodes.h:1461
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
Node * transformLimitClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName, LimitOption limitOption)
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
int location
Definition: primnodes.h:201
Node * limitCount
Definition: parsenodes.h:172
AttrNumber p_varattno
Definition: parse_node.h:302
List * p_namespace
Definition: parse_node.h:186
List * sortClause
Definition: parsenodes.h:1671
int errdetail(const char *fmt,...)
Definition: elog.c:1042
AttrNumber resno
Definition: primnodes.h:1455
int p_next_resno
Definition: parse_node.h:197
bool recursive
Definition: parsenodes.h:1425
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static Node * transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, bool isTopLevel, List **targetlist)
Definition: analyze.c:1895
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lockingClause
Definition: parsenodes.h:1675
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
bool p_hasModifyingCTE
Definition: parse_node.h:212
List * lappend(List *list, void *datum)
Definition: list.c:336
LimitOption limitOption
Definition: parsenodes.h:173
List * colCollations
Definition: parsenodes.h:1720
void * palloc0(Size size)
Definition: mcxt.c:1093
SetOperation op
Definition: parsenodes.h:1681
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool hasWindowFuncs
Definition: parsenodes.h:134
Expr * expr
Definition: primnodes.h:1454
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:109
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:503
List * cteList
Definition: parsenodes.h:145
Node * setOperations
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:158
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool hasSubLinks
Definition: parsenodes.h:136
void assign_query_collations(ParseState *pstate, Query *query)
AttrNumber p_varattnosyn
Definition: parse_node.h:307
List * p_joinlist
Definition: parse_node.h:184
bool hasModifyingCTE
Definition: parsenodes.h:139
WithClause * withClause
Definition: parsenodes.h:1676
Node * havingQual
Definition: parsenodes.h:163
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
Node * limitCount
Definition: parsenodes.h:1673
#define lfirst_oid(lc)
Definition: pg_list.h:171
List * p_rtable
Definition: parse_node.h:182

◆ transformSetOperationTree()

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

Definition at line 1895 of file analyze.c.

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

1897 {
1898  bool isLeaf;
1899 
1900  Assert(stmt && IsA(stmt, SelectStmt));
1901 
1902  /* Guard against stack overflow due to overly complex set-expressions */
1904 
1905  /*
1906  * Validity-check both leaf and internal SELECTs for disallowed ops.
1907  */
1908  if (stmt->intoClause)
1909  ereport(ERROR,
1910  (errcode(ERRCODE_SYNTAX_ERROR),
1911  errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
1912  parser_errposition(pstate,
1913  exprLocation((Node *) stmt->intoClause))));
1914 
1915  /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1916  if (stmt->lockingClause)
1917  ereport(ERROR,
1918  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1919  /*------
1920  translator: %s is a SQL row locking clause such as FOR UPDATE */
1921  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1923  linitial(stmt->lockingClause))->strength))));
1924 
1925  /*
1926  * If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
1927  * or WITH clauses attached, we need to treat it like a leaf node to
1928  * generate an independent sub-Query tree. Otherwise, it can be
1929  * represented by a SetOperationStmt node underneath the parent Query.
1930  */
1931  if (stmt->op == SETOP_NONE)
1932  {
1933  Assert(stmt->larg == NULL && stmt->rarg == NULL);
1934  isLeaf = true;
1935  }
1936  else
1937  {
1938  Assert(stmt->larg != NULL && stmt->rarg != NULL);
1939  if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
1940  stmt->lockingClause || stmt->withClause)
1941  isLeaf = true;
1942  else
1943  isLeaf = false;
1944  }
1945 
1946  if (isLeaf)
1947  {
1948  /* Process leaf SELECT */
1949  Query *selectQuery;
1950  char selectName[32];
1951  ParseNamespaceItem *nsitem;
1952  RangeTblRef *rtr;
1953  ListCell *tl;
1954 
1955  /*
1956  * Transform SelectStmt into a Query.
1957  *
1958  * This works the same as SELECT transformation normally would, except
1959  * that we prevent resolving unknown-type outputs as TEXT. This does
1960  * not change the subquery's semantics since if the column type
1961  * matters semantically, it would have been resolved to something else
1962  * anyway. Doing this lets us resolve such outputs using
1963  * select_common_type(), below.
1964  *
1965  * Note: previously transformed sub-queries don't affect the parsing
1966  * of this sub-query, because they are not in the toplevel pstate's
1967  * namespace list.
1968  */
1969  selectQuery = parse_sub_analyze((Node *) stmt, pstate,
1970  NULL, false, false);
1971 
1972  /*
1973  * Check for bogus references to Vars on the current query level (but
1974  * upper-level references are okay). Normally this can't happen
1975  * because the namespace will be empty, but it could happen if we are
1976  * inside a rule.
1977  */
1978  if (pstate->p_namespace)
1979  {
1980  if (contain_vars_of_level((Node *) selectQuery, 1))
1981  ereport(ERROR,
1982  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1983  errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
1984  parser_errposition(pstate,
1985  locate_var_of_level((Node *) selectQuery, 1))));
1986  }
1987 
1988  /*
1989  * Extract a list of the non-junk TLEs for upper-level processing.
1990  */
1991  if (targetlist)
1992  {
1993  *targetlist = NIL;
1994  foreach(tl, selectQuery->targetList)
1995  {
1996  TargetEntry *tle = (TargetEntry *) lfirst(tl);
1997 
1998  if (!tle->resjunk)
1999  *targetlist = lappend(*targetlist, tle);
2000  }
2001  }
2002 
2003  /*
2004  * Make the leaf query be a subquery in the top-level rangetable.
2005  */
2006  snprintf(selectName, sizeof(selectName), "*SELECT* %d",
2007  list_length(pstate->p_rtable) + 1);
2008  nsitem = addRangeTableEntryForSubquery(pstate,
2009  selectQuery,
2010  makeAlias(selectName, NIL),
2011  false,
2012  false);
2013 
2014  /*
2015  * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
2016  */
2017  rtr = makeNode(RangeTblRef);
2018  rtr->rtindex = nsitem->p_rtindex;
2019  return (Node *) rtr;
2020  }
2021  else
2022  {
2023  /* Process an internal node (set operation node) */
2025  List *ltargetlist;
2026  List *rtargetlist;
2027  ListCell *ltl;
2028  ListCell *rtl;
2029  const char *context;
2030 
2031  context = (stmt->op == SETOP_UNION ? "UNION" :
2032  (stmt->op == SETOP_INTERSECT ? "INTERSECT" :
2033  "EXCEPT"));
2034 
2035  op->op = stmt->op;
2036  op->all = stmt->all;
2037 
2038  /*
2039  * Recursively transform the left child node.
2040  */
2041  op->larg = transformSetOperationTree(pstate, stmt->larg,
2042  false,
2043  &ltargetlist);
2044 
2045  /*
2046  * If we are processing a recursive union query, now is the time to
2047  * examine the non-recursive term's output columns and mark the
2048  * containing CTE as having those result columns. We should do this
2049  * only at the topmost setop of the CTE, of course.
2050  */
2051  if (isTopLevel &&
2052  pstate->p_parent_cte &&
2053  pstate->p_parent_cte->cterecursive)
2054  determineRecursiveColTypes(pstate, op->larg, ltargetlist);
2055 
2056  /*
2057  * Recursively transform the right child node.
2058  */
2059  op->rarg = transformSetOperationTree(pstate, stmt->rarg,
2060  false,
2061  &rtargetlist);
2062 
2063  /*
2064  * Verify that the two children have the same number of non-junk
2065  * columns, and determine the types of the merged output columns.
2066  */
2067  if (list_length(ltargetlist) != list_length(rtargetlist))
2068  ereport(ERROR,
2069  (errcode(ERRCODE_SYNTAX_ERROR),
2070  errmsg("each %s query must have the same number of columns",
2071  context),
2072  parser_errposition(pstate,
2073  exprLocation((Node *) rtargetlist))));
2074 
2075  if (targetlist)
2076  *targetlist = NIL;
2077  op->colTypes = NIL;
2078  op->colTypmods = NIL;
2079  op->colCollations = NIL;
2080  op->groupClauses = NIL;
2081  forboth(ltl, ltargetlist, rtl, rtargetlist)
2082  {
2083  TargetEntry *ltle = (TargetEntry *) lfirst(ltl);
2084  TargetEntry *rtle = (TargetEntry *) lfirst(rtl);
2085  Node *lcolnode = (Node *) ltle->expr;
2086  Node *rcolnode = (Node *) rtle->expr;
2087  Oid lcoltype = exprType(lcolnode);
2088  Oid rcoltype = exprType(rcolnode);
2089  Node *bestexpr;
2090  int bestlocation;
2091  Oid rescoltype;
2092  int32 rescoltypmod;
2093  Oid rescolcoll;
2094 
2095  /* select common type, same as CASE et al */
2096  rescoltype = select_common_type(pstate,
2097  list_make2(lcolnode, rcolnode),
2098  context,
2099  &bestexpr);
2100  bestlocation = exprLocation(bestexpr);
2101 
2102  /*
2103  * Verify the coercions are actually possible. If not, we'd fail
2104  * later anyway, but we want to fail now while we have sufficient
2105  * context to produce an error cursor position.
2106  *
2107  * For all non-UNKNOWN-type cases, we verify coercibility but we
2108  * don't modify the child's expression, for fear of changing the
2109  * child query's semantics.
2110  *
2111  * If a child expression is an UNKNOWN-type Const or Param, we
2112  * want to replace it with the coerced expression. This can only
2113  * happen when the child is a leaf set-op node. It's safe to
2114  * replace the expression because if the child query's semantics
2115  * depended on the type of this output column, it'd have already
2116  * coerced the UNKNOWN to something else. We want to do this
2117  * because (a) we want to verify that a Const is valid for the
2118  * target type, or resolve the actual type of an UNKNOWN Param,
2119  * and (b) we want to avoid unnecessary discrepancies between the
2120  * output type of the child query and the resolved target type.
2121  * Such a discrepancy would disable optimization in the planner.
2122  *
2123  * If it's some other UNKNOWN-type node, eg a Var, we do nothing
2124  * (knowing that coerce_to_common_type would fail). The planner
2125  * is sometimes able to fold an UNKNOWN Var to a constant before
2126  * it has to coerce the type, so failing now would just break
2127  * cases that might work.
2128  */
2129  if (lcoltype != UNKNOWNOID)
2130  lcolnode = coerce_to_common_type(pstate, lcolnode,
2131  rescoltype, context);
2132  else if (IsA(lcolnode, Const) ||
2133  IsA(lcolnode, Param))
2134  {
2135  lcolnode = coerce_to_common_type(pstate, lcolnode,
2136  rescoltype, context);
2137  ltle->expr = (Expr *) lcolnode;
2138  }
2139 
2140  if (rcoltype != UNKNOWNOID)
2141  rcolnode = coerce_to_common_type(pstate, rcolnode,
2142  rescoltype, context);
2143  else if (IsA(rcolnode, Const) ||
2144  IsA(rcolnode, Param))
2145  {
2146  rcolnode = coerce_to_common_type(pstate, rcolnode,
2147  rescoltype, context);
2148  rtle->expr = (Expr *) rcolnode;
2149  }
2150 
2151  rescoltypmod = select_common_typmod(pstate,
2152  list_make2(lcolnode, rcolnode),
2153  rescoltype);
2154 
2155  /*
2156  * Select common collation. A common collation is required for
2157  * all set operators except UNION ALL; see SQL:2008 7.13 <query
2158  * expression> Syntax Rule 15c. (If we fail to identify a common
2159  * collation for a UNION ALL column, the colCollations element
2160  * will be set to InvalidOid, which may result in a runtime error
2161  * if something at a higher query level wants to use the column's
2162  * collation.)
2163  */
2164  rescolcoll = select_common_collation(pstate,
2165  list_make2(lcolnode, rcolnode),
2166  (op->op == SETOP_UNION && op->all));
2167 
2168  /* emit results */
2169  op->colTypes = lappend_oid(op->colTypes, rescoltype);
2170  op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
2171  op->colCollations = lappend_oid(op->colCollations, rescolcoll);
2172 
2173  /*
2174  * For all cases except UNION ALL, identify the grouping operators
2175  * (and, if available, sorting operators) that will be used to
2176  * eliminate duplicates.
2177  */
2178  if (op->op != SETOP_UNION || !op->all)
2179  {
2180  ParseCallbackState pcbstate;
2181 
2182  setup_parser_errposition_callback(&pcbstate, pstate,
2183  bestlocation);
2184 
2185  op->groupClauses = lappend(op->groupClauses,
2186  makeSortGroupClauseForSetOp(rescoltype));
2187 
2189  }
2190 
2191  /*
2192  * Construct a dummy tlist entry to return. We use a SetToDefault
2193  * node for the expression, since it carries exactly the fields
2194  * needed, but any other expression node type would do as well.
2195  */
2196  if (targetlist)
2197  {
2198  SetToDefault *rescolnode = makeNode(SetToDefault);
2199  TargetEntry *restle;
2200 
2201  rescolnode->typeId = rescoltype;
2202  rescolnode->typeMod = rescoltypmod;
2203  rescolnode->collation = rescolcoll;
2204  rescolnode->location = bestlocation;
2205  restle = makeTargetEntry((Expr *) rescolnode,
2206  0, /* no need to set resno */
2207  NULL,
2208  false);
2209  *targetlist = lappend(*targetlist, restle);
2210  }
2211  }
2212 
2213  return (Node *) op;
2214  }
2215 }
#define list_make2(x1, x2)
Definition: pg_list.h:208
#define NIL
Definition: pg_list.h:65
struct SelectStmt * larg
Definition: parsenodes.h:1683
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3065
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
IntoClause * intoClause
Definition: parsenodes.h:1648
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
Node * limitOffset
Definition: parsenodes.h:1672
SortGroupClause * makeSortGroupClauseForSetOp(Oid rescoltype)
Definition: analyze.c:1857
int32 select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
CommonTableExpr * p_parent_cte
Definition: parse_node.h:191
signed int int32
Definition: c.h:429
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
int locate_var_of_level(Node *node, int levelsup)
Definition: var.c:464
void cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
Definition: parse_node.c:161
bool resjunk
Definition: primnodes.h:1461
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
List * p_namespace
Definition: parse_node.h:186
int32 typeMod
Definition: primnodes.h:1342
List * sortClause
Definition: parsenodes.h:1671
void check_stack_depth(void)
Definition: postgres.c:3469
Oid select_common_collation(ParseState *pstate, List *exprs, bool none_ok)
static Node * transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, bool isTopLevel, List **targetlist)
Definition: analyze.c:1895
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lockingClause
Definition: parsenodes.h:1675
void setup_parser_errposition_callback(ParseCallbackState *pcbstate, ParseState *pstate, int location)
Definition: parse_node.c:145
List * lappend_int(List *list, int datum)
Definition: list.c:354
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
List * lappend(List *list, void *datum)
Definition: list.c:336
List * colCollations
Definition: parsenodes.h:1720
SetOperation op
Definition: parsenodes.h:1681
Query * parse_sub_analyze(Node *parseTree, ParseState *parentParseState, CommonTableExpr *parentCTE, bool locked_from_parent, bool resolve_unknowns)
Definition: analyze.c:186
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:396
Expr * expr
Definition: primnodes.h:1454
struct SelectStmt * rarg
Definition: parsenodes.h:1684
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
SetOperation op
Definition: parsenodes.h:1711
int errmsg(const char *fmt,...)
Definition: elog.c:909
ParseNamespaceItem * addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, bool lateral, bool inFromCl)
Oid select_common_type(ParseState *pstate, List *exprs, const char *context, Node **which_expr)
WithClause * withClause
Definition: parsenodes.h:1676
static void determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
Definition: analyze.c:2222
Definition: pg_list.h:50
#define snprintf
Definition: port.h:216
Node * limitCount
Definition: parsenodes.h:1673
List * p_rtable
Definition: parse_node.h:182

◆ transformStmt()

Query* transformStmt ( ParseState pstate,
Node parseTree 
)

Definition at line 276 of file analyze.c.

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_PLAssignStmt, T_ReturnStmt, T_SelectStmt, T_UpdateStmt, transformCallStmt(), transformCreateTableAsStmt(), transformDeclareCursorStmt(), transformDeleteStmt(), transformExplainStmt(), transformInsertStmt(), transformPLAssignStmt(), transformReturnStmt(), transformSelectStmt(), transformSetOperationStmt(), transformUpdateStmt(), transformValuesClause(), Query::utilityStmt, and SelectStmt::valuesLists.

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

277 {
278  Query *result;
279 
280  /*
281  * We apply RAW_EXPRESSION_COVERAGE_TEST testing to basic DML statements;
282  * we can't just run it on everything because raw_expression_tree_walker()
283  * doesn't claim to handle utility statements.
284  */
285 #ifdef RAW_EXPRESSION_COVERAGE_TEST
286  switch (nodeTag(parseTree))
287  {
288  case T_SelectStmt:
289  case T_InsertStmt:
290  case T_UpdateStmt:
291  case T_DeleteStmt:
292  (void) test_raw_expression_coverage(parseTree, NULL);
293  break;
294  default:
295  break;
296  }
297 #endif /* RAW_EXPRESSION_COVERAGE_TEST */
298 
299  switch (nodeTag(parseTree))
300  {
301  /*
302  * Optimizable statements
303  */
304  case T_InsertStmt:
305  result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
306  break;
307 
308  case T_DeleteStmt:
309  result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
310  break;
311 
312  case T_UpdateStmt:
313  result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
314  break;
315 
316  case T_SelectStmt:
317  {
318  SelectStmt *n = (SelectStmt *) parseTree;
319 
320  if (n->valuesLists)
321  result = transformValuesClause(pstate, n);
322  else if (n->op == SETOP_NONE)
323  result = transformSelectStmt(pstate, n);
324  else
325  result = transformSetOperationStmt(pstate, n);
326  }
327  break;
328 
329  case T_ReturnStmt:
330  result = transformReturnStmt(pstate, (ReturnStmt *) parseTree);
331  break;
332 
333  case T_PLAssignStmt:
334  result = transformPLAssignStmt(pstate,
335  (PLAssignStmt *) parseTree);
336  break;
337 
338  /*
339  * Special cases
340  */
341  case T_DeclareCursorStmt:
342  result = transformDeclareCursorStmt(pstate,
343  (DeclareCursorStmt *) parseTree);
344  break;
345 
346  case T_ExplainStmt:
347  result = transformExplainStmt(pstate,
348  (ExplainStmt *) parseTree);
349  break;
350 
351  case T_CreateTableAsStmt:
352  result = transformCreateTableAsStmt(pstate,
353  (CreateTableAsStmt *) parseTree);
354  break;
355 
356  case T_CallStmt:
357  result = transformCallStmt(pstate,
358  (CallStmt *) parseTree);
359  break;
360 
361  default:
362 
363  /*
364  * other statements don't require any transformation; just return
365  * the original parsetree with a Query node plastered on top.
366  */
367  result = makeNode(Query);
368  result->commandType = CMD_UTILITY;
369  result->utilityStmt = (Node *) parseTree;
370  break;
371  }
372 
373  /* Mark as original query until we learn differently */
374  result->querySource = QSRC_ORIGINAL;
375  result->canSetTag = true;
376 
377  return result;
378 }
static Query * transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
Definition: analyze.c:2865
static Query * transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
Definition: analyze.c:2748
static Query * transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
Definition: analyze.c:2306
static Query * transformValuesClause(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1381
Definition: nodes.h:539
Node * utilityStmt
Definition: parsenodes.h:128
static Query * transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
Definition: analyze.c:2841
static Query * transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1239
List * valuesLists
Definition: parsenodes.h:1665
static Query * transformReturnStmt(ParseState *pstate, ReturnStmt *stmt)
Definition: analyze.c:2276
static Query * transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
Definition: analyze.c:2500
static Query * transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
Definition: analyze.c:499
SetOperation op
Definition: parsenodes.h:1681
CmdType commandType
Definition: parsenodes.h:120
#define makeNode(_type_)
Definition: nodes.h:587
QuerySource querySource
Definition: parsenodes.h:122
bool canSetTag
Definition: parsenodes.h:126
static Query * transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
Definition: analyze.c:429
static Query * transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1605
#define nodeTag(nodeptr)
Definition: nodes.h:544
static Query * transformCallStmt(ParseState *pstate, CallStmt *stmt)
Definition: analyze.c:2940

◆ transformTopLevelStmt()

Query* transformTopLevelStmt ( ParseState pstate,
RawStmt parseTree 
)

Definition at line 213 of file analyze.c.

References RawStmt::stmt, Query::stmt_len, RawStmt::stmt_len, Query::stmt_location, RawStmt::stmt_location, and transformOptionalSelectInto().

Referenced by inline_function(), parse_analyze(), parse_analyze_varparams(), and pg_analyze_and_rewrite_params().

214 {
215  Query *result;
216 
217  /* We're at top level, so allow SELECT INTO */
218  result = transformOptionalSelectInto(pstate, parseTree->stmt);
219 
220  result->stmt_location = parseTree->stmt_location;
221  result->stmt_len = parseTree->stmt_len;
222 
223  return result;
224 }
int stmt_location
Definition: parsenodes.h:192
Node * stmt
Definition: parsenodes.h:1560
int stmt_len
Definition: parsenodes.h:1562
int stmt_location
Definition: parsenodes.h:1561
static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
Definition: analyze.c:237
int stmt_len
Definition: parsenodes.h:193

◆ transformUpdateStmt()

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

Definition at line 2306 of file analyze.c.

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

2307 {
2308  Query *qry = makeNode(Query);
2309  ParseNamespaceItem *nsitem;
2310  Node *qual;
2311 
2312  qry->commandType = CMD_UPDATE;
2313  pstate->p_is_insert = false;
2314 
2315  /* process the WITH clause independently of all else */
2316  if (stmt->withClause)
2317  {
2318  qry->hasRecursive = stmt->withClause->recursive;
2319  qry->cteList = transformWithClause(pstate, stmt->withClause);
2320  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
2321  }
2322 
2323  qry->resultRelation = setTargetTable(pstate, stmt->relation,
2324  stmt->relation->inh,
2325  true,
2326  ACL_UPDATE);
2327  nsitem = pstate->p_target_nsitem;
2328 
2329  /* subqueries in FROM cannot access the result relation */
2330  nsitem->p_lateral_only = true;
2331  nsitem->p_lateral_ok = false;
2332 
2333  /*
2334  * the FROM clause is non-standard SQL syntax. We used to be able to do
2335  * this with REPLACE in POSTQUEL so we keep the feature.
2336  */
2337  transformFromClause(pstate, stmt->fromClause);
2338 
2339  /* remaining clauses can reference the result relation normally */
2340  nsitem->p_lateral_only = false;
2341  nsitem->p_lateral_ok = true;
2342 
2343  qual = transformWhereClause(pstate, stmt->whereClause,
2344  EXPR_KIND_WHERE, "WHERE");
2345 
2346  qry->returningList = transformReturningList(pstate, stmt->returningList);
2347 
2348  /*
2349  * Now we are done with SELECT-like processing, and can get on with
2350  * transforming the target list to match the UPDATE target columns.
2351  */
2352  qry->targetList = transformUpdateTargetList(pstate, stmt->targetList);
2353 
2354  qry->rtable = pstate->p_rtable;
2355  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2356 
2357  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2358  qry->hasSubLinks = pstate->p_hasSubLinks;
2359 
2360  assign_query_collations(pstate, qry);
2361 
2362  return qry;
2363 }
List * fromClause
Definition: parsenodes.h:1613
bool p_hasSubLinks
Definition: parse_node.h:211
static List * transformUpdateTargetList(ParseState *pstate, List *targetList)
Definition: analyze.c:2370
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
FromExpr * jointree
Definition: parsenodes.h:148
int resultRelation
Definition: parsenodes.h:130
bool p_hasTargetSRFs
Definition: parse_node.h:210
Definition: nodes.h:539
List * targetList
Definition: parsenodes.h:1611
static List * transformReturningList(ParseState *pstate, List *returningList)
Definition: analyze.c:2442
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:193
Node * whereClause
Definition: parsenodes.h:1612
List * targetList
Definition: parsenodes.h:150
bool hasRecursive
Definition: parsenodes.h:138
List * rtable
Definition: parsenodes.h:147
bool recursive
Definition: parsenodes.h:1425
List * returningList
Definition: parsenodes.h:156
bool p_hasModifyingCTE
Definition: parse_node.h:212
bool inh
Definition: primnodes.h:69
#define ACL_UPDATE
Definition: parsenodes.h:84
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
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
#define makeNode(_type_)
Definition: nodes.h:587
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
RangeVar * relation
Definition: parsenodes.h:1610
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:109
List * returningList
Definition: parsenodes.h:1614
List * cteList
Definition: parsenodes.h:145
bool hasSubLinks
Definition: parsenodes.h:136
void assign_query_collations(ParseState *pstate, Query *query)
bool p_is_insert
Definition: parse_node.h:194
List * p_joinlist
Definition: parse_node.h:184
bool hasModifyingCTE
Definition: parsenodes.h:139
WithClause * withClause
Definition: parsenodes.h:1615
List * p_rtable
Definition: parse_node.h:182

◆ transformUpdateTargetList()

static List * transformUpdateTargetList ( ParseState pstate,
List targetList 
)
static

Definition at line 2370 of file analyze.c.

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 transformOnConflictClause(), and transformUpdateStmt().

2371 {
2372  List *tlist = NIL;
2373  RangeTblEntry *target_rte;
2374  ListCell *orig_tl;
2375  ListCell *tl;
2376 
2377  tlist = transformTargetList(pstate, origTlist,
2379 
2380  /* Prepare to assign non-conflicting resnos to resjunk attributes */
2383 
2384  /* Prepare non-junk columns for assignment to target table */
2385  target_rte = pstate->p_target_nsitem->p_rte;
2386  orig_tl = list_head(origTlist);
2387 
2388  foreach(tl, tlist)
2389  {
2390  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2391  ResTarget *origTarget;
2392  int attrno;
2393 
2394  if (tle->resjunk)
2395  {
2396  /*
2397  * Resjunk nodes need no additional processing, but be sure they
2398  * have resnos that do not match any target columns; else rewriter
2399  * or planner might get confused. They don't need a resname
2400  * either.
2401  */
2402  tle->resno = (AttrNumber) pstate->p_next_resno++;
2403  tle->resname = NULL;
2404  continue;
2405  }