博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PostgreSQL 源码解读(12)- 插入数据#11(exec_simple_query)
阅读量:2500 次
发布时间:2019-05-11

本文共 133020 字,大约阅读时间需要 443 分钟。

本文简单介绍了PG插入数据部分的源码,主要内容包括exec_simple_query函数的实现逻辑,该函数位于src/backend/tcop/postgres.c文件中。

一、源码解读

exec_simple_query函数,顾名思义,执行简单“查询”(包括INSERT/UPDATE/DELETE等语句)

/* * exec_simple_query * * Execute a "simple Query" protocol message. *//*输入:    query_string-SQL语句输出:    无*/static voidexec_simple_query(const char *query_string){    CommandDest dest = whereToSendOutput;//输出到哪里的定义    MemoryContext oldcontext;//存储原内存上下文    List       *parsetree_list;//分析树列表    ListCell   *parsetree_item;//分析树中的ITEM    bool        save_log_statement_stats = log_statement_stats;//是否保存统计信息,false    bool        was_logged = false;//Log?    bool        use_implicit_block;//是否使用隐式事务块    char        msec_str[32];    /*     * Report query to various monitoring facilities.     */    debug_query_string = query_string;    pgstat_report_activity(STATE_RUNNING, query_string);//统计信息    TRACE_POSTGRESQL_QUERY_START(query_string);    /*     * We use save_log_statement_stats so ShowUsage doesn't report incorrect     * results because ResetUsage wasn't called.     */    if (save_log_statement_stats)        ResetUsage();    /*     * Start up a transaction command.  All queries generated by the     * query_string will be in this same command block, *unless* we find a     * BEGIN/COMMIT/ABORT statement; we have to force a new xact command after     * one of those, else bad things will happen in xact.c. (Note that this     * will normally change current memory context.)     */    start_xact_command();//启动事务    /*     * Zap any pre-existing unnamed statement.  (While not strictly necessary,     * it seems best to define simple-Query mode as if it used the unnamed     * statement and portal; this ensures we recover any storage used by prior     * unnamed operations.)     */    drop_unnamed_stmt();//清除匿名语句    /*     * Switch to appropriate context for constructing parsetrees.     */    oldcontext = MemoryContextSwitchTo(MessageContext);//切换内存上下文    /*     * Do basic parsing of the query or queries (this should be safe even if     * we are in aborted transaction state!)     */    parsetree_list = pg_parse_query(query_string);//解析输入的查询语句,获得分析树List(元素是RawStmt nodes)    /* Log immediately if dictated by log_statement */    if (check_log_statement(parsetree_list))//日志记录    {        ereport(LOG,                (errmsg("statement: %s", query_string),                 errhidestmt(true),                 errdetail_execute(parsetree_list)));        was_logged = true;    }    /*     * Switch back to transaction context to enter the loop.     */    MemoryContextSwitchTo(oldcontext);//切换回原内存上下文    /*     * For historical reasons, if multiple SQL statements are given in a     * single "simple Query" message, we execute them as a single transaction,     * unless explicit transaction control commands are included to make     * portions of the list be separate transactions.  To represent this     * behavior properly in the transaction machinery, we use an "implicit"     * transaction block.     */    use_implicit_block = (list_length(parsetree_list) > 1);//如果分析树条目>1,使用隐式事务块(多条SQL语句在同一个事务中)    /*     * Run through the raw parsetree(s) and process each one.     */    foreach(parsetree_item, parsetree_list)//对分析树中的每一个条目进行处理    {        RawStmt    *parsetree = lfirst_node(RawStmt, parsetree_item);//分析树List中的元素为RawStmt指针类型        bool        snapshot_set = false;//是否设置快照?        const char *commandTag;//命令标识        char        completionTag[COMPLETION_TAG_BUFSIZE];//完成标记,如INSERT 0 1之类的字符串        List       *querytree_list,//查询树List                   *plantree_list;//执行计划List        Portal      portal;//“门户”变量        DestReceiver *receiver;//目标接收端        int16       format;//        /*         * Get the command name for use in status display (it also becomes the         * default completion tag, down inside PortalRun).  Set ps_status and         * do any special start-of-SQL-command processing needed by the         * destination.         */        commandTag = CreateCommandTag(parsetree->stmt);//创建命令标记,插入数据则为INSERT        set_ps_display(commandTag, false);        BeginCommand(commandTag, dest);//do Nothing!        /*         * If we are in an aborted transaction, reject all commands except         * COMMIT/ABORT.  It is important that this test occur before we try         * to do parse analysis, rewrite, or planning, since all those phases         * try to do database accesses, which may fail in abort state. (It         * might be safe to allow some additional utility commands in this         * state, but not many...)         */        if (IsAbortedTransactionBlockState() &&            !IsTransactionExitStmt(parsetree->stmt))            ereport(ERROR,                    (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),                     errmsg("current transaction is aborted, "                            "commands ignored until end of transaction block"),                     errdetail_abort()));        /* Make sure we are in a transaction command */        start_xact_command();//确认在事务中        /*         * If using an implicit transaction block, and we're not already in a         * transaction block, start an implicit block to force this statement         * to be grouped together with any following ones.  (We must do this         * each time through the loop; otherwise, a COMMIT/ROLLBACK in the         * list would cause later statements to not be grouped.)         */        if (use_implicit_block)            BeginImplicitTransactionBlock();//隐式事务,进入事务块        /* If we got a cancel signal in parsing or prior command, quit */        CHECK_FOR_INTERRUPTS();        /*         * Set up a snapshot if parse analysis/planning will need one.         */        if (analyze_requires_snapshot(parsetree))//是否需要快照进行分析?增删改查均需要        {            PushActiveSnapshot(GetTransactionSnapshot());//            snapshot_set = true;        }        /*         * OK to analyze, rewrite, and plan this query.         *         * Switch to appropriate context for constructing querytrees (again,         * these must outlive the execution context).         */        oldcontext = MemoryContextSwitchTo(MessageContext);//切换内存上下文        querytree_list = pg_analyze_and_rewrite(parsetree, query_string,                                                NULL, 0, NULL);//根据分析树获得查询树,返回List(元素为Query)        plantree_list = pg_plan_queries(querytree_list,                                        CURSOR_OPT_PARALLEL_OK, NULL);//根据查询树获取计划树,返回List(元素为PlannedStmt)        /* Done with the snapshot used for parsing/planning */        if (snapshot_set)            PopActiveSnapshot();//        /* If we got a cancel signal in analysis or planning, quit */        CHECK_FOR_INTERRUPTS();        /*         * Create unnamed portal to run the query or queries in. If there         * already is one, silently drop it.         */        portal = CreatePortal("", true, true);//创建匿名Portal变量        /* Don't display the portal in pg_cursors */        portal->visible = false;        /*         * We don't have to copy anything into the portal, because everything         * we are passing here is in MessageContext, which will outlive the         * portal anyway.         */        PortalDefineQuery(portal,                          NULL,                          query_string,                          commandTag,                          plantree_list,                          NULL);//给Portal变量赋值        /*         * Start the portal.  No parameters here.         */        PortalStart(portal, NULL, 0, InvalidSnapshot);//为PortalRun作准备        /*         * Select the appropriate output format: text unless we are doing a         * FETCH from a binary cursor.  (Pretty grotty to have to do this here         * --- but it avoids grottiness in other places.  Ah, the joys of         * backward compatibility...)         */        format = 0;             /* TEXT is default */        if (IsA(parsetree->stmt, FetchStmt))        {            FetchStmt  *stmt = (FetchStmt *) parsetree->stmt;            if (!stmt->ismove)            {                Portal      fportal = GetPortalByName(stmt->portalname);                if (PortalIsValid(fportal) &&                    (fportal->cursorOptions & CURSOR_OPT_BINARY))                    format = 1; /* BINARY */            }        }        PortalSetResultFormat(portal, 1, &format);//设置结果返回的格式,默认为TEXT        /*         * Now we can create the destination receiver object.         */        receiver = CreateDestReceiver(dest);//创建目标接收器(如使用psql则为:printtup DestReceiver)        if (dest == DestRemote)            SetRemoteDestReceiverParams(receiver, portal);        /*         * Switch back to transaction context for execution.         */        MemoryContextSwitchTo(oldcontext);//切换回原内存上下文        /*         * Run the portal to completion, and then drop it (and the receiver).         */        (void) PortalRun(portal,                         FETCH_ALL,                         true,  /* always top level */                         true,                         receiver,                         receiver,                         completionTag);//执行        receiver->rDestroy(receiver);//执行完毕,销毁接收器        PortalDrop(portal, false);//清除Portal中的资源&Portal        if (lnext(parsetree_item) == NULL)//所有语句已执行完毕        {            /*             * If this is the last parsetree of the query string, close down             * transaction statement before reporting command-complete.  This             * is so that any end-of-transaction errors are reported before             * the command-complete message is issued, to avoid confusing             * clients who will expect either a command-complete message or an             * error, not one and then the other.  Also, if we're using an             * implicit transaction block, we must close that out first.             */            if (use_implicit_block)                EndImplicitTransactionBlock();//结束事务            finish_xact_command();//结束事务        }        else if (IsA(parsetree->stmt, TransactionStmt))//事务语句?BEGIN/COMMIT/ABORT...        {            /*             * If this was a transaction control statement, commit it. We will             * start a new xact command for the next command.             */            finish_xact_command();        }        else        {            /*             * We need a CommandCounterIncrement after every query, except             * those that start or end a transaction block.             */            CommandCounterIncrement();//命令+1(对应Tuple中的cid)        }        /*         * Tell client that we're done with this query.  Note we emit exactly         * one EndCommand report for each raw parsetree, thus one for each SQL         * command the client sent, regardless of rewriting. (But a command         * aborted by error will not send an EndCommand report at all.)         */        EndCommand(completionTag, dest);//命令Done    }                           /* end loop over parsetrees */        //所有语句结束    /*     * Close down transaction statement, if one is open.  (This will only do     * something if the parsetree list was empty; otherwise the last loop     * iteration already did it.)     */    finish_xact_command();    /*     * If there were no parsetrees, return EmptyQueryResponse message.     */    if (!parsetree_list)        NullCommand(dest);    /*     * Emit duration logging if appropriate.     */    switch (check_log_duration(msec_str, was_logged))    {        case 1:            ereport(LOG,                    (errmsg("duration: %s ms", msec_str),                     errhidestmt(true)));            break;        case 2:            ereport(LOG,                    (errmsg("duration: %s ms  statement: %s",                            msec_str, query_string),                     errhidestmt(true),                     errdetail_execute(parsetree_list)));            break;    }    if (save_log_statement_stats)        ShowUsage("QUERY STATISTICS");    TRACE_POSTGRESQL_QUERY_DONE(query_string);    debug_query_string = NULL;}

二、基础信息

exec_simple_query函数使用的数据结构、宏定义以及依赖的函数等。

数据结构/宏定义
*1、whereToSendOutput *

/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */ CommandDest whereToSendOutput = DestDebug; /* ----------------  *      CommandDest is a simplistic means of identifying the desired  *      destination.  Someday this will probably need to be improved.  *  * Note: only the values DestNone, DestDebug, DestRemote are legal for the  * global variable whereToSendOutput.   The other values may be used  * as the destination for individual commands.  * ----------------  */ typedef enum {     DestNone,                   /* results are discarded */     DestDebug,                  /* results go to debugging output */     DestRemote,                 /* results sent to frontend process */     DestRemoteExecute,          /* sent to frontend, in Execute command */     DestRemoteSimple,           /* sent to frontend, w/no catalog access */     DestSPI,                    /* results sent to SPI manager */     DestTuplestore,             /* results sent to Tuplestore */     DestIntoRel,                /* results sent to relation (SELECT INTO) */     DestCopyOut,                /* results sent to COPY TO code */     DestSQLFunction,            /* results sent to SQL-language func mgr */     DestTransientRel,           /* results sent to transient relation */     DestTupleQueue              /* results sent to tuple queue */ } CommandDest;

2、RawStmt

/*  *      RawStmt --- container for any one statement's raw parse tree  *  * Parse analysis converts a raw parse tree headed by a RawStmt node into  * an analyzed statement headed by a Query node.  For optimizable statements,  * the conversion is complex.  For utility statements, the parser usually just  * transfers the raw parse tree (sans RawStmt) into the utilityStmt field of  * the Query node, and all the useful work happens at execution time.  *  * stmt_location/stmt_len identify the portion of the source text string  * containing this raw statement (useful for multi-statement strings).  */ typedef struct RawStmt {     NodeTag     type;     Node       *stmt;           /* raw parse tree */     int         stmt_location;  /* start location, or -1 if unknown */     int         stmt_len;       /* length in bytes; 0 means "rest of string" */ } RawStmt;

3、Query

//在解析查询语句时再深入解析/*****************************************************************************  *  Query Tree  *****************************************************************************/  /*  * Query -  *    Parse analysis turns all statements into a Query tree  *    for further processing by the rewriter and planner.  *  *    Utility statements (i.e. non-optimizable statements) have the  *    utilityStmt field set, and the rest of the Query is mostly dummy.  *  *    Planning converts a Query tree into a Plan tree headed by a PlannedStmt  *    node --- the Query structure is not used by the executor.  */ typedef struct Query {     NodeTag     type;      CmdType     commandType;    /* select|insert|update|delete|utility */      QuerySource querySource;    /* where did I come from? */      uint64      queryId;        /* query identifier (can be set by plugins) */      bool        canSetTag;      /* do I set the command result tag? */      Node       *utilityStmt;    /* non-null if commandType == CMD_UTILITY */      int         resultRelation; /* rtable index of target relation for                                  * INSERT/UPDATE/DELETE; 0 for SELECT */      bool        hasAggs;        /* has aggregates in tlist or havingQual */     bool        hasWindowFuncs; /* has window functions in tlist */     bool        hasTargetSRFs;  /* has set-returning functions in tlist */     bool        hasSubLinks;    /* has subquery SubLink */     bool        hasDistinctOn;  /* distinctClause is from DISTINCT ON */     bool        hasRecursive;   /* WITH RECURSIVE was specified */     bool        hasModifyingCTE;    /* has INSERT/UPDATE/DELETE in WITH */     bool        hasForUpdate;   /* FOR [KEY] UPDATE/SHARE was specified */     bool        hasRowSecurity; /* rewriter has applied some RLS policy */      List       *cteList;        /* WITH list (of CommonTableExpr's) */      List       *rtable;         /* list of range table entries */     FromExpr   *jointree;       /* table join tree (FROM and WHERE clauses) */      List       *targetList;     /* target list (of TargetEntry) */      OverridingKind override;    /* OVERRIDING clause */      OnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */      List       *returningList;  /* return-values list (of TargetEntry) */      List       *groupClause;    /* a list of SortGroupClause's */      List       *groupingSets;   /* a list of GroupingSet's if present */      Node       *havingQual;     /* qualifications applied to groups */      List       *windowClause;   /* a list of WindowClause's */      List       *distinctClause; /* a list of SortGroupClause's */      List       *sortClause;     /* a list of SortGroupClause's */      Node       *limitOffset;    /* # of result tuples to skip (int8 expr) */     Node       *limitCount;     /* # of result tuples to return (int8 expr) */      List       *rowMarks;       /* a list of RowMarkClause's */      Node       *setOperations;  /* set-operation tree if this is top level of                                  * a UNION/INTERSECT/EXCEPT query */      List       *constraintDeps; /* a list of pg_constraint OIDs that the query                                  * depends on to be semantically valid */      List       *withCheckOptions;   /* a list of WithCheckOption's, which are                                      * only added during rewrite and therefore                                      * are not written out as part of Query. */      /*      * The following two fields identify the portion of the source text string      * containing this query.  They are typically only populated in top-level      * Queries, not in sub-queries.  When not set, they might both be zero, or      * both be -1 meaning "unknown".      */     int         stmt_location;  /* start location, or -1 if unknown */     int         stmt_len;       /* length in bytes; 0 means "rest of string" */ } Query;

4、ParseState

/*  * Function signatures for parser hooks  */ typedef struct ParseState ParseState;  typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref); typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var); typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref); typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,                                   Oid targetTypeId, int32 targetTypeMod,                                   int location);   /*  * State information used during parse analysis  *  * parentParseState: NULL in a top-level ParseState.  When parsing a subquery,  * links to current parse state of outer query.  *  * p_sourcetext: source string that generated the raw parsetree being  * analyzed, or NULL if not available.  (The string is used only to  * generate cursor positions in error messages: we need it to convert  * byte-wise locations in parse structures to character-wise cursor  * positions.)  *  * p_rtable: list of RTEs that will become the rangetable of the query.  * Note that neither relname nor refname of these entries are necessarily  * unique; searching the rtable by name is a bad idea.  *  * p_joinexprs: list of JoinExpr nodes associated with p_rtable entries.  * This is one-for-one with p_rtable, but contains NULLs for non-join  * RTEs, and may be shorter than p_rtable if the last RTE(s) aren't joins.  *  * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that  * will become the fromlist of the query's top-level FromExpr node.  *  * p_namespace: list of ParseNamespaceItems that represents the current  * namespace for table and column lookup.  (The RTEs listed here may be just  * a subset of the whole rtable.  See ParseNamespaceItem comments below.)  *  * p_lateral_active: true if we are currently parsing a LATERAL subexpression  * of this parse level.  This makes p_lateral_only namespace items visible,  * whereas they are not visible when p_lateral_active is FALSE.  *  * p_ctenamespace: list of CommonTableExprs (WITH items) that are visible  * at the moment.  This is entirely different from p_namespace because a CTE  * is not an RTE, rather "visibility" means you could make an RTE from it.  *  * p_future_ctes: list of CommonTableExprs (WITH items) that are not yet  * visible due to scope rules.  This is used to help improve error messages.  *  * p_parent_cte: CommonTableExpr that immediately contains the current query,  * if any.  *  * p_target_relation: target relation, if query is INSERT, UPDATE, or DELETE.  *  * p_target_rangetblentry: target relation's entry in the rtable list.  *  * p_is_insert: true to process assignment expressions like INSERT, false  * to process them like UPDATE.  (Note this can change intra-statement, for  * cases like INSERT ON CONFLICT UPDATE.)  *  * p_windowdefs: list of WindowDefs representing WINDOW and OVER clauses.  * We collect these while transforming expressions and then transform them  * afterwards (so that any resjunk tlist items needed for the sort/group  * clauses end up at the end of the query tlist).  A WindowDef's location in  * this list, counting from 1, is the winref number to use to reference it.  *  * p_expr_kind: kind of expression we're currently parsing, as per enum above;  * EXPR_KIND_NONE when not in an expression.  *  * p_next_resno: next TargetEntry.resno to assign, starting from 1.  *  * p_multiassign_exprs: partially-processed MultiAssignRef source expressions.  *  * p_locking_clause: query's FOR UPDATE/FOR SHARE clause, if any.  *  * p_locked_from_parent: true if parent query level applies FOR UPDATE/SHARE  * to this subquery as a whole.  *  * p_resolve_unknowns: resolve unknown-type SELECT output columns as type TEXT  * (this is true by default).  *  * p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated  * constructs in the query.  *  * p_last_srf: the set-returning FuncExpr or OpExpr most recently found in  * the query, or NULL if none.  *  * p_pre_columnref_hook, etc: optional parser hook functions for modifying the  * interpretation of ColumnRefs and ParamRefs.  *  * p_ref_hook_state: passthrough state for the parser hook functions.  */ struct ParseState {     struct ParseState *parentParseState;    /* stack link */     const char *p_sourcetext;   /* source text, or NULL if not available */     List       *p_rtable;       /* range table so far */     List       *p_joinexprs;    /* JoinExprs for RTE_JOIN p_rtable entries */     List       *p_joinlist;     /* join items so far (will become FromExpr                                  * node's fromlist) */     List       *p_namespace;    /* currently-referenceable RTEs (List of                                  * ParseNamespaceItem) */     bool        p_lateral_active;   /* p_lateral_only items visible? */     List       *p_ctenamespace; /* current namespace for common table exprs */     List       *p_future_ctes;  /* common table exprs not yet in namespace */     CommonTableExpr *p_parent_cte;  /* this query's containing CTE */     Relation    p_target_relation;  /* INSERT/UPDATE/DELETE target rel */     RangeTblEntry *p_target_rangetblentry;  /* target rel's RTE */     bool        p_is_insert;    /* process assignment like INSERT not UPDATE */     List       *p_windowdefs;   /* raw representations of window clauses */     ParseExprKind p_expr_kind;  /* what kind of expression we're parsing */     int         p_next_resno;   /* next targetlist resno to assign */     List       *p_multiassign_exprs;    /* junk tlist entries for multiassign */     List       *p_locking_clause;   /* raw FOR UPDATE/FOR SHARE info */     bool        p_locked_from_parent;   /* parent has marked this subquery                                          * with FOR UPDATE/FOR SHARE */     bool        p_resolve_unknowns; /* resolve unknown-type SELECT outputs as                                      * type text */      QueryEnvironment *p_queryEnv;   /* curr env, incl refs to enclosing env */      /* Flags telling about things found in the query: */     bool        p_hasAggs;     bool        p_hasWindowFuncs;     bool        p_hasTargetSRFs;     bool        p_hasSubLinks;     bool        p_hasModifyingCTE;      Node       *p_last_srf;     /* most recent set-returning func/op found */      /*      * Optional hook functions for parser callbacks.  These are null unless      * set up by the caller of make_parsestate.      */     PreParseColumnRefHook p_pre_columnref_hook;     PostParseColumnRefHook p_post_columnref_hook;     ParseParamRefHook p_paramref_hook;     CoerceParamHook p_coerce_param_hook;     void       *p_ref_hook_state;   /* common passthrough link for above */ };

5、RangeTblEntry

/*--------------------  * RangeTblEntry -  *    A range table is a List of RangeTblEntry nodes.  *  *    A range table entry may represent a plain relation, a sub-select in  *    FROM, or the result of a JOIN clause.  (Only explicit JOIN syntax  *    produces an RTE, not the implicit join resulting from multiple FROM  *    items.  This is because we only need the RTE to deal with SQL features  *    like outer joins and join-output-column aliasing.)  Other special  *    RTE types also exist, as indicated by RTEKind.  *  *    Note that we consider RTE_RELATION to cover anything that has a pg_class  *    entry.  relkind distinguishes the sub-cases.  *  *    alias is an Alias node representing the AS alias-clause attached to the  *    FROM expression, or NULL if no clause.  *  *    eref is the table reference name and column reference names (either  *    real or aliases).  Note that system columns (OID etc) are not included  *    in the column list.  *    eref->aliasname is required to be present, and should generally be used  *    to identify the RTE for error messages etc.  *  *    In RELATION RTEs, the colnames in both alias and eref are indexed by  *    physical attribute number; this means there must be colname entries for  *    dropped columns.  When building an RTE we insert empty strings ("") for  *    dropped columns.  Note however that a stored rule may have nonempty  *    colnames for columns dropped since the rule was created (and for that  *    matter the colnames might be out of date due to column renamings).  *    The same comments apply to FUNCTION RTEs when a function's return type  *    is a named composite type.  *  *    In JOIN RTEs, the colnames in both alias and eref are one-to-one with  *    joinaliasvars entries.  A JOIN RTE will omit columns of its inputs when  *    those columns are known to be dropped at parse time.  Again, however,  *    a stored rule might contain entries for columns dropped since the rule  *    was created.  (This is only possible for columns not actually referenced  *    in the rule.)  When loading a stored rule, we replace the joinaliasvars  *    items for any such columns with null pointers.  (We can't simply delete  *    them from the joinaliasvars list, because that would affect the attnums  *    of Vars referencing the rest of the list.)  *  *    inh is true for relation references that should be expanded to include  *    inheritance children, if the rel has any.  This *must* be false for  *    RTEs other than RTE_RELATION entries.  *  *    inFromCl marks those range variables that are listed in the FROM clause.  *    It's false for RTEs that are added to a query behind the scenes, such  *    as the NEW and OLD variables for a rule, or the subqueries of a UNION.  *    This flag is not used anymore during parsing, since the parser now uses  *    a separate "namespace" data structure to control visibility, but it is  *    needed by ruleutils.c to determine whether RTEs should be shown in  *    decompiled queries.  *  *    requiredPerms and checkAsUser specify run-time access permissions  *    checks to be performed at query startup.  The user must have *all*  *    of the permissions that are OR'd together in requiredPerms (zero  *    indicates no permissions checking).  If checkAsUser is not zero,  *    then do the permissions checks using the access rights of that user,  *    not the current effective user ID.  (This allows rules to act as  *    setuid gateways.)  Permissions checks only apply to RELATION RTEs.  *  *    For SELECT/INSERT/UPDATE permissions, if the user doesn't have  *    table-wide permissions then it is sufficient to have the permissions  *    on all columns identified in selectedCols (for SELECT) and/or  *    insertedCols and/or updatedCols (INSERT with ON CONFLICT DO UPDATE may  *    have all 3).  selectedCols, insertedCols and updatedCols are bitmapsets,  *    which cannot have negative integer members, so we subtract  *    FirstLowInvalidHeapAttributeNumber from column numbers before storing  *    them in these fields.  A whole-row Var reference is represented by  *    setting the bit for InvalidAttrNumber.  *  *    securityQuals is a list of security barrier quals (boolean expressions),  *    to be tested in the listed order before returning a row from the  *    relation.  It is always NIL in parser output.  Entries are added by the  *    rewriter to implement security-barrier views and/or row-level security.  *    Note that the planner turns each boolean expression into an implicitly  *    AND'ed sublist, as is its usual habit with qualification expressions.  *--------------------  */ typedef enum RTEKind {     RTE_RELATION,               /* ordinary relation reference */     RTE_SUBQUERY,               /* subquery in FROM */     RTE_JOIN,                   /* join */     RTE_FUNCTION,               /* function in FROM */     RTE_TABLEFUNC,              /* TableFunc(.., column list) */     RTE_VALUES,                 /* VALUES (
), (
), ... */ RTE_CTE, /* common table expr (WITH list element) */ RTE_NAMEDTUPLESTORE /* tuplestore, e.g. for AFTER triggers */ } RTEKind; typedef struct RangeTblEntry { NodeTag type; RTEKind rtekind; /* see above */ /* * XXX the fields applicable to only some rte kinds should be merged into * a union. I didn't do this yet because the diffs would impact a lot of * code that is being actively worked on. FIXME someday. */ /* * Fields valid for a plain relation RTE (else zero): * * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate * that the tuple format of the tuplestore is the same as the referenced * relation. This allows plans referencing AFTER trigger transition * tables to be invalidated if the underlying table is altered. */ Oid relid; /* OID of the relation */ char relkind; /* relation kind (see pg_class.relkind) */ struct TableSampleClause *tablesample; /* sampling info, or NULL */ /* * Fields valid for a subquery RTE (else NULL): */ Query *subquery; /* the sub-query */ bool security_barrier; /* is from security_barrier view? */ /* * Fields valid for a join RTE (else NULL/zero): * * joinaliasvars is a list of (usually) Vars corresponding to the columns * of the join result. An alias Var referencing column K of the join * result can be replaced by the K'th element of joinaliasvars --- but to * simplify the task of reverse-listing aliases correctly, we do not do * that until planning time. In detail: an element of joinaliasvars can * be a Var of one of the join's input relations, or such a Var with an * implicit coercion to the join's output column type, or a COALESCE * expression containing the two input column Vars (possibly coerced). * Within a Query loaded from a stored rule, it is also possible for * joinaliasvars items to be null pointers, which are placeholders for * (necessarily unreferenced) columns dropped since the rule was made. * Also, once planning begins, joinaliasvars items can be almost anything, * as a result of subquery-flattening substitutions. */ JoinType jointype; /* type of join */ List *joinaliasvars; /* list of alias-var expansions */ /* * Fields valid for a function RTE (else NIL/zero): * * When funcordinality is true, the eref->colnames list includes an alias * for the ordinality column. The ordinality column is otherwise * implicit, and must be accounted for "by hand" in places such as * expandRTE(). */ List *functions; /* list of RangeTblFunction nodes */ bool funcordinality; /* is this called WITH ORDINALITY? */ /* * Fields valid for a TableFunc RTE (else NULL): */ TableFunc *tablefunc; /* * Fields valid for a values RTE (else NIL): */ List *values_lists; /* list of expression lists */ /* * Fields valid for a CTE RTE (else NULL/zero): */ char *ctename; /* name of the WITH list item */ Index ctelevelsup; /* number of query levels up */ bool self_reference; /* is this a recursive self-reference? */ /* * Fields valid for table functions, values, CTE and ENR RTEs (else NIL): * * We need these for CTE RTEs so that the types of self-referential * columns are well-defined. For VALUES RTEs, storing these explicitly * saves having to re-determine the info by scanning the values_lists. For * ENRs, we store the types explicitly here (we could get the information * from the catalogs if 'relid' was supplied, but we'd still need these * for TupleDesc-based ENRs, so we might as well always store the type * info here). * * For ENRs only, we have to consider the possibility of dropped columns. * A dropped column is included in these lists, but it will have zeroes in * all three lists (as well as an empty-string entry in eref). Testing * for zero coltype is the standard way to detect a dropped column. */ List *coltypes; /* OID list of column type OIDs */ List *coltypmods; /* integer list of column typmods */ List *colcollations; /* OID list of column collation OIDs */ /* * Fields valid for ENR RTEs (else NULL/zero): */ char *enrname; /* name of ephemeral named relation */ double enrtuples; /* estimated or actual from caller */ /* * Fields valid in all RTEs: */ Alias *alias; /* user-written alias clause, if any */ Alias *eref; /* expanded reference names */ bool lateral; /* subquery, function, or values is LATERAL? */ bool inh; /* inheritance requested? */ bool inFromCl; /* present in FROM clause? */ AclMode requiredPerms; /* bitmask of required access permissions */ Oid checkAsUser; /* if valid, check access as this role */ Bitmapset *selectedCols; /* columns needing SELECT permission */ Bitmapset *insertedCols; /* columns needing INSERT permission */ Bitmapset *updatedCols; /* columns needing UPDATE permission */ List *securityQuals; /* security barrier quals to apply, if any */ } RangeTblEntry;

