📄 execqual.c
字号:
* Evaluate a CASE clause. Will have boolean expressions * inside the WHEN clauses, and will have constants * for results. * - thomas 1998-11-09 * ---------------------------------------------------------------- */static DatumExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull){ List *clauses; List *clause; CaseWhen *wclause; Datum const_value = 0; bool isDone; clauses = caseExpr->args; /* * we evaluate each of the WHEN clauses in turn, as soon as one is * true we return the corresponding result. If none are true then we * return the value of the default clause, or NULL. */ foreach(clause, clauses) { /* * We don't iterate over sets in the quals, so pass in an isDone * flag, but ignore it. */ wclause = lfirst(clause); const_value = ExecEvalExpr((Node *) wclause->expr, econtext, isNull, &isDone); /* * if we have a true test, then we return the result, since the * case statement is satisfied. */ if (DatumGetInt32(const_value) != 0) { const_value = ExecEvalExpr((Node *) wclause->result, econtext, isNull, &isDone); return (Datum) const_value; } } if (caseExpr->defresult) { const_value = ExecEvalExpr((Node *) caseExpr->defresult, econtext, isNull, &isDone); } else *isNull = true; return const_value;}/* ---------------------------------------------------------------- * ExecEvalExpr * * Recursively evaluate a targetlist or qualification expression. * * This routine is an inner loop routine and should be as fast * as possible. * * Node comparison functions were replaced by macros for speed and to plug * memory leaks incurred by using the planner's Lispy stuff for * comparisons. Order of evaluation of node comparisons IS IMPORTANT; * the macros do no checks. Order of evaluation: * * o an isnull check, largely to avoid coredumps since greg doubts this * routine is called with a null ptr anyway in proper operation, but is * not completely sure... * o ExactNodeType checks. * o clause checks or other checks where we look at the lfirst of something. * ---------------------------------------------------------------- */DatumExecEvalExpr(Node *expression, ExprContext *econtext, bool *isNull, bool *isDone){ Datum retDatum = 0; *isNull = false; /* * Some callers don't care about is done and only want 1 result. They * indicate this by passing NULL */ if (isDone) *isDone = true; /* * here we dispatch the work to the appropriate type of function given * the type of our expression. */ if (expression == NULL) { *isNull = true; return (Datum) true; } switch (nodeTag(expression)) { case T_Var: retDatum = (Datum) ExecEvalVar((Var *) expression, econtext, isNull); break; case T_Const: { Const *con = (Const *) expression; if (con->constisnull) *isNull = true; retDatum = con->constvalue; break; } case T_Param: retDatum = (Datum) ExecEvalParam((Param *) expression, econtext, isNull); break; case T_Iter: retDatum = (Datum) ExecEvalIter((Iter *) expression, econtext, isNull, isDone); break; case T_Aggref: retDatum = (Datum) ExecEvalAggref((Aggref *) expression, econtext, isNull); break; case T_ArrayRef: retDatum = (Datum) ExecEvalArrayRef((ArrayRef *) expression, econtext, isNull, isDone); break; case T_Expr: { Expr *expr = (Expr *) expression; switch (expr->opType) { case OP_EXPR: retDatum = (Datum) ExecEvalOper(expr, econtext, isNull); break; case FUNC_EXPR: retDatum = (Datum) ExecEvalFunc(expr, econtext, isNull, isDone); break; case OR_EXPR: retDatum = (Datum) ExecEvalOr(expr, econtext, isNull); break; case AND_EXPR: retDatum = (Datum) ExecEvalAnd(expr, econtext, isNull); break; case NOT_EXPR: retDatum = (Datum) ExecEvalNot(expr, econtext, isNull); break; case SUBPLAN_EXPR: retDatum = (Datum) ExecSubPlan((SubPlan *) expr->oper, expr->args, econtext); break; default: elog(ERROR, "ExecEvalExpr: unknown expression type %d", expr->opType); break; } break; } case T_CaseExpr: retDatum = (Datum) ExecEvalCase((CaseExpr *) expression, econtext, isNull); break; default: elog(ERROR, "ExecEvalExpr: unknown expression type %d", nodeTag(expression)); break; } return retDatum;} /* ExecEvalExpr() *//* ---------------------------------------------------------------- * ExecQual / ExecTargetList * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- * ExecQualClause * * this is a workhorse for ExecQual. ExecQual has to deal * with a list of qualifications, so it passes each qualification * in the list to this function one at a time. ExecQualClause * returns true when the qualification *fails* and false if * the qualification succeeded (meaning we have to test the * rest of the qualification) * ---------------------------------------------------------------- */static boolExecQualClause(Node *clause, ExprContext *econtext){ Datum expr_value; bool isNull; bool isDone; /* when there is a null clause, consider the qualification to be true */ if (clause == NULL) return true; /* * pass isDone, but ignore it. We don't iterate over multiple returns * in the qualifications. */ expr_value = (Datum) ExecEvalExpr(clause, econtext, &isNull, &isDone); /* * this is interesting behaviour here. When a clause evaluates to * null, then we consider this as passing the qualification. it seems * kind of like, if the qual is NULL, then there's no qual.. */ if (isNull) return true; /* * remember, we return true when the qualification fails.. */ if (DatumGetInt32(expr_value) == 0) return true; return false;}/* ---------------------------------------------------------------- * ExecQual * * Evaluates a conjunctive boolean expression and returns t * iff none of the subexpressions are false (or null). * ---------------------------------------------------------------- */boolExecQual(List *qual, ExprContext *econtext){ List *clause; bool result; /* * debugging stuff */ EV_printf("ExecQual: qual is "); EV_nodeDisplay(qual); EV_printf("\n"); IncrProcessed(); /* * return true immediately if no qual */ if (qual == NIL) return true; /* * a "qual" is a list of clauses. To evaluate the qual, we evaluate * each of the clauses in the list. * * ExecQualClause returns true when we know the qualification *failed* so * we just pass each clause in qual to it until we know the qual * failed or there are no more clauses. */ result = false; foreach(clause, qual) { result = ExecQualClause((Node *) lfirst(clause), econtext); if (result == true) break; } /* * if result is true, then it means a clause failed so we return * false. if result is false then it means no clause failed so we * return true. */ if (result == true) return false; return true;}intExecTargetListLength(List *targetlist){ int len; List *tl; TargetEntry *curTle; len = 0; foreach(tl, targetlist) { curTle = lfirst(tl); if (curTle->resdom != NULL) len++; else len += curTle->fjoin->fj_nNodes; } return len;}/* ---------------------------------------------------------------- * ExecTargetList * * Evaluates a targetlist with respect to the current * expression context and return a tuple. * ---------------------------------------------------------------- */static HeapTupleExecTargetList(List *targetlist, int nodomains, TupleDesc targettype, Datum *values, ExprContext *econtext, bool *isDone){ char nulls_array[64]; bool fjNullArray[64]; bool *fjIsNull; char *null_head; List *tl; TargetEntry *tle; Node *expr; Resdom *resdom; AttrNumber resind; Datum constvalue; HeapTuple newTuple; bool isNull; static struct tupleDesc NullTupleDesc; /* we assume this inits to zeroes */ /* * debugging stuff */ EV_printf("ExecTargetList: tl is "); EV_nodeDisplay(targetlist); EV_printf("\n"); /* * There used to be some klugy and demonstrably broken code here that * special-cased the situation where targetlist == NIL. Now we just * fall through and return an empty-but-valid tuple. We do, however, * have to cope with the possibility that targettype is NULL --- * heap_formtuple won't like that, so pass a dummy descriptor with * natts = 0 to deal with it. */ if (targettype == NULL) targettype = &NullTupleDesc; /* * allocate an array of char's to hold the "null" information only if * we have a really large targetlist. otherwise we use the stack. */ if (nodomains > 64) { null_head = (char *) palloc(nodomains + 1); fjIsNull = (bool *) palloc(nodomains + 1); } else { null_head = &nulls_array[0]; fjIsNull = &fjNullArray[0]; } /* * evaluate all the expressions in the target list */ EV_printf("ExecTargetList: setting target list values\n"); *isDone = true; foreach(tl, targetlist) { /* * remember, a target list is a list of lists: * * ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...) * * tl is a pointer to successive cdr's of the targetlist tle is a * pointer to the target list entry in tl */ tle = lfirst(tl); if (tle->resdom != NULL) { expr = tle->expr; resdom = tle->resdom; resind = resdom->resno - 1; constvalue = (Datum) ExecEvalExpr(expr, econtext, &isNull, isDone); if ((IsA(expr, Iter)) && (*isDone)) return (HeapTuple) NULL; values[resind] = constvalue; if (!isNull) null_head[resind] = ' '; else null_head[resind] = 'n'; } else { int curNode; Resdom *fjRes; List *fjTlist = (List *) tle->expr; Fjoin *fjNode = tle->fjoin; int nNodes = fjNode->fj_nNodes; DatumPtr results = fjNode->fj_results; ExecEvalFjoin(tle, econtext, fjIsNull, isDone); if (*isDone) return (HeapTuple) NULL; /* * get the result from the inner node */ fjRes = (Resdom *) fjNode->fj_innerNode; resind = fjRes->resno - 1; if (fjIsNull[0]) null_head[resind] = 'n'; else { null_head[resind] = ' '; values[resind] = results[0]; } /* * Get results from all of the outer nodes */ for (curNode = 1; curNode < nNodes; curNode++, fjTlist = lnext(fjTlist)) {#ifdef NOT_USED /* what is this?? */ Node *outernode = lfirst(fjTlist); fjRes = (Resdom *) outernode->iterexpr;#endif resind = fjRes->resno - 1; if (fjIsNull[curNode]) null_head[resind] = 'n'; else { null_head[resind] = ' '; values[resind] = results[curNode]; } } } } /* * form the new result tuple (in the "normal" context) */ newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head); /* * free the nulls array if we allocated one.. */ if (nodomains > 64) { pfree(null_head); pfree(fjIsNull); } return newTuple;}/* ---------------------------------------------------------------- * ExecProject * * projects a tuple based in projection info and stores * it in the specified tuple table slot. * * Note: someday soon the executor can be extended to eliminate * redundant projections by storing pointers to datums * in the tuple table and then passing these around when * possible. this should make things much quicker. * -cim 6/3/91 * ---------------------------------------------------------------- */TupleTableSlot *ExecProject(ProjectionInfo *projInfo, bool *isDone){ TupleTableSlot *slot; List *targetlist; int len; TupleDesc tupType; Datum *tupValue; ExprContext *econtext; HeapTuple newTuple; /* * sanity checks */ if (projInfo == NULL) return (TupleTableSlot *) NULL; /* * get the projection info we want */ slot = projInfo->pi_slot; targetlist = projInfo->pi_targetlist; len = projInfo->pi_len; tupType = slot->ttc_tupleDescriptor; tupValue = projInfo->pi_tupValue; econtext = projInfo->pi_exprContext; /* * form a new (result) tuple */ newTuple = ExecTargetList(targetlist, len, tupType, tupValue, econtext, isDone); /* * store the tuple in the projection slot and return the slot. */ return (TupleTableSlot *) ExecStoreTuple(newTuple,/* tuple to store */ slot, /* slot to store in */ InvalidBuffer, /* tuple has no buffer */ true);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -