#include //#include #include "include.h" /* * Flag to keep track of whether we have started a transaction. * For extended query protocol this has to be remembered across messages. */ bool xact_started = false; /* * If an unnamed prepared statement exists, it's stored here. * We keep it separate from the hashtable kept by commands/prepare.c * in order to reduce overhead for short-lived queries. */ static CachedPlanSource *unnamed_stmt_psrc = NULL; static bool check_log_statement(List *stmt_list); static int errdetail_execute(List *raw_parsetree_list); static int errdetail_abort(void); static void start_xact_command(void); static void finish_xact_command(void); static bool IsTransactionExitStmt(Node *parsetree); static void drop_unnamed_stmt(void); /* * exec_simple_query * * Execute a "simple Query" protocol message. */ void exec_simple_query_my(const char *query_string) { CommandDest dest = whereToSendOutput; MemoryContext oldcontext; List *parsetree_list; ListCell *parsetree_item; bool save_log_statement_stats = log_statement_stats; bool was_logged = false; bool isTopLevel; char msec_str[32]; /* * Report query to various monitoring facilities. */ debug_query_string = query_string; pgstat_report_activity(STATE_RUNNING, query_string); // TRACE_POSTGRESQL_QUERY_START(query_string); /* * We use save_log_statement_stats so ShowUsage doesn't report incorrect * results because ResetUsage wasn't called. */ if (save_log_statement_stats) ResetUsage(); /* * Start up a transaction command. All queries generated by the * query_string will be in this same command block, *unless* we find a * BEGIN/COMMIT/ABORT statement; we have to force a new xact command after * one of those, else bad things will happen in xact.c. (Note that this * will normally change current memory context.) */ start_xact_command(); /* * Zap any pre-existing unnamed statement. (While not strictly necessary, * it seems best to define simple-Query mode as if it used the unnamed * statement and portal; this ensures we recover any storage used by prior * unnamed operations.) */ drop_unnamed_stmt(); /* * Switch to appropriate context for constructing parsetrees. */ oldcontext = MemoryContextSwitchTo(MessageContext); /* * Do basic parsing of the query or queries (this should be safe even if * we are in aborted transaction state!) */ parsetree_list = pg_parse_query(query_string); /* 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); /* * We'll tell PortalRun it's a top-level command iff there's exactly one * raw parsetree. If more than one, it's effectively a transaction block * and we want PreventTransactionChain to reject unsafe commands. (Note: * we're assuming that query rewrite cannot add commands that are * significant to PreventTransactionChain.) */ isTopLevel = (list_length(parsetree_list) == 1); /* * Run through the raw parsetree(s) and process each one. */ foreach(parsetree_item, parsetree_list) { Node *parsetree = (Node *) lfirst(parsetree_item); bool snapshot_set = false; 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, false); BeginCommandMy(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"), errdetail_abort())); /* 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(); /* * Set up a snapshot if parse analysis/planning will need one. */ if (analyze_requires_snapshot(parsetree)) { PushActiveSnapshot(GetTransactionSnapshot()); snapshot_set = true; } /* * OK to analyze, rewrite, and plan this query. * * Switch to appropriate context for constructing querytrees (again, * these must outlive the execution context). */ oldcontext = MemoryContextSwitchTo(MessageContext); querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0); plantree_list = pg_plan_queries(querytree_list, CURSOR_OPT_PARALLEL_OK, NULL); /* Done with the snapshot used for parsing/planning */ if (snapshot_set) PopActiveSnapshot(); /* If we got a cancel signal in analysis or planning, quit */ CHECK_FOR_INTERRUPTS(); /* * Create unnamed portal to run the query or queries in. If there * already is one, silently drop it. */ portal = CreatePortal("", true, true); /* Don't display the portal in pg_cursors */ portal->visible = false; /* * We don't have to copy anything into the portal, because everything * we are passing here is in MessageContext, which will outlive the * portal anyway. */ PortalDefineQuery(portal, NULL, query_string, commandTag, plantree_list, NULL); /* * Start the portal. No parameters here. */ PortalStart(portal, NULL, 0, InvalidSnapshot); /* * 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 = CreateDestReceiverMy(dest); 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, isTopLevel, 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) == 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. 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.) */ EndCommandMy(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) NullCommandMy(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; } /* * check_log_statement * Determine whether command should be logged because of log_statement * * stmt_list can be either raw grammar output or a list of planned * statements */ static bool check_log_statement(List *stmt_list) { ListCell *stmt_item; if (log_statement == LOGSTMT_NONE) return false; if (log_statement == LOGSTMT_ALL) return true; /* Else we have to inspect the statement(s) to see whether to log */ foreach(stmt_item, stmt_list) { Node *stmt = (Node *) lfirst(stmt_item); if (GetCommandLogLevel(stmt) <= log_statement) return true; } return false; } /* * errdetail_execute * * Add an errdetail() line showing the query referenced by an EXECUTE, if any. * The argument is the raw parsetree list. */ static int errdetail_execute(List *raw_parsetree_list) { ListCell *parsetree_item; foreach(parsetree_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(parsetree_item); if (IsA(parsetree, ExecuteStmt)) { ExecuteStmt *stmt = (ExecuteStmt *) parsetree; PreparedStatement *pstmt; pstmt = FetchPreparedStatement(stmt->name, false); if (pstmt) { errdetail("prepare: %s", pstmt->plansource->query_string); return 0; } } } return 0; } /* * errdetail_abort * * Add an errdetail() line showing abort reason, if any. */ static int errdetail_abort(void) { if (MyProc->recoveryConflictPending) errdetail("abort reason: recovery conflict"); return 0; } /* * Convenience routines for starting/committing a single command. */ static void start_xact_command(void) { if (!xact_started) { ereport(DEBUG3, (errmsg_internal("StartTransactionCommand"))); StartTransactionCommand(); /* Set statement timeout running, if any */ /* NB: this mustn't be enabled until we are within an xact */ if (StatementTimeout > 0) enable_timeout_after(STATEMENT_TIMEOUT, StatementTimeout); else disable_timeout(STATEMENT_TIMEOUT, false); xact_started = true; } } static void finish_xact_command(void) { if (xact_started) { /* 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 /* Check all memory contexts that weren't freed during commit */ /* (those that were, were checked before being deleted) */ MemoryContextCheck(TopMemoryContext); #endif #ifdef SHOW_MEMORY_STATS /* Print mem stats after each commit for leak tracking */ MemoryContextStats(TopMemoryContext); #endif xact_started = false; } } /* * Convenience routines for checking whether a statement is one of the * ones that we allow in transaction-aborted state. */ /* Test a bare parsetree */ static bool IsTransactionExitStmt(Node *parsetree) { if (parsetree && IsA(parsetree, TransactionStmt)) { TransactionStmt *stmt = (TransactionStmt *) parsetree; if (stmt->kind == TRANS_STMT_COMMIT || stmt->kind == TRANS_STMT_PREPARE || stmt->kind == TRANS_STMT_ROLLBACK || stmt->kind == TRANS_STMT_ROLLBACK_TO) return true; } return false; } /* 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); } }