PostgreSQL Source Code  git master
analyze.c File Reference
#include "postgres.h"
#include "access/sysattr.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/builtins.h"
#include "utils/rel.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 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)
 
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 366 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().

367 {
368  bool result;
369 
370  switch (nodeTag(parseTree->stmt))
371  {
372  /*
373  * Optimizable statements
374  */
375  case T_InsertStmt:
376  case T_DeleteStmt:
377  case T_UpdateStmt:
378  case T_SelectStmt:
379  case T_PLAssignStmt:
380  result = true;
381  break;
382 
383  /*
384  * Special cases
385  */
386  case T_DeclareCursorStmt:
387  case T_ExplainStmt:
388  case T_CreateTableAsStmt:
389  /* yes, because we must analyze the contained statement */
390  result = true;
391  break;
392 
393  default:
394  /* other utility statements don't have any real parse analysis */
395  result = false;
396  break;
397  }
398 
399  return result;
400 }
Node * stmt
Definition: parsenodes.h:1513
#define nodeTag(nodeptr)
Definition: nodes.h:533

◆ applyLockingClause()

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

Definition at line 3155 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().

3158 {
3159  RowMarkClause *rc;
3160 
3161  Assert(strength != LCS_NONE); /* else caller error */
3162 
3163  /* If it's an explicit clause, make sure hasForUpdate gets set */
3164  if (!pushedDown)
3165  qry->hasForUpdate = true;
3166 
3167  /* Check for pre-existing entry for same rtindex */
3168  if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
3169  {
3170  /*
3171  * If the same RTE is specified with more than one locking strength,
3172  * use the strongest. (Reasonable, since you can't take both a shared
3173  * and exclusive lock at the same time; it'll end up being exclusive
3174  * anyway.)
3175  *
3176  * Similarly, if the same RTE is specified with more than one lock
3177  * wait policy, consider that NOWAIT wins over SKIP LOCKED, which in
3178  * turn wins over waiting for the lock (the default). This is a bit
3179  * more debatable but raising an error doesn't seem helpful. (Consider
3180  * for instance SELECT FOR UPDATE NOWAIT from a view that internally
3181  * contains a plain FOR UPDATE spec.) Having NOWAIT win over SKIP
3182  * LOCKED is reasonable since the former throws an error in case of
3183  * coming across a locked tuple, which may be undesirable in some
3184  * cases but it seems better than silently returning inconsistent
3185  * results.
3186  *
3187  * And of course pushedDown becomes false if any clause is explicit.
3188  */
3189  rc->strength = Max(rc->strength, strength);
3190  rc->waitPolicy = Max(rc->waitPolicy, waitPolicy);
3191  rc->pushedDown &= pushedDown;
3192  return;
3193  }
3194 
3195  /* Make a new RowMarkClause */
3196  rc = makeNode(RowMarkClause);
3197  rc->rti = rtindex;
3198  rc->strength = strength;
3199  rc->waitPolicy = waitPolicy;
3200  rc->pushedDown = pushedDown;
3201  qry->rowMarks = lappend(qry->rowMarks, rc);
3202 }
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
List * rowMarks
Definition: parsenodes.h:164
LockClauseStrength strength
Definition: parsenodes.h:1388
List * lappend(List *list, void *datum)
Definition: list.c:336
#define Max(x, y)
Definition: c.h:968
#define makeNode(_type_)
Definition: nodes.h:576
#define Assert(condition)
Definition: c.h:792
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1389
bool hasForUpdate
Definition: parsenodes.h:132

◆ BuildOnConflictExcludedTargetlist()

List* BuildOnConflictExcludedTargetlist ( Relation  targetrel,
Index  exclRelIndex 
)

Definition at line 1088 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().

1090 {
1091  List *result = NIL;
1092  int attno;
1093  Var *var;
1094  TargetEntry *te;
1095 
1096  /*
1097  * Note that resnos of the tlist must correspond to attnos of the
1098  * underlying relation, hence we need entries for dropped columns too.
1099  */
1100  for (attno = 0; attno < RelationGetNumberOfAttributes(targetrel); attno++)
1101  {
1102  Form_pg_attribute attr = TupleDescAttr(targetrel->rd_att, attno);
1103  char *name;
1104 
1105  if (attr->attisdropped)
1106  {
1107  /*
1108  * can't use atttypid here, but it doesn't really matter what type
1109  * the Const claims to be.
1110  */
1111  var = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
1112  name = NULL;
1113  }
1114  else
1115  {
1116  var = makeVar(exclRelIndex, attno + 1,
1117  attr->atttypid, attr->atttypmod,
1118  attr->attcollation,
1119  0);
1120  name = pstrdup(NameStr(attr->attname));
1121  }
1122 
1123  te = makeTargetEntry((Expr *) var,
1124  attno + 1,
1125  name,
1126  false);
1127 
1128  result = lappend(result, te);
1129  }
1130 
1131  /*
1132  * Add a whole-row-Var entry to support references to "EXCLUDED.*". Like
1133  * the other entries in the EXCLUDED tlist, its resno must match the Var's
1134  * varattno, else the wrong things happen while resolving references in
1135  * setrefs.c. This is against normal conventions for targetlists, but
1136  * it's okay since we don't use this as a real tlist.
1137  */
1138  var = makeVar(exclRelIndex, InvalidAttrNumber,
1139  targetrel->rd_rel->reltype,
1140  -1, InvalidOid, 0);
1141  te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true);
1142  result = lappend(result, te);
1143 
1144  return result;
1145 }
#define NIL
Definition: pg_list.h:65
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:463
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1187
Form_pg_class rd_rel
Definition: rel.h:110
Definition: primnodes.h:181
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
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:111
#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:669
Definition: pg_list.h:50

◆ CheckSelectLocking()

void CheckSelectLocking ( Query qry,
LockClauseStrength  strength 
)

Definition at line 2917 of file analyze.c.

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

Referenced by preprocess_rowmarks(), and transformLockingClause().

2918 {
2919  Assert(strength != LCS_NONE); /* else caller error */
2920 
2921  if (qry->setOperations)
2922  ereport(ERROR,
2923  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2924  /*------
2925  translator: %s is a SQL row locking clause such as FOR UPDATE */
2926  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
2927  LCS_asString(strength))));
2928  if (qry->distinctClause != NIL)
2929  ereport(ERROR,
2930  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2931  /*------
2932  translator: %s is a SQL row locking clause such as FOR UPDATE */
2933  errmsg("%s is not allowed with DISTINCT clause",
2934  LCS_asString(strength))));
2935  if (qry->groupClause != NIL)
2936  ereport(ERROR,
2937  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2938  /*------
2939  translator: %s is a SQL row locking clause such as FOR UPDATE */
2940  errmsg("%s is not allowed with GROUP BY clause",
2941  LCS_asString(strength))));
2942  if (qry->havingQual != NULL)
2943  ereport(ERROR,
2944  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2945  /*------
2946  translator: %s is a SQL row locking clause such as FOR UPDATE */
2947  errmsg("%s is not allowed with HAVING clause",
2948  LCS_asString(strength))));
2949  if (qry->hasAggs)
2950  ereport(ERROR,
2951  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2952  /*------
2953  translator: %s is a SQL row locking clause such as FOR UPDATE */
2954  errmsg("%s is not allowed with aggregate functions",
2955  LCS_asString(strength))));
2956  if (qry->hasWindowFuncs)
2957  ereport(ERROR,
2958  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2959  /*------
2960  translator: %s is a SQL row locking clause such as FOR UPDATE */
2961  errmsg("%s is not allowed with window functions",
2962  LCS_asString(strength))));
2963  if (qry->hasTargetSRFs)
2964  ereport(ERROR,
2965  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2966  /*------
2967  translator: %s is a SQL row locking clause such as FOR UPDATE */
2968  errmsg("%s is not allowed with set-returning functions in the target list",
2969  LCS_asString(strength))));
2970 }
#define NIL
Definition: pg_list.h:65
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:2892
bool hasAggs
Definition: parsenodes.h:125
int errcode(int sqlerrcode)
Definition: elog.c:704
List * distinctClause
Definition: parsenodes.h:156
#define ERROR
Definition: elog.h:45
#define ereport(elevel,...)
Definition: elog.h:155
bool hasTargetSRFs
Definition: parsenodes.h:127
#define Assert(condition)
Definition: c.h:792
bool hasWindowFuncs
Definition: parsenodes.h:126
Node * setOperations
Definition: parsenodes.h:166
List * groupClause
Definition: parsenodes.h:148
int errmsg(const char *fmt,...)
Definition: elog.c:915
Node * havingQual
Definition: parsenodes.h:152

◆ count_rowexpr_columns()

static int count_rowexpr_columns ( ParseState pstate,
Node expr 
)
static

Definition at line 1158 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().

1159 {
1160  if (expr == NULL)
1161  return -1;
1162  if (IsA(expr, RowExpr))
1163  return list_length(((RowExpr *) expr)->args);
1164  if (IsA(expr, Var))
1165  {
1166  Var *var = (Var *) expr;
1167  AttrNumber attnum = var->varattno;
1168 
1169  if (attnum > 0 && var->vartype == RECORDOID)
1170  {
1171  RangeTblEntry *rte;
1172 
1173  rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
1174  if (rte->rtekind == RTE_SUBQUERY)
1175  {
1176  /* Subselect-in-FROM: examine sub-select's output expr */
1178  attnum);
1179 
1180  if (ste == NULL || ste->resjunk)
1181  return -1;
1182  expr = (Node *) ste->expr;
1183  if (IsA(expr, RowExpr))
1184  return list_length(((RowExpr *) expr)->args);
1185  }
1186  }
1187  }
1188  return -1;
1189 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Index varlevelsup
Definition: primnodes.h:191
Definition: nodes.h:528
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
List * targetList
Definition: parsenodes.h:140
bool resjunk
Definition: primnodes.h:1438
Oid vartype
Definition: primnodes.h:188
Index varno
Definition: primnodes.h:184
RangeTblEntry * GetRTEByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
int16 attnum
Definition: pg_attribute.h:79
Expr * expr
Definition: primnodes.h:1431
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
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 2170 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().

2171 {
2172  Node *node;
2173  int leftmostRTI;
2174  Query *leftmostQuery;
2175  List *targetList;
2176  ListCell *left_tlist;
2177  ListCell *nrtl;
2178  int next_resno;
2179 
2180  /*
2181  * Find leftmost leaf SELECT
2182  */
2183  node = larg;
2184  while (node && IsA(node, SetOperationStmt))
2185  node = ((SetOperationStmt *) node)->larg;
2186  Assert(node && IsA(node, RangeTblRef));
2187  leftmostRTI = ((RangeTblRef *) node)->rtindex;
2188  leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
2189  Assert(leftmostQuery != NULL);
2190 
2191  /*
2192  * Generate dummy targetlist using column names of leftmost select and
2193  * dummy result expressions of the non-recursive term.
2194  */
2195  targetList = NIL;
2196  next_resno = 1;
2197 
2198  forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
2199  {
2200  TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
2201  TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
2202  char *colName;
2203  TargetEntry *tle;
2204 
2205  Assert(!lefttle->resjunk);
2206  colName = pstrdup(lefttle->resname);
2207  tle = makeTargetEntry(nrtle->expr,
2208  next_resno++,
2209  colName,
2210  false);
2211  targetList = lappend(targetList, tle);
2212  }
2213 
2214  /* Now build CTE's output column info using dummy targetlist */
2215  analyzeCTETargetList(pstate, pstate->p_parent_cte, targetList);
2216 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
void analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
Definition: parse_cte.c:352
char * pstrdup(const char *in)
Definition: mcxt.c:1187
Definition: nodes.h:528
char * resname
Definition: primnodes.h:1433
CommonTableExpr * p_parent_cte
Definition: parse_node.h:189
List * targetList
Definition: parsenodes.h:140
bool resjunk
Definition: primnodes.h:1438
#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:792
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1431
Definition: pg_list.h:50
List * p_rtable
Definition: parse_node.h:180

◆ LCS_asString()

const char* LCS_asString ( LockClauseStrength  strength)

Definition at line 2892 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().

2893 {
2894  switch (strength)
2895  {
2896  case LCS_NONE:
2897  Assert(false);
2898  break;
2899  case LCS_FORKEYSHARE:
2900  return "FOR KEY SHARE";
2901  case LCS_FORSHARE:
2902  return "FOR SHARE";
2903  case LCS_FORNOKEYUPDATE:
2904  return "FOR NO KEY UPDATE";
2905  case LCS_FORUPDATE:
2906  return "FOR UPDATE";
2907  }
2908  return "FOR some"; /* shouldn't happen */
2909 }
#define Assert(condition)
Definition: c.h:792

◆ parse_analyze()

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

Definition at line 104 of file analyze.c.

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

Referenced by DefineView(), and pg_analyze_and_rewrite().

107 {
108  ParseState *pstate = make_parsestate(NULL);
109  Query *query;
110 
111  Assert(sourceText != NULL); /* required as of 8.4 */
112 
113  pstate->p_sourcetext = sourceText;
114 
115  if (numParams > 0)
116  parse_fixed_parameters(pstate, paramTypes, numParams);
117 
118  pstate->p_queryEnv = queryEnv;
119 
120  query = transformTopLevelStmt(pstate, parseTree);
121 
123  (*post_parse_analyze_hook) (pstate, query);
124 
125  free_parsestate(pstate);
126 
127  return query;
128 }
QueryEnvironment * p_queryEnv
Definition: parse_node.h:203
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
const char * p_sourcetext
Definition: parse_node.h:179
#define Assert(condition)
Definition: c.h:792
void parse_fixed_parameters(ParseState *pstate, Oid *paramTypes, int numParams)
Definition: parse_param.c:67
Query * transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree)
Definition: analyze.c:195
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:53

◆ parse_analyze_varparams()

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

Definition at line 138 of file analyze.c.

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

Referenced by exec_parse_message(), and PrepareQuery().

