久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

怎么使用PostgreSQL的ExprEvalStep

176次閱讀
沒有評論

共計 25676 個字符,預計需要花費 65 分鐘才能閱讀完成。

本篇內容介紹了“怎么使用 PostgreSQL 的 ExprEvalStep”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

ExprEvalStep
表達式解析步驟結構體

typedef struct ExprEvalStep
 /*
 * Instruction to be executed. During instruction preparation this is an
 * enum ExprEvalOp, but later it can be changed to some other type, e.g. a
 * pointer for computed goto (that s why it s an intptr_t).
 *  待執行指令.
 *  在指令準備期間這是枚舉型的 ExprEvalOp,
 *  但后續會被改變為某些其他類型, 比如用于 goto 的指針, 因此被定義為 intprt_t 類型
 */
 intptr_t opcode;
 /* where to store the result of this step */
 // 存儲該步驟的結果
 Datum *resvalue;
 bool *resnull;
 /*
 * Inline data for the operation. Inline data is faster to access, but
 * also bloats the size of all instructions. The union should be kept to
 * no more than 40 bytes on 64-bit systems (so that the entire struct is
 * no more than 64 bytes, a single cacheline on common systems).
 *  操作的內聯數據.
 *  內聯數據用于更快的訪問, 但同時會導致指令的盤膨脹.
 *  聯合體在 64-bit 系統上應保持在 40 字節范圍內
 * (因此整個結構體不應大于 64 字節, 普通系統上的單個緩存線大小)
 */
 union
 {
 /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */
 // 用于 EEOP_INNER/OUTER/SCAN_FETCHSOME
 struct
 { /* attribute number up to which to fetch (inclusive) */
 // 獲取到的屬性編號
 int last_var;
 TupleDesc known_desc;
 } fetch;
 /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */
 struct
 {
 /* attnum is attr number - 1 for regular VAR ... */
 //attnum 是常規 VAR 的 attr number - 1
 /* but it s just the normal (negative) attr number for SYSVAR */
 // 對于 SYSVAR, 該值是常規的 attr number
 int attnum;
 Oid vartype; /* type OID of variable */
 } var;
 /* for EEOP_WHOLEROW */
 struct
 {
 Var *var; /* original Var node in plan tree */
 bool first; /* first time through, need to initialize? */
 bool slow; /* need runtime check for nulls? */
 TupleDesc tupdesc; /* descriptor for resulting tuples */
 JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */
 } wholerow;
 /* for EEOP_ASSIGN_*_VAR */
 struct
 {
 /* target index in ExprState- resultslot- tts_values/nulls */
 int resultnum;
 /* source attribute number - 1 */
 int attnum;
 } assign_var;
 /* for EEOP_ASSIGN_TMP[_MAKE_RO] */
 struct
 {
 /* target index in ExprState- resultslot- tts_values/nulls */
 int resultnum;
 } assign_tmp;
 /* for EEOP_CONST */
 struct
 {
 /* constant s value */
 Datum value;
 bool isnull;
 } constval;
 /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */
 // 對于 EEOP_FUNCEXPR_* / NULLIF / DISTINCT
 struct
 {
 // 函數的檢索數據
 FmgrInfo *finfo; /* function s lookup data */
 // 參數信息等
 FunctionCallInfo fcinfo_data; /* arguments etc */
 /* faster to access without additional indirection: */
 // 無需額外的指向, 更快速的訪問
 PGFunction fn_addr; /* actual call address */
 int nargs; /* number of arguments */
 } func;
 /* for EEOP_BOOL_*_STEP */
 struct
 {
 bool *anynull; /* track if any input was NULL */
 int jumpdone; /* jump here if result determined */
 } boolexpr;
 /* for EEOP_QUAL */
 struct
 {
 int jumpdone; /* jump here on false or null */
 } qualexpr;
 /* for EEOP_JUMP[_CONDITION] */
 struct
 {
 int jumpdone; /* target instruction s index */
 } jump;
 /* for EEOP_NULLTEST_ROWIS[NOT]NULL */
 struct
 {
 /* cached tupdesc pointer - filled at runtime */
 TupleDesc argdesc;
 } nulltest_row;
 /* for EEOP_PARAM_EXEC/EXTERN */
 struct
 {
 int paramid; /* numeric ID for parameter */
 Oid paramtype; /* OID of parameter s datatype */
 } param;
 /* for EEOP_PARAM_CALLBACK */
 struct
 {
 ExecEvalSubroutine paramfunc; /* add-on evaluation subroutine */
 void *paramarg; /* private data for same */
 int paramid; /* numeric ID for parameter */
 Oid paramtype; /* OID of parameter s datatype */
 } cparam;
 /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */
 struct
 {
 Datum *value; /* value to return */
 bool *isnull;
 } casetest;
 /* for EEOP_MAKE_READONLY */
 struct
 {
 Datum *value; /* value to coerce to read-only */
 bool *isnull;
 } make_readonly;
 /* for EEOP_IOCOERCE */
 struct
 {
 /* lookup and call info for source type s output function */
 FmgrInfo *finfo_out;
 FunctionCallInfo fcinfo_data_out;
 /* lookup and call info for result type s input function */
 FmgrInfo *finfo_in;
 FunctionCallInfo fcinfo_data_in;
 } iocoerce;
 /* for EEOP_SQLVALUEFUNCTION */
 struct
 {
 SQLValueFunction *svf;
 } sqlvaluefunction;
 /* for EEOP_NEXTVALUEEXPR */
 //EEOP_NEXTVALUEEXPR
 struct
 {
 Oid seqid;
 Oid seqtypid;
 } nextvalueexpr;
 /* for EEOP_ARRAYEXPR */
 struct
 {
 Datum *elemvalues; /* element values get stored here */
 bool *elemnulls;
 int nelems; /* length of the above arrays */
 Oid elemtype; /* array element type */
 int16 elemlength; /* typlen of the array element type */
 bool elembyval; /* is the element type pass-by-value? */
 char elemalign; /* typalign of the element type */
 bool multidims; /* is array expression multi-D? */
 } arrayexpr;
 /* for EEOP_ARRAYCOERCE */
 struct
 {
 ExprState *elemexprstate; /* null if no per-element work */
 Oid resultelemtype; /* element type of result array */
 struct ArrayMapState *amstate; /* workspace for array_map */
 } arraycoerce;
 /* for EEOP_ROW */
 struct
 {
 TupleDesc tupdesc; /* descriptor for result tuples */
 /* workspace for the values constituting the row: */
 Datum *elemvalues;
 bool *elemnulls;
 } row;
 /* for EEOP_ROWCOMPARE_STEP */
 struct
 {
 /* lookup and call data for column comparison function */
 FmgrInfo *finfo;
 FunctionCallInfo fcinfo_data;
 PGFunction fn_addr;
 /* target for comparison resulting in NULL */
 int jumpnull;
 /* target for comparison yielding inequality */
 int jumpdone;
 } rowcompare_step;
 /* for EEOP_ROWCOMPARE_FINAL */
 struct
 {
 RowCompareType rctype;
 } rowcompare_final;
 /* for EEOP_MINMAX */
 struct
 {
 /* workspace for argument values */
 Datum *values;
 bool *nulls;
 int nelems;
 /* is it GREATEST or LEAST? */
 MinMaxOp op;
 /* lookup and call data for comparison function */
 FmgrInfo *finfo;
 FunctionCallInfo fcinfo_data;
 } minmax;
 /* for EEOP_FIELDSELECT */
 struct
 {
 AttrNumber fieldnum; /* field number to extract */
 Oid resulttype; /* field s type */
 /* cached tupdesc pointer - filled at runtime */
 TupleDesc argdesc;
 } fieldselect;
 /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */
 struct
 {
 /* original expression node */
 FieldStore *fstore;
 /* cached tupdesc pointer - filled at runtime */
 /* note that a DEFORM and FORM pair share the same tupdesc */
 TupleDesc *argdesc;
 /* workspace for column values */
 Datum *values;
 bool *nulls;
 int ncolumns;
 } fieldstore;
 /* for EEOP_ARRAYREF_SUBSCRIPT */
 struct
 {
 /* too big to have inline */
 struct ArrayRefState *state;
 int off; /* 0-based index of this subscript */
 bool isupper; /* is it upper or lower subscript? */
 int jumpdone; /* jump here on null */
 } arrayref_subscript;
 /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */
 struct
 {
 /* too big to have inline */
 struct ArrayRefState *state;
 } arrayref;
 /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */
 struct
 {
 /* name of constraint */
 char *constraintname;
 /* where the result of a CHECK constraint will be stored */
 Datum *checkvalue;
 bool *checknull;
 /* OID of domain type */
 Oid resulttype;
 } domaincheck;
 /* for EEOP_CONVERT_ROWTYPE */
 struct
 {
 ConvertRowtypeExpr *convert; /* original expression */
 /* these three fields are filled at runtime: */
 TupleDesc indesc; /* tupdesc for input type */
 TupleDesc outdesc; /* tupdesc for output type */
 TupleConversionMap *map; /* column mapping */
 bool initialized; /* initialized for current types? */
 } convert_rowtype;
 /* for EEOP_SCALARARRAYOP */
 struct
 {
 /* element_type/typlen/typbyval/typalign are filled at runtime */
 Oid element_type; /* InvalidOid if not yet filled */
 bool useOr; /* use OR or AND semantics? */
 int16 typlen; /* array element type storage info */
 bool typbyval;
 char typalign;
 FmgrInfo *finfo; /* function s lookup data */
 FunctionCallInfo fcinfo_data; /* arguments etc */
 /* faster to access without additional indirection: */
 PGFunction fn_addr; /* actual call address */
 } scalararrayop;
 /* for EEOP_XMLEXPR */
 struct
 {
 XmlExpr *xexpr; /* original expression node */
 /* workspace for evaluating named args, if any */
 Datum *named_argvalue;
 bool *named_argnull;
 /* workspace for evaluating unnamed args, if any */
 Datum *argvalue;
 bool *argnull;
 } xmlexpr;
 /* for EEOP_AGGREF */
 struct
 {
 /* out-of-line state, modified by nodeAgg.c */
 AggrefExprState *astate;
 } aggref;
 /* for EEOP_GROUPING_FUNC */
 struct
 {
 AggState *parent; /* parent Agg */
 List *clauses; /* integer list of column numbers */
 } grouping_func;
 /* for EEOP_WINDOW_FUNC */
 struct
 {
 /* out-of-line state, modified by nodeWindowFunc.c */
 WindowFuncExprState *wfstate;
 } window_func;
 /* for EEOP_SUBPLAN */
 struct
 {
 /* out-of-line state, created by nodeSubplan.c */
 SubPlanState *sstate;
 } subplan;
 /* for EEOP_ALTERNATIVE_SUBPLAN */
 struct
 {
 /* out-of-line state, created by nodeSubplan.c */
 AlternativeSubPlanState *asstate;
 } alternative_subplan;
 /* for EEOP_AGG_*DESERIALIZE */
 struct
 {
 AggState *aggstate;
 FunctionCallInfo fcinfo_data;
 int jumpnull;
 } agg_deserialize;
 /* for EEOP_AGG_STRICT_INPUT_CHECK */
 struct
 {
 bool *nulls;
 int nargs;
 int jumpnull;
 } agg_strict_input_check;
 /* for EEOP_AGG_INIT_TRANS */
 struct
 {
 AggState *aggstate;
 AggStatePerTrans pertrans;
 ExprContext *aggcontext;
 int setno;
 int transno;
 int setoff;
 int jumpnull;
 } agg_init_trans;
 /* for EEOP_AGG_STRICT_TRANS_CHECK */
 struct
 {
 AggState *aggstate;
 int setno;
 int transno;
 int setoff;
 int jumpnull;
 } agg_strict_trans_check;
 /* for EEOP_AGG_{PLAIN,ORDERED}_TRANS* */
 struct
 {
 AggState *aggstate;
 AggStatePerTrans pertrans;
 ExprContext *aggcontext;
 int setno;
 int transno;
 int setoff;
 } agg_trans;
 } d;
} ExprEvalStep;