6、TargetEntry

/*--------------------  * TargetEntry -  *     a target entry (used in query target lists)  *  * Strictly speaking, a TargetEntry isn't an expression node (since it can't  * be evaluated by ExecEvalExpr).  But we treat it as one anyway, since in  * very many places it's convenient to process a whole query targetlist as a  * single expression tree.  *  * In a SELECT's targetlist, resno should always be equal to the item's  * ordinal position (counting from 1).  However, in an INSERT or UPDATE  * targetlist, resno represents the attribute number of the destination  * column for the item; so there may be missing or out-of-order resnos.  * It is even legal to have duplicated resnos; consider  *      UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ...  * The two meanings come together in the executor, because the planner  * transforms INSERT/UPDATE tlists into a normalized form with exactly  * one entry for each column of the destination table.  Before that's  * happened, however, it is risky to assume that resno == position.  * Generally get_tle_by_resno() should be used rather than list_nth()  * to fetch tlist entries by resno, and only in SELECT should you assume  * that resno is a unique identifier.  *  * resname is required to represent the correct column name in non-resjunk  * entries of top-level SELECT targetlists, since it will be used as the  * column title sent to the frontend.  In most other contexts it is only  * a debugging aid, and may be wrong or even NULL.  (In particular, it may  * be wrong in a tlist from a stored rule, if the referenced column has been  * renamed by ALTER TABLE since the rule was made.  Also, the planner tends  * to store NULL rather than look up a valid name for tlist entries in  * non-toplevel plan nodes.)  In resjunk entries, resname should be either  * a specific system-generated name (such as "ctid") or NULL; anything else  * risks confusing ExecGetJunkAttribute!  *  * ressortgroupref is used in the representation of ORDER BY, GROUP BY, and  * DISTINCT items.  Targetlist entries with ressortgroupref=0 are not  * sort/group items.  If ressortgroupref>0, then this item is an ORDER BY,  * GROUP BY, and/or DISTINCT target value.  No two entries in a targetlist  * may have the same nonzero ressortgroupref --- but there is no particular  * meaning to the nonzero values, except as tags.  (For example, one must  * not assume that lower ressortgroupref means a more significant sort key.)  * The order of the associated SortGroupClause lists determine the semantics.  *  * resorigtbl/resorigcol identify the source of the column, if it is a  * simple reference to a column of a base table (or view).  If it is not  * a simple reference, these fields are zeroes.  *  * If resjunk is true then the column is a working column (such as a sort key)  * that should be removed from the final output of the query.  Resjunk columns  * must have resnos that cannot duplicate any regular column's resno.  Also  * note that there are places that assume resjunk columns come after non-junk  * columns.  *--------------------  */ typedef struct TargetEntry {     Expr        xpr;     Expr       *expr;           /* expression to evaluate */     AttrNumber  resno;          /* attribute number (see notes above) */     char       *resname;        /* name of the column (could be NULL) */     Index       ressortgroupref;    /* nonzero if referenced by a sort/group                                      * clause */     Oid         resorigtbl;     /* OID of column's source table */     AttrNumber  resorigcol;     /* column's number in source table */     bool        resjunk;        /* set to true to eliminate the attribute from                                  * final target list */ } TargetEntry;

7、全局变量定义

bool        log_parser_stats = false; bool        log_planner_stats = false; bool        log_executor_stats = false; bool        log_statement_stats = false;    /* this is sort of all three above                                              * together */

依赖的函数

1、start_xact_command

