转载:PostgreSQL服务过程中的那些事二:Pg服务进程处理简单查询六:执行器执行

转载来自:

PostgreSQL服务过程中的那些事二:Pg服务进程处理简单查询六:执行器执行

blog.csdn.net/beiigang

beigang.iteye.com


话说 查询“ select cname, comp from test1, test2 where test1.id=test2.id; ” 发送到服务器端, 走查询分支 exec_simple_query ,先调用 start_xact_command 初始化了事务管理相关对象和资源,接着调用 pg_parse_query ,通过 Lex 和 Yacc 对传入 SQL 语句进行词法语法解析,生成解析树。下来调用 GetTransactionSnapshot 方法做内存快照,然后调用 pg_analyze_and_rewrite 方法,进行语义分析把 parsetree 转换成 querytree ,然后对该 querytree 进行重写。接着调用pg_plan_queries 方法,根据 querytree 做查询 规划,生成查询计划树 plantree 。然后调用了一系列方法 CreatePortal 、 PortalStart 、 PortalSetResultFormat 、 CreateDestReceiver 、 PortalRun、 PortalDrop ,创建 portal 、初始化 portal 、 设置结果列格式、创建目的地接收者、运行portal执行查询并返回结果,然后释放 portal 相关资源,再调用 finish_xact_command 释放事务相关资源。这个例子终于执行完了。

 

1

下面是执行 plantree 的调用序列图。


 

 

执行 plantree 的调用序列图

 

上图红色方框中显示了执行 plantree 的过程,主要分为 portal 创建和初始化( CreatePortal 、PortalStart )、执行( PortalRun )、释放资源( PortalDrop )三个部分。 portal 是个抽象概念,它表示一个正在运行或可运行 query 的执行状态。 Portal 支持 SQL 层的 CURSOR 和协议层的portal 。从上图中可以看出,在各个部分, portal 调用了执行器 executor 的对应方法 ExecutorStart 、 Executor Run 、 Executor Drop 完成了相关操作。

简单描述一下执行过程,方法 CreatePortal 在内存上下文 PortalMemory 里创建 portal ,并在portal 管理器 "Portal hash" 中注册(参见《 PostgreSQL 服务过程中的那些事一:启动 postgres服务进程一 . 七:初始化 portal 管理环境》);调用 PortalDefineQuery 为新建的 portal 设置sourceText (就是例子里的源 SQL 语句)、 stmts (就是上一节讨论的 plantree 列表)等字段,将 portal 状态设置为 PORTAL_DEFINED ;再调用 PortalStart 初始化 portal ,在该例子里选择PORTAL_ONE_SELECT 策略,调用 CreateQueryDesc 方法,为 portal 创建查询描述符,将portal 状态设置为 PORTAL_READY ;调用方法 PortalRun ,根据选择策略调用相应方法,根据portal 相关由 plantree 转化来的各节点结构由下至上逐层进行处理,涉及扫描数据、进行投射、结果缓存等;最后调用 PortalDrop 释放 portal 相关资源。

portal 有多个执行策略,依赖于执行什么样的 query (其实就是根据不同的 SQL 语句调用不同的方法以完成相应操作)。(注意:在所有情况下,一个 portal 仅执行一个源 SQL query ,并且从用户的视点,仅产生一个结果。但是,规则重写器可以扩展一个源 query 成 0 或多个实际的 query。)下面是 portal 的四种策略

