中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PostgreSQL中ExecProcNode和ExecProcNodeFirst函數的實現邏輯是什么

發布時間:2021-11-11 11:52:05 來源:億速云 閱讀:281 作者:iii 欄目:關系型數據庫

這篇文章主要講解了“PostgreSQL中ExecProcNode和ExecProcNodeFirst函數的實現邏輯是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“PostgreSQL中ExecProcNode和ExecProcNodeFirst函數的實現邏輯是什么”吧!

一、基礎信息

ExecProcNode/ExecProcNodeFirst函數使用的數據結構、宏定義以及依賴的函數等。
數據結構/宏定義
1、ExecProcNodeMtd
ExecProcNodeMtd是一個函數指針類型,指向的函數輸入參數是PlanState結構體指針,輸出參數是TupleTableSlot 結構體指針

 /* ----------------
  *   ExecProcNodeMtd
  *
  * This is the method called by ExecProcNode to return the next tuple
  * from an executor node.  It returns NULL, or an empty TupleTableSlot,
  * if no more tuples are available.
  * ----------------
  */
 typedef TupleTableSlot *(*ExecProcNodeMtd) (struct PlanState *pstate);

依賴的函數
1、check_stack_depth

//檢查stack的深度,如超出系統限制,則主動報錯
 /*
  * check_stack_depth/stack_is_too_deep: check for excessively deep recursion
  *
  * This should be called someplace in any recursive routine that might possibly
  * recurse deep enough to overflow the stack.  Most Unixen treat stack
  * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves
  * before hitting the hardware limit.
  *
  * check_stack_depth() just throws an error summarily.  stack_is_too_deep()
  * can be used by code that wants to handle the error condition itself.
  */
 void
 check_stack_depth(void)
 {
     if (stack_is_too_deep())
     {
         ereport(ERROR,
                 (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
                  errmsg("stack depth limit exceeded"),
                  errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), "
                          "after ensuring the platform's stack depth limit is adequate.",
                          max_stack_depth)));
     }
 }
 
 bool
 stack_is_too_deep(void)
 {
     char        stack_top_loc;
     long        stack_depth;
 
     /*
      * Compute distance from reference point to my local variables
      */
     stack_depth = (long) (stack_base_ptr - &stack_top_loc);
 
     /*
      * Take abs value, since stacks grow up on some machines, down on others
      */
     if (stack_depth < 0)
         stack_depth = -stack_depth;
 
     /*
      * Trouble?
      *
      * The test on stack_base_ptr prevents us from erroring out if called
      * during process setup or in a non-backend process.  Logically it should
      * be done first, but putting it here avoids wasting cycles during normal
      * cases.
      */
     if (stack_depth > max_stack_depth_bytes &&
         stack_base_ptr != NULL)
         return true;
 
     /*
      * On IA64 there is a separate "register" stack that requires its own
      * independent check.  For this, we have to measure the change in the
      * "BSP" pointer from PostgresMain to here.  Logic is just as above,
      * except that we know IA64's register stack grows up.
      *
      * Note we assume that the same max_stack_depth applies to both stacks.
      */
 #if defined(__ia64__) || defined(__ia64)
     stack_depth = (long) (ia64_get_bsp() - register_stack_base_ptr);
 
     if (stack_depth > max_stack_depth_bytes &&
         register_stack_base_ptr != NULL)
         return true;
 #endif                          /* IA64 */
 
     return false;
 }

2、ExecProcNodeInstr

 /*
  * ExecProcNode wrapper that performs instrumentation calls.  By keeping
  * this a separate function, we avoid overhead in the normal case where
  * no instrumentation is wanted.
  */
 static TupleTableSlot *
 ExecProcNodeInstr(PlanState *node)
 {
     TupleTableSlot *result;
 
     InstrStartNode(node->instrument);
 
     result = node->ExecProcNodeReal(node);
 
     InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
 
     return result;
 }

二、源碼解讀

1、ExecProcNode

//外部調用者可通過改變node實現遍歷
 /* ----------------------------------------------------------------
  *      ExecProcNode
  *
  *      Execute the given node to return a(nother) tuple.
  * ----------------------------------------------------------------
  */
 #ifndef FRONTEND
 static inline TupleTableSlot *
 ExecProcNode(PlanState *node)
 {
     if (node->chgParam != NULL) /* something changed? */
         ExecReScan(node);       /* let ReScan handle this */
 
     return node->ExecProcNode(node);
 }
 #endif

2、ExecProcNodeFirst

/*
 * ExecProcNode wrapper that performs some one-time checks, before calling
 * the relevant node method (possibly via an instrumentation wrapper).
 */
/*
輸入:
    node-PlanState指針
輸出:
    存儲Tuple的Slot
*/
static TupleTableSlot *
ExecProcNodeFirst(PlanState *node)
{
    /*
     * Perform stack depth check during the first execution of the node.  We
     * only do so the first time round because it turns out to not be cheap on
     * some common architectures (eg. x86).  This relies on the assumption
     * that ExecProcNode calls for a given plan node will always be made at
     * roughly the same stack depth.
     */
    //檢查Stack是否超深
    check_stack_depth();

    /*
     * If instrumentation is required, change the wrapper to one that just
     * does instrumentation.  Otherwise we can dispense with all wrappers and
     * have ExecProcNode() directly call the relevant function from now on.
     */
    //如果instrument(TODO)
    if (node->instrument)
        node->ExecProcNode = ExecProcNodeInstr;
    else
        node->ExecProcNode = node->ExecProcNodeReal;
    //執行該Node的處理過程
    return node->ExecProcNode(node);
}

三、跟蹤分析

插入測試數據:

testdb=# -- 獲取pid
testdb=# select pg_backend_pid();
 pg_backend_pid 
----------------
           2835
(1 row)
testdb=# -- 插入1行
testdb=# insert into t_insert values(14,'ExecProcNodeFirst','ExecProcNodeFirst','ExecProcNodeFirst');
(掛起)

啟動gdb分析:

[root@localhost ~]# gdb -p 2835
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7
Copyright (C) 2013 Free Software Foundation, Inc.
...
(gdb) b ExecProcNodeFirst
Breakpoint 1 at 0x69a797: file execProcnode.c, line 433.
(gdb) c
Continuing.

Breakpoint 1, ExecProcNodeFirst (node=0x2cca790) at execProcnode.c:433
433     check_stack_depth();
#查看輸入參數
(gdb) p *node
$1 = {type = T_ModifyTableState, plan = 0x2c1d028, state = 0x2cca440, ExecProcNode = 0x69a78b <ExecProcNodeFirst>, ExecProcNodeReal = 0x6c2485 <ExecModifyTable>, instrument = 0x0, 
  worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2ccb6a0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, 
  scandesc = 0x0}
#ExecProcNode 實際對應的函數是ExecProcNodeFirst
#ExecProcNodeReal 實際對應的函數是ExecModifyTable(上一章節已粗略解析)
(gdb) next
440     if (node->instrument)
(gdb) 
#實際調用ExecModifyTable函數(這個函數由更高層的調用函數植入)
443         node->ExecProcNode = node->ExecProcNodeReal;
(gdb) 
445     return node->ExecProcNode(node);
(gdb) next
#第二次調用(TODO)
Breakpoint 1, ExecProcNodeFirst (node=0x2ccac80) at execProcnode.c:433
433     check_stack_depth();
(gdb) next
440     if (node->instrument)
(gdb) next
443         node->ExecProcNode = node->ExecProcNodeReal;
(gdb) next
445     return node->ExecProcNode(node);
(gdb) next
446 }
(gdb) next
ExecProcNode (node=0x2ccac80) at ../../../src/include/executor/executor.h:238
238 }
#第二次調用的參數
(gdb) p *node
$2 = {type = T_ResultState, plan = 0x2cd0488, state = 0x2cca440, ExecProcNode = 0x6c5094 <ExecResult>, ExecProcNodeReal = 0x6c5094 <ExecResult>, instrument = 0x0, worker_instrument = 0x0, qual = 0x0, 
  lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2ccad90, ps_ExprContext = 0x2ccab30, ps_ProjInfo = 0x2ccabc0, scandesc = 0x0}
#ExecProcNode對應的實際函數是ExecResult
(gdb)

感謝各位的閱讀,以上就是“PostgreSQL中ExecProcNode和ExecProcNodeFirst函數的實現邏輯是什么”的內容了,經過本文的學習后,相信大家對PostgreSQL中ExecProcNode和ExecProcNodeFirst函數的實現邏輯是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

泉州市| 英吉沙县| 武宣县| 同仁县| 元朗区| 盖州市| 嘉义市| 宁明县| 萝北县| 游戏| 夏津县| 宁强县| 昌都县| 湖北省| 东阿县| 丹巴县| 集安市| 泗阳县| 贺州市| 盈江县| 武功县| 和田市| 海伦市| 都昌县| 婺源县| 洛阳市| 新野县| 邵阳县| 阳西县| 青神县| 衡南县| 乐清市| 平乡县| 昌黎县| 藁城市| 格尔木市| 定安县| 泸定县| 伊金霍洛旗| 静宁县| 民县|