diff options
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 238 |
1 files changed, 128 insertions, 110 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 528fb9757d..5adeb2d804 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -79,7 +79,6 @@ bool Log_connections = false; CommandDest whereToSendOutput = Debug; -extern void BaseInit(void); extern void StartupXLOG(void); extern void ShutdownXLOG(void); @@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS); extern char XLogDir[]; extern char ControlFilePath[]; -extern int lockingOff; -extern int NBuffers; +static bool dontExecute = false; -int dontExecute = 0; static bool IsEmptyQuery = false; /* note: these declarations had better match tcopprot.h */ @@ -101,8 +98,6 @@ bool Warn_restart_ready = false; bool InError = false; bool ExitAfterAbort = false; -extern int NBuffers; - static bool EchoQuery = false; /* default don't echo */ char pg_pathname[MAXPGPATH]; FILE *StatFp = NULL; @@ -133,7 +128,6 @@ int XfuncMode = 0; static int InteractiveBackend(StringInfo inBuf); static int SocketBackend(StringInfo inBuf); static int ReadCommand(StringInfo inBuf); -static void pg_exec_query(char *query_string); static void SigHupHandler(SIGNAL_ARGS); static void FloatExceptionHandler(SIGNAL_ARGS); static void quickdie(SIGNAL_ARGS); @@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf) static int ReadCommand(StringInfo inBuf) { - MemoryContext oldcontext; int result; - /* - * Make sure any expansion of inBuf happens in permanent memory - * context, so that we can keep using it for future command cycles. - */ - oldcontext = MemoryContextSwitchTo(TopMemoryContext); if (IsUnderPostmaster) result = SocketBackend(inBuf); else result = InteractiveBackend(inBuf); - MemoryContextSwitchTo(oldcontext); return result; } @@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf) * multiple queries and/or the rewriter might expand one query to several. */ List * -pg_parse_and_rewrite(char *query_string, /* string to execute */ - Oid *typev,/* argument types */ - int nargs, /* number of arguments */ - bool aclOverride) +pg_parse_and_rewrite(char *query_string, /* string to execute */ + Oid *typev, /* parameter types */ + int nargs) /* number of parameters */ { List *querytree_list; List *querytree_list_item; @@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */ querytree_list = new_list; - /* ---------------- - * (3) If ACL override is requested, mark queries for no ACL check. - * ---------------- - */ - if (aclOverride) - { - foreach(querytree_list_item, querytree_list) - { - List *l; - - querytree = (Query *) lfirst(querytree_list_item); - - if (querytree->commandType == CMD_UTILITY) - continue; - - foreach(l, querytree->rtable) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); - - rte->skipAcl = TRUE; - } - } - } - if (Debug_print_rewritten) { if (Debug_pretty_print) @@ -516,63 +478,66 @@ pg_plan_query(Query *querytree) /* ---------------------------------------------------------------- - * pg_exec_query() + * pg_exec_query_dest() * * Takes a querystring, runs the parser/utilities or - * parser/planner/executor over it as necessary - * Begin Transaction Should have been called before this - * and CommitTransaction After this is called - * This is strictly because we do not allow for nested xactions. + * parser/planner/executor over it as necessary. + * + * Assumptions: + * + * Caller is responsible for calling StartTransactionCommand() beforehand + * and CommitTransactionCommand() afterwards (if successful). + * + * The CurrentMemoryContext at entry references a context that is + * appropriate for execution of individual queries (typically this will be + * TransactionCommandContext). Note that this routine resets that context + * after each individual query, so don't store anything there that + * must outlive the call! * - * NON-OBVIOUS-RESTRICTIONS - * this function _MUST_ allocate a new "parsetree" each time, - * since it may be stored in a named portal and should not - * change its value. + * parse_context references a context suitable for holding the + * parse/rewrite trees (typically this will be QueryContext). + * This context must be longer-lived than the CurrentMemoryContext! + * In fact, if the query string might contain BEGIN/COMMIT commands, + * parse_context had better outlive TopTransactionContext! + * + * We could have hard-wired knowledge about QueryContext and + * TransactionCommandContext into this routine, but it seems better + * not to, in case callers from outside this module need to use some + * other contexts. * * ---------------------------------------------------------------- */ -static void -pg_exec_query(char *query_string) -{ - pg_exec_query_dest(query_string, whereToSendOutput, FALSE); -} - -#ifdef NOT_USED -void -pg_exec_query_acl_override(char *query_string) -{ - pg_exec_query_dest(query_string, whereToSendOutput, TRUE); -} -#endif - void pg_exec_query_dest(char *query_string, /* string to execute */ CommandDest dest, /* where results should go */ - bool aclOverride) /* to give utility commands power - * of superusers */ + MemoryContext parse_context) /* context for parsetrees */ { - List *querytree_list; + MemoryContext oldcontext; + List *querytree_list, + *querytree_item; - /* parse and rewrite the queries */ - querytree_list = pg_parse_and_rewrite(query_string, NULL, 0, - aclOverride); + /* + * Switch to appropriate context for constructing parsetrees. + */ + oldcontext = MemoryContextSwitchTo(parse_context); /* - * NOTE: we do not use "foreach" here because we want to be sure the - * list pointer has been advanced before the query is executed. We - * need to do that because VACUUM has a nasty little habit of doing - * CommitTransactionCommand at startup, and that will release the - * memory holding our parse list :-(. This needs a better solution - * --- currently, the code will crash if someone submits "vacuum; - * something-else" in a single query string. But memory allocation - * needs redesigned anyway, so this will have to do for now. + * Parse and rewrite the query or queries. */ - while (querytree_list) - { - Query *querytree = (Query *) lfirst(querytree_list); + querytree_list = pg_parse_and_rewrite(query_string, NULL, 0); - querytree_list = lnext(querytree_list); + /* + * Switch back to execution context for planning and execution. + */ + MemoryContextSwitchTo(oldcontext); + + /* + * Run through the query or queries and execute each one. + */ + foreach(querytree_item, querytree_list) + { + Query *querytree = (Query *) lfirst(querytree_item); /* if we got a cancel signal in parsing or prior command, quit */ if (QueryCancel) @@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */ if (Show_executor_stats) ResetUsage(); - if (DebugLvl > 1) - elog(DEBUG, "ProcessQuery"); - ProcessQuery(querytree, plan, dest); + if (dontExecute) + { + /* don't execute it, just show the query plan */ + print_plan(plan, querytree); + } + else + { + if (DebugLvl > 1) + elog(DEBUG, "ProcessQuery"); + ProcessQuery(querytree, plan, dest); + } if (Show_executor_stats) { @@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */ * between queries so that the effects of early queries are * visible to subsequent ones. */ - CommandCounterIncrement(); + /* + * Also, clear the execution context to recover temporary + * memory used by the query. NOTE: if query string contains + * BEGIN/COMMIT transaction commands, execution context may + * now be different from what we were originally passed; + * so be careful to clear current context not "oldcontext". + */ + MemoryContextResetAndDeleteChildren(CurrentMemoryContext); } } @@ -822,6 +802,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) extern int DebugLvl; /* + * Fire up essential subsystems: error and memory management + * + * If we are running under the postmaster, this is done already. + */ + if (!IsUnderPostmaster) + { + EnableExceptionHandling(true); + MemoryContextInit(); + } + + /* * Set default values for command-line options. */ Noversion = false; @@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) break; case 'i': - dontExecute = 1; + dontExecute = true; break; case 'L': @@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * * Note that postmaster already blocked ALL signals to make us happy. */ - if (!IsUnderPostmaster) - { - PG_INITMASK(); - PG_SETMASK(&BlockSig); - } + pqinitmask(); #ifdef HAVE_SIGPROCMASK sigdelset(&BlockSig, SIGUSR1); @@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) BlockSig &= ~(sigmask(SIGUSR1)); #endif + PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */ + pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */ pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */ pqsignal(SIGQUIT, handle_warn); /* handle error */ @@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGCONT, SIG_DFL); - PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */ - /* * Get user name (needed now in case it is the default database name) * and check command line validity @@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) on_shmem_exit(remove_all_temp_relations, NULL); - { - MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext); - - parser_input = makeStringInfo(); /* initialize input buffer */ - MemoryContextSwitchTo(oldcontext); - } - /* * Send this backend's cancellation info to the frontend. */ @@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.161 $ $Date: 2000/06/22 22:31:20 $\n"); + puts("$Revision: 1.162 $ $Date: 2000/06/28 03:32:18 $\n"); } /* @@ -1398,6 +1378,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) SetProcessingMode(NormalProcessing); /* + * Create the memory context we will use in the main loop. + * + * QueryContext is reset once per iteration of the main loop, + * ie, upon completion of processing of each supplied query string. + * It can therefore be used for any data that should live just as + * long as the query string --- parse trees, for example. + */ + QueryContext = AllocSetContextCreate(TopMemoryContext, + "QueryContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + + /* * POSTGRES main processing loop begins here * * If an exception is encountered, processing resumes here so we abort @@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) if (sigsetjmp(Warn_restart, 1) != 0) { - /* Make sure we are in a valid memory context */ - MemoryContextSwitchTo(TopMemoryContext); + /* + * Make sure we are in a valid memory context during recovery. + * + * We use ErrorContext in hopes that it will have some free space + * even if we're otherwise up against it... + */ + MemoryContextSwitchTo(ErrorContext); if (DebugLvl >= 1) elog(DEBUG, "AbortCurrentTransaction"); AbortCurrentTransaction(); - InError = false; + if (ExitAfterAbort) { ProcReleaseLocks(); /* Just to be sure... */ proc_exit(0); } + /* + * If we recovered successfully, return to normal top-level context + * and clear ErrorContext for next time. + */ + MemoryContextSwitchTo(TopMemoryContext); + MemoryContextResetAndDeleteChildren(ErrorContext); + InError = false; } Warn_restart_ready = true; /* we can now handle elog(ERROR) */ @@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) for (;;) { - set_ps_display("idle"); + /* + * Release storage left over from prior query cycle, and + * create a new query input buffer in the cleared QueryContext. + */ + MemoryContextSwitchTo(QueryContext); + MemoryContextResetAndDeleteChildren(QueryContext); + + parser_input = makeStringInfo(); /* XXX this could be moved after ReadCommand below to get more * sensical behaviour */ @@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * (3) read a command (loop blocks here) * ---------------- */ + set_ps_display("idle"); + firstchar = ReadCommand(parser_input); QueryCancel = false; /* forget any earlier CANCEL signal */ @@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) elog(DEBUG, "StartTransactionCommand"); StartTransactionCommand(); - pg_exec_query(parser_input->data); + pg_exec_query_dest(parser_input->data, + whereToSendOutput, + QueryContext); /* * Invoke IMMEDIATE constraint triggers @@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * (6) commit the current transaction * * Note: if we had an empty input buffer, then we didn't - * call pg_exec_query, so we don't bother to commit this transaction. + * call pg_exec_query_dest, so we don't bother to commit + * this transaction. * ---------------- */ if (!IsEmptyQuery) @@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) #ifdef SHOW_MEMORY_STATS /* print global-context stats at each commit for leak tracking */ if (ShowStats) - GlobalMemoryStats(); + MemoryContextStats(TopMemoryContext); #endif } else |