You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by in...@apache.org on 2018/04/19 10:28:40 UTC
[3/3] incubator-hawq git commit: HAWQ-1603. Add new hook API
HAWQ-1603. Add new hook API
Project: http://git-wip-us.apache.org/repos/asf/incubator-hawq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-hawq/commit/80eaf448
Tree: http://git-wip-us.apache.org/repos/asf/incubator-hawq/tree/80eaf448
Diff: http://git-wip-us.apache.org/repos/asf/incubator-hawq/diff/80eaf448
Branch: refs/heads/master
Commit: 80eaf448f01c9422f1d7631527026804f954b252
Parents: f68cac7
Author: Shujie Zhang <sh...@Shujie-Zhangs-MacBook-Pro.local>
Authored: Wed Apr 4 16:10:07 2018 +0800
Committer: interma <in...@outlook.com>
Committed: Thu Apr 19 18:27:54 2018 +0800
----------------------------------------------------------------------
contrib/vexecutor/execVQual.c | 574 +-
contrib/vexecutor/execVQual.h | 7 +-
contrib/vexecutor/execVScan.c | 43 +-
contrib/vexecutor/vadt.c | 66 +-
contrib/vexecutor/vexecutor.c | 83 +-
contrib/vexecutor/vexecutor.h | 1 +
src/backend/executor/execMain.c | 5 +
src/backend/executor/execProcnode.c | 20 +-
src/backend/executor/execQual.c | 10 +
src/include/executor/executor.h | 4 +-
src/test/feature/vexecutor/ans/.DS_Store | Bin 0 -> 6148 bytes
src/test/feature/vexecutor/ans/projandqual.ans | 40 +
src/test/feature/vexecutor/ans/scan1.ans | 19743 +++++++++---------
src/test/feature/vexecutor/sql/projandqual.sql | 4 +
src/test/feature/vexecutor/sql/scan1.sql | 2 +-
src/test/feature/vexecutor/test_vexecutor.cpp | 19 +
16 files changed, 10657 insertions(+), 9964 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/contrib/vexecutor/execVQual.c
----------------------------------------------------------------------
diff --git a/contrib/vexecutor/execVQual.c b/contrib/vexecutor/execVQual.c
index c4ccf9e..83e298a 100644
--- a/contrib/vexecutor/execVQual.c
+++ b/contrib/vexecutor/execVQual.c
@@ -16,8 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
+#include "postgres.h"
+#include "utils/builtins.h"
#include "execVQual.h"
-
+static bool
+ExecVTargetList(List *targetlist,
+ ExprContext *econtext,
+ TupleTableSlot *slot,
+ ExprDoneCond *itemIsDone,
+ ExprDoneCond *isDone);
/*
* ExecVariableList
* Evaluates a simple-Variable-list projection.
@@ -26,12 +33,12 @@
*/
static void
ExecVecVariableList(ProjectionInfo *projInfo,
- Datum *values)
+ Datum values)
{
ExprContext *econtext = projInfo->pi_exprContext;
int *varSlotOffsets = projInfo->pi_varSlotOffsets;
int *varNumbers = projInfo->pi_varNumbers;
- TupleBatch tb = (TupleBatch) values;
+ TupleBatch tb = (TupleBatch) DatumGetPointer(values);
int i;
tb->ncols = list_length(projInfo->pi_targetlist);
@@ -81,14 +88,12 @@ ExecVProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
}
else
{
- elog(FATAL,"does not support expression in projection stmt");
- // if (ExecTargetList(projInfo->pi_targetlist,
- // projInfo->pi_exprContext,
- // slot_get_values(slot),
- // slot_get_isnull(slot),
- // (ExprDoneCond *) projInfo->pi_itemIsDone,
- // isDone))
- // ExecStoreVirtualTuple(slot);
+ if (ExecVTargetList(projInfo->pi_targetlist,
+ projInfo->pi_exprContext,
+ slot,
+ (ExprDoneCond *) projInfo->pi_itemIsDone,
+ isDone))
+ ExecStoreVirtualTuple(slot);
}
return slot;
@@ -104,7 +109,7 @@ VirtualNodeProc(ScanState* state,TupleTableSlot *slot){
if(TupIsNull(slot) )
return false;
- TupleBatch tb = slot->PRIVATE_tb;
+ TupleBatch tb = (TupleBatch)DatumGetPointer(slot->PRIVATE_tb);
ExecClearTuple(slot);
while (tb->skip[tb->iter] && tb->iter < tb->nrows)
@@ -123,3 +128,548 @@ VirtualNodeProc(ScanState* state,TupleTableSlot *slot){
ExecStoreVirtualTuple(slot);
return true;
}
+
+/*
+ * get values from vectorized tuple slot
+ * copy from src/backend/executor/execQual.c
+ */
+static Datum
+VExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ Var *variable = (Var *) exprstate->expr;
+ TupleTableSlot *slot;
+ AttrNumber attnum;
+ TupleBatch tb;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ Assert(econtext->ecxt_scantuple != NULL || econtext->ecxt_innertuple != NULL || econtext->ecxt_outertuple != NULL);
+ /*
+ * Get the input slot and attribute number we want
+ *
+ * The asserts check that references to system attributes only appear at
+ * the level of a relation scan; at higher levels, system attributes must
+ * be treated as ordinary variables (since we no longer have access to the
+ * original tuple).
+ */
+ attnum = variable->varattno;
+
+ switch (variable->varno)
+ {
+ case INNER: /* get the tuple from the inner node */
+ slot = econtext->ecxt_innertuple;
+ Assert(attnum > 0);
+ break;
+
+ case OUTER: /* get the tuple from the outer node */
+ slot = econtext->ecxt_outertuple;
+ Assert(attnum > 0);
+ break;
+
+ default: /* get the tuple from the relation being
+ * scanned */
+ slot = econtext->ecxt_scantuple;
+ break;
+ }
+
+ /* isNull is a single value, it can not be used when data is vectorized */
+ *isNull = false;
+
+ /* Fetch the value from the slot */
+ Assert(NULL != slot);
+ tb = (TupleBatch )slot->PRIVATE_tb;
+
+ Assert(NULL != tb);
+
+ return PointerGetDatum(tb->datagroup[attnum - 1]);
+}
+
+
+/*
+ * get values from vectorized tuple slot
+ * copy from src/backend/executor/execQual.c
+ */
+static Datum
+VExecEvalVar(ExprState *exprstate, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ Var *variable = (Var *) exprstate->expr;
+ TupleTableSlot *slot;
+ AttrNumber attnum;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ Assert(econtext->ecxt_scantuple != NULL || econtext->ecxt_innertuple != NULL || econtext->ecxt_outertuple != NULL);
+ /*
+ * Get the input slot and attribute number we want
+ *
+ * The asserts check that references to system attributes only appear at
+ * the level of a relation scan; at higher levels, system attributes must
+ * be treated as ordinary variables (since we no longer have access to the
+ * original tuple).
+ */
+ attnum = variable->varattno;
+
+ switch (variable->varno)
+ {
+ case INNER: /* get the tuple from the inner node */
+ slot = econtext->ecxt_innertuple;
+ Assert(attnum > 0);
+ break;
+
+ case OUTER: /* get the tuple from the outer node */
+ slot = econtext->ecxt_outertuple;
+ Assert(attnum > 0);
+ break;
+
+ default: /* get the tuple from the relation being
+ * scanned */
+ slot = econtext->ecxt_scantuple;
+ break;
+ }
+
+ Assert(NULL != slot);
+
+ if (attnum != InvalidAttrNumber)
+ {
+ TupleBatch tb;
+ /*
+ * Scalar variable case.
+ *
+ * If it's a user attribute, check validity (bogus system attnums will
+ * be caught inside slot_getattr). What we have to check for here
+ * is the possibility of an attribute having been changed in type
+ * since the plan tree was created. Ideally the plan would get
+ * invalidated and not re-used, but until that day arrives, we need
+ * defenses. Fortunately it's sufficient to check once on the first
+ * time through.
+ *
+ * Note: we allow a reference to a dropped attribute. slot_getattr
+ * will force a NULL result in such cases.
+ *
+ * Note: ideally we'd check typmod as well as typid, but that seems
+ * impractical at the moment: in many cases the tupdesc will have
+ * been generated by ExecTypeFromTL(), and that can't guarantee to
+ * generate an accurate typmod in all cases, because some expression
+ * node types don't carry typmod.
+ */
+ if (attnum > 0)
+ {
+ TupleDesc slot_tupdesc = slot->tts_tupleDescriptor;
+ Form_pg_attribute attr;
+
+ if (attnum > slot_tupdesc->natts) /* should never happen */
+ elog(ERROR, "attribute number %d exceeds number of columns %d",
+ attnum, slot_tupdesc->natts);
+
+ attr = slot_tupdesc->attrs[attnum - 1];
+
+ /* can't check type if dropped, since atttypid is probably 0 */
+ if (!attr->attisdropped)
+ {
+ if (variable->vartype != attr->atttypid &&
+ GetNType(variable->vartype) != attr->atttypid)
+ ereport(ERROR,
+ (errmsg("attribute %d has wrong type", attnum),
+ errdetail("Table has type %s, but query expects %s.",
+ format_type_be(attr->atttypid),
+ format_type_be(variable->vartype))));
+ }
+ }
+
+ /* Skip the checking on future executions of node */
+ exprstate->evalfunc = VExecEvalScalarVar;
+
+ /* isNull is a single value, it can not be used when data is vectorized */
+ *isNull = false;
+
+ /* Fetch the value from the slot */
+ tb = (TupleBatch )slot->PRIVATE_tb;
+
+ Assert(NULL != tb);
+ return PointerGetDatum(tb->datagroup[attnum - 1]);
+ }
+ else
+ {
+ /* NOT support so far */
+ Assert(false);
+ }
+
+ return PointerGetDatum(NULL);
+}
+
+
+/* ----------------------------------------------------------------
+ * VExecEvalNot
+ * VExecEvalOr
+ * VExecEvalAnd
+ *
+ * copy from src/backend/executor/execQual.c
+ *
+ * Evaluate boolean expressions, with appropriate short-circuiting.
+ *
+ * The query planner reformulates clause expressions in the
+ * qualification to conjunctive normal form. If we ever get
+ * an AND to evaluate, we can be sure that it's not a top-level
+ * clause in the qualification, but appears lower (as a function
+ * argument, for example), or in the target list. Not that you
+ * need to know this, mind you...
+ * ----------------------------------------------------------------
+ */
+static Datum
+VExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ ExprState *clause = linitial(notclause->args);
+ Datum expr_value;
+ vbool *ret;
+ int i;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ expr_value = ExecEvalExpr(clause, econtext, isNull, NULL);
+
+ ret = (vbool*)DatumGetPointer(expr_value);
+ for(i = 0; i < ret->header.dim; i++)
+ {
+ if(!ret->header.isnull[i])
+ ret->values[i] = !ret->values[i];
+ }
+
+ /*
+ * evaluation of 'not' is simple.. expr is false, then return 'true' and
+ * vice versa.
+ */
+ return PointerGetDatum(ret);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalOr
+ * ----------------------------------------------------------------
+ */
+static Datum
+VExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ List *clauses = orExpr->args;
+ ListCell *clause;
+ vbool *res = NULL;
+ vbool *next = NULL;
+ bool skip = true;
+ int i = 0;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ /*
+ * If any of the clauses is TRUE, the OR result is TRUE regardless of the
+ * states of the rest of the clauses, so we can stop evaluating and return
+ * TRUE immediately. If none are TRUE and one or more is NULL, we return
+ * NULL; otherwise we return FALSE. This makes sense when you interpret
+ * NULL as "don't know": if we have a TRUE then the OR is TRUE even if we
+ * aren't sure about some of the other inputs. If all the known inputs are
+ * FALSE, but we have one or more "don't knows", then we have to report
+ * that we "don't know" what the OR's result should be --- perhaps one of
+ * the "don't knows" would have been TRUE if we'd known its value. Only
+ * when all the inputs are known to be FALSE can we state confidently that
+ * the OR's result is FALSE.
+ */
+ foreach(clause, clauses)
+ {
+ ExprState *clausestate = (ExprState *) lfirst(clause);
+ Datum clause_value;
+
+ /*
+ * to check if all the values is true, then skip to evaluate some
+ * expressions
+ */
+ skip = true;
+
+ clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
+
+ if(NULL == res)
+ {
+ res = DatumGetPointer(clause_value);
+ Assert(NULL != res->header.isnull);
+ for(i = 0; i < res->header.dim; i++)
+ {
+ if(res->header.isnull[i] ||
+ !res->values[i])
+ {
+ skip = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ next = DatumGetPointer(clause_value);
+ Assert(NULL != res->header.isnull && NULL != next->header.isnull);
+ for(i = 0; i < res->header.dim; i++)
+ {
+ res->header.isnull[i] =
+ (res->header.isnull[i] || next->header.isnull[i]);
+ res->values[i] = (res->values[i] || next->values[i]);
+ if(skip && (res->header.isnull[i] || !res->values[i]))
+ skip = false;
+ }
+ }
+
+ if(skip)
+ {
+ *isNull = false;
+ return PointerGetDatum(res);
+ }
+ }
+
+ *isNull = false;
+ return PointerGetDatum(res);
+}
+
+static Datum
+VExecEvalAndInternal(List* clauses, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ ListCell *clause;
+ vbool *res = NULL;
+ vbool *next = NULL;
+ bool skip = true;
+ int i = 0;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ /*
+ * If any of the clauses is FALSE, the AND result is FALSE regardless of
+ * the states of the rest of the clauses, so we can stop evaluating and
+ * return FALSE immediately. If none are FALSE and one or more is NULL,
+ * we return NULL; otherwise we return TRUE. This makes sense when you
+ * interpret NULL as "don't know", using the same sort of reasoning as for
+ * OR, above.
+ */
+
+ foreach(clause, clauses)
+ {
+ ExprState *clausestate = (ExprState *) lfirst(clause);
+ Datum clause_value;
+
+ /*
+ * to check if all the values is false, then skip to evaluate some
+ * expressions
+ */
+ skip = true;
+
+ clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
+
+ if(NULL == res)
+ {
+ res = DatumGetPointer(clause_value);
+ Assert(NULL != res->header.isnull);
+ for(i = 0; i < res->header.dim; i++)
+ {
+ if(res->header.isnull[i] || res->values[i])
+ {
+ skip = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ next = DatumGetPointer(clause_value);
+ Assert(NULL != res->header.isnull && NULL != next->header.isnull);
+ for(i = 0; i < res->header.dim; i++)
+ {
+ res->header.isnull[i] =
+ (res->header.isnull[i] || next->header.isnull[i]);
+ res->values[i] = (res->values[i] && next->values[i]);
+ if(skip && (res->header.isnull[i] || res->values[i]))
+ skip = false;
+ }
+ }
+
+ if(skip)
+ {
+ *isNull = false;
+ return PointerGetDatum(res);
+ }
+ }
+
+ *isNull = false;
+ return PointerGetDatum(res);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalAnd
+ * ----------------------------------------------------------------
+ */
+static Datum
+VExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ return VExecEvalAndInternal(andExpr->args, econtext, isNull, isDone);
+}
+
+/*
+ * Init the vectorized expressions
+ */
+ExprState *
+VExecInitExpr(Expr *node, PlanState *parent)
+{
+ ExprState *state = NULL;
+
+ /*
+ * Because Var is the leaf node of the expression tree, it have to be
+ * refactored first, otherwise the all call stack should be refactored.
+ */
+ switch (nodeTag(node))
+ {
+ case T_Var:
+ state = (ExprState *) makeNode(ExprState);
+ state->evalfunc = VExecEvalVar;
+ break;
+ case T_BoolExpr:
+ {
+ BoolExpr *boolexpr = (BoolExpr *) node;
+ BoolExprState *bstate = makeNode(BoolExprState);
+
+ switch (boolexpr->boolop)
+ {
+ case AND_EXPR:
+ bstate->xprstate.evalfunc = (ExprStateEvalFunc) VExecEvalAnd;
+ break;
+ case OR_EXPR:
+ bstate->xprstate.evalfunc = (ExprStateEvalFunc) VExecEvalOr;
+ break;
+ case NOT_EXPR:
+ bstate->xprstate.evalfunc = (ExprStateEvalFunc) VExecEvalNot;
+ break;
+ default:
+ elog(ERROR, "unrecognized boolop: %d",
+ (int) boolexpr->boolop);
+ break;
+ }
+ bstate->args = (List *)
+ ExecInitExpr((Expr *) boolexpr->args, parent);
+ state = (ExprState *) bstate;
+ }
+ break;
+
+ /*TODO: More and more expressions should be vectorized */
+ default:
+ break;
+ }
+
+ /* Common code for all state-node types */
+ if(NULL != state)
+ state->expr = node;
+
+ return state;
+}
+
+/* ----------------------------------------------------------------
+ * copy from src/backend/executor/execQual.c
+ *
+ * NOTE:resultForNull do not used now, we can process it when call the
+ * ExecVQual.
+ * ----------------------------------------------------------------
+ */
+vbool*
+ExecVQual(List *qual, ExprContext *econtext, bool resultForNull)
+{
+ vbool *result;
+ MemoryContext oldContext;
+ bool isNull;
+
+ /*
+ * 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);
+
+ result = (vbool*)DatumGetPointer(VExecEvalAndInternal(qual, econtext, &isNull, NULL));
+
+ MemoryContextSwitchTo(oldContext);
+
+ return result;
+}
+
+/*
+ * copy from src/backend/executor/ExecQual.c
+ * 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.
+ */
+static bool
+ExecVTargetList(List *targetlist,
+ ExprContext *econtext,
+ TupleTableSlot *slot,
+ ExprDoneCond *itemIsDone,
+ ExprDoneCond *isDone)
+{
+ MemoryContext oldContext;
+ ListCell *tl;
+ TupleBatch tb;
+ bool isnull;
+
+ Assert(NULL != slot);
+
+ tb = (TupleBatch)DatumGetPointer(slot->PRIVATE_tb);
+
+ Assert(NULL != tb);
+
+ tb->ncols = list_length(targetlist);
+
+ /*
+ * 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
+ */
+ if (isDone)
+ *isDone = ExprSingleResult; /* until proven otherwise */
+
+ foreach(tl, targetlist)
+ {
+ GenericExprState *gstate = (GenericExprState *) lfirst(tl);
+ TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
+ AttrNumber resind = tle->resno - 1;
+
+ tb->datagroup[resind] = ExecEvalExpr(gstate->arg,
+ econtext,
+ &isnull,
+ &itemIsDone[resind]);
+
+ if (itemIsDone[resind] != ExprSingleResult)
+ {
+ /*TODO: DO NOT SUPPORT SO FAR*/
+ elog(ERROR, "Only support single result so far.");
+ }
+ }
+
+ /* Report success */
+ MemoryContextSwitchTo(oldContext);
+
+ return true;
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/contrib/vexecutor/execVQual.h
----------------------------------------------------------------------
diff --git a/contrib/vexecutor/execVQual.h b/contrib/vexecutor/execVQual.h
index fb35789..01113dc 100644
--- a/contrib/vexecutor/execVQual.h
+++ b/contrib/vexecutor/execVQual.h
@@ -31,10 +31,13 @@
extern TupleTableSlot *
ExecVProject(ProjectionInfo *projInfo, ExprDoneCond *isDone);
-extern bool
-ExecVQual(List *qual, ExprContext *econtext);
+extern vbool*
+ExecVQual(List *qual, ExprContext *econtext, bool resultForNull);
extern bool
VirtualNodeProc(ScanState* state,TupleTableSlot *slot);
+extern ExprState *
+VExecInitExpr(Expr *node, PlanState *parent);
+
#endif
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/contrib/vexecutor/execVScan.c
----------------------------------------------------------------------
diff --git a/contrib/vexecutor/execVScan.c b/contrib/vexecutor/execVScan.c
index 8779e14..deb2724 100644
--- a/contrib/vexecutor/execVScan.c
+++ b/contrib/vexecutor/execVScan.c
@@ -69,16 +69,24 @@ TupleTableSlot *ExecTableVScanVirtualLayer(ScanState *scanState)
VectorizedState* pvs = vs->parent->vectorized;
if(pvs->vectorized)
- return ExecVScan(scanState,getVScanMethod(scanState->tableType)->accessMethod);
+ return ExecTableVScan(scanState);
else
{
TupleTableSlot* slot = scanState->ps.ps_ProjInfo ? scanState->ps.ps_ResultTupleSlot : scanState->ss_ScanTupleSlot;
- bool succ = VirtualNodeProc(scanState,slot);
-
- if(!succ)
+ while(1)
{
- slot = ExecTableVScan(scanState);
- VirtualNodeProc(scanState,slot);
+ bool succ = VirtualNodeProc(scanState,slot);
+
+ if(!succ)
+ {
+ slot = ExecTableVScan(scanState);
+ if(TupIsNull(slot))
+ break;
+ else
+ continue;
+ }
+
+ break;
}
return slot;
@@ -112,6 +120,7 @@ ExecVScan(ScanState *node, ExecScanAccessMtd accessMtd)
ExprContext *econtext;
List *qual;
ProjectionInfo *projInfo;
+ vbool *skip = NULL;
/*
* Fetch data from node
@@ -172,19 +181,35 @@ ExecVScan(ScanState *node, ExecScanAccessMtd accessMtd)
* when the qual is nil ... saves only a few cycles, but they add up
* ...
*/
- if (!qual || ExecQual(qual, econtext, false))
+ if (!qual || (NULL != (skip = ExecVQual(qual, econtext, false))))
{
/*
* Found a satisfactory scan tuple.
*/
if (projInfo)
{
+ int i;
+
+ /* first construct the skip array */
+ if(NULL != skip)
+ {
+ for(i = 0; i < skip->header.dim; i++)
+ {
+ skip->values[i] = ((!(skip->values[i])) ||
+ (skip->header.isnull[i]) ||
+ ((TupleBatch)slot->PRIVATE_tb)->skip[i]);
+ }
+ }
+
/*
* Form a projection tuple, store it in the result tuple slot
* and return it.
*/
((TupleBatch)projInfo->pi_slot->PRIVATE_tb)->nrows = ((TupleBatch)slot->PRIVATE_tb)->nrows;
- ((TupleBatch)projInfo->pi_slot->PRIVATE_tb)->skip = ((TupleBatch)slot->PRIVATE_tb)->skip;
+ if(NULL != skip)
+ ((TupleBatch)projInfo->pi_slot->PRIVATE_tb)->skip = skip->values;
+ else
+ ((TupleBatch)projInfo->pi_slot->PRIVATE_tb)->skip = ((TupleBatch)slot->PRIVATE_tb)->skip;
return ExecVProject(projInfo, NULL);
}
else
@@ -203,4 +228,4 @@ ExecVScan(ScanState *node, ExecScanAccessMtd accessMtd)
tbReset(node->ss_ScanTupleSlot->PRIVATE_tb);
tbReset(node->ps.ps_ResultTupleSlot->PRIVATE_tb);
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/contrib/vexecutor/vadt.c
----------------------------------------------------------------------
diff --git a/contrib/vexecutor/vadt.c b/contrib/vexecutor/vadt.c
index 4e5b766..1aa486e 100644
--- a/contrib/vexecutor/vadt.c
+++ b/contrib/vexecutor/vadt.c
@@ -138,6 +138,7 @@ v##type##in(PG_FUNCTION_ARGS) \
SET_VARSIZE(res, (offsetof(v##type, values) + n * sizeof(type))); \
res->header.elemtype = typeoid; \
res->header.dim = n; \
+ res->header.isnull = palloc0(sizeof(bool) * n); \
PG_RETURN_POINTER(res); \
}
@@ -181,29 +182,36 @@ v##type1##v##type2##opstr(PG_FUNCTION_ARGS) \
int i = 0; \
v##type1 *arg1 = PG_GETARG_POINTER(0); \
v##type2 *arg2 = PG_GETARG_POINTER(1); \
- v##type1 *res = NULL; \
Assert((arg1)->header.dim == (arg2)->header.dim); \
size = (arg1)->header.dim; \
if(sizeof(type1) > sizeof(type2)) \
{ \
- res = palloc0(offsetof(v##type1, values) + (size) * sizeof(type1)); \
- SET_VARSIZE(res, (offsetof(v##type1, values) + (size) * sizeof(type1))); \
- res->header.dim = size; \
- res->header.elemtype = arg1->header.elemtype; \
+ v##type1 *res = NULL; \
+ res = (v##type1 *)buildv##type1(size); \
+ while(i < size) \
+ { \
+ res->header.isnull[i] = \
+ arg1->header.isnull[i] || arg2->header.isnull[i]; \
+ if(!res->header.isnull[i]) \
+ res->values[i] = arg1->values[i] opsym arg2->values[i]; \
+ i++; \
+ } \
+ PG_RETURN_POINTER(res); \
} \
else \
{ \
- res = palloc0(offsetof(v##type2, values) + (size) * sizeof(type2)); \
- SET_VARSIZE(res, (offsetof(v##type2, values) + (size) * sizeof(type2))); \
- res->header.dim = size; \
- res->header.elemtype = arg2->header.elemtype; \
+ v##type2 *res = NULL; \
+ res = (v##type2 *)buildv##type2(size); \
+ while(i < size) \
+ { \
+ res->header.isnull[i] = \
+ arg1->header.isnull[i] || arg2->header.isnull[i]; \
+ if(!res->header.isnull[i]) \
+ res->values[i] = arg1->values[i] opsym arg2->values[i]; \
+ i++; \
+ } \
+ PG_RETURN_POINTER(res); \
} \
- while(i < size) \
- { \
- res->values[i] = arg1->values[i] opsym arg2->values[i]; \
- i++; \
- } \
- PG_RETURN_POINTER(res); \
}
/*
@@ -222,13 +230,12 @@ v##type##const_type##opstr(PG_FUNCTION_ARGS) \
const_type arg2 = CONST_ARG_MACRO(1); \
v##type *res = NULL; \
size = (arg1)->header.dim; \
- res = palloc0(offsetof(v##type, values) + (size) * sizeof(type)); \
- SET_VARSIZE(res, (offsetof(v##type, values) + (size) * sizeof(type))); \
- res->header.elemtype = arg1->header.elemtype; \
- res->header.dim = arg1->header.dim; \
+ res = (v##type *)buildv##type(size); \
while(i < size) \
{ \
- res->values[i] = arg1->values[i] opsym arg2; \
+ res->header.isnull[i] = (arg1)->header.isnull[i]; \
+ if(!res->header.isnull[i]) \
+ res->values[i] = arg1->values[i] opsym arg2; \
i ++ ;\
} \
PG_RETURN_POINTER(res); \
@@ -250,13 +257,13 @@ v##type1##v##type2##cmpstr(PG_FUNCTION_ARGS) \
v##type2 *arg2 = PG_GETARG_POINTER(1); \
vbool *res = NULL; \
size = (arg1)->header.dim; \
- res = palloc0(offsetof(vbool, values) + (size) * sizeof(bool)); \
- SET_VARSIZE(res, (offsetof(vbool, values) + (size) * sizeof(bool))); \
- res->header.elemtype = BOOLOID; \
- res->header.dim = arg1->header.dim; \
+ res = (vbool*)buildvbool(size); \
while(i < size) \
{ \
- res->values[i] = arg1->values[i] cmpsym arg2->values[i]; \
+ res->header.isnull[i] = \
+ arg1->header.isnull[i] || arg2->header.isnull[i]; \
+ if(!res->header.isnull[i]) \
+ res->values[i] = arg1->values[i] cmpsym arg2->values[i]; \
i++; \
} \
PG_RETURN_POINTER(res); \
@@ -278,13 +285,12 @@ v##type##const_type##cmpstr(PG_FUNCTION_ARGS) \
const_type arg2 = CONST_ARG_MACRO(1); \
vbool *res = NULL; \
size = (arg1)->header.dim; \
- res = palloc0(offsetof(vbool, values) + (size) * sizeof(bool)); \
- SET_VARSIZE(res, (offsetof(vbool, values) + (size) * sizeof(bool))); \
- res->header.elemtype = BOOLOID; \
- res->header.dim = size; \
+ res = (vbool*)buildvbool(size); \
while(i < size) \
{ \
- res->values[i] = arg1->values[i] cmpsym arg2; \
+ res->header.isnull[i] = (arg1)->header.isnull[i]; \
+ if(!res->header.isnull[i]) \
+ res->values[i] = arg1->values[i] cmpsym arg2; \
i++; \
} \
PG_RETURN_POINTER(res); \
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/contrib/vexecutor/vexecutor.c
----------------------------------------------------------------------
diff --git a/contrib/vexecutor/vexecutor.c b/contrib/vexecutor/vexecutor.c
index 4533fdd..9f5506f 100644
--- a/contrib/vexecutor/vexecutor.c
+++ b/contrib/vexecutor/vexecutor.c
@@ -26,7 +26,10 @@
#include "executor/nodeTableScan.h"
#include "catalog/catquery.h"
#include "cdb/cdbvars.h"
+#include "utils/memaccounting.h"
#include "execVScan.h"
+#include "execVQual.h"
+#include "vexecutor.h"
PG_MODULE_MAGIC;
int BATCHSIZE = 1024;
@@ -35,10 +38,10 @@ static int MAXBATCHSIZE = 4096;
/*
* hook function
*/
-static PlanState* VExecInitNode(PlanState *node,EState *eState,int eflags,MemoryAccount* ptr);
+static PlanState* VExecInitNode(Plan *node,EState *eState,int eflags);
+static PlanState* VExecVecNode(PlanState *Node, PlanState *parentNode, EState *eState,int eflags);
static TupleTableSlot* VExecProcNode(PlanState *node);
static bool VExecEndNode(PlanState *node);
-static Oid GetNType(Oid vtype);
extern int currentSliceId;
/*
@@ -51,7 +54,9 @@ _PG_init(void)
{
elog(DEBUG3, "PG INIT VEXECTOR");
vmthd.CheckPlanVectorized_Hook = CheckAndReplacePlanVectorized;
+ vmthd.ExecInitExpr_Hook = VExecInitExpr;
vmthd.ExecInitNode_Hook = VExecInitNode;
+ vmthd.ExecVecNode_Hook = VExecVecNode;
vmthd.ExecProcNode_Hook = VExecProcNode;
vmthd.ExecEndNode_Hook = VExecEndNode;
vmthd.GetNType = GetNType;
@@ -80,7 +85,9 @@ _PG_fini(void)
{
elog(DEBUG3, "PG FINI VEXECTOR");
vmthd.CheckPlanVectorized_Hook = NULL;
+ vmthd.ExecInitExpr_Hook = NULL;
vmthd.ExecInitNode_Hook = NULL;
+ vmthd.ExecVecNode_Hook = NULL;
vmthd.ExecProcNode_Hook = NULL;
vmthd.ExecEndNode_Hook = NULL;
}
@@ -124,10 +131,24 @@ static void backportTupleDescriptor(PlanState* ps,TupleDesc td)
ExecAssignResultType(ps,td);
}
-static PlanState* VExecInitNode(PlanState *node,EState *eState,int eflags,MemoryAccount* curMemoryAccount)
+static PlanState* VExecInitNode(Plan *node,EState *eState,int eflags)
+{
+ elog(DEBUG3, "PG VEXECINIT NODE");
+
+ return NULL;
+}
+
+#define HAS_EXECUTOR_MEMORY_ACCOUNT(planNode, NodeType) \
+ (NULL != planNode->memoryAccount && \
+ MEMORY_OWNER_TYPE_Exec_##NodeType == planNode->memoryAccount->ownerType)
+
+/*
+ * when vectorized_executor_enable is ON, we have to process the plan.
+ */
+static PlanState*
+VExecVecNode(PlanState *node, PlanState *parentNode, EState *eState,int eflags)
{
Plan *plan = node->plan;
- PlanState *subState = NULL;
VectorizedState *vstate = (VectorizedState*)palloc0(sizeof(VectorizedState));
elog(DEBUG3, "PG VEXECINIT NODE");
@@ -139,22 +160,7 @@ static PlanState* VExecInitNode(PlanState *node,EState *eState,int eflags,Memory
node->vectorized = (void*)vstate;
vstate->vectorized = plan->vectorized;
-
- /* set the parent state of son */
- if(innerPlanState(node))
- {
- subState = innerPlanState(node);
- Assert(NULL != subState);
-
- ((VectorizedState*)(subState->vectorized))->parent = node;
- }
- if(outerPlanState(node))
- {
- subState = outerPlanState(node);
- Assert(NULL != subState);
-
- ((VectorizedState*)(subState->vectorized))->parent = node;
- }
+ vstate->parent = parentNode;
if(Gp_role != GP_ROLE_DISPATCH)
{
@@ -163,15 +169,21 @@ static PlanState* VExecInitNode(PlanState *node,EState *eState,int eflags,Memory
case T_AppendOnlyScan:
case T_ParquetScan:
case T_TableScanState:
- START_MEMORY_ACCOUNT(curMemoryAccount);
- {
- TupleDesc td = ((TableScanState *)node)->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
- ((TableScanState *)node)->ss.ss_ScanTupleSlot->PRIVATE_tb = PointerGetDatum(tbGenerate(td->natts,BATCHSIZE));
- node->ps_ResultTupleSlot->PRIVATE_tb = PointerGetDatum(tbGenerate(td->natts,BATCHSIZE));
- /* if V->N */
- backportTupleDescriptor(node,node->ps_ResultTupleSlot->tts_tupleDescriptor);
- }
- END_MEMORY_ACCOUNT();
+ if(HAS_EXECUTOR_MEMORY_ACCOUNT(plan, TableScan))
+ START_MEMORY_ACCOUNT(plan->memoryAccount);
+
+ TupleDesc td = ((TableScanState *)node)->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
+ ((TableScanState *)node)->ss.ss_ScanTupleSlot->PRIVATE_tb = PointerGetDatum(tbGenerate(td->natts,BATCHSIZE));
+ node->ps_ResultTupleSlot->PRIVATE_tb = PointerGetDatum(tbGenerate(td->natts,BATCHSIZE));
+
+ /* if V->N */
+ if( NULL == parentNode ||
+ NULL == parentNode->vectorized ||
+ !((VectorizedState *)parentNode->vectorized)->vectorized)
+ backportTupleDescriptor(node,node->ps_ResultTupleSlot->tts_tupleDescriptor);
+
+ if(HAS_EXECUTOR_MEMORY_ACCOUNT(plan, TableScan))
+ END_MEMORY_ACCOUNT();
break;
default:
((VectorizedState *)node->vectorized)->vectorized = false;
@@ -179,8 +191,15 @@ static PlanState* VExecInitNode(PlanState *node,EState *eState,int eflags,Memory
}
}
+ /* recursively */
+ if(NULL != node->lefttree)
+ VExecVecNode(node->lefttree, node, eState, eflags);
+ if(NULL != node->righttree)
+ VExecVecNode(node->righttree, node, eState, eflags);
+
return node;
}
+
static TupleTableSlot* VExecProcNode(PlanState *node)
{
TupleTableSlot* result = NULL;
@@ -189,7 +208,7 @@ static TupleTableSlot* VExecProcNode(PlanState *node)
case T_ParquetScanState:
case T_AppendOnlyScanState:
case T_TableScanState:
- result = ExecTableVScanVirtualLayer((TableScanState*)node);
+ result = ExecTableVScanVirtualLayer((TableScanState*)node);
break;
default:
break;
@@ -238,8 +257,8 @@ HasVecExecOprator(NodeTag tag)
return result;
}
-static Oid GetNType(Oid vtype)
+Oid GetNType(Oid vtype)
{
const vFuncMap* vf = GetVFunc(vtype);
return vf == NULL ? InvalidOid : vf->ntype;
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/contrib/vexecutor/vexecutor.h
----------------------------------------------------------------------
diff --git a/contrib/vexecutor/vexecutor.h b/contrib/vexecutor/vexecutor.h
index 490f784..fdc3219 100644
--- a/contrib/vexecutor/vexecutor.h
+++ b/contrib/vexecutor/vexecutor.h
@@ -30,5 +30,6 @@ extern void _PG_init(void);
extern void _PG_fini(void);
extern bool HasVecExecOprator(NodeTag tag);
+Oid GetNType(Oid vtype);
#endif
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/src/backend/executor/execMain.c
----------------------------------------------------------------------
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 6b692a7..81f68f2 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2047,6 +2047,11 @@ InitPlan(QueryDesc *queryDesc, int eflags)
*/
planstate = ExecInitNode(plannedstmt->planTree, estate, eflags);
+ /* to process the planstate */
+ if(vmthd.vectorized_executor_enable &&
+ NULL != vmthd.ExecVecNode_Hook)
+ planstate = vmthd.ExecVecNode_Hook(planstate, NULL, estate, eflags);
+
queryDesc->planstate = planstate;
Assert(queryDesc->planstate);
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/src/backend/executor/execProcnode.c
----------------------------------------------------------------------
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 7ee99c6..fa6f657 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -271,6 +271,18 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
}
+
+ /*
+ * If the plan node can be vectorized and vectorized is enable, enter the
+ * vectorized execution operators.
+ */
+ if(vmthd.vectorized_executor_enable
+ && vmthd.ExecInitNode_Hook
+ && node->vectorized
+ && (result = vmthd.ExecInitNode_Hook(node,estate,eflags)))
+ return result;
+
+
switch (nodeTag(node))
{
/*
@@ -753,14 +765,6 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
if (result != NULL)
{
- /*
- * If the plan node can be vectorized and vectorized is enable, enter the
- * vectorized execution operators.
- */
- if(vmthd.vectorized_executor_enable
- && vmthd.ExecInitNode_Hook)
- result = vmthd.ExecInitNode_Hook(result,estate,eflags,curMemoryAccount);
-
SAVE_EXECUTOR_MEMORY_ACCOUNT(result, curMemoryAccount);
}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/src/backend/executor/execQual.c
----------------------------------------------------------------------
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index b49b7ec..451e498 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -4516,6 +4516,16 @@ ExecInitExpr(Expr *node, PlanState *parent)
/* Guard against stack overflow due to overly complex expressions */
check_stack_depth();
+ /* Initialize the vectorzied expressions */
+ if( vmthd.vectorized_executor_enable
+ && vmthd.ExecInitExpr_Hook
+ && parent->plan->vectorized)
+ {
+ state = vmthd.ExecInitExpr_Hook(node, parent);
+ if(NULL != state)
+ return state;
+ }
+
switch (nodeTag(node))
{
case T_Var:
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/src/include/executor/executor.h
----------------------------------------------------------------------
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 8484d66..b71904f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -44,7 +44,9 @@
typedef struct vectorexe_t {
bool vectorized_executor_enable;
Plan* (*CheckPlanVectorized_Hook)(PlannerInfo *node, Plan *plan);
- PlanState* (*ExecInitNode_Hook)(PlanState *node,EState *eState,int eflags,MemoryAccount* ptr);
+ ExprState* (*ExecInitExpr_Hook)(Expr *node, PlanState *parent);
+ PlanState* (*ExecInitNode_Hook)(Plan *node, EState *eState,int eflags);
+ PlanState* (*ExecVecNode_Hook)(PlanState *Node, PlanState *parentNode, EState *eState,int eflags);
TupleTableSlot* (*ExecProcNode_Hook)(PlanState *node);
bool (*ExecEndNode_Hook)(PlanState *node);
Oid (*GetNType)(Oid vtype);
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/src/test/feature/vexecutor/ans/.DS_Store
----------------------------------------------------------------------
diff --git a/src/test/feature/vexecutor/ans/.DS_Store b/src/test/feature/vexecutor/ans/.DS_Store
new file mode 100644
index 0000000..2d9613b
Binary files /dev/null and b/src/test/feature/vexecutor/ans/.DS_Store differ
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80eaf448/src/test/feature/vexecutor/ans/projandqual.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/vexecutor/ans/projandqual.ans b/src/test/feature/vexecutor/ans/projandqual.ans
new file mode 100644
index 0000000..52084d5
--- /dev/null
+++ b/src/test/feature/vexecutor/ans/projandqual.ans
@@ -0,0 +1,40 @@
+-- start_ignore
+SET SEARCH_PATH=TestVexecutor_ProjAndQual;
+SET
+-- end_ignore
+select a + b from test1 where a + b > 1020 and b + c > 1;
+ ?column?
+----------
+ 1021
+ 1022
+ 1023
+ 1024
+ 1025
+(5 rows)
+
+select a - b from test1 where a - b > 1020 and b - c >= 0;
+ ?column?
+----------
+ 1021
+ 1022
+ 1023
+(3 rows)
+
+select a * b from test1 where a * b > 1020 and b * c < 10;
+ ?column?
+----------
+ 1021
+ 1022
+ 1023
+ 1024
+(4 rows)
+
+select a / b from test1 where a / b > 1020 and b * c = 1;
+ ?column?
+----------
+ 1021
+ 1022
+ 1023
+ 1024
+(4 rows)
+