postgres.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,551 行 · 第 1/5 页
C
2,551 行
*/List *pg_rewrite_queries(List *querytree_list){ List *new_list = NIL; List *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 = nconc(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){ 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); 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, bool needSnapshot){ List *plan_list = NIL; List *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) { SetQuerySnapshot(); needSnapshot = false; } plan = pg_plan_query(query); } 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, *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; /* * 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); /* * 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()) { bool allowit = false; if (IsA(parsetree, TransactionStmt)) { TransactionStmt *stmt = (TransactionStmt *) parsetree; if (stmt->kind == TRANS_STMT_COMMIT || stmt->kind == TRANS_STMT_ROLLBACK) allowit = true; } if (!allowit) 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, 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); PortalDefineQuery(portal, query_string, commandTag, querytree_list, plantree_list, MessageContext); /* * Start the portal. No parameters here. */ PortalStart(portal, NULL); /* * 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, FetchStmt)) { FetchStmt *stmt = (FetchStmt *) parsetree; if (!stmt->ismove) { Portal fportal = GetPortalByName(stmt->portalname); if (PortalIsValid(fportal) && (fportal->cursorOptions & CURSOR_OPT_BINARY)) format = 1; /* BINARY */ } } PortalSetResultFormat(portal, 1, &format); /* * Now we can create the destination receiver object. */ receiver = CreateDestReceiver(dest, 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, receiver, receiver, completionTag); (*receiver->rDestroy) (receiver); PortalDrop(portal, false); if (IsA(parsetree, TransactionStmt)) { /* * If this was a transaction control statement, commit it. We * will start a new xact command for the next command (if * any). */ finish_xact_command(); } else if (lnext(parsetree_item) == NIL) { /* * 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. But for compatibility with historical Postgres * behavior, we do not force a transaction boundary between * queries appearing in a single query string. */ finish_xact_command(); } else { /* * We need a CommandCounterIncrement after every query, except * those that start or end a transaction block. */ CommandCounterIncrement(); } /* * Tell client that we're done with this query. Note we emit * exactly one EndCommand report for each raw parsetree, thus one * for each SQL command the client sent, regardless of rewriting. * (But a command aborted by error will not send an EndCommand * report at all.) */ EndCommand(completionTag, dest); } /* end loop over parsetrees */ /* * Close down transaction statement, if one is open. */ finish_xact_command(); /* * If there were no parsetrees, return EmptyQueryResponse message. */ if (!parsetree_list) NullCommand(dest); QueryContext = NULL; /* * Combine processing here as we need to calculate the query duration * in both instances. */ if (save_log_duration || save_log_min_duration_statement != -1) { long usecs; gettimeofday(&stop_t, NULL); if (stop_t.tv_usec < start_t.tv_usec) { stop_t.tv_sec--; stop_t.tv_usec += 1000000; } usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 + (long) (stop_t.tv_usec - start_t.tv_usec); if (save_log_duration) ereport(LOG, (errmsg("duration: %ld.%03ld ms", (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 + (stop_t.tv_usec - start_t.tv_usec) / 1000), (long) (stop_t.tv_usec - start_t.tv_usec) % 1000))); /* * Output a duration_statement to the log if the query has exceeded * the min duration, or if we are to print all durations. */ if (save_log_min_duration_statement == 0 || (save_log_min_duration_statement > 0 && usecs >= save_log_min_duration_statement * 1000)) ereport(LOG, (errmsg("duration: %ld.%03ld ms statement: %s", (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 + (stop_t.tv_usec - start_t.tv_usec) / 1000), (long) (stop_t.tv_usec - start_t.tv_usec) % 1000, query_string))); } if (save_log_statement_stats) ShowUsage("QUERY STATISTICS"); debug_query_string = NULL;}/* * exec_parse_message * * Execute a "Parse" protocol message. */static voidexec_parse_message(const char *query_string, /* string to execute */ const char *stmt_name, /* name for prepared stmt */ Oid *paramTypes, /* parameter types */ int numParams) /* number of parameters */{ MemoryContext oldcontext; List *parsetree_list; const char *commandTag; List *querytree_list, *plantree_list, *param_list; bool is_named; bool save_log_statement_stats = log_statement_stats; /* * Report query to various monitoring facilities. */ debug_query_string = query_string; pgstat_report_activity(query_string); set_ps_display("PARSE"); if (save_log_statement_stats) ResetUsage(); /* * Start up a transaction command so we can run parse analysis etc. * (Note that this will normally change current memory context.) * Nothing happens if we are already in one. */ start_xact_command(); /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?