diff options
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 181 |
1 files changed, 85 insertions, 96 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 95cf984772..a4f4884372 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4,7 +4,7 @@ * POSTGRES C Backend Interface * * Portions Copyright (c) 2012-2014, TransLattice, Inc. - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 2010-2012 Postgres-XC Development Group * @@ -202,8 +202,8 @@ static int errdetail_recovery_conflict(void); static void start_xact_command(void); static void finish_xact_command(void); static bool IsTransactionExitStmt(Node *parsetree); -static bool IsTransactionExitStmtList(List *parseTrees); -static bool IsTransactionStmtList(List *parseTrees); +static bool IsTransactionExitStmtList(List *pstmts); +static bool IsTransactionStmtList(List *pstmts); static void drop_unnamed_stmt(void); static void SigHupHandler(SIGNAL_ARGS); static void log_disconnections(int code, Datum arg); @@ -732,8 +732,8 @@ ProcessClientWriteInterrupt(bool blocked) /* * Do raw parsing (only). * - * A list of parsetrees is returned, since there might be multiple - * commands in the given string. + * 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 @@ -760,7 +760,7 @@ pg_parse_query_internal(const char *query_string, List **querysource_list) #ifdef COPY_PARSE_PLAN_TREES /* Optional debugging check: pass raw parsetrees through copyObject() */ { - List *new_list = (List *) copyObject(raw_parsetree_list); + List *new_list = copyObject(raw_parsetree_list); /* This checks both copyObject() and the equal() routines... */ if (!equal(new_list, raw_parsetree_list)) @@ -797,8 +797,9 @@ pg_parse_query_get_source(const char *query_string, List **querysource_list) * NOTE: for reasons mentioned above, this must be separate from raw parsing. */ List * -pg_analyze_and_rewrite(Node *parsetree, const char *query_string, - Oid *paramTypes, int numParams) +pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, + Oid *paramTypes, int numParams, + QueryEnvironment *queryEnv) { Query *query; List *querytree_list; @@ -811,7 +812,8 @@ pg_analyze_and_rewrite(Node *parsetree, const char *query_string, if (log_parser_stats) ResetUsage(); - query = parse_analyze(parsetree, query_string, paramTypes, numParams); + query = parse_analyze(parsetree, query_string, paramTypes, numParams, + queryEnv); if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); @@ -832,10 +834,11 @@ pg_analyze_and_rewrite(Node *parsetree, const char *query_string, * hooks instead of a fixed list of parameter datatypes. */ List * -pg_analyze_and_rewrite_params(Node *parsetree, +pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, - void *parserSetupArg) + void *parserSetupArg, + QueryEnvironment *queryEnv) { ParseState *pstate; Query *query; @@ -853,6 +856,7 @@ pg_analyze_and_rewrite_params(Node *parsetree, pstate = make_parsestate(NULL); pstate->p_sourcetext = query_string; + pstate->p_queryEnv = queryEnv; (*parserSetup) (pstate, parserSetupArg); query = transformTopLevelStmt(pstate, parsetree); @@ -925,7 +929,7 @@ pg_rewrite_query(Query *query) { List *new_list; - new_list = (List *) copyObject(querytree_list); + new_list = copyObject(querytree_list); /* This checks both copyObject() and the equal() routines... */ if (!equal(new_list, querytree_list)) elog(WARNING, "copyObject() failed to produce equal parse tree"); @@ -972,7 +976,7 @@ pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams) #ifdef COPY_PARSE_PLAN_TREES /* Optional debugging check: pass plan output through copyObject() */ { - PlannedStmt *new_plan = (PlannedStmt *) copyObject(plan); + PlannedStmt *new_plan = copyObject(plan); /* * equal() currently does not have routines to compare Plan nodes, so @@ -1002,8 +1006,10 @@ pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams) /* * Generate plans for a list of already-rewritten queries. * - * Normal optimizable statements generate PlannedStmt entries in the result - * list. Utility statements are simply represented by their statement nodes. + * 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) @@ -1013,17 +1019,22 @@ pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams) foreach(query_list, querytrees) { - Query *query = (Query *) lfirst(query_list); - Node *stmt; + Query *query = lfirst_node(Query, query_list); + PlannedStmt *stmt; if (query->commandType == CMD_UTILITY) { - /* Utility commands have no plans. */ - stmt = query->utilityStmt; + /* 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 = (Node *) pg_plan_query(query, cursorOptions, boundParams); + stmt = pg_plan_query(query, cursorOptions, boundParams); } stmt_list = lappend(stmt_list, stmt); @@ -1164,7 +1175,7 @@ exec_simple_query(const char *query_string) */ forboth(parsetree_item, parsetree_list, querysource_item, querysource_list) { - Node *parsetree = (Node *) lfirst(parsetree_item); + RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item); char *querysource = (char *) lfirst(querysource_item); bool snapshot_set = false; const char *commandTag; @@ -1190,7 +1201,7 @@ exec_simple_query(const char *query_string) * do any special start-of-SQL-command processing needed by the * destination. */ - commandTag = CreateCommandTag(parsetree); + commandTag = CreateCommandTag(parsetree->stmt); set_ps_display(commandTag, false); @@ -1205,7 +1216,7 @@ exec_simple_query(const char *query_string) * state, but not many...) */ if (IsAbortedTransactionBlockState() && - !IsTransactionExitStmt(parsetree)) + !IsTransactionExitStmt(parsetree->stmt)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " @@ -1236,7 +1247,7 @@ exec_simple_query(const char *query_string) oldcontext = MemoryContextSwitchTo(MessageContext); querytree_list = pg_analyze_and_rewrite(parsetree, query_string, - NULL, 0); + NULL, 0, NULL); plantree_list = pg_plan_queries(querytree_list, CURSOR_OPT_PARALLEL_OK, NULL); @@ -1312,9 +1323,9 @@ exec_simple_query(const char *query_string) * backward compatibility...) */ format = 0; /* TEXT is default */ - if (IsA(parsetree, FetchStmt)) + if (IsA(parsetree->stmt, FetchStmt)) { - FetchStmt *stmt = (FetchStmt *) parsetree; + FetchStmt *stmt = (FetchStmt *) parsetree->stmt; if (!stmt->ismove) { @@ -1345,6 +1356,7 @@ exec_simple_query(const char *query_string) (void) PortalRun(portal, FETCH_ALL, isTopLevel, + true, receiver, receiver, completionTag); @@ -1353,7 +1365,7 @@ exec_simple_query(const char *query_string) PortalDrop(portal, false); - if (IsA(parsetree, TransactionStmt)) + if (IsA(parsetree->stmt, TransactionStmt)) { /* * If this was a transaction control statement, commit it. We will @@ -1451,7 +1463,7 @@ exec_parse_message(const char *query_string, /* string to execute */ MemoryContext unnamed_stmt_context = NULL; MemoryContext oldcontext; List *parsetree_list; - Node *raw_parse_tree; + RawStmt *raw_parse_tree; const char *commandTag; List *querytree_list; CachedPlanSource *psrc; @@ -1510,9 +1522,7 @@ exec_parse_message(const char *query_string, /* string to execute */ unnamed_stmt_context = AllocSetContextCreate(MessageContext, "unnamed prepared statement", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(unnamed_stmt_context); } @@ -1555,12 +1565,12 @@ exec_parse_message(const char *query_string, /* string to execute */ bool snapshot_set = false; int i; - raw_parse_tree = (Node *) linitial(parsetree_list); + raw_parse_tree = linitial_node(RawStmt, parsetree_list); /* * Get the command name for possible use in status display. */ - commandTag = CreateCommandTag(raw_parse_tree); + commandTag = CreateCommandTag(raw_parse_tree->stmt); /* * If we are in an aborted transaction, reject all commands except @@ -1571,7 +1581,7 @@ exec_parse_message(const char *query_string, /* string to execute */ * state, but not many...) */ if (IsAbortedTransactionBlockState() && - !IsTransactionExitStmt(raw_parse_tree)) + !IsTransactionExitStmt(raw_parse_tree->stmt)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " @@ -1984,7 +1994,8 @@ exec_bind_message(StringInfo input_message) * functions. */ if (IsAbortedTransactionBlockState() && - (!IsTransactionExitStmt(psrc->raw_parse_tree) || + (!(psrc->raw_parse_tree && + IsTransactionExitStmt(psrc->raw_parse_tree->stmt)) || numParams != 0)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), @@ -2192,7 +2203,7 @@ exec_bind_message(StringInfo input_message) * will be generated in MessageContext. The plan refcount will be * assigned to the Portal, so it will be released at portal destruction. */ - cplan = GetCachedPlan(psrc, params, false); + cplan = GetCachedPlan(psrc, params, false, NULL); /* * Now we can define the portal. @@ -2409,6 +2420,7 @@ exec_execute_message(const char *portal_name, long max_rows) completed = PortalRun(portal, max_rows, true, /* always top level */ + !execute_is_fetch && max_rows == FETCH_ALL, receiver, receiver, completionTag); @@ -2576,11 +2588,11 @@ errdetail_execute(List *raw_parsetree_list) foreach(parsetree_item, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(parsetree_item); + RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item); - if (IsA(parsetree, ExecuteStmt)) + if (IsA(parsetree->stmt, ExecuteStmt)) { - ExecuteStmt *stmt = (ExecuteStmt *) parsetree; + ExecuteStmt *stmt = (ExecuteStmt *) parsetree->stmt; PreparedStatement *pstmt; pstmt = FetchPreparedStatement(stmt->name, false); @@ -2793,7 +2805,7 @@ exec_describe_statement_message(const char *stmt_name) List *tlist; /* Get the plan's primary targetlist */ - tlist = CachedPlanGetTargetList(psrc); + tlist = CachedPlanGetTargetList(psrc, NULL); SendRowDescriptionMessage(psrc->resultDesc, tlist, NULL); } @@ -2863,8 +2875,6 @@ start_xact_command(void) { if (!xact_started) { - ereport(DEBUG3, - (errmsg_internal("StartTransactionCommand"))); StartTransactionCommand(); /* Set statement timeout running, if any */ @@ -2886,10 +2896,6 @@ finish_xact_command(void) /* Cancel any active statement timeout before committing */ disable_timeout(STATEMENT_TIMEOUT, false); - /* Now commit the command */ - ereport(DEBUG3, - (errmsg_internal("CommitTransactionCommand"))); - CommitTransactionCommand(); #ifdef MEMORY_CONTEXT_CHECKING @@ -2930,45 +2936,31 @@ IsTransactionExitStmt(Node *parsetree) return false; } -/* Test a list that might contain Query nodes or bare parsetrees */ +/* Test a list that contains PlannedStmt nodes */ static bool -IsTransactionExitStmtList(List *parseTrees) +IsTransactionExitStmtList(List *pstmts) { - if (list_length(parseTrees) == 1) + if (list_length(pstmts) == 1) { - Node *stmt = (Node *) linitial(parseTrees); - - if (IsA(stmt, Query)) - { - Query *query = (Query *) stmt; + PlannedStmt *pstmt = linitial_node(PlannedStmt, pstmts); - if (query->commandType == CMD_UTILITY && - IsTransactionExitStmt(query->utilityStmt)) - return true; - } - else if (IsTransactionExitStmt(stmt)) + if (pstmt->commandType == CMD_UTILITY && + IsTransactionExitStmt(pstmt->utilityStmt)) return true; } return false; } -/* Test a list that might contain Query nodes or bare parsetrees */ +/* Test a list that contains PlannedStmt nodes */ static bool -IsTransactionStmtList(List *parseTrees) +IsTransactionStmtList(List *pstmts) { - if (list_length(parseTrees) == 1) + if (list_length(pstmts) == 1) { - Node *stmt = (Node *) linitial(parseTrees); - - if (IsA(stmt, Query)) - { - Query *query = (Query *) stmt; + PlannedStmt *pstmt = linitial_node(PlannedStmt, pstmts); - if (query->commandType == CMD_UTILITY && - IsA(query->utilityStmt, TransactionStmt)) - return true; - } - else if (IsA(stmt, TransactionStmt)) + if (pstmt->commandType == CMD_UTILITY && + IsA(pstmt->utilityStmt, TransactionStmt)) return true; } return false; @@ -4285,8 +4277,7 @@ PostgresMain(int argc, char *argv[], /* * Send this backend's cancellation info to the frontend. */ - if (whereToSendOutput == DestRemote && - PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) + if (whereToSendOutput == DestRemote) { StringInfoData buf; @@ -4309,9 +4300,7 @@ PostgresMain(int argc, char *argv[], */ MessageContext = AllocSetContextCreate(TopMemoryContext, "MessageContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Remember stand-alone backend startup time @@ -4478,6 +4467,9 @@ PostgresMain(int argc, char *argv[], if (MyReplicationSlot != NULL) ReplicationSlotRelease(); + /* We also want to cleanup temporary slots on error. */ + ReplicationSlotCleanup(); + /* * Now return to normal top-level context and clear ErrorContext for * next time. @@ -4540,6 +4532,12 @@ PostgresMain(int argc, char *argv[], initStringInfo(&input_message); /* + * Also consider releasing our catalog snapshot if any, so that it's + * not preventing advance of global xmin while we wait for the client. + */ + InvalidateCatalogSnapshotConditionally(); + + /* * (1) If we've reached idle state, tell the frontend we're ready for * a new query. * @@ -4694,7 +4692,10 @@ PostgresMain(int argc, char *argv[], pq_getmsgend(&input_message); if (am_walsender) - exec_replication_command(query_string); + { + if (!exec_replication_command(query_string)) + exec_simple_query(query_string); + } else exec_simple_query(query_string); @@ -4831,19 +4832,7 @@ PostgresMain(int argc, char *argv[], /* switch back to message context */ MemoryContextSwitchTo(MessageContext); - if (HandleFunctionRequest(&input_message) == EOF) - { - /* lost frontend connection during F message input */ - - /* - * Reset whereToSendOutput to prevent ereport from - * attempting to send any more messages to client. - */ - if (whereToSendOutput == DestRemote) - whereToSendOutput = DestNone; - - proc_exit(0); - } + HandleFunctionRequest(&input_message); /* commit the function-invocation transaction */ finish_xact_command(); @@ -5220,15 +5209,15 @@ ShowUsageCommon(const char *title, struct rusage *save_r, struct timeval *save_t appendStringInfoString(&str, "! system usage stats:\n"); appendStringInfo(&str, - "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n", - (long) (elapse_t.tv_sec - save_t->tv_sec), - (long) (elapse_t.tv_usec - save_t->tv_usec), + "!\t%ld.%06ld s user, %ld.%06ld s system, %ld.%06ld s elapsed\n", (long) (r.ru_utime.tv_sec - save_r->ru_utime.tv_sec), (long) (r.ru_utime.tv_usec - save_r->ru_utime.tv_usec), (long) (r.ru_stime.tv_sec - save_r->ru_stime.tv_sec), - (long) (r.ru_stime.tv_usec - save_r->ru_stime.tv_usec)); + (long) (r.ru_stime.tv_usec - save_r->ru_stime.tv_usec), + (long) (elapse_t.tv_sec - save_t->tv_sec), + (long) (elapse_t.tv_usec - save_t->tv_usec)); appendStringInfo(&str, - "!\t[%ld.%06ld user %ld.%06ld sys total]\n", + "!\t[%ld.%06ld s user, %ld.%06ld s system total]\n", (long) user.tv_sec, (long) user.tv_usec, (long) sys.tv_sec, |