140 {
141  ParseState *pstate = make_parsestate(NULL);
142  Query *query;
143 
144  Assert(sourceText != NULL); /* required as of 8.4 */
145 
146  pstate->p_sourcetext = sourceText;
147 
148  parse_variable_parameters(pstate, paramTypes, numParams);
149 
150  query = transformTopLevelStmt(pstate, parseTree);
151 
152  /* make sure all is well with parameter types */
153  check_variable_parameters(pstate, query);
154 
156  (*post_parse_analyze_hook) (pstate, query);
157 
158  free_parsestate(pstate);
159 
160  return query;
161 }
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:179
#define Assert(condition)
Definition: c.h:792
Query * transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree)
Definition: analyze.c:195
void check_variable_parameters(ParseState *pstate, Query *query)
Definition: parse_param.c:272
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:53

◆ parse_sub_analyze()

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

Definition at line 168 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().

172 {
173  ParseState *pstate = make_parsestate(parentParseState);
174  Query *query;
175 
176  pstate->p_parent_cte = parentCTE;
177  pstate->p_locked_from_parent = locked_from_parent;
178  pstate->p_resolve_unknowns = resolve_unknowns;
179 
180  query = transformStmt(pstate, parseTree);
181 
182  free_parsestate(pstate);
183 
184  return query;
185 }
CommonTableExpr * p_parent_cte
Definition: parse_node.h:189
bool p_locked_from_parent
Definition: parse_node.h:198
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
bool p_resolve_unknowns
Definition: parse_node.h:200
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:258
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77

◆ transformCallStmt()

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

Definition at line 2853 of file analyze.c.

References FuncCall::args, assign_expr_collations(), castNode, CMD_UTILITY, Query::commandType, EXPR_KIND_CALL_ARGUMENT, CallStmt::funccall, CallStmt::funcexpr, FuncCall::funcname, lappend(), lfirst, FuncCall::location, makeNode, NIL, ParseState::p_last_srf, ParseFuncOrColumn(), transformExpr(), and Query::utilityStmt.

Referenced by transformStmt().

2854 {
2855  List *targs;
2856  ListCell *lc;
2857  Node *node;
2858  Query *result;
2859 
2860  targs = NIL;
2861  foreach(lc, stmt->funccall->args)
2862  {
2863  targs = lappend(targs, transformExpr(pstate,
2864  (Node *) lfirst(lc),
2866  }
2867 
2868  node = ParseFuncOrColumn(pstate,
2869  stmt->funccall->funcname,
2870  targs,
2871  pstate->p_last_srf,
2872  stmt->funccall,
2873  true,
2874  stmt->funccall->location);
2875 
2876  assign_expr_collations(pstate, node);
2877 
2878  stmt->funcexpr = castNode(FuncExpr, node);
2879 
2880  result = makeNode(Query);
2881  result->commandType = CMD_UTILITY;
2882  result->utilityStmt = (Node *) stmt;
2883 
2884  return result;
2885 }
#define NIL
Definition: pg_list.h:65
FuncExpr * funcexpr
Definition: parsenodes.h:2918
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
FuncCall * funccall
Definition: parsenodes.h:2917
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
Definition: nodes.h:528
int location
Definition: parsenodes.h:360
Node * utilityStmt
Definition: parsenodes.h:120
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, Node *last_srf, FuncCall *fn, bool proc_call, int location)
Definition: parse_func.c:88
List * lappend(List *list, void *datum)
Definition: list.c:336
Node * p_last_srf
Definition: parse_node.h:212
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:576
#define lfirst(lc)
Definition: pg_list.h:169
List * args
Definition: parsenodes.h:351
List * funcname
Definition: parsenodes.h:350
Definition: pg_list.h:50

◆ transformCreateTableAsStmt()

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

Definition at line 2776 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().

2777 {
2778  Query *result;
2779  Query *query;
2780 
2781  /* transform contained query, not allowing SELECT INTO */
2782  query = transformStmt(pstate, stmt->query);
2783  stmt->query = (Node *) query;
2784 
2785  /* additional work needed for CREATE MATERIALIZED VIEW */
2786  if (stmt->objtype == OBJECT_MATVIEW)
2787  {
2788  /*
2789  * Prohibit a data-modifying CTE in the query used to create a
2790  * materialized view. It's not sufficiently clear what the user would
2791  * want to happen if the MV is refreshed or incrementally maintained.
2792  */
2793  if (query->hasModifyingCTE)
2794  ereport(ERROR,
2795  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2796  errmsg("materialized views must not use data-modifying statements in WITH")));
2797 
2798  /*
2799  * Check whether any temporary database objects are used in the
2800  * creation query. It would be hard to refresh data or incrementally
2801  * maintain it if a source disappeared.
2802  */
2803  if (isQueryUsingTempRelation(query))
2804  ereport(ERROR,
2805  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2806  errmsg("materialized views must not use temporary tables or views")));
2807 
2808  /*
2809  * A materialized view would either need to save parameters for use in
2810  * maintaining/loading the data or prohibit them entirely. The latter
2811  * seems safer and more sane.
2812  */
2813  if (query_contains_extern_params(query))
2814  ereport(ERROR,
2815  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2816  errmsg("materialized views may not be defined using bound parameters")));
2817 
2818  /*
2819  * For now, we disallow unlogged materialized views, because it seems
2820  * like a bad idea for them to just go to empty after a crash. (If we
2821  * could mark them as unpopulated, that would be better, but that
2822  * requires catalog changes which crash recovery can't presently
2823  * handle.)
2824  */
2825  if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
2826  ereport(ERROR,
2827  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2828  errmsg("materialized views cannot be unlogged")));
2829 
2830  /*
2831  * At runtime, we'll need a copy of the parsed-but-not-rewritten Query
2832  * for purposes of creating the view's ON SELECT rule. We stash that
2833  * in the IntoClause because that's where intorel_startup() can
2834  * conveniently get it from.
2835  */
2836  stmt->into->viewQuery = (Node *) copyObject(query);
2837  }
2838 
2839  /* represent the command as a utility Query */
2840  result = makeNode(Query);
2841  result->commandType = CMD_UTILITY;
2842  result->utilityStmt = (Node *) stmt;
2843 
2844  return result;
2845 }
bool isQueryUsingTempRelation(Query *query)
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
Node * utilityStmt
Definition: parsenodes.h:120
ObjectType objtype
Definition: parsenodes.h:3289
#define ERROR
Definition: elog.h:45
Node * viewQuery
Definition: primnodes.h:118
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:258
#define ereport(elevel,...)
Definition: elog.h:155
IntoClause * into
Definition: parsenodes.h:3288
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:576
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:915
RangeVar * rel
Definition: primnodes.h:112
bool hasModifyingCTE
Definition: parsenodes.h:131
#define copyObject(obj)
Definition: nodes.h:644

◆ transformDeclareCursorStmt()

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

Definition at line 2666 of file analyze.c.

References CMD_SELECT, CMD_UTILITY, Query::commandType, 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().

2667 {
2668  Query *result;
2669  Query *query;
2670 
2671  /*
2672  * Don't allow both SCROLL and NO SCROLL to be specified
2673  */
2674  if ((stmt->options & CURSOR_OPT_SCROLL) &&
2675  (stmt->options & CURSOR_OPT_NO_SCROLL))
2676  ereport(ERROR,
2677  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
2678  errmsg("cannot specify both SCROLL and NO SCROLL")));
2679 
2680  /* Transform contained query, not allowing SELECT INTO */
2681  query = transformStmt(pstate, stmt->query);
2682  stmt->query = (Node *) query;
2683 
2684  /* Grammar should not have allowed anything but SELECT */
2685  if (!IsA(query, Query) ||
2686  query->commandType != CMD_SELECT)
2687  elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
2688 
2689  /*
2690  * We also disallow data-modifying WITH in a cursor. (This could be
2691  * allowed, but the semantics of when the updates occur might be
2692  * surprising.)
2693  */
2694  if (query->hasModifyingCTE)
2695  ereport(ERROR,
2696  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2697  errmsg("DECLARE CURSOR must not contain data-modifying statements in WITH")));
2698 
2699  /* FOR UPDATE and WITH HOLD are not compatible */
2700  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
2701  ereport(ERROR,
2702  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2703  /*------
2704  translator: %s is a SQL row locking clause such as FOR UPDATE */
2705  errmsg("DECLARE CURSOR WITH HOLD ... %s is not supported",
2707  linitial(query->rowMarks))->strength)),
2708  errdetail("Holdable cursors must be READ ONLY.")));
2709 
2710  /* FOR UPDATE and SCROLL are not compatible */
2711  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL))
2712  ereport(ERROR,
2713  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2714  /*------
2715  translator: %s is a SQL row locking clause such as FOR UPDATE */
2716  errmsg("DECLARE SCROLL CURSOR ... %s is not supported",
2718  linitial(query->rowMarks))->strength)),
2719  errdetail("Scrollable cursors must be READ ONLY.")));
2720 
2721  /* FOR UPDATE and INSENSITIVE are not compatible */
2722  if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE))
2723  ereport(ERROR,
2724  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2725  /*------
2726  translator: %s is a SQL row locking clause such as FOR UPDATE */
2727  errmsg("DECLARE INSENSITIVE CURSOR ... %s is not supported",
2729  linitial(query->rowMarks))->strength)),
2730  errdetail("Insensitive cursors must be READ ONLY.")));
2731 
2732  /* represent the command as a utility Query */
2733  result = makeNode(Query);
2734  result->commandType = CMD_UTILITY;
2735  result->utilityStmt = (Node *) stmt;
2736 
2737  return result;
2738 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:2892
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2727
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
#define CURSOR_OPT_INSENSITIVE
Definition: parsenodes.h:2726
List * rowMarks
Definition: parsenodes.h:164
Node * utilityStmt
Definition: parsenodes.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2725
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
int errdetail(const char *fmt,...)
Definition: elog.c:1048
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:258
#define ereport(elevel,...)
Definition: elog.h:155
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:576
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2724
bool hasModifyingCTE
Definition: parsenodes.h:131

◆ transformDeleteStmt()

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

Definition at line 407 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().

408 {
409  Query *qry = makeNode(Query);
410  ParseNamespaceItem *nsitem;
411  Node *qual;
412 
413  qry->commandType = CMD_DELETE;
414 
415  /* process the WITH clause independently of all else */
416  if (stmt->withClause)
417  {
418  qry->hasRecursive = stmt->withClause->recursive;
419  qry->cteList = transformWithClause(pstate, stmt->withClause);
420  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
421  }
422 
423  /* set up range table with just the result rel */
424  qry->resultRelation = setTargetTable(pstate, stmt->relation,
425  stmt->relation->inh,
426  true,
427  ACL_DELETE);
428  nsitem = pstate->p_target_nsitem;
429 
430  /* there's no DISTINCT in DELETE */
431  qry->distinctClause = NIL;
432 
433  /* subqueries in USING cannot access the result relation */
434  nsitem->p_lateral_only = true;
435  nsitem->p_lateral_ok = false;
436 
437  /*
438  * The USING clause is non-standard SQL syntax, and is equivalent in
439  * functionality to the FROM list that can be specified for UPDATE. The
440  * USING keyword is used rather than FROM because FROM is already a
441  * keyword in the DELETE syntax.
442  */
443  transformFromClause(pstate, stmt->usingClause);
444 
445  /* remaining clauses can reference the result relation normally */
446  nsitem->p_lateral_only = false;
447  nsitem->p_lateral_ok = true;
448 
449  qual = transformWhereClause(pstate, stmt->whereClause,
450  EXPR_KIND_WHERE, "WHERE");
451 
452  qry->returningList = transformReturningList(pstate, stmt->returningList);
453 
454  /* done building the range table and jointree */
455  qry->rtable = pstate->p_rtable;
456  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
457 
458  qry->hasSubLinks = pstate->p_hasSubLinks;
459  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
460  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
461  qry->hasAggs = pstate->p_hasAggs;
462 
463  assign_query_collations(pstate, qry);
464 
465  /* this must be done after collations, for reliable comparison of exprs */
466  if (pstate->p_hasAggs)
467  parseCheckAggregates(pstate, qry);
468 
469  return qry;
470 }
#define NIL
Definition: pg_list.h:65
bool p_hasSubLinks
Definition: parse_node.h:209
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
RangeVar * relation
Definition: parsenodes.h:1549
FromExpr * jointree
Definition: parsenodes.h:138
bool hasAggs
Definition: parsenodes.h:125
int resultRelation
Definition: parsenodes.h:122
bool p_hasTargetSRFs
Definition: parse_node.h:208
Definition: nodes.h:528
#define ACL_DELETE
Definition: parsenodes.h:77
bool p_hasAggs
Definition: parse_node.h:206
static List * transformReturningList(ParseState *pstate, List *returningList)
Definition: analyze.c:2360
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:191
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1042
bool p_hasWindowFuncs
Definition: parse_node.h:207
bool hasRecursive
Definition: parsenodes.h:130
WithClause * withClause
Definition: parsenodes.h:1553
List * returningList
Definition: parsenodes.h:1552
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
bool recursive
Definition: parsenodes.h:1404
List * returningList
Definition: parsenodes.h:146
bool p_hasModifyingCTE
Definition: parse_node.h:210
bool inh
Definition: primnodes.h:69
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:114
Node * whereClause
Definition: parsenodes.h:1551
List * usingClause
Definition: parsenodes.h:1550
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:178
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define makeNode(_type_)
Definition: nodes.h:576
bool hasWindowFuncs
Definition: parsenodes.h:126
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:105
List * cteList
Definition: parsenodes.h:135
bool hasSubLinks
Definition: parsenodes.h:128
void assign_query_collations(ParseState *pstate, Query *query)
List * p_joinlist
Definition: parse_node.h:182
bool hasModifyingCTE
Definition: parsenodes.h:131
List * p_rtable
Definition: parse_node.h:180

◆ transformExplainStmt()

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

Definition at line 2752 of file analyze.c.

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

Referenced by transformStmt().

2753 {
2754  Query *result;
2755 
2756  /* transform contained query, allowing SELECT INTO */
2757  stmt->query = (Node *) transformOptionalSelectInto(pstate, stmt->query);
2758 
2759  /* represent the command as a utility Query */
2760  result = makeNode(Query);
2761  result->commandType = CMD_UTILITY;
2762  result->utilityStmt = (Node *) stmt;
2763 
2764  return result;
2765 }
Definition: nodes.h:528
Node * utilityStmt
Definition: parsenodes.h:120
Node * query
Definition: parsenodes.h:3267
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:576
static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
Definition: analyze.c:219

