postgres.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,390 行 · 第 1/5 页
C
2,390 行
List *querytree_list; ListCell *list_item; /* * (1) parse the request string into a list of raw parse trees. */ raw_parsetree_list = pg_parse_query(query_string); /* * (2) Do parse analysis and rule rewrite. */ querytree_list = NIL; foreach(list_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(list_item); querytree_list = list_concat(querytree_list, pg_analyze_and_rewrite(parsetree, paramTypes, numParams)); } return querytree_list;}/* * Do raw parsing (only). * * A list of parsetrees is returned, since there might be multiple * commands in the given string. * * NOTE: for interactive queries, it is important to keep this routine * separate from the analysis & rewrite stages. Analysis and rewriting * cannot be done in an aborted transaction, since they require access to * database tables. So, we rely on the raw parser to determine whether * we've seen a COMMIT or ABORT command; when we are in abort state, other * commands are not processed any further than the raw parse stage. */List *pg_parse_query(const char *query_string){ List *raw_parsetree_list; if (log_parser_stats) ResetUsage(); raw_parsetree_list = raw_parser(query_string); if (log_parser_stats) ShowUsage("PARSER STATISTICS"); return raw_parsetree_list;}static boollog_after_parse(List *raw_parsetree_list, const char *query_string, char **prepare_string){ ListCell *parsetree_item; bool log_this_statement = (log_statement == LOGSTMT_ALL); *prepare_string = NULL; /* Check if we need to log the statement, and get prepare_string. */ foreach(parsetree_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(parsetree_item); const char *commandTag; if (IsA(parsetree, ExplainStmt) && ((ExplainStmt *) parsetree)->analyze) parsetree = (Node *) (((ExplainStmt *) parsetree)->query); if (IsA(parsetree, PrepareStmt)) parsetree = (Node *) (((PrepareStmt *) parsetree)->query); if (IsA(parsetree, SelectStmt) && ((SelectStmt *) parsetree)->into == NULL) continue; /* optimization for frequent command */ if (log_statement == LOGSTMT_MOD && (IsA(parsetree, InsertStmt) || IsA(parsetree, UpdateStmt) || IsA(parsetree, DeleteStmt) || IsA(parsetree, TruncateStmt) || (IsA(parsetree, CopyStmt) && ((CopyStmt *) parsetree)->is_from))) /* COPY FROM */ log_this_statement = true; commandTag = CreateCommandTag(parsetree); if ((log_statement == LOGSTMT_MOD || log_statement == LOGSTMT_DDL) && (strncmp(commandTag, "CREATE ", strlen("CREATE ")) == 0 || IsA(parsetree, SelectStmt) || /* SELECT INTO, CREATE AS */ strncmp(commandTag, "ALTER ", strlen("ALTER ")) == 0 || strncmp(commandTag, "DROP ", strlen("DROP ")) == 0 || IsA(parsetree, GrantStmt) || /* GRANT or REVOKE */ IsA(parsetree, CommentStmt))) log_this_statement = true; /* * For the first EXECUTE we find, record the client statement used by * the PREPARE. PREPARE doesn't save the parse tree so we have no * way to conditionally output based on the type of query prepared. */ if (IsA(parsetree, ExecuteStmt)) { ExecuteStmt *stmt = (ExecuteStmt *) parsetree; PreparedStatement *entry; if (*prepare_string == NULL && (entry = FetchPreparedStatement(stmt->name, false)) != NULL && entry->query_string) { *prepare_string = palloc(strlen(entry->query_string) + strlen(" [PREPARE: %s]") - 2 + 1); sprintf(*prepare_string, " [PREPARE: %s]", entry->query_string); } } } if (log_this_statement) { ereport(LOG, (errmsg("statement: %s%s", query_string, *prepare_string ? *prepare_string : ""))); return true; } else return false;}/* * 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(Node *parsetree, Oid *paramTypes, int numParams){ List *querytree_list; /* * (1) Perform parse analysis. */ if (log_parser_stats) ResetUsage(); querytree_list = parse_analyze(parsetree, paramTypes, numParams); if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); /* * (2) Rewrite the queries, as necessary */ querytree_list = pg_rewrite_queries(querytree_list); return querytree_list;}/* * Perform rewriting of a list of queries produced by parse analysis. * * Note: queries must just have come from the parser, because we do not do * AcquireRewriteLocks() on them. */static List *pg_rewrite_queries(List *querytree_list){ List *new_list = NIL; ListCell *list_item; if (log_parser_stats) ResetUsage(); /* * rewritten queries are collected in new_list. Note there may be more or * fewer than in the original list. */ foreach(list_item, querytree_list) { Query *querytree = (Query *) lfirst(list_item); if (Debug_print_parse) elog_node_display(DEBUG1, "parse tree", querytree, Debug_pretty_print); if (querytree->commandType == CMD_UTILITY) { /* don't rewrite utilities, just dump 'em into new_list */ new_list = lappend(new_list, querytree); } else { /* rewrite regular queries */ List *rewritten = QueryRewrite(querytree); new_list = list_concat(new_list, rewritten); } } querytree_list = new_list; if (log_parser_stats) ShowUsage("REWRITER STATISTICS");#ifdef COPY_PARSE_PLAN_TREES /* * Optional debugging check: pass querytree output through copyObject() */ new_list = (List *) copyObject(querytree_list); /* This checks both copyObject() and the equal() routines... */ if (!equal(new_list, querytree_list)) elog(WARNING, "copyObject() failed to produce an equal parse tree"); else querytree_list = new_list;#endif if (Debug_print_rewritten) elog_node_display(DEBUG1, "rewritten parse tree", querytree_list, Debug_pretty_print); return querytree_list;}/* Generate a plan for a single already-rewritten query. */Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams){ Plan *plan; /* Utility commands have no plans. */ if (querytree->commandType == CMD_UTILITY) return NULL; if (log_planner_stats) ResetUsage(); /* call the optimizer */ plan = planner(querytree, false, 0, boundParams); if (log_planner_stats) ShowUsage("PLANNER STATISTICS");#ifdef COPY_PARSE_PLAN_TREES /* Optional debugging check: pass plan output through copyObject() */ { Plan *new_plan = (Plan *) copyObject(plan); /* * equal() currently does not have routines to compare Plan nodes, so * don't try to test equality here. Perhaps fix someday? */#ifdef NOT_USED /* This checks both copyObject() and the equal() routines... */ if (!equal(new_plan, plan)) elog(WARNING, "copyObject() failed to produce an equal plan tree"); else#endif plan = new_plan; }#endif /* * Print plan if debugging. */ if (Debug_print_plan) elog_node_display(DEBUG1, "plan", plan, Debug_pretty_print); return plan;}/* * Generate plans for a list of already-rewritten queries. * * If needSnapshot is TRUE, we haven't yet set a snapshot for the current * query. A snapshot must be set before invoking the planner, since it * might try to evaluate user-defined functions. But we must not set a * snapshot if the list contains only utility statements, because some * utility statements depend on not having frozen the snapshot yet. * (We assume that such statements cannot appear together with plannable * statements in the rewriter's output.) */List *pg_plan_queries(List *querytrees, ParamListInfo boundParams, bool needSnapshot){ List *plan_list = NIL; ListCell *query_list; foreach(query_list, querytrees) { Query *query = (Query *) lfirst(query_list); Plan *plan; if (query->commandType == CMD_UTILITY) { /* Utility commands have no plans. */ plan = NULL; } else { if (needSnapshot) { ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); needSnapshot = false; } plan = pg_plan_query(query, boundParams); } plan_list = lappend(plan_list, plan); } return plan_list;}/* * exec_simple_query * * Execute a "simple Query" protocol message. */static voidexec_simple_query(const char *query_string){ CommandDest dest = whereToSendOutput; MemoryContext oldcontext; List *parsetree_list; ListCell *parsetree_item; struct timeval start_t, stop_t; bool save_log_duration = log_duration; int save_log_min_duration_statement = log_min_duration_statement; bool save_log_statement_stats = log_statement_stats; char *prepare_string = NULL; bool was_logged = false; /* * Report query to various monitoring facilities. */ debug_query_string = query_string; pgstat_report_activity(query_string); /* * We use save_log_* so "SET log_duration = true" and "SET * log_min_duration_statement = true" don't report incorrect time because * gettimeofday() wasn't called. Similarly, log_statement_stats has to be * captured once. */ if (save_log_duration || save_log_min_duration_statement != -1) gettimeofday(&start_t, NULL); 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.) */ unnamed_stmt_pstmt = NULL; if (unnamed_stmt_context) { DropDependentPortals(unnamed_stmt_context); MemoryContextDelete(unnamed_stmt_context); } unnamed_stmt_context = NULL; /* * Switch to appropriate context for constructing parsetrees. */ oldcontext = MemoryContextSwitchTo(MessageContext); QueryContext = CurrentMemoryContext; /* * 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); if (log_statement != LOGSTMT_NONE || save_log_min_duration_statement != -1) was_logged = log_after_parse(parsetree_list, query_string, &prepare_string); /* * Switch back to transaction context to enter the loop. */ MemoryContextSwitchTo(oldcontext); /* * Run through the raw parsetree(s) and process each one. */ foreach(parsetree_item, parsetree_list) { Node *parsetree = (Node *) lfirst(parsetree_item); const char *commandTag; char completionTag[COMPLETION_TAG_BUFSIZE]; List *querytree_list, *plantree_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); set_ps_display(commandTag); BeginCommand(commandTag, dest); /* * 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)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " "commands ignored until end of transaction block"))); /* Make sure we are in a transaction command */ start_xact_command(); /* If we got a cancel signal in parsing or prior command, quit */ CHECK_FOR_INTERRUPTS(); /* * 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, NULL, 0); plantree_list = pg_plan_queries(querytree_list, NULL, true); /* If we got a cancel signal in analysis or planning, quit */ CHECK_FOR_INTERRUPTS(); /* * Create unnamed portal to run the query or queries in. If there * already is one, silently drop it. */ portal = CreatePortal("", true, true);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?