summaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
authorPavan Deolasee2015-06-04 08:02:02 +0000
committerPavan Deolasee2015-06-04 08:02:02 +0000
commit1e86f652fa5e214a284f9862c67bb976317ac730 (patch)
tree2478baa40ebd47196528ee0a5aa6f6921d8e5bd9 /src/backend/tcop/postgres.c
parent3165b5fde927ff766921270bd56d3236b6c09c21 (diff)
parent4cb7d671fddc8855c8def2de51fb23df1c8ac0af (diff)
Merge remote-tracking branch 'remotes/PGSQL/master' into XL_NEW_MASTER
Conflicts: COPYRIGHT configure configure.in contrib/Makefile doc/bug.template src/backend/access/common/heaptuple.c src/backend/access/common/printtup.c src/backend/access/transam/Makefile src/backend/access/transam/clog.c src/backend/access/transam/twophase.c src/backend/access/transam/varsup.c src/backend/access/transam/xact.c src/backend/access/transam/xlog.c src/backend/bootstrap/bootstrap.c src/backend/catalog/Makefile src/backend/catalog/catalog.c src/backend/catalog/dependency.c src/backend/catalog/genbki.pl src/backend/catalog/namespace.c src/backend/catalog/pg_aggregate.c src/backend/catalog/pg_proc.c src/backend/catalog/storage.c src/backend/commands/aggregatecmds.c src/backend/commands/analyze.c src/backend/commands/comment.c src/backend/commands/copy.c src/backend/commands/dbcommands.c src/backend/commands/event_trigger.c src/backend/commands/explain.c src/backend/commands/indexcmds.c src/backend/commands/portalcmds.c src/backend/commands/schemacmds.c src/backend/commands/sequence.c src/backend/commands/tablecmds.c src/backend/commands/trigger.c src/backend/commands/vacuum.c src/backend/commands/variable.c src/backend/commands/view.c src/backend/executor/execAmi.c src/backend/executor/execCurrent.c src/backend/executor/execMain.c src/backend/executor/execProcnode.c src/backend/executor/execTuples.c src/backend/executor/execUtils.c src/backend/executor/nodeAgg.c src/backend/executor/nodeModifyTable.c src/backend/executor/nodeSubplan.c src/backend/executor/nodeWindowAgg.c src/backend/libpq/hba.c src/backend/nodes/copyfuncs.c src/backend/nodes/equalfuncs.c src/backend/nodes/outfuncs.c src/backend/nodes/readfuncs.c src/backend/optimizer/path/allpaths.c src/backend/optimizer/path/costsize.c src/backend/optimizer/plan/createplan.c src/backend/optimizer/plan/planagg.c src/backend/optimizer/plan/planner.c src/backend/optimizer/plan/setrefs.c src/backend/optimizer/plan/subselect.c src/backend/optimizer/prep/preptlist.c src/backend/optimizer/prep/prepunion.c src/backend/optimizer/util/pathnode.c src/backend/optimizer/util/plancat.c src/backend/parser/analyze.c src/backend/parser/gram.y src/backend/parser/parse_agg.c src/backend/parser/parse_relation.c src/backend/parser/parse_utilcmd.c src/backend/postmaster/autovacuum.c src/backend/postmaster/pgstat.c src/backend/postmaster/postmaster.c src/backend/replication/logical/decode.c src/backend/storage/buffer/bufmgr.c src/backend/storage/ipc/ipci.c src/backend/storage/ipc/procarray.c src/backend/storage/ipc/procsignal.c src/backend/storage/lmgr/lock.c src/backend/storage/lmgr/lwlock.c src/backend/storage/lmgr/proc.c src/backend/tcop/dest.c src/backend/tcop/postgres.c src/backend/tcop/pquery.c src/backend/tcop/utility.c src/backend/utils/adt/arrayfuncs.c src/backend/utils/adt/date.c src/backend/utils/adt/dbsize.c src/backend/utils/adt/pseudotypes.c src/backend/utils/adt/ri_triggers.c src/backend/utils/adt/ruleutils.c src/backend/utils/adt/version.c src/backend/utils/cache/inval.c src/backend/utils/cache/lsyscache.c src/backend/utils/cache/plancache.c src/backend/utils/cache/relcache.c src/backend/utils/init/globals.c src/backend/utils/init/miscinit.c src/backend/utils/init/postinit.c src/backend/utils/misc/guc.c src/backend/utils/mmgr/portalmem.c src/backend/utils/sort/tuplesort.c src/backend/utils/sort/tuplestore.c src/backend/utils/time/combocid.c src/backend/utils/time/snapmgr.c src/bin/Makefile src/bin/initdb/initdb.c src/bin/pg_ctl/pg_ctl.c src/bin/pg_dump/pg_dump.c src/bin/pgbench/pgbench.c src/bin/psql/tab-complete.c src/include/access/htup.h src/include/access/rmgrlist.h src/include/access/transam.h src/include/access/xact.h src/include/catalog/catalog.h src/include/catalog/namespace.h src/include/catalog/pg_aggregate.h src/include/catalog/pg_namespace.h src/include/catalog/pg_proc.h src/include/catalog/pg_type.h src/include/commands/explain.h src/include/commands/sequence.h src/include/commands/vacuum.h src/include/commands/variable.h src/include/executor/execdesc.h src/include/executor/executor.h src/include/executor/tuptable.h src/include/miscadmin.h src/include/nodes/execnodes.h src/include/nodes/nodes.h src/include/nodes/params.h src/include/nodes/parsenodes.h src/include/nodes/plannodes.h src/include/nodes/primnodes.h src/include/nodes/relation.h src/include/optimizer/cost.h src/include/optimizer/pathnode.h src/include/optimizer/planmain.h src/include/parser/analyze.h src/include/parser/parse_agg.h src/include/parser/parse_utilcmd.h src/include/pg_config.h.win32 src/include/pgstat.h src/include/storage/backendid.h src/include/storage/barrier.h src/include/storage/lwlock.h src/include/storage/proc.h src/include/storage/procarray.h src/include/storage/procsignal.h src/include/storage/smgr.h src/include/tcop/dest.h src/include/tcop/pquery.h src/include/utils/builtins.h src/include/utils/guc.h src/include/utils/lsyscache.h src/include/utils/plancache.h src/include/utils/portal.h src/include/utils/rel.h src/include/utils/tuplesort.h src/include/utils/tuplestore.h src/test/regress/expected/aggregates.out src/test/regress/expected/create_index.out src/test/regress/expected/foreign_data.out src/test/regress/expected/join.out src/test/regress/expected/macaddr.out src/test/regress/expected/polygon.out src/test/regress/expected/rangetypes.out src/test/regress/expected/update.out src/test/regress/input/constraints.source src/test/regress/pg_regress.c src/test/regress/serial_schedule src/test/regress/sql/rangetypes.sql
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c377
1 files changed, 193 insertions, 184 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1173032d81..0f44702dcd 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Portions Copyright (c) 2012-2014, TransLattice, Inc.
- * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 2010-2012 Postgres-XC Development Group
*
@@ -28,7 +28,6 @@
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
-#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_SELECT_H
@@ -349,17 +348,25 @@ InteractiveBackend(StringInfo inBuf)
* 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.
+ * respond to signals, particularly SIGTERM/SIGQUIT.
*/
static int
interactive_getc(void)
{
int c;
- prepare_for_client_read();
+ /*
+ * This will not process catchup interrupts or notifications while
+ * reading. But those can't really be relevant for a standalone backend
+ * anyway. To properly handle SIGTERM there's a hack in die() that
+ * directly processes interrupts at this stage...
+ */
+ CHECK_FOR_INTERRUPTS();
+
c = getc(stdin);
- client_read_ended();
+
+ ProcessClientReadInterrupt(true);
+
return c;
}
@@ -473,6 +480,8 @@ SocketBackend(StringInfo inBuf)
/*
* Get message type code from the frontend.
*/
+ HOLD_CANCEL_INTERRUPTS();
+ pq_startmsgread();
qtype = pq_getbyte();
#endif
@@ -522,7 +531,7 @@ SocketBackend(StringInfo inBuf)
{
/*
* Can't send DEBUG log messages to client at this
- * point.Since we're disconnecting right away, we
+ * point. Since we're disconnecting right away, we
* don't need to restore whereToSendOutput.
*/
whereToSendOutput = DestNone;
@@ -536,8 +545,30 @@ SocketBackend(StringInfo inBuf)
break;
case 'F': /* fastpath function call */
- /* we let fastpath.c cope with old-style input of this */
doing_extended_query_message = false;
+ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
+ {
+ if (GetOldFunctionMessage(inBuf))
+ {
+ if (IsTransactionState())
+ ereport(COMMERROR,
+ (errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("unexpected EOF on client connection with an open transaction")));
+ else
+ {
+ /*
+ * Can't send DEBUG log messages to client at this
+ * point. Since we're disconnecting right away, we
+ * don't need to restore whereToSendOutput.
+ */
+ whereToSendOutput = DestNone;
+ ereport(DEBUG1,
+ (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
+ errmsg("unexpected EOF on client connection")));
+ }
+ return EOF;
+ }
+ }
break;
case 'X': /* terminate */
@@ -616,6 +647,9 @@ SocketBackend(StringInfo inBuf)
if (pq_getmessage(inBuf, 0))
return EOF; /* suitable message already logged */
}
+ else
+ pq_endmsgread();
+ RESUME_CANCEL_INTERRUPTS();
return qtype;
}
@@ -641,55 +675,79 @@ ReadCommand(StringInfo inBuf)
}
/*
- * prepare_for_client_read -- set up to possibly block on client input
+ * ProcessClientReadInterrupt() - Process interrupts specific to client reads
+ *
+ * This is called just after low-level reads. That might be after the read
+ * finished successfully, or it was interrupted via interrupt.
*
- * This must be called immediately before any low-level read from the
- * client connection. It is necessary to do it at a sufficiently low level
- * that there won't be any other operations except the read kernel call
- * itself between this call and the subsequent client_read_ended() call.
- * In particular there mustn't be use of malloc() or other potentially
- * non-reentrant libc functions. This restriction makes it safe for us
- * to allow interrupt service routines to execute nontrivial code while
- * we are waiting for input.
+ * Must preserve errno!
*/
void
-prepare_for_client_read(void)
+ProcessClientReadInterrupt(bool blocked)
{
+ int save_errno = errno;
+
if (DoingCommandRead)
{
- /* Enable immediate processing of asynchronous signals */
- EnableNotifyInterrupt();
- EnableCatchupInterrupt();
+ /* Check for general interrupts that arrived while reading */
+ CHECK_FOR_INTERRUPTS();
- /* Allow cancel/die interrupts to be processed while waiting */
- ImmediateInterruptOK = true;
+ /* Process sinval catchup interrupts that happened while reading */
+ if (catchupInterruptPending)
+ ProcessCatchupInterrupt();
- /* And don't forget to detect one that already arrived */
+ /* Process sinval catchup interrupts that happened while reading */
+ if (notifyInterruptPending)
+ ProcessNotifyInterrupt();
+ }
+ else if (ProcDiePending && blocked)
+ {
+ /*
+ * We're dying. It's safe (and sane) to handle that now.
+ */
CHECK_FOR_INTERRUPTS();
}
+
+ errno = save_errno;
}
/*
- * client_read_ended -- get out of the client-input state
+ * ProcessClientWriteInterrupt() - Process interrupts specific to client writes
+ *
+ * This is called just after low-level writes. That might be after the read
+ * finished successfully, or it was interrupted via interrupt. 'blocked' tells
+ * us whether the
*
- * This is called just after low-level reads. It must preserve errno!
+ * Must preserve errno!
*/
void
-client_read_ended(void)
+ProcessClientWriteInterrupt(bool blocked)
{
- if (DoingCommandRead)
- {
- int save_errno = errno;
-
- ImmediateInterruptOK = false;
+ int save_errno = errno;
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ /*
+ * We only want to process the interrupt here if socket writes are
+ * blocking to increase the chance to get an error message to the
+ * client. If we're not blocked there'll soon be a
+ * CHECK_FOR_INTERRUPTS(). But if we're blocked we'll never get out of
+ * that situation if the client has died.
+ */
+ if (ProcDiePending && blocked)
+ {
+ /*
+ * We're dying. It's safe (and sane) to handle that now. But we don't
+ * want to send the client the error message as that a) would possibly
+ * block again b) would possibly lead to sending an error message to
+ * the client, while we already started to send something else.
+ */
+ if (whereToSendOutput == DestRemote)
+ whereToSendOutput = DestNone;
- errno = save_errno;
+ CHECK_FOR_INTERRUPTS();
}
-}
+ errno = save_errno;
+}
/*
* Do raw parsing (only).
@@ -1957,7 +2015,9 @@ exec_bind_message(StringInfo input_message)
* snapshot active till we're done, so that plancache.c doesn't have to
* take new ones.
*/
- if (numParams > 0 || analyze_requires_snapshot(psrc->raw_parse_tree))
+ if (numParams > 0 ||
+ (psrc->raw_parse_tree &&
+ analyze_requires_snapshot(psrc->raw_parse_tree)))
{
PushActiveSnapshot(GetTransactionSnapshot());
snapshot_set = true;
@@ -1970,9 +2030,8 @@ exec_bind_message(StringInfo input_message)
{
int paramno;
- /* sizeof(ParamListInfoData) includes the first array element */
- params = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (numParams - 1) * sizeof(ParamExternData));
+ params = (ParamListInfo) palloc(offsetof(ParamListInfoData, params) +
+ numParams * sizeof(ParamExternData));
/* we have static list of params, so no hooks needed */
params->paramFetch = NULL;
params->paramFetchArg = NULL;
@@ -2410,7 +2469,7 @@ exec_execute_message(const char *portal_name, long max_rows)
* check_log_statement
* Determine whether command should be logged because of log_statement
*
- * parsetree_list can be either raw grammar output or a list of planned
+ * stmt_list can be either raw grammar output or a list of planned
* statements
*/
static bool
@@ -2997,23 +3056,6 @@ die(SIGNAL_ARGS)
{
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++;
- LockErrorCleanup(); /* prevent CheckDeadLock from running */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
- InterruptHoldoffCount--;
- ProcessInterrupts();
- }
}
#ifdef XCP
@@ -3025,8 +3067,16 @@ die(SIGNAL_ARGS)
#endif
/* If we're still here, waken anything waiting on the process latch */
- if (MyProc)
- SetLatch(&MyProc->procLatch);
+ SetLatch(MyLatch);
+
+ /*
+ * If we're in single user mode, we want to quit immediately - we can't
+ * rely on latches as they wouldn't work when stdin/stdout is a
+ * file. Rather ugly, but it's unlikely to be worthwhile to invest much
+ * more effort just for the benefit of single user mode.
+ */
+ if (DoingCommandRead && whereToSendOutput != DestRemote)
+ ProcessInterrupts();
errno = save_errno;
}
@@ -3048,28 +3098,10 @@ StatementCancelHandler(SIGNAL_ARGS)
{
InterruptPending = true;
QueryCancelPending = 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++;
- LockErrorCleanup(); /* prevent CheckDeadLock from running */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
- InterruptHoldoffCount--;
- ProcessInterrupts();
- }
}
/* If we're still here, waken anything waiting on the process latch */
- if (MyProc)
- SetLatch(&MyProc->procLatch);
+ SetLatch(MyLatch);
errno = save_errno;
}
@@ -3094,8 +3126,7 @@ SigHupHandler(SIGNAL_ARGS)
int save_errno = errno;
got_SIGHUP = true;
- if (MyProc)
- SetLatch(&MyProc->procLatch);
+ SetLatch(MyLatch);
errno = save_errno;
}
@@ -3207,23 +3238,6 @@ RecoveryConflictInterrupt(ProcSignalReason reason)
*/
if (reason == PROCSIG_RECOVERY_CONFLICT_DATABASE)
RecoveryConflictRetryable = false;
-
- /*
- * 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++;
- LockErrorCleanup(); /* prevent CheckDeadLock from running */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
- InterruptHoldoffCount--;
- ProcessInterrupts();
- }
}
/*
@@ -3233,8 +3247,7 @@ RecoveryConflictInterrupt(ProcSignalReason reason)
* waiting on that latch, expecting to get interrupted by query cancels et
* al., would also need to set set_latch_on_sigusr1.
*/
- if (MyProc)
- SetLatch(&MyProc->procLatch);
+ SetLatch(MyLatch);
errno = save_errno;
}
@@ -3249,21 +3262,24 @@ RecoveryConflictInterrupt(ProcSignalReason reason)
void
ProcessInterrupts(void)
{
- /* OK to accept interrupt now? */
+ /* OK to accept any interrupts now? */
if (InterruptHoldoffCount != 0 || CritSectionCount != 0)
return;
InterruptPending = false;
+
if (ProcDiePending)
{
ProcDiePending = false;
QueryCancelPending = false; /* ProcDie trumps QueryCancel */
- ImmediateInterruptOK = false; /* not idle anymore */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
/* As in quickdie, don't risk sending to client during auth */
if (ClientAuthInProgress && whereToSendOutput == DestRemote)
whereToSendOutput = DestNone;
- if (IsAutoVacuumWorkerProcess())
+ if (ClientAuthInProgress)
+ ereport(FATAL,
+ (errcode(ERRCODE_QUERY_CANCELED),
+ errmsg("canceling authentication due to timeout")));
+ else if (IsAutoVacuumWorkerProcess())
ereport(FATAL,
(errcode(ERRCODE_ADMIN_SHUTDOWN),
errmsg("terminating autovacuum process due to administrator command")));
@@ -3293,82 +3309,89 @@ ProcessInterrupts(void)
if (ClientConnectionLost)
{
QueryCancelPending = false; /* lost connection trumps QueryCancel */
- ImmediateInterruptOK = false; /* not idle anymore */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
/* don't send to client, we already know the connection to be dead. */
whereToSendOutput = DestNone;
ereport(FATAL,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("connection to client lost")));
}
+
+ /*
+ * If a recovery conflict happens while we are waiting for input from the
+ * client, the client is presumably just sitting idle in a transaction,
+ * preventing recovery from making progress. Terminate the connection to
+ * dislodge it.
+ */
+ if (RecoveryConflictPending && DoingCommandRead)
+ {
+ QueryCancelPending = false; /* this trumps QueryCancel */
+ RecoveryConflictPending = false;
+ LockErrorCleanup();
+ pgstat_report_recovery_conflict(RecoveryConflictReason);
+ ereport(FATAL,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("terminating connection due to conflict with recovery"),
+ errdetail_recovery_conflict(),
+ errhint("In a moment you should be able to reconnect to the"
+ " database and repeat your command.")));
+ }
+
if (QueryCancelPending)
{
- QueryCancelPending = false;
- if (ClientAuthInProgress)
+ /*
+ * Don't allow query cancel interrupts while reading input from the
+ * client, because we might lose sync in the FE/BE protocol. (Die
+ * interrupts are OK, because we won't read any further messages from
+ * the client in that case.)
+ */
+ if (QueryCancelHoldoffCount != 0)
{
- ImmediateInterruptOK = false; /* not idle anymore */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
- /* As in quickdie, don't risk sending to client during auth */
- if (whereToSendOutput == DestRemote)
- whereToSendOutput = DestNone;
- ereport(ERROR,
- (errcode(ERRCODE_QUERY_CANCELED),
- errmsg("canceling authentication due to timeout")));
+ /*
+ * Re-arm InterruptPending so that we process the cancel request
+ * as soon as we're done reading the message.
+ */
+ InterruptPending = true;
+ return;
}
+ QueryCancelPending = false;
+
/*
* If LOCK_TIMEOUT and STATEMENT_TIMEOUT indicators are both set, we
* prefer to report the former; but be sure to clear both.
*/
if (get_timeout_indicator(LOCK_TIMEOUT, true))
{
- ImmediateInterruptOK = false; /* not idle anymore */
(void) get_timeout_indicator(STATEMENT_TIMEOUT, true);
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("canceling statement due to lock timeout")));
}
if (get_timeout_indicator(STATEMENT_TIMEOUT, true))
{
- ImmediateInterruptOK = false; /* not idle anymore */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
ereport(ERROR,
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling statement due to statement timeout")));
}
if (IsAutoVacuumWorkerProcess())
{
- ImmediateInterruptOK = false; /* not idle anymore */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
ereport(ERROR,
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling autovacuum task")));
}
if (RecoveryConflictPending)
{
- ImmediateInterruptOK = false; /* not idle anymore */
RecoveryConflictPending = false;
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
pgstat_report_recovery_conflict(RecoveryConflictReason);
- if (DoingCommandRead)
- ereport(FATAL,
- (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
- errmsg("terminating connection due to conflict with recovery"),
- errdetail_recovery_conflict(),
- errhint("In a moment you should be able to reconnect to the"
- " database and repeat your command.")));
- else
- ereport(ERROR,
- (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("canceling statement due to conflict with recovery"),
- errdetail_recovery_conflict()));
+ errdetail_recovery_conflict()));
}
/*
@@ -3378,14 +3401,13 @@ ProcessInterrupts(void)
*/
if (!DoingCommandRead)
{
- ImmediateInterruptOK = false; /* not idle anymore */
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
+ LockErrorCleanup();
ereport(ERROR,
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling statement due to user request")));
}
}
+
/* If we get here, do nothing (probably, QueryCancelPending was reset) */
}
@@ -3678,7 +3700,7 @@ get_stats_option_name(const char *arg)
* argv[0] is ignored in either case (it's assumed to be the program name).
*
* ctx is PGC_POSTMASTER for secure options, PGC_BACKEND for insecure options
- * coming from the client, or PGC_SUSET for insecure options coming from
+ * coming from the client, or PGC_SU_BACKEND for insecure options coming from
* a superuser client.
*
* If a database name is present in the command line arguments, it's
@@ -3731,14 +3753,10 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
* 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:bc:C:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:v:W:-:")) != -1)
+ while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:v:W:-:")) != -1)
{
switch (flag)
{
- case 'A':
- SetConfigOption("debug_assertions", optarg, ctx, gucsource);
- break;
-
case 'B':
SetConfigOption("shared_buffers", optarg, ctx, gucsource);
break;
@@ -4031,30 +4049,12 @@ PostgresMain(int argc, char *argv[],
cluster_ex_lock_held = false;
#endif /* XCP */
- /*
- * Initialize globals (already done if under postmaster, but not if
- * standalone).
- */
+ /* Initialize startup process environment if necessary. */
if (!IsUnderPostmaster)
- {
- MyProcPid = getpid();
-
- MyStartTime = time(NULL);
- }
+ InitStandaloneProcess(argv[0]);
SetProcessingMode(InitProcessing);
- /* Compute paths, if we didn't inherit them from postmaster */
- if (my_exec_path[0] == '\0')
- {
- if (find_my_exec(argv[0], my_exec_path) < 0)
- elog(FATAL, "%s: could not locate my own executable path",
- argv[0]);
- }
-
- if (pkglib_path[0] == '\0')
- get_pkglib_path(my_exec_path, pkglib_path);
-
/*
* Set default values for command-line options.
*/
@@ -4085,11 +4085,6 @@ PostgresMain(int argc, char *argv[],
}
/*
- * You might expect to see a setsid() call here, but it's not needed,
- * because if we are under a postmaster then BackendInitialize() did it.
- */
-
- /*
* Set up signal handlers and masks.
*
* Note that postmaster blocked all signals before forking child process,
@@ -4199,7 +4194,7 @@ PostgresMain(int argc, char *argv[],
* it inside InitPostgres() instead. In particular, anything that
* involves database access should be there, not here.
*/
- InitPostgres(dbname, InvalidOid, username, NULL);
+ InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
/*
* If the PostmasterContext is still around, recycle the space; we don't
@@ -4396,14 +4391,8 @@ PostgresMain(int argc, char *argv[],
disable_all_timeouts(false);
QueryCancelPending = false; /* second to avoid race condition */
- /*
- * Turn off these interrupts too. This is only needed here and not in
- * other exception-catching places since these interrupts are only
- * enabled while we wait for client input.
- */
+ /* Not reading from the client anymore. */
DoingCommandRead = false;
- DisableNotifyInterrupt();
- DisableCatchupInterrupt();
/* Make sure libpq is in a good state */
pq_comm_reset();
@@ -4453,6 +4442,19 @@ PostgresMain(int argc, char *argv[],
/* We don't have a transaction command open anymore */
xact_started = false;
+ /*
+ * If an error occurred while we were reading a message from the
+ * client, we have potentially lost track of where the previous
+ * message ends and the next one begins. Even though we have
+ * otherwise recovered from the error, we cannot safely read any more
+ * messages from the client, so there isn't much we can do with the
+ * connection anymore.
+ */
+ if (pq_is_reading_msg())
+ ereport(FATAL,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("terminating connection because protocol sync was lost")));
+
/* Now we can allow interrupts again */
RESUME_INTERRUPTS();
}
@@ -4555,7 +4557,14 @@ PostgresMain(int argc, char *argv[],
/*
* (4) disable async signal conditions again.
+ *
+ * Query cancel is supposed to be a no-op when there is no query in
+ * progress, so if a query cancel arrived while we were idle, just
+ * reset QueryCancelPending. ProcessInterrupts() has that effect when
+ * it's called when DoingCommandRead is set, so check for interrupts
+ * before resetting DoingCommandRead.
*/
+ CHECK_FOR_INTERRUPTS();
DoingCommandRead = false;
/*