Github user zhangjackey commented on a diff in the pull request:
https://github.com/apache/incubator-hawq/pull/1351#discussion_r181933267
--- Diff: contrib/vexecutor/execVQual.c ---
@@ -123,3 +123,431 @@ 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 */
+ tb = (TupleBatch )slot->PRIVATE_tb;
+
+ Assert(NULL != tb);
+
+ return PointerGetDatum(tb->datagroup[attnum]);
+}
+
+
+/*
+ * 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;
+ }
+
+ 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)
+ 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]);
+ }
+ 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;
+ bool AnyNull;
+ vbool *res = NULL;
+ vbool *next = NULL;
+ bool skip = true;
+ int i = 0;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ AnyNull = false;
+
+ /*
+ * 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);
+ for(i = 0; i < res->header.dim; i++)
+ {
+ if(res->header.isnull[i] || !res->values[i])
+ {
+ skip = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ next = DatumGetPointer(clause_value);
+ 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)
+{
+ List *clauses = andExpr->args;
+ ListCell *clause;
+ bool AnyNull;
+ vbool *res = NULL;
+ vbool *next = NULL;
+ bool skip = true;
+ int i = 0;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ AnyNull = false;
+
+ /*
+ * 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);
+ for(i = 0; i < res->header.dim; i++)
+ {
+ if(res->header.isnull[i] || res->values[i])
+ {
+ skip = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ next = DatumGetPointer(clause_value);
+ 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);
+}
+
+/*
+ * Init the vectorized expressions
+ */
+ExprState *
+VExecInitExpr(Expr *node, PlanState *parent)
+{
+ ExprState *state = NULL;
+ if(NULL == parent->vectorized)
+ return 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;
+ }
+
--- End diff --
yes, add in next commit.
---