aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pg_stat_statements/pg_stat_statements.c8
-rw-r--r--src/backend/catalog/dependency.c14
-rw-r--r--src/backend/executor/execExprInterp.c46
-rw-r--r--src/backend/nodes/nodeFuncs.c16
-rw-r--r--src/backend/nodes/outfuncs.c12
-rw-r--r--src/backend/nodes/readfuncs.c16
-rw-r--r--src/backend/optimizer/path/costsize.c9
-rw-r--r--src/backend/optimizer/util/clauses.c23
-rw-r--r--src/backend/utils/adt/ruleutils.c17
-rw-r--r--src/include/executor/execExpr.h3
-rw-r--r--src/include/nodes/nodes.h2
-rw-r--r--src/include/nodes/primnodes.h28
12 files changed, 147 insertions, 47 deletions
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index b9d4a936905..fa409d72b7b 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2763,6 +2763,14 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
APP_JUMB(ce->cursor_param);
}
break;
+ case T_NextValueExpr:
+ {
+ NextValueExpr *nve = (NextValueExpr *) node;
+
+ APP_JUMB(nve->seqid);
+ APP_JUMB(nve->typeId);
+ }
+ break;
case T_InferenceElem:
{
InferenceElem *ie = (InferenceElem *) node;
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 1a7645d341f..6fffc290fad 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1791,6 +1791,13 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_TYPE, cd->resulttype, 0,
context->addrs);
}
+ else if (IsA(node, NextValueExpr))
+ {
+ NextValueExpr *nve = (NextValueExpr *) node;
+
+ add_object_address(OCLASS_CLASS, nve->seqid, 0,
+ context->addrs);
+ }
else if (IsA(node, OnConflictExpr))
{
OnConflictExpr *onconflict = (OnConflictExpr *) node;
@@ -1942,13 +1949,6 @@ find_expr_references_walker(Node *node,
context->addrs);
/* fall through to examine arguments */
}
- else if (IsA(node, NextValueExpr))
- {
- NextValueExpr *nve = (NextValueExpr *) node;
-
- add_object_address(OCLASS_CLASS, nve->seqid, 0,
- context->addrs);
- }
return expression_tree_walker(node, find_expr_references_walker,
(void *) context);
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index c227d9bdd99..f2a52f62135 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -1232,21 +1232,11 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_CASE(EEOP_NEXTVALUEEXPR)
{
- switch (op->d.nextvalueexpr.seqtypid)
- {
- case INT2OID:
- *op->resvalue = Int16GetDatum((int16) nextval_internal(op->d.nextvalueexpr.seqid, false));
- break;
- case INT4OID:
- *op->resvalue = Int32GetDatum((int32) nextval_internal(op->d.nextvalueexpr.seqid, false));
- break;
- case INT8OID:
- *op->resvalue = Int64GetDatum((int64) nextval_internal(op->d.nextvalueexpr.seqid, false));
- break;
- default:
- elog(ERROR, "unsupported sequence type %u", op->d.nextvalueexpr.seqtypid);
- }
- *op->resnull = false;
+ /*
+ * Doesn't seem worthwhile to have an inline implementation
+ * efficiency-wise.
+ */
+ ExecEvalNextValueExpr(state, op);
EEO_NEXT();
}
@@ -1990,6 +1980,32 @@ ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
}
/*
+ * Evaluate NextValueExpr.
+ */
+void
+ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
+{
+ int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
+
+ switch (op->d.nextvalueexpr.seqtypid)
+ {
+ case INT2OID:
+ *op->resvalue = Int16GetDatum((int16) newval);
+ break;
+ case INT4OID:
+ *op->resvalue = Int32GetDatum((int32) newval);
+ break;
+ case INT8OID:
+ *op->resvalue = Int64GetDatum((int64) newval);
+ break;
+ default:
+ elog(ERROR, "unsupported sequence type %u",
+ op->d.nextvalueexpr.seqtypid);
+ }
+ *op->resnull = false;
+}
+
+/*
* Evaluate NullTest / IS NULL for rows.
*/
void
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 97ba25fc72c..e3eb0c57887 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1642,10 +1642,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, and CoerceToDomain
- * nodes, because they do not contain SQL function OIDs. However, they can
- * invoke SQL-visible functions, so callers should take thought about how to
- * treat them.
+ * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
+ * and NextValueExpr nodes, because they do not contain SQL function OIDs.
+ * However, they can invoke SQL-visible functions, so callers should take
+ * thought about how to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1865,12 +1865,12 @@ expression_tree_walker(Node *node,
case T_Var:
case T_Const:
case T_Param:
- case T_CoerceToDomainValue:
case T_CaseTestExpr:
+ case T_SQLValueFunction:
+ case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
case T_NextValueExpr:
- case T_SQLValueFunction:
case T_RangeTblRef:
case T_SortGroupClause:
/* primitive node types with no expression subnodes */
@@ -2461,12 +2461,12 @@ expression_tree_mutator(Node *node,
}
break;
case T_Param:
- case T_CoerceToDomainValue:
case T_CaseTestExpr:
+ case T_SQLValueFunction:
+ case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
case T_NextValueExpr:
- case T_SQLValueFunction:
case T_RangeTblRef:
case T_SortGroupClause:
return (Node *) copyObject(node);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b0abe9ec10f..21e39a0b810 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1611,6 +1611,15 @@ _outCurrentOfExpr(StringInfo str, const CurrentOfExpr *node)
}
static void
+_outNextValueExpr(StringInfo str, const NextValueExpr *node)
+{
+ WRITE_NODE_TYPE("NEXTVALUEEXPR");
+
+ WRITE_OID_FIELD(seqid);
+ WRITE_OID_FIELD(typeId);
+}
+
+static void
_outInferenceElem(StringInfo str, const InferenceElem *node)
{
WRITE_NODE_TYPE("INFERENCEELEM");
@@ -3872,6 +3881,9 @@ outNode(StringInfo str, const void *obj)
case T_CurrentOfExpr:
_outCurrentOfExpr(str, obj);
break;
+ case T_NextValueExpr:
+ _outNextValueExpr(str, obj);
+ break;
case T_InferenceElem:
_outInferenceElem(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 1380703cbc6..8ab09d74d60 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1203,6 +1203,20 @@ _readCurrentOfExpr(void)
}
/*
+ * _readNextValueExpr
+ */
+static NextValueExpr *
+_readNextValueExpr(void)
+{
+ READ_LOCALS(NextValueExpr);
+
+ READ_OID_FIELD(seqid);
+ READ_OID_FIELD(typeId);
+
+ READ_DONE();
+}
+
+/*
* _readInferenceElem
*/
static InferenceElem *
@@ -2517,6 +2531,8 @@ parseNodeString(void)
return_value = _readSetToDefault();
else if (MATCH("CURRENTOFEXPR", 13))
return_value = _readCurrentOfExpr();
+ else if (MATCH("NEXTVALUEEXPR", 13))
+ return_value = _readNextValueExpr();
else if (MATCH("INFERENCEELEM", 13))
return_value = _readInferenceElem();
else if (MATCH("TARGETENTRY", 11))
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index eb653cf3bec..b35acb7bdcf 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3627,6 +3627,15 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
cpu_operator_cost;
}
}
+ else if (IsA(node, MinMaxExpr) ||
+ IsA(node, SQLValueFunction) ||
+ IsA(node, XmlExpr) ||
+ IsA(node, CoerceToDomain) ||
+ IsA(node, NextValueExpr))
+ {
+ /* Treat all these as having cost 1 */
+ context->total.per_tuple += cpu_operator_cost;
+ }
else if (IsA(node, CurrentOfExpr))
{
/* Report high cost to prevent selection of anything but TID scan */
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8961ed88a81..8b4425dcf90 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -902,6 +902,12 @@ contain_mutable_functions_walker(Node *node, void *context)
return true;
}
+ if (IsA(node, NextValueExpr))
+ {
+ /* NextValueExpr is volatile */
+ return true;
+ }
+
/*
* It should be safe to treat MinMaxExpr as immutable, because it will
* depend on a non-cross-type btree comparison function, and those should
@@ -969,6 +975,12 @@ contain_volatile_functions_walker(Node *node, void *context)
context))
return true;
+ if (IsA(node, NextValueExpr))
+ {
+ /* NextValueExpr is volatile */
+ return true;
+ }
+
/*
* See notes in contain_mutable_functions_walker about why we treat
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
@@ -1019,6 +1031,8 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
* See notes in contain_mutable_functions_walker about why we treat
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
* SQLValueFunction is stable. Hence, none of them are of interest here.
+ * Also, since we're intentionally ignoring nextval(), presumably we
+ * should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -1146,7 +1160,7 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
* parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases.
+ * should be safe in all cases. NextValueExpr is parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1154,6 +1168,12 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
return true;
}
+ if (IsA(node, NextValueExpr))
+ {
+ if (max_parallel_hazard_test(PROPARALLEL_UNSAFE, context))
+ return true;
+ }
+
/*
* As a notational convenience for callers, look through RestrictInfo.
*/
@@ -1495,6 +1515,7 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
+ case T_NextValueExpr:
case T_List:
/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5cfb916684f..d2fb20d5649 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7283,6 +7283,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_MinMaxExpr:
case T_SQLValueFunction:
case T_XmlExpr:
+ case T_NextValueExpr:
case T_NullIfExpr:
case T_Aggref:
case T_WindowFunc:
@@ -8612,6 +8613,22 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
+ case T_NextValueExpr:
+ {
+ NextValueExpr *nvexpr = (NextValueExpr *) node;
+
+ /*
+ * This isn't exactly nextval(), but that seems close enough
+ * for EXPLAIN's purposes.
+ */
+ appendStringInfoString(buf, "nextval(");
+ simple_quote_literal(buf,
+ generate_relation_name(nvexpr->seqid,
+ NIL));
+ appendStringInfoChar(buf, ')');
+ }
+ break;
+
case T_InferenceElem:
{
InferenceElem *iexpr = (InferenceElem *) node;
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 7a65339f01a..8ee0496e010 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -362,7 +362,7 @@ typedef struct ExprEvalStep
SQLValueFunction *svf;
} sqlvaluefunction;
- /* for EEOP_NEXTVALUEXPR */
+ /* for EEOP_NEXTVALUEEXPR */
struct
{
Oid seqid;
@@ -615,6 +615,7 @@ extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 01527399b80..27bd4f3363e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -183,6 +183,7 @@ typedef enum NodeTag
T_CoerceToDomainValue,
T_SetToDefault,
T_CurrentOfExpr,
+ T_NextValueExpr,
T_InferenceElem,
T_TargetEntry,
T_RangeTblRef,
@@ -190,7 +191,6 @@ typedef enum NodeTag
T_FromExpr,
T_OnConflictExpr,
T_IntoClause,
- T_NextValueExpr,
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 38015ed5405..8c536a8d38d 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1280,6 +1280,20 @@ typedef struct CurrentOfExpr
} CurrentOfExpr;
/*
+ * NextValueExpr - get next value from sequence
+ *
+ * This has the same effect as calling the nextval() function, but it does not
+ * check permissions on the sequence. This is used for identity columns,
+ * where the sequence is an implicit dependency without its own permissions.
+ */
+typedef struct NextValueExpr
+{
+ Expr xpr;
+ Oid seqid;
+ Oid typeId;
+} NextValueExpr;
+
+/*
* InferenceElem - an element of a unique index inference specification
*
* This mostly matches the structure of IndexElems, but having a dedicated
@@ -1294,20 +1308,6 @@ typedef struct InferenceElem
Oid inferopclass; /* OID of att opclass, or InvalidOid */
} InferenceElem;
-/*
- * NextValueExpr - get next value from sequence
- *
- * This has the same effect as calling the nextval() function, but it does not
- * check permissions on the sequence. This is used for identity columns,
- * where the sequence is an implicit dependency without its own permissions.
- */
-typedef struct NextValueExpr
-{
- Expr xpr;
- Oid seqid;
- Oid typeId;
-} NextValueExpr;
-
/*--------------------
* TargetEntry -
* a target entry (used in query target lists)