PostgreSQL中exec_simple_query函数的实现逻辑是什么

网友投稿 362 2024-01-03

PostgreSQL中exec_simple_query函数的实现逻辑是什么

这篇文章主要介绍“PostgreSQL中exec_simple_query函数的实现逻辑是什么”,在日常操作中,相信很多人在PostgreSQL中exec_simple_query函数的实现逻辑是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL中exec_simple_query函数的实现逻辑是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、源码解读

PostgreSQL中exec_simple_query函数的实现逻辑是什么

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

/*  * exec_simple_query  *  * Execute a "simple Query" protocol message.  */ /* 输入:     query_string-SQL语句 输出:     无 */ static void exec_simple_query(constchar *query_string) {     CommandDest dest = whereToSendOutput;//输出到哪里的定义     MemoryContext oldcontext;//存储原内存上下文     List       *parsetree_list;//分析树列表     ListCell   *parsetree_item;//分析树中的ITEMbool        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 doesnt report incorrect      * results because ResetUsage wasnt 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 were 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,                                                 NULL0NULL);//根据分析树获得查询树,返回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(""truetrue);//创建匿名Portal变量         /* Dont display the portal in pg_cursors */         portal->visible = false;         /*          * We dont 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, NULL0, 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 were 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 were 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 statements 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 */      boolhasRowSecurity;/* rewriter has applied some RLS policy */        List       *cteList;        /* WITH list (of CommonTableExprs) */        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 SortGroupClauses */        List       *groupingSets;   /* a list of GroupingSets if present */        Node       *havingQual;     /* qualifications applied to groups */        List       *windowClause;   /* a list of WindowClauses */List       *distinctClause;/* a list of SortGroupClauses */        List       *sortClause;     /* a list of SortGroupClauses */        Node       *limitOffset;    /* # of result tuples to skip (int8 expr) */      Node       *limitCount;     /* # of result tuples to return (int8 expr) */        List       *rowMarks;       /* a list of RowMarkClauses */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 WithCheckOptions, 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;    typedefNode *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref);typedefNode *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var);typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref);  typedefNode *(*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) arent joins.   *   * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that   * will become the fromlist of the querys 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 relations 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 WindowDefs location in   * this list, counting from 1, is the winref number to use to reference it.   *   * p_expr_kind: kind of expression were 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: querys 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 weve 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                                   * nodes 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 querys containing CTE */      Relation    p_target_relation;  /* INSERT/UPDATE/DELETE target rel */      RangeTblEntry *p_target_rangetblentry;  /* target rels 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 were 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;      boolp_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 functions 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 cant 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.   *    Its 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 ORd 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 doesnt 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   *    ANDed 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 (<exprlist>), (<exprlist>), ... */      RTE_CTE,                    /* common table expr (WITH list element) */      RTE_NAMEDTUPLESTORE         /* tuplestore, e.g. for AFTER triggers */  } RTEKind;    typedef struct RangeTblEntry{      NodeTagtype;        RTEKind     rtekind;        /* see above */        /*       * XXX the fields applicable to only some rte kinds should be merged into       * a union.  I didnt 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 Kth 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 joins input relations, or such a Var with an       * implicit coercion to the joins 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 wed 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 isnt an expression node (since it cant   * be evaluated by ExecEvalExpr).  But we treat it as one anyway, since in   * very many places its convenient to process a whole query targetlist as a   * single expression tree.   *   * In a SELECTs targetlist, resno should always be equal to the items   * 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 thats   * 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 columns 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 columns source table */      AttrNumber  resorigcol;     /* columns number in source table */      bool        resjunk;        /* set to true to eliminate the attribute from                                   * final target list */  } TargetEntry;

7、全局变量定义

 bool        log_parser_stats = false;  boollog_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 thisll 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 thats       * not desired, the timeout has to be disabled explicitly.       */      enable_statement_timeout();  }  /*   *  StartTransactionCommand   */  void  StartTransactionCommand(void)  {      TransactionState s = CurrentTransactionState;switch (s->blockState)      {              /*               * if we arent in a transaction block, we just do our usual start               * transaction.               */          caseTBLOCK_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:          caseTBLOCK_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:          caseTBLOCK_SUBABORT:break;                /* These cases are invalid. */          case TBLOCK_STARTED:          case TBLOCK_BEGIN:          caseTBLOCK_PARALLEL_INPROGRESS:case TBLOCK_SUBBEGIN:          case TBLOCK_END:          case TBLOCK_SUBRELEASE:          case TBLOCK_SUBCOMMIT:          caseTBLOCK_ABORT_END:case TBLOCK_SUBABORT_END:          case TBLOCK_ABORT_PENDING:          case TBLOCK_SUBABORT_PENDING:          caseTBLOCK_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, its 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   * weve 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");          elseraw_parsetree_list = new_list;      }#endif        TRACE_POSTGRESQL_QUERY_PARSE_DONE(query_string);        returnraw_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 */          returnNIL;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 were given a RawStmt */          caseT_RawStmt:              tag = CreateCommandTag(((RawStmt *) parsetree)->stmt);break;                /* raw plannable queries */          caseT_InsertStmt:              tag ="INSERT";              break;            case T_DeleteStmt:              tag = "DELETE";              break;            case T_UpdateStmt:              tag = "UPDATE";              break;            caseT_SelectStmt:              tag ="SELECT";              break;                /* utility statements --- same whether raw or cooked */          caseT_TransactionStmt:              {                  TransactionStmt *stmt = (TransactionStmt *) parsetree;switch (stmt->kind)                  {                      caseTRANS_STMT_BEGIN:                          tag ="BEGIN";                          break;                        case TRANS_STMT_START:                          tag = "START TRANSACTION";                          break;                        case TRANS_STMT_COMMIT:                          tag = "COMMIT";                          break;                        caseTRANS_STMT_ROLLBACK:case TRANS_STMT_ROLLBACK_TO:                          tag = "ROLLBACK";                          break;                        caseTRANS_STMT_SAVEPOINT:                          tag ="SAVEPOINT";                          break;                        caseTRANS_STMT_RELEASE:                          tag ="RELEASE";                          break;                        caseTRANS_STMT_PREPARE:                          tag ="PREPARE TRANSACTION";                          break;                        caseTRANS_STMT_COMMIT_PREPARED:                          tag ="COMMIT PREPARED";                          break;                        caseTRANS_STMT_ROLLBACK_PREPARED:                          tag ="ROLLBACK PREPARED";                          break;                        default:                          tag = "-";                          break;                  }              }break;            caseT_DeclareCursorStmt:              tag ="DECLARE CURSOR";              break;            caseT_ClosePortalStmt:              {                  ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;if (stmt->portalname == NULL)                      tag ="CLOSE CURSOR ALL";                  else                      tag = "CLOSE CURSOR";              }              break;            caseT_FetchStmt:              {                  FetchStmt  *stmt = (FetchStmt *) parsetree;                    tag = (stmt->ismove) ?"MOVE" : "FETCH";              }              break;            caseT_CreateDomainStmt:              tag ="CREATE DOMAIN";              break;            caseT_CreateSchemaStmt:              tag ="CREATE SCHEMA";              break;            case T_CreateStmt:              tag = "CREATE TABLE";              break;            case T_CreateTableSpaceStmt:              tag = "CREATE TABLESPACE";              break;            caseT_DropTableSpaceStmt:              tag ="DROP TABLESPACE";              break;            caseT_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;            caseT_CreateFdwStmt:              tag ="CREATE FOREIGN DATA WRAPPER";              break;            caseT_AlterFdwStmt:              tag ="ALTER FOREIGN DATA WRAPPER";              break;            caseT_CreateForeignServerStmt:              tag ="CREATE SERVER";              break;            case T_AlterForeignServerStmt:              tag = "ALTER SERVER";              break;            case T_CreateUserMappingStmt:              tag = "CREATE USER MAPPING";              break;            caseT_AlterUserMappingStmt:              tag ="ALTER USER MAPPING";              break;            caseT_DropUserMappingStmt:              tag ="DROP USER MAPPING";              break;            caseT_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;                  caseOBJECT_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;                  caseOBJECT_TYPE:                      tag ="DROP TYPE";                      break;                  case OBJECT_DOMAIN:                      tag = "DROP DOMAIN";                      break;                  case OBJECT_COLLATION:                      tag = "DROP COLLATION";                      break;                  caseOBJECT_CONVERSION:                      tag ="DROP CONVERSION";                      break;                  caseOBJECT_SCHEMA:                      tag ="DROP SCHEMA";                      break;                  caseOBJECT_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;                  caseOBJECT_FUNCTION:                      tag ="DROP FUNCTION";                      break;                  caseOBJECT_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;                  caseOBJECT_LANGUAGE:                      tag ="DROP LANGUAGE";                      break;                  caseOBJECT_CAST:                      tag ="DROP CAST";                      break;                  case OBJECT_TRIGGER:                      tag = "DROP TRIGGER";                      break;                  caseOBJECT_EVENT_TRIGGER:                      tag ="DROP EVENT TRIGGER";                      break;                  caseOBJECT_RULE:                      tag ="DROP RULE";                      break;                  caseOBJECT_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;                  caseOBJECT_POLICY:                      tag ="DROP POLICY";                      break;                  caseOBJECT_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;            caseT_TruncateStmt:              tag ="TRUNCATE TABLE";              break;            case T_CommentStmt:              tag = "COMMENT";              break;            caseT_SecLabelStmt:              tag ="SECURITY LABEL";              break;            caseT_CopyStmt:              tag ="COPY";              break;            caseT_RenameStmt:              tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);break;            caseT_AlterObjectDependsStmt:              tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);break;            caseT_AlterObjectSchemaStmt:              tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);break;            caseT_AlterOwnerStmt:              tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);break;            caseT_AlterTableMoveAllStmt:              tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);break;            caseT_AlterTableStmt:              tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);break;            case T_AlterDomainStmt:              tag = "ALTER DOMAIN";              break;            case T_AlterFunctionStmt:              switch(((AlterFunctionStmt *) parsetree)->objtype)              {caseOBJECT_FUNCTION:                      tag ="ALTER FUNCTION";                      break;                  caseOBJECT_PROCEDURE:                      tag ="ALTER PROCEDURE";                      break;                  case OBJECT_ROUTINE:                      tag = "ALTER ROUTINE";                      break;default:                      tag = "-";              }              break;            caseT_GrantStmt:              {                  GrantStmt  *stmt = (GrantStmt *) parsetree;                    tag = (stmt->is_grant) ?"GRANT" : "REVOKE";              }              break;            caseT_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;                  caseOBJECT_OPERATOR:                      tag ="CREATE OPERATOR";                      break;                  caseOBJECT_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;                  caseOBJECT_ACCESS_METHOD:                      tag ="CREATE ACCESS METHOD";                      break;                  default:                      tag ="-";              }              break;            caseT_CompositeTypeStmt:              tag ="CREATE TYPE";              break;            case T_CreateEnumStmt:              tag = "CREATE TYPE";              break;case T_CreateRangeStmt:              tag = "CREATE TYPE";              break;            caseT_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;            caseT_IndexStmt:              tag ="CREATE INDEX";              break;            case T_RuleStmt:              tag = "CREATE RULE";              break;            caseT_CreateSeqStmt:              tag ="CREATE SEQUENCE";              break;            caseT_AlterSeqStmt:              tag ="ALTER SEQUENCE";              break;            case T_DoStmt:              tag = "DO";              break;            caseT_CreatedbStmt:              tag ="CREATE DATABASE";              break;            case T_AlterDatabaseStmt:              tag = "ALTER DATABASE";              break;            case T_AlterDatabaseSetStmt:              tag = "ALTER DATABASE";              break;            caseT_DropdbStmt:              tag ="DROP DATABASE";              break;            caseT_NotifyStmt:              tag ="NOTIFY";              break;            case T_ListenStmt:              tag = "LISTEN";              break;            caseT_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;                  caseOBJECT_MATVIEW:                      tag ="CREATE MATERIALIZED VIEW";                      break;                  default:                      tag = "-";              }break;            case T_RefreshMatViewStmt:              tag = "REFRESH MATERIALIZED VIEW";              break;            case T_AlterSystemStmt:              tag = "ALTER SYSTEM";              break;            caseT_VariableSetStmt:switch (((VariableSetStmt *) parsetree)->kind)              {                  case VAR_SET_VALUE:                  caseVAR_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;            caseT_VariableShowStmt:              tag ="SHOW";              break;            case T_DiscardStmt:              switch(((DiscardStmt *) parsetree)->target)              {case DISCARD_ALL:                      tag = "DISCARD ALL";                      break;                  caseDISCARD_PLANS:                      tag ="DISCARD PLANS";                      break;                  caseDISCARD_TEMP:                      tag ="DISCARD TEMP";                      break;                  case DISCARD_SEQUENCES:                      tag = "DISCARD SEQUENCES";break;                  default:                      tag = "-";              }              break;            caseT_CreateTransformStmt:              tag ="CREATE TRANSFORM";              break;            caseT_CreateTrigStmt:              tag ="CREATE TRIGGER";              break;            case T_CreateEventTrigStmt:              tag = "CREATE EVENT TRIGGER";              break;            case T_AlterEventTrigStmt:              tag = "ALTER EVENT TRIGGER";              break;            caseT_CreatePLangStmt:              tag ="CREATE LANGUAGE";              break;            caseT_CreateRoleStmt:              tag ="CREATE ROLE";              break;            case T_AlterRoleStmt:              tag = "ALTER ROLE";              break;            case T_AlterRoleSetStmt:              tag = "ALTER ROLE";              break;            caseT_DropRoleStmt:              tag ="DROP ROLE";              break;            case T_DropOwnedStmt:              tag = "DROP OWNED";              break;            case T_ReassignOwnedStmt:              tag = "REASSIGN OWNED";              break;            caseT_LockStmt:              tag ="LOCK TABLE";              break;            case T_ConstraintsSetStmt:              tag = "SET CONSTRAINTS";              break;            case T_CheckPointStmt:              tag = "CHECKPOINT";              break;            caseT_ReindexStmt:              tag ="REINDEX";              break;            case T_CreateConversionStmt:              tag = "CREATE CONVERSION";              break;            case T_CreateCastStmt:              tag = "CREATE CAST";              break;            caseT_CreateOpClassStmt:              tag ="CREATE OPERATOR CLASS";              break;            caseT_CreateOpFamilyStmt:              tag ="CREATE OPERATOR FAMILY";              break;            caseT_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;            caseT_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;            caseT_CreateSubscriptionStmt:              tag ="CREATE SUBSCRIPTION";              break;            caseT_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;            caseT_ExecuteStmt:              tag ="EXECUTE";              break;            case T_CreateStatsStmt:              tag = "CREATE STATISTICS";              break;            caseT_DeallocateStmt:              {                  DeallocateStmt *stmt = (DeallocateStmt *) parsetree;if (stmt->name == NULL)                      tag = "DEALLOCATE ALL";                  else                      tag = "DEALLOCATE";              }              break;                /* already-planned queries */          caseT_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;                      caseCMD_UPDATE:                          tag ="UPDATE";                          break;                      caseCMD_INSERT:                          tag ="INSERT";                          break;                      case CMD_DELETE:                          tag = "DELETE";                          break;                      caseCMD_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 */          caseT_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)                              {caseLCS_FORKEYSHARE:                                      tag ="SELECT FOR KEY SHARE";                                      break;                                  caseLCS_FORSHARE:                                      tag ="SELECT FOR SHARE";                                      break;                                  caseLCS_FORNOKEYUPDATE:                                      tag ="SELECT FOR NO KEY UPDATE";                                      break;                                  caseLCS_FORUPDATE:                                      tag ="SELECT FOR UPDATE";                                      break;                                  default:                                      tag = "-";break;                              }                          }                          else                              tag = "SELECT";                          break;                      case CMD_UPDATE:                          tag = "UPDATE";                          break;                      caseCMD_INSERT:                          tag ="INSERT";                          break;                      case CMD_DELETE:                          tag = "DELETE";                          break;                      caseCMD_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:          caseT_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 dont 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,constchar *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, constchar *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 dont 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;/* Were 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 dont do in transformStmt() is to   * convert SELECT ... INTO into CREATE TABLE AS.  Since utility statements   * arent 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.   */  staticQuery *  transformOptionalSelectInto(ParseState *pstate, Node *parseTree)  {if(IsA(parseTree, SelectStmt))      {          SelectStmt *stmt = (SelectStmt *) parseTree;/* If its 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 cant just run it on everything because raw_expression_tree_walker()       * doesnt claim to handle utility statements.       */  #ifdef RAW_EXPRESSION_COVERAGE_TEST      switch (nodeTag(parseTree))      {          case T_SelectStmt:          caseT_InsertStmt:case T_UpdateStmt:          caseT_DeleteStmt:              (void) test_raw_expression_coverage(parseTree,NULL);              break;          default:              break;      }  #endif                          /* RAW_EXPRESSION_COVERAGE_TEST */        switch (nodeTag(parseTree))      {              /*               * Optimizable statements               */          caseT_InsertStmt:              result = transformInsertStmt(pstate, (InsertStmt *) parseTree);break;            caseT_DeleteStmt:              result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);break;            caseT_UpdateStmt:              result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);break;            caseT_SelectStmt:              {                  SelectStmt *n = (SelectStmt *) parseTree;if(n->valuesLists)                      result = transformValuesClause(pstate, n);else if(n->op == SETOP_NONE)                      result = transformSelectStmt(pstate, n);elseresult = transformSetOperationStmt(pstate, n);              }break;                /*               * Special cases               */          caseT_DeclareCursorStmt:              result = transformDeclareCursorStmt(pstate,                                                  (DeclareCursorStmt *) parseTree);break;            caseT_ExplainStmt:              result = transformExplainStmt(pstate,                                            (ExplainStmt *) parseTree);break;            caseT_CreateTableAsStmt:              result = transformCreateTableAsStmt(pstate,                                                  (CreateTableAsStmt *) parseTree);break;            caseT_CallStmt:              result = transformCallStmt(pstate,                                         (CallStmt *) parseTree);break;            default:                /*               * other statements dont 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   */  staticQuery *  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 cant 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 cant 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 rules OLD and NEW rtable entries to appear as       * part of the SELECTs rtable, not as outer references for it.  (Kluge!)       * The SELECTs joinlist is not affected however.  We must do this before       * adding the target table to the INSERTs 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,falsefalse, 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           * pstates rtable and namespace are presently empty, there are no           * side-effects of exposing names the sub-SELECT shouldnt 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 columns 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 INSERTs rangetable, and add           * it to the INSERTs 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.  (INSERTs tlist must be           * separate from the subquerys tlist because we may add columns,           * insert datatype coercions, etc.)           *           * HACK: unknown-type constants and params in the SELECTs 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 columns 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 cant 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 dont               * want the parsed statement to contain copies of those in each               * VALUES row.  (Its 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               * doesnt process rangetable entries.  We just assign all the               * collations independently in each row, and dont worry about               * whether they are consistent vertically.  The outer INSERT query               * isnt going to care about the collations of the VALUES columns,               * so its not worth the effort to identify a common collation for               * each one here.  (But note this does have one user-visible               * consequence: INSERT ... VALUES wont 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 its sufficient           * to look at the exprType/exprTypmod of the first row.  We dont 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 cant be any current-level Vars in the expression           * lists, because the namespace was empty ... but if were 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-1falseNULL, &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 Querys 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 querys 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,falsetruetrue);          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);returnqry;  }

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           * dont 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 youd 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);      returnresult;  }

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, dont even emit a WARNING.   */  Portal  CreatePortal(const char*name,bool allowDup, booldupSilent)  {      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 wont 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 dont 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 portals query.   *   * Notes: as of PG 8.4, caller MUST supply a sourceText string; it is not   * allowed anymore to pass NULL.  (If you really dont 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 callers responsibility to ensure that   * the passed plan trees have adequate lifetime.  Typically this is done by   * copying them into the portals context.   *   * The caller is also responsible for ensuring that the passed prepStmtName   * (if not NULL) and sourceText have adequate lifetime.   *   * NB: this function mustnt do much beyond storing the passed values; in   * particular dont do anything that risks elog(ERROR).  If that were to   * happen here before storing the cplan reference, wed leak the plancache   * refcount that the caller is trying to hand off to us.   */  void  PortalDefineQuery(Portal portal,                    constchar *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 (its 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 portals 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 its a scrollable cursor, executor needs to support                   * REWIND and backwards scan, as well as whatever the caller                   * mightve 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 dont 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 dont 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 portals 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 wont 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)      {          caseDestRemote:case DestRemoteExecute:              return printtup_create_DR(dest);            case DestRemoteSimple:              return &printsimpleDR;            case DestNone:              return &donothingDR;            case DestDebug:              return &debugtupDR;            case DestSPI:              return &spi_printtupDR;            caseDestTuplestore:return CreateTuplestoreDestReceiver();            case DestIntoRel:              return CreateIntoRelDestReceiver(NULL);            case DestCopyOut:              return CreateCopyDestReceiver();            case DestSQLFunction:              returnCreateSQLFunctionDestReceiver();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));/*       * Dont allow dropping a pinned portal, its 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.  Its the cleanup       * hooks 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.  Were 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 theres 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 portals       * 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), wed better clean up       * its resources to avoid resource-leakage warning messages.       *       * Sub transaction commit: never comes here at all, since we dont 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 transactions ResourceOwner (since it is the       * parent of the portals 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 (its in TopPortalContext) */      pfree(portal);  }

17、EndImplicitTransactionBlock

 /*   * EndImplicitTransactionBlock   *      End an implicit transaction block, if were 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();    #ifdefMEMORY_CONTEXT_CHECKING          /* Check all memory contexts that werent freed during commit */          /* (those that were, were checked before being deleted) */          MemoryContextCheck(TopMemoryContext);  #endif    #ifdefSHOW_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 hasnt been "used" to mark       * tuples, we need not increment it, since theres 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 cant 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 dont need to do this after a           * read-only command.  (But see hacks in inval.c to make real sure we           * dont 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:          caseDestRemoteSimple:/*               * 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:          caseDestIntoRel:case DestCopyOut:          case DestSQLFunction:          case DestTransientRel:          case DestTupleQueue:              break;      }  }三、跟踪分析

插入测试数据:

testdb=# -- 获取pid testdb=# selectpg_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 1893 GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7 Copyright (C) 2013 Free Software Foundation, Inc. ... (gdb) b exec_simple_query Breakpoint 1 at 0x84cad8: file postgres.c, line 893. (gdb) c Continuing. 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:893 893     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 <AllocSetMethods>, parent = 0x1503ba0, firstchild = 0x0, prevchild = 0x157c3c0, nextchild = 0x15956d0,    name = 0xb4e87c "MessageContext", ident = 0x0, reset_cbs = 0x0} (gdb) n 944     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 <AllocSetMethods>, parent = 0x1503ba0, firstchild = 0x0, prevchild = 0x0, nextchild = 0x157c3c0,    name = 0xa1b4ff "TopTransactionContext", ident = 0x0, reset_cbs = 0x0} (gdb) step pg_parse_query (query_string=0x1508ef0 "insert into t_insert values(22,exec_simple_query,exec_simple_query,exec_simple_query);") at postgres.c:615 615     if (log_parser_stats) (gdb)  618     raw_parsetree_list = raw_parser(query_string); #进入raw_parser (gdb) step raw_parser (str=0x1508ef0 "insert into t_insert values(22,exec_simple_query,exec_simple_query,exec_simple_query);") at parser.c:43 43      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 <ScanKeywords>,      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 <Address 0x300990000 out of bounds>, keyword = 0x300990000 <Address 0x300990000 out of bounds>}, 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:947 947     if (check_log_statement(parsetree_list)) ... #解析树只有一个元素 (gdb) n 974     foreach(parsetree_item, parsetree_list) (gdb) p list_length(parsetree_list) $30 = 1 (gdb) n 976         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) n 992         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) step pg_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:663 663     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:1050 1050            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 <PortalCleanup>, 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) n 1073            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 <PortalCleanup>, 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} #Receiver 1110            receiver = CreateDestReceiver(dest); (gdb)  1111            if (dest == DestRemote) (gdb) p *receiver $42 = {receiveSlot = 0x4857ad <printtup>, rStartup = 0x485196 <printtup_startup>, rShutdown = 0x485bad <printtup_shutdown>, rDestroy = 0x485c21 <printtup_destroy>, mydest = DestRemote} (gdb)  #执行 ... 1122            (void) PortalRun(portal, (gdb) ... #DONE! (gdb)  PostgresMain (argc=1, argv=0x1532aa8, dbname=0x1532990 "testdb", username=0x1532978 "xdb") at postgres.c:4155 4155                        send_ready_for_query = true;

到此,关于“PostgreSQL中exec_simple_query函数的实现逻辑是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:hash join构建位图的示例分析
下一篇:怎么理解Oracle表压缩
相关文章

 发表评论

暂时没有评论,来抢沙发吧~