您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么使用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 testdb Timing 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; ANALYZE Time: 64.442 ms [local]:5432 pg12@testdb=# analyze t_big_null; ANALYZE Time: 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 ExecMaterial Breakpoint 1 at 0x720edb: file nodeMaterial.c, line 41. (gdb) c Continuing. Breakpoint 1, ExecMaterial (pstate=0x1230128) at nodeMaterial.c:41 41 MaterialState *node = castNode(MaterialState, pstate); (gdb)
輸入參數
(gdb) p *pstate $4 = {type = T_MaterialState, plan = 0x1211858, state = 0x122fe88, ExecProcNode = 0x720ecf <ExecMaterial>, ExecProcNodeReal = 0x720ecf <ExecMaterial>, 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 <TTSOpsMinimalTuple>, outerops = 0x0, innerops = 0x0, resultops = 0xc3e720 <TTSOpsMinimalTuple>, 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 <ExecMaterial>, ExecProcNodeReal = 0x720ecf <ExecMaterial>, 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 <TTSOpsMinimalTuple>, outerops = 0x0, innerops = 0x0, resultops = 0xc3e720 <TTSOpsMinimalTuple>, 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) n 64 tuplestorestate = tuplestore_begin_heap(true, false, work_mem); (gdb) n 65 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 <copytup_heap>, writetup = 0xaba811 <writetup_heap>, readtup = 0xaba9d9 <readtup_heap>, 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) n 66 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 <copytup_heap>, writetup = 0xaba811 <writetup_heap>, readtup = 0xaba9d9 <readtup_heap>, 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) n 86 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) n 107 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 <TTSOpsMinimalTuple>, 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) n 110 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) n 133 outerNode = outerPlanState(node); (gdb) n 134 outerslot = ExecProcNode(outerNode); (gdb) 135 if (TupIsNull(outerslot)) (gdb) p *outerNode $14 = {type = T_SeqScanState, plan = 0x1210f58, state = 0x122fe88, ExecProcNode = 0x72b904 <ExecSeqScan>, ExecProcNodeReal = 0x72b904 <ExecSeqScan>, 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 <TTSOpsBufferHeapTuple>, outerops = 0x0, innerops = 0x0, resultops = 0xc3e780 <TTSOpsBufferHeapTuple>, 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 <TTSOpsBufferHeapTuple>, 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) n 146 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 <TTSOpsMinimalTuple>, 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) c Continuing. Breakpoint 1, ExecMaterial (pstate=0x1230128) at nodeMaterial.c:41 41 MaterialState *node = castNode(MaterialState, pstate); (gdb) n 49 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函數”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。