FmgrInfo
在函數通過 fmgr 調用前, 該結構體持有系統目錄 (字典) 信息, 用于檢索相關信息.
如果相同的函數將被調用多次, 檢索只需要完成一次即可, 該結構體會緩存多次使用.

/*
 * This struct holds the system-catalog information that must be looked up
 * before a function can be called through fmgr. If the same function is
 * to be called multiple times, the lookup need be done only once and the
 * info struct saved for re-use.
 *  在函數通過 fmgr 調用前, 該結構體持有系統目錄 (字典) 信息, 用于檢索相關信息.
 *  如果相同的函數將被調用多次, 檢索只需要完成一次即可, 該結構體會緩存多次使用.
 *
 * Note that fn_expr really is parse-time-determined information about the
 * arguments, rather than about the function itself. But it s convenient
 * to store it here rather than in FunctionCallInfoData, where it might more
 * logically belong.
 *  注意,fn_expr 實際上是關于參數的解析時確定的信息, 而不是函數自身.
 *  但 fn_expr 在這里存儲而不是 FunctionCallInfoData 中存儲, 因為從邏輯上來說, 它就應該屬于那.
 *
 * fn_extra is available for use by the called function; all other fields
 * should be treated as read-only after the struct is created.
 * fn_extra 可用于被調用函數的使用; 所有其他字段應該在結構體創建后被處理為只讀.
 */
typedef struct FmgrInfo
 // 指向函數或者將被調用的處理器
 PGFunction fn_addr; /* pointer to function or handler to be called */
 // 函數的 oid
 Oid fn_oid; /* OID of function (NOT of handler, if any) */
 // 輸入參數的個數,0..FUNC_MAX_ARGS
 short fn_nargs; /* number of input args (0..FUNC_MAX_ARGS) */
 // 函數是否嚴格(strict), 輸入 NULL, 輸出 NULL
 bool fn_strict; /* function is  strict  (NULL in =  NULL out) */
 // 函數是否返回集合
 bool fn_retset; /* function returns a set */
 // 如 track_functions   this, 則收集統計信息
 unsigned char fn_stats; /* collect stats if track_functions   this */
 //handler 使用的額外空間
 void *fn_extra; /* extra space for use by handler */
 // 存儲 fn_extra 的內存上下文
 MemoryContext fn_mcxt; /* memory context to store fn_extra in */
 // 表達式解析樹, 或者為 NULL
 fmNodePtr fn_expr; /* expression parse tree for call, or NULL */
} FmgrInfo;
typedef struct Node *fmNodePtr;

FunctionCallInfoData
該結構體存儲了實際傳遞給 fmgr-called 函數的參數

/*
 * This struct is the data actually passed to an fmgr-called function.
 *  該結構體存儲了實際傳遞給 fmgr-called 函數的參數
 *
 * The called function is expected to set isnull, and possibly resultinfo or
 * fields in whatever resultinfo points to. It should not change any other
 * fields. (In particular, scribbling on the argument arrays is a bad idea,
 * since some callers assume they can re-call with the same arguments.)
 *  被調用的函數期望設置 isnull 以及可能的 resultinfo 或者 resultinfo 指向的域字段.
 *  不應該改變其他字段.
 * (特別的, 在參數數組上亂寫是個壞主意, 因為某些調用者假定它們可以使用相同的參數重復調用)
 */
typedef struct FunctionCallInfoData
 // 指向該調用的檢索信息
 FmgrInfo *flinfo; /* ptr to lookup info used for this call */
 // 調用上下文
 fmNodePtr context; /* pass info about context of call */
 // 傳遞或返回關于結果的特別信息
 fmNodePtr resultinfo; /* pass or return extra info about result */
 // 函數的 collation
 Oid fncollation; /* collation for function to use */
#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
 // 如結果為 NULL, 則必須設置為 T
 bool isnull; /* function must set true if result is NULL */
 // 實際傳遞的參數個數
 short nargs; /* # arguments actually passed */
#define FIELDNO_FUNCTIONCALLINFODATA_ARG 6
 // 傳遞給函數的參數
 Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
#define FIELDNO_FUNCTIONCALLINFODATA_ARGNULL 7
 // 如 arg[i]為 NULL, 則對應的值為 T
 bool argnull[FUNC_MAX_ARGS]; /* T if arg[i] is actually NULL */
} FunctionCallInfoData;
 * All functions that can be called directly by fmgr must have this signature.
 * (Other functions can be called by using a handler that does have this
 * signature.)
 *  所有函數可以通過 fmgr 直接調用, 但必須持有簽名.
 * (其他函數可通過使用 handler 的方式調用, 也有此簽名)
 */
typedef struct FunctionCallInfoData *FunctionCallInfo;

二、源碼解讀

ExecInitFunc 函數為類函數表達式的執行配置步驟, 在 *state 的 steps 中追加參數解析步驟, 同時設置 *scratch 以便可以 push 到步驟中.
其主要邏輯如下:
1. 檢查調用函數的權限
2. 檢查 nargs 是否合法
3. 為該調用分配函數檢索數據和參數空間
4. 配置主要的 fmgr 檢索信息
5. 初始化函數調用參數結構體
6. 解析參數直接存儲到 fcinfo 結構體中
7. 根據函數的嚴格性和統計級別插入相應的 opcode

/*
 * Perform setup necessary for the evaluation of a function-like expression,
 * appending argument evaluation steps to the steps list in *state, and
 * setting up *scratch so it is ready to be pushed.
 *  為類函數表達式的執行配置步驟, 在 *state 的 steps 中追加參數解析步驟,
 *  同時設置 *scratch 以便可以 push 到步驟中.
 *
 * *scratch is not pushed here, so that callers may override the opcode,
 * which is useful for function-like cases like DISTINCT.
 * *scratch 不在這里 push, 以便調用者可以覆蓋 opcode, 這在 DISTINCT 這類操作時很有用.
 */
static void
ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
 Oid inputcollid, ExprState *state)
 int nargs = list_length(args);
 AclResult aclresult;
 FmgrInfo *flinfo;
 FunctionCallInfo fcinfo;
 int argno;
 ListCell *lc;
 /* Check permission to call function */
 // 檢查調用函數的權限
 aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
 if (aclresult != ACLCHECK_OK)
 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
 InvokeFunctionExecuteHook(funcid);
 /*
 * Safety check on nargs. Under normal circumstances this should never
 * fail, as parser should check sooner. But possibly it might fail if
 * server has been compiled with FUNC_MAX_ARGS smaller than some functions
 * declared in pg_proc?
 *  檢查 nargs. 在通常的環境下, 這不會出現異常.
 *  但如果服務器使用 FUNC_MAX_ARGS 宏定義比某些在 pg_proc 中定義的函數要小時會出現問題.
 */
 if (nargs   FUNC_MAX_ARGS)
 ereport(ERROR,
 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
 errmsg_plural( cannot pass more than %d argument to a function ,
  cannot pass more than %d arguments to a function ,
 FUNC_MAX_ARGS,
 FUNC_MAX_ARGS)));
 /* Allocate function lookup data and parameter workspace for this call */
 // 為該調用分配函數檢索數據和參數空間
 scratch- d.func.finfo = palloc0(sizeof(FmgrInfo));
 scratch- d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData));
 flinfo = scratch- d.func.finfo;
 fcinfo = scratch- d.func.fcinfo_data;
 /* Set up the primary fmgr lookup information */
 // 配置主要的 fmgr 檢索信息
 fmgr_info(funcid, flinfo);
 fmgr_info_set_expr((Node *) node, flinfo);
 /* Initialize function call parameter structure too */
 // 初始化函數調用參數結構體
 InitFunctionCallInfoData(*fcinfo, flinfo,
 nargs, inputcollid, NULL, NULL);
 /* Keep extra copies of this info to save an indirection at runtime */
 // 保留此信息的額外副本, 以便在運行時保存間接信息
 scratch- d.func.fn_addr = flinfo- fn_addr;
 scratch- d.func.nargs = nargs;
 /* We only support non-set functions here */
 // 只支持 non-set 函數
 if (flinfo- fn_retset)
 ereport(ERROR,
 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 errmsg(set-valued function called in context that cannot accept a set),
 state- parent ?
 executor_errposition(state- parent- state,
 exprLocation((Node *) node)) : 0));
 /* Build code to evaluate arguments directly into the fcinfo struct */
 // 解析參數直接存儲到 fcinfo 結構體中
 argno = 0;
 foreach(lc, args)
 {
 // 遍歷參數
 Expr *arg = (Expr *) lfirst(lc);
 if (IsA(arg, Const))
 {
 // 常量
 /*
 * Don t evaluate const arguments every round; especially
 * interesting for constants in comparisons.
 *  不要每輪都對常量參數進行解析, 只需要關注在對比中感興趣的常量即可.
 */
 Const *con = (Const *) arg;
 fcinfo- arg[argno] = con- constvalue;
 fcinfo- argnull[argno] = con- constisnull;
 }
 else
 {
 // 非常量, 則遞歸調用
 ExecInitExprRec(arg, state,
  fcinfo- arg[argno],  fcinfo- argnull[argno]);
 }
 argno++;
 }
 /* Insert appropriate opcode depending on strictness and stats level */
 // 根據函數的嚴格性和統計級別插入相應的 opcode
 if (pgstat_track_functions  = flinfo- fn_stats)
 { if (flinfo- fn_strict   nargs   0)
 scratch- opcode = EEOP_FUNCEXPR_STRICT;
 else
 scratch- opcode = EEOP_FUNCEXPR;
 }
 else
 { if (flinfo- fn_strict   nargs   0)
 scratch- opcode = EEOP_FUNCEXPR_STRICT_FUSAGE;
 else
 scratch- opcode = EEOP_FUNCEXPR_FUSAGE;
 }
}

三、跟蹤分析

測試腳本

testdb=# select 1+id,c2 from t_expr where id   3;

設置斷點, 跟蹤

(gdb) b ExecInitFunc
Breakpoint 1 at 0x6c8c33: file execExpr.c, line 2160.
(gdb) c
Continuing.
Breakpoint 1, ExecInitFunc (scratch=0x7ffd862de730, node=0x2e675d8, args=0x2e67520, funcid=177, inputcollid=0, 
 state=0x2f228c0) at execExpr.c:2160
2160 int nargs = list_length(args);
(gdb) bt
#0 ExecInitFunc (scratch=0x7ffd862de730, node=0x2e675d8, args=0x2e67520, funcid=177, inputcollid=0, state=0x2f228c0)
 at execExpr.c:2160
#1 0x00000000006c6200 in ExecInitExprRec (node=0x2e675d8, state=0x2f228c0, resv=0x2f228c8, resnull=0x2f228c5)
 at execExpr.c:893
#2 0x00000000006c55bc in ExecBuildProjectionInfo (targetList=0x2f2a348, econtext=0x2f223a8, slot=0x2f22820, 
 parent=0x2f22190, inputDesc=0x7ff79b051ab8) at execExpr.c:452
#3 0x00000000006e60d5 in ExecAssignProjectionInfo (planstate=0x2f22190, inputDesc=0x7ff79b051ab8) at execUtils.c:468
#4 0x00000000006e613c in ExecConditionalAssignProjectionInfo (planstate=0x2f22190, inputDesc=0x7ff79b051ab8, varno=1)
 at execUtils.c:493
#5 0x00000000006e23f5 in ExecAssignScanProjectionInfo (node=0x2f22190) at execScan.c:240
#6 0x0000000000700afc in ExecInitIndexScan (node=0x2e425f0, estate=0x2f21f78, eflags=16) at nodeIndexscan.c:962
#7 0x00000000006e00cc in ExecInitNode (node=0x2e425f0, estate=0x2f21f78, eflags=16) at execProcnode.c:217
#8 0x00000000006d6abe in InitPlan (queryDesc=0x2e65688, eflags=16) at execMain.c:1046
#9 0x00000000006d58ad in standard_ExecutorStart (queryDesc=0x2e65688, eflags=16) at execMain.c:265
#10 0x00000000006d5649 in ExecutorStart (queryDesc=0x2e65688, eflags=0) at execMain.c:147
#11 0x00000000008c18d6 in PortalStart (portal=0x2eaf608, params=0x0, eflags=0, snapshot=0x0) at pquery.c:520
#12 0x00000000008bbe1b in exec_simple_query (query_string=0x2e40d78  select 1+id,c2 from t_expr where id   3;)
 at postgres.c:1106
#13 0x00000000008c0191 in PostgresMain (argc=1, argv=0x2e6ecb8, dbname=0x2e6eb20  testdb , username=0x2e3da98  xdb)
 at postgres.c:4182
#14 0x000000000081e06c in BackendRun (port=0x2e62ae0) at postmaster.c:4361
#15 0x000000000081d7df in BackendStartup (port=0x2e62ae0) at postmaster.c:4033
#16 0x0000000000819bd9 in ServerLoop () at postmaster.c:1706
#17 0x000000000081948f in PostmasterMain (argc=1, argv=0x2e3ba50) at postmaster.c:1379
#18 0x0000000000742931 in main (argc=1, argv=0x2e3ba50) at main.c:228
(gdb)

輸入參數

(gdb) p *scratch --   步驟
$1 = {opcode = 0, resvalue = 0x2f228c8, resnull = 0x2f228c5, d = {fetch = {last_var = 0, known_desc = 0x0}, var = { attnum = 0, vartype = 0}, wholerow = {var = 0x0, first = false, slow = false, tupdesc = 0x0, junkFilter = 0x0}, 
 assign_var = {resultnum = 0, attnum = 0}, assign_tmp = {resultnum = 0}, constval = {value = 0, isnull = false}, func = { finfo = 0x0, fcinfo_data = 0x0, fn_addr = 0x0, nargs = 0}, boolexpr = {anynull = 0x0, jumpdone = 0}, qualexpr = { jumpdone = 0}, jump = {jumpdone = 0}, nulltest_row = {argdesc = 0x0}, param = {paramid = 0, paramtype = 0}, cparam = { paramfunc = 0x0, paramarg = 0x0, paramid = 0, paramtype = 0}, casetest = {value = 0x0, isnull = 0x0}, 
 make_readonly = {value = 0x0, isnull = 0x0}, iocoerce = {finfo_out = 0x0, fcinfo_data_out = 0x0, finfo_in = 0x0, 
 fcinfo_data_in = 0x0}, sqlvaluefunction = {svf = 0x0}, nextvalueexpr = {seqid = 0, seqtypid = 0}, arrayexpr = {
 elemvalues = 0x0, elemnulls = 0x0, nelems = 0, elemtype = 0, elemlength = 0, elembyval = false, elemalign = 0  \000 , 
 multidims = false}, arraycoerce = {elemexprstate = 0x0, resultelemtype = 0, amstate = 0x0}, row = {tupdesc = 0x0, 
 elemvalues = 0x0, elemnulls = 0x0}, rowcompare_step = {finfo = 0x0, fcinfo_data = 0x0, fn_addr = 0x0, jumpnull = 0, 
 jumpdone = 0}, rowcompare_final = {rctype = 0}, minmax = {values = 0x0, nulls = 0x0, nelems = 0, op = IS_GREATEST, 
 finfo = 0x0, fcinfo_data = 0x0}, fieldselect = {fieldnum = 0, resulttype = 0, argdesc = 0x0}, fieldstore = { fstore = 0x0, argdesc = 0x0, values = 0x0, nulls = 0x0, ncolumns = 0}, arrayref_subscript = {state = 0x0, off = 0, 
 isupper = false, jumpdone = 0}, arrayref = {state = 0x0}, domaincheck = {constraintname = 0x0, checkvalue = 0x0, 
 checknull = 0x0, resulttype = 0}, convert_rowtype = {convert = 0x0, indesc = 0x0, outdesc = 0x0, map = 0x0, 
 initialized = false}, scalararrayop = {element_type = 0, useOr = false, typlen = 0, typbyval = false, 
 typalign = 0  \000 , finfo = 0x0, fcinfo_data = 0x0, fn_addr = 0x0}, xmlexpr = {xexpr = 0x0, named_argvalue = 0x0, 
 named_argnull = 0x0, argvalue = 0x0, argnull = 0x0}, aggref = {astate = 0x0}, grouping_func = {parent = 0x0, 
 clauses = 0x0}, window_func = {wfstate = 0x0}, subplan = {sstate = 0x0}, alternative_subplan = {asstate = 0x0}, 
 agg_deserialize = {aggstate = 0x0, fcinfo_data = 0x0, jumpnull = 0}, agg_strict_input_check = {nulls = 0x0, nargs = 0, 
 jumpnull = 0}, agg_init_trans = {aggstate = 0x0, pertrans = 0x0, aggcontext = 0x0, setno = 0, transno = 0, 
 setoff = 0, jumpnull = 0}, agg_strict_trans_check = {aggstate = 0x0, setno = 0, transno = 0, setoff = 0, 
 jumpnull = 0}, agg_trans = {aggstate = 0x0, pertrans = 0x0, aggcontext = 0x0, setno = 0, transno = 0, setoff = 0}}}
######################################### 
(gdb) p *node
$2 = {type = T_OpExpr}
(gdb) p *(OpExpr *)node --  OpExpr 節點
$3 = {xpr = {type = T_OpExpr}, opno = 551, opfuncid = 177, opresulttype = 23, opretset = false, opcollid = 0, 
 inputcollid = 0, args = 0x2e67520, location = 8}
testdb=# \x
Expanded display is on.
testdb=# select * from pg_proc where oid=177; --  opfuncid = 177 對應的系統 proc
-[ RECORD 1 ]---+-------
proname | int4pl
pronamespace | 11
proowner | 10
prolang | 12
procost | 1
prorows | 0
provariadic | 0
protransform | -
prokind | f
prosecdef | f
proleakproof | f
proisstrict | t
proretset | f
provolatile | i
proparallel | s
pronargs | 2
pronargdefaults | 0
prorettype | 23
proargtypes | 23 23
proallargtypes | 
proargmodes | 
proargnames | 
proargdefaults | 
protrftypes | 
prosrc | int4pl
probin | 
proconfig | 
proacl | 
#########################################
(gdb) p *args
$4 = {type = T_List, length = 2, head = 0x2e674f8, tail = 0x2e675b0}
#########################################
(gdb) p *state --  ExprState
$5 = {tag = {type = T_ExprState}, flags = 0  \000 , resnull = false, resvalue = 0, resultslot = 0x2f22820, 
 steps = 0x2f229b0, evalfunc = 0x0, expr = 0x2f2a348, evalfunc_private = 0x0, steps_len = 1, steps_alloc = 16, 
 parent = 0x2f22190, ext_params = 0x0, innermost_caseval = 0x0, innermost_casenull = 0x0, innermost_domainval = 0x0, 
 innermost_domainnull = 0x0}

1. 檢查調用函數的權限

(gdb) n
2168 aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
(gdb) 
2169 if (aclresult != ACLCHECK_OK)
(gdb) 
2171 InvokeFunctionExecuteHook(funcid);
(gdb)

2. 檢查 nargs 是否合法

(gdb) 
2179 if (nargs   FUNC_MAX_ARGS)
(gdb)

3. 為該調用分配函數檢索數據和參數空間

(gdb) 
2188 scratch- d.func.finfo = palloc0(sizeof(FmgrInfo));
(gdb) 
2189 scratch- d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData));
(gdb)

4. 配置主要的 fmgr 檢索信息

(gdb) 
2194 fmgr_info(funcid, flinfo);
(gdb) 
2195 fmgr_info_set_expr((Node *) node, flinfo);
(gdb) 
(gdb) p *flinfo
$6 = {fn_addr = 0x93d60c  int4pl , fn_oid = 177, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2  \002 , 
 fn_extra = 0x0, fn_mcxt = 0x2f21e60, fn_expr = 0x2e675d8}
(gdb) p *node
$7 = {type = T_OpExpr}
(gdb) p *(OpExpr *)node
$8 = {xpr = {type = T_OpExpr}, opno = 551, opfuncid = 177, opresulttype = 23, opretset = false, opcollid = 0, 
 inputcollid = 0, args = 0x2e67520, location = 8}
(gdb)

5. 初始化函數調用參數結構體

(gdb) 
2198 InitFunctionCallInfoData(*fcinfo, flinfo,
(gdb) n
2202 scratch- d.func.fn_addr = flinfo- fn_addr;
(gdb) 
2203 scratch- d.func.nargs = nargs;
(gdb) 
2206 if (flinfo- fn_retset)
(gdb) 
2215 argno = 0;
(gdb) 
2216 foreach(lc, args)
(gdb) p nargs
$9 = 2
(gdb) p flinfo- fn_addr
$10 = (PGFunction) 0x93d60c  int4pl 
(gdb) p *fcinfo
$11 = {flinfo = 0x2f226b0, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = { 0  repeats 100 times}, argnull = {false  repeats 100 times}}
(gdb) p scratch- d.func
$12 = {finfo = 0x2f226b0, fcinfo_data = 0x2f22dc8, fn_addr = 0x93d60c  int4pl , nargs = 2}
(gdb)

6. 循環解析參數 args 直接存儲到 fcinfo 結構體中
第 1 個參數, 是常量 1

(gdb) n
2218 Expr *arg = (Expr *) lfirst(lc);
(gdb) 
2220 if (IsA(arg, Const))
(gdb) p *arg
$13 = {type = T_Const}
(gdb) p *(Const *)arg
$14 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 1, 
 constisnull = false, constbyval = true, location = 7}
(gdb) n
2226 Const *con = (Const *) arg;
(gdb) 
2228 fcinfo- arg[argno] = con- constvalue;
(gdb) 
2229 fcinfo- argnull[argno] = con- constisnull;
(gdb) 
2236 argno++;
(gdb)

第 2 個參數, 是 Var, 遞歸調用 ExecInitExprRec 解析

(gdb) 
2216 foreach(lc, args)
(gdb) 
2218 Expr *arg = (Expr *) lfirst(lc);
(gdb) 
2220 if (IsA(arg, Const))
(gdb) 
2233 ExecInitExprRec(arg, state,
(gdb) p *arg
$15 = {type = T_Var}
(gdb) p *(Var *)arg
$16 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 23, vartypmod = -1, varcollid = 0, varlevelsup = 0, 
 varnoold = 1, varoattno = 1, location = 9}
(gdb) n
2236 argno++;
(gdb) 
(gdb) n
2216 foreach(lc, args)
(gdb)

7. 根據函數的嚴格性和統計級別插入相應的 opcode

2240 if (pgstat_track_functions  = flinfo- fn_stats)
(gdb) n
2242 if (flinfo- fn_strict   nargs   0)
(gdb) 
2243 scratch- opcode = EEOP_FUNCEXPR_STRICT;
(gdb) p pgstat_track_functions
$17 = 0
(gdb) p flinfo- fn_stats
$18 = 2  \002 
(gdb) n

完成調用

2254 }
(gdb) 
ExecInitExprRec (node=0x2e675d8, state=0x2f228c0, resv=0x2f228c8, resnull=0x2f228c5) at execExpr.c:896
896 ExprEvalPushStep(state,  scratch);
(gdb)

“怎么使用 PostgreSQL 的 ExprEvalStep”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注丸趣 TV 網站,丸趣 TV 小編將為大家輸出更多高質量的實用文章!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-24發表,共計25676字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 赣州市| 永和县| 六盘水市| 东光县| 尚义县| 临沭县| 厦门市| 亳州市| 康保县| 南阳市| 五莲县| 高密市| 龙口市| 镇赉县| 丹东市| 阳朔县| 神池县| 中宁县| 嘉黎县| 辽阳县| 新乡市| 志丹县| 新昌县| 两当县| 平潭县| 万年县| 察隅县| 长治市| 夹江县| 彝良县| 金塔县| 库车县| 平山县| 班玛县| 视频| 且末县| 重庆市| 万盛区| 梁平县| 舟山市| 马尔康县|