📄 execqual.c
字号:
/*------------------------------------------------------------------------- * * execQual.c * Routines to evaluate qualification and targetlist expressions * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/executor/execQual.c,v 1.53 1999/06/12 19:22:40 tgl Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES * ExecEvalExpr - evaluate an expression and return a datum * ExecQual - return true/false if qualification is satisified * ExecTargetList - form a new tuple by projecting the given tuple * * NOTES * ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster * will speed up the entire system. Unfortunately they are currently * implemented recursively. Eliminating the recursion is bound to * improve the speed of the executor. * * ExecTargetList() is used to make tuple projections. Rather then * trying to speed it up, the execution plan should be pre-processed * to facilitate attribute sharing between nodes wherever possible, * instead of doing needless copying. -cim 5/31/91 * */#include <string.h>#include "postgres.h"#include "access/heapam.h"#include "catalog/pg_language.h"#include "executor/execdebug.h"#include "executor/executor.h"#include "executor/execFlatten.h"#include "executor/functions.h"#include "executor/nodeSubplan.h"#include "fmgr.h"#include "nodes/memnodes.h"#include "nodes/primnodes.h"#include "nodes/relation.h"#include "optimizer/clauses.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/fcache.h"#include "utils/fcache2.h"#include "utils/mcxt.h"#include "utils/memutils.h"/* * externs and constants *//* * XXX Used so we can get rid of use of Const nodes in the executor. * Currently only used by ExecHashGetBucket and set only by ExecMakeVarConst * and by ExecEvalArrayRef. */bool execConstByVal;int execConstLen;/* static functions decls */static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull);static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext, bool *isNull, bool *isDone);static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext, bool *isNull, bool *isDone);static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext, List *argList, Datum argV[], bool *argIsDone);static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull);static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull);static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);static Datum ExecMakeFunctionResult(Node *node, List *arguments, ExprContext *econtext, bool *isNull, bool *isDone);static bool ExecQualClause(Node *clause, ExprContext *econtext);/* * ExecEvalArrayRef * * This function takes an ArrayRef and returns a Const Node if it * is an array reference or returns the changed Array Node if it is * an array assignment. */static DatumExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext, bool *isNull, bool *isDone){ bool dummy; int i = 0, j = 0; ArrayType *array_scanner; List *upperIndexpr, *lowerIndexpr; Node *assgnexpr; List *elt; IntArray upper, lower; int *lIndex; char *dataPtr; *isNull = false; array_scanner = (ArrayType *) ExecEvalExpr(arrayRef->refexpr, econtext, isNull, isDone); if (*isNull) return (Datum) NULL; upperIndexpr = arrayRef->refupperindexpr; foreach(elt, upperIndexpr) { upper.indx[i++] = (int32) ExecEvalExpr((Node *) lfirst(elt), econtext, isNull, &dummy); if (*isNull) return (Datum) NULL; } lowerIndexpr = arrayRef->reflowerindexpr; lIndex = NULL; if (lowerIndexpr != NIL) { foreach(elt, lowerIndexpr) { lower.indx[j++] = (int32) ExecEvalExpr((Node *) lfirst(elt), econtext, isNull, &dummy); if (*isNull) return (Datum) NULL; } if (i != j) elog(ERROR, "ExecEvalArrayRef: upper and lower indices mismatch"); lIndex = lower.indx; } assgnexpr = arrayRef->refassgnexpr; if (assgnexpr != NULL) { dataPtr = (char *) ExecEvalExpr((Node *) assgnexpr, econtext, isNull, &dummy); if (*isNull) return (Datum) NULL; execConstByVal = arrayRef->refelembyval; execConstLen = arrayRef->refelemlength; if (lIndex == NULL) return (Datum) array_set(array_scanner, i, upper.indx, dataPtr, arrayRef->refelembyval, arrayRef->refelemlength, arrayRef->refattrlength, isNull); return (Datum) array_assgn(array_scanner, i, upper.indx, lower.indx, (ArrayType *) dataPtr, arrayRef->refelembyval, arrayRef->refelemlength, isNull); } execConstByVal = arrayRef->refelembyval; execConstLen = arrayRef->refelemlength; if (lIndex == NULL) return (Datum) array_ref(array_scanner, i, upper.indx, arrayRef->refelembyval, arrayRef->refelemlength, arrayRef->refattrlength, isNull); return (Datum) array_clip(array_scanner, i, upper.indx, lower.indx, arrayRef->refelembyval, arrayRef->refelemlength, isNull);}/* ---------------------------------------------------------------- * ExecEvalAggref * * Returns a Datum whose value is the value of the precomputed * aggregate found in the given expression context. * ---------------------------------------------------------------- */static DatumExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull){ *isNull = econtext->ecxt_nulls[aggref->aggno]; return econtext->ecxt_values[aggref->aggno];}/* ---------------------------------------------------------------- * ExecEvalVar * * Returns a Datum whose value is the value of a range * variable with respect to given expression context. * * * As an entry condition, we expect that the datatype the * plan expects to get (as told by our "variable" argument) is in * fact the datatype of the attribute the plan says to fetch (as * seen in the current context, identified by our "econtext" * argument). * * If we fetch a Type A attribute and Caller treats it as if it * were Type B, there will be undefined results (e.g. crash). * One way these might mismatch now is that we're accessing a * catalog class and the type information in the pg_attribute * class does not match the hardcoded pg_attribute information * (in pg_attribute.h) for the class in question. * * We have an Assert to make sure this entry condition is met. * * ---------------------------------------------------------------- */static DatumExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull){ Datum result; TupleTableSlot *slot; AttrNumber attnum; HeapTuple heapTuple; TupleDesc tuple_type; Buffer buffer; bool byval; int16 len; /* * get the slot we want */ switch (variable->varno) { case INNER: /* get the tuple from the inner node */ slot = econtext->ecxt_innertuple; break; case OUTER: /* get the tuple from the outer node */ slot = econtext->ecxt_outertuple; break; default: /* get the tuple from the relation being * scanned */ slot = econtext->ecxt_scantuple; break; } /* * extract tuple information from the slot */ heapTuple = slot->val; tuple_type = slot->ttc_tupleDescriptor; buffer = slot->ttc_buffer; attnum = variable->varattno; /* (See prolog for explanation of this Assert) */ Assert(attnum <= 0 || (attnum - 1 <= tuple_type->natts - 1 && tuple_type->attrs[attnum - 1] != NULL && variable->vartype == tuple_type->attrs[attnum - 1]->atttypid)) /* * If the attribute number is invalid, then we are supposed to return * the entire tuple, we give back a whole slot so that callers know * what the tuple looks like. */ if (attnum == InvalidAttrNumber) { TupleTableSlot *tempSlot; TupleDesc td; HeapTuple tup; tempSlot = makeNode(TupleTableSlot); tempSlot->ttc_shouldFree = false; tempSlot->ttc_descIsNew = true; tempSlot->ttc_tupleDescriptor = (TupleDesc) NULL; tempSlot->ttc_buffer = InvalidBuffer; tempSlot->ttc_whichplan = -1; tup = heap_copytuple(heapTuple); td = CreateTupleDescCopy(slot->ttc_tupleDescriptor); ExecSetSlotDescriptor(tempSlot, td); ExecStoreTuple(tup, tempSlot, InvalidBuffer, true); return (Datum) tempSlot; } result = heap_getattr(heapTuple, /* tuple containing attribute */ attnum, /* attribute number of desired * attribute */ tuple_type, /* tuple descriptor of tuple */ isNull); /* return: is attribute null? */ /* * return null if att is null */ if (*isNull) return (Datum) NULL; /* * get length and type information.. ??? what should we do about * variable length attributes - variable length attributes have their * length stored in the first 4 bytes of the memory pointed to by the * returned value.. If we can determine that the type is a variable * length type, we can do the right thing. -cim 9/15/89 */ if (attnum < 0) { /* * If this is a pseudo-att, we get the type and fake the length. * There ought to be a routine to return the real lengths, so * we'll mark this one ... XXX -mao */ len = heap_sysattrlen(attnum); /* XXX see -mao above */ byval = heap_sysattrbyval(attnum); /* XXX see -mao above */ } else { len = tuple_type->attrs[attnum - 1]->attlen; byval = tuple_type->attrs[attnum - 1]->attbyval ? true : false; } execConstByVal = byval; execConstLen = len; return result;}/* ---------------------------------------------------------------- * ExecEvalParam * * Returns the value of a parameter. A param node contains * something like ($.name) and the expression context contains * the current parameter bindings (name = "sam") (age = 34)... * so our job is to replace the param node with the datum * containing the appropriate information ("sam"). * * Q: if we have a parameter ($.foo) without a binding, i.e. * there is no (foo = xxx) in the parameter list info, * is this a fatal error or should this be a "not available" * (in which case we shoud return a Const node with the * isnull flag) ? -cim 10/13/89 * * Minor modification: Param nodes now have an extra field, * `paramkind' which specifies the type of parameter * (see params.h). So while searching the paramList for * a paramname/value pair, we have also to check for `kind'. * * NOTE: The last entry in `paramList' is always an * entry with kind == PARAM_INVALID. * ---------------------------------------------------------------- */DatumExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull){ char *thisParameterName; int thisParameterKind = expression->paramkind; AttrNumber thisParameterId = expression->paramid; int matchFound; ParamListInfo paramList; if (thisParameterKind == PARAM_EXEC) { ParamExecData *prm = &(econtext->ecxt_param_exec_vals[thisParameterId]); if (prm->execPlan != NULL) ExecSetParamPlan(prm->execPlan); Assert(prm->execPlan == NULL); *isNull = prm->isnull; return prm->value; } thisParameterName = expression->paramname; paramList = econtext->ecxt_param_list_info; *isNull = false; /* * search the list with the parameter info to find a matching name. An * entry with an InvalidName denotes the last element in the array. */ matchFound = 0; if (paramList != NULL) { /* * search for an entry in 'paramList' that matches the * `expression'. */ while (paramList->kind != PARAM_INVALID && !matchFound) { switch (thisParameterKind) { case PARAM_NAMED: if (thisParameterKind == paramList->kind && strcmp(paramList->name, thisParameterName) == 0) matchFound = 1; break; case PARAM_NUM: if (thisParameterKind == paramList->kind && paramList->id == thisParameterId) matchFound = 1; break; case PARAM_OLD: case PARAM_NEW: if (thisParameterKind == paramList->kind && paramList->id == thisParameterId) { matchFound = 1; /* * sanity check */ if (strcmp(paramList->name, thisParameterName) != 0) { elog(ERROR, "ExecEvalParam: new/old params with same id & diff names"); } } break; default: /* * oops! this is not supposed to happen! */ elog(ERROR, "ExecEvalParam: invalid paramkind %d", thisParameterKind); } if (!matchFound) paramList++; } /* while */ } /* if */ if (!matchFound) { /* * ooops! we couldn't find this parameter in the parameter list. * Signal an error */ elog(ERROR, "ExecEvalParam: Unknown value for parameter %s", thisParameterName); } /* * return the value. */ if (paramList->isnull) { *isNull = true; return (Datum) NULL; } if (expression->param_tlist != NIL) { HeapTuple tup; Datum value; List *tlist = expression->param_tlist; TargetEntry *tle = (TargetEntry *) lfirst(tlist); TupleTableSlot *slot = (TupleTableSlot *) paramList->value; tup = slot->val; value = ProjectAttribute(slot->ttc_tupleDescriptor, tle, tup, isNull); return value; } return paramList->value;}/* ---------------------------------------------------------------- * ExecEvalOper / ExecEvalFunc support routines * ---------------------------------------------------------------- *//* * GetAttributeByName * GetAttributeByNum * * These are functions which return the value of the * named attribute out of the tuple from the arg slot. User defined * C functions which take a tuple as an argument are expected * to use this. Ex: overpaid(EMP) might call GetAttributeByNum(). *//* static but gets called from external functions */char *GetAttributeByNum(TupleTableSlot *slot, AttrNumber attrno, bool *isNull){ Datum retval; if (!AttributeNumberIsValid(attrno)) elog(ERROR, "GetAttributeByNum: Invalid attribute number"); if (!AttrNumberIsForUserDefinedAttr(attrno)) elog(ERROR, "GetAttributeByNum: cannot access system attributes here"); if (isNull == (bool *) NULL) elog(ERROR, "GetAttributeByNum: a NULL isNull flag was passed"); if (TupIsNull(slot)) { *isNull = true; return (char *) NULL; } retval = heap_getattr(slot->val, attrno, slot->ttc_tupleDescriptor, isNull); if (*isNull) return (char *) NULL; return (char *) retval;}/* XXX name for catalogs */#ifdef NOT_USEDchar *att_by_num(TupleTableSlot *slot, AttrNumber attrno, bool *isNull){ return GetAttributeByNum(slot, attrno, isNull);}#endifchar *GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull){ AttrNumber attrno; TupleDesc tupdesc; Datum retval; int natts; int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -