文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL 源码解读(83)- 查询语句#68(PortalStart函数)

2024-04-02 19:55

关注

本节介绍了PortalStart函数,该函数在create_simple_query中被调用,用于执行前初始化portal结构体中的相关信息。

一、数据结构

Portal
包括场景PortalStrategy枚举定义/PortalStatus状态定义/PortalData结构体.Portal是PortalData结构体指针,详见代码注释.


typedef enum PortalStrategy
{
    PORTAL_ONE_SELECT,
    PORTAL_ONE_RETURNING,
    PORTAL_ONE_MOD_WITH,
    PORTAL_UTIL_SELECT,
    PORTAL_MULTI_QUERY
} PortalStrategy;


typedef enum PortalStatus
{
    PORTAL_NEW,                 
    PORTAL_DEFINED,             
    PORTAL_READY,               
    PORTAL_ACTIVE,              
    PORTAL_DONE,                
    PORTAL_FAILED               
} PortalStatus;

typedef struct PortalData *Portal;//结构体指针

typedef struct PortalData
{
    
    const char *name;           
    const char *prepStmtName;   
    MemoryContext portalContext;    
    ResourceOwner resowner;     
    void        (*cleanup) (Portal portal); 

    
    SubTransactionId createSubid;   
    SubTransactionId activeSubid;   

    
    //portal将会执行的查询
    const char *sourceText;     
    const char *commandTag;     
    List       *stmts;          
    CachedPlan *cplan;          

    ParamListInfo portalParams; 
    QueryEnvironment *queryEnv; 

    
    PortalStrategy strategy;    
    int         cursorOptions;  
    bool        run_once;       

    
    PortalStatus status;        
    bool        portalPinned;   
    bool        autoHeld;       

    
    //如不为NULL,执行器处于活动状态
    QueryDesc  *queryDesc;      

    
    //如Portal需要返回元组,这是元组的描述
    TupleDesc   tupDesc;        
    
    //列信息的格式码
    int16      *formats;        

    
    Tuplestorestate *holdStore; 
    MemoryContext holdContext;  

    
    Snapshot    holdSnapshot;   

    
    bool        atStart;//处于开始位置?
    bool        atEnd;//处于结束位置?
    uint64      portalPos;//实际行号

    
    //用于表示的数据,主要由pg_cursors系统视图使用
    TimestampTz creation_time;  
    bool        visible;        
}           PortalData;


#define PortalIsValid(p) PointerIsValid(p)

QueryDesc
QueryDesc封装了执行器执行查询所需的所有内容。


typedef struct QueryDesc
{
    
    //以下变量由CreateQueryDesc函数设置
    CmdType     operation;      
    PlannedStmt *plannedstmt;   
    const char *sourceText;     
    Snapshot    snapshot;       
    Snapshot    crosscheck_snapshot;    
    DestReceiver *dest;         
    ParamListInfo params;       
    QueryEnvironment *queryEnv; 
    int         instrument_options; 

    
    //以下变量由ExecutorStart函数设置
    TupleDesc   tupDesc;        
    EState     *estate;         
    PlanState  *planstate;      

    
    //以下变量由ExecutorRun设置
    bool        already_executed;   

    
    //内核设置为NULL,可由插件修改
    struct Instrumentation *totaltime;  
} QueryDesc;

二、源码解读

PortalStart
PortalStart函数的作用是在执行SQL语句前初始化portal结构体中的相关信息,其中有2个重要数据结构的初始化:
1.调用CreateQueryDesc函数结构体QueryDesc
2.调用ExecutorStart函数初始化结构体EState,ExecutorStart函数调用InitPlan(下一节介绍)初始化计划状态树.