PORTAL_ONE_SELECT :这个 portal 包含一个 SELECT 查询。我们增加运行一个执行器作为被要求的结果。这个策略还支持可持有的 cursor (为了事务结束后访问结果,执行器结果可以被转储到一个 tuplestore 里)。

         PORTAL_ONE_RETURNING :这个 portal 包含一个伴有 RETURNING 子句的INSERT/UPDATE/DELETE 查询(由规则重写器重写增加的可能的辅助查询 /query )。在第一次执行时,我们运行 portal 以完成和转储主 query 的结果到 portal 的 tuplestore 里;然后这个结果按要求返回给用户。(我们不支持 query 的部分遍历悬挂,因为 AFTER 触发器代码不能处理,并且还因为我们不想在执行所有辅助 query 时冒失败风险。)

         PORTAL_ONE_MOD_WITH : portal 包含一个 SELECT qiery ,但它包含数据修改 CTE 。这个目前和处理 PORTAL_ONE_RETURNING 的情况一样,因为需要触发触发器的可能性。将来处理这种情况的行为可以更像 PORTAL_ONE_SELECT 。

         PORTAL_UTIL_SELECT : portal 包含一个 utility 语句,其返回一个象 SELECT 那样的结果(例如, WXPLAIN 或者 SHOW )。在第一次执行时,我们运行这个语句任何转储其结果到 portal的 tuplestore 里;然后这个结果按要求的返回给客户端。

         PORTAL_MULTI_QUERY :所有其它情况。这儿,我们不支持 portal 执行: portal 的 query会被运行以完成第一次调用。

 

下面是 portal 和其执行状态、策略的类型定义及执行器状态结构定义,其他涉及到节点结构定义略去。

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 ,                 /* freshly created */

    PORTAL_DEFINED ,             /* PortalDefineQuery done */

    PORTAL_READY ,            /* PortalStart complete, can run it */

    PORTAL_ACTIVE ,              /* portal is running (can't delete it) */

    PORTAL_DONE ,             /* portal is finished (don't re-run it) */

    PORTAL_FAILED             /* portal got error (can't re-run it) */

} PortalStatus ;

 

 

typedef struct PortalData * Portal ;

 

typedef struct PortalData

{

    /* Bookkeeping data */

    const char name ;           /* portal's name */

    const char prepStmtName ;   /* source prepared statement (NULL if none) */

    MemoryContext heap ;         /* subsidiary memory for portal */

    ResourceOwner resowner ;     /* resources owned by portal */

    void         (* cleanup ) ( Portal portal);     /* cleanup hook */

    SubTransactionId createSubid ;       /* the ID of the creating subxact */

 

    /*

      * if createSubid is InvalidSubTransactionId, the portal is held over from

      * a previous transaction

      */

 

    /* The query or queries the portal will execute */

    const char sourceText ;     /* text of query (as of 8.4, never NULL) */

    const char commandTag ;     /* command tag for original query */

    List        * stmts ;          /* PlannedStmts and/or utility statements */

    CachedPlan * cplan ;          /* CachedPlan, if stmts are from one */

 

    ParamListInfo portalParams ; /* params to pass to query */

 

    /* Features/options */

    PortalStrategy strategy ;    /* see above */

    int          cursorOptions ;  /* DECLARE CURSOR option bits */

 

    /* Status data */

    PortalStatus status ;        /* see above */

    bool         portalPinned ;   /* a pinned portal can't be dropped */

 

    /* If not NULL, Executor is active; call ExecutorEnd eventually: */

    QueryDesc   * queryDesc ;      /* info needed for executor invocation */

 

    /* If portal returns tuples, this is their tupdesc : */

    TupleDesc    tupDesc ;        /* descriptor for result tuples */

    /* and these are the format codes to use for the columns: */

    int16       * formats ;    /* a format code for each column */

 

    /*

      * Where we store tuples for a held cursor or a PORTAL_ONE_RETURNING or

      * PORTAL_UTIL_SELECT query.  (A cursor held past the end of its

      * transaction no longer has any active executor state.)

      */

    Tuplestorestate * holdStore ; /* store for holdable cursors */

    MemoryContext holdContext ;  /* memory containing holdStore */

 

    /*

      * atStart, atEnd and portalPos indicate the current cursor position.

      * portalPos is zero before the first row, N after fetching N'th row of

      * query.  After we run off the end, portalPos = # of rows in query, and

      * atEnd is true.  If portalPos overflows, set posOverflow (this causes us

      * to stop relying on its value for navigation).  Note that atStart

      * implies portalPos == 0, but not the reverse (portalPos could have

      * overflowed).

      */

    bool         atStart ;

    bool         atEnd ;

    bool         posOverflow ;

    long         portalPos ;

 

    /* Presentation data, primarily used by the pg_cursors system view */

    TimestampTz creation_time ;  /* time at which this portal was defined */

    bool         visible ;        /* include this portal in pg_cursors? */

}   PortalData ;

 

执行器调用的主工作状态

typedef struct EState

{

    NodeTag      type ;

 

    /* Basic state for all query types: */

    ScanDirection es_direction ; /* current scan direction */

    Snapshot     es_snapshot ;    /* time qual to use */

    Snapshot     es_crosscheck_snapshot ; /* crosscheck time qual for RI */

    List        * es_range_table ; /* List of RangeTblEntry */

    PlannedStmt * es_plannedstmt ;    /* link to top of plan tree */

 

    JunkFilter * es_junkFilter ;  /* top-level junk filter, if any */

 

    /* If query can insert/delete tuples, the command ID to mark them with */

    CommandId    es_output_cid ;

 

    /* Info about target table(s) for insert/update/delete queries: */

    ResultRelInfo * es_result_relations ; /* array of ResultRelInfos */

    int          es_num_result_relations ;        /* length of array */

    ResultRelInfo * es_result_relation_info ;     /* currently active array elt*/

 

    /* Stuff used for firing triggers: */

    List        * es_trig_target_relations ;       /* trigger-only ResultRelInfos */

    TupleTableSlot * es_trig_tuple_slot ; /* for trigger output tuples */

    TupleTableSlot * es_trig_oldtup_slot ;        /* for TriggerEnabled */

 

    /* Parameter info: */

    ParamListInfo es_param_list_info ;   /* values of external params */

    ParamExecData * es_param_exec_vals ;  /* values of internal params */

 

    /* Other working state: */

    MemoryContext es_query_cxt ; /* per-query context in which EState lives */

 

    List        * es_tupleTable ;  /* List of TupleTableSlots */

 

    List        * es_rowMarks ; /* List of ExecRowMarks */

 

    uint32       es_processed ;   /* # of tuples processed */

    Oid          es_lastoid ;     /* last oid processed (by INSERT) */

 

    int          es_top_eflags ;  /* eflags passed to ExecutorStart */

    int          es_instrument ;  /* OR of InstrumentOption flags */

    bool         es_select_into ; /* true if doing SELECT INTO */

    bool         es_into_oids ;   /* true to generate OIDs in SELECT INTO */

    bool         es_finished ;    /* true when ExecutorFinish is done */

 

    List        * es_exprcontexts ; /* List of ExprContexts within EState */

 

    List        * es_subplanstates ;       /* List of PlanState for SubPlans */

 

    List        * es_auxmodifytables ;     /* List of secondary ModifyTableStates */

 

    /*

      * this ExprContext is for per-output-tuple operations, such as constraint

      * checks and index-value computations.  It will be reset for each output

      * tuple.  Note that it will be created only if needed.

      */

    ExprContext * es_per_tuple_exprcontext ;

 

    /*

      * These fields are for re-evaluating plan quals when an updated tuple is

      * substituted in READ COMMITTED mode.  es_epqTuple[] contains tuples that

      * scan plan nodes should return instead of whatever they'd normally

      * return, or NULL if nothing to return; es_epqTupleSet[] is true if a

      * particular array entry is valid; and es_epqScanDone[] is state to

      * remember if the tuple has been returned already.  Arrays are of size

      * list_length(es_range_table) and are indexed by scan node scanrelid - 1.

      */

    HeapTuple   * es_epqTuple ; /* array of EPQ substitute tuples */

    bool        * es_epqTupleSet ; /* true if EPQ tuple is provided */

    bool        * es_epqScanDone ; /* true if EPQ tuple has been fetched */

 

    /*

      * this field added at end of struct to avoid post-release ABI breakage in

      * existing release branches.  It'll be in a more logical place in 9.2.

      */

    TupleTableSlot * es_trig_newtup_slot ;        /* for TriggerEnabled */

EState ;

 

         下面是执行这个查询的 portal 相关内存结构图:

  

 

portal 相关内存结构图

 

 

就到这儿吧。

相关文章
相关标签/搜索