◆ transformInsertRow()

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

Definition at line 895 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().

898 {
899  List *result;
900  ListCell *lc;
901  ListCell *icols;
902  ListCell *attnos;
903 
904  /*
905  * Check length of expr list. It must not have more expressions than
906  * there are target columns. We allow fewer, but only if no explicit
907  * columns list was given (the remaining columns are implicitly
908  * defaulted). Note we must check this *after* transformation because
909  * that could expand '*' into multiple items.
910  */
911  if (list_length(exprlist) > list_length(icolumns))
912  ereport(ERROR,
913  (errcode(ERRCODE_SYNTAX_ERROR),
914  errmsg("INSERT has more expressions than target columns"),
915  parser_errposition(pstate,
916  exprLocation(list_nth(exprlist,
917  list_length(icolumns))))));
918  if (stmtcols != NIL &&
919  list_length(exprlist) < list_length(icolumns))
920  {
921  /*
922  * We can get here for cases like INSERT ... SELECT (a,b,c) FROM ...
923  * where the user accidentally created a RowExpr instead of separate
924  * columns. Add a suitable hint if that seems to be the problem,
925  * because the main error message is quite misleading for this case.
926  * (If there's no stmtcols, you'll get something about data type
927  * mismatch, which is less misleading so we don't worry about giving a
928  * hint in that case.)
929  */
930  ereport(ERROR,
931  (errcode(ERRCODE_SYNTAX_ERROR),
932  errmsg("INSERT has more target columns than expressions"),
933  ((list_length(exprlist) == 1 &&
934  count_rowexpr_columns(pstate, linitial(exprlist)) ==
935  list_length(icolumns)) ?
936  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),
937  parser_errposition(pstate,
938  exprLocation(list_nth(icolumns,
939  list_length(exprlist))))));
940  }
941 
942  /*
943  * Prepare columns for assignment to target table.
944  */
945  result = NIL;
946  forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
947  {
948  Expr *expr = (Expr *) lfirst(lc);
949  ResTarget *col = lfirst_node(ResTarget, icols);
950  int attno = lfirst_int(attnos);
951 
952  expr = transformAssignedExpr(pstate, expr,
954  col->name,
955  attno,
956  col->indirection,
957  col->location);
958 
959  if (strip_indirection)
960  {
961  while (expr)
962  {
963  if (IsA(expr, FieldStore))
964  {
965  FieldStore *fstore = (FieldStore *) expr;
966 
967  expr = (Expr *) linitial(fstore->newvals);
968  }
969  else if (IsA(expr, SubscriptingRef))
970  {
971  SubscriptingRef *sbsref = (SubscriptingRef *) expr;
972 
973  if (sbsref->refassgnexpr == NULL)
974  break;
975 
976  expr = sbsref->refassgnexpr;
977  }
978  else
979  break;
980  }
981  }
982 
983  result = lappend(result, expr);
984  }
985 
986  return result;
987 }
List * indirection
Definition: parsenodes.h:442
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
int errhint(const char *fmt,...)
Definition: elog.c:1162
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1231
Expr * transformAssignedExpr(ParseState *pstate, Expr *expr, ParseExprKind exprKind, const char *colname, int attrno, List *indirection, int location)
Definition: parse_target.c:440
char * name
Definition: parsenodes.h:441
#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:1158
int errcode(int sqlerrcode)
Definition: elog.c:704
int location
Definition: parsenodes.h:444
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
#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:816
List * lappend(List *list, void *datum)
Definition: list.c:336
#define ereport(elevel,...)
Definition: elog.h:155
#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:446
int errmsg(const char *fmt,...)
Definition: elog.c:915
Definition: pg_list.h:50

◆ transformInsertStmt()

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

Definition at line 477 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().

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

◆ transformLockingClause()

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

Definition at line 2981 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().

2983 {
2984  List *lockedRels = lc->lockedRels;
2985  ListCell *l;
2986  ListCell *rt;
2987  Index i;
2988  LockingClause *allrels;
2989 
2990  CheckSelectLocking(qry, lc->strength);
2991 
2992  /* make a clause we can pass down to subqueries to select all rels */
2993  allrels = makeNode(LockingClause);
2994  allrels->lockedRels = NIL; /* indicates all rels */
2995  allrels->strength = lc->strength;
2996  allrels->waitPolicy = lc->waitPolicy;
2997 
2998  if (lockedRels == NIL)
2999  {
3000  /* all regular tables used in query */
3001  i = 0;
3002  foreach(rt, qry->rtable)
3003  {
3004  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3005 
3006  ++i;
3007  switch (rte->rtekind)
3008  {
3009  case RTE_RELATION:
3010  applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3011  pushedDown);
3013  break;
3014  case RTE_SUBQUERY:
3015  applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
3016  pushedDown);
3017 
3018  /*
3019  * FOR UPDATE/SHARE of subquery is propagated to all of
3020  * subquery's rels, too. We could do this later (based on
3021  * the marking of the subquery RTE) but it is convenient
3022  * to have local knowledge in each query level about which
3023  * rels need to be opened with RowShareLock.
3024  */
3025  transformLockingClause(pstate, rte->subquery,
3026  allrels, true);
3027  break;
3028  default:
3029  /* ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE RTEs */
3030  break;
3031  }
3032  }
3033  }
3034  else
3035  {
3036  /* just the named tables */
3037  foreach(l, lockedRels)
3038  {
3039  RangeVar *thisrel = (RangeVar *) lfirst(l);
3040 
3041  /* For simplicity we insist on unqualified alias names here */
3042  if (thisrel->catalogname || thisrel->schemaname)
3043  ereport(ERROR,
3044  (errcode(ERRCODE_SYNTAX_ERROR),
3045  /*------
3046  translator: %s is a SQL row locking clause such as FOR UPDATE */
3047  errmsg("%s must specify unqualified relation names",
3048  LCS_asString(lc->strength)),
3049  parser_errposition(pstate, thisrel->location)));
3050 
3051  i = 0;
3052  foreach(rt, qry->rtable)
3053  {
3054  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
3055 
3056  ++i;
3057  if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
3058  {
3059  switch (rte->rtekind)
3060  {
3061  case RTE_RELATION:
3062  applyLockingClause(qry, i, lc->strength,
3063  lc->waitPolicy, pushedDown);
3065  break;
3066  case RTE_SUBQUERY:
3067  applyLockingClause(qry, i, lc->strength,
3068  lc->waitPolicy, pushedDown);
3069  /* see comment above */
3070  transformLockingClause(pstate, rte->subquery,
3071  allrels, true);
3072  break;
3073  case RTE_JOIN:
3074  ereport(ERROR,
3075  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3076  /*------
3077  translator: %s is a SQL row locking clause such as FOR UPDATE */
3078  errmsg("%s cannot be applied to a join",
3079  LCS_asString(lc->strength)),
3080  parser_errposition(pstate, thisrel->location)));
3081  break;
3082  case RTE_FUNCTION:
3083  ereport(ERROR,
3084  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3085  /*------
3086  translator: %s is a SQL row locking clause such as FOR UPDATE */
3087  errmsg("%s cannot be applied to a function",
3088  LCS_asString(lc->strength)),
3089  parser_errposition(pstate, thisrel->location)));
3090  break;
3091  case RTE_TABLEFUNC:
3092  ereport(ERROR,
3093  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3094  /*------
3095  translator: %s is a SQL row locking clause such as FOR UPDATE */
3096  errmsg("%s cannot be applied to a table function",
3097  LCS_asString(lc->strength)),
3098  parser_errposition(pstate, thisrel->location)));
3099  break;
3100  case RTE_VALUES:
3101  ereport(ERROR,
3102  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3103  /*------
3104  translator: %s is a SQL row locking clause such as FOR UPDATE */
3105  errmsg("%s cannot be applied to VALUES",
3106  LCS_asString(lc->strength)),
3107  parser_errposition(pstate, thisrel->location)));
3108  break;
3109  case RTE_CTE:
3110  ereport(ERROR,
3111  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3112  /*------
3113  translator: %s is a SQL row locking clause such as FOR UPDATE */
3114  errmsg("%s cannot be applied to a WITH query",
3115  LCS_asString(lc->strength)),
3116  parser_errposition(pstate, thisrel->location)));
3117  break;
3118  case RTE_NAMEDTUPLESTORE:
3119  ereport(ERROR,
3120  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3121  /*------
3122  translator: %s is a SQL row locking clause such as FOR UPDATE */
3123  errmsg("%s cannot be applied to a named tuplestore",
3124  LCS_asString(lc->strength)),
3125  parser_errposition(pstate, thisrel->location)));
3126  break;
3127 
3128  /* Shouldn't be possible to see RTE_RESULT here */
3129 
3130  default:
3131  elog(ERROR, "unrecognized RTE type: %d",
3132  (int) rte->rtekind);
3133  break;
3134  }
3135  break; /* out of foreach loop */
3136  }
3137  }
3138  if (rt == NULL)
3139  ereport(ERROR,
3141  /*------
3142  translator: %s is a SQL row locking clause such as FOR UPDATE */
3143  errmsg("relation \"%s\" in %s clause not found in FROM clause",
3144  thisrel->relname,
3145  LCS_asString(lc->strength)),
3146  parser_errposition(pstate, thisrel->location)));
3147  }
3148  }
3149 }
List * lockedRels
Definition: parsenodes.h:751
#define NIL
Definition: pg_list.h:65
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:2981
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:2892
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:74
int errcode(int sqlerrcode)
Definition: elog.c:704
AclMode requiredPerms
Definition: parsenodes.h:1124
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:2917
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
LockClauseStrength strength
Definition: parsenodes.h:752
unsigned int Index
Definition: c.h:537
#define ereport(elevel,...)
Definition: elog.h:155
#define makeNode(_type_)
Definition: nodes.h:576
#define lfirst(lc)
Definition: pg_list.h:169
char * aliasname
Definition: primnodes.h:42
#define ACL_SELECT_FOR_UPDATE
Definition: parsenodes.h:90
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
int i
Alias * eref
Definition: parsenodes.h:1120
Definition: pg_list.h:50
LockWaitPolicy waitPolicy
Definition: parsenodes.h:753
char * catalogname
Definition: primnodes.h:66
void applyLockingClause(Query *qry, Index rtindex, LockClauseStrength strength, LockWaitPolicy waitPolicy, bool pushedDown)
Definition: analyze.c:3155

◆ transformOnConflictClause()

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

Definition at line 994 of file analyze.c.

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

Referenced by transformInsertStmt().

996 {
997  List *arbiterElems;
998  Node *arbiterWhere;
999  Oid arbiterConstraint;
1000  List *onConflictSet = NIL;
1001  Node *onConflictWhere = NULL;
1002  int exclRelIndex = 0;
1003  List *exclRelTlist = NIL;
1004  OnConflictExpr *result;
1005 
1006  /* Process the arbiter clause, ON CONFLICT ON (...) */
1007  transformOnConflictArbiter(pstate, onConflictClause, &arbiterElems,
1008  &arbiterWhere, &arbiterConstraint);
1009 
1010  /* Process DO UPDATE */
1011  if (onConflictClause->action == ONCONFLICT_UPDATE)
1012  {
1013  Relation targetrel = pstate->p_target_relation;
1014  ParseNamespaceItem *exclNSItem;
1015  RangeTblEntry *exclRte;
1016 
1017  /*
1018  * All INSERT expressions have been parsed, get ready for potentially
1019  * existing SET statements that need to be processed like an UPDATE.
1020  */
1021  pstate->p_is_insert = false;
1022 
1023  /*
1024  * Add range table entry for the EXCLUDED pseudo relation. relkind is
1025  * set to composite to signal that we're not dealing with an actual
1026  * relation, and no permission checks are required on it. (We'll
1027  * check the actual target relation, instead.)
1028  */
1029  exclNSItem = addRangeTableEntryForRelation(pstate,
1030  targetrel,
1032  makeAlias("excluded", NIL),
1033  false, false);
1034  exclRte = exclNSItem->p_rte;
1035  exclRelIndex = exclNSItem->p_rtindex;
1036 
1037  exclRte->relkind = RELKIND_COMPOSITE_TYPE;
1038  exclRte->requiredPerms = 0;
1039  /* other permissions fields in exclRte are already empty */
1040 
1041  /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
1042  exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
1043  exclRelIndex);
1044 
1045  /*
1046  * Add EXCLUDED and the target RTE to the namespace, so that they can
1047  * be used in the UPDATE subexpressions.
1048  */
1049  addNSItemToQuery(pstate, exclNSItem, false, true, true);
1050  addNSItemToQuery(pstate, pstate->p_target_nsitem,
1051  false, true, true);
1052 
1053  /*
1054  * Now transform the UPDATE subexpressions.
1055  */
1056  onConflictSet =
1057  transformUpdateTargetList(pstate, onConflictClause->targetList);
1058 
1059  onConflictWhere = transformWhereClause(pstate,
1060  onConflictClause->whereClause,
1061  EXPR_KIND_WHERE, "WHERE");
1062  }
1063 
1064  /* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */
1065  result = makeNode(OnConflictExpr);
1066 
1067  result->action = onConflictClause->action;
1068  result->arbiterElems = arbiterElems;
1069  result->arbiterWhere = arbiterWhere;
1070  result->constraint = arbiterConstraint;
1071  result->onConflictSet = onConflictSet;
1072  result->onConflictWhere = onConflictWhere;
1073  result->exclRelIndex = exclRelIndex;
1074  result->exclRelTlist = exclRelTlist;
1075 
1076  return result;
1077 }
#define NIL
Definition: pg_list.h:65
static List * transformUpdateTargetList(ParseState *pstate, List *targetList)
Definition: analyze.c:2288
List * BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex)
Definition: analyze.c:1088
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Definition: nodes.h:528
void transformOnConflictArbiter(ParseState *pstate, OnConflictClause *onConflictClause, List **arbiterExpr, Node **arbiterWhere, Oid *constraint)
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:191
AclMode requiredPerms
Definition: parsenodes.h:1124
unsigned int Oid
Definition: postgres_ext.h:31
List * arbiterElems
Definition: primnodes.h:1553
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:257
List * exclRelTlist
Definition: primnodes.h:1562
#define RowExclusiveLock
Definition: lockdefs.h:38
OnConflictAction action
Definition: primnodes.h:1550
#define makeNode(_type_)
Definition: nodes.h:576
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
Node * arbiterWhere
Definition: primnodes.h:1555
Relation p_target_relation
Definition: parse_node.h:190
bool p_is_insert
Definition: parse_node.h:192
List * onConflictSet
Definition: primnodes.h:1559
Node * onConflictWhere
Definition: primnodes.h:1560
OnConflictAction action
Definition: parsenodes.h:1432
Definition: pg_list.h:50

◆ transformOptionalSelectInto()

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

Definition at line 219 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().

220 {
221  if (IsA(parseTree, SelectStmt))
222  {
223  SelectStmt *stmt = (SelectStmt *) parseTree;
224 
225  /* If it's a set-operation tree, drill down to leftmost SelectStmt */
226  while (stmt && stmt->op != SETOP_NONE)
227  stmt = stmt->larg;
228  Assert(stmt && IsA(stmt, SelectStmt) && stmt->larg == NULL);
229 
230  if (stmt->intoClause)
231  {
233 
234  ctas->query = parseTree;
235  ctas->into = stmt->intoClause;
236  ctas->objtype = OBJECT_TABLE;
237  ctas->is_select_into = true;
238 
239  /*
240  * Remove the intoClause from the SelectStmt. This makes it safe
241  * for transformSelectStmt to complain if it finds intoClause set
242  * (implying that the INTO appeared in a disallowed place).
243  */
244  stmt->intoClause = NULL;
245 
246  parseTree = (Node *) ctas;
247  }
248  }
249 
250  return transformStmt(pstate, parseTree);
251 }
struct SelectStmt * larg
Definition: parsenodes.h:1635
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
IntoClause * intoClause
Definition: parsenodes.h:1601
Definition: nodes.h:528
ObjectType objtype
Definition: parsenodes.h:3289
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:258
SetOperation op
Definition: parsenodes.h:1633
IntoClause * into
Definition: parsenodes.h:3288
#define makeNode(_type_)
Definition: nodes.h:576
#define Assert(condition)
Definition: c.h:792

◆ transformPLAssignStmt()

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

Definition at line 2418 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().

2419 {
2420  Query *qry = makeNode(Query);
2421  ColumnRef *cref = makeNode(ColumnRef);
2422  List *indirection = stmt->indirection;
2423  int nnames = stmt->nnames;
2424  SelectStmt *sstmt = stmt->val;
2425  Node *target;
2426  Oid targettype;
2427  int32 targettypmod;
2428  Oid targetcollation;
2429  List *tlist;
2430  TargetEntry *tle;
2431  Oid type_id;
2432  Node *qual;
2433  ListCell *l;
2434 
2435  /*
2436  * First, construct a ColumnRef for the target variable. If the target
2437  * has more than one dotted name, we have to pull the extra names out of
2438  * the indirection list.
2439  */
2440  cref->fields = list_make1(makeString(stmt->name));
2441  cref->location = stmt->location;
2442  if (nnames > 1)
2443  {
2444  /* avoid munging the raw parsetree */
2445  indirection = list_copy(indirection);
2446  while (--nnames > 0 && indirection != NIL)
2447  {
2448  Node *ind = (Node *) linitial(indirection);
2449 
2450  if (!IsA(ind, String))
2451  elog(ERROR, "invalid name count in PLAssignStmt");
2452  cref->fields = lappend(cref->fields, ind);
2453  indirection = list_delete_first(indirection);
2454  }
2455  }
2456 
2457  /*
2458  * Transform the target reference. Typically we will get back a Param
2459  * node, but there's no reason to be too picky about its type.
2460  */
2461  target = transformExpr(pstate, (Node *) cref,
2463  targettype = exprType(target);
2464  targettypmod = exprTypmod(target);
2465  targetcollation = exprCollation(target);
2466 
2467  /*
2468  * The rest mostly matches transformSelectStmt, except that we needn't
2469  * consider WITH or INTO, and we build a targetlist our own way.
2470  */
2471  qry->commandType = CMD_SELECT;
2472  pstate->p_is_insert = false;
2473 
2474  /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
2475  pstate->p_locking_clause = sstmt->lockingClause;
2476 
2477  /* make WINDOW info available for window functions, too */
2478  pstate->p_windowdefs = sstmt->windowClause;
2479 
2480  /* process the FROM clause */
2481  transformFromClause(pstate, sstmt->fromClause);
2482 
2483  /* initially transform the targetlist as if in SELECT */
2484  tlist = transformTargetList(pstate, sstmt->targetList,
2486 
2487  /* we should have exactly one targetlist item */
2488  if (list_length(tlist) != 1)
2489  ereport(ERROR,
2490  (errcode(ERRCODE_SYNTAX_ERROR),
2491  errmsg_plural("assignment source returned %d column",
2492  "assignment source returned %d columns",
2493  list_length(tlist),
2494  list_length(tlist))));
2495 
2496  tle = linitial_node(TargetEntry, tlist);
2497 
2498  /*
2499  * This next bit is similar to transformAssignedExpr; the key difference
2500  * is we use COERCION_PLPGSQL not COERCION_ASSIGNMENT.
2501  */
2502  type_id = exprType((Node *) tle->expr);
2503 
2505 
2506  if (indirection)
2507  {
2508  tle->expr = (Expr *)
2510  target,
2511  stmt->name,
2512  false,
2513  targettype,
2514  targettypmod,
2515  targetcollation,
2516  indirection,
2517  list_head(indirection),
2518  (Node *) tle->expr,
2520  exprLocation(target));
2521  }
2522  else if (targettype != type_id &&
2523  (targettype == RECORDOID || ISCOMPLEX(targettype)) &&
2524  (type_id == RECORDOID || ISCOMPLEX(type_id)))
2525  {
2526  /*
2527  * Hack: do not let coerce_to_target_type() deal with inconsistent
2528  * composite types. Just pass the expression result through as-is,
2529  * and let the PL/pgSQL executor do the conversion its way. This is
2530  * rather bogus, but it's needed for backwards compatibility.
2531  */
2532  }
2533  else
2534  {
2535  /*
2536  * For normal non-qualified target column, do type checking and
2537  * coercion.
2538  */
2539  Node *orig_expr = (Node *) tle->expr;
2540 
2541  tle->expr = (Expr *)
2542  coerce_to_target_type(pstate,
2543  orig_expr, type_id,
2544  targettype, targettypmod,
2547  -1);
2548  /* With COERCION_PLPGSQL, this error is probably unreachable */
2549  if (tle->expr == NULL)
2550  ereport(ERROR,
2551  (errcode(ERRCODE_DATATYPE_MISMATCH),
2552  errmsg("variable \"%s\" is of type %s"
2553  " but expression is of type %s",
2554  stmt->name,
2555  format_type_be(targettype),
2556  format_type_be(type_id)),
2557  errhint("You will need to rewrite or cast the expression."),
2558  parser_errposition(pstate, exprLocation(orig_expr))));
2559  }
2560 
2561  pstate->p_expr_kind = EXPR_KIND_NONE;
2562 
2563  qry->targetList = list_make1(tle);
2564 
2565  /* transform WHERE */
2566  qual = transformWhereClause(pstate, sstmt->whereClause,
2567  EXPR_KIND_WHERE, "WHERE");
2568 
2569  /* initial processing of HAVING clause is much like WHERE clause */
2570  qry->havingQual = transformWhereClause(pstate, sstmt->havingClause,
2571  EXPR_KIND_HAVING, "HAVING");
2572 
2573  /*
2574  * Transform sorting/grouping stuff. Do ORDER BY first because both
2575  * transformGroupClause and transformDistinctClause need the results. Note
2576  * that these functions can also change the targetList, so it's passed to
2577  * them by reference.
2578  */
2579  qry->sortClause = transformSortClause(pstate,
2580  sstmt->sortClause,
2581  &qry->targetList,
2583  false /* allow SQL92 rules */ );
2584 
2585  qry->groupClause = transformGroupClause(pstate,
2586  sstmt->groupClause,
2587  &qry->groupingSets,
2588  &qry->targetList,
2589  qry->sortClause,
2591  false /* allow SQL92 rules */ );
2592 
2593  if (sstmt->distinctClause == NIL)
2594  {
2595  qry->distinctClause = NIL;
2596  qry->hasDistinctOn = false;
2597  }
2598  else if (linitial(sstmt->distinctClause) == NULL)
2599  {
2600  /* We had SELECT DISTINCT */
2602  &qry->targetList,
2603  qry->sortClause,
2604  false);
2605  qry->hasDistinctOn = false;
2606  }
2607  else
2608  {
2609  /* We had SELECT DISTINCT ON */
2611  sstmt->distinctClause,
2612  &qry->targetList,
2613  qry->sortClause);
2614  qry->hasDistinctOn = true;
2615  }
2616 
2617  /* transform LIMIT */
2618  qry->limitOffset = transformLimitClause(pstate, sstmt->limitOffset,
2619  EXPR_KIND_OFFSET, "OFFSET",
2620  sstmt->limitOption);
2621  qry->limitCount = transformLimitClause(pstate, sstmt->limitCount,
2622  EXPR_KIND_LIMIT, "LIMIT",
2623  sstmt->limitOption);
2624  qry->limitOption = sstmt->limitOption;
2625 
2626  /* transform window clauses after we have seen all window functions */
2628  pstate->p_windowdefs,
2629  &qry->targetList);
2630 
2631  qry->rtable = pstate->p_rtable;
2632  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2633 
2634  qry->hasSubLinks = pstate->p_hasSubLinks;
2635  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
2636  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2637  qry->hasAggs = pstate->p_hasAggs;
2638 
2639  foreach(l, sstmt->lockingClause)
2640  {
2641  transformLockingClause(pstate, qry,
2642  (LockingClause *) lfirst(l), false);
2643  }
2644 
2645  assign_query_collations(pstate, qry);
2646 
2647  /* this must be done after collations, for reliable comparison of exprs */
2648  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
2649  parseCheckAggregates(pstate, qry);
2650 
2651  return qry;
2652 }
Value * makeString(char *str)
Definition: value.c:53
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
LimitOption limitOption
Definition: parsenodes.h:1626
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:2981
bool p_hasSubLinks
Definition: parse_node.h:209
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
int errhint(const char *fmt,...)
Definition: elog.c:1162
List * sortClause
Definition: parsenodes.h:158
List * transformDistinctOnClause(ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1231
List * fromClause
Definition: parsenodes.h:1603
FromExpr * jointree
Definition: parsenodes.h:138
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1025
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:1624
bool hasAggs
Definition: parsenodes.h:125
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
bool p_hasTargetSRFs
Definition: parse_node.h:208
List * indirection
Definition: parsenodes.h:1690
List * groupingSets
Definition: parsenodes.h:150
List * list_copy(const List *oldlist)
Definition: list.c:1418
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
bool p_hasAggs
Definition: parse_node.h:206
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
SelectStmt * val
Definition: parsenodes.h:1692
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:1042
bool hasDistinctOn
Definition: parsenodes.h:129
signed int int32
Definition: c.h:417
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
bool p_hasWindowFuncs
Definition: parse_node.h:207
int location
Definition: parsenodes.h:237
#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:1599
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
#define ERROR
Definition: elog.h:45
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:193
Node * limitCount
Definition: parsenodes.h:161
List * sortClause
Definition: parsenodes.h:1623
List * targetList
Definition: parsenodes.h:1602
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:197
List * lockingClause
Definition: parsenodes.h:1627
List * lappend(List *list, void *datum)
Definition: list.c:336
LimitOption limitOption
Definition: parsenodes.h:162
List * transformWindowDefinitions(ParseState *pstate, List *windowdefs, List **targetlist)
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:114
ParseExprKind p_expr_kind
Definition: parse_node.h:194
List * windowClause
Definition: parsenodes.h:1607
#define ereport(elevel,...)
Definition: elog.h:155
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define makeNode(_type_)
Definition: nodes.h:576
#define lfirst(lc)
Definition: pg_list.h:169
bool hasWindowFuncs
Definition: parsenodes.h:126
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
Expr * expr
Definition: primnodes.h:1431
#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:1605
List * groupClause
Definition: parsenodes.h:148
int errmsg(const char *fmt,...)
Definition: elog.c:915
bool hasSubLinks
Definition: parsenodes.h:128
void assign_query_collations(ParseState *pstate, Query *query)
Node * havingClause
Definition: parsenodes.h:1606
#define elog(elevel,...)
Definition: elog.h:228
bool p_is_insert
Definition: parse_node.h:192
List * p_joinlist
Definition: parse_node.h:182
List * transformDistinctClause(ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
Node * havingQual
Definition: parsenodes.h:152
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:671
Node * limitCount
Definition: parsenodes.h:1625
List * fields
Definition: parsenodes.h:236
Node * whereClause
Definition: parsenodes.h:1604
List * list_delete_first(List *list)
Definition: list.c:875
List * p_rtable
Definition: parse_node.h:180

◆ transformReturningList()

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

Definition at line 2360 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().

2361 {
2362  List *rlist;
2363  int save_next_resno;
2364 
2365  if (returningList == NIL)
2366  return NIL; /* nothing to do */
2367 
2368  /*
2369  * We need to assign resnos starting at one in the RETURNING list. Save
2370  * and restore the main tlist's value of p_next_resno, just in case
2371  * someone looks at it later (probably won't happen).
2372  */
2373  save_next_resno = pstate->p_next_resno;
2374  pstate->p_next_resno = 1;
2375 
2376  /* transform RETURNING identically to a SELECT targetlist */
2377  rlist = transformTargetList(pstate, returningList, EXPR_KIND_RETURNING);
2378 
2379  /*
2380  * Complain if the nonempty tlist expanded to nothing (which is possible
2381  * if it contains only a star-expansion of a zero-column table). If we
2382  * allow this, the parsed Query will look like it didn't have RETURNING,
2383  * with results that would probably surprise the user.
2384  */
2385  if (rlist == NIL)
2386  ereport(ERROR,
2387  (errcode(ERRCODE_SYNTAX_ERROR),
2388  errmsg("RETURNING must have at least one column"),
2389  parser_errposition(pstate,
2390  exprLocation(linitial(returningList)))));
2391 
2392  /* mark column origins */
2393  markTargetListOrigins(pstate, rlist);
2394 
2395  /* resolve any still-unresolved output columns as being type text */
2396  if (pstate->p_resolve_unknowns)
2397  resolveTargetListUnknowns(pstate, rlist);
2398 
2399  /* restore state */
2400  pstate->p_next_resno = save_next_resno;
2401 
2402  return rlist;
2403 }
#define NIL
Definition: pg_list.h:65
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1231
int errcode(int sqlerrcode)
Definition: elog.c:704
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:45
bool p_resolve_unknowns
Definition: parse_node.h:200
int p_next_resno
Definition: parse_node.h:195
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
Definition: parse_target.c:291
#define ereport(elevel,...)
Definition: elog.h:155
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:915
Definition: pg_list.h:50

◆ transformSelectStmt()

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

Definition at line 1200 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::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().

1201 {
1202  Query *qry = makeNode(Query);
1203  Node *qual;
1204  ListCell *l;
1205 
1206  qry->commandType = CMD_SELECT;
1207 
1208  /* process the WITH clause independently of all else */
1209  if (stmt->withClause)
1210  {
1211  qry->hasRecursive = stmt->withClause->recursive;
1212  qry->cteList = transformWithClause(pstate, stmt->withClause);
1213  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1214  }
1215 
1216  /* Complain if we get called from someplace where INTO is not allowed */
1217  if (stmt->intoClause)
1218  ereport(ERROR,
1219  (errcode(ERRCODE_SYNTAX_ERROR),
1220  errmsg("SELECT ... INTO is not allowed here"),
1221  parser_errposition(pstate,
1222  exprLocation((Node *) stmt->intoClause))));
1223 
1224  /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
1225  pstate->p_locking_clause = stmt->lockingClause;
1226 
1227  /* make WINDOW info available for window functions, too */
1228  pstate->p_windowdefs = stmt->windowClause;
1229 
1230  /* process the FROM clause */
1231  transformFromClause(pstate, stmt->fromClause);
1232 
1233  /* transform targetlist */
1234  qry->targetList = transformTargetList(pstate, stmt->targetList,
1236 
1237  /* mark column origins */
1238  markTargetListOrigins(pstate, qry->targetList);
1239 
1240  /* transform WHERE */
1241  qual = transformWhereClause(pstate, stmt->whereClause,
1242  EXPR_KIND_WHERE, "WHERE");
1243 
1244  /* initial processing of HAVING clause is much like WHERE clause */
1245  qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
1246  EXPR_KIND_HAVING, "HAVING");
1247 
1248  /*
1249  * Transform sorting/grouping stuff. Do ORDER BY first because both
1250  * transformGroupClause and transformDistinctClause need the results. Note
1251  * that these functions can also change the targetList, so it's passed to
1252  * them by reference.
1253  */
1254  qry->sortClause = transformSortClause(pstate,
1255  stmt->sortClause,
1256  &qry->targetList,
1258  false /* allow SQL92 rules */ );
1259 
1260  qry->groupClause = transformGroupClause(pstate,
1261  stmt->groupClause,
1262  &qry->groupingSets,
1263  &qry->targetList,
1264  qry->sortClause,
1266  false /* allow SQL92 rules */ );
1267 
1268  if (stmt->distinctClause == NIL)
1269  {
1270  qry->distinctClause = NIL;
1271  qry->hasDistinctOn = false;
1272  }
1273  else if (linitial(stmt->distinctClause) == NULL)
1274  {
1275  /* We had SELECT DISTINCT */
1277  &qry->targetList,
1278  qry->sortClause,
1279  false);
1280  qry->hasDistinctOn = false;
1281  }
1282  else
1283  {
1284  /* We had SELECT DISTINCT ON */
1286  stmt->distinctClause,
1287  &qry->targetList,
1288  qry->sortClause);
1289  qry->hasDistinctOn = true;
1290  }
1291 
1292  /* transform LIMIT */
1293  qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1294  EXPR_KIND_OFFSET, "OFFSET",
1295  stmt->limitOption);
1296  qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1297  EXPR_KIND_LIMIT, "LIMIT",
1298  stmt->limitOption);
1299  qry->limitOption = stmt->limitOption;
1300 
1301  /* transform window clauses after we have seen all window functions */
1303  pstate->p_windowdefs,
1304  &qry->targetList);
1305 
1306  /* resolve any still-unresolved output columns as being type text */
1307  if (pstate->p_resolve_unknowns)
1308  resolveTargetListUnknowns(pstate, qry->targetList);
1309 
1310  qry->rtable = pstate->p_rtable;
1311  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
1312 
1313  qry->hasSubLinks = pstate->p_hasSubLinks;
1314  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1315  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1316  qry->hasAggs = pstate->p_hasAggs;
1317 
1318  foreach(l, stmt->lockingClause)
1319  {
1320  transformLockingClause(pstate, qry,
1321  (LockingClause *) lfirst(l), false);
1322  }
1323 
1324  assign_query_collations(pstate, qry);
1325 
1326  /* this must be done after collations, for reliable comparison of exprs */
1327  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1328  parseCheckAggregates(pstate, qry);
1329 
1330  return qry;
1331 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
LimitOption limitOption
Definition: parsenodes.h:1626
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:2981
bool p_hasSubLinks
Definition: parse_node.h:209
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
List * sortClause
Definition: parsenodes.h:158
List * transformDistinctOnClause(ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
IntoClause * intoClause
Definition: parsenodes.h:1601
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1231
List * fromClause
Definition: parsenodes.h:1603
FromExpr * jointree
Definition: parsenodes.h:138
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
Node * limitOffset
Definition: parsenodes.h:1624
bool hasAggs
Definition: parsenodes.h:125
bool p_hasTargetSRFs
Definition: parse_node.h:208
List * groupingSets
Definition: parsenodes.h:150
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
bool p_hasAggs
Definition: parse_node.h:206
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1042
bool hasDistinctOn
Definition: parsenodes.h:129
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
bool p_hasWindowFuncs
Definition: parse_node.h:207
bool hasRecursive
Definition: parsenodes.h:130
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:123
List * distinctClause
Definition: parsenodes.h:1599
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
#define ERROR
Definition: elog.h:45
Node * transformLimitClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName, LimitOption limitOption)
List * p_windowdefs
Definition: parse_node.h:193
bool p_resolve_unknowns
Definition: parse_node.h:200
Node * limitCount
Definition: parsenodes.h:161
List * sortClause
Definition: parsenodes.h:1623
List * targetList
Definition: parsenodes.h:1602
List * transformGroupClause(ParseState *pstate, List *grouplist, List **groupingSets, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99)
List * p_locking_clause
Definition: parse_node.h:197
bool recursive
Definition: parsenodes.h:1404
List * lockingClause
Definition: parsenodes.h:1627
bool p_hasModifyingCTE
Definition: parse_node.h:210
LimitOption limitOption
Definition: parsenodes.h:162
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:114
List * windowClause
Definition: parsenodes.h:1607
#define ereport(elevel,...)
Definition: elog.h:155
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define makeNode(_type_)
Definition: nodes.h:576
#define lfirst(lc)
Definition: pg_list.h:169
bool hasWindowFuncs
Definition: parsenodes.h:126
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:105
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
List * groupClause
Definition: parsenodes.h:1605
List * cteList
Definition: parsenodes.h:135
List * groupClause
Definition: parsenodes.h:148
int errmsg(const char *fmt,...)
Definition: elog.c:915
bool hasSubLinks
Definition: parsenodes.h:128
void assign_query_collations(ParseState *pstate, Query *query)
Node * havingClause
Definition: parsenodes.h:1606
List * p_joinlist
Definition: parse_node.h:182
bool hasModifyingCTE
Definition: parsenodes.h:131
WithClause * withClause
Definition: parsenodes.h:1628
List * transformDistinctClause(ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
Node * havingQual
Definition: parsenodes.h:152
Node * limitCount
Definition: parsenodes.h:1625
Node * whereClause
Definition: parsenodes.h:1604
List * p_rtable
Definition: parse_node.h:180

◆ transformSetOperationStmt()

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

Definition at line 1565 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().

1566 {
1567  Query *qry = makeNode(Query);
1568  SelectStmt *leftmostSelect;
1569  int leftmostRTI;
1570  Query *leftmostQuery;
1571  SetOperationStmt *sostmt;
1572  List *sortClause;
1573  Node *limitOffset;
1574  Node *limitCount;
1575  List *lockingClause;
1576  WithClause *withClause;
1577  Node *node;
1578  ListCell *left_tlist,
1579  *lct,
1580  *lcm,
1581  *lcc,
1582  *l;
1583  List *targetvars,
1584  *targetnames,
1585  *sv_namespace;
1586  int sv_rtable_length;
1587  ParseNamespaceItem *jnsitem;
1588  ParseNamespaceColumn *sortnscolumns;
1589  int sortcolindex;
1590  int tllen;
1591 
1592  qry->commandType = CMD_SELECT;
1593 
1594  /*
1595  * Find leftmost leaf SelectStmt. We currently only need to do this in
1596  * order to deliver a suitable error message if there's an INTO clause
1597  * there, implying the set-op tree is in a context that doesn't allow
1598  * INTO. (transformSetOperationTree would throw error anyway, but it
1599  * seems worth the trouble to throw a different error for non-leftmost
1600  * INTO, so we produce that error in transformSetOperationTree.)
1601  */
1602  leftmostSelect = stmt->larg;
1603  while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
1604  leftmostSelect = leftmostSelect->larg;
1605  Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
1606  leftmostSelect->larg == NULL);
1607  if (leftmostSelect->intoClause)
1608  ereport(ERROR,
1609  (errcode(ERRCODE_SYNTAX_ERROR),
1610  errmsg("SELECT ... INTO is not allowed here"),
1611  parser_errposition(pstate,
1612  exprLocation((Node *) leftmostSelect->intoClause))));
1613 
1614  /*
1615  * We need to extract ORDER BY and other top-level clauses here and not
1616  * let transformSetOperationTree() see them --- else it'll just recurse
1617  * right back here!
1618  */
1619  sortClause = stmt->sortClause;
1620  limitOffset = stmt->limitOffset;
1621  limitCount = stmt->limitCount;
1622  lockingClause = stmt->lockingClause;
1623  withClause = stmt->withClause;
1624 
1625  stmt->sortClause = NIL;
1626  stmt->limitOffset = NULL;
1627  stmt->limitCount = NULL;
1628  stmt->lockingClause = NIL;
1629  stmt->withClause = NULL;
1630 
1631  /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1632  if (lockingClause)
1633  ereport(ERROR,
1634  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1635  /*------
1636  translator: %s is a SQL row locking clause such as FOR UPDATE */
1637  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1639  linitial(lockingClause))->strength))));
1640 
1641  /* Process the WITH clause independently of all else */
1642  if (withClause)
1643  {
1644  qry->hasRecursive = withClause->recursive;
1645  qry->cteList = transformWithClause(pstate, withClause);
1646  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1647  }
1648 
1649  /*
1650  * Recursively transform the components of the tree.
1651  */
1652  sostmt = castNode(SetOperationStmt,
1653  transformSetOperationTree(pstate, stmt, true, NULL));
1654  Assert(sostmt);
1655  qry->setOperations = (Node *) sostmt;
1656 
1657  /*
1658  * Re-find leftmost SELECT (now it's a sub-query in rangetable)
1659  */
1660  node = sostmt->larg;
1661  while (node && IsA(node, SetOperationStmt))
1662  node = ((SetOperationStmt *) node)->larg;
1663  Assert(node && IsA(node, RangeTblRef));
1664  leftmostRTI = ((RangeTblRef *) node)->rtindex;
1665  leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
1666  Assert(leftmostQuery != NULL);
1667 
1668  /*
1669  * Generate dummy targetlist for outer query using column names of
1670  * leftmost select and common datatypes/collations of topmost set
1671  * operation. Also make lists of the dummy vars and their names for use
1672  * in parsing ORDER BY.
1673  *
1674  * Note: we use leftmostRTI as the varno of the dummy variables. It
1675  * shouldn't matter too much which RT index they have, as long as they
1676  * have one that corresponds to a real RT entry; else funny things may
1677  * happen when the tree is mashed by rule rewriting.
1678  */
1679  qry->targetList = NIL;
1680  targetvars = NIL;
1681  targetnames = NIL;
1682  sortnscolumns = (ParseNamespaceColumn *)
1683  palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
1684  sortcolindex = 0;
1685 
1686  forfour(lct, sostmt->colTypes,
1687  lcm, sostmt->colTypmods,
1688  lcc, sostmt->colCollations,
1689  left_tlist, leftmostQuery->targetList)
1690  {
1691  Oid colType = lfirst_oid(lct);
1692  int32 colTypmod = lfirst_int(lcm);
1693  Oid colCollation = lfirst_oid(lcc);
1694  TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
1695  char *colName;
1696  TargetEntry *tle;
1697  Var *var;
1698 
1699  Assert(!lefttle->resjunk);
1700  colName = pstrdup(lefttle->resname);
1701  var = makeVar(leftmostRTI,
1702  lefttle->resno,
1703  colType,
1704  colTypmod,
1705  colCollation,
1706  0);
1707  var->location = exprLocation((Node *) lefttle->expr);
1708  tle = makeTargetEntry((Expr *) var,
1709  (AttrNumber) pstate->p_next_resno++,
1710  colName,
1711  false);
1712  qry->targetList = lappend(qry->targetList, tle);
1713  targetvars = lappend(targetvars, var);
1714  targetnames = lappend(targetnames, makeString(colName));
1715  sortnscolumns[sortcolindex].p_varno = leftmostRTI;
1716  sortnscolumns[sortcolindex].p_varattno = lefttle->resno;
1717  sortnscolumns[sortcolindex].p_vartype = colType;
1718  sortnscolumns[sortcolindex].p_vartypmod = colTypmod;
1719  sortnscolumns[sortcolindex].p_varcollid = colCollation;
1720  sortnscolumns[sortcolindex].p_varnosyn = leftmostRTI;
1721  sortnscolumns[sortcolindex].p_varattnosyn = lefttle->resno;
1722  sortcolindex++;
1723  }
1724 
1725  /*
1726  * As a first step towards supporting sort clauses that are expressions
1727  * using the output columns, generate a namespace entry that makes the
1728  * output columns visible. A Join RTE node is handy for this, since we
1729  * can easily control the Vars generated upon matches.
1730  *
1731  * Note: we don't yet do anything useful with such cases, but at least
1732  * "ORDER BY upper(foo)" will draw the right error message rather than
1733  * "foo not found".
1734  */
1735  sv_rtable_length = list_length(pstate->p_rtable);
1736 
1737  jnsitem = addRangeTableEntryForJoin(pstate,
1738  targetnames,
1739  sortnscolumns,
1740  JOIN_INNER,
1741  0,
1742  targetvars,
1743  NIL,
1744  NIL,
1745  NULL,
1746  false);
1747 
1748  sv_namespace = pstate->p_namespace;
1749  pstate->p_namespace = NIL;
1750 
1751  /* add jnsitem to column namespace only */
1752  addNSItemToQuery(pstate, jnsitem, false, false, true);
1753 
1754  /*
1755  * For now, we don't support resjunk sort clauses on the output of a
1756  * setOperation tree --- you can only use the SQL92-spec options of
1757  * selecting an output column by name or number. Enforce by checking that
1758  * transformSortClause doesn't add any items to tlist.
1759  */
1760  tllen = list_length(qry->targetList);
1761 
1762  qry->sortClause = transformSortClause(pstate,
1763  sortClause,
1764  &qry->targetList,
1766  false /* allow SQL92 rules */ );
1767 
1768  /* restore namespace, remove join RTE from rtable */
1769  pstate->p_namespace = sv_namespace;
1770  pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
1771 
1772  if (tllen != list_length(qry->targetList))
1773  ereport(ERROR,
1774  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1775  errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
1776  errdetail("Only result column names can be used, not expressions or functions."),
1777  errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
1778  parser_errposition(pstate,
1779  exprLocation(list_nth(qry->targetList, tllen)))));
1780 
1781  qry->limitOffset = transformLimitClause(pstate, limitOffset,
1782  EXPR_KIND_OFFSET, "OFFSET",
1783  stmt->limitOption);
1784  qry->limitCount = transformLimitClause(pstate, limitCount,
1785  EXPR_KIND_LIMIT, "LIMIT",
1786  stmt->limitOption);
1787  qry->limitOption = stmt->limitOption;
1788 
1789  qry->rtable = pstate->p_rtable;
1790  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1791 
1792  qry->hasSubLinks = pstate->p_hasSubLinks;
1793  qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
1794  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
1795  qry->hasAggs = pstate->p_hasAggs;
1796 
1797  foreach(l, lockingClause)
1798  {
1799  transformLockingClause(pstate, qry,
1800  (LockingClause *) lfirst(l), false);
1801  }
1802 
1803  assign_query_collations(pstate, qry);
1804 
1805  /* this must be done after collations, for reliable comparison of exprs */
1806  if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual)
1807  parseCheckAggregates(pstate, qry);
1808 
1809  return qry;
1810 }
Value * makeString(char *str)
Definition: value.c:53
struct ParseNamespaceColumn ParseNamespaceColumn
Definition: parse_node.h:25
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
struct SelectStmt * larg
Definition: parsenodes.h:1635
LimitOption limitOption
Definition: parsenodes.h:1626
static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown)
Definition: analyze.c:2981
bool p_hasSubLinks
Definition: parse_node.h:209
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:2892
int errhint(const char *fmt,...)
Definition: elog.c:1162
List * sortClause
Definition: parsenodes.h:158
IntoClause * intoClause
Definition: parsenodes.h:1601
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1231
FromExpr * jointree
Definition: parsenodes.h:138
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99)
Node * limitOffset
Definition: parsenodes.h:1624
char * pstrdup(const char *in)
Definition: mcxt.c:1187
bool hasAggs
Definition: parsenodes.h:125
List * list_truncate(List *list, int new_size)
Definition: list.c:600
bool p_hasTargetSRFs
Definition: parse_node.h:208
List * groupingSets
Definition: parsenodes.h:150
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
bool p_hasAggs
Definition: parse_node.h:206
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1433
Definition: primnodes.h:181
void parseCheckAggregates(ParseState *pstate, Query *qry)
Definition: parse_agg.c:1042
signed int int32
Definition: c.h:417
List * targetList
Definition: parsenodes.h:140
bool p_hasWindowFuncs
Definition: parse_node.h:207
bool hasRecursive
Definition: parsenodes.h:130
bool resjunk
Definition: primnodes.h:1438
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
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:196
Node * limitCount
Definition: parsenodes.h:161
AttrNumber p_varattno
Definition: parse_node.h:291
List * p_namespace
Definition: parse_node.h:184
List * sortClause
Definition: parsenodes.h:1623
int errdetail(const char *fmt,...)
Definition: elog.c:1048
AttrNumber resno
Definition: primnodes.h:1432
int p_next_resno
Definition: parse_node.h:195
bool recursive
Definition: parsenodes.h:1404
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static Node * transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, bool isTopLevel, List **targetlist)
Definition: analyze.c:1827
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lockingClause
Definition: parsenodes.h:1627
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:210
List * lappend(List *list, void *datum)
Definition: list.c:336
LimitOption limitOption
Definition: parsenodes.h:162
List * colCollations
Definition: parsenodes.h:1672
void * palloc0(Size size)
Definition: mcxt.c:981
SetOperation op
Definition: parsenodes.h:1633
#define ereport(elevel,...)
Definition: elog.h:155
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define makeNode(_type_)
Definition: nodes.h:576
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
bool hasWindowFuncs
Definition: parsenodes.h:126
Expr * expr
Definition: primnodes.h:1431
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:105
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:135
Node * setOperations
Definition: parsenodes.h:166
List * groupClause
Definition: parsenodes.h:148
int errmsg(const char *fmt,...)
Definition: elog.c:915
bool hasSubLinks
Definition: parsenodes.h:128
void assign_query_collations(ParseState *pstate, Query *query)
AttrNumber p_varattnosyn
Definition: parse_node.h:296
List * p_joinlist
Definition: parse_node.h:182
bool hasModifyingCTE
Definition: parsenodes.h:131
ParseNamespaceItem * addRangeTableEntryForJoin(ParseState *pstate, List *colnames, ParseNamespaceColumn *nscolumns, JoinType jointype, int nummergedcols, List *aliasvars, List *leftcols, List *rightcols, Alias *alias, bool inFromCl)
WithClause * withClause
Definition: parsenodes.h:1628
Node * havingQual
Definition: parsenodes.h:152
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
Node * limitCount
Definition: parsenodes.h:1625
#define lfirst_oid(lc)
Definition: pg_list.h:171
List * p_rtable
Definition: parse_node.h:180

