summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorAndres Freund2017-03-14 22:45:36 +0000
committerAndres Freund2017-03-25 21:52:06 +0000
commitb8d7f053c5c2bf2a7e8734fe3327f6a8bc711755 (patch)
tree6fd5db4d05a3dec9bed6b8cc4c98ca9d3f80425e /src/include
parent7d3957e53ebf26fc8d72dee1dacc2c827cc07caa (diff)
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with non-recursive, opcode dispatch based, expression evaluation. Projection is now implemented as part of expression evaluation. This both leads to significant performance improvements, and makes future just-in-time compilation of expressions easier. The speed gains primarily come from: - non-recursive implementation reduces stack usage / overhead - simple sub-expressions are implemented with a single jump, without function calls - sharing some state between different sub-expressions - reduced amount of indirect/hard to predict memory accesses by laying out operation metadata sequentially; including the avoidance of nearly all of the previously used linked lists - more code has been moved to expression initialization, avoiding constant re-checks at evaluation time Future just-in-time compilation (JIT) has become easier, as demonstrated by released patches intended to be merged in a later release, for primarily two reasons: Firstly, due to a stricter split between expression initialization and evaluation, less code has to be handled by the JIT. Secondly, due to the non-recursive nature of the generated "instructions", less performance-critical code-paths can easily be shared between interpreted and compiled evaluation. The new framework allows for significant future optimizations. E.g.: - basic infrastructure for to later reduce the per executor-startup overhead of expression evaluation, by caching state in prepared statements. That'd be helpful in OLTPish scenarios where initialization overhead is measurable. - optimizing the generated "code". A number of proposals for potential work has already been made. - optimizing the interpreter. Similarly a number of proposals have been made here too. The move of logic into the expression initialization step leads to some backward-incompatible changes: - Function permission checks are now done during expression initialization, whereas previously they were done during execution. In edge cases this can lead to errors being raised that previously wouldn't have been, e.g. a NULL array being coerced to a different array type previously didn't perform checks. - The set of domain constraints to be checked, is now evaluated once during expression initialization, previously it was re-built every time a domain check was evaluated. For normal queries this doesn't change much, but e.g. for plpgsql functions, which caches ExprStates, the old set could stick around longer. The behavior around might still change. Author: Andres Freund, with significant changes by Tom Lane, changes by Heikki Linnakangas Reviewed-By: Tom Lane, Heikki Linnakangas Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
Diffstat (limited to 'src/include')
-rw-r--r--src/include/executor/execExpr.h642
-rw-r--r--src/include/executor/execdebug.h23
-rw-r--r--src/include/executor/executor.h178
-rw-r--r--src/include/executor/nodeSubplan.h4
-rw-r--r--src/include/fmgr.h8
-rw-r--r--src/include/nodes/execnodes.h504
-rw-r--r--src/include/nodes/nodes.h30
-rw-r--r--src/include/utils/typcache.h3
-rw-r--r--src/include/utils/xml.h4
9 files changed, 946 insertions, 450 deletions
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
new file mode 100644
index 00000000000..a6653882321
--- /dev/null
+++ b/src/include/executor/execExpr.h
@@ -0,0 +1,642 @@
+/*-------------------------------------------------------------------------
+ *
+ * execExpr.h
+ * Low level infrastructure related to expression evaluation
+ *
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/executor/execExpr.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef EXEC_EXPR_H
+#define EXEC_EXPR_H
+
+#include "nodes/execnodes.h"
+
+/* forward reference to avoid circularity */
+struct ArrayRefState;
+
+/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
+/* expression's interpreter has been initialized */
+#define EEO_FLAG_INTERPRETER_INITIALIZED (1 << 1)
+/* jump-threading is in use */
+#define EEO_FLAG_DIRECT_THREADED (1 << 2)
+
+/*
+ * Discriminator for ExprEvalSteps.
+ *
+ * Identifies the operation to be executed and which member in the
+ * ExprEvalStep->d union is valid.
+ *
+ * The order of entries needs to be kept in sync with the dispatch_table[]
+ * array in execExprInterp.c:ExecInterpExpr().
+ */
+typedef enum ExprEvalOp
+{
+ /* entire expression has been evaluated completely, return */
+ EEOP_DONE,
+
+ /* apply slot_getsomeattrs on corresponding tuple slot */
+ EEOP_INNER_FETCHSOME,
+ EEOP_OUTER_FETCHSOME,
+ EEOP_SCAN_FETCHSOME,
+
+ /* compute non-system Var value */
+ /* "FIRST" variants are used only the first time through */
+ EEOP_INNER_VAR_FIRST,
+ EEOP_INNER_VAR,
+ EEOP_OUTER_VAR_FIRST,
+ EEOP_OUTER_VAR,
+ EEOP_SCAN_VAR_FIRST,
+ EEOP_SCAN_VAR,
+
+ /* compute system Var value */
+ EEOP_INNER_SYSVAR,
+ EEOP_OUTER_SYSVAR,
+ EEOP_SCAN_SYSVAR,
+
+ /* compute wholerow Var */
+ EEOP_WHOLEROW,
+
+ /* compute non-system Var value, assign it into ExprState's resultslot */
+ /* (these are not used if _FIRST checks would be needed) */
+ EEOP_ASSIGN_INNER_VAR,
+ EEOP_ASSIGN_OUTER_VAR,
+ EEOP_ASSIGN_SCAN_VAR,
+
+ /* assign ExprState's resvalue/resnull to a column of its resultslot */
+ EEOP_ASSIGN_TMP,
+ /* ditto, applying MakeExpandedObjectReadOnly() */
+ EEOP_ASSIGN_TMP_MAKE_RO,
+
+ /* evaluate Const value */
+ EEOP_CONST,
+
+ /*
+ * Evaluate function call (including OpExprs etc). For speed, we
+ * distinguish in the opcode whether the function is strict and/or
+ * requires usage stats tracking.
+ */
+ EEOP_FUNCEXPR,
+ EEOP_FUNCEXPR_STRICT,
+ EEOP_FUNCEXPR_FUSAGE,
+ EEOP_FUNCEXPR_STRICT_FUSAGE,
+
+ /*
+ * Evaluate boolean AND expression, one step per subexpression. FIRST/LAST
+ * subexpressions are special-cased for performance. Since AND always has
+ * at least two subexpressions, FIRST and LAST never apply to the same
+ * subexpression.
+ */
+ EEOP_BOOL_AND_STEP_FIRST,
+ EEOP_BOOL_AND_STEP,
+ EEOP_BOOL_AND_STEP_LAST,
+
+ /* similarly for boolean OR expression */
+ EEOP_BOOL_OR_STEP_FIRST,
+ EEOP_BOOL_OR_STEP,
+ EEOP_BOOL_OR_STEP_LAST,
+
+ /* evaluate boolean NOT expression */
+ EEOP_BOOL_NOT_STEP,
+
+ /* simplified version of BOOL_AND_STEP for use by ExecQual() */
+ EEOP_QUAL,
+
+ /* unconditional jump to another step */
+ EEOP_JUMP,
+
+ /* conditional jumps based on current result value */
+ EEOP_JUMP_IF_NULL,
+ EEOP_JUMP_IF_NOT_NULL,
+ EEOP_JUMP_IF_NOT_TRUE,
+
+ /* perform NULL tests for scalar values */
+ EEOP_NULLTEST_ISNULL,
+ EEOP_NULLTEST_ISNOTNULL,
+
+ /* perform NULL tests for row values */
+ EEOP_NULLTEST_ROWISNULL,
+ EEOP_NULLTEST_ROWISNOTNULL,
+
+ /* evaluate a BooleanTest expression */
+ EEOP_BOOLTEST_IS_TRUE,
+ EEOP_BOOLTEST_IS_NOT_TRUE,
+ EEOP_BOOLTEST_IS_FALSE,
+ EEOP_BOOLTEST_IS_NOT_FALSE,
+
+ /* evaluate PARAM_EXEC/EXTERN parameters */
+ EEOP_PARAM_EXEC,
+ EEOP_PARAM_EXTERN,
+
+ /* return CaseTestExpr value */
+ EEOP_CASE_TESTVAL,
+
+ /* apply MakeExpandedObjectReadOnly() to target value */
+ EEOP_MAKE_READONLY,
+
+ /* evaluate assorted special-purpose expression types */
+ EEOP_IOCOERCE,
+ EEOP_DISTINCT,
+ EEOP_NULLIF,
+ EEOP_SQLVALUEFUNCTION,
+ EEOP_CURRENTOFEXPR,
+ EEOP_ARRAYEXPR,
+ EEOP_ARRAYCOERCE,
+ EEOP_ROW,
+
+ /*
+ * Compare two individual elements of each of two compared ROW()
+ * expressions. Skip to ROWCOMPARE_FINAL if elements are not equal.
+ */
+ EEOP_ROWCOMPARE_STEP,
+
+ /* evaluate boolean value based on previous ROWCOMPARE_STEP operations */
+ EEOP_ROWCOMPARE_FINAL,
+
+ /* evaluate GREATEST() or LEAST() */
+ EEOP_MINMAX,
+
+ /* evaluate FieldSelect expression */
+ EEOP_FIELDSELECT,
+
+ /*
+ * Deform tuple before evaluating new values for individual fields in a
+ * FieldStore expression.
+ */
+ EEOP_FIELDSTORE_DEFORM,
+
+ /*
+ * Form the new tuple for a FieldStore expression. Individual fields will
+ * have been evaluated into columns of the tuple deformed by the preceding
+ * DEFORM step.
+ */
+ EEOP_FIELDSTORE_FORM,
+
+ /* Process an array subscript; short-circuit expression to NULL if NULL */
+ EEOP_ARRAYREF_SUBSCRIPT,
+
+ /*
+ * Compute old array element/slice when an ArrayRef assignment expression
+ * contains ArrayRef/FieldStore subexpressions. Value is accessed using
+ * the CaseTest mechanism.
+ */
+ EEOP_ARRAYREF_OLD,
+
+ /* compute new value for ArrayRef assignment expression */
+ EEOP_ARRAYREF_ASSIGN,
+
+ /* compute element/slice for ArrayRef fetch expression */
+ EEOP_ARRAYREF_FETCH,
+
+ /* evaluate value for CoerceToDomainValue */
+ EEOP_DOMAIN_TESTVAL,
+
+ /* evaluate a domain's NOT NULL constraint */
+ EEOP_DOMAIN_NOTNULL,
+
+ /* evaluate a single domain CHECK constraint */
+ EEOP_DOMAIN_CHECK,
+
+ /* evaluate assorted special-purpose expression types */
+ EEOP_CONVERT_ROWTYPE,
+ EEOP_SCALARARRAYOP,
+ EEOP_XMLEXPR,
+ EEOP_AGGREF,
+ EEOP_GROUPING_FUNC,
+ EEOP_WINDOW_FUNC,
+ EEOP_SUBPLAN,
+ EEOP_ALTERNATIVE_SUBPLAN,
+
+ /* non-existent operation, used e.g. to check array lengths */
+ EEOP_LAST
+} ExprEvalOp;
+
+
+typedef struct ExprEvalStep
+{
+ /*
+ * Instruction to be executed. During instruction preparation this is an
+ * enum ExprEvalOp, but later it can be changed to some other type, e.g. a
+ * pointer for computed goto (that's why it's an intptr_t).
+ */
+ intptr_t opcode;
+
+ /* where to store the result of this step */
+ Datum *resvalue;
+ bool *resnull;
+
+ /*
+ * Inline data for the operation. Inline data is faster to access, but
+ * also bloats the size of all instructions. The union should be kept to
+ * no more than 40 bytes on 64-bit systems (so that the entire struct is
+ * no more than 64 bytes, a single cacheline on common systems).
+ */
+ union
+ {
+ /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */
+ struct
+ {
+ /* attribute number up to which to fetch (inclusive) */
+ int last_var;
+ } fetch;
+
+ /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */
+ struct
+ {
+ /* attnum is attr number - 1 for regular VAR ... */
+ /* but it's just the normal (negative) attr number for SYSVAR */
+ int attnum;
+ Oid vartype; /* type OID of variable */
+ } var;
+
+ /* for EEOP_WHOLEROW */
+ struct
+ {
+ Var *var; /* original Var node in plan tree */
+ bool first; /* first time through, need to initialize? */
+ bool slow; /* need runtime check for nulls? */
+ TupleDesc tupdesc; /* descriptor for resulting tuples */
+ JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */
+ } wholerow;
+
+ /* for EEOP_ASSIGN_*_VAR */
+ struct
+ {
+ /* target index in ExprState->resultslot->tts_values/nulls */
+ int resultnum;
+ /* source attribute number - 1 */
+ int attnum;
+ } assign_var;
+
+ /* for EEOP_ASSIGN_TMP[_MAKE_RO] */
+ struct
+ {
+ /* target index in ExprState->resultslot->tts_values/nulls */
+ int resultnum;
+ } assign_tmp;
+
+ /* for EEOP_CONST */
+ struct
+ {
+ /* constant's value */
+ Datum value;
+ bool isnull;
+ } constval;
+
+ /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */
+ struct
+ {
+ FmgrInfo *finfo; /* function's lookup data */
+ FunctionCallInfo fcinfo_data; /* arguments etc */
+ /* faster to access without additional indirection: */
+ PGFunction fn_addr; /* actual call address */
+ int nargs; /* number of arguments */
+ } func;
+
+ /* for EEOP_BOOL_*_STEP */
+ struct
+ {
+ bool *anynull; /* track if any input was NULL */
+ int jumpdone; /* jump here if result determined */
+ } boolexpr;
+
+ /* for EEOP_QUAL */
+ struct
+ {
+ int jumpdone; /* jump here on false or null */
+ } qualexpr;
+
+ /* for EEOP_JUMP[_CONDITION] */
+ struct
+ {
+ int jumpdone; /* target instruction's index */
+ } jump;
+
+ /* for EEOP_NULLTEST_ROWIS[NOT]NULL */
+ struct
+ {
+ /* cached tupdesc pointer - filled at runtime */
+ TupleDesc argdesc;
+ } nulltest_row;
+
+ /* for EEOP_PARAM_EXEC/EXTERN */
+ struct
+ {
+ int paramid; /* numeric ID for parameter */
+ Oid paramtype; /* OID of parameter's datatype */
+ } param;
+
+ /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */
+ struct
+ {
+ Datum *value; /* value to return */
+ bool *isnull;
+ } casetest;
+
+ /* for EEOP_MAKE_READONLY */
+ struct
+ {
+ Datum *value; /* value to coerce to read-only */
+ bool *isnull;
+ } make_readonly;
+
+ /* for EEOP_IOCOERCE */
+ struct
+ {
+ /* lookup and call info for source type's output function */
+ FmgrInfo *finfo_out;
+ FunctionCallInfo fcinfo_data_out;
+ /* lookup and call info for result type's input function */
+ FmgrInfo *finfo_in;
+ FunctionCallInfo fcinfo_data_in;
+ } iocoerce;
+
+ /* for EEOP_SQLVALUEFUNCTION */
+ struct
+ {
+ SQLValueFunction *svf;
+ } sqlvaluefunction;
+
+ /* for EEOP_ARRAYEXPR */
+ struct
+ {
+ Datum *elemvalues; /* element values get stored here */
+ bool *elemnulls;
+ int nelems; /* length of the above arrays */
+ Oid elemtype; /* array element type */
+ int16 elemlength; /* typlen of the array element type */
+ bool elembyval; /* is the element type pass-by-value? */
+ char elemalign; /* typalign of the element type */
+ bool multidims; /* is array expression multi-D? */
+ } arrayexpr;
+
+ /* for EEOP_ARRAYCOERCE */
+ struct
+ {
+ ArrayCoerceExpr *coerceexpr;
+ Oid resultelemtype; /* element type of result array */
+ FmgrInfo *elemfunc; /* lookup info for element coercion
+ * function */
+ struct ArrayMapState *amstate; /* workspace for array_map */
+ } arraycoerce;
+
+ /* for EEOP_ROW */
+ struct
+ {
+ TupleDesc tupdesc; /* descriptor for result tuples */
+ /* workspace for the values constituting the row: */
+ Datum *elemvalues;
+ bool *elemnulls;
+ } row;
+
+ /* for EEOP_ROWCOMPARE_STEP */
+ struct
+ {
+ /* lookup and call data for column comparison function */
+ FmgrInfo *finfo;
+ FunctionCallInfo fcinfo_data;
+ PGFunction fn_addr;
+ /* target for comparison resulting in NULL */
+ int jumpnull;
+ /* target for comparison yielding inequality */
+ int jumpdone;
+ } rowcompare_step;
+
+ /* for EEOP_ROWCOMPARE_FINAL */
+ struct
+ {
+ RowCompareType rctype;
+ } rowcompare_final;
+
+ /* for EEOP_MINMAX */
+ struct
+ {
+ /* workspace for argument values */
+ Datum *values;
+ bool *nulls;
+ int nelems;
+ /* is it GREATEST or LEAST? */
+ MinMaxOp op;
+ /* lookup and call data for comparison function */
+ FmgrInfo *finfo;
+ FunctionCallInfo fcinfo_data;
+ } minmax;
+
+ /* for EEOP_FIELDSELECT */
+ struct
+ {
+ AttrNumber fieldnum; /* field number to extract */
+ Oid resulttype; /* field's type */
+ /* cached tupdesc pointer - filled at runtime */
+ TupleDesc argdesc;
+ } fieldselect;
+
+ /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */
+ struct
+ {
+ /* original expression node */
+ FieldStore *fstore;
+
+ /* cached tupdesc pointer - filled at runtime */
+ /* note that a DEFORM and FORM pair share the same tupdesc */
+ TupleDesc *argdesc;
+
+ /* workspace for column values */
+ Datum *values;
+ bool *nulls;
+ int ncolumns;
+ } fieldstore;
+
+ /* for EEOP_ARRAYREF_SUBSCRIPT */
+ struct
+ {
+ /* too big to have inline */
+ struct ArrayRefState *state;
+ int off; /* 0-based index of this subscript */
+ bool isupper; /* is it upper or lower subscript? */
+ int jumpdone; /* jump here on null */
+ } arrayref_subscript;
+
+ /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */
+ struct
+ {
+ /* too big to have inline */
+ struct ArrayRefState *state;
+ } arrayref;
+
+ /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */
+ struct
+ {
+ /* name of constraint */
+ char *constraintname;
+ /* where the result of a CHECK constraint will be stored */
+ Datum *checkvalue;
+ bool *checknull;
+ /* OID of domain type */
+ Oid resulttype;
+ } domaincheck;
+
+ /* for EEOP_CONVERT_ROWTYPE */
+ struct
+ {
+ ConvertRowtypeExpr *convert; /* original expression */
+ /* these three fields are filled at runtime: */
+ TupleDesc indesc; /* tupdesc for input type */
+ TupleDesc outdesc; /* tupdesc for output type */
+ TupleConversionMap *map; /* column mapping */
+ bool initialized; /* initialized for current types? */
+ } convert_rowtype;
+
+ /* for EEOP_SCALARARRAYOP */
+ struct
+ {
+ /* element_type/typlen/typbyval/typalign are filled at runtime */
+ Oid element_type; /* InvalidOid if not yet filled */
+ bool useOr; /* use OR or AND semantics? */
+ int16 typlen; /* array element type storage info */
+ bool typbyval;
+ char typalign;
+ FmgrInfo *finfo; /* function's lookup data */
+ FunctionCallInfo fcinfo_data; /* arguments etc */
+ /* faster to access without additional indirection: */
+ PGFunction fn_addr; /* actual call address */
+ } scalararrayop;
+
+ /* for EEOP_XMLEXPR */
+ struct
+ {
+ XmlExpr *xexpr; /* original expression node */
+ /* workspace for evaluating named args, if any */
+ Datum *named_argvalue;
+ bool *named_argnull;
+ /* workspace for evaluating unnamed args, if any */
+ Datum *argvalue;
+ bool *argnull;
+ } xmlexpr;
+
+ /* for EEOP_AGGREF */
+ struct
+ {
+ /* out-of-line state, modified by nodeAgg.c */
+ AggrefExprState *astate;
+ } aggref;
+
+ /* for EEOP_GROUPING_FUNC */
+ struct
+ {
+ AggState *parent; /* parent Agg */
+ List *clauses; /* integer list of column numbers */
+ } grouping_func;
+
+ /* for EEOP_WINDOW_FUNC */
+ struct
+ {
+ /* out-of-line state, modified by nodeWindowFunc.c */
+ WindowFuncExprState *wfstate;
+ } window_func;
+
+ /* for EEOP_SUBPLAN */
+ struct
+ {
+ /* out-of-line state, created by nodeSubplan.c */
+ SubPlanState *sstate;
+ } subplan;
+
+ /* for EEOP_ALTERNATIVE_SUBPLAN */
+ struct
+ {
+ /* out-of-line state, created by nodeSubplan.c */
+ AlternativeSubPlanState *asstate;
+ } alternative_subplan;
+ } d;
+} ExprEvalStep;
+
+
+/* Non-inline data for array operations */
+typedef struct ArrayRefState
+{
+ bool isassignment; /* is it assignment, or just fetch? */
+
+ Oid refelemtype; /* OID of the array element type */
+ int16 refattrlength; /* typlen of array type */
+ int16 refelemlength; /* typlen of the array element type */
+ bool refelembyval; /* is the element type pass-by-value? */
+ char refelemalign; /* typalign of the element type */
+
+ /* numupper and upperprovided[] are filled at compile time */
+ /* at runtime, extracted subscript datums get stored in upperindex[] */
+ int numupper;
+ bool upperprovided[MAXDIM];
+ int upperindex[MAXDIM];
+
+ /* similarly for lower indexes, if any */
+ int numlower;
+ bool lowerprovided[MAXDIM];
+ int lowerindex[MAXDIM];
+
+ /* subscript expressions get evaluated into here */
+ Datum subscriptvalue;
+ bool subscriptnull;
+
+ /* for assignment, new value to assign is evaluated into here */
+ Datum replacevalue;
+ bool replacenull;
+
+ /* if we have a nested assignment, ARRAYREF_OLD puts old value here */
+ Datum prevvalue;
+ bool prevnull;
+} ArrayRefState;
+
+
+extern void ExecReadyInterpretedExpr(ExprState *state);
+
+extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op);
+
+/*
+ * Non fast-path execution functions. These are externs instead of statics in
+ * execExprInterp.c, because that allows them to be used by other methods of
+ * expression evaluation, reducing code duplication.
+ */
+extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+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 ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalRow(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalMinMax(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern bool ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
+
+#endif /* EXEC_EXPR_H */
diff --git a/src/include/executor/execdebug.h b/src/include/executor/execdebug.h
index cf44c3edbbc..8b61520e189 100644
--- a/src/include/executor/execdebug.h
+++ b/src/include/executor/execdebug.h
@@ -38,13 +38,6 @@
*/
/* ----------------
- * EXEC_EVALDEBUG is a flag which turns on debugging of
- * ExecEval and ExecTargetList() stuff by EV_printf() in execQual.c
- * ----------------
-#undef EXEC_EVALDEBUG
- */
-
-/* ----------------
* EXEC_SORTDEBUG is a flag which turns on debugging of
* the ExecSort() stuff by SO_printf() in nodeSort.c
* ----------------
@@ -86,20 +79,6 @@
#endif /* EXEC_NESTLOOPDEBUG */
/* ----------------
- * exec eval / target list debugging defines
- * ----------------
- */
-#ifdef EXEC_EVALDEBUG
-#define EV_nodeDisplay(l) nodeDisplay(l)
-#define EV_printf(s) printf(s)
-#define EV1_printf(s, a) printf(s, a)
-#else
-#define EV_nodeDisplay(l)
-#define EV_printf(s)
-#define EV1_printf(s, a)
-#endif /* EXEC_EVALDEBUG */
-
-/* ----------------
* sort node debugging defines
* ----------------
*/
@@ -146,4 +125,4 @@
#define MJ_DEBUG_PROC_NODE(slot)
#endif /* EXEC_MERGEJOINDEBUG */
-#endif /* ExecDebugIncluded */
+#endif /* EXECDEBUG_H */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index a5c75e771f0..d3849b93eb1 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -65,15 +65,6 @@
#define EXEC_FLAG_WITH_NO_DATA 0x0080 /* rel scannability doesn't matter */
-/*
- * ExecEvalExpr was formerly a function containing a switch statement;
- * now it's just a macro invoking the function pointed to by an ExprState
- * node. Beware of double evaluation of the ExprState argument!
- */
-#define ExecEvalExpr(expr, econtext, isNull) \
- ((*(expr)->evalfunc) (expr, econtext, isNull))
-
-
/* Hook for plugins to get control in ExecutorStart() */
typedef void (*ExecutorStart_hook_type) (QueryDesc *queryDesc, int eflags);
extern PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook;
@@ -242,29 +233,155 @@ extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
/*
- * prototypes from functions in execQual.c
+ * prototypes from functions in execExpr.c
*/
-extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno,
- bool *isNull);
-extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname,
- bool *isNull);
-extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,
+extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
+extern ExprState *ExecInitQual(List *qual, PlanState *parent);
+extern ExprState *ExecInitCheck(List *qual, PlanState *parent);
+extern List *ExecInitExprList(List *nodes, PlanState *parent);
+extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList,
+ ExprContext *econtext,
+ TupleTableSlot *slot,
+ PlanState *parent,
+ TupleDesc inputDesc);
+extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
+extern ExprState *ExecPrepareQual(List *qual, EState *estate);
+extern ExprState *ExecPrepareCheck(List *qual, EState *estate);
+extern List *ExecPrepareExprList(List *nodes, EState *estate);
+
+/*
+ * ExecEvalExpr
+ *
+ * Evaluate expression identified by "state" in the execution context
+ * given by "econtext". *isNull is set to the is-null flag for the result,
+ * and the Datum value is the function result.
+ *
+ * The caller should already have switched into the temporary memory
+ * context econtext->ecxt_per_tuple_memory. The convenience entry point
+ * ExecEvalExprSwitchContext() is provided for callers who don't prefer to
+ * do the switch in an outer loop.
+ */
+#ifndef FRONTEND
+static inline Datum
+ExecEvalExpr(ExprState *state,
+ ExprContext *econtext,
+ bool *isNull)
+{
+ return (*state->evalfunc) (state, econtext, isNull);
+}
+#endif
+
+/*
+ * ExecEvalExprSwitchContext
+ *
+ * Same as ExecEvalExpr, but get into the right allocation context explicitly.
+ */
+#ifndef FRONTEND
+static inline Datum
+ExecEvalExprSwitchContext(ExprState *state,
+ ExprContext *econtext,
+ bool *isNull)
+{
+ Datum retDatum;
+ MemoryContext oldContext;
+
+ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+ retDatum = (*state->evalfunc) (state, econtext, isNull);
+ MemoryContextSwitchTo(oldContext);
+ return retDatum;
+}
+#endif
+
+/*
+ * ExecProject
+ *
+ * Projects a tuple based on projection info and stores it in the slot passed
+ * to ExecBuildProjectInfo().
+ *
+ * Note: the result is always a virtual tuple; therefore it may reference
+ * the contents of the exprContext's scan tuples and/or temporary results
+ * constructed in the exprContext. If the caller wishes the result to be
+ * valid longer than that data will be valid, he must call ExecMaterializeSlot
+ * on the result slot.
+ */
+#ifndef FRONTEND
+static inline TupleTableSlot *
+ExecProject(ProjectionInfo *projInfo)
+{
+ ExprContext *econtext = projInfo->pi_exprContext;
+ ExprState *state = &projInfo->pi_state;
+ TupleTableSlot *slot = state->resultslot;
+ bool isnull;
+
+ /*
+ * Clear any former contents of the result slot. This makes it safe for
+ * us to use the slot's Datum/isnull arrays as workspace.
+ */
+ ExecClearTuple(slot);
+
+ /* Run the expression, discarding scalar result from the last column. */
+ (void) ExecEvalExprSwitchContext(state, econtext, &isnull);
+
+ /*
+ * Successfully formed a result row. Mark the result slot as containing a
+ * valid virtual tuple (inlined version of ExecStoreVirtualTuple()).
+ */
+ slot->tts_isempty = false;
+ slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
+
+ return slot;
+}
+#endif
+
+/*
+ * ExecQual - evaluate a qual prepared with ExecInitQual (possibly via
+ * ExecPrepareQual). Returns true if qual is satisfied, else false.
+ *
+ * Note: ExecQual used to have a third argument "resultForNull". The
+ * behavior of this function now corresponds to resultForNull == false.
+ * If you want the resultForNull == true behavior, see ExecCheck.
+ */
+#ifndef FRONTEND
+static inline bool
+ExecQual(ExprState *state, ExprContext *econtext)
+{
+ Datum ret;
+ bool isnull;
+
+ /* short-circuit (here and in ExecInitQual) for empty restriction list */
+ if (state == NULL)
+ return true;
+
+ /* verify that expression was compiled using ExecInitQual */
+ Assert(state->flags & EEO_FLAG_IS_QUAL);
+
+ ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
+
+ /* EEOP_QUAL should never return NULL */
+ Assert(!isnull);
+
+ return DatumGetBool(ret);
+}
+#endif
+
+extern bool ExecCheck(ExprState *state, ExprContext *context);
+
+/*
+ * prototypes from functions in execSRF.c
+ */
+extern SetExprState *ExecInitTableFunctionResult(Expr *expr,
+ ExprContext *econtext, PlanState *parent);
+extern Tuplestorestate *ExecMakeTableFunctionResult(SetExprState *setexpr,
ExprContext *econtext,
MemoryContext argContext,
TupleDesc expectedDesc,
bool randomAccess);
-extern Datum ExecMakeFunctionResultSet(FuncExprState *fcache,
+extern SetExprState *ExecInitFunctionResultSet(Expr *expr,
+ ExprContext *econtext, PlanState *parent);
+extern Datum ExecMakeFunctionResultSet(SetExprState *fcache,
ExprContext *econtext,
bool *isNull,
ExprDoneCond *isDone);
-extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
- bool *isNull);
-extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
-extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
-extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
-extern int ExecTargetListLength(List *targetlist);
-extern int ExecCleanTargetListLength(List *targetlist);
-extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo);
/*
* prototypes from functions in execScan.c
@@ -355,10 +472,6 @@ extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
extern void ExecAssignResultType(PlanState *planstate, TupleDesc tupDesc);
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
extern TupleDesc ExecGetResultType(PlanState *planstate);
-extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList,
- ExprContext *econtext,
- TupleTableSlot *slot,
- TupleDesc inputDesc);
extern void ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc);
extern void ExecFreeExprContext(PlanState *planstate);
@@ -376,8 +489,17 @@ extern void RegisterExprContextCallback(ExprContext *econtext,
extern void UnregisterExprContextCallback(ExprContext *econtext,
ExprContextCallbackFunction function,
Datum arg);
+
extern void ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate);
+extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname,
+ bool *isNull);
+extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno,
+ bool *isNull);
+
+extern int ExecTargetListLength(List *targetlist);
+extern int ExecCleanTargetListLength(List *targetlist);
+
/*
* prototypes from functions in execIndexing.c
*/
diff --git a/src/include/executor/nodeSubplan.h b/src/include/executor/nodeSubplan.h
index 0f821dc8f67..0d3f52118b2 100644
--- a/src/include/executor/nodeSubplan.h
+++ b/src/include/executor/nodeSubplan.h
@@ -20,6 +20,10 @@ extern SubPlanState *ExecInitSubPlan(SubPlan *subplan, PlanState *parent);
extern AlternativeSubPlanState *ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent);
+extern Datum ExecSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull);
+
+extern Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node, ExprContext *econtext, bool *isNull);
+
extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
extern void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext);
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 0a155acee62..6128752ab19 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -49,6 +49,9 @@ typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
* arguments, rather than about the function itself. But it's convenient
* to store it here rather than in FunctionCallInfoData, where it might more
* logically belong.
+ *
+ * fn_extra is available for use by the called function; all other fields
+ * should be treated as read-only after the struct is created.
*/
typedef struct FmgrInfo
{
@@ -65,6 +68,11 @@ typedef struct FmgrInfo
/*
* This struct is the data actually passed to an fmgr-called function.
+ *
+ * The called function is expected to set isnull, and possibly resultinfo or
+ * fields in whatever resultinfo points to. It should not change any other
+ * fields. (In particular, scribbling on the argument arrays is a bad idea,
+ * since some callers assume they can re-call with the same arguments.)
*/
typedef struct FunctionCallInfoData
{
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f856f6036f6..ff428951186 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -31,6 +31,72 @@
/* ----------------
+ * ExprState node
+ *
+ * ExprState is the top-level node for expression evaluation.
+ * It contains instructions (in ->steps) to evaluate the expression.
+ * ----------------
+ */
+struct ExprState; /* forward references in this file */
+struct ExprContext;
+struct ExprEvalStep; /* avoid including execExpr.h everywhere */
+
+typedef Datum (*ExprStateEvalFunc) (struct ExprState *expression,
+ struct ExprContext *econtext,
+ bool *isNull);
+
+/* Bits in ExprState->flags (see also execExpr.h for private flag bits): */
+/* expression is for use with ExecQual() */
+#define EEO_FLAG_IS_QUAL (1 << 0)
+
+typedef struct ExprState
+{
+ Node tag;
+
+ uint8 flags; /* bitmask of EEO_FLAG_* bits, see above */
+
+ /*
+ * Storage for result value of a scalar expression, or for individual
+ * column results within expressions built by ExecBuildProjectionInfo().
+ */
+ bool resnull;
+ Datum resvalue;
+
+ /*
+ * If projecting a tuple result, this slot holds the result; else NULL.
+ */
+ TupleTableSlot *resultslot;
+
+ /*
+ * Instructions to compute expression's return value.
+ */
+ struct ExprEvalStep *steps;
+
+ /*
+ * Function that actually evaluates the expression. This can be set to
+ * different values depending on the complexity of the expression.
+ */
+ ExprStateEvalFunc evalfunc;
+
+ /* original expression tree, for debugging only */
+ Expr *expr;
+
+ /*
+ * XXX: following only needed during "compilation", could be thrown away.
+ */
+
+ int steps_len; /* number of steps currently */
+ int steps_alloc; /* allocated length of steps array */
+
+ Datum *innermost_caseval;
+ bool *innermost_casenull;
+
+ Datum *innermost_domainval;
+ bool *innermost_domainnull;
+} ExprState;
+
+
+/* ----------------
* IndexInfo information
*
* this struct holds the information needed to construct new index
@@ -69,7 +135,7 @@ typedef struct IndexInfo
List *ii_Expressions; /* list of Expr */
List *ii_ExpressionsState; /* list of ExprState */
List *ii_Predicate; /* list of Expr */
- List *ii_PredicateState; /* list of ExprState */
+ ExprState *ii_PredicateState;
Oid *ii_ExclusionOps; /* array with one entry per column */
Oid *ii_ExclusionProcs; /* array with one entry per column */
uint16 *ii_ExclusionStrats; /* array with one entry per column */
@@ -214,51 +280,21 @@ typedef struct ReturnSetInfo
* that is, form new tuples by evaluation of targetlist expressions.
* Nodes which need to do projections create one of these.
*
+ * The target tuple slot is kept in ProjectionInfo->pi_state.resultslot.
* ExecProject() evaluates the tlist, forms a tuple, and stores it
* in the given slot. Note that the result will be a "virtual" tuple
* unless ExecMaterializeSlot() is then called to force it to be
* converted to a physical tuple. The slot must have a tupledesc
* that matches the output of the tlist!
- *
- * The planner very often produces tlists that consist entirely of
- * simple Var references (lower levels of a plan tree almost always
- * look like that). And top-level tlists are often mostly Vars too.
- * We therefore optimize execution of simple-Var tlist entries.
- * The pi_targetlist list actually contains only the tlist entries that
- * aren't simple Vars, while those that are Vars are processed using the
- * varSlotOffsets/varNumbers/varOutputCols arrays.
- *
- * The lastXXXVar fields are used to optimize fetching of fields from
- * input tuples: they let us do a slot_getsomeattrs() call to ensure
- * that all needed attributes are extracted in one pass.
- *
- * targetlist target list for projection (non-Var expressions only)
- * exprContext expression context in which to evaluate targetlist
- * slot slot to place projection result in
- * directMap true if varOutputCols[] is an identity map
- * numSimpleVars number of simple Vars found in original tlist
- * varSlotOffsets array indicating which slot each simple Var is from
- * varNumbers array containing input attr numbers of simple Vars
- * varOutputCols array containing output attr numbers of simple Vars
- * lastInnerVar highest attnum from inner tuple slot (0 if none)
- * lastOuterVar highest attnum from outer tuple slot (0 if none)
- * lastScanVar highest attnum from scan tuple slot (0 if none)
* ----------------
*/
typedef struct ProjectionInfo
{
NodeTag type;
- List *pi_targetlist;
+ /* instructions to evaluate projection */
+ ExprState pi_state;
+ /* expression context in which to evaluate expression */
ExprContext *pi_exprContext;
- TupleTableSlot *pi_slot;
- bool pi_directMap;
- int pi_numSimpleVars;
- int *pi_varSlotOffsets;
- int *pi_varNumbers;
- int *pi_varOutputCols;
- int pi_lastInnerVar;
- int pi_lastOuterVar;
- int pi_lastScanVar;
} ProjectionInfo;
/* ----------------
@@ -340,20 +376,20 @@ typedef struct ResultRelInfo
IndexInfo **ri_IndexRelationInfo;
TriggerDesc *ri_TrigDesc;
FmgrInfo *ri_TrigFunctions;
- List **ri_TrigWhenExprs;
+ ExprState **ri_TrigWhenExprs;
Instrumentation *ri_TrigInstrument;
struct FdwRoutine *ri_FdwRoutine;
void *ri_FdwState;
bool ri_usesFdwDirectModify;
List *ri_WithCheckOptions;
List *ri_WithCheckOptionExprs;
- List **ri_ConstraintExprs;
+ ExprState **ri_ConstraintExprs;
JunkFilter *ri_junkFilter;
ProjectionInfo *ri_projectReturning;
ProjectionInfo *ri_onConflictSetProj;
- List *ri_onConflictSetWhere;
+ ExprState *ri_onConflictSetWhere;
List *ri_PartitionCheck;
- List *ri_PartitionCheckExpr;
+ ExprState *ri_PartitionCheckExpr;
Relation ri_PartitionRoot;
} ResultRelInfo;
@@ -564,139 +600,63 @@ typedef tuplehash_iterator TupleHashIterator;
/* ----------------------------------------------------------------
- * Expression State Trees
- *
- * Each executable expression tree has a parallel ExprState tree.
- *
- * Unlike PlanState, there is not an exact one-for-one correspondence between
- * ExprState node types and Expr node types. Many Expr node types have no
- * need for node-type-specific run-time state, and so they can use plain
- * ExprState or GenericExprState as their associated ExprState node type.
+ * Expression State Nodes
+ *
+ * Formerly, there was a separate executor expression state node corresponding
+ * to each node in a planned expression tree. That's no longer the case; for
+ * common expression node types, all the execution info is embedded into
+ * step(s) in a single ExprState node. But we still have a few executor state
+ * node types for selected expression node types, mostly those in which info
+ * has to be shared with other parts of the execution state tree.
* ----------------------------------------------------------------
*/
/* ----------------
- * ExprState node
- *
- * ExprState is the common superclass for all ExprState-type nodes.
- *
- * It can also be instantiated directly for leaf Expr nodes that need no
- * local run-time state (such as Var, Const, or Param).
- *
- * To save on dispatch overhead, each ExprState node contains a function
- * pointer to the routine to execute to evaluate the node.
- * ----------------
- */
-
-typedef struct ExprState ExprState;
-
-typedef Datum (*ExprStateEvalFunc) (ExprState *expression,
- ExprContext *econtext,
- bool *isNull);
-
-struct ExprState
-{
- NodeTag type;
- Expr *expr; /* associated Expr node */
- ExprStateEvalFunc evalfunc; /* routine to run to execute node */
-};
-
-/* ----------------
- * GenericExprState node
- *
- * This is used for Expr node types that need no local run-time state,
- * but have one child Expr node.
- * ----------------
- */
-typedef struct GenericExprState
-{
- ExprState xprstate;
- ExprState *arg; /* state of my child node */
-} GenericExprState;
-
-/* ----------------
- * WholeRowVarExprState node
- * ----------------
- */
-typedef struct WholeRowVarExprState
-{
- ExprState xprstate;
- struct PlanState *parent; /* parent PlanState, or NULL if none */
- TupleDesc wrv_tupdesc; /* descriptor for resulting tuples */
- JunkFilter *wrv_junkFilter; /* JunkFilter to remove resjunk cols */
-} WholeRowVarExprState;
-
-/* ----------------
* AggrefExprState node
* ----------------
*/
typedef struct AggrefExprState
{
- ExprState xprstate;
+ NodeTag type;
+ Aggref *aggref; /* expression plan node */
int aggno; /* ID number for agg within its plan node */
} AggrefExprState;
/* ----------------
- * GroupingFuncExprState node
- *
- * The list of column numbers refers to the input tuples of the Agg node to
- * which the GroupingFunc belongs, and may contain 0 for references to columns
- * that are only present in grouping sets processed by different Agg nodes (and
- * which are therefore always considered "grouping" here).
- * ----------------
- */
-typedef struct GroupingFuncExprState
-{
- ExprState xprstate;
- struct AggState *aggstate;
- List *clauses; /* integer list of column numbers */
-} GroupingFuncExprState;
-
-/* ----------------
* WindowFuncExprState node
* ----------------
*/
typedef struct WindowFuncExprState
{
- ExprState xprstate;
- List *args; /* states of argument expressions */
+ NodeTag type;
+ WindowFunc *wfunc; /* expression plan node */
+ List *args; /* ExprStates for argument expressions */
ExprState *aggfilter; /* FILTER expression */
int wfuncno; /* ID number for wfunc within its plan node */
} WindowFuncExprState;
-/* ----------------
- * ArrayRefExprState node
- *
- * Note: array types can be fixed-length (typlen > 0), but only when the
- * element type is itself fixed-length. Otherwise they are varlena structures
- * and have typlen = -1. In any case, an array type is never pass-by-value.
- * ----------------
- */
-typedef struct ArrayRefExprState
-{
- ExprState xprstate;
- List *refupperindexpr; /* states for child nodes */
- List *reflowerindexpr;
- ExprState *refexpr;
- ExprState *refassgnexpr;
- int16 refattrlength; /* typlen of array type */
- int16 refelemlength; /* typlen of the array element type */
- bool refelembyval; /* is the element type pass-by-value? */
- char refelemalign; /* typalign of the element type */
-} ArrayRefExprState;
/* ----------------
- * FuncExprState node
+ * SetExprState node
*
- * Although named for FuncExpr, this is also used for OpExpr, DistinctExpr,
- * and NullIf nodes; be careful to check what xprstate.expr is actually
- * pointing at!
+ * State for evaluating a potentially set-returning expression (like FuncExpr
+ * or OpExpr). In some cases, like some of the expressions in ROWS FROM(...)
+ * the expression might not be a SRF, but nonetheless it uses the same
+ * machinery as SRFs; it will be treated as a SRF returning a single row.
* ----------------
*/
-typedef struct FuncExprState
+typedef struct SetExprState
{
- ExprState xprstate;
- List *args; /* states of argument expressions */
+ NodeTag type;
+ Expr *expr; /* expression plan node */
+ List *args; /* ExprStates for argument expressions */
+
+ /*
+ * In ROWS FROM, functions can be inlined, removing the FuncExpr normally
+ * inside. In such a case this is the compiled expression (which cannot
+ * return a set), which'll be evaluated using regular ExecEvalExpr().
+ */
+ ExprState *elidedFuncState;
/*
* Function manager's lookup info for the target function. If func.fn_oid
@@ -738,7 +698,7 @@ typedef struct FuncExprState
/*
* Flag to remember whether we have registered a shutdown callback for
- * this FuncExprState. We do so only if funcResultStore or setArgsValid
+ * this SetExprState. We do so only if funcResultStore or setArgsValid
* has been set at least once (since all the callback is for is to release
* the tuplestore or clear setArgsValid).
*/
@@ -750,33 +710,7 @@ typedef struct FuncExprState
* argument values between calls, when setArgsValid is true.
*/
FunctionCallInfoData fcinfo_data;
-} FuncExprState;
-
-/* ----------------
- * ScalarArrayOpExprState node
- *
- * This is a FuncExprState plus some additional data.
- * ----------------
- */
-typedef struct ScalarArrayOpExprState
-{
- FuncExprState fxprstate;
- /* Cached info about array element type */
- Oid element_type;
- int16 typlen;
- bool typbyval;
- char typalign;
-} ScalarArrayOpExprState;
-
-/* ----------------
- * BoolExprState node
- * ----------------
- */
-typedef struct BoolExprState
-{
- ExprState xprstate;
- List *args; /* states of argument expression(s) */
-} BoolExprState;
+} SetExprState;
/* ----------------
* SubPlanState node
@@ -784,7 +718,8 @@ typedef struct BoolExprState
*/
typedef struct SubPlanState
{
- ExprState xprstate;
+ NodeTag type;
+ SubPlan *subplan; /* expression plan node */
struct PlanState *planstate; /* subselect plan's state tree */
struct PlanState *parent; /* parent plan node's state tree */
ExprState *testexpr; /* state of combining expression */
@@ -814,203 +749,18 @@ typedef struct SubPlanState
*/
typedef struct AlternativeSubPlanState
{
- ExprState xprstate;
- List *subplans; /* states of alternative subplans */
+ NodeTag type;
+ AlternativeSubPlan *subplan; /* expression plan node */
+ List *subplans; /* SubPlanStates of alternative subplans */
int active; /* list index of the one we're using */
} AlternativeSubPlanState;
-/* ----------------
- * FieldSelectState node
- * ----------------
- */
-typedef struct FieldSelectState
-{
- ExprState xprstate;
- ExprState *arg; /* input expression */
- TupleDesc argdesc; /* tupdesc for most recent input */
-} FieldSelectState;
-
-/* ----------------
- * FieldStoreState node
- * ----------------
- */
-typedef struct FieldStoreState
-{
- ExprState xprstate;
- ExprState *arg; /* input tuple value */
- List *newvals; /* new value(s) for field(s) */
- TupleDesc argdesc; /* tupdesc for most recent input */
-} FieldStoreState;
-
-/* ----------------
- * CoerceViaIOState node
- * ----------------
- */
-typedef struct CoerceViaIOState
-{
- ExprState xprstate;
- ExprState *arg; /* input expression */
- FmgrInfo outfunc; /* lookup info for source output function */
- FmgrInfo infunc; /* lookup info for result input function */
- Oid intypioparam; /* argument needed for input function */
-} CoerceViaIOState;
-
-/* ----------------
- * ArrayCoerceExprState node
- * ----------------
- */
-typedef struct ArrayCoerceExprState
-{
- ExprState xprstate;
- ExprState *arg; /* input array value */
- Oid resultelemtype; /* element type of result array */
- FmgrInfo elemfunc; /* lookup info for element coercion function */
- /* use struct pointer to avoid including array.h here */
- struct ArrayMapState *amstate; /* workspace for array_map */
-} ArrayCoerceExprState;
-
-/* ----------------
- * ConvertRowtypeExprState node
- * ----------------
- */
-typedef struct ConvertRowtypeExprState
-{
- ExprState xprstate;
- ExprState *arg; /* input tuple value */
- TupleDesc indesc; /* tupdesc for source rowtype */
- TupleDesc outdesc; /* tupdesc for result rowtype */
- /* use "struct" so we needn't include tupconvert.h here */
- struct TupleConversionMap *map;
- bool initialized;
-} ConvertRowtypeExprState;
-
-/* ----------------
- * CaseExprState node
- * ----------------
- */
-typedef struct CaseExprState
-{
- ExprState xprstate;
- ExprState *arg; /* implicit equality comparison argument */
- List *args; /* the arguments (list of WHEN clauses) */
- ExprState *defresult; /* the default result (ELSE clause) */
- int16 argtyplen; /* if arg is provided, its typlen */
-} CaseExprState;
-
-/* ----------------
- * CaseWhenState node
- * ----------------
- */
-typedef struct CaseWhenState
-{
- ExprState xprstate;
- ExprState *expr; /* condition expression */
- ExprState *result; /* substitution result */
-} CaseWhenState;
-
-/* ----------------
- * ArrayExprState node
- *
- * Note: ARRAY[] expressions always produce varlena arrays, never fixed-length
- * arrays.
- * ----------------
- */
-typedef struct ArrayExprState
-{
- ExprState xprstate;
- List *elements; /* states for child nodes */
- int16 elemlength; /* typlen of the array element type */
- bool elembyval; /* is the element type pass-by-value? */
- char elemalign; /* typalign of the element type */
-} ArrayExprState;
-
-/* ----------------
- * RowExprState node
- * ----------------
- */
-typedef struct RowExprState
-{
- ExprState xprstate;
- List *args; /* the arguments */
- TupleDesc tupdesc; /* descriptor for result tuples */
-} RowExprState;
-
-/* ----------------
- * RowCompareExprState node
- * ----------------
- */
-typedef struct RowCompareExprState
-{
- ExprState xprstate;
- List *largs; /* the left-hand input arguments */
- List *rargs; /* the right-hand input arguments */
- FmgrInfo *funcs; /* array of comparison function info */
- Oid *collations; /* array of collations to use */
-} RowCompareExprState;
-
-/* ----------------
- * CoalesceExprState node
- * ----------------
- */
-typedef struct CoalesceExprState
-{
- ExprState xprstate;
- List *args; /* the arguments */
-} CoalesceExprState;
-
-/* ----------------
- * MinMaxExprState node
- * ----------------
- */
-typedef struct MinMaxExprState
-{
- ExprState xprstate;
- List *args; /* the arguments */
- FmgrInfo cfunc; /* lookup info for comparison func */
-} MinMaxExprState;
-
-/* ----------------
- * XmlExprState node
- * ----------------
- */
-typedef struct XmlExprState
-{
- ExprState xprstate;
- List *named_args; /* ExprStates for named arguments */
- List *args; /* ExprStates for other arguments */
-} XmlExprState;
-
-/* ----------------
- * NullTestState node
- * ----------------
- */
-typedef struct NullTestState
-{
- ExprState xprstate;
- ExprState *arg; /* input expression */
- /* used only if input is of composite type: */
- TupleDesc argdesc; /* tupdesc for most recent input */
-} NullTestState;
-
-/* ----------------
- * CoerceToDomainState node
- * ----------------
- */
-typedef struct CoerceToDomainState
-{
- ExprState xprstate;
- ExprState *arg; /* input expression */
- /* Cached set of constraints that need to be checked */
- /* use struct pointer to avoid including typcache.h here */
- struct DomainConstraintRef *constraint_ref;
-} CoerceToDomainState;
-
/*
* DomainConstraintState - one item to check during CoerceToDomain
*
- * Note: this is just a Node, and not an ExprState, because it has no
- * corresponding Expr to link to. Nonetheless it is part of an ExprState
- * tree, so we give it a name following the xxxState convention.
+ * Note: we consider this to be part of an ExprState tree, so we give it
+ * a name following the xxxState convention. But there's no directly
+ * associated plan-tree node.
*/
typedef enum DomainConstraintType
{
@@ -1023,7 +773,8 @@ typedef struct DomainConstraintState
NodeTag type;
DomainConstraintType constrainttype; /* constraint type */
char *name; /* name of constraint (for error msgs) */
- ExprState *check_expr; /* for CHECK, a boolean expression */
+ Expr *check_expr; /* for CHECK, a boolean expression */
+ ExprState *check_exprstate; /* check_expr's eval state, or NULL */
} DomainConstraintState;
@@ -1060,8 +811,7 @@ typedef struct PlanState
* state trees parallel links in the associated plan tree (except for the
* subPlan list, which does not exist in the plan tree).
*/
- List *targetlist; /* target list to be computed at this node */
- List *qual; /* implicitly-ANDed qual conditions */
+ ExprState *qual; /* boolean qual condition */
struct PlanState *lefttree; /* input plan tree(s) */
struct PlanState *righttree;
List *initPlan; /* Init SubPlanState nodes (un-correlated expr
@@ -1133,11 +883,15 @@ typedef struct ResultState
/* ----------------
* ProjectSetState information
+ *
+ * Note: at least one of the "elems" will be a SetExprState; the rest are
+ * regular ExprStates.
* ----------------
*/
typedef struct ProjectSetState
{
PlanState ps; /* its first field is NodeTag */
+ Node **elems; /* array of expression states */
ExprDoneCond *elemdone; /* array of per-SRF is-done states */
int nelems; /* length of elemdone[] array */
bool pending_srf_tuples; /* still evaluating srfs in tlist? */
@@ -1372,7 +1126,7 @@ typedef struct
typedef struct IndexScanState
{
ScanState ss; /* its first field is NodeTag */
- List *indexqualorig;
+ ExprState *indexqualorig;
List *indexorderbyorig;
ScanKey iss_ScanKeys;
int iss_NumScanKeys;
@@ -1418,7 +1172,7 @@ typedef struct IndexScanState
typedef struct IndexOnlyScanState
{
ScanState ss; /* its first field is NodeTag */
- List *indexqual;
+ ExprState *indexqual;
ScanKey ioss_ScanKeys;
int ioss_NumScanKeys;
ScanKey ioss_OrderByKeys;
@@ -1534,7 +1288,7 @@ typedef struct ParallelBitmapHeapState
typedef struct BitmapHeapScanState
{
ScanState ss; /* its first field is NodeTag */
- List *bitmapqualorig;
+ ExprState *bitmapqualorig;
TIDBitmap *tbm;
TBMIterator *tbmiterator;
TBMIterateResult *tbmres;
@@ -1554,16 +1308,18 @@ typedef struct BitmapHeapScanState
/* ----------------
* TidScanState information
*
+ * tidexprs list of TidExpr structs (see nodeTidscan.c)
* isCurrentOf scan has a CurrentOfExpr qual
* NumTids number of tids in this scan
* TidPtr index of currently fetched tid
* TidList evaluated item pointers (array of size NumTids)
+ * htup currently-fetched tuple, if any
* ----------------
*/
typedef struct TidScanState
{
ScanState ss; /* its first field is NodeTag */
- List *tss_tidquals; /* list of ExprState nodes */
+ List *tss_tidexprs;
bool tss_isCurrentOf;
int tss_NumTids;
int tss_TidPtr;
@@ -1712,7 +1468,7 @@ typedef struct WorkTableScanState
typedef struct ForeignScanState
{
ScanState ss; /* its first field is NodeTag */
- List *fdw_recheck_quals; /* original quals not in ss.ps.qual */
+ ExprState *fdw_recheck_quals; /* original quals not in ss.ps.qual */
Size pscan_len; /* size of parallel coordination information */
/* use struct pointer to avoid including fdwapi.h here */
struct FdwRoutine *fdwroutine;
@@ -1759,7 +1515,7 @@ typedef struct JoinState
{
PlanState ps;
JoinType jointype;
- List *joinqual; /* JOIN quals (in addition to ps.qual) */
+ ExprState *joinqual; /* JOIN quals (in addition to ps.qual) */
} JoinState;
/* ----------------
@@ -1857,7 +1613,7 @@ typedef struct HashJoinTableData *HashJoinTable;
typedef struct HashJoinState
{
JoinState js; /* its first field is NodeTag */
- List *hashclauses; /* list of ExprState nodes */
+ ExprState *hashclauses;
List *hj_OuterHashKeys; /* list of ExprState nodes */
List *hj_InnerHashKeys; /* list of ExprState nodes */
List *hj_HashOperators; /* list of operator OIDs */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index fc883a6f3ec..c83216943c1 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -192,36 +192,18 @@ typedef enum NodeTag
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
*
- * These correspond (not always one-for-one) to primitive nodes derived
- * from Expr.
+ * ExprState represents the evaluation state for a whole expression tree.
+ * Most Expr-based plan nodes do not have a corresponding expression state
+ * node, they're fully handled within execExpr* - but sometimes the state
+ * needs to be shared with other parts of the executor, as for example
+ * with AggrefExprState, which nodeAgg.c has to modify.
*/
T_ExprState,
- T_GenericExprState,
- T_WholeRowVarExprState,
T_AggrefExprState,
- T_GroupingFuncExprState,
T_WindowFuncExprState,
- T_ArrayRefExprState,
- T_FuncExprState,
- T_ScalarArrayOpExprState,
- T_BoolExprState,
+ T_SetExprState,
T_SubPlanState,
T_AlternativeSubPlanState,
- T_FieldSelectState,
- T_FieldStoreState,
- T_CoerceViaIOState,
- T_ArrayCoerceExprState,
- T_ConvertRowtypeExprState,
- T_CaseExprState,
- T_CaseWhenState,
- T_ArrayExprState,
- T_RowExprState,
- T_RowCompareExprState,
- T_CoalesceExprState,
- T_MinMaxExprState,
- T_XmlExprState,
- T_NullTestState,
- T_CoerceToDomainState,
T_DomainConstraintState,
/*
diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h
index 90a1f6347a4..1bf94e2548d 100644
--- a/src/include/utils/typcache.h
+++ b/src/include/utils/typcache.h
@@ -132,6 +132,7 @@ typedef struct DomainConstraintRef
List *constraints; /* list of DomainConstraintState nodes */
MemoryContext refctx; /* context holding DomainConstraintRef */
TypeCacheEntry *tcache; /* typcache entry for domain type */
+ bool need_exprstate; /* does caller need check_exprstate? */
/* Management data --- treat these fields as private to typcache.c */
DomainConstraintCache *dcc; /* current constraints, or NULL if none */
@@ -142,7 +143,7 @@ typedef struct DomainConstraintRef
extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);
extern void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref,
- MemoryContext refctx);
+ MemoryContext refctx, bool need_exprstate);
extern void UpdateDomainConstraintRef(DomainConstraintRef *ref);
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index e570b71c04f..195b9b3a97a 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -61,7 +61,9 @@ extern void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode,
const char *msg);
extern xmltype *xmlconcat(List *args);
-extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
+extern xmltype *xmlelement(XmlExpr *xexpr,
+ Datum *named_argvalue, bool *named_argnull,
+ Datum *argvalue, bool *argnull);
extern xmltype *xmlparse(text *data, XmlOptionType xmloption, bool preserve_whitespace);
extern xmltype *xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null);
extern xmltype *xmlroot(xmltype *data, text *version, int standalone);