*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.534 2007/06/23 22:12:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.538 2007/11/15 21:14:38 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
#include "optimizer/planner.h"
#include "parser/analyze.h"
#include "parser/parser.h"
+#include "postmaster/autovacuum.h"
#include "rewrite/rewriteHandler.h"
#include "storage/freespace.h"
#include "storage/ipc.h"
* in order to reduce overhead for short-lived queries.
*/
static CachedPlanSource *unnamed_stmt_psrc = NULL;
+
/* workspace for building a new unnamed statement in */
static MemoryContext unnamed_stmt_context = NULL;
* ----------------------------------------------------------------
*/
static int InteractiveBackend(StringInfo inBuf);
+static int interactive_getc(void);
static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf);
static List *pg_rewrite_query(Query *query);
resetStringInfo(inBuf);
- for (;;)
+ if (UseNewLine)
{
- if (UseNewLine)
+ /*
+ * if we are using \n as a delimiter, then read characters until the
+ * \n.
+ */
+ while ((c = interactive_getc()) != EOF)
{
- /*
- * if we are using \n as a delimiter, then read characters until
- * the \n.
- */
- while ((c = getc(stdin)) != EOF)
+ if (c == '\n')
{
- if (c == '\n')
+ if (backslashSeen)
{
- if (backslashSeen)
- {
- /* discard backslash from inBuf */
- inBuf->data[--inBuf->len] = '\0';
- backslashSeen = false;
- continue;
- }
- else
- {
- /* keep the newline character */
- appendStringInfoChar(inBuf, '\n');
- break;
- }
+ /* discard backslash from inBuf */
+ inBuf->data[--inBuf->len] = '\0';
+ backslashSeen = false;
+ continue;
}
- else if (c == '\\')
- backslashSeen = true;
else
- backslashSeen = false;
-
- appendStringInfoChar(inBuf, (char) c);
+ {
+ /* keep the newline character */
+ appendStringInfoChar(inBuf, '\n');
+ break;
+ }
}
+ else if (c == '\\')
+ backslashSeen = true;
+ else
+ backslashSeen = false;
- 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;
+ appendStringInfoChar(inBuf, (char) c);
}
- if (end)
- return EOF;
-
+ if (c == EOF)
+ end = true;
+ }
+ else
+ {
/*
- * otherwise we have a user query so process it.
+ * otherwise read characters until EOF.
*/
- break;
+ while ((c = interactive_getc()) != EOF)
+ appendStringInfoChar(inBuf, (char) c);
+
+ /* No input before EOF signal means time to quit. */
+ if (inBuf->len == 0)
+ end = true;
}
+ if (end)
+ return EOF;
+
+ /*
+ * otherwise we have a user query so process it.
+ */
+
/* Add '\0' to make it look the same as message case. */
appendStringInfoChar(inBuf, (char) '\0');
return 'Q';
}
+/*
+ * interactive_getc -- collect one character from stdin
+ *
+ * Even though we are not reading from a "client" process, we still want to
+ * respond to signals, particularly SIGTERM/SIGQUIT. Hence we must use
+ * prepare_for_client_read and client_read_ended.
+ */
+static int
+interactive_getc(void)
+{
+ int c;
+
+ prepare_for_client_read();
+ c = getc(stdin);
+ client_read_ended();
+ return c;
+}
+
/* ----------------
* SocketBackend() Is called for frontend-backend connections
*
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
+ * 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);
* originally specified parameter set is not required to be complete,
* so we have to use parse_analyze_varparams().
*
- * XXX must use copyObject here since parse analysis scribbles on
- * its input, and we need the unmodified raw parse tree for possible
+ * XXX must use copyObject here since parse analysis scribbles on its
+ * input, and we need the unmodified raw parse tree for possible
* replanning later.
*/
if (log_parser_stats)
commandTag,
paramTypes,
numParams,
- 0, /* default cursor options */
+ 0, /* default cursor options */
stmt_list,
false);
}
* paramTypes and query_string need to be copied into
* unnamed_stmt_context. The rest is there already
*/
- Oid *newParamTypes;
+ Oid *newParamTypes;
if (numParams > 0)
{
commandTag,
newParamTypes,
numParams,
- 0, /* cursor options */
+ 0, /* cursor options */
stmt_list,
fully_planned,
true,
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("bind message supplies %d parameters, but prepared statement \"%s\" requires %d",
- numParams, stmt_name, psrc->num_params)));
+ numParams, stmt_name, psrc->num_params)));
/*
* If we are in aborted transaction state, the only portals we can
{
/*
* Revalidate the cached plan; this may result in replanning. Any
- * cruft will be generated in MessageContext. The plan refcount
- * will be assigned to the Portal, so it will be released at portal
+ * cruft will be generated in MessageContext. The plan refcount will
+ * be assigned to the Portal, so it will be released at portal
* destruction.
*/
cplan = RevalidateCachedPlan(psrc, false);
*stmt_name ? stmt_name : "<unnamed>",
*portal_name ? "/" : "",
*portal_name ? portal_name : "",
- psrc->query_string ? psrc->query_string : "<source not stored>"),
+ psrc->query_string ? psrc->query_string : "<source not stored>"),
errhidestmt(true),
errdetail_params(params)));
break;
completed = PortalRun(portal,
max_rows,
- true, /* always top level */
+ true, /* always top level */
receiver,
receiver,
completionTag);
/*
* If we are in aborted transaction state, we can't run
- * SendRowDescriptionMessage(), because that needs catalog accesses.
- * (We can't do RevalidateCachedPlan, either, but that's a lesser problem.)
+ * SendRowDescriptionMessage(), because that needs catalog accesses. (We
+ * can't do RevalidateCachedPlan, either, but that's a lesser problem.)
* Hence, refuse to Describe statements that return data. (We shouldn't
* just refuse all Describes, since that might break the ability of some
* clients to issue COMMIT or ROLLBACK commands, if they use code that
if (unnamed_stmt_psrc)
DropCachedPlan(unnamed_stmt_psrc);
unnamed_stmt_psrc = NULL;
+
/*
* If we failed while trying to build a prior unnamed statement, we may
* have a memory context that wasn't assigned to a completed plancache
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
- ereport(FATAL,
- (errcode(ERRCODE_ADMIN_SHUTDOWN),
+ if (IsAutoVacuumWorkerProcess())
+ ereport(FATAL,
+ (errcode(ERRCODE_ADMIN_SHUTDOWN),
+ errmsg("terminating autovacuum process due to administrator command")));
+ else
+ ereport(FATAL,
+ (errcode(ERRCODE_ADMIN_SHUTDOWN),
errmsg("terminating connection due to administrator command")));
}
if (QueryCancelPending)
ereport(ERROR,
(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
errmsg("stack depth limit exceeded"),
- errhint("Increase the configuration parameter \"max_stack_depth\", "
- "after ensuring the platform's stack depth limit is adequate.")));
+ errhint("Increase the configuration parameter \"max_stack_depth\", "
+ "after ensuring the platform's stack depth limit is adequate.")));
}
}
*/
MyProcPid = getpid();
+ MyStartTime = time(NULL);
+
/*
* Fire up essential subsystems: error and memory management
*
gucsource = PGC_S_ARGV; /* initial switches came from command line */
/*
- * Parse command-line options. CAUTION: keep this in sync with
- * postmaster/postmaster.c (the option sets should not conflict)
- * and with the common help() function in main/main.c.
+ * Parse command-line options. CAUTION: keep this in sync with
+ * postmaster/postmaster.c (the option sets should not conflict) and with
+ * the common help() function in main/main.c.
*/
while ((flag = getopt(argc, argv, "A:B:c:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:v:W:y:-:")) != -1)
{
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, StatementCancelHandler); /* cancel current query */
pqsignal(SIGTERM, die); /* cancel current query and exit */
- pqsignal(SIGQUIT, quickdie); /* hard crash time */
+
+ /*
+ * In a standalone backend, SIGQUIT can be generated from the keyboard
+ * easily, while SIGTERM cannot, so we make both signals do die() rather
+ * than quickdie().
+ */
+ if (IsUnderPostmaster)
+ pqsignal(SIGQUIT, quickdie); /* hard crash time */
+ else
+ pqsignal(SIGQUIT, die); /* cancel current query and exit */
pqsignal(SIGALRM, handle_sig_alarm); /* timeout conditions */
/*
pqinitmask();
- /* We allow SIGQUIT (quickdie) at all times */
+ if (IsUnderPostmaster)
+ {
+ /* We allow SIGQUIT (quickdie) at all times */
#ifdef HAVE_SIGPROCMASK
- sigdelset(&BlockSig, SIGQUIT);
+ sigdelset(&BlockSig, SIGQUIT);
#else
- BlockSig &= ~(sigmask(SIGQUIT));
+ BlockSig &= ~(sigmask(SIGQUIT));
#endif
+ }
PG_SETMASK(&BlockSig); /* block everything except SIGQUIT */
val = rlim.rlim_cur;
}
return val;
-#else /* no getrlimit */
+#else /* no getrlimit */
#if defined(WIN32) || defined(__CYGWIN__)
/* On Windows we set the backend stack size in src/backend/Makefile */
return WIN32_STACK_RLIMIT;
-#else /* not windows ... give up */
+#else /* not windows ... give up */
return -1;
#endif
#endif