文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么使用PostgreSQL中ExecInitExprRec函数

2024-04-02 19:55

关注

本篇内容主要讲解“怎么使用PostgreSQL中ExecInitExprRec函数”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用PostgreSQL中ExecInitExprRec函数”吧!

EEO_XXX宏定义
opcode分发器宏定义


#if defined(EEO_USE_COMPUTED_GOTO)
//--------------- 定义了EEO_USE_COMPUTED_GOTO

//跳转target -> opcode搜索表结构体
typedef struct ExprEvalOpLookup
{
    const void *opcode;
    ExprEvalOp  op;
} ExprEvalOpLookup;

static const void **dispatch_table = NULL;

static ExprEvalOpLookup reverse_dispatch_table[EEOP_LAST];
#define EEO_SWITCH()
#define EEO_CASE(name)      CASE_##name:
#define EEO_DISPATCH()      goto *((void *) op->opcode)
#define EEO_OPCODE(opcode)  ((intptr_t) dispatch_table[opcode])
#else                           
//--------------- 没有定义EEO_USE_COMPUTED_GOTO
#define EEO_SWITCH()        starteval: switch ((ExprEvalOp) op->opcode)
#define EEO_CASE(name)      case name:
#define EEO_DISPATCH()      goto starteval
#define EEO_OPCODE(opcode)  (opcode)
#endif                          
#define EEO_NEXT() \
    do { \
        op++; \
        EEO_DISPATCH(); \
    } while (0)
#define EEO_JUMP(stepno) \
    do { \
        op = &state->steps[stepno]; \
        EEO_DISPATCH(); \
    } while (0)

ExprState
解析表达式中运行期状态节点



#define EEO_FLAG_IS_QUAL                    (1 << 0)
typedef struct ExprState
{
    //节点tag
    Node        tag;
    //EEO_FLAG_IS_QUAL
    uint8       flags;          
    
#define FIELDNO_EXPRSTATE_RESNULL 2
    bool        resnull;
#define FIELDNO_EXPRSTATE_RESVALUE 3
    Datum       resvalue;
    
#define FIELDNO_EXPRSTATE_RESULTSLOT 4
    TupleTableSlot *resultslot;
    
    struct ExprEvalStep *steps;
    
    ExprStateEvalFunc evalfunc;
    
    //原始的表达式树,仅用于debugging
    Expr       *expr;
    
    //evalfunc的私有状态
    void       *evalfunc_private;
    
    //当前的步数
    int         steps_len;      
    //steps数组已分配的长度
    int         steps_alloc;    
    //父PlanState节点(如存在)
    struct PlanState *parent;   
    //用于编译PARAM_EXTERN节点
    ParamListInfo ext_params;   
    //
    Datum      *innermost_caseval;
    bool       *innermost_casenull;
    Datum      *innermost_domainval;
    bool       *innermost_domainnull;
} ExprState;

ExprEvalStep
表达式解析步骤结构体

typedef struct ExprEvalStep
{
    
    intptr_t    opcode;
    
    //存储该步骤的结果
    Datum      *resvalue;
    bool       *resnull;
    
    union
    {
        
        //用于EEOP_INNER/OUTER/SCAN_FETCHSOME
        struct
        {
            
            //获取到的属性编号
            int         last_var;
            TupleDesc   known_desc;
        }           fetch;
        
        struct
        {
            
            //attnum是常规VAR的attr number - 1
            
            //对于SYSVAR,该值是常规的attr number
            int         attnum;
            Oid         vartype;    
        }           var;
        
        struct
        {
            Var        *var;    
            bool        first;  
            bool        slow;   
            TupleDesc   tupdesc;    
            JunkFilter *junkFilter; 
        }           wholerow;
        
        struct
        {
            
            int         resultnum;
            
            int         attnum;
        }           assign_var;
        
        struct
        {
            
            int         resultnum;
        }           assign_tmp;
        
        struct
        {
            
            Datum       value;
            bool        isnull;
        }           constval;
        
        //对于EEOP_FUNCEXPR_* / NULLIF / DISTINCT
        struct
        {
            //函数的检索数据
            FmgrInfo   *finfo;  
            //参数信息等
            FunctionCallInfo fcinfo_data;   
            
            //无需额外的指向,更快速的访问
            PGFunction  fn_addr;    
            int         nargs;  
        }           func;
        
        struct
        {
            bool       *anynull;    
            int         jumpdone;   
        }           boolexpr;
        
        struct
        {
            int         jumpdone;   
        }           qualexpr;
        
        struct
        {
            int         jumpdone;   
        }           jump;
        
        struct
        {
            
            TupleDesc   argdesc;
        }           nulltest_row;
        
        struct
        {
            int         paramid;    
            Oid         paramtype;  
        }           param;
        
        struct
        {
            ExecEvalSubroutine paramfunc;   
            void       *paramarg;   
            int         paramid;    
            Oid         paramtype;  
        }           cparam;
        
        struct
        {
            Datum      *value;  
            bool       *isnull;
        }           casetest;
        
        struct
        {
            Datum      *value;  
            bool       *isnull;
        }           make_readonly;
        
        struct
        {
            
            FmgrInfo   *finfo_out;
            FunctionCallInfo fcinfo_data_out;
            
            FmgrInfo   *finfo_in;
            FunctionCallInfo fcinfo_data_in;
        }           iocoerce;
        
        struct
        {
            SQLValueFunction *svf;
        }           sqlvaluefunction;
        
        //EEOP_NEXTVALUEEXPR
        struct
        {
            Oid         seqid;
            Oid         seqtypid;
        }           nextvalueexpr;
        
        struct
        {
            Datum      *elemvalues; 
            bool       *elemnulls;
            int         nelems; 
            Oid         elemtype;   
            int16       elemlength; 
            bool        elembyval;  
            char        elemalign;  
            bool        multidims;  
        }           arrayexpr;
        
        struct
        {
            ExprState  *elemexprstate;  
            Oid         resultelemtype; 
            struct ArrayMapState *amstate;  
        }           arraycoerce;
        
        struct
        {
            TupleDesc   tupdesc;    
            
            Datum      *elemvalues;
            bool       *elemnulls;
        }           row;
        
        struct
        {
            
            FmgrInfo   *finfo;
            FunctionCallInfo fcinfo_data;
            PGFunction  fn_addr;
            
            int         jumpnull;
            
            int         jumpdone;
        }           rowcompare_step;
        
        struct
        {
            RowCompareType rctype;
        }           rowcompare_final;
        
        struct
        {
            
            Datum      *values;
            bool       *nulls;
            int         nelems;
            
            MinMaxOp    op;
            
            FmgrInfo   *finfo;
            FunctionCallInfo fcinfo_data;
        }           minmax;
        
        struct
        {
            AttrNumber  fieldnum;   
            Oid         resulttype; 
            
            TupleDesc   argdesc;
        }           fieldselect;
        
        struct
        {
            
            FieldStore *fstore;
            
            
            TupleDesc  *argdesc;
            
            Datum      *values;
            bool       *nulls;
            int         ncolumns;
        }           fieldstore;
        
        struct
        {
            
            struct ArrayRefState *state;
            int         off;    
            bool        isupper;    
            int         jumpdone;   
        }           arrayref_subscript;
        
        struct
        {
            
            struct ArrayRefState *state;
        }           arrayref;
        
        struct
        {
            
            char       *constraintname;
            
            Datum      *checkvalue;
            bool       *checknull;
            
            Oid         resulttype;
        }           domaincheck;
        
        struct
        {
            ConvertRowtypeExpr *convert;    
            
            TupleDesc   indesc; 
            TupleDesc   outdesc;    
            TupleConversionMap *map;    
            bool        initialized;    
        }           convert_rowtype;
        
        struct
        {
            
            Oid         element_type;   
            bool        useOr;  
            int16       typlen; 
            bool        typbyval;
            char        typalign;
            FmgrInfo   *finfo;  
            FunctionCallInfo fcinfo_data;   
            
            PGFunction  fn_addr;    
        }           scalararrayop;
        
        struct
        {
            XmlExpr    *xexpr;  
            
            Datum      *named_argvalue;
            bool       *named_argnull;
            
            Datum      *argvalue;
            bool       *argnull;
        }           xmlexpr;
        
        struct
        {
            
            AggrefExprState *astate;
        }           aggref;
        
        struct
        {
            AggState   *parent; 
            List       *clauses;    
        }           grouping_func;
        
        struct
        {
            
            WindowFuncExprState *wfstate;
        }           window_func;
        
        struct
        {
            
            SubPlanState *sstate;
        }           subplan;
        
        struct
        {
            
            AlternativeSubPlanState *asstate;
        }           alternative_subplan;
        
        struct
        {
            AggState   *aggstate;
            FunctionCallInfo fcinfo_data;
            int         jumpnull;
        }           agg_deserialize;
        
        struct
        {
            bool       *nulls;
            int         nargs;
            int         jumpnull;
        }           agg_strict_input_check;
        
        struct
        {
            AggState   *aggstate;
            AggStatePerTrans pertrans;
            ExprContext *aggcontext;
            int         setno;
            int         transno;
            int         setoff;
            int         jumpnull;
        }           agg_init_trans;
        
        struct
        {
            AggState   *aggstate;
            int         setno;
            int         transno;
            int         setoff;
            int         jumpnull;
        }           agg_strict_trans_check;
        
        struct
        {
            AggState   *aggstate;
            AggStatePerTrans pertrans;
            ExprContext *aggcontext;
            int         setno;
            int         transno;
            int         setoff;
        }           agg_trans;
    }           d;
} ExprEvalStep;

ExprEvalOp
ExprEvalSteps的鉴频器,定义哪个操作将被执行并且联合体ExprEvalStep->d中的哪个struct将被使用.


typedef enum ExprEvalOp
{
    
    //整个表达式已被解析,返回
    EEOP_DONE,
    
    //在相应的元组slot上应用了slot_getsomeattrs方法
    EEOP_INNER_FETCHSOME,
    EEOP_OUTER_FETCHSOME,
    EEOP_SCAN_FETCHSOME,
    
    //计算非系统Var变量值
    EEOP_INNER_VAR,
    EEOP_OUTER_VAR,
    EEOP_SCAN_VAR,
    
    //计算系统Var变量值
    EEOP_INNER_SYSVAR,
    EEOP_OUTER_SYSVAR,
    EEOP_SCAN_SYSVAR,
    
    //计算整行Var
    EEOP_WHOLEROW,
    
    EEOP_ASSIGN_INNER_VAR,
    EEOP_ASSIGN_OUTER_VAR,
    EEOP_ASSIGN_SCAN_VAR,
    
    //分配ExprState's resvalue/resnull到该列的resultslot中
    EEOP_ASSIGN_TMP,
    
    //同上,应用MakeExpandedObjectReadOnly()
    EEOP_ASSIGN_TMP_MAKE_RO,
    
    //解析常量值
    EEOP_CONST,
    
    EEOP_FUNCEXPR,
    EEOP_FUNCEXPR_STRICT,
    EEOP_FUNCEXPR_FUSAGE,
    EEOP_FUNCEXPR_STRICT_FUSAGE,
    
    EEOP_BOOL_AND_STEP_FIRST,
    EEOP_BOOL_AND_STEP,
    EEOP_BOOL_AND_STEP_LAST,
    
    //与布尔OR表达式类似
    EEOP_BOOL_OR_STEP_FIRST,
    EEOP_BOOL_OR_STEP,
    EEOP_BOOL_OR_STEP_LAST,
    
    //解析布尔NOT表达式
    EEOP_BOOL_NOT_STEP,
    
    //用于ExecQual()中的BOOL_AND_STEP简化版本
    EEOP_QUAL,
    
    //无条件跳转到另外一个步骤
    EEOP_JUMP,
    
    //基于当前结果值的条件跳转
    EEOP_JUMP_IF_NULL,
    EEOP_JUMP_IF_NOT_NULL,
    EEOP_JUMP_IF_NOT_TRUE,
    
    //为scalar值执行NULL测试
    EEOP_NULLTEST_ISNULL,
    EEOP_NULLTEST_ISNOTNULL,
    
    //为行值执行NULL测试
    EEOP_NULLTEST_ROWISNULL,
    EEOP_NULLTEST_ROWISNOTNULL,
    
    //解析BooleanTest表达式
    EEOP_BOOLTEST_IS_TRUE,
    EEOP_BOOLTEST_IS_NOT_TRUE,
    EEOP_BOOLTEST_IS_FALSE,
    EEOP_BOOLTEST_IS_NOT_FALSE,
    
    //解析PARAM_EXEC/EXTERN参数
    EEOP_PARAM_EXEC,
    EEOP_PARAM_EXTERN,
    EEOP_PARAM_CALLBACK,
    
    //返回CaseTestExpr值
    EEOP_CASE_TESTVAL,
    
    //对目标值应用MakeExpandedObjectReadOnly()
    EEOP_MAKE_READONLY,
    
    //解析各种特殊用途的表达式类型
    EEOP_IOCOERCE,
    EEOP_DISTINCT,
    EEOP_NOT_DISTINCT,
    EEOP_NULLIF,
    EEOP_SQLVALUEFUNCTION,
    EEOP_CURRENTOFEXPR,
    EEOP_NEXTVALUEEXPR,
    EEOP_ARRAYEXPR,
    EEOP_ARRAYCOERCE,
    EEOP_ROW,
    
    EEOP_ROWCOMPARE_STEP,
    
    //基于上一步的ROWCOMPARE_STEP操作解析布尔值
    EEOP_ROWCOMPARE_FINAL,
    
    //解析GREATEST()和LEAST()
    EEOP_MINMAX,
    
    //解析FieldSelect表达式
    EEOP_FIELDSELECT,
    
    EEOP_FIELDSTORE_DEFORM,
    
    EEOP_FIELDSTORE_FORM,
    
    //处理数组子脚本.如为NULL则短路表达式为NULL
    EEOP_ARRAYREF_SUBSCRIPT,
    
    EEOP_ARRAYREF_OLD,
    
    //为ArrayRef分配118
    EEOP_ARRAYREF_ASSIGN,
    
    //为ArrayRef提取表达式计算element/slice
    EEOP_ARRAYREF_FETCH,
    
    //为CoerceToDomainValue解析值
    EEOP_DOMAIN_TESTVAL,
    
    //解析域 NOT NULL 约束
    EEOP_DOMAIN_NOTNULL,
    
    //解析单个域CHECK约束
    EEOP_DOMAIN_CHECK,
    
    //解析特殊目的的表达式类型
    EEOP_CONVERT_ROWTYPE,
    EEOP_SCALARARRAYOP,
    EEOP_XMLEXPR,
    EEOP_AGGREF,
    EEOP_GROUPING_FUNC,
    EEOP_WINDOW_FUNC,
    EEOP_SUBPLAN,
    EEOP_ALTERNATIVE_SUBPLAN,
    
    //聚合相关节点
    EEOP_AGG_STRICT_DESERIALIZE,
    EEOP_AGG_DESERIALIZE,
    EEOP_AGG_STRICT_INPUT_CHECK,
    EEOP_AGG_INIT_TRANS,
    EEOP_AGG_STRICT_TRANS_CHECK,
    EEOP_AGG_PLAIN_TRANS_BYVAL,
    EEOP_AGG_PLAIN_TRANS,
    EEOP_AGG_ORDERED_TRANS_DATUM,
    EEOP_AGG_ORDERED_TRANS_TUPLE,
    
    //不存在的操作,比如用于检测数组长度
    EEOP_LAST
} ExprEvalOp;

二、源码解读

ExecInitExprRec函数,把表达式解析需要的步骤追加到ExprState->steps中,可能会递归进入到子表达式节点中.
其主要逻辑是根据节点类型,执行相应的处理逻辑,比如节点类型为OpExpr,则其逻辑为:

case T_OpExpr://操作符表达式
            {
                OpExpr     *op = (OpExpr *) node;
                ExecInitFunc(&scratch, node,
                             op->args, op->opfuncid, op->inputcollid,
                             state);
                ExprEvalPushStep(state, &scratch);
                break;
            }

其他节点类型类似,代码虽然很长,但逻辑清晰简单.


static void
ExecInitExprRec(Expr *node, ExprState *state,
                Datum *resv, bool *resnull)
{
    ExprEvalStep scratch = {0};
    
    //避免出现堆栈溢出
    check_stack_depth();
    
    //步骤的输出位置往往是调用者提供给我们的
    Assert(resv != NULL && resnull != NULL);
    scratch.resvalue = resv;
    scratch.resnull = resnull;
    
    //CASE的顺序与NodeTag枚举类型中的顺序一样
    switch (nodeTag(node))
    {
        case T_Var://VAR
            {
                Var        *variable = (Var *) node;
                if (variable->varattno == InvalidAttrNumber)
                {
                    
                    ExecInitWholeRowVar(&scratch, variable, state);
                }
                else if (variable->varattno <= 0)
                {
                    
                    scratch.d.var.attnum = variable->varattno;
                    scratch.d.var.vartype = variable->vartype;
                    switch (variable->varno)
                    {
                        case INNER_VAR:
                            scratch.opcode = EEOP_INNER_SYSVAR;
                            break;
                        case OUTER_VAR:
                            scratch.opcode = EEOP_OUTER_SYSVAR;
                            break;
                            
                        default:
                            scratch.opcode = EEOP_SCAN_SYSVAR;
                            break;
                    }
                }
                else
                {
                    
                    scratch.d.var.attnum = variable->varattno - 1;
                    scratch.d.var.vartype = variable->vartype;
                    switch (variable->varno)
                    {
                        case INNER_VAR:
                            scratch.opcode = EEOP_INNER_VAR;
                            break;
                        case OUTER_VAR:
                            scratch.opcode = EEOP_OUTER_VAR;
                            break;
                            
                        default:
                            scratch.opcode = EEOP_SCAN_VAR;
                            break;
                    }
                }
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_Const://常量
            {
                Const      *con = (Const *) node;
                scratch.opcode = EEOP_CONST;
                scratch.d.constval.value = con->constvalue;
                scratch.d.constval.isnull = con->constisnull;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_Param://参数
            {
                Param      *param = (Param *) node;
                ParamListInfo params;
                switch (param->paramkind)
                {
                    case PARAM_EXEC:
                        scratch.opcode = EEOP_PARAM_EXEC;
                        scratch.d.param.paramid = param->paramid;
                        scratch.d.param.paramtype = param->paramtype;
                        ExprEvalPushStep(state, &scratch);
                        break;
                    case PARAM_EXTERN:
                        
                        if (state->ext_params)
                            params = state->ext_params;
                        else if (state->parent &&
                                 state->parent->state)
                            params = state->parent->state->es_param_list_info;
                        else
                            params = NULL;
                        if (params && params->paramCompile)
                        {
                            params->paramCompile(params, param, state,
                                                 resv, resnull);
                        }
                        else
                        {
                            scratch.opcode = EEOP_PARAM_EXTERN;
                            scratch.d.param.paramid = param->paramid;
                            scratch.d.param.paramtype = param->paramtype;
                            ExprEvalPushStep(state, &scratch);
                        }
                        break;
                    default:
                        elog(ERROR, "unrecognized paramkind: %d",
                             (int) param->paramkind);
                        break;
                }
                break;
            }
        case T_Aggref://聚集
            {
                Aggref     *aggref = (Aggref *) node;
                AggrefExprState *astate = makeNode(AggrefExprState);
                scratch.opcode = EEOP_AGGREF;
                scratch.d.aggref.astate = astate;
                astate->aggref = aggref;
                if (state->parent && IsA(state->parent, AggState))
                {
                    AggState   *aggstate = (AggState *) state->parent;
                    aggstate->aggs = lcons(astate, aggstate->aggs);
                    aggstate->numaggs++;
                }
                else
                {
                    
                    elog(ERROR, "Aggref found in non-Agg plan node");
                }
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_GroupingFunc:
            {
                GroupingFunc *grp_node = (GroupingFunc *) node;
                Agg        *agg;
                if (!state->parent || !IsA(state->parent, AggState) ||
                    !IsA(state->parent->plan, Agg))
                    elog(ERROR, "GroupingFunc found in non-Agg plan node");
                scratch.opcode = EEOP_GROUPING_FUNC;
                scratch.d.grouping_func.parent = (AggState *) state->parent;
                agg = (Agg *) (state->parent->plan);
                if (agg->groupingSets)
                    scratch.d.grouping_func.clauses = grp_node->cols;
                else
                    scratch.d.grouping_func.clauses = NIL;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_WindowFunc:
            {
                WindowFunc *wfunc = (WindowFunc *) node;
                WindowFuncExprState *wfstate = makeNode(WindowFuncExprState);
                wfstate->wfunc = wfunc;
                if (state->parent && IsA(state->parent, WindowAggState))
                {
                    WindowAggState *winstate = (WindowAggState *) state->parent;
                    int         nfuncs;
                    winstate->funcs = lcons(wfstate, winstate->funcs);
                    nfuncs = ++winstate->numfuncs;
                    if (wfunc->winagg)
                        winstate->numaggs++;
                    
                    wfstate->args = ExecInitExprList(wfunc->args,
                                                     state->parent);
                    wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
                                                      state->parent);
                    
                    if (nfuncs != winstate->numfuncs)
                        ereport(ERROR,
                                (errcode(ERRCODE_WINDOWING_ERROR),
                                 errmsg("window function calls cannot be nested")));
                }
                else
                {
                    
                    elog(ERROR, "WindowFunc found in non-WindowAgg plan node");
                }
                scratch.opcode = EEOP_WINDOW_FUNC;
                scratch.d.window_func.wfstate = wfstate;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_ArrayRef:
            {
                ArrayRef   *aref = (ArrayRef *) node;
                ExecInitArrayRef(&scratch, aref, state, resv, resnull);
                break;
            }
        case T_FuncExpr://函数表达式
            {
                FuncExpr   *func = (FuncExpr *) node;
                ExecInitFunc(&scratch, node,
                             func->args, func->funcid, func->inputcollid,
                             state);
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_OpExpr://操作符表达式
            {
                OpExpr     *op = (OpExpr *) node;
                ExecInitFunc(&scratch, node,
                             op->args, op->opfuncid, op->inputcollid,
                             state);
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_DistinctExpr:
            {
                DistinctExpr *op = (DistinctExpr *) node;
                ExecInitFunc(&scratch, node,
                             op->args, op->opfuncid, op->inputcollid,
                             state);
                
                scratch.opcode = EEOP_DISTINCT;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_NullIfExpr:
            {
                NullIfExpr *op = (NullIfExpr *) node;
                ExecInitFunc(&scratch, node,
                             op->args, op->opfuncid, op->inputcollid,
                             state);
                
                scratch.opcode = EEOP_NULLIF;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_ScalarArrayOpExpr:
            {
                ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
                Expr       *scalararg;
                Expr       *arrayarg;
                FmgrInfo   *finfo;
                FunctionCallInfo fcinfo;
                AclResult   aclresult;
                Assert(list_length(opexpr->args) == 2);
                scalararg = (Expr *) linitial(opexpr->args);
                arrayarg = (Expr *) lsecond(opexpr->args);
                
                aclresult = pg_proc_aclcheck(opexpr->opfuncid,
                                             GetUserId(),
                                             ACL_EXECUTE);
                if (aclresult != ACLCHECK_OK)
                    aclcheck_error(aclresult, OBJECT_FUNCTION,
                                   get_func_name(opexpr->opfuncid));
                InvokeFunctionExecuteHook(opexpr->opfuncid);
                
                finfo = palloc0(sizeof(FmgrInfo));
                fcinfo = palloc0(sizeof(FunctionCallInfoData));
                fmgr_info(opexpr->opfuncid, finfo);
                fmgr_info_set_expr((Node *) node, finfo);
                InitFunctionCallInfoData(*fcinfo, finfo, 2,
                                         opexpr->inputcollid, NULL, NULL);
                
                ExecInitExprRec(scalararg, state,
                                &fcinfo->arg[0], &fcinfo->argnull[0]);
                
                ExecInitExprRec(arrayarg, state, resv, resnull);
                
                scratch.opcode = EEOP_SCALARARRAYOP;
                scratch.d.scalararrayop.element_type = InvalidOid;
                scratch.d.scalararrayop.useOr = opexpr->useOr;
                scratch.d.scalararrayop.finfo = finfo;
                scratch.d.scalararrayop.fcinfo_data = fcinfo;
                scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_BoolExpr:
            {
                BoolExpr   *boolexpr = (BoolExpr *) node;
                int         nargs = list_length(boolexpr->args);
                List       *adjust_jumps = NIL;
                int         off;
                ListCell   *lc;
                
                if (boolexpr->boolop != NOT_EXPR)
                    scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));
                
                off = 0;
                foreach(lc, boolexpr->args)
                {
                    Expr       *arg = (Expr *) lfirst(lc);
                    
                    ExecInitExprRec(arg, state, resv, resnull);
                    
                    switch (boolexpr->boolop)
                    {
                        case AND_EXPR:
                            Assert(nargs >= 2);
                            if (off == 0)
                                scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;
                            else if (off + 1 == nargs)
                                scratch.opcode = EEOP_BOOL_AND_STEP_LAST;
                            else
                                scratch.opcode = EEOP_BOOL_AND_STEP;
                            break;
                        case OR_EXPR:
                            Assert(nargs >= 2);
                            if (off == 0)
                                scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;
                            else if (off + 1 == nargs)
                                scratch.opcode = EEOP_BOOL_OR_STEP_LAST;
                            else
                                scratch.opcode = EEOP_BOOL_OR_STEP;
                            break;
                        case NOT_EXPR:
                            Assert(nargs == 1);
                            scratch.opcode = EEOP_BOOL_NOT_STEP;
                            break;
                        default:
                            elog(ERROR, "unrecognized boolop: %d",
                                 (int) boolexpr->boolop);
                            break;
                    }
                    scratch.d.boolexpr.jumpdone = -1;
                    ExprEvalPushStep(state, &scratch);
                    adjust_jumps = lappend_int(adjust_jumps,
                                               state->steps_len - 1);
                    off++;
                }
                
                foreach(lc, adjust_jumps)
                {
                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];
                    Assert(as->d.boolexpr.jumpdone == -1);
                    as->d.boolexpr.jumpdone = state->steps_len;
                }
                break;
            }
        case T_SubPlan:
            {
                SubPlan    *subplan = (SubPlan *) node;
                SubPlanState *sstate;
                if (!state->parent)
                    elog(ERROR, "SubPlan found with no parent plan");
                sstate = ExecInitSubPlan(subplan, state->parent);
                
                state->parent->subPlan = lappend(state->parent->subPlan,
                                                 sstate);
                scratch.opcode = EEOP_SUBPLAN;
                scratch.d.subplan.sstate = sstate;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_AlternativeSubPlan:
            {
                AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
                AlternativeSubPlanState *asstate;
                if (!state->parent)
                    elog(ERROR, "AlternativeSubPlan found with no parent plan");
                asstate = ExecInitAlternativeSubPlan(asplan, state->parent);
                scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN;
                scratch.d.alternative_subplan.asstate = asstate;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_FieldSelect:
            {
                FieldSelect *fselect = (FieldSelect *) node;
                
                ExecInitExprRec(fselect->arg, state, resv, resnull);
                
                scratch.opcode = EEOP_FIELDSELECT;
                scratch.d.fieldselect.fieldnum = fselect->fieldnum;
                scratch.d.fieldselect.resulttype = fselect->resulttype;
                scratch.d.fieldselect.argdesc = NULL;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_FieldStore:
            {
                FieldStore *fstore = (FieldStore *) node;
                TupleDesc   tupDesc;
                TupleDesc  *descp;
                Datum      *values;
                bool       *nulls;
                int         ncolumns;
                ListCell   *l1,
                           *l2;
                
                tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);
                ncolumns = tupDesc->natts;
                DecrTupleDescRefCount(tupDesc);
                
                values = (Datum *) palloc(sizeof(Datum) * ncolumns);
                nulls = (bool *) palloc(sizeof(bool) * ncolumns);
                
                descp = (TupleDesc *) palloc(sizeof(TupleDesc));
                *descp = NULL;
                
                ExecInitExprRec(fstore->arg, state, resv, resnull);
                
                scratch.opcode = EEOP_FIELDSTORE_DEFORM;
                scratch.d.fieldstore.fstore = fstore;
                scratch.d.fieldstore.argdesc = descp;
                scratch.d.fieldstore.values = values;
                scratch.d.fieldstore.nulls = nulls;
                scratch.d.fieldstore.ncolumns = ncolumns;
                ExprEvalPushStep(state, &scratch);
                
                forboth(l1, fstore->newvals, l2, fstore->fieldnums)
                {
                    Expr       *e = (Expr *) lfirst(l1);
                    AttrNumber  fieldnum = lfirst_int(l2);
                    Datum      *save_innermost_caseval;
                    bool       *save_innermost_casenull;
                    if (fieldnum <= 0 || fieldnum > ncolumns)
                        elog(ERROR, "field number %d is out of range in FieldStore",
                             fieldnum);
                    
                    save_innermost_caseval = state->innermost_caseval;
                    save_innermost_casenull = state->innermost_casenull;
                    state->innermost_caseval = &values[fieldnum - 1];
                    state->innermost_casenull = &nulls[fieldnum - 1];
                    ExecInitExprRec(e, state,
                                    &values[fieldnum - 1],
                                    &nulls[fieldnum - 1]);
                    state->innermost_caseval = save_innermost_caseval;
                    state->innermost_casenull = save_innermost_casenull;
                }
                
                scratch.opcode = EEOP_FIELDSTORE_FORM;
                scratch.d.fieldstore.fstore = fstore;
                scratch.d.fieldstore.argdesc = descp;
                scratch.d.fieldstore.values = values;
                scratch.d.fieldstore.nulls = nulls;
                scratch.d.fieldstore.ncolumns = ncolumns;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_RelabelType:
            {
                
                RelabelType *relabel = (RelabelType *) node;
                ExecInitExprRec(relabel->arg, state, resv, resnull);
                break;
            }
        case T_CoerceViaIO:
            {
                CoerceViaIO *iocoerce = (CoerceViaIO *) node;
                Oid         iofunc;
                bool        typisvarlena;
                Oid         typioparam;
                FunctionCallInfo fcinfo_in;
                
                ExecInitExprRec(iocoerce->arg, state, resv, resnull);
                
                scratch.opcode = EEOP_IOCOERCE;
                
                scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
                scratch.d.iocoerce.fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData));
                getTypeOutputInfo(exprType((Node *) iocoerce->arg),
                                  &iofunc, &typisvarlena);
                fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);
                fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);
                InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,
                                         scratch.d.iocoerce.finfo_out,
                                         1, InvalidOid, NULL, NULL);
                
                scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
                scratch.d.iocoerce.fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData));
                getTypeInputInfo(iocoerce->resulttype,
                                 &iofunc, &typioparam);
                fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);
                fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);
                InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,
                                         scratch.d.iocoerce.finfo_in,
                                         3, InvalidOid, NULL, NULL);
                
                fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
                fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam);
                fcinfo_in->argnull[1] = false;
                fcinfo_in->arg[2] = Int32GetDatum(-1);
                fcinfo_in->argnull[2] = false;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_ArrayCoerceExpr:
            {
                ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
                Oid         resultelemtype;
                ExprState  *elemstate;
                
                ExecInitExprRec(acoerce->arg, state, resv, resnull);
                resultelemtype = get_element_type(acoerce->resulttype);
                if (!OidIsValid(resultelemtype))
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                             errmsg("target type is not an array")));
                
                elemstate = makeNode(ExprState);
                elemstate->expr = acoerce->elemexpr;
                elemstate->parent = state->parent;
                elemstate->ext_params = state->ext_params;
                elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
                elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
                ExecInitExprRec(acoerce->elemexpr, elemstate,
                                &elemstate->resvalue, &elemstate->resnull);
                if (elemstate->steps_len == 1 &&
                    elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
                {
                    
                    elemstate = NULL;
                }
                else
                {
                    
                    scratch.opcode = EEOP_DONE;
                    ExprEvalPushStep(elemstate, &scratch);
                    
                    ExecReadyExpr(elemstate);
                }
                scratch.opcode = EEOP_ARRAYCOERCE;
                scratch.d.arraycoerce.elemexprstate = elemstate;
                scratch.d.arraycoerce.resultelemtype = resultelemtype;
                if (elemstate)
                {
                    
                    scratch.d.arraycoerce.amstate =
                        (ArrayMapState *) palloc0(sizeof(ArrayMapState));
                }
                else
                {
                    
                    scratch.d.arraycoerce.amstate = NULL;
                }
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_ConvertRowtypeExpr:
            {
                ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
                
                ExecInitExprRec(convert->arg, state, resv, resnull);
                
                scratch.opcode = EEOP_CONVERT_ROWTYPE;
                scratch.d.convert_rowtype.convert = convert;
                scratch.d.convert_rowtype.indesc = NULL;
                scratch.d.convert_rowtype.outdesc = NULL;
                scratch.d.convert_rowtype.map = NULL;
                scratch.d.convert_rowtype.initialized = false;
                ExprEvalPushStep(state, &scratch);
                break;
            }
            
        case T_CaseExpr:
            {
                CaseExpr   *caseExpr = (CaseExpr *) node;
                List       *adjust_jumps = NIL;
                Datum      *caseval = NULL;
                bool       *casenull = NULL;
                ListCell   *lc;
                
                if (caseExpr->arg != NULL)
                {
                    
                    caseval = palloc(sizeof(Datum));
                    casenull = palloc(sizeof(bool));
                    ExecInitExprRec(caseExpr->arg, state,
                                    caseval, casenull);
                    
                    if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)
                    {
                        
                        scratch.opcode = EEOP_MAKE_READONLY;
                        scratch.resvalue = caseval;
                        scratch.resnull = casenull;
                        scratch.d.make_readonly.value = caseval;
                        scratch.d.make_readonly.isnull = casenull;
                        ExprEvalPushStep(state, &scratch);
                        
                        scratch.resvalue = resv;
                        scratch.resnull = resnull;
                    }
                }
                
                foreach(lc, caseExpr->args)
                {
                    CaseWhen   *when = (CaseWhen *) lfirst(lc);
                    Datum      *save_innermost_caseval;
                    bool       *save_innermost_casenull;
                    int         whenstep;
                    
                    save_innermost_caseval = state->innermost_caseval;
                    save_innermost_casenull = state->innermost_casenull;
                    state->innermost_caseval = caseval;
                    state->innermost_casenull = casenull;
                    
                    ExecInitExprRec(when->expr, state, resv, resnull);
                    state->innermost_caseval = save_innermost_caseval;
                    state->innermost_casenull = save_innermost_casenull;
                    
                    scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
                    scratch.d.jump.jumpdone = -1;   
                    ExprEvalPushStep(state, &scratch);
                    whenstep = state->steps_len - 1;
                    
                    ExecInitExprRec(when->result, state, resv, resnull);
                    
                    scratch.opcode = EEOP_JUMP;
                    scratch.d.jump.jumpdone = -1;   
                    ExprEvalPushStep(state, &scratch);
                    
                    adjust_jumps = lappend_int(adjust_jumps,
                                               state->steps_len - 1);
                    
                    state->steps[whenstep].d.jump.jumpdone = state->steps_len;
                }
                
                Assert(caseExpr->defresult);
                
                ExecInitExprRec(caseExpr->defresult, state,
                                resv, resnull);
                
                foreach(lc, adjust_jumps)
                {
                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];
                    Assert(as->opcode == EEOP_JUMP);
                    Assert(as->d.jump.jumpdone == -1);
                    as->d.jump.jumpdone = state->steps_len;
                }
                break;
            }
        case T_CaseTestExpr:
            {
                
                scratch.opcode = EEOP_CASE_TESTVAL;
                scratch.d.casetest.value = state->innermost_caseval;
                scratch.d.casetest.isnull = state->innermost_casenull;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_ArrayExpr:
            {
                ArrayExpr  *arrayexpr = (ArrayExpr *) node;
                int         nelems = list_length(arrayexpr->elements);
                ListCell   *lc;
                int         elemoff;
                
                scratch.opcode = EEOP_ARRAYEXPR;
                scratch.d.arrayexpr.elemvalues =
                    (Datum *) palloc(sizeof(Datum) * nelems);
                scratch.d.arrayexpr.elemnulls =
                    (bool *) palloc(sizeof(bool) * nelems);
                scratch.d.arrayexpr.nelems = nelems;
                
                scratch.d.arrayexpr.multidims = arrayexpr->multidims;
                scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;
                
                get_typlenbyvalalign(arrayexpr->element_typeid,
                                     &scratch.d.arrayexpr.elemlength,
                                     &scratch.d.arrayexpr.elembyval,
                                     &scratch.d.arrayexpr.elemalign);
                
                elemoff = 0;
                foreach(lc, arrayexpr->elements)
                {
                    Expr       *e = (Expr *) lfirst(lc);
                    ExecInitExprRec(e, state,
                                    &scratch.d.arrayexpr.elemvalues[elemoff],
                                    &scratch.d.arrayexpr.elemnulls[elemoff]);
                    elemoff++;
                }
                
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_RowExpr:
            {
                RowExpr    *rowexpr = (RowExpr *) node;
                int         nelems = list_length(rowexpr->args);
                TupleDesc   tupdesc;
                int         i;
                ListCell   *l;
                
                if (rowexpr->row_typeid == RECORDOID)
                {
                    
                    tupdesc = ExecTypeFromExprList(rowexpr->args);
                }
                else
                {
                    
                    tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
                }
                
                ExecTypeSetColNames(tupdesc, rowexpr->colnames);
                
                BlessTupleDesc(tupdesc);
                
                Assert(nelems <= tupdesc->natts);
                nelems = Max(nelems, tupdesc->natts);
                
                scratch.opcode = EEOP_ROW;
                scratch.d.row.tupdesc = tupdesc;
                
                scratch.d.row.elemvalues =
                    (Datum *) palloc(sizeof(Datum) * nelems);
                scratch.d.row.elemnulls =
                    (bool *) palloc(sizeof(bool) * nelems);
                
                memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);
                
                i = 0;
                foreach(l, rowexpr->args)
                {
                    Form_pg_attribute att = TupleDescAttr(tupdesc, i);
                    Expr       *e = (Expr *) lfirst(l);
                    if (!att->attisdropped)
                    {
                        
                        if (exprType((Node *) e) != att->atttypid)
                            ereport(ERROR,
                                    (errcode(ERRCODE_DATATYPE_MISMATCH),
                                     errmsg("ROW() column has type %s instead of type %s",
                                            format_type_be(exprType((Node *) e)),
                                            format_type_be(att->atttypid))));
                    }
                    else
                    {
                        
                        e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);
                    }
                    
                    ExecInitExprRec(e, state,
                                    &scratch.d.row.elemvalues[i],
                                    &scratch.d.row.elemnulls[i]);
                    i++;
                }
                
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_RowCompareExpr:
            {
                RowCompareExpr *rcexpr = (RowCompareExpr *) node;
                int         nopers = list_length(rcexpr->opnos);
                List       *adjust_jumps = NIL;
                ListCell   *l_left_expr,
                           *l_right_expr,
                           *l_opno,
                           *l_opfamily,
                           *l_inputcollid;
                ListCell   *lc;
                int         off;
                
                Assert(list_length(rcexpr->largs) == nopers);
                Assert(list_length(rcexpr->rargs) == nopers);
                Assert(list_length(rcexpr->opfamilies) == nopers);
                Assert(list_length(rcexpr->inputcollids) == nopers);
                off = 0;
                for (off = 0,
                     l_left_expr = list_head(rcexpr->largs),
                     l_right_expr = list_head(rcexpr->rargs),
                     l_opno = list_head(rcexpr->opnos),
                     l_opfamily = list_head(rcexpr->opfamilies),
                     l_inputcollid = list_head(rcexpr->inputcollids);
                     off < nopers;
                     off++,
                     l_left_expr = lnext(l_left_expr),
                     l_right_expr = lnext(l_right_expr),
                     l_opno = lnext(l_opno),
                     l_opfamily = lnext(l_opfamily),
                     l_inputcollid = lnext(l_inputcollid))
                {
                    Expr       *left_expr = (Expr *) lfirst(l_left_expr);
                    Expr       *right_expr = (Expr *) lfirst(l_right_expr);
                    Oid         opno = lfirst_oid(l_opno);
                    Oid         opfamily = lfirst_oid(l_opfamily);
                    Oid         inputcollid = lfirst_oid(l_inputcollid);
                    int         strategy;
                    Oid         lefttype;
                    Oid         righttype;
                    Oid         proc;
                    FmgrInfo   *finfo;
                    FunctionCallInfo fcinfo;
                    get_op_opfamily_properties(opno, opfamily, false,
                                               &strategy,
                                               &lefttype,
                                               &righttype);
                    proc = get_opfamily_proc(opfamily,
                                             lefttype,
                                             righttype,
                                             BTORDER_PROC);
                    if (!OidIsValid(proc))
                        elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
                             BTORDER_PROC, lefttype, righttype, opfamily);
                    
                    finfo = palloc0(sizeof(FmgrInfo));
                    fcinfo = palloc0(sizeof(FunctionCallInfoData));
                    fmgr_info(proc, finfo);
                    fmgr_info_set_expr((Node *) node, finfo);
                    InitFunctionCallInfoData(*fcinfo, finfo, 2,
                                             inputcollid, NULL, NULL);
                    
                    
                    ExecInitExprRec(left_expr, state,
                                    &fcinfo->arg[0], &fcinfo->argnull[0]);
                    ExecInitExprRec(right_expr, state,
                                    &fcinfo->arg[1], &fcinfo->argnull[1]);
                    scratch.opcode = EEOP_ROWCOMPARE_STEP;
                    scratch.d.rowcompare_step.finfo = finfo;
                    scratch.d.rowcompare_step.fcinfo_data = fcinfo;
                    scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;
                    
                    scratch.d.rowcompare_step.jumpnull = -1;
                    scratch.d.rowcompare_step.jumpdone = -1;
                    ExprEvalPushStep(state, &scratch);
                    adjust_jumps = lappend_int(adjust_jumps,
                                               state->steps_len - 1);
                }
                
                if (nopers == 0)
                {
                    scratch.opcode = EEOP_CONST;
                    scratch.d.constval.value = Int32GetDatum(0);
                    scratch.d.constval.isnull = false;
                    ExprEvalPushStep(state, &scratch);
                }
                
                scratch.opcode = EEOP_ROWCOMPARE_FINAL;
                scratch.d.rowcompare_final.rctype = rcexpr->rctype;
                ExprEvalPushStep(state, &scratch);
                
                foreach(lc, adjust_jumps)
                {
                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];
                    Assert(as->opcode == EEOP_ROWCOMPARE_STEP);
                    Assert(as->d.rowcompare_step.jumpdone == -1);
                    Assert(as->d.rowcompare_step.jumpnull == -1);
                    
                    as->d.rowcompare_step.jumpdone = state->steps_len - 1;
                    
                    as->d.rowcompare_step.jumpnull = state->steps_len;
                }
                break;
            }
        case T_CoalesceExpr:
            {
                CoalesceExpr *coalesce = (CoalesceExpr *) node;
                List       *adjust_jumps = NIL;
                ListCell   *lc;
                
                Assert(coalesce->args != NIL);
                
                foreach(lc, coalesce->args)
                {
                    Expr       *e = (Expr *) lfirst(lc);
                    
                    ExecInitExprRec(e, state, resv, resnull);
                    
                    scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
                    scratch.d.jump.jumpdone = -1;   
                    ExprEvalPushStep(state, &scratch);
                    adjust_jumps = lappend_int(adjust_jumps,
                                               state->steps_len - 1);
                }
                
                
                foreach(lc, adjust_jumps)
                {
                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];
                    Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL);
                    Assert(as->d.jump.jumpdone == -1);
                    as->d.jump.jumpdone = state->steps_len;
                }
                break;
            }
        case T_MinMaxExpr:
            {
                MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
                int         nelems = list_length(minmaxexpr->args);
                TypeCacheEntry *typentry;
                FmgrInfo   *finfo;
                FunctionCallInfo fcinfo;
                ListCell   *lc;
                int         off;
                
                typentry = lookup_type_cache(minmaxexpr->minmaxtype,
                                             TYPECACHE_CMP_PROC);
                if (!OidIsValid(typentry->cmp_proc))
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_FUNCTION),
                             errmsg("could not identify a comparison function for type %s",
                                    format_type_be(minmaxexpr->minmaxtype))));
                
                
                finfo = palloc0(sizeof(FmgrInfo));
                fcinfo = palloc0(sizeof(FunctionCallInfoData));
                fmgr_info(typentry->cmp_proc, finfo);
                fmgr_info_set_expr((Node *) node, finfo);
                InitFunctionCallInfoData(*fcinfo, finfo, 2,
                                         minmaxexpr->inputcollid, NULL, NULL);
                scratch.opcode = EEOP_MINMAX;
                
                scratch.d.minmax.values =
                    (Datum *) palloc(sizeof(Datum) * nelems);
                scratch.d.minmax.nulls =
                    (bool *) palloc(sizeof(bool) * nelems);
                scratch.d.minmax.nelems = nelems;
                scratch.d.minmax.op = minmaxexpr->op;
                scratch.d.minmax.finfo = finfo;
                scratch.d.minmax.fcinfo_data = fcinfo;
                
                off = 0;
                foreach(lc, minmaxexpr->args)
                {
                    Expr       *e = (Expr *) lfirst(lc);
                    ExecInitExprRec(e, state,
                                    &scratch.d.minmax.values[off],
                                    &scratch.d.minmax.nulls[off]);
                    off++;
                }
                
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_SQLValueFunction:
            {
                SQLValueFunction *svf = (SQLValueFunction *) node;
                scratch.opcode = EEOP_SQLVALUEFUNCTION;
                scratch.d.sqlvaluefunction.svf = svf;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_XmlExpr:
            {
                XmlExpr    *xexpr = (XmlExpr *) node;
                int         nnamed = list_length(xexpr->named_args);
                int         nargs = list_length(xexpr->args);
                int         off;
                ListCell   *arg;
                scratch.opcode = EEOP_XMLEXPR;
                scratch.d.xmlexpr.xexpr = xexpr;
                
                if (nnamed)
                {
                    scratch.d.xmlexpr.named_argvalue =
                        (Datum *) palloc(sizeof(Datum) * nnamed);
                    scratch.d.xmlexpr.named_argnull =
                        (bool *) palloc(sizeof(bool) * nnamed);
                }
                else
                {
                    scratch.d.xmlexpr.named_argvalue = NULL;
                    scratch.d.xmlexpr.named_argnull = NULL;
                }
                if (nargs)
                {
                    scratch.d.xmlexpr.argvalue =
                        (Datum *) palloc(sizeof(Datum) * nargs);
                    scratch.d.xmlexpr.argnull =
                        (bool *) palloc(sizeof(bool) * nargs);
                }
                else
                {
                    scratch.d.xmlexpr.argvalue = NULL;
                    scratch.d.xmlexpr.argnull = NULL;
                }
                
                off = 0;
                foreach(arg, xexpr->named_args)
                {
                    Expr       *e = (Expr *) lfirst(arg);
                    ExecInitExprRec(e, state,
                                    &scratch.d.xmlexpr.named_argvalue[off],
                                    &scratch.d.xmlexpr.named_argnull[off]);
                    off++;
                }
                off = 0;
                foreach(arg, xexpr->args)
                {
                    Expr       *e = (Expr *) lfirst(arg);
                    ExecInitExprRec(e, state,
                                    &scratch.d.xmlexpr.argvalue[off],
                                    &scratch.d.xmlexpr.argnull[off]);
                    off++;
                }
                
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_NullTest:
            {
                NullTest   *ntest = (NullTest *) node;
                if (ntest->nulltesttype == IS_NULL)
                {
                    if (ntest->argisrow)
                        scratch.opcode = EEOP_NULLTEST_ROWISNULL;
                    else
                        scratch.opcode = EEOP_NULLTEST_ISNULL;
                }
                else if (ntest->nulltesttype == IS_NOT_NULL)
                {
                    if (ntest->argisrow)
                        scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL;
                    else
                        scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
                }
                else
                {
                    elog(ERROR, "unrecognized nulltesttype: %d",
                         (int) ntest->nulltesttype);
                }
                
                scratch.d.nulltest_row.argdesc = NULL;
                
                ExecInitExprRec(ntest->arg, state,
                                resv, resnull);
                
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_BooleanTest:
            {
                BooleanTest *btest = (BooleanTest *) node;
                
                ExecInitExprRec(btest->arg, state, resv, resnull);
                switch (btest->booltesttype)
                {
                    case IS_TRUE:
                        scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
                        break;
                    case IS_NOT_TRUE:
                        scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE;
                        break;
                    case IS_FALSE:
                        scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
                        break;
                    case IS_NOT_FALSE:
                        scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE;
                        break;
                    case IS_UNKNOWN:
                        
                        scratch.opcode = EEOP_NULLTEST_ISNULL;
                        break;
                    case IS_NOT_UNKNOWN:
                        
                        scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
                        break;
                    default:
                        elog(ERROR, "unrecognized booltesttype: %d",
                             (int) btest->booltesttype);
                }
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_CoerceToDomain:
            {
                CoerceToDomain *ctest = (CoerceToDomain *) node;
                ExecInitCoerceToDomain(&scratch, ctest, state,
                                       resv, resnull);
                break;
            }
        case T_CoerceToDomainValue:
            {
                
                scratch.opcode = EEOP_DOMAIN_TESTVAL;
                
                scratch.d.casetest.value = state->innermost_domainval;
                scratch.d.casetest.isnull = state->innermost_domainnull;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_CurrentOfExpr:
            {
                scratch.opcode = EEOP_CURRENTOFEXPR;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        case T_NextValueExpr:
            {
                NextValueExpr *nve = (NextValueExpr *) node;
                scratch.opcode = EEOP_NEXTVALUEEXPR;
                scratch.d.nextvalueexpr.seqid = nve->seqid;
                scratch.d.nextvalueexpr.seqtypid = nve->typeId;
                ExprEvalPushStep(state, &scratch);
                break;
            }
        default:
            elog(ERROR, "unrecognized node type: %d",
                 (int) nodeTag(node));
            break;
    }
}

void
ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
{
    if (es->steps_alloc == 0)
    {
        es->steps_alloc = 16;
        es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
    }
    else if (es->steps_alloc == es->steps_len)
    {
        es->steps_alloc *= 2;
        es->steps = repalloc(es->steps,
                             sizeof(ExprEvalStep) * es->steps_alloc);
    }
    memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
}

三、跟踪分析

测试脚本

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

进入ExecInitExprRec,Node节点为OpExpr,执行ExprEvalPushStep压入步骤中

(gdb) step
ExecInitExprRec (node=0x1c9a930, state=0x1c8f7d8, resv=0x1c8f7e0, resnull=0x1c8f7dd) at execExpr.c:645
645     ExprEvalStep scratch = {0};
(gdb) n
648     check_stack_depth();
(gdb) 
651     Assert(resv != NULL && resnull != NULL);
(gdb) 
652     scratch.resvalue = resv;
(gdb) 
653     scratch.resnull = resnull;
(gdb) 
656     switch (nodeTag(node))
(gdb) 
891                 OpExpr     *op = (OpExpr *) node;
(gdb) p *node
$16 = {type = T_OpExpr}
(gdb) n
893                 ExecInitFunc(&scratch, node,
(gdb) 
896                 ExprEvalPushStep(state, &scratch);
(gdb) 
897                 break;
(gdb) 
2122    }
(gdb)

到此,相信大家对“怎么使用PostgreSQL中ExecInitExprRec函数”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