◆ transformSetOperationTree()

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

Definition at line 1827 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(), SortGroupClause::eqop, ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprLocation(), exprType(), forboth, get_sort_group_operators(), SetOperationStmt::groupClauses, SortGroupClause::hashable, 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, makeTargetEntry(), NIL, SortGroupClause::nulls_first, 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, SortGroupClause::sortop, Query::targetList, SortGroupClause::tleSortGroupRef, SetToDefault::typeId, SetToDefault::typeMod, and SelectStmt::withClause.

Referenced by transformSetOperationStmt().

1829 {
1830  bool isLeaf;
1831 
1832  Assert(stmt && IsA(stmt, SelectStmt));
1833 
1834  /* Guard against stack overflow due to overly complex set-expressions */
1836 
1837  /*
1838  * Validity-check both leaf and internal SELECTs for disallowed ops.
1839  */
1840  if (stmt->intoClause)
1841  ereport(ERROR,
1842  (errcode(ERRCODE_SYNTAX_ERROR),
1843  errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
1844  parser_errposition(pstate,
1845  exprLocation((Node *) stmt->intoClause))));
1846 
1847  /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
1848  if (stmt->lockingClause)
1849  ereport(ERROR,
1850  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1851  /*------
1852  translator: %s is a SQL row locking clause such as FOR UPDATE */
1853  errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1855  linitial(stmt->lockingClause))->strength))));
1856 
1857  /*
1858  * If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
1859  * or WITH clauses attached, we need to treat it like a leaf node to
1860  * generate an independent sub-Query tree. Otherwise, it can be
1861  * represented by a SetOperationStmt node underneath the parent Query.
1862  */
1863  if (stmt->op == SETOP_NONE)
1864  {
1865  Assert(stmt->larg == NULL && stmt->rarg == NULL);
1866  isLeaf = true;
1867  }
1868  else
1869  {
1870  Assert(stmt->larg != NULL && stmt->rarg != NULL);
1871  if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
1872  stmt->lockingClause || stmt->withClause)
1873  isLeaf = true;
1874  else
1875  isLeaf = false;
1876  }
1877 
1878  if (isLeaf)
1879  {
1880  /* Process leaf SELECT */
1881  Query *selectQuery;
1882  char selectName[32];
1883  ParseNamespaceItem *nsitem;
1884  RangeTblRef *rtr;
1885  ListCell *tl;
1886 
1887  /*
1888  * Transform SelectStmt into a Query.
1889  *
1890  * This works the same as SELECT transformation normally would, except
1891  * that we prevent resolving unknown-type outputs as TEXT. This does
1892  * not change the subquery's semantics since if the column type
1893  * matters semantically, it would have been resolved to something else
1894  * anyway. Doing this lets us resolve such outputs using
1895  * select_common_type(), below.
1896  *
1897  * Note: previously transformed sub-queries don't affect the parsing
1898  * of this sub-query, because they are not in the toplevel pstate's
1899  * namespace list.
1900  */
1901  selectQuery = parse_sub_analyze((Node *) stmt, pstate,
1902  NULL, false, false);
1903 
1904  /*
1905  * Check for bogus references to Vars on the current query level (but
1906  * upper-level references are okay). Normally this can't happen
1907  * because the namespace will be empty, but it could happen if we are
1908  * inside a rule.
1909  */
1910  if (pstate->p_namespace)
1911  {
1912  if (contain_vars_of_level((Node *) selectQuery, 1))
1913  ereport(ERROR,
1914  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1915  errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
1916  parser_errposition(pstate,
1917  locate_var_of_level((Node *) selectQuery, 1))));
1918  }
1919 
1920  /*
1921  * Extract a list of the non-junk TLEs for upper-level processing.
1922  */
1923  if (targetlist)
1924  {
1925  *targetlist = NIL;
1926  foreach(tl, selectQuery->targetList)
1927  {
1928  TargetEntry *tle = (TargetEntry *) lfirst(tl);
1929 
1930  if (!tle->resjunk)
1931  *targetlist = lappend(*targetlist, tle);
1932  }
1933  }
1934 
1935  /*
1936  * Make the leaf query be a subquery in the top-level rangetable.
1937  */
1938  snprintf(selectName, sizeof(selectName), "*SELECT* %d",
1939  list_length(pstate->p_rtable) + 1);
1940  nsitem = addRangeTableEntryForSubquery(pstate,
1941  selectQuery,
1942  makeAlias(selectName, NIL),
1943  false,
1944  false);
1945 
1946  /*
1947  * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
1948  */
1949  rtr = makeNode(RangeTblRef);
1950  rtr->rtindex = nsitem->p_rtindex;
1951  return (Node *) rtr;
1952  }
1953  else
1954  {
1955  /* Process an internal node (set operation node) */
1957  List *ltargetlist;
1958  List *rtargetlist;
1959  ListCell *ltl;
1960  ListCell *rtl;
1961  const char *context;
1962 
1963  context = (stmt->op == SETOP_UNION ? "UNION" :
1964  (stmt->op == SETOP_INTERSECT ? "INTERSECT" :
1965  "EXCEPT"));
1966 
1967  op->op = stmt->op;
1968  op->all = stmt->all;
1969 
1970  /*
1971  * Recursively transform the left child node.
1972  */
1973  op->larg = transformSetOperationTree(pstate, stmt->larg,
1974  false,
1975  &ltargetlist);
1976 
1977  /*
1978  * If we are processing a recursive union query, now is the time to
1979  * examine the non-recursive term's output columns and mark the
1980  * containing CTE as having those result columns. We should do this
1981  * only at the topmost setop of the CTE, of course.
1982  */
1983  if (isTopLevel &&
1984  pstate->p_parent_cte &&
1985  pstate->p_parent_cte->cterecursive)
1986  determineRecursiveColTypes(pstate, op->larg, ltargetlist);
1987 
1988  /*
1989  * Recursively transform the right child node.
1990  */
1991  op->rarg = transformSetOperationTree(pstate, stmt->rarg,
1992  false,
1993  &rtargetlist);
1994 
1995  /*
1996  * Verify that the two children have the same number of non-junk
1997  * columns, and determine the types of the merged output columns.
1998  */
1999  if (list_length(ltargetlist) != list_length(rtargetlist))
2000  ereport(ERROR,
2001  (errcode(ERRCODE_SYNTAX_ERROR),
2002  errmsg("each %s query must have the same number of columns",
2003  context),
2004  parser_errposition(pstate,
2005  exprLocation((Node *) rtargetlist))));
2006 
2007  if (targetlist)
2008  *targetlist = NIL;
2009  op->colTypes = NIL;
2010  op->colTypmods = NIL;
2011  op->colCollations = NIL;
2012  op->groupClauses = NIL;
2013  forboth(ltl, ltargetlist, rtl, rtargetlist)
2014  {
2015  TargetEntry *ltle = (TargetEntry *) lfirst(ltl);
2016  TargetEntry *rtle = (TargetEntry *) lfirst(rtl);
2017  Node *lcolnode = (Node *) ltle->expr;
2018  Node *rcolnode = (Node *) rtle->expr;
2019  Oid lcoltype = exprType(lcolnode);
2020  Oid rcoltype = exprType(rcolnode);
2021  Node *bestexpr;
2022  int bestlocation;
2023  Oid rescoltype;
2024  int32 rescoltypmod;
2025  Oid rescolcoll;
2026 
2027  /* select common type, same as CASE et al */
2028  rescoltype = select_common_type(pstate,
2029  list_make2(lcolnode, rcolnode),
2030  context,
2031  &bestexpr);
2032  bestlocation = exprLocation(bestexpr);
2033 
2034  /*
2035  * Verify the coercions are actually possible. If not, we'd fail
2036  * later anyway, but we want to fail now while we have sufficient
2037  * context to produce an error cursor position.
2038  *
2039  * For all non-UNKNOWN-type cases, we verify coercibility but we
2040  * don't modify the child's expression, for fear of changing the
2041  * child query's semantics.
2042  *
2043  * If a child expression is an UNKNOWN-type Const or Param, we
2044  * want to replace it with the coerced expression. This can only
2045  * happen when the child is a leaf set-op node. It's safe to
2046  * replace the expression because if the child query's semantics
2047  * depended on the type of this output column, it'd have already
2048  * coerced the UNKNOWN to something else. We want to do this
2049  * because (a) we want to verify that a Const is valid for the
2050  * target type, or resolve the actual type of an UNKNOWN Param,
2051  * and (b) we want to avoid unnecessary discrepancies between the
2052  * output type of the child query and the resolved target type.
2053  * Such a discrepancy would disable optimization in the planner.
2054  *
2055  * If it's some other UNKNOWN-type node, eg a Var, we do nothing
2056  * (knowing that coerce_to_common_type would fail). The planner
2057  * is sometimes able to fold an UNKNOWN Var to a constant before
2058  * it has to coerce the type, so failing now would just break
2059  * cases that might work.
2060  */
2061  if (lcoltype != UNKNOWNOID)
2062  lcolnode = coerce_to_common_type(pstate, lcolnode,
2063  rescoltype, context);
2064  else if (IsA(lcolnode, Const) ||
2065  IsA(lcolnode, Param))
2066  {
2067  lcolnode = coerce_to_common_type(pstate, lcolnode,
2068  rescoltype, context);
2069  ltle->expr = (Expr *) lcolnode;
2070  }
2071 
2072  if (rcoltype != UNKNOWNOID)
2073  rcolnode = coerce_to_common_type(pstate, rcolnode,
2074  rescoltype, context);
2075  else if (IsA(rcolnode, Const) ||
2076  IsA(rcolnode, Param))
2077  {
2078  rcolnode = coerce_to_common_type(pstate, rcolnode,
2079  rescoltype, context);
2080  rtle->expr = (Expr *) rcolnode;
2081  }
2082 
2083  rescoltypmod = select_common_typmod(pstate,
2084  list_make2(lcolnode, rcolnode),
2085  rescoltype);
2086 
2087  /*
2088  * Select common collation. A common collation is required for
2089  * all set operators except UNION ALL; see SQL:2008 7.13 <query
2090  * expression> Syntax Rule 15c. (If we fail to identify a common
2091  * collation for a UNION ALL column, the colCollations element
2092  * will be set to InvalidOid, which may result in a runtime error
2093  * if something at a higher query level wants to use the column's
2094  * collation.)
2095  */
2096  rescolcoll = select_common_collation(pstate,
2097  list_make2(lcolnode, rcolnode),
2098  (op->op == SETOP_UNION && op->all));
2099 
2100  /* emit results */
2101  op->colTypes = lappend_oid(op->colTypes, rescoltype);
2102  op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
2103  op->colCollations = lappend_oid(op->colCollations, rescolcoll);
2104 
2105  /*
2106  * For all cases except UNION ALL, identify the grouping operators
2107  * (and, if available, sorting operators) that will be used to
2108  * eliminate duplicates.
2109  */
2110  if (op->op != SETOP_UNION || !op->all)
2111  {
2113  Oid sortop;
2114  Oid eqop;
2115  bool hashable;
2116  ParseCallbackState pcbstate;
2117 
2118  setup_parser_errposition_callback(&pcbstate, pstate,
2119  bestlocation);
2120 
2121  /* determine the eqop and optional sortop */
2122  get_sort_group_operators(rescoltype,
2123  false, true, false,
2124  &sortop, &eqop, NULL,
2125  &hashable);
2126 
2128 
2129  /* we don't have a tlist yet, so can't assign sortgrouprefs */
2130  grpcl->tleSortGroupRef = 0;
2131  grpcl->eqop = eqop;
2132  grpcl->sortop = sortop;
2133  grpcl->nulls_first = false; /* OK with or without sortop */
2134  grpcl->hashable = hashable;
2135 
2136  op->groupClauses = lappend(op->groupClauses, grpcl);
2137  }
2138 
2139  /*
2140  * Construct a dummy tlist entry to return. We use a SetToDefault
2141  * node for the expression, since it carries exactly the fields
2142  * needed, but any other expression node type would do as well.
2143  */
2144  if (targetlist)
2145  {
2146  SetToDefault *rescolnode = makeNode(SetToDefault);
2147  TargetEntry *restle;
2148 
2149  rescolnode->typeId = rescoltype;
2150  rescolnode->typeMod = rescoltypmod;
2151  rescolnode->collation = rescolcoll;
2152  rescolnode->location = bestlocation;
2153  restle = makeTargetEntry((Expr *) rescolnode,
2154  0, /* no need to set resno */
2155  NULL,
2156  false);
2157  *targetlist = lappend(*targetlist, restle);
2158  }
2159  }
2160 
2161  return (Node *) op;
2162  }
2163 }
#define list_make2(x1, x2)
Definition: pg_list.h:208
#define NIL
Definition: pg_list.h:65
struct SelectStmt * larg
Definition: parsenodes.h:1635
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:2892
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
IntoClause * intoClause
Definition: parsenodes.h:1601
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1231
Node * limitOffset
Definition: parsenodes.h:1624
int32 select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
Index tleSortGroupRef
Definition: parsenodes.h:1262
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
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:189
signed int int32
Definition: c.h:417
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:1438
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
List * p_namespace
Definition: parse_node.h:184
int32 typeMod
Definition: primnodes.h:1320
List * sortClause
Definition: parsenodes.h:1623
void check_stack_depth(void)
Definition: postgres.c:3377
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:1827
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lockingClause
Definition: parsenodes.h:1627
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:1672
SetOperation op
Definition: parsenodes.h:1633
Query * parse_sub_analyze(Node *parseTree, ParseState *parentParseState, CommonTableExpr *parentCTE, bool locked_from_parent, bool resolve_unknowns)
Definition: analyze.c:168
#define ereport(elevel,...)
Definition: elog.h:155
#define makeNode(_type_)
Definition: nodes.h:576
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
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
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:396
Expr * expr
Definition: primnodes.h:1431
struct SelectStmt * rarg
Definition: parsenodes.h:1636
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:1663
int errmsg(const char *fmt,...)
Definition: elog.c:915
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:1628
static void determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
Definition: analyze.c:2170
Definition: pg_list.h:50
#define snprintf
Definition: port.h:215
Node * limitCount
Definition: parsenodes.h:1625
List * p_rtable
Definition: parse_node.h:180

