summaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c2437
1 files changed, 0 insertions, 2437 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
deleted file mode 100644
index a8f83e48e4d..00000000000
--- a/src/backend/tcop/postgres.c
+++ /dev/null
@@ -1,2437 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * postgres.c
- * POSTGRES C Backend Interface
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.268 2002/06/20 20:29:36 momjian Exp $
- *
- * NOTES
- * this is the "main" module of the postgres backend and
- * hence the main module of the "traffic cop".
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include <unistd.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <errno.h>
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-#include "access/xlog.h"
-#include "commands/async.h"
-#include "commands/trigger.h"
-#include "libpq/libpq.h"
-#include "libpq/pqformat.h"
-#include "libpq/pqsignal.h"
-#include "miscadmin.h"
-#include "nodes/print.h"
-#include "optimizer/cost.h"
-#include "optimizer/planner.h"
-#include "parser/analyze.h"
-#include "parser/parse.h"
-#include "parser/parser.h"
-#include "rewrite/rewriteHandler.h"
-#include "storage/ipc.h"
-#include "storage/proc.h"
-#include "tcop/fastpath.h"
-#include "tcop/pquery.h"
-#include "tcop/tcopprot.h"
-#include "tcop/utility.h"
-#include "utils/exc.h"
-#include "utils/guc.h"
-#include "utils/memutils.h"
-#include "utils/ps_status.h"
-#ifdef MULTIBYTE
-#include "mb/pg_wchar.h"
-#endif
-
-#include "pgstat.h"
-
-
-/* ----------------
- * global variables
- * ----------------
- */
-
-extern int optind;
-extern char *optarg;
-
-char *debug_query_string; /* used by pgmonitor */
-
-/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
-CommandDest whereToSendOutput = Debug;
-
-static bool dontExecute = false;
-
-/* note: these declarations had better match tcopprot.h */
-sigjmp_buf Warn_restart;
-
-bool Warn_restart_ready = false;
-bool InError = false;
-
-static bool EchoQuery = false; /* default don't echo */
-
-/*
- * Flag to mark SIGHUP. Whenever the main loop comes around it
- * will reread the configuration file. (Better than doing the
- * reading in the signal handler, ey?)
- */
-static volatile bool got_SIGHUP = false;
-
-/* ----------------
- * people who want to use EOF should #define DONTUSENEWLINE in
- * tcop/tcopdebug.h
- * ----------------
- */
-#ifndef TCOP_DONTUSENEWLINE
-int UseNewLine = 1; /* Use newlines query delimiters (the
- * default) */
-
-#else
-int UseNewLine = 0; /* Use EOF as query delimiters */
-#endif /* TCOP_DONTUSENEWLINE */
-
-/*
-** Flags for expensive function optimization -- JMH 3/9/92
-*/
-int XfuncMode = 0;
-
-/* ----------------------------------------------------------------
- * decls for routines only used in this file
- * ----------------------------------------------------------------
- */
-static int InteractiveBackend(StringInfo inBuf);
-static int SocketBackend(StringInfo inBuf);
-static int ReadCommand(StringInfo inBuf);
-static List *pg_parse_query(StringInfo query_string, Oid *typev, int nargs);
-static List *pg_analyze_and_rewrite(Node *parsetree);
-static void start_xact_command(void);
-static void finish_xact_command(void);
-static void SigHupHandler(SIGNAL_ARGS);
-static void FloatExceptionHandler(SIGNAL_ARGS);
-static const char *CreateCommandTag(Node *parsetree);
-
-
-/* ----------------------------------------------------------------
- * routines to obtain user input
- * ----------------------------------------------------------------
- */
-
-/* ----------------
- * InteractiveBackend() is called for user interactive connections
- * the string entered by the user is placed in its parameter inBuf.
- *
- * EOF is returned if end-of-file input is seen; time to shut down.
- * ----------------
- */
-
-static int
-InteractiveBackend(StringInfo inBuf)
-{
- int c; /* character read from getc() */
- bool end = false; /* end-of-input flag */
- bool backslashSeen = false; /* have we seen a \ ? */
-
- /*
- * display a prompt and obtain input from the user
- */
- printf("backend> ");
- fflush(stdout);
-
- /* Reset inBuf to empty */
- inBuf->len = 0;
- inBuf->data[0] = '\0';
-
- for (;;)
- {
- if (UseNewLine)
- {
- /*
- * if we are using \n as a delimiter, then read characters
- * until the \n.
- */
- while ((c = getc(stdin)) != EOF)
- {
- if (c == '\n')
- {
- if (backslashSeen)
- {
- /* discard backslash from inBuf */
- inBuf->data[--inBuf->len] = '\0';
- backslashSeen = false;
- continue;
- }
- else
- {
- /* keep the newline character */
- appendStringInfoChar(inBuf, '\n');
- break;
- }
- }
- else if (c == '\\')
- backslashSeen = true;
- else
- backslashSeen = false;
-
- appendStringInfoChar(inBuf, (char) c);
- }
-
- if (c == EOF)
- end = true;
- }
- else
- {
- /*
- * otherwise read characters until EOF.
- */
- while ((c = getc(stdin)) != EOF)
- appendStringInfoChar(inBuf, (char) c);
-
- if (inBuf->len == 0)
- end = true;
- }
-
- if (end)
- return EOF;
-
- /*
- * otherwise we have a user query so process it.
- */
- break;
- }
-
- /*
- * if the query echo flag was given, print the query..
- */
- if (EchoQuery)
- printf("query: %s\n", inBuf->data);
- fflush(stdout);
-
- return 'Q';
-}
-
-/* ----------------
- * SocketBackend() Is called for frontend-backend connections
- *
- * If the input is a query (case 'Q') then the string entered by
- * the user is placed in its parameter inBuf.
- *
- * If the input is a fastpath function call (case 'F') then
- * the function call is processed in HandleFunctionRequest()
- * (now called from PostgresMain()).
- *
- * EOF is returned if the connection is lost.
- * ----------------
- */
-
-static int
-SocketBackend(StringInfo inBuf)
-{
- int qtype;
-
- /*
- * get input from the frontend
- */
- qtype = pq_getbyte();
-
- switch (qtype)
- {
- case EOF:
- /* frontend disconnected */
- break;
-
- /*
- * 'Q': user entered a query
- */
- case 'Q':
- if (pq_getstr(inBuf))
- return EOF;
- break;
-
- /*
- * 'F': calling user/system functions
- */
- case 'F':
- if (pq_getstr(inBuf))
- return EOF; /* ignore "string" at start of F message */
- break;
-
- /*
- * 'X': frontend is exiting
- */
- case 'X':
- break;
-
- /*
- * otherwise we got garbage from the frontend.
- *
- * XXX are we certain that we want to do an elog(FATAL) here?
- * -cim 1/24/90
- */
- default:
- elog(FATAL, "Socket command type %c unknown", qtype);
- break;
- }
-
- return qtype;
-}
-
-/* ----------------
- * ReadCommand reads a command from either the frontend or
- * standard input, places it in inBuf, and returns a char
- * representing whether the string is a 'Q'uery or a 'F'astpath
- * call. EOF is returned if end of file.
- * ----------------
- */
-static int
-ReadCommand(StringInfo inBuf)
-{
- int result;
-
- if (IsUnderPostmaster)
- result = SocketBackend(inBuf);
- else
- result = InteractiveBackend(inBuf);
- return result;
-}
-
-
-/*
- * Parse a query string and pass it through the rewriter.
- *
- * A list of Query nodes is returned, since the string might contain
- * multiple queries and/or the rewriter might expand one query to several.
- *
- * NOTE: this routine is no longer used for processing interactive queries,
- * but it is still needed for parsing of SQL function bodies.
- */
-List *
-pg_parse_and_rewrite(char *query_string, /* string to execute */
- Oid *typev, /* parameter types */
- int nargs) /* number of parameters */
-{
- List *raw_parsetree_list;
- List *querytree_list;
- List *list_item;
- StringInfoData stri;
-
- initStringInfo(&stri);
- appendStringInfo(&stri, "%s", query_string);
-
- /*
- * (1) parse the request string into a list of raw parse trees.
- */
- raw_parsetree_list = pg_parse_query(&stri, typev, nargs);
-
- /*
- * (2) Do parse analysis and rule rewrite.
- */
- querytree_list = NIL;
- foreach(list_item, raw_parsetree_list)
- {
- Node *parsetree = (Node *) lfirst(list_item);
-
- querytree_list = nconc(querytree_list,
- pg_analyze_and_rewrite(parsetree));
- }
-
- 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.
- */
-static List *
-pg_parse_query(StringInfo query_string, Oid *typev, int nargs)
-{
- List *raw_parsetree_list;
-
- if (Debug_print_query)
- elog(LOG, "query: %s", query_string->data);
-
- if (Show_parser_stats)
- ResetUsage();
-
- raw_parsetree_list = parser(query_string, typev, nargs);
-
- if (Show_parser_stats)
- ShowUsage("PARSER STATISTICS");
-
- return raw_parsetree_list;
-}
-
-/*
- * Given a raw parsetree (gram.y output), 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.
- */
-static List *
-pg_analyze_and_rewrite(Node *parsetree)
-{
- List *querytree_list;
- List *list_item;
- Query *querytree;
- List *new_list;
-
- /*
- * (1) Perform parse analysis.
- */
- if (Show_parser_stats)
- ResetUsage();
-
- querytree_list = parse_analyze(parsetree, NULL);
-
- if (Show_parser_stats)
- {
- ShowUsage("PARSE ANALYSIS STATISTICS");
- ResetUsage();
- }
-
- /*
- * (2) Rewrite the queries, as necessary
- *
- * rewritten queries are collected in new_list. Note there may be more
- * or fewer than in the original list.
- */
- new_list = NIL;
- foreach(list_item, querytree_list)
- {
- querytree = (Query *) lfirst(list_item);
-
- if (Debug_print_parse)
- elog_node_display(LOG, "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 (Show_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, "pg_analyze_and_rewrite: copyObject failed on parse tree");
- else
- querytree_list = new_list;
-#endif
-
- if (Debug_print_rewritten)
- elog_node_display(LOG, "rewritten parse tree", querytree_list,
- Debug_pretty_print);
-
- return querytree_list;
-}
-
-
-/* Generate a plan for a single query. */
-Plan *
-pg_plan_query(Query *querytree)
-{
- Plan *plan;
-
- /* Utility commands have no plans. */
- if (querytree->commandType == CMD_UTILITY)
- return NULL;
-
- if (Show_planner_stats)
- ResetUsage();
-
- /* call that optimizer */
- plan = planner(querytree);
-
- if (Show_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, "pg_plan_query: copyObject failed on plan tree");
- else
-#endif
- plan = new_plan;
- }
-#endif
-
- /*
- * Print plan if debugging.
- */
- if (Debug_print_plan)
- elog_node_display(LOG, "plan", plan, Debug_pretty_print);
-
- return plan;
-}
-
-
-/* ----------------------------------------------------------------
- * pg_exec_query_string()
- *
- * Takes a querystring, runs the parser/utilities or
- * parser/planner/executor over it as necessary.
- *
- * Assumptions:
- *
- * At call, we are not inside a transaction command.
- *
- * The CurrentMemoryContext after starting a transaction command must be
- * 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!
- *
- * 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 transaction context!
- * 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.
- *
- * ----------------------------------------------------------------
- */
-
-void
-pg_exec_query_string(StringInfo query_string, /* string to execute */
- CommandDest dest, /* where results should go */
- MemoryContext parse_context) /* context for
- * parsetrees */
-{
- bool xact_started;
- MemoryContext oldcontext;
- List *parsetree_list,
- *parsetree_item;
-
- debug_query_string = query_string->data; /* used by pgmonitor */
-
- /*
- * 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 possibly change current memory context.)
- */
- start_xact_command();
- xact_started = true;
-
- /*
- * parse_context *must* be different from the execution memory
- * context, else the context reset at the bottom of the loop will
- * destroy the parsetree list. (We really ought to check that
- * parse_context isn't a child of CurrentMemoryContext either, but
- * that would take more cycles than it's likely to be worth.)
- */
- Assert(parse_context != CurrentMemoryContext);
-
- /*
- * Switch to appropriate context for constructing parsetrees.
- */
- oldcontext = MemoryContextSwitchTo(parse_context);
-
- /*
- * 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, NULL, 0);
-
- /*
- * Switch back to execution context to enter the loop.
- */
- MemoryContextSwitchTo(oldcontext);
-
- /*
- * Run through the parsetree(s) and process each one.
- */
- foreach(parsetree_item, parsetree_list)
- {
- Node *parsetree = (Node *) lfirst(parsetree_item);
- bool isTransactionStmt;
- const char *commandTag;
- char completionTag[COMPLETION_TAG_BUFSIZE];
- List *querytree_list,
- *querytree_item;
-
- /* Transaction control statements need some special handling */
- isTransactionStmt = IsA(parsetree, TransactionStmt);
-
- /*
- * First we set the command-completion tag to the main query
- * (as opposed to each of the others that may be generated by
- * analyze and rewrite). Also 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, ignore 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 (isTransactionStmt)
- {
- TransactionStmt *stmt = (TransactionStmt *) parsetree;
-
- switch (stmt->command)
- {
- case COMMIT:
- case ROLLBACK:
- allowit = true;
- break;
- default:
- break;
- }
- }
-
- if (!allowit)
- {
- elog(WARNING, "current transaction is aborted, "
- "queries ignored until end of transaction block");
-
- /*
- * We need to emit a command-complete report to the client,
- * even though we didn't process the query.
- * - cim 6/1/90
- */
- commandTag = "*ABORT STATE*";
-
- EndCommand(commandTag, dest);
-
- /*
- * We continue in the loop, on the off chance that there
- * is a COMMIT or ROLLBACK utility command later in the
- * query string.
- */
- continue;
- }
- }
-
- /* Make sure we are in a transaction command */
- if (!xact_started)
- {
- start_xact_command();
- xact_started = true;
- }
-
- /* If we got a cancel signal in parsing or prior command, quit */
- CHECK_FOR_INTERRUPTS();
-
- /*
- * OK to analyze and rewrite this query.
- *
- * Switch to appropriate context for constructing querytrees (again,
- * these must outlive the execution context).
- */
- oldcontext = MemoryContextSwitchTo(parse_context);
-
- querytree_list = pg_analyze_and_rewrite(parsetree);
-
- /*
- * Switch back to execution context for planning and execution.
- */
- MemoryContextSwitchTo(oldcontext);
-
- /*
- * Inner loop handles the individual queries generated from a
- * single parsetree by analysis and rewrite.
- */
- foreach(querytree_item, querytree_list)
- {
- Query *querytree = (Query *) lfirst(querytree_item);
-
- /* Make sure we are in a transaction command */
- if (!xact_started)
- {
- start_xact_command();
- xact_started = true;
- }
-
- /*
- * If we got a cancel signal in analysis or prior command,
- * quit
- */
- CHECK_FOR_INTERRUPTS();
-
- if (querytree->commandType == CMD_UTILITY)
- {
- /*
- * process utility functions (create, destroy, etc..)
- */
- elog(DEBUG2, "ProcessUtility");
-
- if (querytree->originalQuery)
- {
- /* utility statement can override default tag string */
- ProcessUtility(querytree->utilityStmt, dest,
- completionTag);
- if (completionTag[0])
- commandTag = completionTag;
- }
- else
- {
- /* utility added by rewrite cannot override tag */
- ProcessUtility(querytree->utilityStmt, dest, NULL);
- }
- }
- else
- {
- /*
- * process a plannable query.
- */
- Plan *plan;
-
- plan = pg_plan_query(querytree);
-
- /* if we got a cancel signal whilst planning, quit */
- CHECK_FOR_INTERRUPTS();
-
- /* Initialize snapshot state for query */
- SetQuerySnapshot();
-
- /*
- * execute the plan
- */
- if (Show_executor_stats)
- ResetUsage();
-
- if (dontExecute)
- {
- /* don't execute it, just show the query plan */
- print_plan(plan, querytree);
- }
- else
- {
- elog(DEBUG2, "ProcessQuery");
-
- if (querytree->originalQuery)
- {
- /* original stmt can override default tag string */
- ProcessQuery(querytree, plan, dest, completionTag);
- commandTag = completionTag;
- }
- else
- {
- /* stmt added by rewrite cannot override tag */
- ProcessQuery(querytree, plan, dest, NULL);
- }
- }
-
- if (Show_executor_stats)
- ShowUsage("EXECUTOR STATISTICS");
- }
-
- /*
- * In a query block, we want to increment the command counter
- * between queries so that the effects of early queries are
- * visible to subsequent ones. In particular we'd better do
- * so before checking constraints.
- */
- if (!isTransactionStmt)
- CommandCounterIncrement();
-
- /*
- * 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".
- */
- Assert(parse_context != CurrentMemoryContext);
-
- MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
-
- /*
- * If this was a transaction control statement, commit it and
- * arrange to start a new xact command for the next command
- * (if any).
- */
- if (isTransactionStmt)
- {
- finish_xact_command();
- xact_started = false;
- }
-
- } /* end loop over queries generated from a
- * parsetree */
-
- /*
- * 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.
- */
- if (lnext(parsetree_item) == NIL && xact_started)
- {
- finish_xact_command();
- xact_started = false;
- }
-
- /*
- * It is possible that the original query was removed due to
- * a DO INSTEAD rewrite rule. In that case we will still have
- * the default completion tag, which is fine for most purposes,
- * but it may confuse clients if it's INSERT/UPDATE/DELETE.
- * Clients expect those tags to have counts after them (cf.
- * ProcessQuery).
- */
- if (strcmp(commandTag, "INSERT") == 0)
- commandTag = "INSERT 0 0";
- else if (strcmp(commandTag, "UPDATE") == 0)
- commandTag = "UPDATE 0";
- else if (strcmp(commandTag, "DELETE") == 0)
- commandTag = "DELETE 0";
-
- /*
- * 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(commandTag, dest);
- } /* end loop over parsetrees */
-
- /*
- * Close down transaction statement, if one is open.
- * (Note that this will only happen if the querystring was empty.)
- */
- if (xact_started)
- finish_xact_command();
-
- debug_query_string = NULL; /* used by pgmonitor */
-}
-
-/*
- * Convenience routines for starting/committing a single command.
- */
-static void
-start_xact_command(void)
-{
- elog(DEBUG1, "StartTransactionCommand");
- StartTransactionCommand();
-}
-
-static void
-finish_xact_command(void)
-{
- /* Invoke IMMEDIATE constraint triggers */
- DeferredTriggerEndQuery();
-
- /* Now commit the command */
- elog(DEBUG1, "CommitTransactionCommand");
-
- CommitTransactionCommand();
-
-#ifdef SHOW_MEMORY_STATS
- /* Print mem stats at each commit for leak tracking */
- if (ShowStats)
- MemoryContextStats(TopMemoryContext);
-#endif
-}
-
-
-/* --------------------------------
- * signal handler routines used in PostgresMain()
- * --------------------------------
- */
-
-/*
- * quickdie() occurs when signalled SIGQUIT by the postmaster.
- *
- * Some backend has bought the farm,
- * so we need to stop what we're doing and exit.
- */
-void
-quickdie(SIGNAL_ARGS)
-{
- PG_SETMASK(&BlockSig);
- elog(WARNING, "Message from PostgreSQL backend:"
- "\n\tThe Postmaster has informed me that some other backend"
- "\n\tdied abnormally and possibly corrupted shared memory."
- "\n\tI have rolled back the current transaction and am"
- "\n\tgoing to terminate your database system connection and exit."
- "\n\tPlease reconnect to the database system and repeat your query.");
-
- /*
- * DO NOT proc_exit() -- we're here because shared memory may be
- * corrupted, so we don't want to try to clean up our transaction.
- * Just nail the windows shut and get out of town.
- *
- * Note we do exit(1) not exit(0). This is to force the postmaster into
- * a system reset cycle if some idiot DBA sends a manual SIGQUIT to a
- * random backend. This is necessary precisely because we don't clean
- * up our shared memory state.
- */
-
- exit(1);
-}
-
-/*
- * Shutdown signal from postmaster: abort transaction and exit
- * at soonest convenient time
- */
-void
-die(SIGNAL_ARGS)
-{
- int save_errno = errno;
-
- /* Don't joggle the elbow of proc_exit */
- if (!proc_exit_inprogress)
- {
- InterruptPending = true;
- ProcDiePending = true;
-
- /*
- * If it's safe to interrupt, and we're waiting for input or a
- * lock, service the interrupt immediately
- */
- if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
- CritSectionCount == 0)
- {
- /* bump holdoff count to make ProcessInterrupts() a no-op */
- /* until we are done getting ready for it */
- InterruptHoldoffCount++;
- DisableNotifyInterrupt();
- /* Make sure HandleDeadLock won't run while shutting down... */
- LockWaitCancel();
- InterruptHoldoffCount--;
- ProcessInterrupts();
- }
- }
-
- errno = save_errno;
-}
-
-/*
- * Timeout or shutdown signal from postmaster during client authentication.
- * Simply exit(0).
- *
- * XXX: possible future improvement: try to send a message indicating
- * why we are disconnecting. Problem is to be sure we don't block while
- * doing so, nor mess up the authentication message exchange.
- */
-void
-authdie(SIGNAL_ARGS)
-{
- exit(0);
-}
-
-/*
- * Query-cancel signal from postmaster: abort current transaction
- * at soonest convenient time
- */
-static void
-QueryCancelHandler(SIGNAL_ARGS)
-{
- int save_errno = errno;
-
- /*
- * Don't joggle the elbow of proc_exit, nor an already-in-progress
- * abort
- */
- if (!proc_exit_inprogress && !InError)
- {
- InterruptPending = true;
- QueryCancelPending = true;
-
- /*
- * If it's safe to interrupt, and we're waiting for a lock,
- * service the interrupt immediately. No point in interrupting if
- * we're waiting for input, however.
- */
- if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
- CritSectionCount == 0)
- {
- /* bump holdoff count to make ProcessInterrupts() a no-op */
- /* until we are done getting ready for it */
- InterruptHoldoffCount++;
- if (LockWaitCancel())
- {
- DisableNotifyInterrupt();
- InterruptHoldoffCount--;
- ProcessInterrupts();
- }
- else
- InterruptHoldoffCount--;
- }
- }
-
- errno = save_errno;
-}
-
-/* signal handler for floating point exception */
-static void
-FloatExceptionHandler(SIGNAL_ARGS)
-{
- elog(ERROR, "floating point exception!"
- " The last floating point operation either exceeded legal ranges"
- " or was a divide by zero");
-}
-
-/* SIGHUP: set flag to re-read config file at next convenient time */
-static void
-SigHupHandler(SIGNAL_ARGS)
-{
- got_SIGHUP = true;
-}
-
-
-/*
- * ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro
- *
- * If an interrupt condition is pending, and it's safe to service it,
- * then clear the flag and accept the interrupt. Called only when
- * InterruptPending is true.
- */
-void
-ProcessInterrupts(void)
-{
- /* OK to accept interrupt now? */
- if (InterruptHoldoffCount != 0 || CritSectionCount != 0)
- return;
- InterruptPending = false;
- if (ProcDiePending)
- {
- ProcDiePending = false;
- QueryCancelPending = false; /* ProcDie trumps QueryCancel */
- ImmediateInterruptOK = false; /* not idle anymore */
- elog(FATAL, "This connection has been terminated by the administrator.");
- }
- if (QueryCancelPending)
- {
- QueryCancelPending = false;
- ImmediateInterruptOK = false; /* not idle anymore */
- elog(ERROR, "Query was cancelled.");
- }
- /* If we get here, do nothing (probably, QueryCancelPending was reset) */
-}
-
-
-static void
-usage(char *progname)
-{
- printf("%s is the PostgreSQL stand-alone backend. It is not\nintended to be used by normal users.\n\n", progname);
-
- printf("Usage:\n %s [options...] [dbname]\n\n", progname);
- printf("Options:\n");
-#ifdef USE_ASSERT_CHECKING
- printf(" -A 1|0 enable/disable run-time assert checking\n");
-#endif
- printf(" -B NBUFFERS number of shared buffers (default %d)\n", DEF_NBUFFERS);
- printf(" -c NAME=VALUE set run-time parameter\n");
- printf(" -d 1-5,0 debugging level (0 is off)\n");
- printf(" -D DATADIR database directory\n");
- printf(" -e use European date format\n");
- printf(" -E echo query before execution\n");
- printf(" -F turn fsync off\n");
- printf(" -N do not use newline as interactive query delimiter\n");
- printf(" -o FILENAME send stdout and stderr to given file\n");
- printf(" -P disable system indexes\n");
- printf(" -s show statistics after each query\n");
- printf(" -S SORT-MEM set amount of memory for sorts (in kbytes)\n");
- printf("Developer options:\n");
- printf(" -f [s|i|n|m|h] forbid use of some plan types\n");
- printf(" -i do not execute queries\n");
- printf(" -O allow system table structure changes\n");
- printf(" -t [pa|pl|ex] show timings after each query\n");
- printf(" -W NUM wait NUM seconds to allow attach from a debugger\n");
- printf("\nReport bugs to <pgsql-bugs@postgresql.org>.\n");
-}
-
-
-
-/* ----------------------------------------------------------------
- * PostgresMain
- * postgres main loop -- all backends, interactive or otherwise start here
- *
- * argc/argv are the command line arguments to be used. (When being forked
- * by the postmaster, these are not the original argv array of the process.)
- * username is the (possibly authenticated) PostgreSQL user name to be used
- * for the session.
- * ----------------------------------------------------------------
- */
-int
-PostgresMain(int argc, char *argv[], const char *username)
-{
- int flag;
-
- const char *DBName = NULL;
- bool secure;
- int errs = 0;
- GucContext ctx;
- GucSource gucsource;
- char *tmp;
-
- int firstchar;
- StringInfo parser_input;
-
- char *potential_DataDir = NULL;
-
- /*
- * Catch standard options before doing much else. This even works on
- * systems without getopt_long.
- */
- if (!IsUnderPostmaster && argc > 1)
- {
- if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
- {
- usage(argv[0]);
- exit(0);
- }
- if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
- {
- puts("postgres (PostgreSQL) " PG_VERSION);
- exit(0);
- }
- }
-
- /*
- * 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_ps_display("startup");
-
- SetProcessingMode(InitProcessing);
-
- /*
- * Set default values for command-line options.
- */
- Noversion = false;
- EchoQuery = false;
-
- if (!IsUnderPostmaster)
- {
- InitializeGUCOptions();
- potential_DataDir = getenv("PGDATA");
- }
-
- /* ----------------
- * parse command line arguments
- *
- * There are now two styles of command line layout for the backend:
- *
- * For interactive use (not started from postmaster) the format is
- * postgres [switches] [databasename]
- * If the databasename is omitted it is taken to be the user name.
- *
- * When started from the postmaster, the format is
- * postgres [secure switches] -p databasename [insecure switches]
- * Switches appearing after -p came from the client (via "options"
- * field of connection request). For security reasons we restrict
- * what these switches can do.
- * ----------------
- */
-
- /* all options are allowed until '-p' */
- secure = true;
- ctx = PGC_POSTMASTER;
- gucsource = PGC_S_ARGV; /* initial switches came from command line */
-
- while ((flag = getopt(argc, argv, "A:B:c:CD:d:Eef:FiNOPo:p:S:st:v:W:x:-:")) != -1)
- switch (flag)
- {
- case 'A':
-#ifdef USE_ASSERT_CHECKING
- SetConfigOption("debug_assertions", optarg, ctx, gucsource);
-#else
- elog(WARNING, "Assert checking is not compiled in");
-#endif
- break;
-
- case 'B':
-
- /*
- * specify the size of buffer pool
- */
- SetConfigOption("shared_buffers", optarg, ctx, gucsource);
- break;
-
- case 'C':
-
- /*
- * don't print version string
- */
- Noversion = true;
- break;
-
- case 'D': /* PGDATA directory */
- if (secure)
- potential_DataDir = optarg;
- break;
-
- case 'd': /* debug level */
- {
- /* Set server debugging level. */
- if (atoi(optarg) != 0)
- {
- char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
-
- sprintf(debugstr, "debug%s", optarg);
- SetConfigOption("server_min_messages", debugstr, ctx, gucsource);
- pfree(debugstr);
- /*
- * -d is not the same as setting client_min_messages
- * because it enables other output options.
- */
- if (atoi(optarg) >= 1)
- SetConfigOption("log_connections", "true", ctx, gucsource);
- if (atoi(optarg) >= 2)
- SetConfigOption("debug_print_query", "true", ctx, gucsource);
- if (atoi(optarg) >= 3)
- SetConfigOption("debug_print_parse", "true", ctx, gucsource);
- if (atoi(optarg) >= 4)
- SetConfigOption("debug_print_plan", "true", ctx, gucsource);
- if (atoi(optarg) >= 5)
- SetConfigOption("debug_print_rewritten", "true", ctx, gucsource);
- }
- else
- /*
- * -d 0 allows user to prevent postmaster debug from
- * propagating to backend.
- */
- SetConfigOption("server_min_messages", "notice",
- ctx, gucsource);
- }
- break;
-
- case 'E':
-
- /*
- * E - echo the query the user entered
- */
- EchoQuery = true;
- break;
-
- case 'e':
-
- /*
- * Use european date formats.
- */
- SetConfigOption("datestyle", "euro", ctx, gucsource);
- break;
-
- case 'F':
-
- /*
- * turn off fsync
- */
- SetConfigOption("fsync", "false", ctx, gucsource);
- break;
-
- case 'f':
-
- /*
- * f - forbid generation of certain plans
- */
- tmp = NULL;
- switch (optarg[0])
- {
- case 's': /* seqscan */
- tmp = "enable_seqscan";
- break;
- case 'i': /* indexscan */
- tmp = "enable_indexscan";
- break;
- case 't': /* tidscan */
- tmp = "enable_tidscan";
- break;
- case 'n': /* nestloop */
- tmp = "enable_nestloop";
- break;
- case 'm': /* mergejoin */
- tmp = "enable_mergejoin";
- break;
- case 'h': /* hashjoin */
- tmp = "enable_hashjoin";
- break;
- default:
- errs++;
- }
- if (tmp)
- SetConfigOption(tmp, "false", ctx, gucsource);
- break;
-
- case 'i':
- dontExecute = true;
- break;
-
- case 'N':
-
- /*
- * N - Don't use newline as a query delimiter
- */
- UseNewLine = 0;
- break;
-
- case 'O':
-
- /*
- * allow system table structure modifications
- */
- if (secure) /* XXX safe to allow from client??? */
- allowSystemTableMods = true;
- break;
-
- case 'P':
-
- /*
- * ignore system indexes
- */
- if (secure) /* XXX safe to allow from client??? */
- IgnoreSystemIndexes(true);
- break;
-
- case 'o':
-
- /*
- * o - send output (stdout and stderr) to the given file
- */
- if (secure)
- StrNCpy(OutputFileName, optarg, MAXPGPATH);
- break;
-
- case 'p':
-
- /*
- * p - special flag passed if backend was forked by a
- * postmaster.
- */
- if (secure)
- {
- DBName = strdup(optarg);
- secure = false; /* subsequent switches are NOT
- * secure */
- ctx = PGC_BACKEND;
- gucsource = PGC_S_CLIENT;
- }
- break;
-
- case 'S':
-
- /*
- * S - amount of sort memory to use in 1k bytes
- */
- SetConfigOption("sort_mem", optarg, ctx, gucsource);
- break;
-
- case 's':
-
- /*
- * s - report usage statistics (timings) after each query
- */
- SetConfigOption("show_query_stats", "true", ctx, gucsource);
- break;
-
- case 't':
- /* ---------------
- * tell postgres to report usage statistics (timings) for
- * each query
- *
- * -tpa[rser] = print stats for parser time of each query
- * -tpl[anner] = print stats for planner time of each query
- * -te[xecutor] = print stats for executor time of each query
- * caution: -s can not be used together with -t.
- * ----------------
- */
- tmp = NULL;
- switch (optarg[0])
- {
- case 'p':
- if (optarg[1] == 'a')
- tmp = "show_parser_stats";
- else if (optarg[1] == 'l')
- tmp = "show_planner_stats";
- else
- errs++;
- break;
- case 'e':
- tmp = "show_executor_stats";
- break;
- default:
- errs++;
- break;
- }
- if (tmp)
- SetConfigOption(tmp, "true", ctx, gucsource);
- break;
-
- case 'v':
- if (secure)
- FrontendProtocol = (ProtocolVersion) atoi(optarg);
- break;
-
- case 'W':
-
- /*
- * wait N seconds to allow attach from a debugger
- */
- sleep(atoi(optarg));
- break;
-
- case 'x':
-#ifdef NOT_USED /* planner/xfunc.h */
-
- /*
- * control joey hellerstein's expensive function
- * optimization
- */
- if (XfuncMode != 0)
- {
- elog(WARNING, "only one -x flag is allowed");
- errs++;
- break;
- }
- if (strcmp(optarg, "off") == 0)
- XfuncMode = XFUNC_OFF;
- else if (strcmp(optarg, "nor") == 0)
- XfuncMode = XFUNC_NOR;
- else if (strcmp(optarg, "nopull") == 0)
- XfuncMode = XFUNC_NOPULL;
- else if (strcmp(optarg, "nopm") == 0)
- XfuncMode = XFUNC_NOPM;
- else if (strcmp(optarg, "pullall") == 0)
- XfuncMode = XFUNC_PULLALL;
- else if (strcmp(optarg, "wait") == 0)
- XfuncMode = XFUNC_WAIT;
- else
- {
- elog(WARNING, "use -x {off,nor,nopull,nopm,pullall,wait}");
- errs++;
- }
-#endif
- break;
-
- case 'c':
- case '-':
- {
- char *name,
- *value;
-
- ParseLongOption(optarg, &name, &value);
- if (!value)
- {
- if (flag == '-')
- elog(ERROR, "--%s requires argument", optarg);
- else
- elog(ERROR, "-c %s requires argument", optarg);
- }
-
- SetConfigOption(name, value, ctx, gucsource);
- free(name);
- if (value)
- free(value);
- break;
- }
-
- default:
- errs++;
- break;
- }
-
- /*
- * Post-processing for command line options.
- */
- if (Show_query_stats &&
- (Show_parser_stats || Show_planner_stats || Show_executor_stats))
- {
- elog(WARNING, "Query statistics are disabled because parser, planner, or executor statistics are on.");
- SetConfigOption("show_query_stats", "false", ctx, gucsource);
- }
-
- if (!IsUnderPostmaster)
- {
- if (!potential_DataDir)
- {
- fprintf(stderr, "%s does not know where to find the database system "
- "data. You must specify the directory that contains the "
- "database system either by specifying the -D invocation "
- "option or by setting the PGDATA environment variable.\n\n",
- argv[0]);
- proc_exit(1);
- }
- SetDataDir(potential_DataDir);
- }
- Assert(DataDir);
-
- /*
- * Set up signal handlers and masks.
- *
- * Note that postmaster blocked all signals before forking child process,
- * so there is no race condition whereby we might receive a signal
- * before we have set up the handler.
- *
- * Also note: it's best not to use any signals that are SIG_IGNored in
- * the postmaster. If such a signal arrives before we are able to
- * change the handler to non-SIG_IGN, it'll get dropped. Instead,
- * make a dummy handler in the postmaster to reserve the signal.
- * (Of course, this isn't an issue for signals that are locally generated,
- * such as SIGALRM and SIGPIPE.)
- */
-
- pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
- pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
- pqsignal(SIGTERM, die); /* cancel current query and exit */
- pqsignal(SIGQUIT, quickdie); /* hard crash time */
- pqsignal(SIGALRM, HandleDeadLock); /* check for deadlock after
- * timeout */
-
- /*
- * Ignore failure to write to frontend. Note: if frontend closes
- * connection, we will notice it and exit cleanly when control next
- * returns to outer loop. This seems safer than forcing exit in the
- * midst of output during who-knows-what operation...
- */
- pqsignal(SIGPIPE, SIG_IGN);
- pqsignal(SIGUSR1, SIG_IGN); /* this signal available for use */
-
- pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */
- pqsignal(SIGFPE, FloatExceptionHandler);
-
- /*
- * Reset some signals that are accepted by postmaster but not by
- * backend
- */
- pqsignal(SIGCHLD, SIG_DFL); /* system() requires this on some
- * platforms */
-
- pqinitmask();
-
- /* We allow SIGQUIT (quickdie) at all times */
-#ifdef HAVE_SIGPROCMASK
- sigdelset(&BlockSig, SIGQUIT);
-#else
- BlockSig &= ~(sigmask(SIGQUIT));
-#endif
-
- PG_SETMASK(&BlockSig); /* block everything except SIGQUIT */
-
-
- if (IsUnderPostmaster)
- {
- /* noninteractive case: nothing should be left after switches */
- if (errs || argc != optind || DBName == NULL)
- {
- elog(WARNING, "%s: invalid command line arguments\nTry -? for help.",
- argv[0]);
- proc_exit(0); /* not 1, that causes system-wide
- * restart... */
- }
- BaseInit();
- }
- else
- {
- /* interactive case: database name can be last arg on command line */
- if (errs || argc - optind > 1)
- {
- elog(WARNING, "%s: invalid command line arguments\nTry -? for help.",
- argv[0]);
- proc_exit(1);
- }
- else if (argc - optind == 1)
- DBName = argv[optind];
- else if ((DBName = username) == NULL)
- {
- elog(WARNING, "%s: user name undefined and no database specified",
- argv[0]);
- proc_exit(1);
- }
-
- /*
- * On some systems our dynloader code needs the executable's
- * pathname. (If under postmaster, this was done already.)
- */
- if (FindExec(pg_pathname, argv[0], "postgres") < 0)
- elog(FATAL, "%s: could not locate executable, bailing out...",
- argv[0]);
-
- /*
- * Validate we have been given a reasonable-looking DataDir (if
- * under postmaster, assume postmaster did this already).
- */
- ValidatePgVersion(DataDir);
-
- /*
- * Create lockfile for data directory.
- */
- if (!CreateDataDirLockFile(DataDir, false))
- proc_exit(1);
-
- XLOGPathInit();
- BaseInit();
-
- /*
- * Start up xlog for standalone backend, and register to have it
- * closed down at exit.
- */
- StartupXLOG();
- on_shmem_exit(ShutdownXLOG, 0);
- }
-
- /*
- * Set up additional info.
- */
-
-#ifdef CYR_RECODE
- SetCharSet();
-#endif
-
- /*
- * General initialization.
- *
- * NOTE: if you are tempted to add code in this vicinity, consider
- * putting it inside InitPostgres() instead. In particular, anything
- * that involves database access should be there, not here.
- */
- elog(DEBUG2, "InitPostgres");
- InitPostgres(DBName, username);
-
- SetProcessingMode(NormalProcessing);
-
- /*
- * Send this backend's cancellation info to the frontend.
- */
- if (whereToSendOutput == Remote &&
- PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
- {
- StringInfoData buf;
-
- pq_beginmessage(&buf);
- pq_sendbyte(&buf, 'K');
- pq_sendint(&buf, (int32) MyProcPid, sizeof(int32));
- pq_sendint(&buf, (int32) MyCancelKey, sizeof(int32));
- pq_endmessage(&buf);
- /* Need not flush since ReadyForQuery will do it. */
- }
-
- if (!IsUnderPostmaster)
- {
- puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.268 $ $Date: 2002/06/20 20:29:36 $\n");
- }
-
- /*
- * 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);
-
- /* ----------
- * Tell the statistics collector that we're alive and
- * to which database we belong.
- * ----------
- */
- pgstat_bestart();
-
- /*
- * POSTGRES main processing loop begins here
- *
- * If an exception is encountered, processing resumes here so we abort
- * the current transaction and start a new one.
- */
-
- if (sigsetjmp(Warn_restart, 1) != 0)
- {
- /*
- * NOTE: if you are tempted to add more code in this if-block,
- * consider the probability that it should be in
- * AbortTransaction() instead.
- *
- * Make sure we're not interrupted while cleaning up. Also forget
- * any pending QueryCancel request, since we're aborting anyway.
- * Force InterruptHoldoffCount to a known state in case we elog'd
- * from inside a holdoff section.
- */
- ImmediateInterruptOK = false;
- QueryCancelPending = false;
- InterruptHoldoffCount = 1;
- CritSectionCount = 0; /* should be unnecessary, but... */
- debug_query_string = NULL; /* used by pgmonitor */
-
- /*
- * 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);
-
- /* Do the recovery */
- elog(DEBUG1, "AbortCurrentTransaction");
- AbortCurrentTransaction();
-
- /*
- * Now return to normal top-level context and clear ErrorContext
- * for next time.
- */
- MemoryContextSwitchTo(TopMemoryContext);
- MemoryContextResetAndDeleteChildren(ErrorContext);
-
- /*
- * Clear flag to indicate that we got out of error recovery mode
- * successfully. (Flag was set in elog.c before longjmp().)
- */
- InError = false;
-
- /*
- * Exit interrupt holdoff section we implicitly established above.
- */
- RESUME_INTERRUPTS();
- }
-
- Warn_restart_ready = true; /* we can now handle elog(ERROR) */
-
- PG_SETMASK(&UnBlockSig);
-
- /*
- * Non-error queries loop here.
- */
-
- for (;;)
- {
- /*
- * 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();
-
- /*
- * (1) tell the frontend we're ready for a new query.
- *
- * Note: this includes fflush()'ing the last of the prior output.
- */
- ReadyForQuery(whereToSendOutput);
-
- /* ----------
- * Tell the statistics collector what we've collected
- * so far.
- * ----------
- */
- pgstat_report_tabstat();
-
- if (IsTransactionBlock())
- {
- set_ps_display("idle in transaction");
- pgstat_report_activity("<IDLE> in transaction");
- }
- else
- {
- set_ps_display("idle");
- pgstat_report_activity("<IDLE>");
- }
-
- /*
- * (2) deal with pending asynchronous NOTIFY from other backends,
- * and enable async.c's signal handler to execute NOTIFY directly.
- * Then set up other stuff needed before blocking for input.
- */
- QueryCancelPending = false; /* forget any earlier CANCEL
- * signal */
-
- EnableNotifyInterrupt();
-
- /* Allow "die" interrupt to be processed while waiting */
- ImmediateInterruptOK = true;
- /* and don't forget to detect one that already arrived */
- QueryCancelPending = false;
- CHECK_FOR_INTERRUPTS();
-
- /*
- * (3) read a command (loop blocks here)
- */
- firstchar = ReadCommand(parser_input);
-
- /*
- * (4) disable async signal conditions again.
- */
- ImmediateInterruptOK = false;
- QueryCancelPending = false; /* forget any CANCEL signal */
-
- DisableNotifyInterrupt();
-
- /*
- * (5) check for any other interesting events that happened while
- * we slept.
- */
- if (got_SIGHUP)
- {
- got_SIGHUP = false;
- ProcessConfigFile(PGC_SIGHUP);
- }
-
- /*
- * (6) process the command.
- */
- switch (firstchar)
- {
- /*
- * 'F' indicates a fastpath call.
- */
- case 'F':
- /* ----------
- * Tell the collector what we're doing
- * ----------
- */
- pgstat_report_activity("<FASTPATH> function call");
-
- /* start an xact for this function invocation */
- start_xact_command();
-
- if (HandleFunctionRequest() == EOF)
- {
- /* lost frontend connection during F message input */
- /*
- * Reset whereToSendOutput to prevent elog from attempting
- * to send any more messages to client.
- */
- if (whereToSendOutput == Remote)
- whereToSendOutput = None;
-
- proc_exit(0);
- }
-
- /* commit the function-invocation transaction */
- finish_xact_command();
- break;
-
- /*
- * 'Q' indicates a user query
- */
- case 'Q':
- if (strspn(parser_input->data, " \t\r\n") == parser_input->len)
- {
- /*
- * if there is nothing in the input buffer, don't
- * bother trying to parse and execute anything; just
- * send back a quick NullCommand response.
- */
- if (IsUnderPostmaster)
- NullCommand(Remote);
- }
- else
- {
- /*
- * otherwise, process the input string.
- *
- * Note: transaction command start/end is now done within
- * pg_exec_query_string(), not here.
- */
- if (Show_query_stats)
- ResetUsage();
-
- pgstat_report_activity(parser_input->data);
-
- pg_exec_query_string(parser_input,
- whereToSendOutput,
- QueryContext);
-
- if (Show_query_stats)
- ShowUsage("QUERY STATISTICS");
- }
- break;
-
- /*
- * 'X' means that the frontend is closing down the socket.
- * EOF means unexpected loss of frontend connection.
- * Either way, perform normal shutdown.
- */
- case 'X':
- case EOF:
- /*
- * Reset whereToSendOutput to prevent elog from attempting
- * to send any more messages to client.
- */
- if (whereToSendOutput == Remote)
- whereToSendOutput = None;
-
- /*
- * NOTE: if you are tempted to add more code here, DON'T!
- * Whatever you had in mind to do should be set up as an
- * on_proc_exit or on_shmem_exit callback, instead.
- * Otherwise it will fail to be called during other
- * backend-shutdown scenarios.
- */
- proc_exit(0);
-
- default:
- elog(ERROR, "unknown frontend message was received");
- }
-
-#ifdef MEMORY_CONTEXT_CHECKING
-
- /*
- * Check all memory after each backend loop. This is a rather
- * weird place to do it, perhaps.
- */
- MemoryContextCheck(TopMemoryContext);
-#endif
- } /* end of input-reading loop */
-
- /* can't get here because the above loop never exits */
- Assert(false);
-
- return 1; /* keep compiler quiet */
-}
-
-#ifndef HAVE_GETRUSAGE
-#include "rusagestub.h"
-#else
-#include <sys/resource.h>
-#endif /* HAVE_GETRUSAGE */
-
-struct rusage Save_r;
-struct timeval Save_t;
-
-void
-ResetUsage(void)
-{
- struct timezone tz;
-
- getrusage(RUSAGE_SELF, &Save_r);
- gettimeofday(&Save_t, &tz);
- ResetBufferUsage();
-/* ResetTupleCount(); */
-}
-
-void
-ShowUsage(const char *title)
-{
- StringInfoData str;
- struct timeval user,
- sys;
- struct timeval elapse_t;
- struct timezone tz;
- struct rusage r;
- char *bufusage;
-
- getrusage(RUSAGE_SELF, &r);
- gettimeofday(&elapse_t, &tz);
- memcpy((char *) &user, (char *) &r.ru_utime, sizeof(user));
- memcpy((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
- if (elapse_t.tv_usec < Save_t.tv_usec)
- {
- elapse_t.tv_sec--;
- elapse_t.tv_usec += 1000000;
- }
- if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec)
- {
- r.ru_utime.tv_sec--;
- r.ru_utime.tv_usec += 1000000;
- }
- if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec)
- {
- r.ru_stime.tv_sec--;
- r.ru_stime.tv_usec += 1000000;
- }
-
- /*
- * the only stats we don't show here are for memory usage -- i can't
- * figure out how to interpret the relevant fields in the rusage
- * struct, and they change names across o/s platforms, anyway. if you
- * can figure out what the entries mean, you can somehow extract
- * resident set size, shared text size, and unshared data and stack
- * sizes.
- */
- initStringInfo(&str);
-
- appendStringInfo(&str, "! system usage stats:\n");
- appendStringInfo(&str,
- "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
- (long int) elapse_t.tv_sec - Save_t.tv_sec,
- (long int) elapse_t.tv_usec - Save_t.tv_usec,
- (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
- (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
- (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
- (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
- appendStringInfo(&str,
- "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
- (long int) user.tv_sec,
- (long int) user.tv_usec,
- (long int) sys.tv_sec,
- (long int) sys.tv_usec);
-/* BeOS has rusage but only has some fields, and not these... */
-#if defined(HAVE_GETRUSAGE)
- appendStringInfo(&str,
- "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
- r.ru_inblock - Save_r.ru_inblock,
- /* they only drink coffee at dec */
- r.ru_oublock - Save_r.ru_oublock,
- r.ru_inblock, r.ru_oublock);
- appendStringInfo(&str,
- "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
- r.ru_majflt - Save_r.ru_majflt,
- r.ru_minflt - Save_r.ru_minflt,
- r.ru_majflt, r.ru_minflt,
- r.ru_nswap - Save_r.ru_nswap,
- r.ru_nswap);
- appendStringInfo(&str,
- "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
- r.ru_nsignals - Save_r.ru_nsignals,
- r.ru_nsignals,
- r.ru_msgrcv - Save_r.ru_msgrcv,
- r.ru_msgsnd - Save_r.ru_msgsnd,
- r.ru_msgrcv, r.ru_msgsnd);
- appendStringInfo(&str,
- "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
- r.ru_nvcsw - Save_r.ru_nvcsw,
- r.ru_nivcsw - Save_r.ru_nivcsw,
- r.ru_nvcsw, r.ru_nivcsw);
-#endif /* HAVE_GETRUSAGE */
-
- bufusage = ShowBufferUsage();
- appendStringInfo(&str, "! postgres usage stats:\n%s", bufusage);
- pfree(bufusage);
-
- /* remove trailing newline */
- if (str.data[str.len-1] == '\n')
- str.data[--str.len] = '\0';
-
- elog(LOG, "%s\n%s", title, str.data);
-
- pfree(str.data);
-}
-
-#ifdef NOT_USED
-static int
-assertEnable(int val)
-{
- assert_enabled = val;
- return val;
-}
-
-#ifdef ASSERT_CHECKING_TEST
-int
-assertTest(int val)
-{
- Assert(val == 0);
-
- if (assert_enabled)
- {
- /* val != 0 should be trapped by previous Assert */
- elog(DEBUG3, "Assert test successful (val = %d)", val);
- }
- else
- elog(DEBUG3, "Assert checking is disabled (val = %d)", val);
-
- return val;
-}
-#endif
-
-#endif
-
-
-/* ----------------------------------------------------------------
- * CreateCommandTag
- *
- * utility to get a string representation of the
- * command operation.
- * ----------------------------------------------------------------
- */
-static const char *
-CreateCommandTag(Node *parsetree)
-{
- const char *tag;
-
- switch (nodeTag(parsetree))
- {
- case T_InsertStmt:
- tag = "INSERT";
- break;
-
- case T_DeleteStmt:
- tag = "DELETE";
- break;
-
- case T_UpdateStmt:
- tag = "UPDATE";
- break;
-
- case T_SelectStmt:
- tag = "SELECT";
- break;
-
- case T_TransactionStmt:
- {
- TransactionStmt *stmt = (TransactionStmt *) parsetree;
-
- switch (stmt->command)
- {
- case BEGIN_TRANS:
- tag = "BEGIN";
- break;
-
- case COMMIT:
- tag = "COMMIT";
- break;
-
- case ROLLBACK:
- tag = "ROLLBACK";
- break;
-
- default:
- tag = "???";
- break;
- }
- }
- break;
-
- case T_ClosePortalStmt:
- tag = "CLOSE CURSOR";
- break;
-
- case T_FetchStmt:
- {
- FetchStmt *stmt = (FetchStmt *) parsetree;
- tag = (stmt->ismove) ? "MOVE" : "FETCH";
- }
- break;
-
- case T_CreateDomainStmt:
- tag = "CREATE DOMAIN";
- break;
-
- case T_CreateSchemaStmt:
- tag = "CREATE SCHEMA";
- break;
-
- case T_CreateStmt:
- tag = "CREATE TABLE";
- break;
-
- case T_DropStmt:
- switch (((DropStmt *) parsetree)->removeType)
- {
- case DROP_TABLE:
- tag = "DROP TABLE";
- break;
- case DROP_SEQUENCE:
- tag = "DROP SEQUENCE";
- break;
- case DROP_VIEW:
- tag = "DROP VIEW";
- break;
- case DROP_INDEX:
- tag = "DROP INDEX";
- break;
- case DROP_TYPE:
- tag = "DROP TYPE";
- break;
- case DROP_DOMAIN:
- tag = "DROP DOMAIN";
- break;
- default:
- tag = "???";
- }
- break;
-
- case T_TruncateStmt:
- tag = "TRUNCATE TABLE";
- break;
-
- case T_CommentStmt:
- tag = "COMMENT";
- break;
-
- case T_CopyStmt:
- tag = "COPY";
- break;
-
- case T_RenameStmt:
- if (((RenameStmt *)parsetree)->renameType == RENAME_TRIGGER)
- tag = "ALTER TRIGGER";
- else
- tag = "ALTER TABLE";
- break;
-
- case T_AlterTableStmt:
- tag = "ALTER TABLE";
- break;
-
- case T_GrantStmt:
- {
- GrantStmt *stmt = (GrantStmt *) parsetree;
- tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
- }
- break;
-
- case T_DefineStmt:
- switch (((DefineStmt *) parsetree)->defType)
- {
- case AGGREGATE:
- tag = "CREATE AGGREGATE";
- break;
- case OPERATOR:
- tag = "CREATE OPERATOR";
- break;
- case TYPE_P:
- tag = "CREATE TYPE";
- break;
- default:
- tag = "???";
- }
- break;
-
- case T_ViewStmt:
- tag = "CREATE VIEW";
- break;
-
- case T_CreateFunctionStmt:
- tag = "CREATE FUNCTION";
- break;
-
- case T_IndexStmt:
- tag = "CREATE INDEX";
- break;
-
- case T_RuleStmt:
- tag = "CREATE RULE";
- break;
-
- case T_CreateSeqStmt:
- tag = "CREATE SEQUENCE";
- break;
-
- case T_RemoveAggrStmt:
- tag = "DROP AGGREGATE";
- break;
-
- case T_RemoveFuncStmt:
- tag = "DROP FUNCTION";
- break;
-
- case T_RemoveOperStmt:
- tag = "DROP OPERATOR";
- break;
-
- case T_CreatedbStmt:
- tag = "CREATE DATABASE";
- break;
-
- case T_AlterDatabaseSetStmt:
- tag = "ALTER DATABASE";
- break;
-
- case T_DropdbStmt:
- tag = "DROP DATABASE";
- break;
-
- case T_NotifyStmt:
- tag = "NOTIFY";
- break;
-
- case T_ListenStmt:
- tag = "LISTEN";
- break;
-
- case T_UnlistenStmt:
- tag = "UNLISTEN";
- break;
-
- case T_LoadStmt:
- tag = "LOAD";
- break;
-
- case T_ClusterStmt:
- tag = "CLUSTER";
- break;
-
- case T_VacuumStmt:
- if (((VacuumStmt *) parsetree)->vacuum)
- tag = "VACUUM";
- else
- tag = "ANALYZE";
- break;
-
- case T_ExplainStmt:
- tag = "EXPLAIN";
- break;
-
-#ifdef NOT_USED
- case T_RecipeStmt:
- tag = "EXECUTE RECIPE";
- break;
-#endif
-
- case T_VariableSetStmt:
- tag = "SET";
- break;
-
- case T_VariableShowStmt:
- tag = "SHOW";
- break;
-
- case T_VariableResetStmt:
- tag = "RESET";
- break;
-
- case T_CreateTrigStmt:
- tag = "CREATE TRIGGER";
- break;
-
- case T_DropPropertyStmt:
- switch (((DropPropertyStmt *) parsetree)->removeType)
- {
- case DROP_TRIGGER:
- tag = "DROP TRIGGER";
- break;
- case DROP_RULE:
- tag = "DROP RULE";
- break;
- default:
- tag = "???";
- }
- break;
-
- case T_CreatePLangStmt:
- tag = "CREATE LANGUAGE";
- break;
-
- case T_DropPLangStmt:
- tag = "DROP LANGUAGE";
- break;
-
- case T_CreateUserStmt:
- tag = "CREATE USER";
- break;
-
- case T_AlterUserStmt:
- tag = "ALTER USER";
- break;
-
- case T_AlterUserSetStmt:
- tag = "ALTER USER";
- break;
-
- case T_DropUserStmt:
- tag = "DROP USER";
- break;
-
- case T_LockStmt:
- tag = "LOCK TABLE";
- break;
-
- case T_ConstraintsSetStmt:
- tag = "SET CONSTRAINTS";
- break;
-
- case T_CreateGroupStmt:
- tag = "CREATE GROUP";
- break;
-
- case T_AlterGroupStmt:
- tag = "ALTER GROUP";
- break;
-
- case T_DropGroupStmt:
- tag = "DROP GROUP";
- break;
-
- case T_CheckPointStmt:
- tag = "CHECKPOINT";
- break;
-
- case T_ReindexStmt:
- tag = "REINDEX";
- break;
-
- default:
- elog(LOG, "CreateCommandTag: unknown parse node type %d",
- nodeTag(parsetree));
- tag = "???";
- break;
- }
-
- return tag;
-}