Initialization and execution Logic of APPEND Plan Node Node
As_first_partial_plan = firstvalid; appendstate- > appendplans = appendplanstates; appendstate- > as_nplans = nplans; / * * Miscellaneous initialization * initialization * / appendstate- > ps.ps_ProjInfo = NULL; / * For parallel query, this will be overridden later. * / / for parallel queries, the value will then be overridden by appendstate- > choose_next_subplan = choose_next_subplan_locally; return appendstate;}
ExecAppend
ExecAppend iterates in multiple subplans
/ *-* ExecAppend * * Handles iteration over multiple subplans. * deal with iterations in multiple subplans *-* / static TupleTableSlot * ExecAppend (PlanState * pstate) {AppendState * node = castNode (AppendState, pstate); if (node- > as_whichplan)
< 0) { /* * If no subplan has been chosen, we must choose one before * proceeding. * 如果没有子计划选中,必须在开始前选择一个 */ if (node->As_whichplan = = INVALID_SUBPLAN_INDEX & &! node- > choose_next_subplan (node) return ExecClearTuple (node- > ps.ps_ResultTupleSlot); / / if there is an error, clear tuple and return / * Nothing to do if there are no matching subplans * / / if there is no matching subplan, return else if (node- > as_whichplan = = NO_MATCHING_SUBPLANS) return ExecClearTuple (node- > ps.ps_ResultTupleSlot) } for (;) / / cycle to get tuple slot {PlanState * subnode; TupleTableSlot * result; CHECK_FOR_INTERRUPTS (); / * * figure out which subplan we are currently processing * choose which subplan to execute now * / Assert (node- > as_whichplan > = 0 & & node- > as_whichplan
< node->As_nplans); subnode = node- > appendplans [node-> as_whichplan]; / * * get a tuple from the subplan * get tuple * / result = ExecProcNode (subnode) from the subplan; if (! TupIsNull (result)) {/ * * If the subplan gave us something then return it as-is. We do * NOT make use of the result slot that was set up in * ExecInitAppend; there's no need for it. * if the subplan returns, it returns directly. * here, there is no need to construct the resulting slot in ExecInitAppend, because it is not necessary. * / return result;} / * choose new subplan; if none, we're done * / Select a new subplan. If none, call if (! node- > choose_next_subplan (node)) return ExecClearTuple (node- > ps.ps_ResultTupleSlot).
The test script is as follows
Testdb=# explain verbose select * from t_hash_partition where C1 = 1 OR C1 = 2 QUERY PLAN -Append (cost=0.00..30.53 rows=6 width=200)-> Seq Scan on public.t_hash_partition_1 (cost=0.00..15.25 rows=3 width=200) Output: t_hash_partition_1.c1 T_hash_partition_1.c2, t_hash_partition_1.c3 Filter: (t_hash_partition_1.c1 = 1) OR (t_hash_partition_1.c1 = 2)-> Seq Scan on public.t_hash_partition_3 (cost=0.00..15.25 rows=3 width=200) Output: t_hash_partition_3.c1, t_hash_partition_3.c2 T_hash_partition_3.c3 Filter: (t_hash_partition_3.c1 = 1) OR (t_hash_partition_3.c1 = 2)) (7 rows)
ExecInitAppend
Start gdb and set breakpoint
(gdb) b ExecInitAppendBreakpoint 1 at 0x6efa8a: file nodeAppend.c, line 103. (gdb) cContinuing.Breakpoint 1, ExecInitAppend (node=0x27af638, estate=0x27be058, eflags=16) at nodeAppend.c:103103 AppendState * appendstate = makeNode (AppendState)
Initialize AppendState
(gdb) n113 Assert (! (eflags & EXEC_FLAG_MARK)); (gdb) 119 ExecLockNonLeafAppendTables (node- > partitioned_rels, estate); (gdb) 124 appendstate- > ps.plan = (Plan *) node; (gdb) 125appendstate- > ps.state = estate; (gdb) 126appendstate- > ps.ExecProcNode = ExecAppend; (gdb) 129appendstate- > as_whichplan = INVALID_SUBPLAN_INDEX; (gdb)
No run-time partition tailoring is required
(gdb) 132 if (node- > part_prune_info! = NULL) (gdb) p node- > part_prune_info$1 = (struct PartitionPruneInfo *) 0x0 (gdb)
All subplans need to be initialized
(gdb) n190 nplans = list_length (node- > appendplans); (gdb) 196 Assert (nplans > 0); (gdb) 198 bms_add_range (NULL, 0, nplans-1); (gdb) 197 appendstate- > as_valid_subplans = validsubplans = (gdb) n199 appendstate- > as_prune_state = NULL (gdb) p * validsubplans$4 = {nwords = 1, words = 0x27be38c} (gdb) p * validsubplans- > words$5 = 3-> that is, No.0 + No.1 (gdb)
Initialize the resulting tuple type and slot
(gdb) n205 ExecInitResultTupleSlotTL (estate, & appendstate- > ps); (gdb) 207appendplanstates = (PlanState *) palloc (nplans * (gdb))
Execute ExecInitNode on each valid plan while keeping the results in the appendplanstates array.
(gdb) 216j = I = 0; (gdb) n217 firstvalid = nplans; (gdb) 218 foreach (lc, node- > appendplans) (gdb) p nplans$6 = 2 (gdb) p node- > appendplans$7 = (List *) 0x27b30f0 (gdb) p * node- > appendplans$8 = {type = T_List, length = 2, head = 0x27b30c8, tail = 0x27b33d8} (gdb)
Traverses the appendplans to initialize the nodes in the appendplans (SeqScan)
(gdb) n220 if (bms_is_member (I, validsubplans)) (gdb) n222 Plan * initNode = (Plan *) lfirst (lc); (gdb) 228 if (I > = node- > first_partial_plan & & j)
< firstvalid)(gdb) 231 appendplanstates[j++] = ExecInitNode(initNode, estate, eflags);(gdb) p j$9 = 0(gdb) p i$10 = 0(gdb) n233 i++;(gdb) 218 foreach(lc, node->Appendplans) (gdb) 220 if (bms_is_member (I, validsubplans)) (gdb) 222 Plan * initNode = (Plan *) lfirst (lc); (gdb) 228 if (I > = node- > first_partial_plan & & j)
< firstvalid)(gdb) p *initNode$11 = {type = T_SeqScan, startup_cost = 0, total_cost = 15.25, plan_rows = 3, plan_width = 200, parallel_aware = false, parallel_safe = true, plan_node_id = 2, targetlist = 0x27b31a8, qual = 0x27b3308, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}(gdb) n231 appendplanstates[j++] = ExecInitNode(initNode, estate, eflags);(gdb) 233 i++;(gdb) 218 foreach(lc, node->Appendplans) (gdb) 236 appendstate- > as_first_partial_plan = firstvalid; (gdb)
Initialization is completed, where the choose_next_subplan function is the choose_next_subplan_locally function
(gdb) p firstvalid$12 = 2 (gdb) n237 appendstate- > appendplans = appendplanstates; (gdb) 238 appendstate- > as_nplans = nplans; (gdb) 244 appendstate- > ps.ps_ProjInfo = NULL; (gdb) 247 appendstate- > choose_next_subplan = choose_next_subplan_locally; (gdb) 249 return appendstate (gdb) p choose_next_subplan_locally$13 = {_ Bool (AppendState *)} 0x6f02d8 (gdb) p * appendstate$15 = {ps = {type = T_AppendState, plan = 0x27af638, state = 0x27be058, ExecProcNode = 0x6efe19, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, 0x0 = 0x0, ps_ResultTupleSlot = ps_ResultTupleSlot, 0x27be5c0 = 0x27be5c0, 0x27be5c0 = 0x27be5c0, 0x27be5c0 = 0x27be5c0 As_nplans = 2, as_whichplan =-1, as_first_partial_plan = 2, as_pstate = 0x0, pstate_len = 0, as_prune_state = 0x0, as_valid_subplans = 0x27be388, choose_next_subplan = 0x6f02d8}
ExecAppend
Set breakpoint and enter ExecAppend
(gdb) del Delete all breakpoints? (y or n) y (gdb) b ExecAppendBreakpoint 2 at 0x6efe2a: file nodeAppend.c, line 261.( gdb) cContinuing.Breakpoint 2, ExecAppend (pstate=0x27be270) at nodeAppend.c:261261 AppendState * node = castNode (AppendState, pstate)
The input parameter is the AppendState that has previously completed initialization
(gdb) p * (AppendState *) pstate$19 = {ps = {type = T_AppendState, plan = 0x27af638, state = 0x27be058, ExecProcNode = 0x6efe19, ExecProcNodeReal = 0x6efe19, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x27be5c0, ps_ExprContext = 0x0, 0x0 = 0x0, ps_ProjInfo = ps_ProjInfo, ps_ProjInfo = 0x0}, 0x0 = 2, 0x0 =-1 As_first_partial_plan = 2, as_pstate = 0x0, pstate_len = 0, as_prune_state = 0x0, as_valid_subplans = 0x27be388, choose_next_subplan = 0x6f02d8}
If no subplan is selected, you must select one before you start (select subplan: No.0)
(gdb) n263 if (node- > as_whichplan)
< 0)(gdb) 269 if (node->As_whichplan = = INVALID_SUBPLAN_INDEX & & (gdb) 270! node- > choose_next_subplan (node) (gdb) 269 if (node- > as_whichplan = = INVALID_SUBPLAN_INDEX & & (gdb) 274 else if (node- > as_whichplan = = NO_MATCHING_SUBPLANS) (gdb) p node- > as_whichplan$20 = 0 (gdb) n283 CHECK_FOR_INTERRUPTS ()
Obtain the subplan and execute it
(gdb) 288 Assert (node- > as_whichplan > = 0 & & node- > as_whichplan
< node->As_nplans); (gdb) 289 subnode = node- > appendplans [node-> as_whichplan]; (gdb) 294 result = ExecProcNode (subnode) (gdb) p * subnode$21 = {type = T_SeqScanState, plan = 0x27b2728, state = 0x27be058, ExecProcNode = 0x6e4bde, ExecProcNodeReal = 0x71578d, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x27bec88, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x27bebc8, ps_ExprContext = 0x27be7f8, ps_ProjInfo = 0x0, 0x0 = scandesc}
Return to slot
(gdb) n296 if (! TupIsNull (result)) (gdb) p * result$22 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x27c5500, tts_tupleDescriptor = 0x7f7d049417e0, tts_mcxt = 0x27bdf40, tts_buffer = 120, tts_nvalid = 1, tts_values = 0x27be950, tts_isnull = 0x27be968, tts_mintuple = 0x0, tts_minhdr = {t_len = 0 T_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 4, tts_fixedTupleDescriptor = true}
If the first subplan is finished, select the next subplan (call the choose_next_subplan function to switch to the next subplan)
(gdb) cContinuing.Breakpoint 2, ExecAppend (pstate=0x27be270) at nodeAppend.c:261261 AppendState * node = castNode (AppendState, pstate); (gdb) n263 if (node- > as_whichplan)
< 0)(gdb) 283 CHECK_FOR_INTERRUPTS();(gdb) 288 Assert(node->As_whichplan > = 0 & & node- > as_whichplan
< node->As_nplans); (gdb) 289 subnode = node- > appendplans [node-> as_whichplan]; (gdb) 294 result = ExecProcNode (subnode); (gdb) 296 if (! TupIsNull (result)) (gdb) 307 if (! node- > choose_next_subplan (node)) (gdb) 309} above are all the contents of this article entitled "initialization and execution Logic of APPEND Plan Node nodes". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!