agora inbox for [email protected]
help / color / mirror / Atom feedFrom: Andres Freund <[email protected]>
Subject: [PATCH 03/20] WIP: Faster expression processing and targetlist projection.
Date: Tue, 12 Jul 2016 21:06:28 -0700
---
src/backend/bootstrap/bootstrap.c | 2 +-
src/backend/catalog/index.c | 38 +-
src/backend/catalog/toasting.c | 2 +-
src/backend/commands/analyze.c | 10 +-
src/backend/commands/indexcmds.c | 4 +-
src/backend/commands/tablecmds.c | 14 +-
src/backend/commands/trigger.c | 8 +-
src/backend/executor/Makefile | 4 +-
src/backend/executor/execExpr.c | 915 ++++++++++++++++++++++++++++++
src/backend/executor/execIndexing.c | 21 +-
src/backend/executor/execMain.c | 17 +-
src/backend/executor/execQual.c | 414 +-------------
src/backend/executor/execScan.c | 4 +-
src/backend/executor/execUtils.c | 140 +----
src/backend/executor/nodeAgg.c | 14 +-
src/backend/executor/nodeBitmapHeapscan.c | 18 +-
src/backend/executor/nodeCtescan.c | 7 +-
src/backend/executor/nodeCustom.c | 7 +-
src/backend/executor/nodeForeignscan.c | 16 +-
src/backend/executor/nodeFunctionscan.c | 7 +-
src/backend/executor/nodeGather.c | 7 +-
src/backend/executor/nodeGroup.c | 11 +-
src/backend/executor/nodeHash.c | 11 +-
src/backend/executor/nodeHashjoin.c | 47 +-
src/backend/executor/nodeIndexonlyscan.c | 16 +-
src/backend/executor/nodeIndexscan.c | 20 +-
src/backend/executor/nodeMergejoin.c | 32 +-
src/backend/executor/nodeModifyTable.c | 36 +-
src/backend/executor/nodeNestloop.c | 29 +-
src/backend/executor/nodeResult.c | 17 +-
src/backend/executor/nodeSamplescan.c | 7 +-
src/backend/executor/nodeSeqscan.c | 7 +-
src/backend/executor/nodeSubplan.c | 12 +-
src/backend/executor/nodeSubqueryscan.c | 7 +-
src/backend/executor/nodeTidscan.c | 7 +-
src/backend/executor/nodeValuesscan.c | 7 +-
src/backend/executor/nodeWindowAgg.c | 2 +-
src/backend/executor/nodeWorktablescan.c | 7 +-
src/bin/initdb/initdb.c | 4 +-
src/include/executor/executor.h | 37 +-
src/include/nodes/execnodes.h | 177 ++++--
src/include/nodes/nodes.h | 2 +
42 files changed, 1353 insertions(+), 811 deletions(-)
create mode 100644 src/backend/executor/execExpr.c
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index e518e17..5b805b5 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -1088,7 +1088,7 @@ index_register(Oid heap,
/* predicate will likely be null, but may as well copy it */
newind->il_info->ii_Predicate = (List *)
copyObject(indexInfo->ii_Predicate);
- newind->il_info->ii_PredicateState = NIL;
+ newind->il_info->ii_PredicateState = NULL;
/* no exclusion constraints at bootstrap time, so no need to copy */
Assert(indexInfo->ii_ExclusionOps == NULL);
Assert(indexInfo->ii_ExclusionProcs == NULL);
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 7b30e46..053a116 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1645,7 +1645,7 @@ BuildIndexInfo(Relation index)
/* fetch index predicate if any */
ii->ii_Predicate = RelationGetIndexPredicate(index);
- ii->ii_PredicateState = NIL;
+ ii->ii_PredicateState = NULL;
/* fetch exclusion constraint info if any */
if (indexStruct->indisexclusion)
@@ -2193,7 +2193,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
Datum values[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
double reltuples;
- List *predicate;
+ ExprState2 *predicate;
TupleTableSlot *slot;
EState *estate;
ExprContext *econtext;
@@ -2232,9 +2232,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
econtext->ecxt_scantuple = slot;
/* Set up execution state for predicate, if any. */
- predicate = (List *)
- ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
- estate);
+ predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
/*
* Prepare for scan of the base relation. In a normal index build, we use
@@ -2537,9 +2535,9 @@ IndexBuildHeapRangeScan(Relation heapRelation,
* In a partial index, discard tuples that don't satisfy the
* predicate.
*/
- if (predicate != NIL)
+ if (predicate != NULL)
{
- if (!ExecQual(predicate, econtext, false))
+ if (!ExecQual(predicate))
continue;
}
@@ -2604,7 +2602,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
/* These may have been pointing to the now-gone estate */
indexInfo->ii_ExpressionsState = NIL;
- indexInfo->ii_PredicateState = NIL;
+ indexInfo->ii_PredicateState = NULL;
return reltuples;
}
@@ -2631,7 +2629,7 @@ IndexCheckExclusion(Relation heapRelation,
HeapTuple heapTuple;
Datum values[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
- List *predicate;
+ ExprState2 *predicate;
TupleTableSlot *slot;
EState *estate;
ExprContext *econtext;
@@ -2657,9 +2655,7 @@ IndexCheckExclusion(Relation heapRelation,
econtext->ecxt_scantuple = slot;
/* Set up execution state for predicate, if any. */
- predicate = (List *)
- ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
- estate);
+ predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
/*
* Scan all live tuples in the base relation.
@@ -2684,9 +2680,9 @@ IndexCheckExclusion(Relation heapRelation,
/*
* In a partial index, ignore tuples that don't satisfy the predicate.
*/
- if (predicate != NIL)
+ if (predicate != NULL)
{
- if (!ExecQual(predicate, econtext, false))
+ if (!ExecQual(predicate))
continue;
}
@@ -2717,7 +2713,7 @@ IndexCheckExclusion(Relation heapRelation,
/* These may have been pointing to the now-gone estate */
indexInfo->ii_ExpressionsState = NIL;
- indexInfo->ii_PredicateState = NIL;
+ indexInfo->ii_PredicateState = NULL;
}
@@ -2947,7 +2943,7 @@ validate_index_heapscan(Relation heapRelation,
HeapTuple heapTuple;
Datum values[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
- List *predicate;
+ ExprState2 *predicate;
TupleTableSlot *slot;
EState *estate;
ExprContext *econtext;
@@ -2977,9 +2973,7 @@ validate_index_heapscan(Relation heapRelation,
econtext->ecxt_scantuple = slot;
/* Set up execution state for predicate, if any. */
- predicate = (List *)
- ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
- estate);
+ predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
/*
* Prepare for scan of the base relation. We need just those tuples
@@ -3106,9 +3100,9 @@ validate_index_heapscan(Relation heapRelation,
* In a partial index, discard tuples that don't satisfy the
* predicate.
*/
- if (predicate != NIL)
+ if (predicate != NULL)
{
- if (!ExecQual(predicate, econtext, false))
+ if (!ExecQual(predicate))
continue;
}
@@ -3161,7 +3155,7 @@ validate_index_heapscan(Relation heapRelation,
/* These may have been pointing to the now-gone estate */
indexInfo->ii_ExpressionsState = NIL;
- indexInfo->ii_PredicateState = NIL;
+ indexInfo->ii_PredicateState = NULL;
}
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 564e10e..c618dc1 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -307,7 +307,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
indexInfo->ii_Expressions = NIL;
indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_Predicate = NIL;
- indexInfo->ii_PredicateState = NIL;
+ indexInfo->ii_PredicateState = NULL;
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 5fcedd7..00c9d30 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -701,7 +701,7 @@ compute_index_stats(Relation onerel, double totalrows,
TupleTableSlot *slot;
EState *estate;
ExprContext *econtext;
- List *predicate;
+ ExprState2 *predicate;
Datum *exprvals;
bool *exprnulls;
int numindexrows,
@@ -727,9 +727,7 @@ compute_index_stats(Relation onerel, double totalrows,
econtext->ecxt_scantuple = slot;
/* Set up execution state for predicate. */
- predicate = (List *)
- ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
- estate);
+ predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
/* Compute and save index expression values */
exprvals = (Datum *) palloc(numrows * attr_cnt * sizeof(Datum));
@@ -752,9 +750,9 @@ compute_index_stats(Relation onerel, double totalrows,
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
/* If index is partial, check predicate */
- if (predicate != NIL)
+ if (predicate != NULL)
{
- if (!ExecQual(predicate, econtext, false))
+ if (!ExecQual(predicate))
continue;
}
numindexrows++;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index d14d540..508130e 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -180,7 +180,7 @@ CheckIndexCompatible(Oid oldId,
indexInfo = makeNode(IndexInfo);
indexInfo->ii_Expressions = NIL;
indexInfo->ii_ExpressionsState = NIL;
- indexInfo->ii_PredicateState = NIL;
+ indexInfo->ii_PredicateState = NULL;
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
@@ -549,7 +549,7 @@ DefineIndex(Oid relationId,
indexInfo->ii_Expressions = NIL; /* for now */
indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
- indexInfo->ii_PredicateState = NIL;
+ indexInfo->ii_PredicateState = NULL;
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 86e9814..804ca92 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -179,7 +179,7 @@ typedef struct NewConstraint
Oid refindid; /* OID of PK's index, if FOREIGN */
Oid conid; /* OID of pg_constraint entry, if FOREIGN */
Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */
- List *qualstate; /* Execution state for CHECK */
+ ExprState2 *qualstate; /* Execution state for CHECK */
} NewConstraint;
/*
@@ -4010,8 +4010,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
{
case CONSTR_CHECK:
needscan = true;
- con->qualstate = (List *)
- ExecPrepareExpr((Expr *) con->qual, estate);
+ con->qualstate = ExecPrepareQual((List *) con->qual, estate);
break;
case CONSTR_FOREIGN:
/* Nothing to do here */
@@ -4195,7 +4194,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
switch (con->contype)
{
case CONSTR_CHECK:
- if (!ExecQual(con->qualstate, econtext, true))
+ if (!ExecQual(con->qualstate))
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("check constraint \"%s\" is violated by some row",
@@ -7308,7 +7307,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
Datum val;
char *conbin;
Expr *origexpr;
- List *exprstate;
+ ExprState2 *exprstate;
TupleDesc tupdesc;
HeapScanDesc scan;
HeapTuple tuple;
@@ -7339,8 +7338,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
HeapTupleGetOid(constrtup));
conbin = TextDatumGetCString(val);
origexpr = (Expr *) stringToNode(conbin);
- exprstate = (List *)
- ExecPrepareExpr((Expr *) make_ands_implicit(origexpr), estate);
+ exprstate = ExecPrepareQual(make_ands_implicit(origexpr), estate);
econtext = GetPerTupleExprContext(estate);
tupdesc = RelationGetDescr(rel);
@@ -7360,7 +7358,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
{
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
- if (!ExecQual(exprstate, econtext, true))
+ if (!ExecQual(exprstate))
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("check constraint \"%s\" is violated by some row",
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 99a659a..0929652 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2867,7 +2867,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
if (trigger->tgqual)
{
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
- List **predicate;
+ ExprState2 **predicate;
ExprContext *econtext;
TupleTableSlot *oldslot = NULL;
TupleTableSlot *newslot = NULL;
@@ -2888,7 +2888,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
* nodetrees for it. Keep them in the per-query memory context so
* they'll survive throughout the query.
*/
- if (*predicate == NIL)
+ if (*predicate == NULL)
{
Node *tgqual;
@@ -2899,7 +2899,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
ChangeVarNodes(tgqual, PRS2_NEW_VARNO, OUTER_VAR, 0);
/* ExecQual wants implicit-AND form */
tgqual = (Node *) make_ands_implicit((Expr *) tgqual);
- *predicate = (List *) ExecPrepareExpr((Expr *) tgqual, estate);
+ *predicate = ExecPrepareQual((List *) tgqual, estate);
MemoryContextSwitchTo(oldContext);
}
@@ -2947,7 +2947,7 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
*/
econtext->ecxt_innertuple = oldslot;
econtext->ecxt_outertuple = newslot;
- if (!ExecQual(*predicate, econtext, false))
+ if (!ExecQual(*predicate))
return false;
}
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 51edd4c..ba7eb50 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -12,8 +12,8 @@ subdir = src/backend/executor
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
-OBJS = execAmi.o execCurrent.o execGrouping.o execIndexing.o execJunk.o \
- execMain.o execParallel.o execProcnode.o execQual.o \
+OBJS = execAmi.o execCurrent.o execExpr.o execGrouping.o execIndexing.o \
+ execJunk.o execMain.o execParallel.o execProcnode.o execQual.o \
execScan.o execTuples.o \
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
nodeBitmapAnd.o nodeBitmapOr.o \
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
new file mode 100644
index 0000000..fe5575f
--- /dev/null
+++ b/src/backend/executor/execExpr.c
@@ -0,0 +1,915 @@
+#include "postgres.h"
+
+#include "access/htup_details.h"
+#include "access/nbtree.h"
+#include "access/tupconvert.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_type.h"
+#include "executor/execdebug.h"
+#include "executor/nodeSubplan.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
+#include "optimizer/planner.h"
+#include "parser/parse_coerce.h"
+#include "parser/parsetree.h"
+#include "pgstat.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/typcache.h"
+#include "utils/xml.h"
+
+static bool ExecInitExprRec(Expr *node, PlanState *parent, ExprContext *context, ExprState2 *state, Datum *resv, bool *resnull);
+
+static void
+ExprEvalPushStep(ExprState2 *es, ExprEvalStep *s)
+{
+ if (es->steps_alloc == 0)
+ {
+ es->steps_alloc = 16;
+ es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
+ }
+ else if (es->steps_alloc == es->steps_len)
+ {
+ es->steps_alloc *= 2;
+ es->steps = repalloc(es->steps,
+ sizeof(ExprEvalStep) * es->steps_alloc);
+ }
+
+ memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
+}
+
+static TupleTableSlot** varslot(Var *variable, ExprContext *econtext)
+{
+ TupleTableSlot **slot;
+
+ switch (variable->varno)
+ {
+ case INNER_VAR: /* get the tuple from the inner node */
+ slot = &econtext->ecxt_innertuple;
+ break;
+
+ case OUTER_VAR: /* get the tuple from the outer node */
+ slot = &econtext->ecxt_outertuple;
+ break;
+
+ /* INDEX_VAR is handled by default case */
+
+ default: /* get the tuple from the relation being
+ * scanned */
+ slot = &econtext->ecxt_scantuple;
+ break;
+ }
+
+ return slot;
+}
+
+static void
+ExecInitOld(ExprState2 *state, PlanState *parent, Expr *expr, Datum *resv, bool *resnull)
+{
+ ExprEvalStep scratch;
+ ExprState *es = ExecInitExpr(expr, parent);
+ scratch.resvalue = resv;
+ scratch.resnull = resnull;
+ scratch.opcode = EEO_EVAL1;
+ scratch.d.eval1.expr = es;
+ ExprEvalPushStep(state, &scratch);
+}
+
+static bool
+ExecInitFunc2(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid,
+ PlanState *parent, ExprContext *econtext, ExprState2 *state, Datum *resv, bool *resnull)
+{
+ ListCell *lc;
+ AclResult aclresult;
+ int nargs = list_length(args);
+ FunctionCallInfo fcinfo;
+ int argno;
+
+ /* Check permission to call function */
+ aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(funcid));
+ InvokeFunctionExecuteHook(funcid);
+
+ /*
+ * Safety check on nargs. Under normal circumstances this should never
+ * fail, as parser should check sooner. But possibly it might fail if
+ * server has been compiled with FUNC_MAX_ARGS smaller than some functions
+ * declared in pg_proc?
+ */
+ if (nargs > FUNC_MAX_ARGS)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
+
+ /* Set up the primary fmgr lookup information */
+ scratch->d.func.finfo = palloc0(sizeof(*scratch->d.func.finfo));
+ scratch->d.func.fcinfo_data = palloc0(sizeof(*scratch->d.func.fcinfo_data));
+
+ fcinfo = scratch->d.func.fcinfo_data;
+ fmgr_info_cxt(funcid, scratch->d.func.finfo, econtext->ecxt_per_query_memory);
+ fmgr_info_set_expr((Node *) node, scratch->d.func.finfo);
+ InitFunctionCallInfoData(*fcinfo, scratch->d.func.finfo,
+ nargs, inputcollid, NULL, NULL);
+ scratch->d.func.fn_addr = scratch->d.func.fcinfo_data->flinfo->fn_addr;
+ if (scratch->d.func.finfo->fn_retset)
+ {
+ elog(ERROR, "targetlist SRFs are not supported");
+ state->failed = true;
+ return false;
+ }
+
+ argno = 0;
+ foreach (lc, args)
+ {
+ Expr *arg = (Expr *) lfirst(lc);
+
+ if (IsA(arg, Const))
+ {
+ /*
+ * Don't evaluate const arguments every round; especially
+ * interesting for constants in comparisons.
+ */
+ Const *con = (Const *) arg;
+
+ fcinfo->arg[argno] = con->constvalue;
+ fcinfo->argnull[argno] = con->constisnull;
+ }
+ else if (!ExecInitExprRec(arg, parent, econtext, state, &fcinfo->arg[argno], &fcinfo->argnull[argno]))
+ {
+ state->failed = true;
+ return false;
+ }
+ argno++;
+ }
+
+ scratch->d.func.nargs = nargs;
+ /*
+ * FIXME: introduce separate opcodes for functioncallusage
+ * enabled/disabled.
+ */
+ if (pgstat_track_functions <= scratch->d.func.finfo->fn_stats)
+ {
+ if (scratch->d.func.finfo->fn_strict)
+ scratch->opcode = EEO_FUNCEXPR_STRICT;
+ else
+ scratch->opcode = EEO_FUNCEXPR;
+ }
+ else
+ {
+ if (scratch->d.func.finfo->fn_strict)
+ scratch->opcode = EEO_FUNCEXPR_STRICT_FUSAGE;
+ else
+ scratch->opcode = EEO_FUNCEXPR_FUSAGE;
+ }
+ return true;
+}
+
+static void
+ExecInitExprSlots(ExprState2 *state, ExprContext *econtext, Node *node)
+{
+ ExprEvalStep scratch;
+ int last_outer = -1;
+ int last_inner = -1;
+ int last_scan = -1;
+
+ /*
+ * Figure out which attributes we're going to need.
+ */
+ ExecGetLastAttnums((Node *) node,
+ &last_outer,
+ &last_inner,
+ &last_scan);
+ if (last_outer > 0)
+ {
+ scratch.opcode = EEO_FETCHSOMEATTRS;
+ scratch.d.fetch.slot = &econtext->ecxt_outertuple;
+ scratch.d.fetch.last_var = last_outer;
+ ExprEvalPushStep(state, &scratch);
+ }
+ if (last_inner > 0)
+ {
+ scratch.opcode = EEO_FETCHSOMEATTRS;
+ scratch.d.fetch.slot = &econtext->ecxt_innertuple;
+ scratch.d.fetch.last_var = last_inner;
+ ExprEvalPushStep(state, &scratch);
+ }
+ if (last_scan > 0)
+ {
+ scratch.opcode = EEO_FETCHSOMEATTRS;
+ scratch.d.fetch.slot = &econtext->ecxt_scantuple;
+ scratch.d.fetch.last_var = last_scan;
+ ExprEvalPushStep(state, &scratch);
+ }
+}
+
+ExprState2 *
+ExecInitQual(List *qual, PlanState *parent, ExprContext *econtext)
+{
+ BoolExpr *andExpr;
+
+ if (qual == NULL)
+ return NULL;
+
+ Assert(IsA(qual, List));
+
+ if (list_length(qual) > 1)
+ {
+ andExpr = makeNode(BoolExpr);
+
+ /* FIXME: ExecQual(false) shortcuts for NULL, this doesn't */
+ andExpr->boolop = AND_EXPR;
+ andExpr->args = qual;
+ andExpr->location = -1;
+ return ExecInitExpr2((Expr *) andExpr, parent, econtext);
+ }
+ else
+ {
+ return ExecInitExpr2((Expr *) linitial(qual), parent, econtext);
+ }
+}
+
+
+ExprState2 *
+ExecInitCheck(List *qual, PlanState *parent, ExprContext *econtext)
+{
+ BoolExpr *andExpr;
+
+ if (qual == NULL)
+ return NULL;
+
+ Assert(IsA(qual, List));
+
+ andExpr = makeNode(BoolExpr);
+
+ andExpr->boolop = AND_EXPR;
+ andExpr->args = qual;
+ andExpr->location = -1;
+
+ return ExecInitExpr2((Expr *) andExpr, parent, econtext);
+}
+
+/* ----------------
+ * ExecBuildProjectionInfo
+ *
+ * Build a ProjectionInfo node for evaluating the given tlist in the given
+ * econtext, and storing the result into the tuple slot. (Caller must have
+ * ensured that tuple slot has a descriptor matching the tlist!) Note that
+ * the given tlist should be a list of ExprState nodes, not Expr nodes.
+ *
+ * inputDesc can be NULL, but if it is not, we check to see whether simple
+ * Vars in the tlist match the descriptor. It is important to provide
+ * inputDesc for relation-scan plan nodes, as a cross check that the relation
+ * hasn't been changed since the plan was made. At higher levels of a plan,
+ * there is no need to recheck.
+ * ----------------
+ */
+ProjectionInfo *
+ExecBuildProjectionInfo(List *targetList,
+ ExprContext *econtext,
+ TupleTableSlot *slot,
+ PlanState *parent,
+ TupleDesc inputDesc)
+{
+ ProjectionInfo *projInfo = makeNode(ProjectionInfo);
+ ExprEvalStep scratch;
+ ListCell *lc;
+ ExprState2 *state;
+
+ projInfo->pi_slot = slot;
+ projInfo->pi_exprContext = econtext;
+ projInfo->pi_state.econtext = econtext;
+ projInfo->pi_state.tag.type = T_ExprState2;
+ state = &projInfo->pi_state;
+ ExecInitExprSlots(state, econtext, (Node *) targetList);
+
+ foreach(lc, targetList)
+ {
+ TargetEntry *tle;
+ Var *variable = NULL;
+ AttrNumber attnum;
+ bool isSimpleVar = false;
+
+ Assert(IsA(lfirst(lc), TargetEntry));
+
+ tle = (TargetEntry *) lfirst(lc);
+
+ if (tle->expr != NULL &&
+ IsA(tle, Var) &&
+ ((Var *)tle->expr)->varattno > 0)
+ {
+ variable = (Var *) tle->expr;
+ attnum = variable->varattno;
+
+ if (!inputDesc)
+ isSimpleVar = true; /* can't check type, assume OK */
+ else if (variable->varattno <= inputDesc->natts)
+ {
+ Form_pg_attribute attr;
+
+ attr = inputDesc->attrs[variable->varattno - 1];
+ if (!attr->attisdropped && variable->vartype == attr->atttypid)
+ isSimpleVar = true;
+ }
+ }
+
+ if (isSimpleVar)
+ {
+ scratch.opcode = EEO_ASSIGN_VAR;
+ scratch.d.assign_var.slot = varslot(variable, econtext);
+ scratch.d.assign_var.attnum = attnum - 1;
+ scratch.d.assign_var.resultnum = tle->resno - 1;
+ ExprEvalPushStep(state, &scratch);
+ }
+ else
+ {
+ if (!ExecInitExprRec(tle->expr, parent, econtext, state, &state->resvalue, &state->resnull))
+ {
+ elog(ERROR, "could not compute target list");
+ }
+ else
+ {
+ scratch.opcode = EEO_ASSIGN_TMP;
+ scratch.d.assign_tmp.resultnum = tle->resno - 1;
+ ExprEvalPushStep(state, &scratch);
+ }
+ }
+ }
+
+
+ scratch.resvalue = &state->resvalue;
+ scratch.resnull = &state->resnull;
+ scratch.opcode = EEO_DONE;
+ ExprEvalPushStep(state, &scratch);
+ return projInfo;
+}
+
+
+ExprState2 *
+ExecInitExpr2(Expr *node, PlanState *parent, ExprContext *econtext)
+{
+ ExprState2 *state = makeNode(ExprState2);
+ ExprEvalStep scratch;
+
+ if (node == NULL)
+ return NULL;
+
+ state->econtext = econtext;
+
+ ExecInitExprSlots(state, econtext, (Node *) node);
+
+ if (!ExecInitExprRec(node, parent, econtext, state, &state->resvalue, &state->resnull))
+ return NULL;
+ scratch.resvalue = &state->resvalue;
+ scratch.resnull = &state->resnull;
+ scratch.opcode = EEO_DONE;
+ ExprEvalPushStep(state, &scratch);
+ return state;
+}
+
+static bool
+ExecInitExprRec(Expr *node, PlanState *parent, ExprContext *econtext, ExprState2 *state, Datum *resv, bool *resnull)
+{
+ ExprEvalStep scratch;
+
+ Assert(resv != NULL && resnull != NULL);
+ scratch.resvalue = resv;
+ scratch.resnull = resnull;
+ Assert(econtext != NULL);
+
+ switch (nodeTag(node))
+ {
+ /* suppported */
+ case T_Var:
+ /* varattno == InvalidAttrNumber means it's a whole-row Var */
+ if (((Var *) node)->varattno == InvalidAttrNumber)
+ {
+ ExecInitOld(state, parent, node, resv, resnull);
+ }
+ else
+ {
+ Var *variable = (Var *) node;
+ TupleTableSlot **slot = varslot(variable, econtext);
+
+ /* FIXME: consider re-adding type checks */
+ if (variable->varattno <= 0)
+ {
+ scratch.d.var.slot = slot;
+ scratch.d.var.attnum = variable->varattno;
+ scratch.opcode = EEO_SYSVAR;
+ }
+ else
+ {
+ scratch.d.var.slot = slot;
+ scratch.d.var.attnum = variable->varattno - 1;
+ scratch.opcode = EEO_VAR;
+ }
+
+ ExprEvalPushStep(state, &scratch);
+ }
+ break;
+ case T_Const:
+ {
+ Const *con = (Const *) node;
+
+ /* FIXME: skip evaluation */
+ scratch.opcode = EEO_CONST;
+ scratch.d.constval.value = con->constvalue;
+ scratch.d.constval.isnull = con->constisnull;
+
+ ExprEvalPushStep(state, &scratch);
+ }
+ break;
+ case T_FuncExpr:
+ {
+ FuncExpr *func = (FuncExpr *) node;
+ if (!ExecInitFunc2(&scratch, node, func->args, func->funcid, func->inputcollid,
+ parent, econtext, state, resv, resnull))
+ {
+ Assert(false);
+ return false;
+ }
+
+ ExprEvalPushStep(state, &scratch);
+ }
+ break;
+ case T_OpExpr:
+ {
+ OpExpr *op = (OpExpr *) node;
+ if (!ExecInitFunc2(&scratch, node, op->args, op->opfuncid, op->inputcollid,
+ parent, econtext, state, resv, resnull))
+ {
+ Assert(false);
+ return false;
+ }
+ ExprEvalPushStep(state, &scratch);
+ }
+ break;
+ case T_BoolExpr:
+ {
+ BoolExpr *boolexpr = (BoolExpr *) node;
+ ListCell *lc;
+ List *adjust_bailout = NIL;
+ bool first = true;
+
+ scratch.d.boolexpr.value = palloc0(sizeof(Datum));
+ scratch.d.boolexpr.isnull = palloc0(sizeof(bool));
+ scratch.d.boolexpr.anynull = palloc0(sizeof(bool));
+
+ foreach (lc, boolexpr->args)
+ {
+ Expr *arg = (Expr *) lfirst(lc);
+
+ switch (boolexpr->boolop)
+ {
+ case AND_EXPR:
+ if (first)
+ scratch.opcode = EEO_BOOL_AND_STEP_FIRST;
+ else
+ scratch.opcode = EEO_BOOL_AND_STEP;
+ break;
+ case OR_EXPR:
+ if (first)
+ scratch.opcode = EEO_BOOL_OR_STEP_FIRST;
+ else
+ scratch.opcode = EEO_BOOL_OR_STEP;
+ break;
+ case NOT_EXPR:
+ Assert(list_length(boolexpr->args) == 1);
+ scratch.opcode = EEO_BOOL_NOT_STEP;
+ break;
+ default:
+ elog(ERROR, "unrecognized boolop: %d",
+ (int) boolexpr->boolop);
+ break;
+ }
+
+ first = false;
+
+ if (!ExecInitExprRec(arg, parent, econtext, state,
+ scratch.d.boolexpr.value,
+ scratch.d.boolexpr.isnull))
+ return false;
+ scratch.d.boolexpr.jumpdone = -1;
+ ExprEvalPushStep(state, &scratch);
+ adjust_bailout = lappend_int(adjust_bailout,
+ state->steps_len - 1);
+ }
+
+ /* adjust early bail out jump target */
+ foreach (lc, adjust_bailout)
+ {
+ ExprEvalStep *as = &state->steps[lfirst_int(lc)];
+ Assert(as->opcode >= EEO_BOOL_AND_STEP_FIRST &&
+ as->opcode <= EEO_BOOL_NOT_STEP);
+ Assert(as->d.boolexpr.jumpdone == -1);
+ as->d.boolexpr.jumpdone = state->steps_len;
+ }
+ }
+ break;
+ /* unsupported */
+ case T_Param:
+ case T_CoerceToDomainValue:
+ case T_CaseTestExpr:
+ case T_Aggref:
+ case T_GroupingFunc:
+ case T_WindowFunc:
+ case T_ArrayRef:
+ case T_DistinctExpr:
+ case T_NullIfExpr:
+ case T_ScalarArrayOpExpr:
+ case T_SubPlan:
+ case T_AlternativeSubPlan:
+ case T_FieldSelect:
+ case T_FieldStore:
+ case T_RelabelType:
+ case T_CoerceViaIO:
+ case T_ArrayCoerceExpr:
+ case T_ConvertRowtypeExpr:
+ case T_CaseExpr:
+ case T_ArrayExpr:
+ case T_RowExpr:
+ case T_RowCompareExpr:
+ case T_CoalesceExpr:
+ case T_MinMaxExpr:
+ case T_XmlExpr:
+ case T_NullTest:
+ case T_BooleanTest:
+ case T_CoerceToDomain:
+ case T_CurrentOfExpr:
+ ExecInitOld(state, parent, node, resv, resnull);
+ break;
+ case T_TargetEntry:
+ case T_List:
+ elog(ERROR, "unexpected");
+ default:
+ elog(ERROR, "unrecognized node type: %d",
+ (int) nodeTag(node));
+ break;
+ }
+ return true;
+}
+
+/*
+ * ExecProjectIntoSlot
+ *
+ * projects a tuple based on projection info and stores
+ * it in the specified tuple table slot.
+ *
+ * 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.
+ */
+void
+ExecProjectIntoSlot(ProjectionInfo *projInfo, TupleTableSlot *slot)
+{
+ bool isnull;
+ MemoryContext oldcontext;
+ ExprContext *econtext;
+ ExprState2 *state;
+
+ state = &projInfo->pi_state;
+ econtext = state->econtext;
+
+ /* make conditional? */
+ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+
+ /*
+ * Clear any former contents of the result slot. This makes it safe for
+ * us to use the slot's Datum/isnull arrays as workspace. (Also, we can
+ * return the slot as-is if we decide no rows can be projected.)
+ */
+ ExecClearTuple(slot);
+
+ state->resultslot = slot;
+ ExecEvalExpr2(state, &isnull);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ /*
+ * Successfully formed a result row. Mark the result slot as containing a
+ * valid virtual tuple.
+ */
+ ExecStoreVirtualTuple(slot);
+}
+
+bool
+ExecQual(ExprState2 *state)
+{
+ MemoryContext oldContext;
+ bool isnull;
+ Datum ret;
+
+ /* error out? */
+ if (state == NULL)
+ return true;
+
+ oldContext = MemoryContextSwitchTo(state->econtext->ecxt_per_tuple_memory);
+
+ ret = ExecEvalExpr2(state, &isnull);
+
+ MemoryContextSwitchTo(oldContext);
+
+ if (isnull)
+ return false;
+ return DatumGetBool(ret);
+}
+
+
+bool
+ExecCheck(ExprState2 *state)
+{
+ MemoryContext oldContext;
+ bool isnull;
+ Datum ret;
+
+ oldContext = MemoryContextSwitchTo(state->econtext->ecxt_per_tuple_memory);
+
+ ret = ExecEvalExpr2(state, &isnull);
+
+ MemoryContextSwitchTo(oldContext);
+
+ if (isnull)
+ return true;
+ return DatumGetBool(ret);
+}
+
+/* FIXME: use computed goto only on gcc / clang */
+#define USE_COMPUTED_GOTO
+
+#ifdef USE_COMPUTED_GOTO
+#define EEO_SWITCH(d)
+#define EEO_DISPATCH(op) goto *dispatch_table[op->opcode];
+#define EEO_CASE(name) CASE_##name
+#else
+#define EEO_SWITCH(d) switch (d)
+#define EEO_DISPATCH(op) goto starteval
+#define EEO_CASE(name) case name
+#endif /* USE_COMPUTED_GOTO */
+
+Datum
+ExecEvalExpr2(ExprState2 *state, bool *isnull)
+{
+ ExprEvalStep *op = state->steps;
+ TupleTableSlot *resultslot = state->resultslot;
+
+#ifdef USE_COMPUTED_GOTO
+ static const void **dispatch_table[] = {
+ &&CASE_EEO_VAR,
+ &&CASE_EEO_SYSVAR,
+ &&CASE_EEO_CONST,
+ &&CASE_EEO_FUNCEXPR,
+ &&CASE_EEO_FUNCEXPR_STRICT,
+ &&CASE_EEO_FUNCEXPR_FUSAGE,
+ &&CASE_EEO_FUNCEXPR_STRICT_FUSAGE,
+ &&CASE_EEO_BOOL_AND_STEP_FIRST,
+ &&CASE_EEO_BOOL_AND_STEP,
+ &&CASE_EEO_BOOL_OR_STEP_FIRST,
+ &&CASE_EEO_BOOL_OR_STEP,
+ &&CASE_EEO_BOOL_NOT_STEP,
+ &&CASE_EEO_FETCHSOMEATTRS,
+ &&CASE_EEO_ASSIGN_VAR,
+ &&CASE_EEO_ASSIGN_TMP,
+ &&CASE_EEO_EVAL1,
+ &&CASE_EEO_ASSIGN_EVAL1,
+ &&CASE_EEO_DONE
+ };
+#endif
+
+#ifdef USE_COMPUTED_GOTO
+ EEO_DISPATCH(op);
+#else
+starteval:
+#endif
+ EEO_SWITCH (op->opcode)
+ {
+ EEO_CASE(EEO_VAR):
+ {
+ TupleTableSlot *slot = *op->d.var.slot;
+ int attnum = op->d.var.attnum;
+ /*
+ * Yuck): can't assert tts_nvalid, wholrow vars or such
+ * could have materialized the slot - but the contents are
+ * still valid :/
+ *
+ * Assert(op->d.var.attnum <= slot->tts_nvalid);
+ */
+ Assert(op->d.var.attnum >= 0);
+ *op->resnull = slot->tts_isnull[attnum];
+ *op->resvalue = slot->tts_values[attnum];
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_SYSVAR):
+ {
+ TupleTableSlot *slot = *op->d.var.slot;
+ int attnum = op->d.var.attnum;
+ Assert(op->d.var.attnum < 0);
+ *op->resvalue = heap_getsysattr(slot->tts_tuple, attnum,
+ slot->tts_tupleDescriptor,
+ op->resnull);
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_CONST):
+ *op->resnull = op->d.constval.isnull;
+ *op->resvalue = op->d.constval.value;
+ op++;
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_FUNCEXPR):
+ {
+ FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+
+ fcinfo->isnull = false;
+ *op->resvalue = (op->d.func.fn_addr)(fcinfo);
+ *op->resnull = fcinfo->isnull;
+
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_FUNCEXPR_STRICT):
+ {
+ FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+ int argno;
+
+ /* strict function, check for NULL args */
+ for (argno = 0; argno < op->d.func.nargs;argno++)
+ {
+ if (fcinfo->argnull[argno])
+ {
+ *op->resnull = true;
+ goto strictfail;
+ }
+ }
+ fcinfo->isnull = false;
+ *op->resvalue = (op->d.func.fn_addr)(fcinfo);
+ *op->resnull = fcinfo->isnull;
+ strictfail:
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_FUNCEXPR_FUSAGE):
+ {
+ PgStat_FunctionCallUsage fcusage;
+ FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+ pgstat_init_function_usage(fcinfo, &fcusage);
+
+ fcinfo->isnull = false;
+ *op->resvalue = (op->d.func.fn_addr)(fcinfo);
+ *op->resnull = fcinfo->isnull;
+
+ pgstat_end_function_usage(&fcusage, true);
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_FUNCEXPR_STRICT_FUSAGE):
+ {
+ PgStat_FunctionCallUsage fcusage;
+ FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+ int argno;
+
+ /* strict function, check for NULL args */
+ for (argno = 0; argno < op->d.func.nargs;argno++)
+ {
+ if (fcinfo->argnull[argno])
+ {
+ *op->resnull = true;
+ goto strictfail_fusage;
+ }
+ }
+
+ pgstat_init_function_usage(fcinfo, &fcusage);
+
+ fcinfo->isnull = false;
+ *op->resvalue = (op->d.func.fn_addr)(fcinfo);
+ *op->resnull = fcinfo->isnull;
+ strictfail_fusage:
+ pgstat_end_function_usage(&fcusage, true);
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_BOOL_AND_STEP_FIRST):
+ *op->d.boolexpr.anynull = false;
+ EEO_CASE(EEO_BOOL_AND_STEP):
+ *op->resvalue = *op->d.boolexpr.value;
+ *op->resnull = *op->d.boolexpr.isnull;
+
+ if (*op->d.boolexpr.isnull)
+ {
+ *op->d.boolexpr.anynull = true;
+ }
+ else if (!DatumGetBool(*op->d.boolexpr.value))
+ {
+ *op->resnull = false;
+ *op->resvalue = BoolGetDatum(false);
+ /* bail out early */
+ op = &state->steps[op->d.boolexpr.jumpdone];
+ EEO_DISPATCH(op);
+ }
+
+ /* XXX: could skip this step till last */
+ if (*op->d.boolexpr.anynull)
+ {
+ *op->resnull = *op->d.boolexpr.anynull;
+ *op->resvalue = BoolGetDatum(false); /* or null */
+ }
+ op++;
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_BOOL_OR_STEP_FIRST):
+ *op->d.boolexpr.anynull = false;
+ EEO_CASE(EEO_BOOL_OR_STEP):
+ *op->resvalue = *op->d.boolexpr.value;
+ *op->resnull = *op->d.boolexpr.isnull;
+
+ if (*op->d.boolexpr.isnull)
+ {
+ *op->d.boolexpr.anynull = true;
+ }
+
+ if (DatumGetBool(*op->d.boolexpr.value))
+ {
+ *op->resnull = false;
+ *op->resvalue = BoolGetDatum(true);
+ /* bail out early */
+ op = &state->steps[op->d.boolexpr.jumpdone];
+ EEO_DISPATCH(op);
+ }
+
+ /* XXX: could skip this step till last */
+ if (*op->d.boolexpr.anynull)
+ {
+ *op->resnull = *op->d.boolexpr.anynull;
+ *op->resvalue = BoolGetDatum(false); /* or null */
+ }
+ op++;
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_BOOL_NOT_STEP):
+ *op->resvalue = BoolGetDatum(!DatumGetBool(*op->d.boolexpr.value));
+ *op->resnull = *op->d.boolexpr.isnull;
+ op++;
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_FETCHSOMEATTRS):
+ /* XXX: add check for tts_nvalid here? */
+ slot_getsomeattrs(*op->d.fetch.slot,
+ op->d.fetch.last_var);
+ op++;
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_ASSIGN_VAR):
+ {
+ size_t resultnum = op->d.assign_var.resultnum;
+ size_t attnum = op->d.assign_var.attnum;
+ TupleTableSlot *source = *op->d.assign_var.slot;
+ resultslot->tts_values[resultnum] = source->tts_values[attnum];
+ resultslot->tts_isnull[resultnum] = source->tts_isnull[attnum];
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_ASSIGN_TMP):
+ {
+ size_t resultnum = op->d.assign_tmp.resultnum;
+ resultslot->tts_values[resultnum] = state->resvalue;
+ resultslot->tts_isnull[resultnum] = state->resnull;
+ op++;
+ }
+ EEO_DISPATCH(op);
+ EEO_CASE(EEO_EVAL1):
+ {
+ *op->resvalue = ExecEvalExpr(op->d.eval1.expr,
+ state->econtext,
+ op->resnull,
+ NULL);
+ op++;
+ EEO_DISPATCH(op);
+ }
+ EEO_CASE(EEO_ASSIGN_EVAL1):
+ {
+ size_t resultnum = op->d.assign_eval1.resultnum;
+ resultslot->tts_values[resultnum] =
+ ExecEvalExpr(op->d.assign_eval1.expr,
+ state->econtext,
+ &resultslot->tts_isnull[resultnum],
+ NULL);
+ op++;
+ EEO_DISPATCH(op);
+ }
+ EEO_CASE(EEO_DONE):
+ goto out;
+ }
+out:
+ *isnull = state->resnull;
+ return state->resvalue;
+}
+
+#undef EEO_SWITCH
+#undef EEO_DISPATCH
+#undef EEO_CASE
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 0e2d834..8e1cbba 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -327,23 +327,21 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
/* Check for partial index */
if (indexInfo->ii_Predicate != NIL)
{
- List *predicate;
+ ExprState2 *predicate;
/*
* If predicate state not set up yet, create it (in the estate's
* per-query context)
*/
predicate = indexInfo->ii_PredicateState;
- if (predicate == NIL)
+ if (predicate == NULL)
{
- predicate = (List *)
- ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
- estate);
+ predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
indexInfo->ii_PredicateState = predicate;
}
/* Skip this index-update if the predicate isn't satisfied */
- if (!ExecQual(predicate, econtext, false))
+ if (!ExecQual(predicate))
continue;
}
@@ -550,23 +548,22 @@ ExecCheckIndexConstraints(TupleTableSlot *slot,
/* Check for partial index */
if (indexInfo->ii_Predicate != NIL)
{
- List *predicate;
+ ExprState2 *predicate;
/*
* If predicate state not set up yet, create it (in the estate's
* per-query context)
*/
predicate = indexInfo->ii_PredicateState;
- if (predicate == NIL)
+ if (predicate == NULL)
{
- predicate = (List *)
- ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
- estate);
+ predicate =
+ ExecPrepareQual(indexInfo->ii_Predicate, estate);
indexInfo->ii_PredicateState = predicate;
}
/* Skip this index-update if the predicate isn't satisfied */
- if (!ExecQual(predicate, econtext, false))
+ if (!ExecQual(predicate))
continue;
}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 32bb3f9..66003c9 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1229,7 +1229,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
resultRelInfo->ri_TrigFunctions = (FmgrInfo *)
palloc0(n * sizeof(FmgrInfo));
- resultRelInfo->ri_TrigWhenExprs = (List **)
+ resultRelInfo->ri_TrigWhenExprs = (ExprState2 **)
palloc0(n * sizeof(List *));
if (instrument_options)
resultRelInfo->ri_TrigInstrument = InstrAlloc(n, instrument_options);
@@ -1640,7 +1640,6 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
ConstrCheck *check = rel->rd_att->constr->check;
ExprContext *econtext;
MemoryContext oldContext;
- List *qual;
int i;
/*
@@ -1652,13 +1651,13 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
{
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
resultRelInfo->ri_ConstraintExprs =
- (List **) palloc(ncheck * sizeof(List *));
+ (ExprState2 **) palloc(ncheck * sizeof(ExprState2 *));
for (i = 0; i < ncheck; i++)
{
+ List *qual;
/* ExecQual wants implicit-AND form */
qual = make_ands_implicit(stringToNode(check[i].ccbin));
- resultRelInfo->ri_ConstraintExprs[i] = (List *)
- ExecPrepareExpr((Expr *) qual, estate);
+ resultRelInfo->ri_ConstraintExprs[i] = ExecPrepareQual(qual, estate);
}
MemoryContextSwitchTo(oldContext);
}
@@ -1675,14 +1674,14 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
/* And evaluate the constraints */
for (i = 0; i < ncheck; i++)
{
- qual = resultRelInfo->ri_ConstraintExprs[i];
+ ExprState2 *qual = resultRelInfo->ri_ConstraintExprs[i];
/*
* NOTE: SQL specifies that a NULL result from a constraint expression
* is not to be treated as a failure. Therefore, tell ExecQual to
* return TRUE for NULL.
*/
- if (!ExecQual(qual, econtext, true))
+ if (!ExecCheck(qual))
return check[i].ccname;
}
@@ -1793,7 +1792,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
l2, resultRelInfo->ri_WithCheckOptionExprs)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(l1);
- ExprState *wcoExpr = (ExprState *) lfirst(l2);
+ ExprState2 *wcoExpr = (ExprState2 *) lfirst(l2);
/*
* Skip any WCOs which are not the kind we are looking for at this
@@ -1811,7 +1810,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
* need ExecQual to return FALSE for NULL to handle the view case (the
* opposite of what we do above for CHECK constraints).
*/
- if (!ExecQual((List *) wcoExpr, econtext, false))
+ if (!ExecQual(wcoExpr))
{
char *val_desc;
Bitmapset *modifiedCols;
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index d04d1a8..fb070e4 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -5194,103 +5194,40 @@ ExecPrepareExpr(Expr *node, EState *estate)
}
+/*
+ * ExecPrepareQual --- initialize for qual execution outside a normal
+ * Plan tree context.
+ *
+ * This differs from ExecInitExpr in that we don't assume the caller is
+ * already running in the EState's per-query context. Also, we run the
+ * passed expression tree through expression_planner() to prepare it for
+ * execution. (In ordinary Plan trees the regular planning process will have
+ * made the appropriate transformations on expressions, but for standalone
+ * expressions this won't have happened.)
+ */
+ExprState2 *
+ExecPrepareQual(List *qual, EState *estate)
+{
+ ExprState2 *result;
+ MemoryContext oldcontext;
+
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ qual = (List *) expression_planner((Expr *) qual);
+
+ result = ExecInitQual(qual, NULL, GetPerTupleExprContext(estate));
+
+ MemoryContextSwitchTo(oldcontext);
+
+ return result;
+}
+
+
/* ----------------------------------------------------------------
* ExecQual / ExecTargetList / ExecProject
* ----------------------------------------------------------------
*/
-/* ----------------------------------------------------------------
- * ExecQual
- *
- * Evaluates a conjunctive boolean expression (qual list) and
- * returns true iff none of the subexpressions are false.
- * (We also return true if the list is empty.)
- *
- * If some of the subexpressions yield NULL but none yield FALSE,
- * then the result of the conjunction is NULL (ie, unknown)
- * according to three-valued boolean logic. In this case,
- * we return the value specified by the "resultForNull" parameter.
- *
- * Callers evaluating WHERE clauses should pass resultForNull=FALSE,
- * since SQL specifies that tuples with null WHERE results do not
- * get selected. On the other hand, callers evaluating constraint
- * conditions should pass resultForNull=TRUE, since SQL also specifies
- * that NULL constraint conditions are not failures.
- *
- * NOTE: it would not be correct to use this routine to evaluate an
- * AND subclause of a boolean expression; for that purpose, a NULL
- * result must be returned as NULL so that it can be properly treated
- * in the next higher operator (cf. ExecEvalAnd and ExecEvalOr).
- * This routine is only used in contexts where a complete expression
- * is being evaluated and we know that NULL can be treated the same
- * as one boolean result or the other.
- *
- * ----------------------------------------------------------------
- */
-bool
-ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
-{
- bool result;
- MemoryContext oldContext;
- ListCell *l;
-
- /*
- * debugging stuff
- */
- EV_printf("ExecQual: qual is ");
- EV_nodeDisplay(qual);
- EV_printf("\n");
-
- /*
- * Run in short-lived per-tuple context while computing expressions.
- */
- oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
-
- /*
- * Evaluate the qual conditions one at a time. If we find a FALSE result,
- * we can stop evaluating and return FALSE --- the AND result must be
- * FALSE. Also, if we find a NULL result when resultForNull is FALSE, we
- * can stop and return FALSE --- the AND result must be FALSE or NULL in
- * that case, and the caller doesn't care which.
- *
- * If we get to the end of the list, we can return TRUE. This will happen
- * when the AND result is indeed TRUE, or when the AND result is NULL (one
- * or more NULL subresult, with all the rest TRUE) and the caller has
- * specified resultForNull = TRUE.
- */
- result = true;
-
- foreach(l, qual)
- {
- ExprState *clause = (ExprState *) lfirst(l);
- Datum expr_value;
- bool isNull;
-
- expr_value = ExecEvalExpr(clause, econtext, &isNull, NULL);
-
- if (isNull)
- {
- if (resultForNull == false)
- {
- result = false; /* treat NULL as FALSE */
- break;
- }
- }
- else
- {
- if (!DatumGetBool(expr_value))
- {
- result = false; /* definitely FALSE */
- break;
- }
- }
- }
-
- MemoryContextSwitchTo(oldContext);
-
- return result;
-}
-
/*
* Number of items in a tlist (including any resjunk items!)
*/
@@ -5320,296 +5257,3 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
-
-/*
- * ExecTargetList
- * Evaluates a targetlist with respect to the given
- * expression context. Returns TRUE if we were able to create
- * a result, FALSE if we have exhausted a set-valued expression.
- *
- * Results are stored into the passed values and isnull arrays.
- * The caller must provide an itemIsDone array that persists across calls.
- *
- * As with ExecEvalExpr, the caller should pass isDone = NULL if not
- * prepared to deal with sets of result tuples. Otherwise, a return
- * of *isDone = ExprMultipleResult signifies a set element, and a return
- * of *isDone = ExprEndResult signifies end of the set of tuple.
- * We assume that *isDone has been initialized to ExprSingleResult by caller.
- *
- * Since fields of the result tuple might be multiply referenced in higher
- * plan nodes, we have to force any read/write expanded values to read-only
- * status. It's a bit annoying to have to do that for every projected
- * expression; in the future, consider teaching the planner to detect
- * actually-multiply-referenced Vars and insert an expression node that
- * would do that only where really required.
- */
-static bool
-ExecTargetList(List *targetlist,
- TupleDesc tupdesc,
- ExprContext *econtext,
- Datum *values,
- bool *isnull,
- ExprDoneCond *itemIsDone,
- ExprDoneCond *isDone)
-{
- Form_pg_attribute *att = tupdesc->attrs;
- MemoryContext oldContext;
- ListCell *tl;
- bool haveDoneSets;
-
- /*
- * Run in short-lived per-tuple context while computing expressions.
- */
- oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
-
- /*
- * evaluate all the expressions in the target list
- */
- haveDoneSets = false; /* any exhausted set exprs in tlist? */
-
- foreach(tl, targetlist)
- {
- GenericExprState *gstate = (GenericExprState *) lfirst(tl);
- TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
- AttrNumber resind = tle->resno - 1;
-
- values[resind] = ExecEvalExpr(gstate->arg,
- econtext,
- &isnull[resind],
- &itemIsDone[resind]);
-
- values[resind] = MakeExpandedObjectReadOnly(values[resind],
- isnull[resind],
- att[resind]->attlen);
-
- if (itemIsDone[resind] != ExprSingleResult)
- {
- /* We have a set-valued expression in the tlist */
- if (isDone == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
- if (itemIsDone[resind] == ExprMultipleResult)
- {
- /* we have undone sets in the tlist, set flag */
- *isDone = ExprMultipleResult;
- }
- else
- {
- /* we have done sets in the tlist, set flag for that */
- haveDoneSets = true;
- }
- }
- }
-
- if (haveDoneSets)
- {
- /*
- * note: can't get here unless we verified isDone != NULL
- */
- if (*isDone == ExprSingleResult)
- {
- /*
- * all sets are done, so report that tlist expansion is complete.
- */
- *isDone = ExprEndResult;
- MemoryContextSwitchTo(oldContext);
- return false;
- }
- else
- {
- /*
- * We have some done and some undone sets. Restart the done ones
- * so that we can deliver a tuple (if possible).
- */
- foreach(tl, targetlist)
- {
- GenericExprState *gstate = (GenericExprState *) lfirst(tl);
- TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
- AttrNumber resind = tle->resno - 1;
-
- if (itemIsDone[resind] == ExprEndResult)
- {
- values[resind] = ExecEvalExpr(gstate->arg,
- econtext,
- &isnull[resind],
- &itemIsDone[resind]);
-
- values[resind] = MakeExpandedObjectReadOnly(values[resind],
- isnull[resind],
- att[resind]->attlen);
-
- if (itemIsDone[resind] == ExprEndResult)
- {
- /*
- * Oh dear, this item is returning an empty set. Guess
- * we can't make a tuple after all.
- */
- *isDone = ExprEndResult;
- break;
- }
- }
- }
-
- /*
- * If we cannot make a tuple because some sets are empty, we still
- * have to cycle the nonempty sets to completion, else resources
- * will not be released from subplans etc.
- *
- * XXX is that still necessary?
- */
- if (*isDone == ExprEndResult)
- {
- foreach(tl, targetlist)
- {
- GenericExprState *gstate = (GenericExprState *) lfirst(tl);
- TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
- AttrNumber resind = tle->resno - 1;
-
- while (itemIsDone[resind] == ExprMultipleResult)
- {
- values[resind] = ExecEvalExpr(gstate->arg,
- econtext,
- &isnull[resind],
- &itemIsDone[resind]);
- /* no need for MakeExpandedObjectReadOnly */
- }
- }
-
- MemoryContextSwitchTo(oldContext);
- return false;
- }
- }
- }
-
- /* Report success */
- MemoryContextSwitchTo(oldContext);
-
- return true;
-}
-
-/*
- * ExecProject
- *
- * projects a tuple based on projection info and stores
- * it in the previously specified tuple table slot.
- *
- * 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.
- */
-TupleTableSlot *
-ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
-{
- TupleTableSlot *slot;
- ExprContext *econtext;
- int numSimpleVars;
-
- /*
- * sanity checks
- */
- Assert(projInfo != NULL);
-
- /*
- * get the projection info we want
- */
- slot = projInfo->pi_slot;
- econtext = projInfo->pi_exprContext;
-
- /* Assume single result row until proven otherwise */
- if (isDone)
- *isDone = ExprSingleResult;
-
- /*
- * Clear any former contents of the result slot. This makes it safe for
- * us to use the slot's Datum/isnull arrays as workspace. (Also, we can
- * return the slot as-is if we decide no rows can be projected.)
- */
- ExecClearTuple(slot);
-
- /*
- * Force extraction of all input values that we'll need. The
- * Var-extraction loops below depend on this, and we are also prefetching
- * all attributes that will be referenced in the generic expressions.
- */
- if (projInfo->pi_lastInnerVar > 0)
- slot_getsomeattrs(econtext->ecxt_innertuple,
- projInfo->pi_lastInnerVar);
- if (projInfo->pi_lastOuterVar > 0)
- slot_getsomeattrs(econtext->ecxt_outertuple,
- projInfo->pi_lastOuterVar);
- if (projInfo->pi_lastScanVar > 0)
- slot_getsomeattrs(econtext->ecxt_scantuple,
- projInfo->pi_lastScanVar);
-
- /*
- * Assign simple Vars to result by direct extraction of fields from source
- * slots ... a mite ugly, but fast ...
- */
- numSimpleVars = projInfo->pi_numSimpleVars;
- if (numSimpleVars > 0)
- {
- Datum *values = slot->tts_values;
- bool *isnull = slot->tts_isnull;
- int *varSlotOffsets = projInfo->pi_varSlotOffsets;
- int *varNumbers = projInfo->pi_varNumbers;
- int i;
-
- if (projInfo->pi_directMap)
- {
- /* especially simple case where vars go to output in order */
- for (i = 0; i < numSimpleVars; i++)
- {
- char *slotptr = ((char *) econtext) + varSlotOffsets[i];
- TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
- int varNumber = varNumbers[i] - 1;
-
- values[i] = varSlot->tts_values[varNumber];
- isnull[i] = varSlot->tts_isnull[varNumber];
- }
- }
- else
- {
- /* we have to pay attention to varOutputCols[] */
- int *varOutputCols = projInfo->pi_varOutputCols;
-
- for (i = 0; i < numSimpleVars; i++)
- {
- char *slotptr = ((char *) econtext) + varSlotOffsets[i];
- TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
- int varNumber = varNumbers[i] - 1;
- int varOutputCol = varOutputCols[i] - 1;
-
- values[varOutputCol] = varSlot->tts_values[varNumber];
- isnull[varOutputCol] = varSlot->tts_isnull[varNumber];
- }
- }
- }
-
- /*
- * If there are any generic expressions, evaluate them. It's possible
- * that there are set-returning functions in such expressions; if so and
- * we have reached the end of the set, we return the result slot, which we
- * already marked empty.
- */
- if (projInfo->pi_targetlist)
- {
- if (!ExecTargetList(projInfo->pi_targetlist,
- slot->tts_tupleDescriptor,
- econtext,
- slot->tts_values,
- slot->tts_isnull,
- projInfo->pi_itemIsDone,
- isDone))
- return slot; /* no more result rows, return empty slot */
- }
-
- /*
- * Successfully formed a result row. Mark the result slot as containing a
- * valid virtual tuple.
- */
- return ExecStoreVirtualTuple(slot);
-}
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index fb0013d..1cb33ee 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -123,7 +123,7 @@ ExecScan(ScanState *node,
ExecScanRecheckMtd recheckMtd)
{
ExprContext *econtext;
- List *qual;
+ ExprState2 *qual;
ProjectionInfo *projInfo;
ExprDoneCond isDone;
TupleTableSlot *resultSlot;
@@ -205,7 +205,7 @@ ExecScan(ScanState *node,
* when the qual is nil ... saves only a few cycles, but they add up
* ...
*/
- if (!qual || ExecQual(qual, econtext, false))
+ if (!qual || ExecQual(qual))
{
/*
* Found a satisfactory scan tuple.
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index a3a59c0..0fa402f 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -54,7 +54,6 @@ typedef struct LastLastAttnumInfo
AttrNumber last_scan;
} LastAttnumInfo;
-
static void ShutdownExprContext(ExprContext *econtext, bool isCommit);
@@ -475,142 +474,6 @@ ExecGetResultType(PlanState *planstate)
return slot->tts_tupleDescriptor;
}
-/* ----------------
- * ExecBuildProjectionInfo
- *
- * Build a ProjectionInfo node for evaluating the given tlist in the given
- * econtext, and storing the result into the tuple slot. (Caller must have
- * ensured that tuple slot has a descriptor matching the tlist!) Note that
- * the given tlist should be a list of ExprState nodes, not Expr nodes.
- *
- * inputDesc can be NULL, but if it is not, we check to see whether simple
- * Vars in the tlist match the descriptor. It is important to provide
- * inputDesc for relation-scan plan nodes, as a cross check that the relation
- * hasn't been changed since the plan was made. At higher levels of a plan,
- * there is no need to recheck.
- * ----------------
- */
-ProjectionInfo *
-ExecBuildProjectionInfo(List *targetList,
- ExprContext *econtext,
- TupleTableSlot *slot,
- TupleDesc inputDesc)
-{
- ProjectionInfo *projInfo = makeNode(ProjectionInfo);
- int len = ExecTargetListLength(targetList);
- int *workspace;
- int *varSlotOffsets;
- int *varNumbers;
- int *varOutputCols;
- List *exprlist;
- int numSimpleVars;
- bool directMap;
- ListCell *tl;
-
- projInfo->pi_exprContext = econtext;
- projInfo->pi_slot = slot;
- /* since these are all int arrays, we need do just one palloc */
- workspace = (int *) palloc(len * 3 * sizeof(int));
- projInfo->pi_varSlotOffsets = varSlotOffsets = workspace;
- projInfo->pi_varNumbers = varNumbers = workspace + len;
- projInfo->pi_varOutputCols = varOutputCols = workspace + len * 2;
- projInfo->pi_lastInnerVar = 0;
- projInfo->pi_lastOuterVar = 0;
- projInfo->pi_lastScanVar = 0;
-
- /*
- * We separate the target list elements into simple Var references and
- * expressions which require the full ExecTargetList machinery. To be a
- * simple Var, a Var has to be a user attribute and not mismatch the
- * inputDesc. (Note: if there is a type mismatch then ExecEvalScalarVar
- * will probably throw an error at runtime, but we leave that to it.)
- */
- exprlist = NIL;
- numSimpleVars = 0;
- directMap = true;
- foreach(tl, targetList)
- {
- GenericExprState *gstate = (GenericExprState *) lfirst(tl);
- Var *variable = (Var *) gstate->arg->expr;
- bool isSimpleVar = false;
-
- if (variable != NULL &&
- IsA(variable, Var) &&
- variable->varattno > 0)
- {
- if (!inputDesc)
- isSimpleVar = true; /* can't check type, assume OK */
- else if (variable->varattno <= inputDesc->natts)
- {
- Form_pg_attribute attr;
-
- attr = inputDesc->attrs[variable->varattno - 1];
- if (!attr->attisdropped && variable->vartype == attr->atttypid)
- isSimpleVar = true;
- }
- }
-
- if (isSimpleVar)
- {
- TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
- AttrNumber attnum = variable->varattno;
-
- varNumbers[numSimpleVars] = attnum;
- varOutputCols[numSimpleVars] = tle->resno;
- if (tle->resno != numSimpleVars + 1)
- directMap = false;
-
- switch (variable->varno)
- {
- case INNER_VAR:
- varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
- ecxt_innertuple);
- if (projInfo->pi_lastInnerVar < attnum)
- projInfo->pi_lastInnerVar = attnum;
- break;
-
- case OUTER_VAR:
- varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
- ecxt_outertuple);
- if (projInfo->pi_lastOuterVar < attnum)
- projInfo->pi_lastOuterVar = attnum;
- break;
-
- /* INDEX_VAR is handled by default case */
-
- default:
- varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
- ecxt_scantuple);
- if (projInfo->pi_lastScanVar < attnum)
- projInfo->pi_lastScanVar = attnum;
- break;
- }
- numSimpleVars++;
- }
- else
- {
- /* Not a simple variable, add it to generic targetlist */
- exprlist = lappend(exprlist, gstate);
- /* Examine expr to include contained Vars in lastXXXVar counts */
- ExecGetLastAttnums((Node *) variable,
- &projInfo->pi_lastOuterVar,
- &projInfo->pi_lastInnerVar,
- &projInfo->pi_lastScanVar);
- }
- }
- projInfo->pi_targetlist = exprlist;
- projInfo->pi_numSimpleVars = numSimpleVars;
- projInfo->pi_directMap = directMap;
-
- if (exprlist == NIL)
- projInfo->pi_itemIsDone = NULL; /* not needed */
- else
- projInfo->pi_itemIsDone = (ExprDoneCond *)
- palloc(len * sizeof(ExprDoneCond));
-
- return projInfo;
-}
-
/*
* get_last_attnums_walker: expression walker for ExecBuildProjectionInfo
*
@@ -691,9 +554,10 @@ ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc)
{
planstate->ps_ProjInfo =
- ExecBuildProjectionInfo(planstate->targetlist,
+ ExecBuildProjectionInfo(planstate->plan->targetlist,
planstate->ps_ExprContext,
planstate->ps_ResultTupleSlot,
+ planstate,
inputDesc);
}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index b3187e6..5046da4 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1571,12 +1571,10 @@ finalize_aggregates(AggState *aggstate,
static TupleTableSlot *
project_aggregates(AggState *aggstate)
{
- ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
-
/*
* Check the qual (HAVING clause); if the group does not match, ignore it.
*/
- if (ExecQual(aggstate->ss.ps.qual, econtext, false))
+ if (ExecQual(aggstate->ss.ps.qual))
{
/*
* Form and return or store a projection tuple using the aggregate
@@ -2414,9 +2412,10 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) aggstate);
- aggstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->plan.qual,
- (PlanState *) aggstate);
+ aggstate->ss.ps.qual =
+ ExecInitQual(node->plan.qual,
+ (PlanState *) aggstate,
+ aggstate->ss.ps.ps_ExprContext);
/*
* Initialize child nodes.
@@ -3094,9 +3093,10 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
errmsg("aggregate function calls cannot be nested")));
/* Set up projection info for evaluation */
- pertrans->evalproj = ExecBuildProjectionInfo(pertrans->args,
+ pertrans->evalproj = ExecBuildProjectionInfo(aggref->args,
aggstate->tmpcontext,
pertrans->evalslot,
+ (PlanState *) aggstate,
NULL);
/*
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 449aacb..f6cc996 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -286,7 +286,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
- if (!ExecQual(node->bitmapqualorig, econtext, false))
+ if (!ExecQual(node->bitmapqualorig))
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
@@ -427,7 +427,7 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
ResetExprContext(econtext);
- return ExecQual(node->bitmapqualorig, econtext, false);
+ return ExecQual(node->bitmapqualorig);
}
/* ----------------------------------------------------------------
@@ -583,12 +583,14 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
- scanstate->bitmapqualorig = (List *)
- ExecInitExpr((Expr *) node->bitmapqualorig,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
+ scanstate->bitmapqualorig =
+ ExecInitQual(node->bitmapqualorig,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 3c2f684..f723f37 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -242,9 +242,10 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 322abca..bdd7039 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -54,9 +54,10 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
css->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
(PlanState *) css);
- css->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) cscan->scan.plan.qual,
- (PlanState *) css);
+ css->ss.ps.qual =
+ ExecInitQual(cscan->scan.plan.qual,
+ (PlanState *) css,
+ css->ss.ps.ps_ExprContext);
/* tuple table initialization */
ExecInitScanTupleSlot(estate, &css->ss);
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index d886aaf..387320e 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -101,7 +101,7 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
!fdwroutine->RecheckForeignScan(node, slot))
return false;
- return ExecQual(node->fdw_recheck_quals, econtext, false);
+ return ExecQual(node->fdw_recheck_quals);
}
/* ----------------------------------------------------------------
@@ -160,12 +160,14 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
- scanstate->fdw_recheck_quals = (List *)
- ExecInitExpr((Expr *) node->fdw_recheck_quals,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
+ scanstate->fdw_recheck_quals =
+ ExecInitQual(node->fdw_recheck_quals,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index a03f6e7..47b890a 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -345,9 +345,10 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
scanstate->funcstates = palloc(nfuncs * sizeof(FunctionScanPerFuncState));
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 313b234..1b933ae 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -83,9 +83,10 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
gatherstate->ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) gatherstate);
- gatherstate->ps.qual = (List *)
- ExecInitExpr((Expr *) node->plan.qual,
- (PlanState *) gatherstate);
+ gatherstate->ps.qual =
+ ExecInitQual(node->plan.qual,
+ (PlanState *) gatherstate,
+ gatherstate->ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index dcf5175..1d61bc2 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -102,7 +102,7 @@ ExecGroup(GroupState *node)
* Check the qual (HAVING clause); if the group does not match, ignore
* it and fall into scan loop.
*/
- if (ExecQual(node->ss.ps.qual, econtext, false))
+ if (ExecQual(node->ss.ps.qual))
{
/*
* Form and return a projection tuple using the first input tuple.
@@ -165,7 +165,7 @@ ExecGroup(GroupState *node)
* Check the qual (HAVING clause); if the group does not match, ignore
* it and loop back to scan the rest of the group.
*/
- if (ExecQual(node->ss.ps.qual, econtext, false))
+ if (ExecQual(node->ss.ps.qual))
{
/*
* Form and return a projection tuple using the first input tuple.
@@ -226,9 +226,10 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
grpstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) grpstate);
- grpstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->plan.qual,
- (PlanState *) grpstate);
+ grpstate->ss.ps.qual =
+ ExecInitQual(node->plan.qual,
+ (PlanState *) grpstate,
+ grpstate->ss.ps.ps_ExprContext);
/*
* initialize child nodes
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 9ed09a7..85be8c2 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -193,9 +193,10 @@ ExecInitHash(Hash *node, EState *estate, int eflags)
hashstate->ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) hashstate);
- hashstate->ps.qual = (List *)
- ExecInitExpr((Expr *) node->plan.qual,
- (PlanState *) hashstate);
+ hashstate->ps.qual =
+ ExecInitQual(node->plan.qual,
+ (PlanState *) hashstate,
+ hashstate->ps.ps_ExprContext);
/*
* initialize child nodes
@@ -1064,7 +1065,7 @@ bool
ExecScanHashBucket(HashJoinState *hjstate,
ExprContext *econtext)
{
- List *hjclauses = hjstate->hashclauses;
+ ExprState2 *hjclauses = hjstate->hashclauses;
HashJoinTable hashtable = hjstate->hj_HashTable;
HashJoinTuple hashTuple = hjstate->hj_CurTuple;
uint32 hashvalue = hjstate->hj_CurHashValue;
@@ -1098,7 +1099,7 @@ ExecScanHashBucket(HashJoinState *hjstate,
/* reset temp memory each time to avoid leaks from qual expr */
ResetExprContext(econtext);
- if (ExecQual(hjclauses, econtext, false))
+ if (ExecQual(hjclauses))
{
hjstate->hj_CurTuple = hashTuple;
return true;
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 369e666..72044b6 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -63,8 +63,8 @@ ExecHashJoin(HashJoinState *node)
{
PlanState *outerNode;
HashState *hashNode;
- List *joinqual;
- List *otherqual;
+ ExprState2 *joinqual;
+ ExprState2 *otherqual;
ExprContext *econtext;
ExprDoneCond isDone;
HashJoinTable hashtable;
@@ -293,7 +293,7 @@ ExecHashJoin(HashJoinState *node)
* Only the joinquals determine tuple match status, but all
* quals must pass to actually return the tuple.
*/
- if (joinqual == NIL || ExecQual(joinqual, econtext, false))
+ if (joinqual == NULL || ExecQual(joinqual))
{
node->hj_MatchedOuter = true;
HeapTupleHeaderSetMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple));
@@ -312,8 +312,7 @@ ExecHashJoin(HashJoinState *node)
if (node->js.jointype == JOIN_SEMI)
node->hj_JoinState = HJ_NEED_NEW_OUTER;
- if (otherqual == NIL ||
- ExecQual(otherqual, econtext, false))
+ if (otherqual == NULL || ExecQual(otherqual))
{
TupleTableSlot *result;
@@ -351,8 +350,7 @@ ExecHashJoin(HashJoinState *node)
*/
econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;
- if (otherqual == NIL ||
- ExecQual(otherqual, econtext, false))
+ if (otherqual == NULL || ExecQual(otherqual))
{
TupleTableSlot *result;
@@ -390,8 +388,7 @@ ExecHashJoin(HashJoinState *node)
*/
econtext->ecxt_outertuple = node->hj_NullOuterTupleSlot;
- if (otherqual == NIL ||
- ExecQual(otherqual, econtext, false))
+ if (otherqual == NULL || ExecQual(otherqual))
{
TupleTableSlot *result;
@@ -465,16 +462,19 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
hjstate->js.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->join.plan.targetlist,
(PlanState *) hjstate);
- hjstate->js.ps.qual = (List *)
- ExecInitExpr((Expr *) node->join.plan.qual,
- (PlanState *) hjstate);
+ hjstate->js.ps.qual =
+ ExecInitQual(node->join.plan.qual,
+ (PlanState *) hjstate,
+ hjstate->js.ps.ps_ExprContext);
hjstate->js.jointype = node->join.jointype;
- hjstate->js.joinqual = (List *)
- ExecInitExpr((Expr *) node->join.joinqual,
- (PlanState *) hjstate);
- hjstate->hashclauses = (List *)
- ExecInitExpr((Expr *) node->hashclauses,
- (PlanState *) hjstate);
+ hjstate->js.joinqual =
+ ExecInitQual(node->join.joinqual,
+ (PlanState *) hjstate,
+ hjstate->js.ps.ps_ExprContext);
+ hjstate->hashclauses =
+ ExecInitQual(node->hashclauses,
+ (PlanState *) hjstate,
+ hjstate->js.ps.ps_ExprContext);
/*
* initialize child nodes
@@ -568,16 +568,13 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
lclauses = NIL;
rclauses = NIL;
hoperators = NIL;
- foreach(l, hjstate->hashclauses)
+ foreach(l, node->hashclauses)
{
- FuncExprState *fstate = (FuncExprState *) lfirst(l);
- OpExpr *hclause;
+ OpExpr *hclause = (OpExpr *) lfirst(l);;
- Assert(IsA(fstate, FuncExprState));
- hclause = (OpExpr *) fstate->xprstate.expr;
Assert(IsA(hclause, OpExpr));
- lclauses = lappend(lclauses, linitial(fstate->args));
- rclauses = lappend(rclauses, lsecond(fstate->args));
+ lclauses = lappend(lclauses, ExecInitExpr(linitial(hclause->args), (PlanState *) hjstate));
+ rclauses = lappend(rclauses, ExecInitExpr(lsecond(hclause->args), (PlanState *) hjstate));
hoperators = lappend_oid(hoperators, hclause->opno);
}
hjstate->hj_OuterHashKeys = lclauses;
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4f6f91c..a3e38df 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -157,7 +157,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
{
econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
- if (!ExecQual(node->indexqual, econtext, false))
+ if (!ExecQual(node->indexqual))
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
@@ -423,12 +423,14 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
indexstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) indexstate);
- indexstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) indexstate);
- indexstate->indexqual = (List *)
- ExecInitExpr((Expr *) node->indexqual,
- (PlanState *) indexstate);
+ indexstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) indexstate,
+ indexstate->ss.ps.ps_ExprContext);
+ indexstate->indexqual =
+ ExecInitQual(node->indexqual,
+ (PlanState *) indexstate,
+ indexstate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 3143bd9..b487119 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -122,7 +122,7 @@ IndexNext(IndexScanState *node)
{
econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
- if (!ExecQual(node->indexqualorig, econtext, false))
+ if (!ExecQual(node->indexqualorig))
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
@@ -241,7 +241,7 @@ next_indextuple:
{
econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
- if (!ExecQual(node->indexqualorig, econtext, false))
+ if (!ExecQual(node->indexqualorig))
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
@@ -362,7 +362,7 @@ IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
ResetExprContext(econtext);
- return ExecQual(node->indexqualorig, econtext, false);
+ return ExecQual(node->indexqualorig);
}
@@ -852,12 +852,14 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) indexstate);
- indexstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) indexstate);
- indexstate->indexqualorig = (List *)
- ExecInitExpr((Expr *) node->indexqualorig,
- (PlanState *) indexstate);
+ indexstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) indexstate,
+ indexstate->ss.ps.ps_ExprContext);
+ indexstate->indexqualorig =
+ ExecInitQual(node->indexqualorig,
+ (PlanState *) indexstate,
+ indexstate->ss.ps.ps_ExprContext);
indexstate->indexorderbyorig = (List *)
ExecInitExpr((Expr *) node->indexorderbyorig,
(PlanState *) indexstate);
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 6db09b8..3e7c500 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -452,14 +452,14 @@ static TupleTableSlot *
MJFillOuter(MergeJoinState *node)
{
ExprContext *econtext = node->js.ps.ps_ExprContext;
- List *otherqual = node->js.ps.qual;
+ ExprState2 *otherqual = node->js.ps.qual;
ResetExprContext(econtext);
econtext->ecxt_outertuple = node->mj_OuterTupleSlot;
econtext->ecxt_innertuple = node->mj_NullInnerTupleSlot;
- if (ExecQual(otherqual, econtext, false))
+ if (ExecQual(otherqual))
{
/*
* qualification succeeded. now form the desired projection tuple and
@@ -493,14 +493,14 @@ static TupleTableSlot *
MJFillInner(MergeJoinState *node)
{
ExprContext *econtext = node->js.ps.ps_ExprContext;
- List *otherqual = node->js.ps.qual;
+ ExprState2 *otherqual = node->js.ps.qual;
ResetExprContext(econtext);
econtext->ecxt_outertuple = node->mj_NullOuterTupleSlot;
econtext->ecxt_innertuple = node->mj_InnerTupleSlot;
- if (ExecQual(otherqual, econtext, false))
+ if (ExecQual(otherqual))
{
/*
* qualification succeeded. now form the desired projection tuple and
@@ -618,8 +618,8 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
TupleTableSlot *
ExecMergeJoin(MergeJoinState *node)
{
- List *joinqual;
- List *otherqual;
+ ExprState2 *joinqual;
+ ExprState2 *otherqual;
bool qualResult;
int compareResult;
PlanState *innerPlan;
@@ -823,8 +823,7 @@ ExecMergeJoin(MergeJoinState *node)
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
- qualResult = (joinqual == NIL ||
- ExecQual(joinqual, econtext, false));
+ qualResult = (joinqual == NULL || ExecQual(joinqual));
MJ_DEBUG_QUAL(joinqual, qualResult);
if (qualResult)
@@ -846,8 +845,7 @@ ExecMergeJoin(MergeJoinState *node)
if (node->js.jointype == JOIN_SEMI)
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
- qualResult = (otherqual == NIL ||
- ExecQual(otherqual, econtext, false));
+ qualResult = (otherqual == NULL || ExecQual(otherqual));
MJ_DEBUG_QUAL(otherqual, qualResult);
if (qualResult)
@@ -1507,13 +1505,15 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate->js.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->join.plan.targetlist,
(PlanState *) mergestate);
- mergestate->js.ps.qual = (List *)
- ExecInitExpr((Expr *) node->join.plan.qual,
- (PlanState *) mergestate);
+ mergestate->js.ps.qual =
+ ExecInitQual(node->join.plan.qual,
+ (PlanState *) mergestate,
+ mergestate->js.ps.ps_ExprContext);
mergestate->js.jointype = node->join.jointype;
- mergestate->js.joinqual = (List *)
- ExecInitExpr((Expr *) node->join.joinqual,
- (PlanState *) mergestate);
+ mergestate->js.joinqual =
+ ExecInitQual(node->join.joinqual,
+ (PlanState *) mergestate,
+ mergestate->js.ps.ps_ExprContext);
mergestate->mj_ConstFalseJoin = false;
/* mergeclauses are handled below */
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index af7b26c..8255688 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1067,7 +1067,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
{
ExprContext *econtext = mtstate->ps.ps_ExprContext;
Relation relation = resultRelInfo->ri_RelationDesc;
- List *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
+ ExprState2 *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
HeapTupleData tuple;
HeapUpdateFailureData hufd;
LockTupleMode lockmode;
@@ -1186,7 +1186,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
econtext->ecxt_innertuple = excludedSlot;
econtext->ecxt_outertuple = NULL;
- if (!ExecQual(onConflictSetWhere, econtext, false))
+ if (!ExecQual(onConflictSetWhere))
{
ReleaseBuffer(buffer);
InstrCountFiltered1(&mtstate->ps, 1);
@@ -1654,8 +1654,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
foreach(ll, wcoList)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
- ExprState *wcoExpr = ExecInitExpr((Expr *) wco->qual,
- mtstate->mt_plans[i]);
+ ExprState2 *wcoExpr = ExecInitQual((List *) wco->qual,
+ mtstate->mt_plans[i],
+ GetPerTupleExprContext(estate));
wcoExprs = lappend(wcoExprs, wcoExpr);
}
@@ -1687,8 +1688,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
slot = mtstate->ps.ps_ResultTupleSlot;
/* Need an econtext too */
- econtext = CreateExprContext(estate);
- mtstate->ps.ps_ExprContext = econtext;
+ if (mtstate->ps.ps_ExprContext == NULL)
+ ExecAssignExprContext(estate, &mtstate->ps);
+ econtext = mtstate->ps.ps_ExprContext;
/*
* Build a projection for each result rel.
@@ -1697,12 +1699,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
foreach(l, node->returningLists)
{
List *rlist = (List *) lfirst(l);
- List *rliststate;
- rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
resultRelInfo->ri_projectReturning =
- ExecBuildProjectionInfo(rliststate, econtext, slot,
- resultRelInfo->ri_RelationDesc->rd_att);
+ ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
+ resultRelInfo->ri_RelationDesc->rd_att);
resultRelInfo++;
}
}
@@ -1727,7 +1727,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (node->onConflictAction == ONCONFLICT_UPDATE)
{
ExprContext *econtext;
- ExprState *setexpr;
TupleDesc tupDesc;
/* insert may only have one plan, inheritance is not expanded */
@@ -1753,22 +1752,21 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc);
- /* build UPDATE SET expression and projection state */
- setexpr = ExecInitExpr((Expr *) node->onConflictSet, &mtstate->ps);
+ /* build UPDATE SET projection state */
resultRelInfo->ri_onConflictSetProj =
- ExecBuildProjectionInfo((List *) setexpr, econtext,
- mtstate->mt_conflproj,
+ ExecBuildProjectionInfo(node->onConflictSet, econtext,
+ mtstate->mt_conflproj, &mtstate->ps,
resultRelInfo->ri_RelationDesc->rd_att);
/* build DO UPDATE WHERE clause expression */
if (node->onConflictWhere)
{
- ExprState *qualexpr;
+ ExprState2 *qualexpr;
- qualexpr = ExecInitExpr((Expr *) node->onConflictWhere,
- &mtstate->ps);
+ qualexpr = ExecInitQual((List *) node->onConflictWhere,
+ &mtstate->ps, econtext);
- resultRelInfo->ri_onConflictSetWhere = (List *) qualexpr;
+ resultRelInfo->ri_onConflictSetWhere = qualexpr;
}
}
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 555fa09..6a8b674 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -64,8 +64,8 @@ ExecNestLoop(NestLoopState *node)
PlanState *outerPlan;
TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot;
- List *joinqual;
- List *otherqual;
+ ExprState2 *joinqual;
+ ExprState2 *otherqual;
ExprContext *econtext;
ListCell *lc;
@@ -194,7 +194,7 @@ ExecNestLoop(NestLoopState *node)
ENL1_printf("testing qualification for outer-join tuple");
- if (otherqual == NIL || ExecQual(otherqual, econtext, false))
+ if (otherqual == NULL || ExecQual(otherqual))
{
/*
* qualification was satisfied so we project and return
@@ -202,11 +202,12 @@ ExecNestLoop(NestLoopState *node)
* ExecProject().
*/
TupleTableSlot *result;
- ExprDoneCond isDone;
+ ExprDoneCond isDone = ExprSingleResult;
ENL1_printf("qualification succeeded, projecting tuple");
- result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
+ result = node->js.ps.ps_ResultTupleSlot;
+ ExecProjectIntoSlot(node->js.ps.ps_ProjInfo, result);
if (isDone != ExprEndResult)
{
@@ -235,7 +236,7 @@ ExecNestLoop(NestLoopState *node)
*/
ENL1_printf("testing qualification");
- if (ExecQual(joinqual, econtext, false))
+ if (ExecQual(joinqual))
{
node->nl_MatchedOuter = true;
@@ -253,7 +254,7 @@ ExecNestLoop(NestLoopState *node)
if (node->js.jointype == JOIN_SEMI)
node->nl_NeedNewOuter = true;
- if (otherqual == NIL || ExecQual(otherqual, econtext, false))
+ if (otherqual == NULL || ExecQual(otherqual))
{
/*
* qualification was satisfied so we project and return the
@@ -323,13 +324,15 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
nlstate->js.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->join.plan.targetlist,
(PlanState *) nlstate);
- nlstate->js.ps.qual = (List *)
- ExecInitExpr((Expr *) node->join.plan.qual,
- (PlanState *) nlstate);
+ nlstate->js.ps.qual =
+ ExecInitQual(node->join.plan.qual,
+ (PlanState *) nlstate,
+ nlstate->js.ps.ps_ExprContext);
nlstate->js.jointype = node->join.jointype;
- nlstate->js.joinqual = (List *)
- ExecInitExpr((Expr *) node->join.joinqual,
- (PlanState *) nlstate);
+ nlstate->js.joinqual =
+ ExecInitQual(node->join.joinqual,
+ (PlanState *) nlstate,
+ nlstate->js.ps.ps_ExprContext);
/*
* initialize child nodes
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 4007b76..41d53f2 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -79,9 +79,7 @@ ExecResult(ResultState *node)
*/
if (node->rs_checkqual)
{
- bool qualResult = ExecQual((List *) node->resconstantqual,
- econtext,
- false);
+ bool qualResult = ExecQual(node->resconstantqual);
node->rs_checkqual = false;
if (!qualResult)
@@ -241,11 +239,14 @@ ExecInitResult(Result *node, EState *estate, int eflags)
resstate->ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) resstate);
- resstate->ps.qual = (List *)
- ExecInitExpr((Expr *) node->plan.qual,
- (PlanState *) resstate);
- resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
- (PlanState *) resstate);
+ resstate->ps.qual =
+ ExecInitQual(node->plan.qual,
+ (PlanState *) resstate,
+ resstate->ps.ps_ExprContext);
+ resstate->resconstantqual =
+ ExecInitQual((List *) node->resconstantqual,
+ (PlanState *) resstate,
+ resstate->ps.ps_ExprContext);
/*
* initialize child nodes
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 9ce7c02..6ebc330 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -166,9 +166,10 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
scanstate->args = (List *)
ExecInitExpr((Expr *) tsc->args,
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 00bf3a5..13a84c5 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -191,9 +191,10 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->plan.qual,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e503494..30c0e33 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -126,7 +126,9 @@ ExecHashSubPlan(SubPlanState *node,
/*
* Evaluate lefthand expressions and form a projection tuple. First we
* have to set the econtext to use (hack alert!).
+ * FIXME: unlikely to still work
*/
+ elog(ERROR, "borked atm");
node->projLeft->pi_exprContext = econtext;
slot = ExecProject(node->projLeft, NULL);
@@ -908,21 +910,25 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
* Fortunately we can just pass NULL for now and fill it in later
* (hack alert!). The righthand expressions will be evaluated in our
* own innerecontext.
+ *
+ * FIXME
*/
tupDesc = ExecTypeFromTL(leftptlist, false);
slot = ExecInitExtraTupleSlot(estate);
ExecSetSlotDescriptor(slot, tupDesc);
- sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
- NULL,
+ sstate->projLeft = ExecBuildProjectionInfo(leftptlist,
+ sstate->innerecontext /* FIXME */,
slot,
+ sstate->planstate,
NULL);
tupDesc = ExecTypeFromTL(rightptlist, false);
slot = ExecInitExtraTupleSlot(estate);
ExecSetSlotDescriptor(slot, tupDesc);
- sstate->projRight = ExecBuildProjectionInfo(righttlist,
+ sstate->projRight = ExecBuildProjectionInfo(rightptlist,
sstate->innerecontext,
slot,
+ sstate->planstate,
NULL);
}
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 9bafc62..1e3a228 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -123,9 +123,10 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
subquerystate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) subquerystate);
- subquerystate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) subquerystate);
+ subquerystate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) subquerystate,
+ subquerystate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 2604103..e47e280 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -477,9 +477,10 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
tidstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) tidstate);
- tidstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) tidstate);
+ tidstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) tidstate,
+ tidstate->ss.ps.ps_ExprContext);
tidstate->tss_tidquals = (List *)
ExecInitExpr((Expr *) node->tidquals,
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 9c03f8a..0f3ef05 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -246,9 +246,10 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
/*
* get info about values list
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index d4c88a1..d2dfcb4 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1838,7 +1838,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
* logical top level of a query (ie, after any WHERE or HAVING filters)
*/
Assert(node->plan.qual == NIL);
- winstate->ss.ps.qual = NIL;
+ winstate->ss.ps.qual = NULL;
/*
* initialize child nodes
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index cfed6e6..352d1cd 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -159,9 +159,10 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
- scanstate->ss.ps.qual = (List *)
- ExecInitExpr((Expr *) node->scan.plan.qual,
- (PlanState *) scanstate);
+ scanstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual,
+ (PlanState *) scanstate,
+ scanstate->ss.ps.ps_ExprContext);
/*
* tuple table initialization
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index d4a5e7c..4b9d0a2 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -2012,8 +2012,8 @@ setup_privileges(FILE *cmdfd)
"UPDATE pg_class "
" SET relacl = (SELECT array_agg(a.acl) FROM "
" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
- " UNION SELECT unnest(pg_catalog.acldefault("
- " CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\",10::oid))"
+ " UNION SELECT * FROM unnest(pg_catalog.acldefault("
+ " CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\",10::oid)) un"
" ) as a) "
" WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n\n",
"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index e5c0a56..8766d09 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -243,11 +243,41 @@ extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econt
bool *isNull, ExprDoneCond *isDone);
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
-extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
+extern ExprState2 *ExecInitExpr2(Expr *node, PlanState *parent, ExprContext *context);
+extern ExprState2 *ExecPrepareQual(List *qual, EState *estate);
+extern ExprState2 *ExecPrepareCheck(List *qual, EState *estate);
+extern ExprState2 *ExecInitQual(List *qual, PlanState *parent, ExprContext *context);
+extern ExprState2 *ExecInitCheck(List *qual, PlanState *parent, ExprContext *context);
+
+extern Datum ExecEvalExpr2(ExprState2 *state, bool *isnull);
+extern bool ExecQual(ExprState2 *state);
+extern bool ExecCheck(ExprState2 *state);
extern int ExecTargetListLength(List *targetlist);
extern int ExecCleanTargetListLength(List *targetlist);
-extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
- ExprDoneCond *isDone);
+
+extern void ExecProjectIntoSlot(ProjectionInfo *projInfo,
+ TupleTableSlot *slot);
+/*
+ * ExecProject
+ *
+ * projects a tuple based on projection info and stores
+ * it in the previously specified tuple table slot.
+ *
+ * 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.
+ */
+static inline TupleTableSlot *
+ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
+{
+ if (isDone)
+ *isDone = ExprSingleResult;
+ ExecProjectIntoSlot(projInfo, projInfo->pi_slot);
+ return projInfo->pi_slot;
+}
/*
* prototypes from functions in execScan.c
@@ -345,6 +375,7 @@ extern void ExecGetLastAttnums(Node *node,
extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList,
ExprContext *econtext,
TupleTableSlot *slot,
+ PlanState *planstate,
TupleDesc inputDesc);
extern void ExecAssignProjectionInfo(PlanState *planstate,
TupleDesc inputDesc);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e7fd7bd..b083629 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -26,6 +26,112 @@
#include "utils/tuplesort.h"
+typedef struct ExprState ExprState;
+typedef struct ExprState2 ExprState2;
+
+
+
+typedef enum ExprEvalOp
+{
+ EEO_VAR,
+ EEO_SYSVAR,
+ EEO_CONST,
+ EEO_FUNCEXPR,
+ EEO_FUNCEXPR_STRICT,
+ EEO_FUNCEXPR_FUSAGE,
+ EEO_FUNCEXPR_STRICT_FUSAGE,
+ EEO_BOOL_AND_STEP_FIRST,
+ EEO_BOOL_AND_STEP,
+ EEO_BOOL_OR_STEP_FIRST,
+ EEO_BOOL_OR_STEP,
+ EEO_BOOL_NOT_STEP,
+ EEO_FETCHSOMEATTRS,
+ EEO_ASSIGN_VAR,
+ EEO_ASSIGN_TMP,
+ EEO_EVAL1,
+ EEO_ASSIGN_EVAL1,
+ EEO_DONE
+} ExprEvalOp;
+
+typedef struct ExprEvalStep
+{
+ ExprEvalOp opcode;
+ bool *resnull;
+ Datum *resvalue;
+ union
+ {
+ struct
+ {
+ TupleTableSlot **slot;
+ int attnum;
+ } var;
+
+ struct
+ {
+ Datum value;
+ bool isnull;
+ } constval;
+
+ struct
+ {
+ FmgrInfo *finfo;
+ FunctionCallInfo fcinfo_data;
+ PGFunction fn_addr;
+ int nargs;
+ } func;
+
+ struct
+ {
+ Datum *value;
+ bool *isnull;
+ bool *anynull;
+ int jumpdone;
+ } boolexpr;
+
+ struct
+ {
+ TupleTableSlot **slot;
+ size_t resultnum;
+ int attnum;
+ } assign_var;
+
+ struct
+ {
+ size_t resultnum;
+ } assign_tmp;
+
+ struct
+ {
+ TupleTableSlot **slot;
+ int last_var;
+ } fetch;
+
+ struct
+ {
+ ExprState *expr;
+ } eval1;
+
+ struct
+ {
+ ExprState *expr;
+ size_t resultnum;
+ } assign_eval1;
+ } d;
+} ExprEvalStep;
+
+struct ExprState2
+{
+ Node tag;
+ bool failed;
+ size_t steps_alloc;
+ size_t steps_len;
+ ExprEvalStep *steps;
+ Datum resvalue;
+ bool resnull;
+ struct ExprContext *econtext;
+ TupleTableSlot *resultslot;
+};
+
/* ----------------
* IndexInfo information
*
@@ -63,7 +169,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 */
+ ExprState2 *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 */
@@ -205,53 +311,16 @@ typedef struct ReturnSetInfo
* that is, form new tuples by evaluation of targetlist expressions.
* Nodes which need to do projections create one of these.
*
- * 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
- * itemIsDone workspace array for ExecProject
- * 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;
+ ExprState2 pi_state;
ExprContext *pi_exprContext;
TupleTableSlot *pi_slot;
- ExprDoneCond *pi_itemIsDone;
- 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;
/* ----------------
@@ -331,18 +400,18 @@ typedef struct ResultRelInfo
IndexInfo **ri_IndexRelationInfo;
TriggerDesc *ri_TrigDesc;
FmgrInfo *ri_TrigFunctions;
- List **ri_TrigWhenExprs;
+ ExprState2 **ri_TrigWhenExprs;
Instrumentation *ri_TrigInstrument;
struct FdwRoutine *ri_FdwRoutine;
void *ri_FdwState;
bool ri_usesFdwDirectModify;
List *ri_WithCheckOptions;
List *ri_WithCheckOptionExprs;
- List **ri_ConstraintExprs;
+ ExprState2 **ri_ConstraintExprs;
JunkFilter *ri_junkFilter;
ProjectionInfo *ri_projectReturning;
ProjectionInfo *ri_onConflictSetProj;
- List *ri_onConflictSetWhere;
+ ExprState2 *ri_onConflictSetWhere;
} ResultRelInfo;
/* ----------------
@@ -1039,7 +1108,7 @@ typedef struct PlanState
* 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 */
+ ExprState2 *qual; /* implicitly-ANDed qual conditions */
struct PlanState *lefttree; /* input plan tree(s) */
struct PlanState *righttree;
List *initPlan; /* Init SubPlanState nodes (un-correlated expr
@@ -1106,7 +1175,7 @@ typedef struct EPQState
typedef struct ResultState
{
PlanState ps; /* its first field is NodeTag */
- ExprState *resconstantqual;
+ ExprState2 *resconstantqual;
bool rs_done; /* are we done? */
bool rs_checkqual; /* do we need to check the qual? */
} ResultState;
@@ -1329,7 +1398,7 @@ typedef struct
typedef struct IndexScanState
{
ScanState ss; /* its first field is NodeTag */
- List *indexqualorig;
+ ExprState2 *indexqualorig;
List *indexorderbyorig;
ScanKey iss_ScanKeys;
int iss_NumScanKeys;
@@ -1373,7 +1442,7 @@ typedef struct IndexScanState
typedef struct IndexOnlyScanState
{
ScanState ss; /* its first field is NodeTag */
- List *indexqual;
+ ExprState2 *indexqual;
ScanKey ioss_ScanKeys;
int ioss_NumScanKeys;
ScanKey ioss_OrderByKeys;
@@ -1438,7 +1507,7 @@ typedef struct BitmapIndexScanState
typedef struct BitmapHeapScanState
{
ScanState ss; /* its first field is NodeTag */
- List *bitmapqualorig;
+ ExprState2 *bitmapqualorig;
TIDBitmap *tbm;
TBMIterator *tbmiterator;
TBMIterateResult *tbmres;
@@ -1462,7 +1531,7 @@ typedef struct BitmapHeapScanState
typedef struct TidScanState
{
ScanState ss; /* its first field is NodeTag */
- List *tss_tidquals; /* list of ExprState nodes */
+ List *tss_tidquals;
bool tss_isCurrentOf;
int tss_NumTids;
int tss_TidPtr;
@@ -1586,7 +1655,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 */
+ ExprState2 *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;
@@ -1632,7 +1701,7 @@ typedef struct JoinState
{
PlanState ps;
JoinType jointype;
- List *joinqual; /* JOIN quals (in addition to ps.qual) */
+ ExprState2 *joinqual; /* JOIN quals (in addition to ps.qual) */
} JoinState;
/* ----------------
@@ -1730,7 +1799,7 @@ typedef struct HashJoinTableData *HashJoinTable;
typedef struct HashJoinState
{
JoinState js; /* its first field is NodeTag */
- List *hashclauses; /* list of ExprState nodes */
+ ExprState2 *hashclauses;
List *hj_OuterHashKeys; /* list of ExprState nodes */
List *hj_InnerHashKeys; /* list of ExprState nodes */
List *hj_HashOperators; /* list of operator OIDs */
@@ -1852,6 +1921,12 @@ typedef struct AggState
/* these fields are used in AGG_HASHED mode: */
TupleHashTable hashtable; /* hash table with one entry per group */
TupleTableSlot *hashslot; /* slot for loading hash table */
+
+ /* Stuff for evaluation of agg inputs. */
+ TupleTableSlot *evalslot; /* slot for agg inputs */
+ ProjectionInfo *evalproj; /* projection machinery */
+ TupleDesc evaldesc; /* descriptor of input tuples */
+
List *hash_needed; /* list of columns needed in hash table */
bool table_filled; /* hash table filled yet? */
TupleHashIterator hashiter; /* for iterating through hash table */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 6b850e4..0f503d3 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -33,6 +33,7 @@ typedef enum NodeTag
T_IndexInfo = 10,
T_ExprContext,
T_ProjectionInfo,
+ T_FastProjectionInfo,
T_JunkFilter,
T_ResultRelInfo,
T_EState,
@@ -188,6 +189,7 @@ typedef enum NodeTag
* from Expr.
*/
T_ExprState = 400,
+ T_ExprState2,
T_GenericExprState,
T_WholeRowVarExprState,
T_AggrefExprState,
--
2.8.1
--jfd4diy4zttxubog
Content-Type: text/x-patch; charset=us-ascii
Content-Disposition: attachment;
filename="0004-WIP-Optimize-slot_deform_tuple-significantly.patch"
view thread (21+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [PATCH 03/20] WIP: Faster expression processing and targetlist projection.
In-Reply-To: <no-message-id-586300@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox