Github user wengyanqing commented on a diff in the pull request:

    https://github.com/apache/incubator-hawq/pull/1351#discussion_r180626391
  
    --- 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 --
    
    Does it need "state->expr = node;" here?


---

Reply via email to