◆ transformStmt()

Query* transformStmt ( ParseState pstate,
Node parseTree 
)

Definition at line 258 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_SelectStmt, T_UpdateStmt, transformCallStmt(), transformCreateTableAsStmt(), transformDeclareCursorStmt(), transformDeleteStmt(), transformExplainStmt(), transformInsertStmt(), transformPLAssignStmt(), transformSelectStmt(), transformSetOperationStmt(), transformUpdateStmt(), transformValuesClause(), Query::utilityStmt, and SelectStmt::valuesLists.

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

259 {
260  Query *result;
261 
262  /*
263  * We apply RAW_EXPRESSION_COVERAGE_TEST testing to basic DML statements;
264  * we can't just run it on everything because raw_expression_tree_walker()
265  * doesn't claim to handle utility statements.
266  */
267 #ifdef RAW_EXPRESSION_COVERAGE_TEST
268  switch (nodeTag(parseTree))
269  {
270  case T_SelectStmt:
271  case T_InsertStmt:
272  case T_UpdateStmt:
273  case T_DeleteStmt:
274  (void) test_raw_expression_coverage(parseTree, NULL);
275  break;
276  default:
277  break;
278  }
279 #endif /* RAW_EXPRESSION_COVERAGE_TEST */
280 
281  switch (nodeTag(parseTree))
282  {
283  /*
284  * Optimizable statements
285  */
286  case T_InsertStmt:
287  result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
288  break;
289 
290  case T_DeleteStmt:
291  result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
292  break;
293 
294  case T_UpdateStmt:
295  result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
296  break;
297 
298  case T_SelectStmt:
299  {
300  SelectStmt *n = (SelectStmt *) parseTree;
301 
302  if (n->valuesLists)
303  result = transformValuesClause(pstate, n);
304  else if (n->op == SETOP_NONE)
305  result = transformSelectStmt(pstate, n);
306  else
307  result = transformSetOperationStmt(pstate, n);
308  }
309  break;
310 
311  case T_PLAssignStmt:
312  result = transformPLAssignStmt(pstate,
313  (PLAssignStmt *) parseTree);
314  break;
315 
316  /*
317  * Special cases
318  */
319  case T_DeclareCursorStmt:
320  result = transformDeclareCursorStmt(pstate,
321  (DeclareCursorStmt *) parseTree);
322  break;
323 
324  case T_ExplainStmt:
325  result = transformExplainStmt(pstate,
326  (ExplainStmt *) parseTree);
327  break;
328 
329  case T_CreateTableAsStmt:
330  result = transformCreateTableAsStmt(pstate,
331  (CreateTableAsStmt *) parseTree);
332  break;
333 
334  case T_CallStmt:
335  result = transformCallStmt(pstate,
336  (CallStmt *) parseTree);
337  break;
338 
339  default:
340 
341  /*
342  * other statements don't require any transformation; just return
343  * the original parsetree with a Query node plastered on top.
344  */
345  result = makeNode(Query);
346  result->commandType = CMD_UTILITY;
347  result->utilityStmt = (Node *) parseTree;
348  break;
349  }
350 
351  /* Mark as original query until we learn differently */
352  result->querySource = QSRC_ORIGINAL;
353  result->canSetTag = true;
354 
355  return result;
356 }
static Query * transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
Definition: analyze.c:2776
static Query * transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
Definition: analyze.c:2666
static Query * transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
Definition: analyze.c:2224
static Query * transformValuesClause(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1341
Definition: nodes.h:528
Node * utilityStmt
Definition: parsenodes.h:120
static Query * transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
Definition: analyze.c:2752
static Query * transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1200
List * valuesLists
Definition: parsenodes.h:1617
static Query * transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
Definition: analyze.c:2418
static Query * transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
Definition: analyze.c:477
SetOperation op
Definition: parsenodes.h:1633
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:576
QuerySource querySource
Definition: parsenodes.h:114
bool canSetTag
Definition: parsenodes.h:118
static Query * transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
Definition: analyze.c:407
static Query * transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
Definition: analyze.c:1565
#define nodeTag(nodeptr)
Definition: nodes.h:533
static Query * transformCallStmt(ParseState *pstate, CallStmt *stmt)
Definition: analyze.c:2853

◆ transformTopLevelStmt()

Query* transformTopLevelStmt ( ParseState pstate,
RawStmt parseTree 
)

Definition at line 195 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().

196 {
197  Query *result;
198 
199  /* We're at top level, so allow SELECT INTO */
200  result = transformOptionalSelectInto(pstate, parseTree->stmt);
201 
202  result->stmt_location = parseTree->stmt_location;
203  result->stmt_len = parseTree->stmt_len;
204 
205  return result;
206 }
int stmt_location
Definition: parsenodes.h:181
Node * stmt
Definition: parsenodes.h:1513
int stmt_len
Definition: parsenodes.h:1515
int stmt_location
Definition: parsenodes.h:1514
static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
Definition: analyze.c:219
int stmt_len
Definition: parsenodes.h:182

◆ transformUpdateStmt()

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

Definition at line 2224 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().

2225 {
2226  Query *qry = makeNode(Query);
2227  ParseNamespaceItem *nsitem;
2228  Node *qual;
2229 
2230  qry->commandType = CMD_UPDATE;
2231  pstate->p_is_insert = false;
2232 
2233  /* process the WITH clause independently of all else */
2234  if (stmt->withClause)
2235  {
2236  qry->hasRecursive = stmt->withClause->recursive;
2237  qry->cteList = transformWithClause(pstate, stmt->withClause);
2238  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
2239  }
2240 
2241  qry->resultRelation = setTargetTable(pstate, stmt->relation,
2242  stmt->relation->inh,
2243  true,
2244  ACL_UPDATE);
2245  nsitem = pstate->p_target_nsitem;
2246 
2247  /* subqueries in FROM cannot access the result relation */
2248  nsitem->p_lateral_only = true;
2249  nsitem->p_lateral_ok = false;
2250 
2251  /*
2252  * the FROM clause is non-standard SQL syntax. We used to be able to do
2253  * this with REPLACE in POSTQUEL so we keep the feature.
2254  */
2255  transformFromClause(pstate, stmt->fromClause);
2256 
2257  /* remaining clauses can reference the result relation normally */
2258  nsitem->p_lateral_only = false;
2259  nsitem->p_lateral_ok = true;
2260 
2261  qual = transformWhereClause(pstate, stmt->whereClause,
2262  EXPR_KIND_WHERE, "WHERE");
2263 
2264  qry->returningList = transformReturningList(pstate, stmt->returningList);
2265 
2266  /*
2267  * Now we are done with SELECT-like processing, and can get on with
2268  * transforming the target list to match the UPDATE target columns.
2269  */
2270  qry->targetList = transformUpdateTargetList(pstate, stmt->targetList);
2271 
2272  qry->rtable = pstate->p_rtable;
2273  qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2274 
2275  qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
2276  qry->hasSubLinks = pstate->p_hasSubLinks;
2277 
2278  assign_query_collations(pstate, qry);
2279 
2280  return qry;
2281 }
List * fromClause
Definition: parsenodes.h:1566
bool p_hasSubLinks
Definition: parse_node.h:209
static List * transformUpdateTargetList(ParseState *pstate, List *targetList)
Definition: analyze.c:2288
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
FromExpr * jointree
Definition: parsenodes.h:138
int resultRelation
Definition: parsenodes.h:122
bool p_hasTargetSRFs
Definition: parse_node.h:208
Definition: nodes.h:528
List * targetList
Definition: parsenodes.h:1564
static List * transformReturningList(ParseState *pstate, List *returningList)
Definition: analyze.c:2360
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:191
Node * whereClause
Definition: parsenodes.h:1565
List * targetList
Definition: parsenodes.h:140
bool hasRecursive
Definition: parsenodes.h:130
List * rtable
Definition: parsenodes.h:137
bool recursive
Definition: parsenodes.h:1404
List * returningList
Definition: parsenodes.h:146
bool p_hasModifyingCTE
Definition: parse_node.h:210
bool inh
Definition: primnodes.h:69
#define ACL_UPDATE
Definition: parsenodes.h:76
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:114
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:178
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define makeNode(_type_)
Definition: nodes.h:576
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
RangeVar * relation
Definition: parsenodes.h:1563
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:105
List * returningList
Definition: parsenodes.h:1567
List * cteList
Definition: parsenodes.h:135
bool hasSubLinks
Definition: parsenodes.h:128
void assign_query_collations(ParseState *pstate, Query *query)
bool p_is_insert
Definition: parse_node.h:192
List * p_joinlist
Definition: parse_node.h:182
bool hasModifyingCTE
Definition: parsenodes.h:131
WithClause * withClause
Definition: parsenodes.h:1568
List * p_rtable
Definition: parse_node.h:180

◆ transformUpdateTargetList()

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

Definition at line 2288 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().

2289 {
2290  List *tlist = NIL;
2291  RangeTblEntry *target_rte;
2292  ListCell *orig_tl;
2293  ListCell *tl;
2294 
2295  tlist = transformTargetList(pstate, origTlist,
2297 
2298  /* Prepare to assign non-conflicting resnos to resjunk attributes */
2301 
2302  /* Prepare non-junk columns for assignment to target table */
2303  target_rte = pstate->p_target_nsitem->p_rte;
2304  orig_tl = list_head(origTlist);
2305 
2306  foreach(tl, tlist)
2307  {
2308  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2309  ResTarget *origTarget;
2310  int attrno;
2311 
2312  if (tle->resjunk)
2313  {
2314  /*
2315  * Resjunk nodes need no additional processing, but be sure they
2316  * have resnos that do not match any target columns; else rewriter
2317  * or planner might get confused. They don't need a resname
2318  * either.
2319  */
2320  tle->resno = (AttrNumber) pstate->p_next_resno++;
2321  tle->resname = NULL;
2322  continue;
2323  }
2324  if (orig_tl == NULL)
2325  elog(ERROR, "UPDATE target count mismatch --- internal error");
2326  origTarget = lfirst_node(ResTarget, orig_tl);
2327 
2328  attrno = attnameAttNum(pstate->p_target_relation,
2329  origTarget->name, true);
2330  if (attrno == InvalidAttrNumber)
2331  ereport(ERROR,
2332  (errcode(ERRCODE_UNDEFINED_COLUMN),
2333  errmsg("column \"%s\" of relation \"%s\" does not exist",
2334  origTarget->name,
2336  parser_errposition(pstate, origTarget->location)));
2337 
2338  updateTargetListEntry(pstate, tle, origTarget->name,
2339  attrno,
2340  origTarget->indirection,
2341  origTarget->location);
2342 
2343  /* Mark the target column as requiring update permissions */
2344  target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
2346 
2347  orig_tl = lnext(origTlist, orig_tl);
2348  }
2349  if (orig_tl != NULL)
2350  elog(ERROR, "UPDATE target count mismatch --- internal error");
2351 
2352  return tlist;
2353 }
List * indirection
Definition: parsenodes.h:442
#define NIL
Definition: pg_list.h:65
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
char * name
Definition: parsenodes.h:441
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:463
int errcode(int sqlerrcode)
Definition: elog.c:704
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:191
char * resname
Definition: primnodes.h:1433
int location
Definition: parsenodes.h:444
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
Definition: parse_target.c:123
RangeTblEntry * p_rte
Definition: parse_node.h:257
bool resjunk
Definition: primnodes.h:1438
#define ERROR
Definition: elog.h:45
#define lfirst_node(type, lc)
Definition: pg_list.h:172
AttrNumber resno
Definition: primnodes.h:1432
int p_next_resno
Definition: parse_node.h:195
#define RelationGetRelationName(relation)
Definition: rel.h:491
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
#define ereport(elevel,...)
Definition: elog.h:155
Bitmapset * updatedCols
Definition: parsenodes.h:1128
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
#define lfirst(lc)
Definition: pg_list.h:169
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
int errmsg(const char *fmt,...)
Definition: elog.c:915
Relation p_target_relation
Definition: parse_node.h:190
#define elog(elevel,...)
Definition: elog.h:228
Definition: pg_list.h:50
void updateTargetListEntry(ParseState *pstate, TargetEntry *tle, char *colname, int attrno, List *indirection, int location)
Definition: parse_target.c:607
int16 AttrNumber
Definition: attnum.h:21

◆ transformValuesClause()

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

Definition at line 1341 of file analyze.c.

References addNSItemToQuery(), addRangeTableEntryForValues(), Assert, assign_query_collations(), CMD_SELECT, coerce_to_common_type(), Query::commandType, contain_vars_of_level(), Query::cteList, SelectStmt::distinctClause, ereport, errcode(), errmsg(), ERROR, expandNSItemAttrs(), EXPR_KIND_LIMIT, EXPR_KIND_OFFSET, EXPR_KIND_ORDER_BY, EXPR_KIND_VALUES, exprLocation(), forboth, SelectStmt::fromClause, SelectStmt::groupClause, Query::hasModifyingCTE, Query::hasRecursive, Query::hasSubLinks, SelectStmt::havingClause, i, SelectStmt::intoClause, Query::jointree, lappend(), lappend_int(), lappend_oid(), LCS_asString(), lfirst, Query::limitCount, SelectStmt::limitCount, Query::limitOffset, SelectStmt::limitOffset, Query::limitOption, SelectStmt::limitOption, linitial, list_free(), list_length(), list_make1, SelectStmt::lockingClause, makeFromExpr(), makeNode, NIL, SelectStmt::op, ParseState::p_hasModifyingCTE, ParseState::p_hasSubLinks, ParseState::p_joinlist, ParseState::p_next_resno, ParseState::p_rtable, palloc0(), parser_errposition(), WithClause::recursive, Query::rtable, select_common_collation(), select_common_type(), select_common_typmod(), SETOP_NONE, Query::sortClause, SelectStmt::sortClause, Query::targetList, SelectStmt::targetList, transformExpressionList(), transformLimitClause(), transformSortClause(), transformWithClause(), SelectStmt::valuesLists, SelectStmt::whereClause, SelectStmt::windowClause, and SelectStmt::withClause.

Referenced by transformStmt().

1342 {
1343  Query *qry = makeNode(Query);
1344  List *exprsLists;
1345  List *coltypes = NIL;
1346  List *coltypmods = NIL;
1347  List *colcollations = NIL;
1348  List **colexprs = NULL;
1349  int sublist_length = -1;
1350  bool lateral = false;
1351  ParseNamespaceItem *nsitem;
1352  ListCell *lc;
1353  ListCell *lc2;
1354  int i;
1355 
1356  qry->commandType = CMD_SELECT;
1357 
1358  /* Most SELECT stuff doesn't apply in a VALUES clause */
1359  Assert(stmt->distinctClause == NIL);
1360  Assert(stmt->intoClause == NULL);
1361  Assert(stmt->targetList == NIL);
1362  Assert(stmt->fromClause == NIL);
1363  Assert(stmt->whereClause == NULL);
1364  Assert(stmt->groupClause == NIL);
1365  Assert(stmt->havingClause == NULL);
1366  Assert(stmt->windowClause == NIL);
1367  Assert(stmt->op == SETOP_NONE);
1368 
1369  /* process the WITH clause independently of all else */
1370  if (stmt->withClause)
1371  {
1372  qry->hasRecursive = stmt->withClause->recursive;
1373  qry->cteList = transformWithClause(pstate, stmt->withClause);
1374  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
1375  }
1376 
1377  /*
1378  * For each row of VALUES, transform the raw expressions.
1379  *
1380  * Note that the intermediate representation we build is column-organized
1381  * not row-organized. That simplifies the type and collation processing
1382  * below.
1383  */
1384  foreach(lc, stmt->valuesLists)
1385  {
1386  List *sublist = (List *) lfirst(lc);
1387 
1388  /*
1389  * Do basic expression transformation (same as a ROW() expr, but here
1390  * we disallow SetToDefault)
1391  */
1392  sublist = transformExpressionList(pstate, sublist,
1393  EXPR_KIND_VALUES, false);
1394 
1395  /*
1396  * All the sublists must be the same length, *after* transformation
1397  * (which might expand '*' into multiple items). The VALUES RTE can't
1398  * handle anything different.
1399  */
1400  if (sublist_length < 0)
1401  {
1402  /* Remember post-transformation length of first sublist */
1403  sublist_length = list_length(sublist);
1404  /* and allocate array for per-column lists */
1405  colexprs = (List **) palloc0(sublist_length * sizeof(List *));
1406  }
1407  else if (sublist_length != list_length(sublist))
1408  {
1409  ereport(ERROR,
1410  (errcode(ERRCODE_SYNTAX_ERROR),
1411  errmsg("VALUES lists must all be the same length"),
1412  parser_errposition(pstate,
1413  exprLocation((Node *) sublist))));
1414  }
1415 
1416  /* Build per-column expression lists */
1417  i = 0;
1418  foreach(lc2, sublist)
1419  {
1420  Node *col = (Node *) lfirst(lc2);
1421 
1422  colexprs[i] = lappend(colexprs[i], col);
1423  i++;
1424  }
1425 
1426  /* Release sub-list's cells to save memory */
1427  list_free(sublist);
1428  }
1429 
1430  /*
1431  * Now resolve the common types of the columns, and coerce everything to
1432  * those types. Then identify the common typmod and common collation, if
1433  * any, of each column.
1434  *
1435  * We must do collation processing now because (1) assign_query_collations
1436  * doesn't process rangetable entries, and (2) we need to label the VALUES
1437  * RTE with column collations for use in the outer query. We don't
1438  * consider conflict of implicit collations to be an error here; instead
1439  * the column will just show InvalidOid as its collation, and you'll get a
1440  * failure later if that results in failure to resolve a collation.
1441  *
1442  * Note we modify the per-column expression lists in-place.
1443  */
1444  for (i = 0; i < sublist_length; i++)
1445  {
1446  Oid coltype;
1447  int32 coltypmod;
1448  Oid colcoll;
1449 
1450  coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
1451 
1452  foreach(lc, colexprs[i])
1453  {
1454  Node *col = (Node *) lfirst(lc);
1455 
1456  col = coerce_to_common_type(pstate, col, coltype, "VALUES");
1457  lfirst(lc) = (void *) col;
1458  }
1459 
1460  coltypmod = select_common_typmod(pstate, colexprs[i], coltype);
1461  colcoll = select_common_collation(pstate, colexprs[i], true);
1462 
1463  coltypes = lappend_oid(coltypes, coltype);
1464  coltypmods = lappend_int(coltypmods, coltypmod);
1465  colcollations = lappend_oid(colcollations, colcoll);
1466  }
1467 
1468  /*
1469  * Finally, rearrange the coerced expressions into row-organized lists.
1470  */
1471  exprsLists = NIL;
1472  foreach(lc, colexprs[0])
1473  {
1474  Node *col = (Node *) lfirst(lc);
1475  List *sublist;
1476 
1477  sublist = list_make1(col);
1478  exprsLists = lappend(exprsLists, sublist);
1479  }
1480  list_free(colexprs[0]);
1481  for (i = 1; i < sublist_length; i++)
1482  {
1483  forboth(lc, colexprs[i], lc2, exprsLists)
1484  {
1485  Node *col = (Node *) lfirst(lc);
1486  List *sublist = lfirst(lc2);
1487 
1488  sublist = lappend(sublist, col);
1489  }
1490  list_free(colexprs[i]);
1491  }
1492 
1493  /*
1494  * Ordinarily there can't be any current-level Vars in the expression
1495  * lists, because the namespace was empty ... but if we're inside CREATE
1496  * RULE, then NEW/OLD references might appear. In that case we have to
1497  * mark the VALUES RTE as LATERAL.
1498  */
1499  if (pstate->p_rtable != NIL &&
1500  contain_vars_of_level((Node *) exprsLists, 0))
1501  lateral = true;
1502 
1503  /*
1504  * Generate the VALUES RTE
1505  */
1506  nsitem = addRangeTableEntryForValues(pstate, exprsLists,
1507  coltypes, coltypmods, colcollations,
1508  NULL, lateral, true);
1509  addNSItemToQuery(pstate, nsitem, true, true, true);
1510 
1511  /*
1512  * Generate a targetlist as though expanding "*"
1513  */
1514  Assert(pstate->p_next_resno == 1);
1515  qry->targetList = expandNSItemAttrs(pstate, nsitem, 0, -1);
1516 
1517  /*
1518  * The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
1519  * VALUES, so cope.
1520  */
1521  qry->sortClause = transformSortClause(pstate,
1522  stmt->sortClause,
1523  &qry->targetList,
1525  false /* allow SQL92 rules */ );
1526 
1527  qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
1528  EXPR_KIND_OFFSET, "OFFSET",
1529  stmt->limitOption);
1530  qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
1531  EXPR_KIND_LIMIT, "LIMIT",
1532  stmt->limitOption);
1533  qry->limitOption = stmt->limitOption;
1534 
1535  if (stmt->lockingClause)
1536  ereport(ERROR,
1537  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1538  /*------
1539  translator: %s is a SQL row locking clause such as FOR UPDATE */
1540  errmsg("%s cannot be applied to VALUES",
1542  linitial(stmt->lockingClause))->strength))));
1543 
1544  qry->rtable = pstate->p_rtable;
1545  qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
1546 
1547  qry->hasSubLinks = pstate->p_hasSubLinks;
1548 
1549  assign_query_collations(pstate, qry);
1550 
1551  return qry;
1552 }
Node * limitOffset
Definition: parsenodes.h:160