Commit 9e09e3b1 authored by Tom Lane's avatar Tom Lane

Fix single-user mode so that interrupts (particularly SIGTERM and

SIGQUIT) will be recognized and processed while waiting for input,
rather than only after something has been typed.  Also make SIGQUIT
do the same thing as SIGTERM in single-user mode, ie, do a normal
shutdown and exit.  Since it's relatively easy to provoke SIGQUIT
from the keyboard, people may try that instead of control-D, and we'd
rather this leads to orderly shutdown.  Per report from Leon Mergen
and subsequent discussion.
parent 9b619679
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.535 2007/06/29 17:07:39 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.536 2007/07/09 01:15:14 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -164,6 +164,7 @@ static int UseNewLine = 0; /* Use EOF as query delimiters */
* ----------------------------------------------------------------
*/
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);
......@@ -210,64 +211,61 @@ InteractiveBackend(StringInfo inBuf)
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');
......@@ -281,6 +279,24 @@ InteractiveBackend(StringInfo inBuf)
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
*
......@@ -3092,7 +3108,16 @@ PostgresMain(int argc, char *argv[], const char *username)
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 */
/*
......@@ -3113,12 +3138,15 @@ PostgresMain(int argc, char *argv[], const char *username)
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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment