千家信息网

怎么使用PostgreSQ中的ExecMaterial函数

发表于:2024-10-01 作者:千家信息网编辑
千家信息网最后更新 2024年10月01日,本篇内容介绍了"怎么使用PostgreSQ中的ExecMaterial函数"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细
千家信息网最后更新 2024年10月01日怎么使用PostgreSQ中的ExecMaterial函数

本篇内容介绍了"怎么使用PostgreSQ中的ExecMaterial函数"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

SubPlanState
子计划运行期状态

/* ---------------- *        SubPlanState node * ---------------- */typedef struct SubPlanState{    NodeTag        type;    SubPlan    *subplan;        /* expression plan node */    struct PlanState *planstate;    /* subselect plan's state tree */    struct PlanState *parent;    /* parent plan node's state tree */    ExprState  *testexpr;        /* 组合表达式状态;state of combining expression */    List       *args;            /* 参数表达式状态;states of argument _expression(s) */    HeapTuple    curTuple;        /* subplan最近的元组;copy of most recent tuple from subplan */    Datum        curArray;        /* most recent array from ARRAY() subplan */    /* these are used when hashing the subselect's output: */    TupleDesc    descRight;        /* 投影后的子查询描述符;subselect desc after projection */    ProjectionInfo *projLeft;    /* for projecting lefthand exprs */    ProjectionInfo *projRight;    /* for projecting subselect output */    TupleHashTable hashtable;    /* hash table for no-nulls subselect rows */    TupleHashTable hashnulls;    /* hash table for rows with null(s) */    bool        havehashrows;    /* true if hashtable is not empty */    bool        havenullrows;    /* true if hashnulls is not empty */    MemoryContext hashtablecxt; /* memory context containing hash tables */    MemoryContext hashtempcxt;    /* temp memory context for hash tables */    ExprContext *innerecontext; /* econtext for computing inner tuples */    AttrNumber *keyColIdx;        /* control data for hash tables */    Oid           *tab_eq_funcoids;    /* equality func oids for table                                     * datatype(s) */    Oid           *tab_collations; /* collations for hash and comparison */    FmgrInfo   *tab_hash_funcs; /* hash functions for table datatype(s) */    FmgrInfo   *tab_eq_funcs;    /* equality functions for table datatype(s) */    FmgrInfo   *lhs_hash_funcs; /* hash functions for lefthand datatype(s) */    FmgrInfo   *cur_eq_funcs;    /* equality functions for LHS vs. table */    ExprState  *cur_eq_comp;    /* equality comparator for LHS vs. table */} SubPlanState;

SubPlan
子查询计划

/* * SubPlan - executable expression node for a subplan (sub-SELECT) * * The planner replaces SubLink nodes in expression trees with SubPlan * nodes after it has finished planning the subquery.  SubPlan references * a sub-plantree stored in the subplans list of the toplevel PlannedStmt. * (We avoid a direct link to make it easier to copy expression trees * without causing multiple processing of the subplan.) * 查询规划器在完成子查询的规划后使用SubPlan节点替换表达式树中的SubLink节点。 * SubPlan引用了存储在高层PlannedStmt中的subplans链表中的sub-plantree。 * (避免使用直接链接,从而使得拷贝表达式树相对比较简单) * * In an ordinary subplan, testexpr points to an executable expression * (OpExpr, an AND/OR tree of OpExprs, or RowCompareExpr) for the combining * operator(s); the left-hand arguments are the original lefthand expressions, * and the right-hand arguments are PARAM_EXEC Param nodes representing the * outputs of the sub-select.  (NOTE: runtime coercion functions may be * inserted as well.)  This is just the same expression tree as testexpr in * the original SubLink node, but the PARAM_SUBLINK nodes are replaced by * suitably numbered PARAM_EXEC nodes. * 常规情况下,testexpr指向用于组合操作的可执行表达式(OpExpr、OpExprs的AND/OR树或者RowCompareExpr); * 左参数是原始的左表达式,右参数是PARAM_EXEC参数节点用以表示子查询的输出。 * 与原始SubLink节点的testexpr具有相同的表达式树,但PARAM_SUBLINK节点则使用合适的已编号PARAM_EXEC节点替代。 * * If the sub-select becomes an initplan rather than a subplan, the executable * expression is part of the outer plan's expression tree (and the SubPlan * node itself is not, but rather is found in the outer plan's initPlan * list).  In this case testexpr is NULL to avoid duplication. * 如果子查询成了initplan而不是subplan,可执行的表达式是外层plan表达式树的一部分。 * 这种情况下,testexpr为NULL以避免重复。 * * The planner also derives lists of the values that need to be passed into * and out of the subplan.  Input values are represented as a list "args" of * expressions to be evaluated in the outer-query context (currently these * args are always just Vars, but in principle they could be any expression). * The values are assigned to the global PARAM_EXEC params indexed by parParam * (the parParam and args lists must have the same ordering).  setParam is a * list of the PARAM_EXEC params that are computed by the sub-select, if it * is an initplan; they are listed in order by sub-select output column * position.  (parParam and setParam are integer Lists, not Bitmapsets, * because their ordering is significant.) * 规划器还派生了需要传入和传出子计划的值的链表。 * 输入值标识位表达式的"args"链表,在外层查询上下文中进行解析。 * (这些args通常是Vars,但原则上它们可以是任意表达式) * 这些值以parParam为索引给全局PARAM_EXEC参数赋值。 * setParam是PARAM_EXEC参数链表,通过子查询(如为initplan)计算所得。 * 它们按子查询输出列的位置进行排序组织为链表形式。 * (parParam和setParam是整型链表,而不是Bitmapsets链表) * * Also, the planner computes startup and per-call costs for use of the * SubPlan.  Note that these include the cost of the subquery proper, * evaluation of the testexpr if any, and any hashtable management overhead. * 同时,规划器计算SubPlan启动和每次调用的成本。注意:包括子查询正常解析testexpr的成本以及哈希表管理成本。 */typedef struct SubPlan{    Expr        xpr;//表达式    /* Fields copied from original SubLink: */    //从SubLink中拷贝而来    SubLinkType subLinkType;    /* see above */    /* The combining operators, transformed to an executable expression: */    //组合操作符,转换为可执行的表达式    Node       *testexpr;        /* OpExpr or RowCompareExpr expression tree */    List       *paramIds;        /* 参数IDs;IDs of Params embedded in the above */    /* Identification of the Plan tree to use: */    //Plan tree标识    int            plan_id;        /* Index (from 1) in PlannedStmt.subplans */    /* Identification of the SubPlan for EXPLAIN and debugging purposes: */    //EXPLAIN和debug目的的SubPlan标识    char       *plan_name;        /* A name assigned during planning */    /* Extra data useful for determining subplan's output type: */    //用于确定subplan输出类型的额外信息    Oid            firstColType;    /* subplan结果的第一个列类型;Type of first column of subplan result */    int32        firstColTypmod; /* 第一列的Typmod;Typmod of first column of subplan result */    Oid            firstColCollation;    /* 第一列的Collation;Collation of first column of subplan                                     * result */    /* Information about execution strategy: */    //执行阶段的相关信息    bool        useHashTable;    /* 是否使用哈希表存储子查询输出;true to store subselect output in a hash                                 * table (implies we are doing "IN") */    bool        unknownEqFalse; /* 如OK为T,如为未知则为F;快速处理null值;true if it's okay to return FALSE when the                                 * spec result is UNKNOWN; this allows much                                 * simpler handling of null values */    bool        parallel_safe;    /* 是否并行安全?is the subplan parallel-safe? */    /* Note: parallel_safe does not consider contents of testexpr or args */    /* Information for passing params into and out of the subselect: */    //用于给子查询传入和传出参数的信息    /* setParam and parParam are lists of integers (param IDs) */    //setParam和parParam是整型链表(param IDs)    List       *setParam;        /* initplan subqueries have to set these                                 * Params for parent plan */    List       *parParam;        /* indices of input Params from parent plan */    List       *args;            /* 以parParam值进行传递的表达式;exprs to pass as parParam values */    /* Estimated execution costs: */    //估算执行成本    Cost        startup_cost;    /* one-time setup cost */    Cost        per_call_cost;    /* cost for each subplan evaluation */} SubPlan;

SubLinkType
SubLink类型

/* * SubLink * * A SubLink represents a subselect appearing in an expression, and in some * cases also the combining operator(s) just above it.  The subLinkType * indicates the form of the expression represented: *    EXISTS_SUBLINK        EXISTS(SELECT ...) *    ALL_SUBLINK            (lefthand) op ALL (SELECT ...) *    ANY_SUBLINK            (lefthand) op ANY (SELECT ...) *    ROWCOMPARE_SUBLINK    (lefthand) op (SELECT ...) *    EXPR_SUBLINK        (SELECT with single targetlist item ...) *    MULTIEXPR_SUBLINK    (SELECT with multiple targetlist items ...) *    ARRAY_SUBLINK        ARRAY(SELECT with single targetlist item ...) *    CTE_SUBLINK            WITH query (never actually part of an expression) * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the * same length as the subselect's targetlist.  ROWCOMPARE will *always* have * a list with more than one entry; if the subselect has just one target * then the parser will create an EXPR_SUBLINK instead (and any operator * above the subselect will be represented separately). * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most * one row (if it returns no rows, the result is NULL). * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean * results.  ALL and ANY combine the per-row results using AND and OR * semantics respectively. * ARRAY requires just one target column, and creates an array of the target * column's type using any number of rows resulting from the subselect. * * SubLink is classed as an Expr node, but it is not actually executable; * it must be replaced in the expression tree by a SubPlan node during * planning. * * NOTE: in the raw output of gram.y, testexpr contains just the raw form * of the lefthand _expression (if any), and operName is the String name of * the combining operator.  Also, subselect is a raw parsetree.  During parse * analysis, the parser transforms testexpr into a complete boolean expression * that compares the lefthand value(s) to PARAM_SUBLINK nodes representing the * output columns of the subselect.  And subselect is transformed to a Query. * This is the representation seen in saved rules and in the rewriter. * * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName * are unused and are always null. * * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in * other SubLinks.  This number identifies different multiple-assignment * subqueries within an UPDATE statement's SET list.  It is unique only * within a particular targetlist.  The output column(s) of the MULTIEXPR * are referenced by PARAM_MULTIEXPR Params appearing elsewhere in the tlist. * * The CTE_SUBLINK case never occurs in actual SubLink nodes, but it is used * in SubPlans generated for WITH subqueries. */typedef enum SubLinkType{    EXISTS_SUBLINK,    ALL_SUBLINK,    ANY_SUBLINK,    ROWCOMPARE_SUBLINK,    EXPR_SUBLINK,    MULTIEXPR_SUBLINK,    ARRAY_SUBLINK,    CTE_SUBLINK                    /* for SubPlans only */} SubLinkType;

SubLink
SubLink结构体

typedef struct SubLink{    Expr        xpr;    SubLinkType subLinkType;    /* see above */    int            subLinkId;        /* ID (1..n); 0 if not MULTIEXPR */    Node       *testexpr;        /* outer-query test for ALL/ANY/ROWCOMPARE */    List       *operName;        /* originally specified operator name */    Node       *subselect;        /* subselect as Query* or raw parsetree */    int            location;        /* token location, or -1 if unknown */} SubLink;

MaterialState
Material状态

/* ---------------- *     MaterialState information * *        materialize nodes are used to materialize the results *        of a subplan into a temporary file. *        materialize节点用于物化subplan的结果为临时文件。 * *        ss.ss_ScanTupleSlot refers to output of underlying plan. *        ss.ss_ScanTupleSlot指向underlyling plan的输出(subplan) * ---------------- */typedef struct MaterialState{    ScanState    ss;                /* its first field is NodeTag */    int            eflags;            /* 传递给tuplestore的capability标记;capability flags to pass to tuplestore */    bool        eof_underlying; /* 已经到达underlying plan的末尾?reached end of underlying plan? */    Tuplestorestate *tuplestorestate;} MaterialState;

二、源码解读


/* ---------------------------------------------------------------- *        ExecMaterial * *        As long as we are at the end of the data collected in the tuplestore, *        we collect one new row from the subplan on each call, and stash it *        aside in the tuplestore before returning it.  The tuplestore is *        only read if we are asked to scan backwards, rescan, or mark/restore. *      只要在tuplestore中数据收集结束时,就会在每次调用时从subplan中收集一条新行, *      并在返回之前将其保存在tuplestore中。 *      只要在往后扫描、重新扫描或标记/恢复时tuplestore才会读取。 * * ---------------------------------------------------------------- */static TupleTableSlot *            /* 从subplan中返回的结果;result tuple from subplan */ExecMaterial(PlanState *pstate){    MaterialState *node = castNode(MaterialState, pstate);//物化节点    EState       *estate;//运行期状态    ScanDirection dir;//扫描方向    bool        forward;//是否往前扫描    Tuplestorestate *tuplestorestate;//Tuplestorestate结构体指针    bool        eof_tuplestore;//是否完成?    TupleTableSlot *slot;//存储元组的slot    CHECK_FOR_INTERRUPTS();    /*     * get state info from node     * 从物化节点中获取相关信息     */    estate = node->ss.ps.state;    dir = estate->es_direction;//方向    forward = ScanDirectionIsForward(dir);//是否往前扫描    tuplestorestate = node->tuplestorestate;    /*     * If first time through, and we need a tuplestore, initialize it.     * 第一次,需要tuplestore并初始化     */    if (tuplestorestate == NULL && node->eflags != 0)    {        tuplestorestate = tuplestore_begin_heap(true, false, work_mem);        tuplestore_set_eflags(tuplestorestate, node->eflags);        if (node->eflags & EXEC_FLAG_MARK)        {            /*             * Allocate a second read pointer to serve as the mark. We know it             * must have index 1, so needn't store that.             * 分配用于mark的读指针             */            int            ptrno PG_USED_FOR_ASSERTS_ONLY;            ptrno = tuplestore_alloc_read_pointer(tuplestorestate,                                                  node->eflags);            Assert(ptrno == 1);        }        node->tuplestorestate = tuplestorestate;    }    /*     * If we are not at the end of the tuplestore, or are going backwards, try     * to fetch a tuple from tuplestore.     * 如果不在tuplestore的末尾或者正在往后扫描,尝试从tuplestore中提取一个元组     */    eof_tuplestore = (tuplestorestate == NULL) ||        tuplestore_ateof(tuplestorestate);    if (!forward && eof_tuplestore)    {        if (!node->eof_underlying)        {            /*             * When reversing direction at tuplestore EOF, the first             * gettupleslot call will fetch the last-added tuple; but we want             * to return the one before that, if possible. So do an extra             * fetch.             * 在EOF处反转方向,第一次的gettupleslot调用会提取最后添加的元组;             * 但如可能,希望返回在此之前的元组,执行额外的提取操作。             */            if (!tuplestore_advance(tuplestorestate, forward))                return NULL;    /* the tuplestore must be empty */        }        eof_tuplestore = false;    }    /*     * If we can fetch another tuple from the tuplestore, return it.     * 如能从tuplestore中提取另外一个tuple,返回     */    slot = node->ss.ps.ps_ResultTupleSlot;    if (!eof_tuplestore)    {        if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))            return slot;        if (forward)            eof_tuplestore = true;    }    /*     * If necessary, try to fetch another row from the subplan.     * 如需要(tuplestore末尾),尝试从subplan中提取另外一行     *     * Note: the eof_underlying state variable exists to short-circuit further     * subplan calls.  It's not optional, unfortunately, because some plan     * node types are not robust about being called again when they've already     * returned NULL.     */    if (eof_tuplestore && !node->eof_underlying)    {        PlanState  *outerNode;        TupleTableSlot *outerslot;        /*         * We can only get here with forward==true, so no need to worry about         * which direction the subplan will go.         */        outerNode = outerPlanState(node);        outerslot = ExecProcNode(outerNode);        if (TupIsNull(outerslot))        {            node->eof_underlying = true;            return NULL;        }        /*         * Append a copy of the returned tuple to tuplestore.  NOTE: because         * the tuplestore is certainly in EOF state, its read position will         * move forward over the added tuple.  This is what we want.         * 追加返回的元组到tuplestore中。         * 注意:因为tuplestore当前处于EOF状态,读取的位置会前移至已添加的tuple前面,这是我们希望看到的。         */        if (tuplestorestate)            tuplestore_puttupleslot(tuplestorestate, outerslot);        ExecCopySlot(slot, outerslot);        return slot;    }    /*     * Nothing left ...     */    return ExecClearTuple(slot);}

三、跟踪分析

执行SQL:

[pg12@localhost ~]$ psql -d testdbTiming is on.Expanded display is used automatically.psql (12.0)Type "help" for help.[local]:5432 pg12@testdb=# [local]:5432 pg12@testdb=# select * from tbl; id | value ----+-------  1 |     2(1 row)Time: 2.678 ms[local]:5432 pg12@testdb=# select count(*) from t_big_null;  count   ---------- 10000001(1 row)Time: 679.972 ms[local]:5432 pg12@testdb=# analyze tbl;ANALYZETime: 64.442 ms[local]:5432 pg12@testdb=# analyze t_big_null;ANALYZETime: 434.702 ms[local]:5432 pg12@testdb=# [local]:5432 pg12@testdb=# select pg_backend_pid(); pg_backend_pid ----------------          18758(1 row)Time: 1.990 ms[local]:5432 pg12@testdb=# select * from tbl a where a.id not in (select b.id from t_big_null b);

启动gdb跟踪

(gdb) b ExecMaterialBreakpoint 1 at 0x720edb: file nodeMaterial.c, line 41.(gdb) cContinuing.Breakpoint 1, ExecMaterial (pstate=0x1230128) at nodeMaterial.c:4141        MaterialState *node = castNode(MaterialState, pstate);(gdb)

输入参数

(gdb) p *pstate$4 = {type = T_MaterialState, plan = 0x1211858, state = 0x122fe88,   ExecProcNode = 0x720ecf , ExecProcNodeReal = 0x720ecf ,   instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,   lefttree = 0x1230240, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,   ps_ResultTupleDesc = 0x1230660, ps_ResultTupleSlot = 0x1230778, ps_ExprContext = 0x0,   ps_ProjInfo = 0x0, scandesc = 0x1230548, scanops = 0xc3e720 ,   outerops = 0x0, innerops = 0x0, resultops = 0xc3e720 ,   scanopsfixed = true, outeropsfixed = false, inneropsfixed = false,   resultopsfixed = true, scanopsset = true, outeropsset = false, inneropsset = false,   resultopsset = true}(gdb)

MaterialState结构体指针数据

(gdb) p *node$1 = {ss = {ps = {type = T_MaterialState, plan = 0x1211858, state = 0x122fe88,       ExecProcNode = 0x720ecf , ExecProcNodeReal = 0x720ecf ,       instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,       lefttree = 0x1230240, righttree = 0x0, initPlan = 0x0, subPlan = 0x0,       chgParam = 0x0, ps_ResultTupleDesc = 0x1230660, ps_ResultTupleSlot = 0x1230778,       ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x1230548,       scanops = 0xc3e720 , outerops = 0x0, innerops = 0x0,       resultops = 0xc3e720 , scanopsfixed = true,       outeropsfixed = false, inneropsfixed = false, resultopsfixed = true,       scanopsset = true, outeropsset = false, inneropsset = false, resultopsset = true},     ss_currentRelation = 0x0, ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x1230838},   eflags = 2, eof_underlying = false, tuplestorestate = 0x0}(gdb) p *node->ss->ps->plan$2 = {type = T_Material, startup_cost = 0, total_cost = 233310.685, plan_rows = 9999979,   plan_width = 4, parallel_aware = false, parallel_safe = true, plan_node_id = 1,   targetlist = 0x1257600, qual = 0x0, lefttree = 0x1210f58, righttree = 0x0,   initPlan = 0x0, extParam = 0x0, allParam = 0x0}(gdb)

运行期信息和方向

(gdb) p *estate$5 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x1164d50,   es_crosscheck_snapshot = 0x0, es_range_table = 0x1257328,   es_range_table_array = 0x12300d8, es_range_table_size = 2, es_relations = 0x1230100,   es_rowmarks = 0x0, es_plannedstmt = 0x1257748,   es_sourceText = 0x113cd88 "select * from tbl a where a.id not in (select b.id from t_big_null b);", es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x0,   es_num_result_relations = 0, es_result_relation_info = 0x0,   es_root_result_relations = 0x0, es_num_root_result_relations = 0,   es_partition_directory = 0x0, es_tuple_routing_result_relations = 0x0,   es_trig_target_relations = 0x0, es_param_list_info = 0x0,   es_param_exec_vals = 0x12300a0, es_queryEnv = 0x0, es_query_cxt = 0x122fd70,   es_tupleTable = 0x1230510, es_processed = 0, es_top_eflags = 16, es_instrument = 0,   es_finished = false, es_exprcontexts = 0x1230418, es_subplanstates = 0x1230920,   es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epq_active = 0x0,   es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 25, es_jit = 0x0,   es_jit_worker_instr = 0x0}(gdb) p dir$6 = ForwardScanDirection(gdb)

初始化tuplestore

(gdb) n64            tuplestorestate = tuplestore_begin_heap(true, false, work_mem);(gdb) n65            tuplestore_set_eflags(tuplestorestate, node->eflags);(gdb) p *tuplestorestate$7 = {status = TSS_INMEM, eflags = 6, backward = false, interXact = false,   truncated = false, availMem = 4177896, allowedMem = 4194304, tuples = 0, myfile = 0x0,   context = 0x122fd70, resowner = 0x116e308, copytup = 0xaba7bd ,   writetup = 0xaba811 , readtup = 0xaba9d9 ,   memtuples = 0x1219e60, memtupdeleted = 0, memtupcount = 0, memtupsize = 2048,   growmemtuples = true, readptrs = 0x123ca50, activeptr = 0, readptrcount = 1,   readptrsize = 8, writepos_file = 0, writepos_offset = 0}(gdb) n66            if (node->eflags & EXEC_FLAG_MARK)(gdb) 78            node->tuplestorestate = tuplestorestate;(gdb) 85        eof_tuplestore = (tuplestorestate == NULL) ||(gdb) p *tuplestorestate$8 = {status = TSS_INMEM, eflags = 2, backward = false, interXact = false,   truncated = false, availMem = 4177896, allowedMem = 4194304, tuples = 0, myfile = 0x0,   context = 0x122fd70, resowner = 0x116e308, copytup = 0xaba7bd ,   writetup = 0xaba811 , readtup = 0xaba9d9 ,   memtuples = 0x1219e60, memtupdeleted = 0, memtupcount = 0, memtupsize = 2048,   growmemtuples = true, readptrs = 0x123ca50, activeptr = 0, readptrcount = 1,   readptrsize = 8, writepos_file = 0, writepos_offset = 0}(gdb)

既不是往后扫描也没有到达EOF

(gdb) n86            tuplestore_ateof(tuplestorestate);(gdb) 85        eof_tuplestore = (tuplestorestate == NULL) ||(gdb) 88        if (!forward && eof_tuplestore)(gdb) p eof_tuplestore$9 = false(gdb) p forward$10 = true(gdb)

如能从tuplestore中提取另外一个tuple,则返回此slot

(gdb) n107        slot = node->ss.ps.ps_ResultTupleSlot;(gdb) 108        if (!eof_tuplestore)(gdb) p *slot$11 = {type = T_TupleTableSlot, tts_flags = 18, tts_nvalid = 0,   tts_ops = 0xc3e720 , tts_tupleDescriptor = 0x1230660,   tts_values = 0x12307e8, tts_isnull = 0x12307f0, tts_mcxt = 0x122fd70, tts_tid = {    ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, tts_tableOid = 0}(gdb) p slot->tts_values[0]$12 = 0(gdb) n110            if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))(gdb)

如扫描方向为往前,则设置eof_tuplestore为T,填充tuple到tuplestore中

112            if (forward)(gdb) 113                eof_tuplestore = true;(gdb)

如需要(处于tuplestore末尾),尝试从subplan(扫描t_big_null)中提取另外一行

124        if (eof_tuplestore && !node->eof_underlying)(gdb) p node->eof_underlying$13 = false(gdb) n133            outerNode = outerPlanState(node);(gdb) n134            outerslot = ExecProcNode(outerNode);(gdb) 135            if (TupIsNull(outerslot))(gdb) p *outerNode$14 = {type = T_SeqScanState, plan = 0x1210f58, state = 0x122fe88,   ExecProcNode = 0x72b904 , ExecProcNodeReal = 0x72b904 ,   instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0,   lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,   ps_ResultTupleDesc = 0x1230548, ps_ResultTupleSlot = 0x0, ps_ExprContext = 0x1230358,   ps_ProjInfo = 0x0, scandesc = 0x7f6ec53386a8,   scanops = 0xc3e780 , outerops = 0x0, innerops = 0x0,   resultops = 0xc3e780 , scanopsfixed = true,   outeropsfixed = false, inneropsfixed = false, resultopsfixed = true, scanopsset = true,   outeropsset = false, inneropsset = false, resultopsset = true}(gdb) p *outerslot$15 = {type = T_TupleTableSlot, tts_flags = 16, tts_nvalid = 0,   tts_ops = 0xc3e780 , tts_tupleDescriptor = 0x7f6ec53386a8,   tts_values = 0x12304c0, tts_isnull = 0x12304c8, tts_mcxt = 0x122fd70, tts_tid = {    ip_blkid = {bi_hi = 0, bi_lo = 44240}, ip_posid = 1}, tts_tableOid = 49155}(gdb) p outerslot->tts_values[0]$16 = 0(gdb) p outerslot->tts_values[1]$17 = 0(gdb) ###[local]:5432 pg12@testdb=# select oid,relname from pg_class where oid = 49155;  oid  |  relname   -------+------------ 49155 | t_big_null(1 row)###

拷贝到tuplestore中,返回slot

(gdb) n146            if (tuplestorestate)(gdb) 147                tuplestore_puttupleslot(tuplestorestate, outerslot);(gdb) 149            ExecCopySlot(slot, outerslot);(gdb) 150            return slot;(gdb) p *slot$18 = {type = T_TupleTableSlot, tts_flags = 20, tts_nvalid = 0,   tts_ops = 0xc3e720 , tts_tupleDescriptor = 0x1230660,   tts_values = 0x12307e8, tts_isnull = 0x12307f0, tts_mcxt = 0x122fd70, tts_tid = {    ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, tts_tableOid = 0}(gdb) p *slot->tts_values$19 = 0(gdb)

继续执行

...(gdb) p slot->tts_values[0]$24 = 9998243(gdb) cContinuing.Breakpoint 1, ExecMaterial (pstate=0x1230128) at nodeMaterial.c:4141        MaterialState *node = castNode(MaterialState, pstate);(gdb) n49        CHECK_FOR_INTERRUPTS();(gdb) 54        estate = node->ss.ps.state;(gdb) 55        dir = estate->es_direction;(gdb) 56        forward = ScanDirectionIsForward(dir);(gdb) 57        tuplestorestate = node->tuplestorestate;(gdb) 62        if (tuplestorestate == NULL && node->eflags != 0)(gdb) 85        eof_tuplestore = (tuplestorestate == NULL) ||(gdb) 86            tuplestore_ateof(tuplestorestate);(gdb) 85        eof_tuplestore = (tuplestorestate == NULL) ||(gdb) 88        if (!forward && eof_tuplestore)(gdb) 107        slot = node->ss.ps.ps_ResultTupleSlot;(gdb) 108        if (!eof_tuplestore)(gdb) 124        if (eof_tuplestore && !node->eof_underlying)(gdb) 133            outerNode = outerPlanState(node);(gdb) 134            outerslot = ExecProcNode(outerNode);(gdb) 135            if (TupIsNull(outerslot))(gdb) 146            if (tuplestorestate)(gdb) 147                tuplestore_puttupleslot(tuplestorestate, outerslot);(gdb) 149            ExecCopySlot(slot, outerslot);(gdb) 150            return slot;(gdb) p slot->tts_values[0]$25 = 9998244(gdb) ...

"怎么使用PostgreSQ中的ExecMaterial函数"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0