/*  * Convenience routines for starting/committing a single command.  */ static void start_xact_command(void) {     if (!xact_started)     {         StartTransactionCommand();//开启事务          xact_started = true;     }      /*      * Start statement timeout if necessary.  Note that this'll intentionally      * not reset the clock on an already started timeout, to avoid the timing      * overhead when start_xact_command() is invoked repeatedly, without an      * interceding finish_xact_command() (e.g. parse/bind/execute).  If that's      * not desired, the timeout has to be disabled explicitly.      */     enable_statement_timeout(); } /*  *  StartTransactionCommand  */ void StartTransactionCommand(void) {     TransactionState s = CurrentTransactionState;      switch (s->blockState)     {             /*              * if we aren't in a transaction block, we just do our usual start              * transaction.              */         case TBLOCK_DEFAULT:             StartTransaction();             s->blockState = TBLOCK_STARTED;             break;              /*              * We are somewhere in a transaction block or subtransaction and              * about to start a new command.  For now we do nothing, but              * someday we may do command-local resource initialization. (Note              * that any needed CommandCounterIncrement was done by the              * previous CommitTransactionCommand.)              */         case TBLOCK_INPROGRESS:         case TBLOCK_IMPLICIT_INPROGRESS:         case TBLOCK_SUBINPROGRESS:             break;              /*              * Here we are in a failed transaction block (one of the commands              * caused an abort) so we do nothing but remain in the abort              * state.  Eventually we will get a ROLLBACK command which will              * get us out of this state.  (It is up to other code to ensure              * that no commands other than ROLLBACK will be processed in these              * states.)              */         case TBLOCK_ABORT:         case TBLOCK_SUBABORT:             break;              /* These cases are invalid. */         case TBLOCK_STARTED:         case TBLOCK_BEGIN:         case TBLOCK_PARALLEL_INPROGRESS:         case TBLOCK_SUBBEGIN:         case TBLOCK_END:         case TBLOCK_SUBRELEASE:         case TBLOCK_SUBCOMMIT:         case TBLOCK_ABORT_END:         case TBLOCK_SUBABORT_END:         case TBLOCK_ABORT_PENDING:         case TBLOCK_SUBABORT_PENDING:         case TBLOCK_SUBRESTART:         case TBLOCK_SUBABORT_RESTART:         case TBLOCK_PREPARE:             elog(ERROR, "StartTransactionCommand: unexpected state %s",                  BlockStateAsString(s->blockState));             break;     }      /*      * We must switch to CurTransactionContext before returning. This is      * already done if we called StartTransaction, otherwise not.      */     Assert(CurTransactionContext != NULL);     MemoryContextSwitchTo(CurTransactionContext);//内存上下文切换至当前事务上下文 }

2、drop_unnamed_stmt

/* Release any existing unnamed prepared statement */ static void drop_unnamed_stmt(void) {     /* paranoia to avoid a dangling pointer in case of error */     if (unnamed_stmt_psrc)     {         CachedPlanSource *psrc = unnamed_stmt_psrc;          unnamed_stmt_psrc = NULL;         DropCachedPlan(psrc);     } } /*  * If an unnamed prepared statement exists, it's stored here.  * We keep it separate from the hashtable kept by commands/prepare.c  * in order to reduce overhead for short-lived queries.  */ static CachedPlanSource *unnamed_stmt_psrc = NULL;

3、pg_parse_query

//执行语句解析,返回RawStmt  nodes(List) /*  * Do raw parsing (only).  *  * A list of parsetrees (RawStmt nodes) is returned, since there might be  * multiple commands in the given string.  *  * NOTE: for interactive queries, it is important to keep this routine  * separate from the analysis & rewrite stages.  Analysis and rewriting  * cannot be done in an aborted transaction, since they require access to  * database tables.  So, we rely on the raw parser to determine whether  * we've seen a COMMIT or ABORT command; when we are in abort state, other  * commands are not processed any further than the raw parse stage.  */ List * pg_parse_query(const char *query_string) {     List       *raw_parsetree_list;      TRACE_POSTGRESQL_QUERY_PARSE_START(query_string);      if (log_parser_stats)         ResetUsage();      raw_parsetree_list = raw_parser(query_string);      if (log_parser_stats)         ShowUsage("PARSER STATISTICS");  #ifdef COPY_PARSE_PLAN_TREES     /* Optional debugging check: pass raw parsetrees through copyObject() */     {         List       *new_list = copyObject(raw_parsetree_list);          /* This checks both copyObject() and the equal() routines... */         if (!equal(new_list, raw_parsetree_list))             elog(WARNING, "copyObject() failed to produce an equal raw parse tree");         else             raw_parsetree_list = new_list;     } #endif      TRACE_POSTGRESQL_QUERY_PARSE_DONE(query_string);      return raw_parsetree_list; }

4、raw_parser

//执行词法和语法分析,返回raw parse trees(List,其中的元素是RawStmt) /*  * raw_parser  *      Given a query in string form, do lexical and grammatical analysis.  *  * Returns a list of raw (un-analyzed) parse trees.  The immediate elements  * of the list are always RawStmt nodes.  */ List * raw_parser(const char *str) {     core_yyscan_t yyscanner;     base_yy_extra_type yyextra;     int         yyresult;      /* initialize the flex scanner */     yyscanner = scanner_init(str, &yyextra.core_yy_extra,                              ScanKeywords, NumScanKeywords);      /* base_yylex() only needs this much initialization */     yyextra.have_lookahead = false;      /* initialize the bison parser */     parser_init(&yyextra);      /* Parse! */     yyresult = base_yyparse(yyscanner);      /* Clean up (release memory) */     scanner_finish(yyscanner);      if (yyresult)               /* error */         return NIL;      return yyextra.parsetree; }

5、CreateCommandTag

//创建命令Tag//基本上,所有的PG命令类型都可以在这里找到 /*  * CreateCommandTag  *      utility to get a string representation of the command operation,  *      given either a raw (un-analyzed) parsetree, an analyzed Query,  *      or a PlannedStmt.  *  * This must handle all command types, but since the vast majority  * of 'em are utility commands, it seems sensible to keep it here.  *  * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.  * Also, the result must point at a true constant (permanent storage).  */ const char * CreateCommandTag(Node *parsetree) {     const char *tag;      switch (nodeTag(parsetree))     {             /* recurse if we're given a RawStmt */         case T_RawStmt:             tag = CreateCommandTag(((RawStmt *) parsetree)->stmt);             break;              /* raw plannable queries */         case T_InsertStmt:             tag = "INSERT";             break;          case T_DeleteStmt:             tag = "DELETE";             break;          case T_UpdateStmt:             tag = "UPDATE";             break;          case T_SelectStmt:             tag = "SELECT";             break;              /* utility statements --- same whether raw or cooked */         case T_TransactionStmt:             {                 TransactionStmt *stmt = (TransactionStmt *) parsetree;                  switch (stmt->kind)                 {                     case TRANS_STMT_BEGIN:                         tag = "BEGIN";                         break;                      case TRANS_STMT_START:                         tag = "START TRANSACTION";                         break;                      case TRANS_STMT_COMMIT:                         tag = "COMMIT";                         break;                      case TRANS_STMT_ROLLBACK:                     case TRANS_STMT_ROLLBACK_TO:                         tag = "ROLLBACK";                         break;                      case TRANS_STMT_SAVEPOINT:                         tag = "SAVEPOINT";                         break;                      case TRANS_STMT_RELEASE:                         tag = "RELEASE";                         break;                      case TRANS_STMT_PREPARE:                         tag = "PREPARE TRANSACTION";                         break;                      case TRANS_STMT_COMMIT_PREPARED:                         tag = "COMMIT PREPARED";                         break;                      case TRANS_STMT_ROLLBACK_PREPARED:                         tag = "ROLLBACK PREPARED";                         break;                      default:                         tag = "???";                         break;                 }             }             break;          case T_DeclareCursorStmt:             tag = "DECLARE CURSOR";             break;          case T_ClosePortalStmt:             {                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;                  if (stmt->portalname == NULL)                     tag = "CLOSE CURSOR ALL";                 else                     tag = "CLOSE CURSOR";             }             break;          case T_FetchStmt:             {                 FetchStmt  *stmt = (FetchStmt *) parsetree;                  tag = (stmt->ismove) ? "MOVE" : "FETCH";             }             break;          case T_CreateDomainStmt:             tag = "CREATE DOMAIN";             break;          case T_CreateSchemaStmt:             tag = "CREATE SCHEMA";             break;          case T_CreateStmt:             tag = "CREATE TABLE";             break;          case T_CreateTableSpaceStmt:             tag = "CREATE TABLESPACE";             break;          case T_DropTableSpaceStmt:             tag = "DROP TABLESPACE";             break;          case T_AlterTableSpaceOptionsStmt:             tag = "ALTER TABLESPACE";             break;          case T_CreateExtensionStmt:             tag = "CREATE EXTENSION";             break;          case T_AlterExtensionStmt:             tag = "ALTER EXTENSION";             break;          case T_AlterExtensionContentsStmt:             tag = "ALTER EXTENSION";             break;          case T_CreateFdwStmt:             tag = "CREATE FOREIGN DATA WRAPPER";             break;          case T_AlterFdwStmt:             tag = "ALTER FOREIGN DATA WRAPPER";             break;          case T_CreateForeignServerStmt:             tag = "CREATE SERVER";             break;          case T_AlterForeignServerStmt:             tag = "ALTER SERVER";             break;          case T_CreateUserMappingStmt:             tag = "CREATE USER MAPPING";             break;          case T_AlterUserMappingStmt:             tag = "ALTER USER MAPPING";             break;          case T_DropUserMappingStmt:             tag = "DROP USER MAPPING";             break;          case T_CreateForeignTableStmt:             tag = "CREATE FOREIGN TABLE";             break;          case T_ImportForeignSchemaStmt:             tag = "IMPORT FOREIGN SCHEMA";             break;          case T_DropStmt:             switch (((DropStmt *) parsetree)->removeType)             {                 case OBJECT_TABLE:                     tag = "DROP TABLE";                     break;                 case OBJECT_SEQUENCE:                     tag = "DROP SEQUENCE";                     break;                 case OBJECT_VIEW:                     tag = "DROP VIEW";                     break;                 case OBJECT_MATVIEW:                     tag = "DROP MATERIALIZED VIEW";                     break;                 case OBJECT_INDEX:                     tag = "DROP INDEX";                     break;                 case OBJECT_TYPE:                     tag = "DROP TYPE";                     break;                 case OBJECT_DOMAIN:                     tag = "DROP DOMAIN";                     break;                 case OBJECT_COLLATION:                     tag = "DROP COLLATION";                     break;                 case OBJECT_CONVERSION:                     tag = "DROP CONVERSION";                     break;                 case OBJECT_SCHEMA:                     tag = "DROP SCHEMA";                     break;                 case OBJECT_TSPARSER:                     tag = "DROP TEXT SEARCH PARSER";                     break;                 case OBJECT_TSDICTIONARY:                     tag = "DROP TEXT SEARCH DICTIONARY";                     break;                 case OBJECT_TSTEMPLATE:                     tag = "DROP TEXT SEARCH TEMPLATE";                     break;                 case OBJECT_TSCONFIGURATION:                     tag = "DROP TEXT SEARCH CONFIGURATION";                     break;                 case OBJECT_FOREIGN_TABLE:                     tag = "DROP FOREIGN TABLE";                     break;                 case OBJECT_EXTENSION:                     tag = "DROP EXTENSION";                     break;                 case OBJECT_FUNCTION:                     tag = "DROP FUNCTION";                     break;                 case OBJECT_PROCEDURE:                     tag = "DROP PROCEDURE";                     break;                 case OBJECT_ROUTINE:                     tag = "DROP ROUTINE";                     break;                 case OBJECT_AGGREGATE:                     tag = "DROP AGGREGATE";                     break;                 case OBJECT_OPERATOR:                     tag = "DROP OPERATOR";                     break;                 case OBJECT_LANGUAGE:                     tag = "DROP LANGUAGE";                     break;                 case OBJECT_CAST:                     tag = "DROP CAST";                     break;                 case OBJECT_TRIGGER:                     tag = "DROP TRIGGER";                     break;                 case OBJECT_EVENT_TRIGGER:                     tag = "DROP EVENT TRIGGER";                     break;                 case OBJECT_RULE:                     tag = "DROP RULE";                     break;                 case OBJECT_FDW:                     tag = "DROP FOREIGN DATA WRAPPER";                     break;                 case OBJECT_FOREIGN_SERVER:                     tag = "DROP SERVER";                     break;                 case OBJECT_OPCLASS:                     tag = "DROP OPERATOR CLASS";                     break;                 case OBJECT_OPFAMILY:                     tag = "DROP OPERATOR FAMILY";                     break;                 case OBJECT_POLICY:                     tag = "DROP POLICY";                     break;                 case OBJECT_TRANSFORM:                     tag = "DROP TRANSFORM";                     break;                 case OBJECT_ACCESS_METHOD:                     tag = "DROP ACCESS METHOD";                     break;                 case OBJECT_PUBLICATION:                     tag = "DROP PUBLICATION";                     break;                 case OBJECT_STATISTIC_EXT:                     tag = "DROP STATISTICS";                     break;                 default:                     tag = "???";             }             break;          case T_TruncateStmt:             tag = "TRUNCATE TABLE";             break;          case T_CommentStmt:             tag = "COMMENT";             break;          case T_SecLabelStmt:             tag = "SECURITY LABEL";             break;          case T_CopyStmt:             tag = "COPY";             break;          case T_RenameStmt:             tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);             break;          case T_AlterObjectDependsStmt:             tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);             break;          case T_AlterObjectSchemaStmt:             tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);             break;          case T_AlterOwnerStmt:             tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);             break;          case T_AlterTableMoveAllStmt:             tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);             break;          case T_AlterTableStmt:             tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);             break;          case T_AlterDomainStmt:             tag = "ALTER DOMAIN";             break;          case T_AlterFunctionStmt:             switch (((AlterFunctionStmt *) parsetree)->objtype)             {                 case OBJECT_FUNCTION:                     tag = "ALTER FUNCTION";                     break;                 case OBJECT_PROCEDURE:                     tag = "ALTER PROCEDURE";                     break;                 case OBJECT_ROUTINE:                     tag = "ALTER ROUTINE";                     break;                 default:                     tag = "???";             }             break;          case T_GrantStmt:             {                 GrantStmt  *stmt = (GrantStmt *) parsetree;                  tag = (stmt->is_grant) ? "GRANT" : "REVOKE";             }             break;          case T_GrantRoleStmt:             {                 GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;                  tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";             }             break;          case T_AlterDefaultPrivilegesStmt:             tag = "ALTER DEFAULT PRIVILEGES";             break;          case T_DefineStmt:             switch (((DefineStmt *) parsetree)->kind)             {                 case OBJECT_AGGREGATE:                     tag = "CREATE AGGREGATE";                     break;                 case OBJECT_OPERATOR:                     tag = "CREATE OPERATOR";                     break;                 case OBJECT_TYPE:                     tag = "CREATE TYPE";                     break;                 case OBJECT_TSPARSER:                     tag = "CREATE TEXT SEARCH PARSER";                     break;                 case OBJECT_TSDICTIONARY:                     tag = "CREATE TEXT SEARCH DICTIONARY";                     break;                 case OBJECT_TSTEMPLATE:                     tag = "CREATE TEXT SEARCH TEMPLATE";                     break;                 case OBJECT_TSCONFIGURATION:                     tag = "CREATE TEXT SEARCH CONFIGURATION";                     break;                 case OBJECT_COLLATION:                     tag = "CREATE COLLATION";                     break;                 case OBJECT_ACCESS_METHOD:                     tag = "CREATE ACCESS METHOD";                     break;                 default:                     tag = "???";             }             break;          case T_CompositeTypeStmt:             tag = "CREATE TYPE";             break;          case T_CreateEnumStmt:             tag = "CREATE TYPE";             break;          case T_CreateRangeStmt:             tag = "CREATE TYPE";             break;          case T_AlterEnumStmt:             tag = "ALTER TYPE";             break;          case T_ViewStmt:             tag = "CREATE VIEW";             break;          case T_CreateFunctionStmt:             if (((CreateFunctionStmt *) parsetree)->is_procedure)                 tag = "CREATE PROCEDURE";             else                 tag = "CREATE FUNCTION";             break;          case T_IndexStmt:             tag = "CREATE INDEX";             break;          case T_RuleStmt:             tag = "CREATE RULE";             break;          case T_CreateSeqStmt:             tag = "CREATE SEQUENCE";             break;          case T_AlterSeqStmt:             tag = "ALTER SEQUENCE";             break;          case T_DoStmt:             tag = "DO";             break;          case T_CreatedbStmt:             tag = "CREATE DATABASE";             break;          case T_AlterDatabaseStmt:             tag = "ALTER DATABASE";             break;          case T_AlterDatabaseSetStmt:             tag = "ALTER DATABASE";             break;          case T_DropdbStmt:             tag = "DROP DATABASE";             break;          case T_NotifyStmt:             tag = "NOTIFY";             break;          case T_ListenStmt:             tag = "LISTEN";             break;          case T_UnlistenStmt:             tag = "UNLISTEN";             break;          case T_LoadStmt:             tag = "LOAD";             break;          case T_CallStmt:             tag = "CALL";             break;          case T_ClusterStmt:             tag = "CLUSTER";             break;          case T_VacuumStmt:             if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM)                 tag = "VACUUM";             else                 tag = "ANALYZE";             break;          case T_ExplainStmt:             tag = "EXPLAIN";             break;          case T_CreateTableAsStmt:             switch (((CreateTableAsStmt *) parsetree)->relkind)             {                 case OBJECT_TABLE:                     if (((CreateTableAsStmt *) parsetree)->is_select_into)                         tag = "SELECT INTO";                     else                         tag = "CREATE TABLE AS";                     break;                 case OBJECT_MATVIEW:                     tag = "CREATE MATERIALIZED VIEW";                     break;                 default:                     tag = "???";             }             break;          case T_RefreshMatViewStmt:             tag = "REFRESH MATERIALIZED VIEW";             break;          case T_AlterSystemStmt:             tag = "ALTER SYSTEM";             break;          case T_VariableSetStmt:             switch (((VariableSetStmt *) parsetree)->kind)             {                 case VAR_SET_VALUE:                 case VAR_SET_CURRENT:                 case VAR_SET_DEFAULT:                 case VAR_SET_MULTI:                     tag = "SET";                     break;                 case VAR_RESET:                 case VAR_RESET_ALL:                     tag = "RESET";                     break;                 default:                     tag = "???";             }             break;          case T_VariableShowStmt:             tag = "SHOW";             break;          case T_DiscardStmt:             switch (((DiscardStmt *) parsetree)->target)             {                 case DISCARD_ALL:                     tag = "DISCARD ALL";                     break;                 case DISCARD_PLANS:                     tag = "DISCARD PLANS";                     break;                 case DISCARD_TEMP:                     tag = "DISCARD TEMP";                     break;                 case DISCARD_SEQUENCES:                     tag = "DISCARD SEQUENCES";                     break;                 default:                     tag = "???";             }             break;          case T_CreateTransformStmt:             tag = "CREATE TRANSFORM";             break;          case T_CreateTrigStmt:             tag = "CREATE TRIGGER";             break;          case T_CreateEventTrigStmt:             tag = "CREATE EVENT TRIGGER";             break;          case T_AlterEventTrigStmt:             tag = "ALTER EVENT TRIGGER";             break;          case T_CreatePLangStmt:             tag = "CREATE LANGUAGE";             break;          case T_CreateRoleStmt:             tag = "CREATE ROLE";             break;          case T_AlterRoleStmt:             tag = "ALTER ROLE";             break;          case T_AlterRoleSetStmt:             tag = "ALTER ROLE";             break;          case T_DropRoleStmt:             tag = "DROP ROLE";             break;          case T_DropOwnedStmt:             tag = "DROP OWNED";             break;          case T_ReassignOwnedStmt:             tag = "REASSIGN OWNED";             break;          case T_LockStmt:             tag = "LOCK TABLE";             break;          case T_ConstraintsSetStmt:             tag = "SET CONSTRAINTS";             break;          case T_CheckPointStmt:             tag = "CHECKPOINT";             break;          case T_ReindexStmt:             tag = "REINDEX";             break;          case T_CreateConversionStmt:             tag = "CREATE CONVERSION";             break;          case T_CreateCastStmt:             tag = "CREATE CAST";             break;          case T_CreateOpClassStmt:             tag = "CREATE OPERATOR CLASS";             break;          case T_CreateOpFamilyStmt:             tag = "CREATE OPERATOR FAMILY";             break;          case T_AlterOpFamilyStmt:             tag = "ALTER OPERATOR FAMILY";             break;          case T_AlterOperatorStmt:             tag = "ALTER OPERATOR";             break;          case T_AlterTSDictionaryStmt:             tag = "ALTER TEXT SEARCH DICTIONARY";             break;          case T_AlterTSConfigurationStmt:             tag = "ALTER TEXT SEARCH CONFIGURATION";             break;          case T_CreatePolicyStmt:             tag = "CREATE POLICY";             break;          case T_AlterPolicyStmt:             tag = "ALTER POLICY";             break;          case T_CreateAmStmt:             tag = "CREATE ACCESS METHOD";             break;          case T_CreatePublicationStmt:             tag = "CREATE PUBLICATION";             break;          case T_AlterPublicationStmt:             tag = "ALTER PUBLICATION";             break;          case T_CreateSubscriptionStmt:             tag = "CREATE SUBSCRIPTION";             break;          case T_AlterSubscriptionStmt:             tag = "ALTER SUBSCRIPTION";             break;          case T_DropSubscriptionStmt:             tag = "DROP SUBSCRIPTION";             break;          case T_AlterCollationStmt:             tag = "ALTER COLLATION";             break;          case T_PrepareStmt:             tag = "PREPARE";             break;          case T_ExecuteStmt:             tag = "EXECUTE";             break;          case T_CreateStatsStmt:             tag = "CREATE STATISTICS";             break;          case T_DeallocateStmt:             {                 DeallocateStmt *stmt = (DeallocateStmt *) parsetree;                  if (stmt->name == NULL)                     tag = "DEALLOCATE ALL";                 else                     tag = "DEALLOCATE";             }             break;              /* already-planned queries */         case T_PlannedStmt:             {                 PlannedStmt *stmt = (PlannedStmt *) parsetree;                  switch (stmt->commandType)                 {                     case CMD_SELECT:                          /*                          * We take a little extra care here so that the result                          * will be useful for complaints about read-only                          * statements                          */                         if (stmt->rowMarks != NIL)                         {                             /* not 100% but probably close enough */                             switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)                             {                                 case LCS_FORKEYSHARE:                                     tag = "SELECT FOR KEY SHARE";                                     break;                                 case LCS_FORSHARE:                                     tag = "SELECT FOR SHARE";                                     break;                                 case LCS_FORNOKEYUPDATE:                                     tag = "SELECT FOR NO KEY UPDATE";                                     break;                                 case LCS_FORUPDATE:                                     tag = "SELECT FOR UPDATE";                                     break;                                 default:                                     tag = "SELECT";                                     break;                             }                         }                         else                             tag = "SELECT";                         break;                     case CMD_UPDATE:                         tag = "UPDATE";                         break;                     case CMD_INSERT:                         tag = "INSERT";                         break;                     case CMD_DELETE:                         tag = "DELETE";                         break;                     case CMD_UTILITY:                         tag = CreateCommandTag(stmt->utilityStmt);                         break;                     default:                         elog(WARNING, "unrecognized commandType: %d",                              (int) stmt->commandType);                         tag = "???";                         break;                 }             }             break;              /* parsed-and-rewritten-but-not-planned queries */         case T_Query:             {                 Query      *stmt = (Query *) parsetree;                  switch (stmt->commandType)                 {                     case CMD_SELECT:                          /*                          * We take a little extra care here so that the result                          * will be useful for complaints about read-only                          * statements                          */                         if (stmt->rowMarks != NIL)                         {                             /* not 100% but probably close enough */                             switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)                             {                                 case LCS_FORKEYSHARE:                                     tag = "SELECT FOR KEY SHARE";                                     break;                                 case LCS_FORSHARE:                                     tag = "SELECT FOR SHARE";                                     break;                                 case LCS_FORNOKEYUPDATE:                                     tag = "SELECT FOR NO KEY UPDATE";                                     break;                                 case LCS_FORUPDATE:                                     tag = "SELECT FOR UPDATE";                                     break;                                 default:                                     tag = "???";                                     break;                             }                         }                         else                             tag = "SELECT";                         break;                     case CMD_UPDATE:                         tag = "UPDATE";                         break;                     case CMD_INSERT:                         tag = "INSERT";                         break;                     case CMD_DELETE:                         tag = "DELETE";                         break;                     case CMD_UTILITY:                         tag = CreateCommandTag(stmt->utilityStmt);                         break;                     default:                         elog(WARNING, "unrecognized commandType: %d",                              (int) stmt->commandType);                         tag = "???";                         break;                 }             }             break;          default:             elog(WARNING, "unrecognized node type: %d",                  (int) nodeTag(parsetree));             tag = "???";             break;     }      return tag; }

6、BeginCommand

/* ----------------  *      BeginCommand - initialize the destination at start of command  * ----------------  */ void BeginCommand(const char *commandTag, CommandDest dest) {     /* Nothing to do at present */ }

7、analyze_requires_snapshot

//是否需要快照?//增删改查均需要 /*  * analyze_requires_snapshot  *      Returns true if a snapshot must be set before doing parse analysis  *      on the given raw parse tree.  *  * Classification here should match transformStmt().  */ bool analyze_requires_snapshot(RawStmt *parseTree) {     bool        result;      switch (nodeTag(parseTree->stmt))     {             /*              * Optimizable statements              */         case T_InsertStmt:         case T_DeleteStmt:         case T_UpdateStmt:         case T_SelectStmt:             result = true;             break;              /*              * Special cases              */         case T_DeclareCursorStmt:         case T_ExplainStmt:         case T_CreateTableAsStmt:             /* yes, because we must analyze the contained statement */             result = true;             break;          default:             /* other utility statements don't have any real parse analysis */             result = false;             break;     }      return result; }

8、pg_analyze_and_rewrite

/*  * Given a raw parsetree (gram.y output), and optionally information about  * types of parameter symbols ($n), perform parse analysis and rule rewriting.  *  * A list of Query nodes is returned, since either the analyzer or the  * rewriter might expand one query to several.  *  * NOTE: for reasons mentioned above, this must be separate from raw parsing.  */ List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string,                        Oid *paramTypes, int numParams,                        QueryEnvironment *queryEnv) {     Query      *query;     List       *querytree_list;      TRACE_POSTGRESQL_QUERY_REWRITE_START(query_string);      /*      * (1) Perform parse analysis.      */     if (log_parser_stats)         ResetUsage();      query = parse_analyze(parsetree, query_string, paramTypes, numParams,                           queryEnv);//解析&分析      if (log_parser_stats)         ShowUsage("PARSE ANALYSIS STATISTICS");      /*      * (2) Rewrite the queries, as necessary      */     querytree_list = pg_rewrite_query(query);//查询重写      TRACE_POSTGRESQL_QUERY_REWRITE_DONE(query_string);      return querytree_list; }  /*  * parse_analyze  *      Analyze a raw parse tree and transform it to Query form.  *  * Optionally, information about $n parameter types can be supplied.  * References to $n indexes not defined by paramTypes[] are disallowed.  *  * The result is a Query node.  Optimizable statements require considerable  * transformation, while utility-type statements are simply hung off  * a dummy CMD_UTILITY Query node.  */ Query * parse_analyze(RawStmt *parseTree, const char *sourceText,               Oid *paramTypes, int numParams,               QueryEnvironment *queryEnv) {     ParseState *pstate = make_parsestate(NULL);     Query      *query;      Assert(sourceText != NULL); /* required as of 8.4 */      pstate->p_sourcetext = sourceText;      if (numParams > 0)         parse_fixed_parameters(pstate, paramTypes, numParams);      pstate->p_queryEnv = queryEnv;      query = transformTopLevelStmt(pstate, parseTree);      if (post_parse_analyze_hook)         (*post_parse_analyze_hook) (pstate, query);      free_parsestate(pstate);      return query; } /*  * make_parsestate  *      Allocate and initialize a new ParseState.  *  * Caller should eventually release the ParseState via free_parsestate().  */ ParseState * make_parsestate(ParseState *parentParseState) {     ParseState *pstate;      pstate = palloc0(sizeof(ParseState));      pstate->parentParseState = parentParseState;      /* Fill in fields that don't start at null/false/zero */     pstate->p_next_resno = 1;     pstate->p_resolve_unknowns = true;      if (parentParseState)     {         pstate->p_sourcetext = parentParseState->p_sourcetext;         /* all hooks are copied from parent */         pstate->p_pre_columnref_hook = parentParseState->p_pre_columnref_hook;         pstate->p_post_columnref_hook = parentParseState->p_post_columnref_hook;         pstate->p_paramref_hook = parentParseState->p_paramref_hook;         pstate->p_coerce_param_hook = parentParseState->p_coerce_param_hook;         pstate->p_ref_hook_state = parentParseState->p_ref_hook_state;         /* query environment stays in context for the whole parse analysis */         pstate->p_queryEnv = parentParseState->p_queryEnv;     }      return pstate; } /*  * transformTopLevelStmt -  *    transform a Parse tree into a Query tree.  *  * This function is just responsible for transferring statement location data  * from the RawStmt into the finished Query.  */ Query * transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree) {     Query      *result;      /* We're at top level, so allow SELECT INTO */     result = transformOptionalSelectInto(pstate, parseTree->stmt);      result->stmt_location = parseTree->stmt_location;     result->stmt_len = parseTree->stmt_len;      return result; }/*  * transformOptionalSelectInto -  *    If SELECT has INTO, convert it to CREATE TABLE AS.  *  * The only thing we do here that we don't do in transformStmt() is to  * convert SELECT ... INTO into CREATE TABLE AS.  Since utility statements  * aren't allowed within larger statements, this is only allowed at the top  * of the parse tree, and so we only try it before entering the recursive  * transformStmt() processing.  */ static Query * transformOptionalSelectInto(ParseState *pstate, Node *parseTree) {     if (IsA(parseTree, SelectStmt))     {         SelectStmt *stmt = (SelectStmt *) parseTree;          /* If it's a set-operation tree, drill down to leftmost SelectStmt */         while (stmt && stmt->op != SETOP_NONE)             stmt = stmt->larg;         Assert(stmt && IsA(stmt, SelectStmt) &&stmt->larg == NULL);          if (stmt->intoClause)         {             CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);              ctas->query = parseTree;             ctas->into = stmt->intoClause;             ctas->relkind = OBJECT_TABLE;             ctas->is_select_into = true;              /*              * Remove the intoClause from the SelectStmt.  This makes it safe              * for transformSelectStmt to complain if it finds intoClause set              * (implying that the INTO appeared in a disallowed place).              */             stmt->intoClause = NULL;              parseTree = (Node *) ctas;         }     }      return transformStmt(pstate, parseTree); }  /*  * transformStmt -  *    recursively transform a Parse tree into a Query tree.  */ Query * transformStmt(ParseState *pstate, Node *parseTree) {     Query      *result;      /*      * We apply RAW_EXPRESSION_COVERAGE_TEST testing to basic DML statements;      * we can't just run it on everything because raw_expression_tree_walker()      * doesn't claim to handle utility statements.      */ #ifdef RAW_EXPRESSION_COVERAGE_TEST     switch (nodeTag(parseTree))     {         case T_SelectStmt:         case T_InsertStmt:         case T_UpdateStmt:         case T_DeleteStmt:             (void) test_raw_expression_coverage(parseTree, NULL);             break;         default:             break;     } #endif                          /* RAW_EXPRESSION_COVERAGE_TEST */      switch (nodeTag(parseTree))     {             /*              * Optimizable statements              */         case T_InsertStmt:             result = transformInsertStmt(pstate, (InsertStmt *) parseTree);             break;          case T_DeleteStmt:             result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);             break;          case T_UpdateStmt:             result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);             break;          case T_SelectStmt:             {                 SelectStmt *n = (SelectStmt *) parseTree;                  if (n->valuesLists)                     result = transformValuesClause(pstate, n);                 else if (n->op == SETOP_NONE)                     result = transformSelectStmt(pstate, n);                 else                     result = transformSetOperationStmt(pstate, n);             }             break;              /*              * Special cases              */         case T_DeclareCursorStmt:             result = transformDeclareCursorStmt(pstate,                                                 (DeclareCursorStmt *) parseTree);             break;          case T_ExplainStmt:             result = transformExplainStmt(pstate,                                           (ExplainStmt *) parseTree);             break;          case T_CreateTableAsStmt:             result = transformCreateTableAsStmt(pstate,                                                 (CreateTableAsStmt *) parseTree);             break;          case T_CallStmt:             result = transformCallStmt(pstate,                                        (CallStmt *) parseTree);             break;          default:              /*              * other statements don't require any transformation; just return              * the original parsetree with a Query node plastered on top.              */             result = makeNode(Query);             result->commandType = CMD_UTILITY;             result->utilityStmt = (Node *) parseTree;             break;     }      /* Mark as original query until we learn differently */     result->querySource = QSRC_ORIGINAL;     result->canSetTag = true;      return result; } /*  * transformInsertStmt -  *    transform an Insert Statement  */ static Query * transformInsertStmt(ParseState *pstate, InsertStmt *stmt) {     Query      *qry = makeNode(Query);     SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt;     List       *exprList = NIL;     bool        isGeneralSelect;     List       *sub_rtable;     List       *sub_namespace;     List       *icolumns;     List       *attrnos;     RangeTblEntry *rte;     RangeTblRef *rtr;     ListCell   *icols;     ListCell   *attnos;     ListCell   *lc;     bool        isOnConflictUpdate;     AclMode     targetPerms;      /* There can't be any outer WITH to worry about */     Assert(pstate->p_ctenamespace == NIL);      qry->commandType = CMD_INSERT;     pstate->p_is_insert = true;      /* process the WITH clause independently of all else */     if (stmt->withClause)     {         qry->hasRecursive = stmt->withClause->recursive;         qry->cteList = transformWithClause(pstate, stmt->withClause);         qry->hasModifyingCTE = pstate->p_hasModifyingCTE;     }      qry->override = stmt->override;      isOnConflictUpdate = (stmt->onConflictClause &&                           stmt->onConflictClause->action == ONCONFLICT_UPDATE);      /*      * We have three cases to deal with: DEFAULT VALUES (selectStmt == NULL),      * VALUES list, or general SELECT input.  We special-case VALUES, both for      * efficiency and so we can handle DEFAULT specifications.      *      * The grammar allows attaching ORDER BY, LIMIT, FOR UPDATE, or WITH to a      * VALUES clause.  If we have any of those, treat it as a general SELECT;      * so it will work, but you can't use DEFAULT items together with those.      */     isGeneralSelect = (selectStmt && (selectStmt->valuesLists == NIL ||                                       selectStmt->sortClause != NIL ||                                       selectStmt->limitOffset != NULL ||                                       selectStmt->limitCount != NULL ||                                       selectStmt->lockingClause != NIL ||                                       selectStmt->withClause != NULL));      /*      * If a non-nil rangetable/namespace was passed in, and we are doing      * INSERT/SELECT, arrange to pass the rangetable/namespace down to the      * SELECT.  This can only happen if we are inside a CREATE RULE, and in      * that case we want the rule's OLD and NEW rtable entries to appear as      * part of the SELECT's rtable, not as outer references for it.  (Kluge!)      * The SELECT's joinlist is not affected however.  We must do this before      * adding the target table to the INSERT's rtable.      */     if (isGeneralSelect)     {         sub_rtable = pstate->p_rtable;         pstate->p_rtable = NIL;         sub_namespace = pstate->p_namespace;         pstate->p_namespace = NIL;     }     else     {         sub_rtable = NIL;       /* not used, but keep compiler quiet */         sub_namespace = NIL;     }      /*      * Must get write lock on INSERT target table before scanning SELECT, else      * we will grab the wrong kind of initial lock if the target table is also      * mentioned in the SELECT part.  Note that the target table is not added      * to the joinlist or namespace.      */     targetPerms = ACL_INSERT;     if (isOnConflictUpdate)         targetPerms |= ACL_UPDATE;     qry->resultRelation = setTargetTable(pstate, stmt->relation,                                          false, false, targetPerms);      /* Validate stmt->cols list, or build default list if no list given */     icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);     Assert(list_length(icolumns) == list_length(attrnos));      /*      * Determine which variant of INSERT we have.      */     if (selectStmt == NULL)     {         /*          * We have INSERT ... DEFAULT VALUES.  We can handle this case by          * emitting an empty targetlist --- all columns will be defaulted when          * the planner expands the targetlist.          */         exprList = NIL;     }     else if (isGeneralSelect)     {         /*          * We make the sub-pstate a child of the outer pstate so that it can          * see any Param definitions supplied from above.  Since the outer          * pstate's rtable and namespace are presently empty, there are no          * side-effects of exposing names the sub-SELECT shouldn't be able to          * see.          */         ParseState *sub_pstate = make_parsestate(pstate);         Query      *selectQuery;          /*          * Process the source SELECT.          *          * It is important that this be handled just like a standalone SELECT;          * otherwise the behavior of SELECT within INSERT might be different          * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had          * bugs of just that nature...)          *          * The sole exception is that we prevent resolving unknown-type          * outputs as TEXT.  This does not change the semantics since if the          * column type matters semantically, it would have been resolved to          * something else anyway.  Doing this lets us resolve such outputs as          * the target column's type, which we handle below.          */         sub_pstate->p_rtable = sub_rtable;         sub_pstate->p_joinexprs = NIL;  /* sub_rtable has no joins */         sub_pstate->p_namespace = sub_namespace;         sub_pstate->p_resolve_unknowns = false;          selectQuery = transformStmt(sub_pstate, stmt->selectStmt);          free_parsestate(sub_pstate);          /* The grammar should have produced a SELECT */         if (!IsA(selectQuery, Query) ||             selectQuery->commandType != CMD_SELECT)             elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT");          /*          * Make the source be a subquery in the INSERT's rangetable, and add          * it to the INSERT's joinlist.          */         rte = addRangeTableEntryForSubquery(pstate,                                             selectQuery,                                             makeAlias("*SELECT*", NIL),                                             false,                                             false);         rtr = makeNode(RangeTblRef);         /* assume new rte is at end */         rtr->rtindex = list_length(pstate->p_rtable);         Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));         pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);          /*----------          * Generate an expression list for the INSERT that selects all the          * non-resjunk columns from the subquery.  (INSERT's tlist must be          * separate from the subquery's tlist because we may add columns,          * insert datatype coercions, etc.)          *          * HACK: unknown-type constants and params in the SELECT's targetlist          * are copied up as-is rather than being referenced as subquery          * outputs.  This is to ensure that when we try to coerce them to          * the target column's datatype, the right things happen (see          * special cases in coerce_type).  Otherwise, this fails:          *      INSERT INTO foo SELECT 'bar', ... FROM baz          *----------          */         exprList = NIL;         foreach(lc, selectQuery->targetList)         {             TargetEntry *tle = (TargetEntry *) lfirst(lc);             Expr       *expr;              if (tle->resjunk)                 continue;             if (tle->expr &&                 (IsA(tle->expr, Const) ||IsA(tle->expr, Param)) &&                 exprType((Node *) tle->expr) == UNKNOWNOID)                 expr = tle->expr;             else             {                 Var        *var = makeVarFromTargetEntry(rtr->rtindex, tle);                  var->location = exprLocation((Node *) tle->expr);                 expr = (Expr *) var;             }             exprList = lappend(exprList, expr);         }          /* Prepare row for assignment to target table */         exprList = transformInsertRow(pstate, exprList,                                       stmt->cols,                                       icolumns, attrnos,                                       false);     }     else if (list_length(selectStmt->valuesLists) > 1)     {         /*          * Process INSERT ... VALUES with multiple VALUES sublists. We          * generate a VALUES RTE holding the transformed expression lists, and          * build up a targetlist containing Vars that reference the VALUES          * RTE.          */         List       *exprsLists = NIL;         List       *coltypes = NIL;         List       *coltypmods = NIL;         List       *colcollations = NIL;         int         sublist_length = -1;         bool        lateral = false;          Assert(selectStmt->intoClause == NULL);          foreach(lc, selectStmt->valuesLists)         {             List       *sublist = (List *) lfirst(lc);              /*              * Do basic expression transformation (same as a ROW() expr, but              * allow SetToDefault at top level)              */             sublist = transformExpressionList(pstate, sublist,                                               EXPR_KIND_VALUES, true);              /*              * All the sublists must be the same length, *after*              * transformation (which might expand '*' into multiple items).              * The VALUES RTE can't handle anything different.              */             if (sublist_length < 0)             {                 /* Remember post-transformation length of first sublist */                 sublist_length = list_length(sublist);             }             else if (sublist_length != list_length(sublist))             {                 ereport(ERROR,                         (errcode(ERRCODE_SYNTAX_ERROR),                          errmsg("VALUES lists must all be the same length"),                          parser_errposition(pstate,                                             exprLocation((Node *) sublist))));             }              /*              * Prepare row for assignment to target table.  We process any              * indirection on the target column specs normally but then strip              * off the resulting field/array assignment nodes, since we don't              * want the parsed statement to contain copies of those in each              * VALUES row.  (It's annoying to have to transform the              * indirection specs over and over like this, but avoiding it              * would take some really messy refactoring of              * transformAssignmentIndirection.)              */             sublist = transformInsertRow(pstate, sublist,                                          stmt->cols,                                          icolumns, attrnos,                                          true);              /*              * We must assign collations now because assign_query_collations              * doesn't process rangetable entries.  We just assign all the              * collations independently in each row, and don't worry about              * whether they are consistent vertically.  The outer INSERT query              * isn't going to care about the collations of the VALUES columns,              * so it's not worth the effort to identify a common collation for              * each one here.  (But note this does have one user-visible              * consequence: INSERT ... VALUES won't complain about conflicting              * explicit COLLATEs in a column, whereas the same VALUES              * construct in another context would complain.)              */             assign_list_collations(pstate, sublist);              exprsLists = lappend(exprsLists, sublist);         }          /*          * Construct column type/typmod/collation lists for the VALUES RTE.          * Every expression in each column has been coerced to the type/typmod          * of the corresponding target column or subfield, so it's sufficient          * to look at the exprType/exprTypmod of the first row.  We don't care          * about the collation labeling, so just fill in InvalidOid for that.          */         foreach(lc, (List *) linitial(exprsLists))         {             Node       *val = (Node *) lfirst(lc);              coltypes = lappend_oid(coltypes, exprType(val));             coltypmods = lappend_int(coltypmods, exprTypmod(val));             colcollations = lappend_oid(colcollations, InvalidOid);         }          /*          * Ordinarily there can't be any current-level Vars in the expression          * lists, because the namespace was empty ... but if we're inside          * CREATE RULE, then NEW/OLD references might appear.  In that case we          * have to mark the VALUES RTE as LATERAL.          */         if (list_length(pstate->p_rtable) != 1 &&             contain_vars_of_level((Node *) exprsLists, 0))             lateral = true;          /*          * Generate the VALUES RTE          */         rte = addRangeTableEntryForValues(pstate, exprsLists,                                           coltypes, coltypmods, colcollations,                                           NULL, lateral, true);         rtr = makeNode(RangeTblRef);         /* assume new rte is at end */         rtr->rtindex = list_length(pstate->p_rtable);         Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));         pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);          /*          * Generate list of Vars referencing the RTE          */         expandRTE(rte, rtr->rtindex, 0, -1, false, NULL, &exprList);          /*          * Re-apply any indirection on the target column specs to the Vars          */         exprList = transformInsertRow(pstate, exprList,                                       stmt->cols,                                       icolumns, attrnos,                                       false);     }     else     {         /*          * Process INSERT ... VALUES with a single VALUES sublist.  We treat          * this case separately for efficiency.  The sublist is just computed          * directly as the Query's targetlist, with no VALUES RTE.  So it          * works just like a SELECT without any FROM.          */         List       *valuesLists = selectStmt->valuesLists;          Assert(list_length(valuesLists) == 1);         Assert(selectStmt->intoClause == NULL);          /*          * Do basic expression transformation (same as a ROW() expr, but allow          * SetToDefault at top level)          */         exprList = transformExpressionList(pstate,                                            (List *) linitial(valuesLists),                                            EXPR_KIND_VALUES_SINGLE,                                            true);          /* Prepare row for assignment to target table */         exprList = transformInsertRow(pstate, exprList,                                       stmt->cols,                                       icolumns, attrnos,                                       false);     }      /*      * Generate query's target list using the computed list of expressions.      * Also, mark all the target columns as needing insert permissions.      */     rte = pstate->p_target_rangetblentry;     qry->targetList = NIL;     icols = list_head(icolumns);     attnos = list_head(attrnos);     foreach(lc, exprList)     {         Expr       *expr = (Expr *) lfirst(lc);         ResTarget  *col;         AttrNumber  attr_num;         TargetEntry *tle;          col = lfirst_node(ResTarget, icols);         attr_num = (AttrNumber) lfirst_int(attnos);          tle = makeTargetEntry(expr,                               attr_num,                               col->name,                               false);         qry->targetList = lappend(qry->targetList, tle);          rte->insertedCols = bms_add_member(rte->insertedCols,                                            attr_num - FirstLowInvalidHeapAttributeNumber);          icols = lnext(icols);         attnos = lnext(attnos);     }      /* Process ON CONFLICT, if any. */     if (stmt->onConflictClause)         qry->onConflict = transformOnConflictClause(pstate,                                                     stmt->onConflictClause);      /*      * If we have a RETURNING clause, we need to add the target relation to      * the query namespace before processing it, so that Var references in      * RETURNING will work.  Also, remove any namespace entries added in a      * sub-SELECT or VALUES list.      */     if (stmt->returningList)     {         pstate->p_namespace = NIL;         addRTEtoQuery(pstate, pstate->p_target_rangetblentry,                       false, true, true);         qry->returningList = transformReturningList(pstate,                                                     stmt->returningList);     }      /* done building the range table and jointree */     qry->rtable = pstate->p_rtable;     qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);      qry->hasTargetSRFs = pstate->p_hasTargetSRFs;     qry->hasSubLinks = pstate->p_hasSubLinks;      assign_query_collations(pstate, qry);      return qry; }

9、pg_plan_queries

/*  * Generate plans for a list of already-rewritten queries.  *  * For normal optimizable statements, invoke the planner.  For utility  * statements, just make a wrapper PlannedStmt node.  *  * The result is a list of PlannedStmt nodes.  */ List * pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams) {     List       *stmt_list = NIL;     ListCell   *query_list;      foreach(query_list, querytrees)     {         Query      *query = lfirst_node(Query, query_list);         PlannedStmt *stmt;          if (query->commandType == CMD_UTILITY)         {             /* Utility commands require no planning. */             stmt = makeNode(PlannedStmt);             stmt->commandType = CMD_UTILITY;             stmt->canSetTag = query->canSetTag;             stmt->utilityStmt = query->utilityStmt;             stmt->stmt_location = query->stmt_location;             stmt->stmt_len = query->stmt_len;         }         else         {             stmt = pg_plan_query(query, cursorOptions, boundParams);         }          stmt_list = lappend(stmt_list, stmt);     }      return stmt_list; } /*  * Generate a plan for a single already-rewritten query.  * This is a thin wrapper around planner() and takes the same parameters.  */ PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams) {     PlannedStmt *plan;      /* Utility commands have no plans. */     if (querytree->commandType == CMD_UTILITY)         return NULL;      /* Planner must have a snapshot in case it calls user-defined functions. */     Assert(ActiveSnapshotSet());      TRACE_POSTGRESQL_QUERY_PLAN_START();      if (log_planner_stats)         ResetUsage();      /* call the optimizer */     plan = planner(querytree, cursorOptions, boundParams);      if (log_planner_stats)         ShowUsage("PLANNER STATISTICS");  #ifdef COPY_PARSE_PLAN_TREES     /* Optional debugging check: pass plan output through copyObject() */     {         PlannedStmt *new_plan = copyObject(plan);          /*          * equal() currently does not have routines to compare Plan nodes, so          * don't try to test equality here.  Perhaps fix someday?          */ #ifdef NOT_USED         /* This checks both copyObject() and the equal() routines... */         if (!equal(new_plan, plan))             elog(WARNING, "copyObject() failed to produce an equal plan tree");         else #endif             plan = new_plan;     } #endif      /*      * Print plan if debugging.      */     if (Debug_print_plan)         elog_node_display(LOG, "plan", plan, Debug_pretty_print);      TRACE_POSTGRESQL_QUERY_PLAN_DONE();      return plan; } /*****************************************************************************  *  *     Query optimizer entry point  *  * To support loadable plugins that monitor or modify planner behavior,  * we provide a hook variable that lets a plugin get control before and  * after the standard planning process.  The plugin would normally call  * standard_planner().  *  * Note to plugin authors: standard_planner() scribbles on its Query input,  * so you'd better copy that data structure if you want to plan more than once.  *  *****************************************************************************/ PlannedStmt * planner(Query *parse, int cursorOptions, ParamListInfo boundParams) {     PlannedStmt *result;      if (planner_hook)         result = (*planner_hook) (parse, cursorOptions, boundParams);     else         result = standard_planner(parse, cursorOptions, boundParams);     return result; }

10、CreatePortal

/*  * CreatePortal  *      Returns a new portal given a name.  *  * allowDup: if true, automatically drop any pre-existing portal of the  * same name (if false, an error is raised).  *  * dupSilent: if true, don't even emit a WARNING.  */ Portal CreatePortal(const char *name, bool allowDup, bool dupSilent) {     Portal      portal;      AssertArg(PointerIsValid(name));      portal = GetPortalByName(name);     if (PortalIsValid(portal))     {         if (!allowDup)             ereport(ERROR,                     (errcode(ERRCODE_DUPLICATE_CURSOR),                      errmsg("cursor \"%s\" already exists", name)));         if (!dupSilent)             ereport(WARNING,                     (errcode(ERRCODE_DUPLICATE_CURSOR),                      errmsg("closing existing cursor \"%s\"",                             name)));         PortalDrop(portal, false);     }      /* make new portal structure */     portal = (Portal) MemoryContextAllocZero(TopPortalContext, sizeof *portal);      /* initialize portal context; typically it won't store much */     portal->portalContext = AllocSetContextCreate(TopPortalContext,                                                   "PortalContext",                                                   ALLOCSET_SMALL_SIZES);      /* create a resource owner for the portal */     portal->resowner = ResourceOwnerCreate(CurTransactionResourceOwner,                                            "Portal");      /* initialize portal fields that don't start off zero */     portal->status = PORTAL_NEW;     portal->cleanup = PortalCleanup;     portal->createSubid = GetCurrentSubTransactionId();     portal->activeSubid = portal->createSubid;     portal->strategy = PORTAL_MULTI_QUERY;     portal->cursorOptions = CURSOR_OPT_NO_SCROLL;     portal->atStart = true;     portal->atEnd = true;       /* disallow fetches until query is set */     portal->visible = true;     portal->creation_time = GetCurrentStatementStartTimestamp();      /* put portal in table (sets portal->name) */     PortalHashTableInsert(portal, name);      /* reuse portal->name copy */     MemoryContextSetIdentifier(portal->portalContext, portal->name);      return portal; }

11、PortalDefineQuery

/*  * PortalDefineQuery  *      A simple subroutine to establish a portal's query.  *  * Notes: as of PG 8.4, caller MUST supply a sourceText string; it is not  * allowed anymore to pass NULL.  (If you really don't have source text,  * you can pass a constant string, perhaps "(query not available)".)  *  * commandTag shall be NULL if and only if the original query string  * (before rewriting) was an empty string.  Also, the passed commandTag must  * be a pointer to a constant string, since it is not copied.  *  * If cplan is provided, then it is a cached plan containing the stmts, and  * the caller must have done GetCachedPlan(), causing a refcount increment.  * The refcount will be released when the portal is destroyed.  *  * If cplan is NULL, then it is the caller's responsibility to ensure that  * the passed plan trees have adequate lifetime.  Typically this is done by  * copying them into the portal's context.  *  * The caller is also responsible for ensuring that the passed prepStmtName  * (if not NULL) and sourceText have adequate lifetime.  *  * NB: this function mustn't do much beyond storing the passed values; in  * particular don't do anything that risks elog(ERROR).  If that were to  * happen here before storing the cplan reference, we'd leak the plancache  * refcount that the caller is trying to hand off to us.  */ void PortalDefineQuery(Portal portal,                   const char *prepStmtName,                   const char *sourceText,                   const char *commandTag,                   List *stmts,                   CachedPlan *cplan) {     AssertArg(PortalIsValid(portal));     AssertState(portal->status == PORTAL_NEW);      AssertArg(sourceText != NULL);     AssertArg(commandTag != NULL || stmts == NIL);      portal->prepStmtName = prepStmtName;     portal->sourceText = sourceText;     portal->commandTag = commandTag;     portal->stmts = stmts;     portal->cplan = cplan;     portal->status = PORTAL_DEFINED; }

12、PortalStart

/*  * PortalStart  *      Prepare a portal for execution.  *  * Caller must already have created the portal, done PortalDefineQuery(),  * and adjusted portal options if needed.  *  * If parameters are needed by the query, they must be passed in "params"  * (caller is responsible for giving them appropriate lifetime).  *  * The caller can also provide an initial set of "eflags" to be passed to  * ExecutorStart (but note these can be modified internally, and they are  * currently only honored for PORTAL_ONE_SELECT portals).  Most callers  * should simply pass zero.  *  * The caller can optionally pass a snapshot to be used; pass InvalidSnapshot  * for the normal behavior of setting a new snapshot.  This parameter is  * presently ignored for non-PORTAL_ONE_SELECT portals (it's only intended  * to be used for cursors).  *  * On return, portal is ready to accept PortalRun() calls, and the result  * tupdesc (if any) is known.  */ 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);      /*      * Set up global portal context pointers.      */     saveActivePortal = ActivePortal;     saveResourceOwner = CurrentResourceOwner;     savePortalContext = PortalContext;     PG_TRY();     {         ActivePortal = portal;         if (portal->resowner)             CurrentResourceOwner = portal->resowner;         PortalContext = portal->portalContext;          oldContext = MemoryContextSwitchTo(PortalContext);          /* Must remember portal param list, if any */         portal->portalParams = params;          /*          * Determine the portal execution strategy          */         portal->strategy = ChoosePortalStrategy(portal->stmts);          /*          * Fire her up according to the strategy          */         switch (portal->strategy)         {             case PORTAL_ONE_SELECT:                  /* Must set snapshot before starting executor. */                 if (snapshot)                     PushActiveSnapshot(snapshot);                 else                     PushActiveSnapshot(GetTransactionSnapshot());                  /*                  * Create QueryDesc in portal's context; for the moment, set                  * the destination to DestNone.                  */                 queryDesc = CreateQueryDesc(linitial_node(PlannedStmt, portal->stmts),                                             portal->sourceText,                                             GetActiveSnapshot(),                                             InvalidSnapshot,                                             None_Receiver,                                             params,                                             portal->queryEnv,                                             0);                  /*                  * If it's a scrollable cursor, executor needs to support                  * REWIND and backwards scan, as well as whatever the caller                  * might've asked for.                  */                 if (portal->cursorOptions & CURSOR_OPT_SCROLL)                     myeflags = eflags | EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD;                 else                     myeflags = eflags;                  /*                  * Call ExecutorStart to prepare the plan for execution                  */                 ExecutorStart(queryDesc, myeflags);                  /*                  * This tells PortalCleanup to shut down the executor                  */                 portal->queryDesc = queryDesc;                  /*                  * Remember tuple descriptor (computed by ExecutorStart)                  */                 portal->tupDesc = queryDesc->tupDesc;                  /*                  * Reset cursor position data to "start of query"                  */                 portal->atStart = true;                 portal->atEnd = false;  /* allow fetches */                 portal->portalPos = 0;                  PopActiveSnapshot();                 break;              case PORTAL_ONE_RETURNING:             case PORTAL_ONE_MOD_WITH:                  /*                  * We don't start the executor until we are told to run the                  * portal.  We do need to set up the result tupdesc.                  */                 {                     PlannedStmt *pstmt;                      pstmt = PortalGetPrimaryStmt(portal);                     portal->tupDesc =                         ExecCleanTypeFromTL(pstmt->planTree->targetlist,                                             false);                 }                  /*                  * Reset cursor position data to "start of query"                  */                 portal->atStart = true;                 portal->atEnd = false;  /* allow fetches */                 portal->portalPos = 0;                 break;              case PORTAL_UTIL_SELECT:                  /*                  * We don't set snapshot here, because PortalRunUtility will                  * take care of it if needed.                  */                 {                     PlannedStmt *pstmt = PortalGetPrimaryStmt(portal);                      Assert(pstmt->commandType == CMD_UTILITY);                     portal->tupDesc = UtilityTupleDescriptor(pstmt->utilityStmt);                 }                  /*                  * Reset cursor position data to "start of query"                  */                 portal->atStart = true;                 portal->atEnd = false;  /* allow fetches */                 portal->portalPos = 0;                 break;              case PORTAL_MULTI_QUERY:                 /* Need do nothing now */                 portal->tupDesc = NULL;                 break;         }     }     PG_CATCH();     {         /* Uncaught error while executing portal: mark it dead */         MarkPortalFailed(portal);          /* Restore global vars and propagate error */         ActivePortal = saveActivePortal;         CurrentResourceOwner = saveResourceOwner;         PortalContext = savePortalContext;          PG_RE_THROW();     }     PG_END_TRY();      MemoryContextSwitchTo(oldContext);      ActivePortal = saveActivePortal;     CurrentResourceOwner = saveResourceOwner;     PortalContext = savePortalContext;      portal->status = PORTAL_READY; }

13、PortalSetResultFormat

/*  * PortalSetResultFormat  *      Select the format codes for a portal's output.  *  * This must be run after PortalStart for a portal that will be read by  * a DestRemote or DestRemoteExecute destination.  It is not presently needed  * for other destination types.  *  * formats[] is the client format request, as per Bind message conventions.  */ void PortalSetResultFormat(Portal portal, int nFormats, int16 *formats) {     int         natts;     int         i;      /* Do nothing if portal won't return tuples */     if (portal->tupDesc == NULL)         return;     natts = portal->tupDesc->natts;     portal->formats = (int16 *)         MemoryContextAlloc(portal->portalContext,                            natts * sizeof(int16));     if (nFormats > 1)     {         /* format specified for each column */         if (nFormats != natts)             ereport(ERROR,                     (errcode(ERRCODE_PROTOCOL_VIOLATION),                      errmsg("bind message has %d result formats but query has %d columns",                             nFormats, natts)));         memcpy(portal->formats, formats, natts * sizeof(int16));     }     else if (nFormats > 0)     {         /* single format specified, use for all columns */         int16       format1 = formats[0];          for (i = 0; i < natts; i++)             portal->formats[i] = format1;     }     else     {         /* use default format for all columns */         for (i = 0; i < natts; i++)             portal->formats[i] = 0;     } }

14、CreateDestReceiver

/* ----------------  *      CreateDestReceiver - return appropriate receiver function set for dest  * ----------------  */ DestReceiver * CreateDestReceiver(CommandDest dest) {     switch (dest)     {         case DestRemote:         case DestRemoteExecute:             return printtup_create_DR(dest);          case DestRemoteSimple:             return &printsimpleDR;          case DestNone:             return &donothingDR;          case DestDebug:             return &debugtupDR;          case DestSPI:             return &spi_printtupDR;          case DestTuplestore:             return CreateTuplestoreDestReceiver();          case DestIntoRel:             return CreateIntoRelDestReceiver(NULL);          case DestCopyOut:             return CreateCopyDestReceiver();          case DestSQLFunction:             return CreateSQLFunctionDestReceiver();          case DestTransientRel:             return CreateTransientRelDestReceiver(InvalidOid);          case DestTupleQueue:             return CreateTupleQueueDestReceiver(NULL);     }      /* should never get here */     return &donothingDR; }

15、printtup_create_DR

/* ----------------  *      Initialize: create a DestReceiver for printtup  * ----------------  */ DestReceiver * printtup_create_DR(CommandDest dest) {     DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));      self->pub.receiveSlot = printtup;   /* might get changed later */     self->pub.rStartup = printtup_startup;     self->pub.rShutdown = printtup_shutdown;     self->pub.rDestroy = printtup_destroy;     self->pub.mydest = dest;      /*      * Send T message automatically if DestRemote, but not if      * DestRemoteExecute      */     self->sendDescrip = (dest == DestRemote);      self->attrinfo = NULL;     self->nattrs = 0;     self->myinfo = NULL;     self->tmpcontext = NULL;      return (DestReceiver *) self; }

16、PortalDrop

/*  * PortalDrop  *      Destroy the portal.  */ void PortalDrop(Portal portal, bool isTopCommit) {     AssertArg(PortalIsValid(portal));      /*      * Don't allow dropping a pinned portal, it's still needed by whoever      * pinned it.      */     if (portal->portalPinned)         ereport(ERROR,                 (errcode(ERRCODE_INVALID_CURSOR_STATE),                  errmsg("cannot drop pinned portal \"%s\"", portal->name)));      /*      * Not sure if the PORTAL_ACTIVE case can validly happen or not...      */     if (portal->status == PORTAL_ACTIVE)         ereport(ERROR,                 (errcode(ERRCODE_INVALID_CURSOR_STATE),                  errmsg("cannot drop active portal \"%s\"", portal->name)));      /*      * Allow portalcmds.c to clean up the state it knows about, in particular      * shutting down the executor if still active.  This step potentially runs      * user-defined code so failure has to be expected.  It's the cleanup      * hook's responsibility to not try to do that more than once, in the case      * that failure occurs and then we come back to drop the portal again      * during transaction abort.      *      * Note: in most paths of control, this will have been done already in      * MarkPortalDone or MarkPortalFailed.  We're just making sure.      */     if (PointerIsValid(portal->cleanup))     {         portal->cleanup(portal);         portal->cleanup = NULL;     }      /*      * Remove portal from hash table.  Because we do this here, we will not      * come back to try to remove the portal again if there's any error in the      * subsequent steps.  Better to leak a little memory than to get into an      * infinite error-recovery loop.      */     PortalHashTableDelete(portal);      /* drop cached plan reference, if any */     PortalReleaseCachedPlan(portal);      /*      * If portal has a snapshot protecting its data, release that.  This needs      * a little care since the registration will be attached to the portal's      * resowner; if the portal failed, we will already have released the      * resowner (and the snapshot) during transaction abort.      */     if (portal->holdSnapshot)     {         if (portal->resowner)             UnregisterSnapshotFromOwner(portal->holdSnapshot,                                         portal->resowner);         portal->holdSnapshot = NULL;     }      /*      * Release any resources still attached to the portal.  There are several      * cases being covered here:      *      * Top transaction commit (indicated by isTopCommit): normally we should      * do nothing here and let the regular end-of-transaction resource      * releasing mechanism handle these resources too.  However, if we have a      * FAILED portal (eg, a cursor that got an error), we'd better clean up      * its resources to avoid resource-leakage warning messages.      *      * Sub transaction commit: never comes here at all, since we don't kill      * any portals in AtSubCommit_Portals().      *      * Main or sub transaction abort: we will do nothing here because      * portal->resowner was already set NULL; the resources were already      * cleaned up in transaction abort.      *      * Ordinary portal drop: must release resources.  However, if the portal      * is not FAILED then we do not release its locks.  The locks become the      * responsibility of the transaction's ResourceOwner (since it is the      * parent of the portal's owner) and will be released when the transaction      * eventually ends.      */     if (portal->resowner &&         (!isTopCommit || portal->status == PORTAL_FAILED))     {         bool        isCommit = (portal->status != PORTAL_FAILED);          ResourceOwnerRelease(portal->resowner,                              RESOURCE_RELEASE_BEFORE_LOCKS,                              isCommit, false);         ResourceOwnerRelease(portal->resowner,                              RESOURCE_RELEASE_LOCKS,                              isCommit, false);         ResourceOwnerRelease(portal->resowner,                              RESOURCE_RELEASE_AFTER_LOCKS,                              isCommit, false);         ResourceOwnerDelete(portal->resowner);     }     portal->resowner = NULL;      /*      * Delete tuplestore if present.  We should do this even under error      * conditions; since the tuplestore would have been using cross-      * transaction storage, its temp files need to be explicitly deleted.      */     if (portal->holdStore)     {         MemoryContext oldcontext;          oldcontext = MemoryContextSwitchTo(portal->holdContext);         tuplestore_end(portal->holdStore);         MemoryContextSwitchTo(oldcontext);         portal->holdStore = NULL;     }      /* delete tuplestore storage, if any */     if (portal->holdContext)         MemoryContextDelete(portal->holdContext);      /* release subsidiary storage */     MemoryContextDelete(portal->portalContext);      /* release portal struct (it's in TopPortalContext) */     pfree(portal); }

17、EndImplicitTransactionBlock

/*  * EndImplicitTransactionBlock  *      End an implicit transaction block, if we're in one.  *  * Like EndTransactionBlock, we just make any needed blockState change here.  * The real work will be done in the upcoming CommitTransactionCommand().  */ void EndImplicitTransactionBlock(void) {     TransactionState s = CurrentTransactionState;      /*      * If we are in IMPLICIT_INPROGRESS state, switch back to STARTED state,      * allowing CommitTransactionCommand to commit whatever happened during      * the implicit transaction block as though it were a single statement.      *      * For caller convenience, we consider all other transaction states as      * legal here; otherwise the caller would need its own state check, which      * seems rather pointless.      */     if (s->blockState == TBLOCK_IMPLICIT_INPROGRESS)         s->blockState = TBLOCK_STARTED; }

18、finish_xact_command

static void finish_xact_command(void) {     /* cancel active statement timeout after each command */     disable_statement_timeout();      if (xact_started)     {         CommitTransactionCommand();  #ifdef MEMORY_CONTEXT_CHECKING         /* Check all memory contexts that weren't freed during commit */         /* (those that were, were checked before being deleted) */         MemoryContextCheck(TopMemoryContext); #endif  #ifdef SHOW_MEMORY_STATS         /* Print mem stats after each commit for leak tracking */         MemoryContextStats(TopMemoryContext); #endif          xact_started = false;     } }

19、CommandCounterIncrement

/*  *  CommandCounterIncrement  */ void CommandCounterIncrement(void) {     /*      * If the current value of the command counter hasn't been "used" to mark      * tuples, we need not increment it, since there's no need to distinguish      * a read-only command from others.  This helps postpone command counter      * overflow, and keeps no-op CommandCounterIncrement operations cheap.      */     if (currentCommandIdUsed)     {         /*          * Workers synchronize transaction state at the beginning of each          * parallel operation, so we can't account for new commands after that          * point.          */         if (IsInParallelMode() || IsParallelWorker())             elog(ERROR, "cannot start commands during a parallel operation");          currentCommandId += 1;         if (currentCommandId == InvalidCommandId)         {             currentCommandId -= 1;             ereport(ERROR,                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),                      errmsg("cannot have more than 2^32-2 commands in a transaction")));         }         currentCommandIdUsed = false;          /* Propagate new command ID into static snapshots */         SnapshotSetCommandId(currentCommandId);          /*          * Make any catalog changes done by the just-completed command visible          * in the local syscache.  We obviously don't need to do this after a          * read-only command.  (But see hacks in inval.c to make real sure we          * don't think a command that queued inval messages was read-only.)          */         AtCCI_LocalCache();     } }

20、EndCommand

/* ----------------  *      EndCommand - clean up the destination at end of command  * ----------------  */ void EndCommand(const char *commandTag, CommandDest dest) {     switch (dest)     {         case DestRemote:         case DestRemoteExecute:         case DestRemoteSimple:              /*              * We assume the commandTag is plain ASCII and therefore requires              * no encoding conversion.              */             pq_putmessage('C', commandTag, strlen(commandTag) + 1);             break;          case DestNone:         case DestDebug:         case DestSPI:         case DestTuplestore:         case DestIntoRel:         case DestCopyOut:         case DestSQLFunction:         case DestTransientRel:         case DestTupleQueue:             break;     } }

三、跟踪分析

插入测试数据:

testdb=# -- 获取pidtestdb=# select pg_backend_pid(); pg_backend_pid ----------------           1893(1 row)testdb=# -- 插入1行testdb=# insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');(挂起)

启动gdb,跟踪调试:

[root@localhost ~]# gdb -p 1893GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7Copyright (C) 2013 Free Software Foundation, Inc....(gdb) b exec_simple_queryBreakpoint 1 at 0x84cad8: file postgres.c, line 893.(gdb) cContinuing.Breakpoint 1, exec_simple_query (query_string=0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');") at postgres.c:893893     CommandDest dest = whereToSendOutput;#输入参数#query_string(gdb) p query_string$1 = 0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');"#单步调试938     oldcontext = MemoryContextSwitchTo(MessageContext);(gdb) p *MessageContext$2 = {type = T_AllocSetContext, isReset = false, allowInCritSection = false, methods = 0xb8c720 
, parent = 0x1503ba0, firstchild = 0x0, prevchild = 0x157c3c0, nextchild = 0x15956d0, name = 0xb4e87c "MessageContext", ident = 0x0, reset_cbs = 0x0}(gdb) n944 parsetree_list = pg_parse_query(query_string);(gdb) p oldcontext$3 = (MemoryContext) 0x15a8320(gdb) p *oldcontext$4 = {type = T_AllocSetContext, isReset = true, allowInCritSection = false, methods = 0xb8c720
, parent = 0x1503ba0, firstchild = 0x0, prevchild = 0x0, nextchild = 0x157c3c0, name = 0xa1b4ff "TopTransactionContext", ident = 0x0, reset_cbs = 0x0}(gdb) steppg_parse_query (query_string=0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');") at postgres.c:615615 if (log_parser_stats)(gdb) 618 raw_parsetree_list = raw_parser(query_string);#进入raw_parser(gdb) stepraw_parser (str=0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');") at parser.c:4343 yyscanner = scanner_init(str, &yyextra.core_yy_extra,(gdb) ...61 return yyextra.parsetree;(gdb) p yyextra$8 = {core_yy_extra = {scanbuf = 0x1509820 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');", scanbuflen = 92, keywords = 0xbb8d40
, num_keywords = 440, backslash_quote = 2, escape_string_warning = true, standard_conforming_strings = true, literalbuf = 0x1509300 "exec_simple_query", literallen = 17, literalalloc = 1024, xcdepth = 1087033144, dolqstart = 0x0, utf16_first_part = 16777215, warn_on_first_escape = true, saw_non_ascii = false}, have_lookahead = false, lookahead_token = 32765, lookahead_yylval = { ival = 10027008, str = 0x300990000
, keyword = 0x300990000
}, lookahead_yylloc = 2015867616, lookahead_end = 0xa1b62b "StartTransaction", lookahead_hold_char = 16 '\020', parsetree = 0x1509d88}(gdb) p *(yyextra.parsetree)$10 = {type = T_List, length = 1, head = 0x1509d68, tail = 0x1509d68}#解析树中的内容(gdb) p *((RawStmt*)(yyextra.parsetree->head->data.ptr_value))$25 = {type = T_RawStmt, stmt = 0x1509ce8, stmt_location = 0, stmt_len = 91}(gdb) p *(((RawStmt*)(yyextra.parsetree->head->data.ptr_value))->stmt)$27 = {type = T_InsertStmt}#跳出子函数,重新进入主函数(gdb) exec_simple_query (query_string=0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');") at postgres.c:947947 if (check_log_statement(parsetree_list))...#解析树只有一个元素(gdb) n974 foreach(parsetree_item, parsetree_list)(gdb) p list_length(parsetree_list)$30 = 1(gdb) n976 RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);(gdb) 977 bool snapshot_set = false;(gdb) p *parsetree$31 = {type = T_RawStmt, stmt = 0x1509ce8, stmt_location = 0, stmt_len = 91}(gdb) p *(parsetree->stmt)$32 = {type = T_InsertStmt}#commandTag(gdb) n992 commandTag = CreateCommandTag(parsetree->stmt);(gdb) 994 set_ps_display(commandTag, false);(gdb) p commandTag$33 = 0xb50908 "INSERT"#进入分析&查询重写1047 querytree_list = pg_analyze_and_rewrite(parsetree, query_string,(gdb) steppg_analyze_and_rewrite (parsetree=0x1509d38, query_string=0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');", paramTypes=0x0, numParams=0, queryEnv=0x0) at postgres.c:663663 if (log_parser_stats)...#分析后的Query数据结构(gdb) p *query$34 = {type = T_Query, commandType = CMD_INSERT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true, utilityStmt = 0x0, resultRelation = 1, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false, hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, rtable = 0x150a788, jointree = 0x152cf40, targetList = 0x152cda8, override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0, groupClause = 0x0, groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, rowMarks = 0x0, setOperations = 0x0, constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 91}...#回到主函数(gdb) exec_simple_query (query_string=0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');") at postgres.c:10501050 plantree_list = pg_plan_queries(querytree_list,(gdb) 1054 if (snapshot_set)(gdb) 1055 PopActiveSnapshot();(gdb) 1058 CHECK_FOR_INTERRUPTS();(gdb) 1064 portal = CreatePortal("", true, true);(gdb) p *plantree_list$36 = {type = T_List, length = 1, head = 0x15c03e8, tail = 0x15c03e8}(gdb) p (PlannedStmt*)(plantree_list->head->data.ptr_value)$37 = (PlannedStmt *) 0x150a4a8(gdb) p *((PlannedStmt*)(plantree_list->head->data.ptr_value))$38 = {type = T_PlannedStmt, commandType = CMD_INSERT, queryId = 0, hasReturning = false, hasModifyingCTE = false, canSetTag = true, transientPlan = false, dependsOnRole = false, parallelModeNeeded = false, jitFlags = 0, planTree = 0x150a028, rtable = 0x15c0318, resultRelations = 0x15c03b8, nonleafResultRelations = 0x0, rootResultRelations = 0x0, subplans = 0x0, rewindPlanIDs = 0x0, rowMarks = 0x0, relationOids = 0x15c0368, invalItems = 0x0, paramExecTypes = 0x152e720, utilityStmt = 0x0, stmt_location = 0, stmt_len = 91}#Portal...(gdb) p *portal$40 = {name = 0x1571e98 "", prepStmtName = 0x0, portalContext = 0x152c3d0, resowner = 0x1539d10, cleanup = 0x62f15c
, createSubid = 1, activeSubid = 1, sourceText = 0x0, commandTag = 0x0, stmts = 0x0, cplan = 0x0, portalParams = 0x0, queryEnv = 0x0, strategy = PORTAL_MULTI_QUERY, cursorOptions = 4, run_once = false, status = PORTAL_NEW, portalPinned = false, autoHeld = false, queryDesc = 0x0, tupDesc = 0x0, formats = 0x0, holdStore = 0x0, holdContext = 0x0, holdSnapshot = 0x0, atStart = true, atEnd = true, portalPos = 0, creation_time = 587101481469205, visible = true}(gdb) n1073 PortalDefineQuery(portal,(gdb) 1083 PortalStart(portal, NULL, 0, InvalidSnapshot);(gdb) 1091 format = 0; /* TEXT is default */(gdb) 1092 if (IsA(parsetree->stmt, FetchStmt))(gdb) p *portal$41 = {name = 0x1571e98 "", prepStmtName = 0x0, portalContext = 0x152c3d0, resowner = 0x1539d10, cleanup = 0x62f15c
, createSubid = 1, activeSubid = 1, sourceText = 0x1508ef0 "insert into t_insert values(22,'exec_simple_query','exec_simple_query','exec_simple_query');", commandTag = 0xb50908 "INSERT", stmts = 0x15c0408, cplan = 0x0, portalParams = 0x0, queryEnv = 0x0, strategy = PORTAL_MULTI_QUERY, cursorOptions = 4, run_once = false, status = PORTAL_READY, portalPinned = false, autoHeld = false, queryDesc = 0x0, tupDesc = 0x0, formats = 0x0, holdStore = 0x0, holdContext = 0x0, holdSnapshot = 0x0, atStart = true, atEnd = true, portalPos = 0, creation_time = 587101481469205, visible = false}#Receiver1110 receiver = CreateDestReceiver(dest);(gdb) 1111 if (dest == DestRemote)(gdb) p *receiver$42 = {receiveSlot = 0x4857ad
, rStartup = 0x485196
, rShutdown = 0x485bad
, rDestroy = 0x485c21
, mydest = DestRemote}(gdb) #执行...1122 (void) PortalRun(portal,(gdb)...#DONE!(gdb) PostgresMain (argc=1, argv=0x1532aa8, dbname=0x1532990 "testdb", username=0x1532978 "xdb") at postgres.c:41554155 send_ready_for_query = true;

四、小结

1、执行/数据流程:SQL语句->解析树RawStmt>查询结构体Query->规划执行PlannedStmt->执行处理ExecProcNode

2、重要的数据结构:本节重要的数据结构是RawStmt、Portal和Query
3、关键的方法:创建Portal“对象”CreatePortal、语句解析pg_parse_query、语句分析&重写pg_analyze_and_rewrite、规划执行pg_plan_queries、规划执行(每个语句)pg_plan_query

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2374904/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/6906/viewspace-2374904/

你可能感兴趣的文章
Promise API
查看>>
第二章实践小结
查看>>
[Notes] 查看Linux系统支持的shell
查看>>
有道词典的翻译接口
查看>>
代码示例_进程
查看>>
PLSQL数据导入导出问题解决(空表、大字段表、表空间错误等)
查看>>
一个屌丝程序猿的人生(七十六)
查看>>
路由协议
查看>>
统计第一个空字符前面的字符长度(java实现)
查看>>
struts2博客学习之旅
查看>>
阻塞、非阻塞的概念和select函数的阻塞功能
查看>>
在Ubuntu64位加安装H3C的INode客户端软件
查看>>
Centos6系统yum升级安装程序库错误解决方法
查看>>
__tostring()和__invoke()的用法
查看>>
作业6
查看>>
es6中promise的用法
查看>>
实现双向绑定
查看>>
java websocket开发的客户端程序
查看>>
【git】强制覆盖本地代码
查看>>
qt creator转换到 COFF 期间失败: 文件无效或损坏
查看>>