void
PortalStart(Portal portal, ParamListInfo params,
            int eflags, Snapshot snapshot)
{
    Portal      saveActivePortal;
    ResourceOwner saveResourceOwner;
    MemoryContext savePortalContext;
    MemoryContext oldContext;
    QueryDesc  *queryDesc;
    int         myeflags;

    AssertArg(PortalIsValid(portal));
    AssertState(portal->status == PORTAL_DEFINED);

    
    //保护"现场"
    saveActivePortal = ActivePortal;
    saveResourceOwner = CurrentResourceOwner;
    savePortalContext = PortalContext;
    PG_TRY();
    {
        ActivePortal = portal;
        if (portal->resowner)
            CurrentResourceOwner = portal->resowner;
        PortalContext = portal->portalContext;

        oldContext = MemoryContextSwitchTo(PortalContext);

        
        //记录传递的参数信息
        portal->portalParams = params;

        
        portal->strategy = ChoosePortalStrategy(portal->stmts);

        
        switch (portal->strategy)
        {
            case PORTAL_ONE_SELECT://PORTAL_ONE_SELECT

                
                //在开始执行前必须设置快照snapshot
                if (snapshot)
                    PushActiveSnapshot(snapshot);
                else
                    PushActiveSnapshot(GetTransactionSnapshot());

                
                queryDesc = CreateQueryDesc(linitial_node(PlannedStmt, portal->stmts),
                                            portal->sourceText,
                                            GetActiveSnapshot(),
                                            InvalidSnapshot,
                                            None_Receiver,
                                            params,
                                            portal->queryEnv,
                                            0);

                
                if (portal->cursorOptions & CURSOR_OPT_SCROLL)
                    myeflags = eflags | EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD;
                else
                    myeflags = eflags;

                
                ExecutorStart(queryDesc, myeflags);

                
                portal->queryDesc = queryDesc;

                
                portal->tupDesc = queryDesc->tupDesc;

                
                portal->atStart = true;//开始的位置
                portal->atEnd = false;  
                portal->portalPos = 0;//游标位置

                PopActiveSnapshot();
                break;

            case PORTAL_ONE_RETURNING:
            case PORTAL_ONE_MOD_WITH:

                
                {
                    PlannedStmt *pstmt;

                    pstmt = PortalGetPrimaryStmt(portal);//获取主stmt
                    portal->tupDesc =
                        ExecCleanTypeFromTL(pstmt->planTree->targetlist,
                                            false);//设置元组描述符
                }

                
                portal->atStart = true;
                portal->atEnd = false;  
                portal->portalPos = 0;
                break;

            case PORTAL_UTIL_SELECT://PORTAL_UTIL_SELECT

                
                {
                    PlannedStmt *pstmt = PortalGetPrimaryStmt(portal);

                    Assert(pstmt->commandType == CMD_UTILITY);
                    portal->tupDesc = UtilityTupleDescriptor(pstmt->utilityStmt);
                }

                
                portal->atStart = true;
                portal->atEnd = false;  
                portal->portalPos = 0;
                break;

            case PORTAL_MULTI_QUERY://PORTAL_MULTI_QUERY
                
                portal->tupDesc = NULL;
                break;
        }
    }
    PG_CATCH();
    {
        
        MarkPortalFailed(portal);

        
        ActivePortal = saveActivePortal;
        CurrentResourceOwner = saveResourceOwner;
        PortalContext = savePortalContext;

        PG_RE_THROW();
    }
    PG_END_TRY();

    MemoryContextSwitchTo(oldContext);

    ActivePortal = saveActivePortal;
    CurrentResourceOwner = saveResourceOwner;
    PortalContext = savePortalContext;

    portal->status = PORTAL_READY;
}



PortalStrategy
ChoosePortalStrategy(List *stmts)
{
    int         nSetTag;
    ListCell   *lc;

    
    if (list_length(stmts) == 1)//只有1条语句
    {
        Node       *stmt = (Node *) linitial(stmts);//获取stmt

        if (IsA(stmt, Query))//Query
        {
            Query      *query = (Query *) stmt;

            if (query->canSetTag)
            {
                if (query->commandType == CMD_SELECT)//查询命令
                {
                    if (query->hasModifyingCTE)
                        return PORTAL_ONE_MOD_WITH;//存在可更新的CTE-->PORTAL_ONE_MOD_WITH
                    else
                        return PORTAL_ONE_SELECT;//单个查询语句
                }
                if (query->commandType == CMD_UTILITY)//工具语句
                {
                    if (UtilityReturnsTuples(query->utilityStmt))//返回元组
                        return PORTAL_UTIL_SELECT;//PORTAL_UTIL_SELECT
                    
                    return PORTAL_MULTI_QUERY;//返回PORTAL_MULTI_QUERY
                }
            }
        }
        else if (IsA(stmt, PlannedStmt))//PlannedStmt,参见Query处理逻辑
        {
            PlannedStmt *pstmt = (PlannedStmt *) stmt;

            if (pstmt->canSetTag)
            {
                if (pstmt->commandType == CMD_SELECT)
                {
                    if (pstmt->hasModifyingCTE)
                        return PORTAL_ONE_MOD_WITH;
                    else
                        return PORTAL_ONE_SELECT;
                }
                if (pstmt->commandType == CMD_UTILITY)
                {
                    if (UtilityReturnsTuples(pstmt->utilityStmt))
                        return PORTAL_UTIL_SELECT;
                    
                    return PORTAL_MULTI_QUERY;
                }
            }
        }
        else
            elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
    }

    //存在多条语句
    
    nSetTag = 0;
    foreach(lc, stmts)//遍历
    {
        Node       *stmt = (Node *) lfirst(lc);

        if (IsA(stmt, Query))
        {
            Query      *query = (Query *) stmt;

            if (query->canSetTag)
            {
                if (++nSetTag > 1)
                    return PORTAL_MULTI_QUERY;  
                if (query->commandType == CMD_UTILITY ||
                    query->returningList == NIL)
                    return PORTAL_MULTI_QUERY;  
            }
        }
        else if (IsA(stmt, PlannedStmt))
        {
            PlannedStmt *pstmt = (PlannedStmt *) stmt;

            if (pstmt->canSetTag)
            {
                if (++nSetTag > 1)
                    return PORTAL_MULTI_QUERY;  
                if (pstmt->commandType == CMD_UTILITY ||
                    !pstmt->hasReturning)
                    return PORTAL_MULTI_QUERY;  
            }
        }
        else
            elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
    }
    if (nSetTag == 1)
        return PORTAL_ONE_RETURNING;

    
    //通常的情况
    return PORTAL_MULTI_QUERY;
}



QueryDesc *
CreateQueryDesc(PlannedStmt *plannedstmt,
                const char *sourceText,
                Snapshot snapshot,
                Snapshot crosscheck_snapshot,
                DestReceiver *dest,
                ParamListInfo params,
                QueryEnvironment *queryEnv,
                int instrument_options)
{
    QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));

    qd->operation = plannedstmt->commandType;   
    qd->plannedstmt = plannedstmt;  
    qd->sourceText = sourceText;    
    qd->snapshot = RegisterSnapshot(snapshot);  
    
    qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
    qd->dest = dest;            
    qd->params = params;        
    qd->queryEnv = queryEnv;    //查询环境变量
    qd->instrument_options = instrument_options;    

    
    qd->tupDesc = NULL;//初始化为NULL
    qd->estate = NULL;
    qd->planstate = NULL;
    qd->totaltime = NULL;

    
    qd->already_executed = false;//未执行

    return qd;
}



void
ExecutorStart(QueryDesc *queryDesc, int eflags)
{
    if (ExecutorStart_hook)//存在钩子函数
        (*ExecutorStart_hook) (queryDesc, eflags);
    else
        standard_ExecutorStart(queryDesc, eflags);
}

void
standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
    EState     *estate;
    MemoryContext oldcontext;

    
    Assert(queryDesc != NULL);
    Assert(queryDesc->estate == NULL);

    
    if ((XactReadOnly || IsInParallelMode()) &&
        !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
        ExecCheckXactReadOnly(queryDesc->plannedstmt);

    
    estate = CreateExecutorState();
    queryDesc->estate = estate;

    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    
    estate->es_param_list_info = queryDesc->params;

    if (queryDesc->plannedstmt->paramExecTypes != NIL)
    {
        int         nParamExec;

        nParamExec = list_length(queryDesc->plannedstmt->paramExecTypes);
        estate->es_param_exec_vals = (ParamExecData *)
            palloc0(nParamExec * sizeof(ParamExecData));
    }

    estate->es_sourceText = queryDesc->sourceText;

    
    estate->es_queryEnv = queryDesc->queryEnv;

    
    switch (queryDesc->operation)
    {
        case CMD_SELECT:

            
            if (queryDesc->plannedstmt->rowMarks != NIL ||
                queryDesc->plannedstmt->hasModifyingCTE)
                estate->es_output_cid = GetCurrentCommandId(true);

            
            if (!queryDesc->plannedstmt->hasModifyingCTE)
                eflags |= EXEC_FLAG_SKIP_TRIGGERS;
            break;

        case CMD_INSERT:
        case CMD_DELETE:
        case CMD_UPDATE:
            estate->es_output_cid = GetCurrentCommandId(true);
            break;

        default:
            elog(ERROR, "unrecognized operation code: %d",
                 (int) queryDesc->operation);
            break;
    }

    
    estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
    estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
    estate->es_top_eflags = eflags;
    estate->es_instrument = queryDesc->instrument_options;
    estate->es_jit_flags = queryDesc->plannedstmt->jitFlags;

    
    if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))
        AfterTriggerBeginQuery();

    
    InitPlan(queryDesc, eflags);

    MemoryContextSwitchTo(oldcontext);
}

三、跟踪分析

测试脚本如下

testdb=# explain select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je 
testdb-# from t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je 
testdb(#                         from t_grxx gr inner join t_jfxx jf 
testdb(#                                        on gr.dwbh = dw.dwbh 
testdb(#                                           and gr.grbh = jf.grbh) grjf
testdb-# order by dw.dwbh;
                                        QUERY PLAN                                        
------------------------------------------------------------------------------------------
 Sort  (cost=20070.93..20320.93 rows=100000 width=47)
   Sort Key: dw.dwbh
   ->  Hash Join  (cost=3754.00..8689.61 rows=100000 width=47)
         Hash Cond: ((gr.dwbh)::text = (dw.dwbh)::text)
         ->  Hash Join  (cost=3465.00..8138.00 rows=100000 width=31)
               Hash Cond: ((jf.grbh)::text = (gr.grbh)::text)
               ->  Seq Scan on t_jfxx jf  (cost=0.00..1637.00 rows=100000 width=20)
               ->  Hash  (cost=1726.00..1726.00 rows=100000 width=16)
                     ->  Seq Scan on t_grxx gr  (cost=0.00..1726.00 rows=100000 width=16)
         ->  Hash  (cost=164.00..164.00 rows=10000 width=20)
               ->  Seq Scan on t_dwxx dw  (cost=0.00..164.00 rows=10000 width=20)
(11 rows)

启动gdb,设置断点,进入PortalStart函数

(gdb) b PortalStart
Breakpoint 1 at 0x8cb67b: file pquery.c, line 455.
(gdb) c
Continuing.

Breakpoint 1, PortalStart (portal=0x25cd468, params=0x0, eflags=0, snapshot=0x0) at pquery.c:455
455     AssertArg(PortalIsValid(portal));

校验并保护现场

455     AssertArg(PortalIsValid(portal));
(gdb) n
456     AssertState(portal->status == PORTAL_DEFINED);
(gdb) 
461     saveActivePortal = ActivePortal;
(gdb) 
462     saveResourceOwner = CurrentResourceOwner;
(gdb) 
463     savePortalContext = PortalContext;

设置内存上下文,资源owner等信息

466         ActivePortal = portal;
(gdb) 
467         if (portal->resowner)
(gdb) 
468             CurrentResourceOwner = portal->resowner;
(gdb) 
469         PortalContext = portal->portalContext;
(gdb) 
471         oldContext = MemoryContextSwitchTo(PortalContext);
(gdb) 
474         portal->portalParams = params;

场景为PORTAL_ONE_SELECT

(gdb) p portal->strategy
$1 = PORTAL_ONE_SELECT

根据strategy,进入相应的处理分支(PORTAL_ONE_SELECT)
设置快照

489                 if (snapshot)
(gdb) 
492                     PushActiveSnapshot(GetTransactionSnapshot());

创建QueryDesc结构体

(gdb) 
498                 queryDesc = CreateQueryDesc(linitial_node(PlannedStmt, portal->stmts),

查看queryDesc结构体信息

(gdb) n
512                 if (portal->cursorOptions & CURSOR_OPT_SCROLL)
(gdb) p *queryDesc
$2 = {operation = CMD_SELECT, plannedstmt = 0x2650df0, 
  sourceText = 0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>..., 
  snapshot = 0x260ce10, crosscheck_snapshot = 0x0, dest = 0xf8f280 <donothingDR>, params = 0x0, queryEnv = 0x0, 
  instrument_options = 0, tupDesc = 0x0, estate = 0x0, planstate = 0x0, already_executed = false, totaltime = 0x0}

设置标记位

(gdb) n
515                     myeflags = eflags;
(gdb) p eflags
$3 = 0

进入ExecutorStart函数

(gdb) n
147         standard_ExecutorStart(queryDesc, eflags);
(gdb) step
standard_ExecutorStart (queryDesc=0x2657f68, eflags=0) at execMain.c:157
157     Assert(queryDesc != NULL);

ExecutorStart-->执行相关校验和判断

157     Assert(queryDesc != NULL);
(gdb) n
158     Assert(queryDesc->estate == NULL);
(gdb) 
175     if ((XactReadOnly || IsInParallelMode()) &&

ExecutorStart-->创建EState,初始化EState结构体

(gdb) 
182     estate = CreateExecutorState();
(gdb) 
183     queryDesc->estate = estate;
(gdb) p *estate
$4 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x0, es_crosscheck_snapshot = 0x0, 
  es_range_table = 0x0, es_plannedstmt = 0x0, es_sourceText = 0x0, 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_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0, 
  es_trig_tuple_slot = 0x0, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, 
  es_param_exec_vals = 0x0, es_queryEnv = 0x0, es_query_cxt = 0x2653e30, es_tupleTable = 0x0, es_rowMarks = 0x0, 
  es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0, es_finished = false, es_exprcontexts = 0x0, 
  es_subplanstates = 0x0, es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0, 
  es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0, 
  es_jit = 0x0, es_jit_worker_instr = 0x0}

ExecutorStart-->EState结构体中的变量赋值

(gdb) n
185     oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
(gdb) 
191     estate->es_param_list_info = queryDesc->params;
(gdb) 
193     if (queryDesc->plannedstmt->paramExecTypes != NIL)
(gdb) 
202     estate->es_sourceText = queryDesc->sourceText;
(gdb) 
207     estate->es_queryEnv = queryDesc->queryEnv;

ExecutorStart-->根据queryDesc->operation的不同执行的处理

(gdb) 
212     switch (queryDesc->operation)
(gdb) 
220             if (queryDesc->plannedstmt->rowMarks != NIL ||
(gdb) p queryDesc->operation
$5 = CMD_SELECT
(gdb) n
221                 queryDesc->plannedstmt->hasModifyingCTE)
(gdb) 
220             if (queryDesc->plannedstmt->rowMarks != NIL ||
(gdb) 
230             if (!queryDesc->plannedstmt->hasModifyingCTE)
(gdb) 
231                 eflags |= EXEC_FLAG_SKIP_TRIGGERS;
(gdb) 
232             break;

ExecutorStart-->设置快照

(gdb) n
249     estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
(gdb) p *queryDesc->snapshot
$6 = {satisfies = 0xa923ca <HeapTupleSatisfiesMVCC>, xmin = 1689, xmax = 1689, xip = 0x0, xcnt = 0, subxip = 0x0, 
  subxcnt = 0, suboverflowed = false, takenDuringRecovery = false, copied = true, curcid = 0, speculativeToken = 0, 
  active_count = 1, regd_count = 1, ph_node = {first_child = 0x0, next_sibling = 0x0, prev_or_parent = 0x0}, whenTaken = 0, 
  lsn = 0}

ExecutorStart-->设置其他EState中的变量

(gdb) n
250     estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
(gdb) p *queryDesc->crosscheck_snapshot
Cannot access memory at address 0x0
(gdb) n
251     estate->es_top_eflags = eflags;
(gdb) 
252     estate->es_instrument = queryDesc->instrument_options;
(gdb) 
253     estate->es_jit_flags = queryDesc->plannedstmt->jitFlags;
(gdb) 
259     if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))

ExecutorStart-->执行InitPlan

(gdb) 
265     InitPlan(queryDesc, eflags);
(gdb) 
267     MemoryContextSwitchTo(oldcontext);
(gdb) 
268 }

ExecutorStart-->查看QueryDesc和EState

(gdb) p *queryDesc
$7 = {operation = CMD_SELECT, plannedstmt = 0x2650df0, 
  sourceText = 0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>..., 
  snapshot = 0x25e46c0, crosscheck_snapshot = 0x0, dest = 0xf8f280 <donothingDR>, params = 0x0, queryEnv = 0x0, 
  instrument_options = 0, tupDesc = 0x2665058, estate = 0x2653f48, planstate = 0x2654160, already_executed = false, 
  totaltime = 0x0}
(gdb) p *estate
$8 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x25e46c0, es_crosscheck_snapshot = 0x0, 
  es_range_table = 0x264ec98, es_plannedstmt = 0x2650df0, 
  es_sourceText = 0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>..., 
  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_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0, es_trig_tuple_slot = 0x0, 
  es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, es_param_exec_vals = 0x0, 
  es_queryEnv = 0x0, es_query_cxt = 0x2653e30, es_tupleTable = 0x2654af8, es_rowMarks = 0x0, es_processed = 0, 
  es_lastoid = 0, es_top_eflags = 16, es_instrument = 0, es_finished = false, es_exprcontexts = 0x2654550, 
  es_subplanstates = 0x0, es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0, 
  es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0, 
  es_jit = 0x0, es_jit_worker_instr = 0x0}

ExecutorStart-->回到PortalStart

(gdb) n
ExecutorStart (queryDesc=0x2657f68, eflags=0) at execMain.c:148
148 }
(gdb) n
PortalStart (portal=0x25cd468, params=0x0, eflags=0, snapshot=0x0) at pquery.c:525
525                 portal->queryDesc = queryDesc;

设置portal中的变量atStart等

525                 portal->queryDesc = queryDesc;
(gdb) n
530                 portal->tupDesc = queryDesc->tupDesc;
(gdb) 
535                 portal->atStart = true;
(gdb) 
536                 portal->atEnd = false;  
(gdb) 
537                 portal->portalPos = 0;
(gdb) 
539                 PopActiveSnapshot();
(gdb) 
540                 break;

执行完毕,回到exec_simple_query

(gdb) 
613     portal->status = PORTAL_READY;
(gdb) 
614 }
(gdb) 
exec_simple_query (
    query_string=0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>...) at postgres.c:1091
warning: Source file is more recent than executable.
1091            format = 0;             
(gdb) 

DONE!

四、参考资料

postgres.c
PG Document:Query Planning

免责声明:

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

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

软考中级精品资料免费领

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

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

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

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

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

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

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