summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Riggs2009-02-25 13:04:37 +0000
committerSimon Riggs2009-02-25 13:04:37 +0000
commit6e52f2d4e02327f4546d8a407b73790aad987276 (patch)
tree4d8f13494217dc084250c8eedc4bd72e4496ef8d
parent18a29ebb4c3c579916d2ef8e9ec4af50be5e8e02 (diff)
parent306ba15ee4313ad7f42352ae63e29e4228d3ff4a (diff)
Merge branch 'recoveryinfra' into dev_hot_standby
Conflicts: src/backend/access/transam/xlog.c src/backend/postmaster/postmaster.c src/include/access/xlog.h Further changes to replace IsRecoveryProcessingMode() with RecoveryInProgress().
-rw-r--r--doc/src/sgml/config.sgml14
-rw-r--r--doc/src/sgml/ref/vacuumdb.sgml12
-rw-r--r--src/Makefile.global.in3
-rw-r--r--src/backend/access/heap/pruneheap.c2
-rw-r--r--src/backend/access/transam/multixact.c2
-rw-r--r--src/backend/access/transam/xact.c4
-rw-r--r--src/backend/access/transam/xlog.c120
-rw-r--r--src/backend/commands/discard.c2
-rw-r--r--src/backend/optimizer/path/joinrels.c26
-rw-r--r--src/backend/optimizer/plan/initsplan.c40
-rw-r--r--src/backend/postmaster/bgwriter.c36
-rw-r--r--src/backend/postmaster/postmaster.c286
-rw-r--r--src/backend/storage/buffer/README6
-rw-r--r--src/backend/storage/ipc/procarray.c16
-rw-r--r--src/backend/storage/lmgr/lock.c4
-rw-r--r--src/backend/storage/lmgr/proc.c2
-rw-r--r--src/backend/tcop/postgres.c4
-rw-r--r--src/backend/tcop/utility.c2
-rw-r--r--src/backend/utils/adt/float.c19
-rw-r--r--src/backend/utils/adt/txid.c2
-rw-r--r--src/backend/utils/init/postinit.c6
-rw-r--r--src/backend/utils/time/tqual.c2
-rw-r--r--src/bin/pg_dump/pg_backup_archiver.c1
-rw-r--r--src/bin/pg_dump/pg_dump.c40
-rw-r--r--src/bin/pg_dump/pg_dump.h1
-rw-r--r--src/bin/pg_dump/pg_dumpall.c35
-rw-r--r--src/bin/scripts/vacuumdb.c24
-rw-r--r--src/include/access/xlog.h3
-rw-r--r--src/include/storage/pmsignal.h1
-rw-r--r--src/include/storage/proc.h6
-rw-r--r--src/pl/plperl/expected/plperl.out16
-rw-r--r--src/pl/plperl/nls.mk4
-rw-r--r--src/pl/plperl/plperl.c22
-rw-r--r--src/pl/plpgsql/src/gram.y22
-rw-r--r--src/pl/plpgsql/src/pl_comp.c8
-rw-r--r--src/pl/plpgsql/src/pl_exec.c48
-rw-r--r--src/pl/plpgsql/src/pl_funcs.c4
-rw-r--r--src/pl/plpgsql/src/pl_handler.c4
-rw-r--r--src/pl/plpgsql/src/scan.l4
-rw-r--r--src/test/regress/expected/numerology.out4
-rw-r--r--src/test/regress/expected/numerology_1.out136
-rw-r--r--src/test/regress/expected/plpgsql.out8
42 files changed, 551 insertions, 450 deletions
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 7d8b5200b7..b617bb72c3 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -3367,11 +3367,19 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
<listitem>
<para>
Enables tracking of function call counts and time used. Specify
- <literal>pl</literal> to count only procedural language functions,
+ <literal>pl</literal> to track only procedural-language functions,
<literal>all</literal> to also track SQL and C language functions.
- The default is <literal>none</literal>.
- Only superusers can change this setting.
+ The default is <literal>none</literal>, which disables function
+ statistics tracking. Only superusers can change this setting.
</para>
+
+ <note>
+ <para>
+ SQL-language functions that are simple enough to be <quote>inlined</>
+ into the calling query will not be tracked, regardless of this
+ setting.
+ </para>
+ </note>
</listitem>
</varlistentry>
diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml
index 6a00946827..bd44f71c25 100644
--- a/doc/src/sgml/ref/vacuumdb.sgml
+++ b/doc/src/sgml/ref/vacuumdb.sgml
@@ -26,6 +26,7 @@ PostgreSQL documentation
<group><arg>--full</arg><arg>-f</arg></group>
<group><arg>--verbose</arg><arg>-v</arg></group>
<group><arg>--analyze</arg><arg>-z</arg></group>
+ <group><arg>--freeze</arg><arg>-F</arg></group>
<arg>--table | -t <replaceable>table</replaceable>
<arg>( <replaceable class="parameter">column</replaceable> [,...] )</arg>
</arg>
@@ -37,6 +38,7 @@ PostgreSQL documentation
<group><arg>--full</arg><arg>-f</arg></group>
<group><arg>--verbose</arg><arg>-v</arg></group>
<group><arg>--analyze</arg><arg>-z</arg></group>
+ <group><arg>--freeze</arg><arg>-F</arg></group>
</cmdsynopsis>
</refsynopsisdiv>
@@ -161,6 +163,16 @@ PostgreSQL documentation
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>-F</option></term>
+ <term><option>--freeze</option></term>
+ <listitem>
+ <para>
+ Aggressively <quote>freeze</quote> tuples.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index ff27dd903d..829ce7218d 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -468,6 +468,9 @@ TAS = @TAS@
#
# Global targets and rules
+%.i: %.c
+ $(CPP) $(CPPFLAGS) -o $@ $<
+
%.gz: %
$(GZIP) -f --best $<
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 8c8bbd8355..00eb502a4a 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -90,7 +90,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
* clean the page. The master will likely issue a cleaning WAL record
* soon anyway, so this is no particular loss.
*/
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
return;
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index f33c7fa91d..d02442249d 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1546,7 +1546,7 @@ CheckPointMultiXact(void)
* removing any data during recovery anyway, so don't truncate.
* We are executing in the bgwriter, so we must access shared status.
*/
- if (!IsRecoveryProcessingMode())
+ if (!RecoveryInProgress())
TruncateMultiXact();
TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 12fec8e477..2fea2460b3 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -402,7 +402,7 @@ AssignTransactionId(TransactionState s, int recursion_level)
bool isSubXact = (s->parent != NULL);
ResourceOwner currentOwner;
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
elog(ERROR, "cannot assign TransactionIds during recovery");
/* Assert that caller didn't screw up */
@@ -1627,7 +1627,7 @@ StartTransaction(void)
s->childXids = NULL;
s->nChildXids = 0;
s->maxChildXids = 0;
- s->startedInRecovery = IsRecoveryProcessingMode();
+ s->startedInRecovery = RecoveryInProgress();
GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
/* SecurityDefinerContext should never be set outside a transaction */
Assert(!s->prevSecDefCxt);
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 9c58231e94..bd07ad2b35 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -129,11 +129,12 @@ TimeLineID ThisTimeLineID = 0;
/*
* Are we doing recovery from XLOG?
*
- * This is only ever true in the startup process, when it's replaying WAL.
- * It's used in functions that need to act differently when called from a
- * redo function (e.g skip WAL logging). To check whether the system is in
- * recovery regardless of what process you're running in, use
- * IsRecoveryProcessingMode().
+ * This is only ever true in the startup process, even if the system is still
+ * in recovery. Prior to 8.4, all activity during recovery were carried out
+ * by Startup process. This local variable continues to be used in functions
+ * that need to act differently when called from a redo function (e.g skip
+ * WAL logging). To check whether the system is in recovery regardless of what
+ * process you're running in, use RecoveryInProgress().
*/
bool InRecovery = false;
@@ -143,10 +144,10 @@ bool InArchiveRecovery = false;
static XLogRecPtr LastRec;
/*
- * Local copy of shared RecoveryProcessingMode variable. True actually
- * means "not known, need to check the shared state"
+ * Local copy of SharedRecoveryInProgress variable. True actually means "not
+ * known, need to check the shared state"
*/
-static bool LocalRecoveryProcessingMode = true;
+static bool LocalRecoveryInProgress = true;
/* is the database proven consistent yet? */
bool reachedSafeStartPoint = false;
@@ -358,10 +359,10 @@ typedef struct XLogCtlData
TimeLineID ThisTimeLineID;
/*
- * SharedRecoveryProcessingMode indicates if we're still in crash or
- * archive recovery. It's checked by IsRecoveryProcessingMode().
+ * SharedRecoveryInProgress indicates if we're still in crash or archive
+ * recovery. It's checked by RecoveryInProgress().
*/
- bool SharedRecoveryProcessingMode;
+ bool SharedRecoveryInProgress;
/*
* During recovery, we keep a copy of the latest checkpoint record
@@ -471,7 +472,7 @@ static bool InRedo = false;
static volatile sig_atomic_t shutdown_requested = false;
/*
* Flag set when executing a restore command, to tell SIGTERM signal handler
- * that it's safe to just proc_exit(0).
+ * that it's safe to just proc_exit.
*/
static volatile sig_atomic_t in_restore_command = false;
@@ -571,7 +572,7 @@ XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata)
bool isLogSwitch = (rmid == RM_XLOG_ID && info == XLOG_SWITCH);
/* cross-check on whether we should be here or not */
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
elog(FATAL, "cannot make new WAL entries during recovery");
/* info's high bits are reserved for use by me */
@@ -1796,7 +1797,7 @@ XLogSetAsyncCommitLSN(XLogRecPtr asyncCommitLSN)
* database is consistent.
*
* If 'force' is true, 'lsn' argument is ignored. Otherwise, minRecoveryPoint
- * is is only updated if it's already greater than or equal to 'lsn'.
+ * is is only updated if it's not already greater than or equal to 'lsn'.
*/
static void
UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
@@ -1823,8 +1824,8 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
XLogRecPtr newMinRecoveryPoint;
/*
- * To avoid having to update the control file too often, we update
- * it all the way to the last record being replayed, even though 'lsn'
+ * To avoid having to update the control file too often, we update it
+ * all the way to the last record being replayed, even though 'lsn'
* would suffice for correctness.
*/
SpinLockAcquire(&xlogctl->info_lck);
@@ -1837,11 +1838,11 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
ControlFile->minRecoveryPoint = newMinRecoveryPoint;
UpdateControlFile();
minRecoveryPoint = newMinRecoveryPoint;
- }
- ereport(DEBUG2,
- (errmsg("updated min recovery point to %X/%X",
+ ereport(DEBUG2,
+ (errmsg("updated min recovery point to %X/%X",
minRecoveryPoint.xlogid, minRecoveryPoint.xrecoff)));
+ }
}
LWLockRelease(ControlFileLock);
}
@@ -1862,7 +1863,7 @@ XLogFlush(XLogRecPtr record)
* During REDO, we don't try to flush the WAL, but update minRecoveryPoint
* instead.
*/
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
{
UpdateMinRecoveryPoint(record, false);
return;
@@ -1953,7 +1954,7 @@ XLogFlush(XLogRecPtr record)
* the bad page is encountered again during recovery then we would be
* unable to restart the database at all! (This scenario has actually
* happened in the field several times with 7.1 releases. Note that we
- * cannot get here while IsRecoveryProcessingMode(), but if the bad page is
+ * cannot get here while RecoveryInProgress(), but if the bad page is
* brought in and marked dirty during recovery then if a checkpoint were
* performed at the end of recovery it will try to flush it.
*
@@ -1993,7 +1994,7 @@ XLogBackgroundFlush(void)
bool flexible = true;
/* XLOG doesn't need flushing during recovery */
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
return;
/* read LogwrtResult and update local state */
@@ -2068,7 +2069,7 @@ XLogAsyncCommitFlush(void)
volatile XLogCtlData *xlogctl = XLogCtl;
/* There's no asynchronously committed transactions during recovery */
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
return;
SpinLockAcquire(&xlogctl->info_lck);
@@ -2088,7 +2089,7 @@ bool
XLogNeedsFlush(XLogRecPtr record)
{
/* XLOG doesn't need flushing during recovery */
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
return false;
/* Quick exit if already known flushed */
@@ -2768,12 +2769,12 @@ RestoreArchivedFile(char *path, const char *xlogfname,
/*
* Set in_restore_command to tell the signal handler that we should exit
* right away on SIGTERM. We know that we're in a safe point to do that.
- * Check if we had already received the signal, so that we don't miss
- * a shutdown request received just before this.
+ * Check if we had already received the signal, so that we don't miss a
+ * shutdown request received just before this.
*/
in_restore_command = true;
if (shutdown_requested)
- proc_exit(0);
+ proc_exit(1);
/*
* Copy xlog from archival storage to XLOGDIR
@@ -2839,7 +2840,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
* On SIGTERM, assume we have received a fast shutdown request, and exit
* cleanly. It's pure chance whether we receive the SIGTERM first, or the
* child process. If we receive it first, the signal handler will call
- * proc_exit(0), otherwise we do it here. If we or the child process
+ * proc_exit, otherwise we do it here. If we or the child process
* received SIGTERM for any other reason than a fast shutdown request,
* postmaster will perform an immediate shutdown when it sees us exiting
* unexpectedly.
@@ -2850,7 +2851,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
* too.
*/
if (WTERMSIG(rc) == SIGTERM)
- proc_exit(0);
+ proc_exit(1);
signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
@@ -5010,7 +5011,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
* recovery.
*/
if (shutdown_requested)
- proc_exit(0);
+ proc_exit(1);
/*
* Let's see if user has updated our recoveryTargetMode.
@@ -5303,7 +5304,7 @@ static void
SetRecoveryTargetMode(int mode, TransactionId xid, TimestampTz ts,
XLogRecPtr lsn, int advance)
{
- if (!IsRecoveryProcessingMode())
+ if (!RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is not in progress"),
@@ -5512,7 +5513,7 @@ pg_current_recovery_target(PG_FUNCTION_ARGS)
Datum
pg_is_in_recovery(PG_FUNCTION_ARGS)
{
- PG_RETURN_BOOL(IsRecoveryProcessingMode());
+ PG_RETURN_BOOL(RecoveryInProgress());
}
/*
@@ -5627,7 +5628,7 @@ StartupXLOG(void)
uint32 freespace;
TransactionId oldestActiveXID;
- XLogCtl->SharedRecoveryProcessingMode = true;
+ XLogCtl->SharedRecoveryInProgress = true;
/*
* Read control file and check XLOG status looks valid.
@@ -5978,7 +5979,6 @@ StartupXLOG(void)
pfree(buf.data);
}
#endif
-
/*
* Have we reached our safe starting point? If so, we can
* tell postmaster that the database is consistent now.
@@ -6190,7 +6190,7 @@ StartupXLOG(void)
* Allow writing WAL for us, so that we can create a checkpoint record.
* But not yet for other backends!
*/
- LocalRecoveryProcessingMode = false;
+ LocalRecoveryInProgress = false;
if (InRecovery)
{
@@ -6282,7 +6282,7 @@ StartupXLOG(void)
/*
* All done. Allow others to write WAL.
*/
- XLogCtl->SharedRecoveryProcessingMode = false;
+ XLogCtl->SharedRecoveryInProgress = false;
}
/*
@@ -6292,31 +6292,31 @@ StartupXLOG(void)
* variables the first time we see that recovery is finished.
*/
bool
-IsRecoveryProcessingMode(void)
+RecoveryInProgress(void)
{
/*
* We check shared state each time only until we leave recovery mode.
* We can't re-enter recovery, so we rely on the local state variable
* after that.
*/
- if (!LocalRecoveryProcessingMode)
+ if (!LocalRecoveryInProgress)
return false;
else
{
/* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl;
- LocalRecoveryProcessingMode = xlogctl->SharedRecoveryProcessingMode;
+ LocalRecoveryInProgress = xlogctl->SharedRecoveryInProgress;
/*
* Initialize TimeLineID and RedoRecPtr the first time we see that
* recovery is finished. InitPostgres() relies upon this behaviour
* to ensure that InitXLOGAccess() is called at backend startup.
*/
- if (!LocalRecoveryProcessingMode)
+ if (!LocalRecoveryInProgress)
InitXLOGAccess();
- return LocalRecoveryProcessingMode;
+ return LocalRecoveryInProgress;
}
}
@@ -6562,7 +6562,7 @@ ShutdownXLOG(int code, Datum arg)
ereport(LOG,
(errmsg("shutting down")));
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
else
CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
@@ -6678,15 +6678,15 @@ CreateCheckPoint(int flags)
int nInCommit;
/* shouldn't happen */
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
elog(ERROR, "can't create a checkpoint during recovery");
/*
* Acquire CheckpointLock to ensure only one checkpoint happens at a time.
* During normal operation, bgwriter is the only process that creates
- * checkpoints, but at the end archive recovery, the bgwriter can be busy
- * creating a restartpoint while the startup process tries to perform the
- * startup checkpoint.
+ * checkpoints, but at the end of archive recovery, the bgwriter can be
+ * busy creating a restartpoint while the startup process tries to perform
+ * the startup checkpoint.
*/
if (!LWLockConditionalAcquire(CheckpointLock, LW_EXCLUSIVE))
{
@@ -7014,7 +7014,7 @@ CreateCheckPoint(int flags)
* If we are shutting down, or Startup process is completing crash
* recovery we don't need to write running xact data.
*/
- if (!shutdown && !IsRecoveryProcessingMode())
+ if (!shutdown && !RecoveryInProgress())
LogCurrentRunningXacts();
}
@@ -7115,7 +7115,7 @@ CreateRestartPoint(int flags)
* Check that we're still in recovery mode. It's ok if we exit recovery
* mode after this check, the restart point is valid anyway.
*/
- if (!IsRecoveryProcessingMode())
+ if (!RecoveryInProgress())
{
ereport(DEBUG2,
(errmsg("skipping restartpoint, recovery has already ended")));
@@ -7261,8 +7261,8 @@ RequestXLogSwitch(void)
/*
* XLOG resource manager's routines
*
- * Definitions of message info are in include/catalog/pg_control.h,
- * though not all messages relate to control file processing.
+ * Definitions of info values are in include/catalog/pg_control.h, though
+ * not all records types are related to control file processing.
*/
void
xlog_redo(XLogRecPtr lsn, XLogRecord *record)
@@ -7570,7 +7570,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to run a backup")));
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is in progress"),
@@ -7748,7 +7748,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to run a backup"))));
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is in progress"),
@@ -7915,7 +7915,7 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to switch transaction log files"))));
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is in progress"),
@@ -7943,7 +7943,7 @@ pg_current_xlog_location(PG_FUNCTION_ARGS)
{
char location[MAXFNAMELEN];
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is in progress"),
@@ -7976,7 +7976,7 @@ pg_current_xlog_insert_location(PG_FUNCTION_ARGS)
XLogRecPtr current_recptr;
char location[MAXFNAMELEN];
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is in progress"),
@@ -8327,7 +8327,7 @@ static void
StartupProcShutdownHandler(SIGNAL_ARGS)
{
if (in_restore_command)
- proc_exit(0);
+ proc_exit(1);
else
shutdown_requested = true;
}
@@ -8375,9 +8375,9 @@ StartupProcessMain(void)
BuildFlatFiles(false);
- /* Let postmaster know that startup is finished */
- SendPostmasterSignal(PMSIGNAL_RECOVERY_COMPLETED);
-
- /* exit normally */
+ /*
+ * Exit normally. Exit code 0 tells postmaster that we completed
+ * recovery successfully.
+ */
proc_exit(0);
}
diff --git a/src/backend/commands/discard.c b/src/backend/commands/discard.c
index 9623a6bd77..613dbc12c3 100644
--- a/src/backend/commands/discard.c
+++ b/src/backend/commands/discard.c
@@ -65,7 +65,7 @@ DiscardAll(bool isTopLevel)
ResetAllOptions();
DropAllPreparedStatements();
PortalHashTableDeleteAll();
- if (!IsRecoveryProcessingMode())
+ if (!RecoveryInProgress())
Async_UnlistenAll();
LockReleaseAll(USER_LOCKMETHOD, true);
ResetPlanCache();
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 1f1309771f..fdf322a386 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -424,9 +424,27 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
create_unique_path(root, rel2, rel2->cheapest_total_path,
sjinfo) != NULL)
{
- /*
+ /*----------
* For a semijoin, we can join the RHS to anything else by
* unique-ifying the RHS (if the RHS can be unique-ified).
+ * We will only get here if we have the full RHS but less
+ * than min_lefthand on the LHS.
+ *
+ * The reason to consider such a join path is exemplified by
+ * SELECT ... FROM a,b WHERE (a.x,b.y) IN (SELECT c1,c2 FROM c)
+ * If we insist on doing this as a semijoin we will first have
+ * to form the cartesian product of A*B. But if we unique-ify
+ * C then the semijoin becomes a plain innerjoin and we can join
+ * in any order, eg C to A and then to B. When C is much smaller
+ * than A and B this can be a huge win. So we allow C to be
+ * joined to just A or just B here, and then make_join_rel has
+ * to handle the case properly.
+ *
+ * Note that actually we'll allow unique-ified C to be joined to
+ * some other relation D here, too. That is legal, if usually not
+ * very sane, and this routine is only concerned with legality not
+ * with whether the join is good strategy.
+ *----------
*/
if (match_sjinfo)
return false; /* invalid join path */
@@ -648,8 +666,10 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
break;
case JOIN_SEMI:
/*
- * Do these steps only if we actually have a regular semijoin,
- * as opposed to a case where we should unique-ify the RHS.
+ * We might have a normal semijoin, or a case where we don't have
+ * enough rels to do the semijoin but can unique-ify the RHS and
+ * then do an innerjoin (see comments in join_is_legal). In the
+ * latter case we can't apply JOIN_SEMI joining.
*/
if (bms_is_subset(sjinfo->min_lefthand, rel1->relids) &&
bms_is_subset(sjinfo->min_righthand, rel2->relids))
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index b4dc2ed62f..1e126a5a12 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -725,6 +725,9 @@ make_outerjoininfo(PlannerInfo *root,
* 'qualscope' identifies what level of JOIN the qual came from syntactically.
* 'ojscope' is needed if we decide to force the qual up to the outer-join
* level, which will be ojscope not necessarily qualscope.
+ *
+ * At the time this is called, root->join_info_list must contain entries for
+ * all and only those special joins that are syntactically below this qual.
*/
static void
distribute_qual_to_rels(PlannerInfo *root, Node *clause,
@@ -1209,7 +1212,6 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
{
Var *forced_null_var;
Index forced_null_rel;
- SpecialJoinInfo *match_sjinfo = NULL;
ListCell *lc;
/* Check for IS NULL, and identify the Var forced to NULL */
@@ -1219,47 +1221,19 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
forced_null_rel = forced_null_var->varno;
/*
- * Search to see if there's a matching antijoin that is not masked by
- * a higher outer join. Because we have to scan the join info bottom-up,
- * we have to continue looking after finding a match to check for masking
- * joins. This logic should agree with reduce_outer_joins's code
- * to detect antijoins on the basis of IS NULL clauses. (It's tempting
- * to consider adding some data structures to avoid redundant work,
- * but in practice this code shouldn't get executed often enough to
- * make it worth the trouble.)
+ * If the Var comes from the nullable side of a lower antijoin, the
+ * IS NULL condition is necessarily true.
*/
foreach(lc, root->join_info_list)
{
SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
- /* Check for match ... */
if (sjinfo->jointype == JOIN_ANTI &&
bms_is_member(forced_null_rel, sjinfo->syn_righthand))
- {
- List *nonnullable_vars;
-
- nonnullable_vars = find_nonnullable_vars((Node *) sjinfo->join_quals);
- if (list_member(nonnullable_vars, forced_null_var))
- {
- match_sjinfo = sjinfo;
- continue;
- }
- }
- /*
- * Else, if we had a lower match, check to see if the target var is
- * from the nullable side of this OJ. If so, this OJ masks the
- * lower one and we can no longer consider the IS NULL as redundant
- * with the lower antijoin.
- */
- if (!match_sjinfo)
- continue;
- if (bms_is_member(forced_null_rel, sjinfo->syn_righthand) ||
- (sjinfo->jointype == JOIN_FULL &&
- bms_is_member(forced_null_rel, sjinfo->syn_lefthand)))
- match_sjinfo = NULL;
+ return true;
}
- return (match_sjinfo != NULL);
+ return false;
}
/*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 79aa36dc3a..d916f3242f 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -198,7 +198,6 @@ BackgroundWriterMain(void)
{
sigjmp_buf local_sigjmp_buf;
MemoryContext bgwriter_context;
- bool BgWriterRecoveryMode = true;
BgWriterShmem->bgwriter_pid = MyProcPid;
am_bg_writer = true;
@@ -420,31 +419,25 @@ BackgroundWriterMain(void)
}
/*
- * Check if we've exited recovery. We do this after determining
- * whether to perform a checkpoint or not, to be sure that we
- * perform a real checkpoint and not a restartpoint, if someone
- * requested a checkpoint immediately after exiting recovery. And
- * we must have the right TimeLineID when we perform a checkpoint;
- * IsRecoveryProcessingMode() initializes that as a side-effect.
- */
- if (BgWriterRecoveryMode && !IsRecoveryProcessingMode())
- {
- elog(DEBUG1, "bgwriter changing from recovery to normal mode");
- BgWriterRecoveryMode = false;
- }
-
- /*
* Do a checkpoint if requested, otherwise do one cycle of
* dirty-buffer writing.
*/
if (do_checkpoint)
{
bool ckpt_performed = false;
+ bool do_restartpoint;
/* use volatile pointer to prevent code rearrangement */
volatile BgWriterShmemStruct *bgs = BgWriterShmem;
/*
+ * Check if we should perform a checkpoint or a restartpoint.
+ * As a side-effect, RecoveryInProgress() initializes
+ * TimeLineID if it's not set yet.
+ */
+ do_restartpoint = RecoveryInProgress();
+
+ /*
* Atomically fetch the request flags to figure out what kind of a
* checkpoint we should perform, and increase the started-counter
* to acknowledge that we've started a new checkpoint.
@@ -462,7 +455,7 @@ BackgroundWriterMain(void)
* implementation will not generate warnings caused by
* CheckPointTimeout < CheckPointWarning.
*/
- if (!BgWriterRecoveryMode &&
+ if (!do_restartpoint &&
(flags & CHECKPOINT_CAUSE_XLOG) &&
elapsed_secs < CheckPointWarning)
ereport(LOG,
@@ -474,7 +467,7 @@ BackgroundWriterMain(void)
* Initialize bgwriter-private variables used during checkpoint.
*/
ckpt_active = true;
- if (!BgWriterRecoveryMode)
+ if (!do_restartpoint)
ckpt_start_recptr = GetInsertRecPtr();
ckpt_start_time = now;
ckpt_cached_elapsed = 0;
@@ -482,7 +475,7 @@ BackgroundWriterMain(void)
/*
* Do the checkpoint.
*/
- if (!BgWriterRecoveryMode)
+ if (!do_restartpoint)
{
CreateCheckPoint(flags);
ckpt_performed = true;
@@ -546,7 +539,7 @@ CheckArchiveTimeout(void)
pg_time_t now;
pg_time_t last_time;
- if (XLogArchiveTimeout <= 0 || IsRecoveryProcessingMode())
+ if (XLogArchiveTimeout <= 0 || RecoveryInProgress())
return;
now = (pg_time_t) time(NULL);
@@ -625,8 +618,7 @@ BgWriterNap(void)
(ckpt_active ? ImmediateCheckpointRequested() : checkpoint_requested))
break;
pg_usleep(1000000L);
- if (!IsRecoveryProcessingMode())
- AbsorbFsyncRequests();
+ AbsorbFsyncRequests();
udelay -= 1000000L;
}
@@ -754,7 +746,7 @@ IsCheckpointOnSchedule(double progress)
* However, it's good enough for our purposes, we're only calculating an
* estimate anyway.
*/
- if (!IsRecoveryProcessingMode())
+ if (!RecoveryInProgress())
{
recptr = GetInsertRecPtr();
elapsed_xlogs =
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index cfd4eeddd2..cff40cfb29 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -225,15 +225,7 @@ static pid_t StartupPID = 0,
static int Shutdown = NoShutdown;
static bool FatalError = false; /* T if recovering from backend crash */
-static bool RecoveryError = false; /* T if recovery failed */
-
-/* State of WAL redo */
-#define NoRecovery 0
-#define RecoveryStarted 1
-#define RecoveryConsistent 2
-#define RecoveryCompleted 3
-
-static int RecoveryStatus = NoRecovery;
+static bool RecoveryError = false; /* T if WAL recovery failed */
/*
* We use a simple state machine to control startup, shutdown, and
@@ -252,8 +244,8 @@ static int RecoveryStatus = NoRecovery;
* could start accepting connections to perform read-only queries at this
* point, if we had the infrastructure to do that.
*
- * When the WAL redo is finished, the startup process signals us the third
- * time, and we switch to PM_RUN state. The startup process can also skip the
+ * When WAL redo is finished, the startup process exits with exit code 0
+ * and we switch to PM_RUN state. Startup process can also skip the
* recovery and consistent recovery phases altogether, as it will during
* normal startup when there's no recovery to be done, for example.
*
@@ -277,6 +269,8 @@ static int RecoveryStatus = NoRecovery;
* states, nor in PM_SHUTDOWN states (because we don't enter those states
* when trying to recover from a crash). It can be true in PM_STARTUP state,
* because we don't clear it until we've successfully started WAL redo.
+ * Similarly, RecoveryError means that we have crashed during recovery, and
+ * should not try to restart.
*/
typedef enum
{
@@ -337,7 +331,6 @@ static void pmdie(SIGNAL_ARGS);
static void reaper(SIGNAL_ARGS);
static void sigusr1_handler(SIGNAL_ARGS);
static void dummy_handler(SIGNAL_ARGS);
-static void CheckRecoverySignals(void);
static void CleanupBackend(int pid, int exitstatus);
static void HandleChildCrash(int pid, int exitstatus, const char *procname);
static void LogChildExit(int lev, const char *procname,
@@ -2016,7 +2009,8 @@ pmdie(SIGNAL_ARGS)
ereport(LOG,
(errmsg("received smart shutdown request")));
- if (pmState == PM_RUN || pmState == PM_RECOVERY || pmState == PM_RECOVERY_CONSISTENT)
+ if (pmState == PM_RUN || pmState == PM_RECOVERY ||
+ pmState == PM_RECOVERY_CONSISTENT)
{
/* autovacuum workers are told to shut down immediately */
if (pmState == PM_RUN)
@@ -2160,20 +2154,11 @@ reaper(SIGNAL_ARGS)
StartupPID = 0;
/*
- * Check if we've received a signal from the startup process
- * first. This can change pmState. If the startup process sends
- * a signal, and exits immediately after that, we might not have
- * processed the signal yet, and we need to know if it completed
- * recovery before exiting.
- */
- CheckRecoverySignals();
-
- /*
* Unexpected exit of startup process (including FATAL exit)
* during PM_STARTUP is treated as catastrophic. There is no
- * other processes running yet.
+ * other processes running yet, so we can just exit.
*/
- if (pmState == PM_STARTUP)
+ if (pmState == PM_STARTUP && !EXIT_STATUS_0(exitstatus))
{
LogChildExit(LOG, _("startup process"),
pid, exitstatus);
@@ -2182,6 +2167,17 @@ reaper(SIGNAL_ARGS)
ExitPostmaster(1);
}
/*
+ * Startup process exited in response to a shutdown request (or
+ * it completed normally regardless of the shutdown request).
+ */
+ if (Shutdown > NoShutdown &&
+ (EXIT_STATUS_0(exitstatus) || EXIT_STATUS_1(exitstatus)))
+ {
+ pmState = PM_WAIT_BACKENDS;
+ /* PostmasterStateMachine logic does the rest */
+ continue;
+ }
+ /*
* Any unexpected exit (including FATAL exit) of the startup
* process is treated as a crash, except that we don't want
* to reinitialize.
@@ -2193,18 +2189,46 @@ reaper(SIGNAL_ARGS)
_("startup process"));
continue;
}
+
/*
- * Startup process exited normally, but didn't finish recovery.
- * This can happen if someone else than postmaster kills the
- * startup process with SIGTERM. Treat it like a crash.
+ * Startup succeeded, commence normal operations
*/
- if (pmState == PM_RECOVERY || pmState == PM_RECOVERY_CONSISTENT)
- {
- RecoveryError = true;
- HandleChildCrash(pid, exitstatus,
- _("startup process"));
- continue;
- }
+ FatalError = false;
+ pmState = PM_RUN;
+
+ /*
+ * Load the flat authorization file into postmaster's cache. The
+ * startup process has recomputed this from the database contents,
+ * so we wait till it finishes before loading it.
+ */
+ load_role();
+
+ /*
+ * Crank up the background writer, if we didn't do that already
+ * when we entered consistent recovery phase. It doesn't matter
+ * if this fails, we'll just try again later.
+ */
+ if (BgWriterPID == 0)
+ BgWriterPID = StartBackgroundWriter();
+
+ /*
+ * Likewise, start other special children as needed. In a restart
+ * situation, some of them may be alive already.
+ */
+ if (WalWriterPID == 0)
+ WalWriterPID = StartWalWriter();
+ if (AutoVacuumingActive() && AutoVacPID == 0)
+ AutoVacPID = StartAutoVacLauncher();
+ if (XLogArchivingActive() && PgArchPID == 0)
+ PgArchPID = pgarch_start();
+ if (PgStatPID == 0)
+ PgStatPID = pgstat_start();
+
+ /* at this point we are really open for business */
+ ereport(LOG,
+ (errmsg("database system is ready to accept connections")));
+
+ continue;
}
/*
@@ -2620,127 +2644,6 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus)
static void
PostmasterStateMachine(void)
{
- /* Startup states */
-
- if (pmState == PM_STARTUP && RecoveryStatus > NoRecovery)
- {
- /* WAL redo has started. We're out of reinitialization. */
- FatalError = false;
-
- /*
- * Go to shutdown mode if a shutdown request was pending.
- */
- if (Shutdown > NoShutdown)
- {
- pmState = PM_WAIT_BACKENDS;
- /* PostmasterStateMachine logic does the rest */
- }
- else
- {
- /*
- * Crank up the background writer. It doesn't matter if this
- * fails, we'll just try again later.
- */
- Assert(BgWriterPID == 0);
- BgWriterPID = StartBackgroundWriter();
-
- pmState = PM_RECOVERY;
- }
- }
- if (pmState == PM_RECOVERY && RecoveryStatus >= RecoveryConsistent)
- {
- /*
- * Go to shutdown mode if a shutdown request was pending.
- */
- if (Shutdown > NoShutdown)
- {
- pmState = PM_WAIT_BACKENDS;
- /* PostmasterStateMachine logic does the rest */
- }
- else
- {
- /*
- * Startup process has entered recovery. We consider that good
- * enough to reset FatalError.
- */
- pmState = PM_RECOVERY_CONSISTENT;
-
- /*
- * Load the flat authorization file into postmaster's cache. The
- * file may change again during recovery, in which case we will
- * be signalled again by startup process to re-read.
- */
- load_role();
-
- /*
- * Likewise, start other special children as needed.
- */
- Assert(PgStatPID == 0);
- PgStatPID = pgstat_start();
-
- /* XXX at this point we could accept read-only connections */
- ereport(DEBUG1,
- (errmsg("database system is in consistent recovery mode")));
- }
- }
- if ((pmState == PM_RECOVERY ||
- pmState == PM_RECOVERY_CONSISTENT ||
- pmState == PM_STARTUP) &&
- RecoveryStatus == RecoveryCompleted)
- {
- /*
- * Startup succeeded.
- *
- * Go to shutdown mode if a shutdown request was pending.
- */
- if (Shutdown > NoShutdown)
- {
- pmState = PM_WAIT_BACKENDS;
- /* PostmasterStateMachine logic does the rest */
- }
- else
- {
- /*
- * Otherwise, commence normal operations.
- */
- pmState = PM_RUN;
-
- /*
- * Load the flat authorization file into postmaster's cache. The
- * startup process has recomputed this from the database contents,
- * so we wait till it finishes before loading it.
- */
- load_role();
-
- /*
- * Crank up the background writer, if we didn't do that already
- * when we entered consistent recovery phase. It doesn't matter
- * if this fails, we'll just try again later.
- */
- if (BgWriterPID == 0)
- BgWriterPID = StartBackgroundWriter();
-
- /*
- * Likewise, start other special children as needed. In a restart
- * situation, some of them may be alive already.
- */
- if (WalWriterPID == 0)
- WalWriterPID = StartWalWriter();
- if (AutoVacuumingActive() && AutoVacPID == 0)
- AutoVacPID = StartAutoVacLauncher();
- if (XLogArchivingActive() && PgArchPID == 0)
- PgArchPID = pgarch_start();
- if (PgStatPID == 0)
- PgStatPID = pgstat_start();
-
- /* at this point we are really open for business */
- ereport(LOG,
- (errmsg("database system is ready to accept connections")));
- }
- }
-
- /* Shutdown states */
-
if (pmState == PM_WAIT_BACKUP)
{
/*
@@ -2902,8 +2805,6 @@ PostmasterStateMachine(void)
shmem_exit(1);
reset_shared(PostPortNumber);
- RecoveryStatus = NoRecovery;
-
StartupPID = StartupDataBase();
Assert(StartupPID != 0);
pmState = PM_STARTUP;
@@ -4009,47 +3910,58 @@ ExitPostmaster(int status)
}
/*
- * common code used in sigusr1_handler() and reaper() to handle
- * recovery-related signals from startup process
+ * sigusr1_handler - handle signal conditions from child processes
*/
static void
-CheckRecoverySignals(void)
+sigusr1_handler(SIGNAL_ARGS)
{
- bool changed = false;
+ int save_errno = errno;
- if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED))
- {
- Assert(pmState == PM_STARTUP);
+ PG_SETMASK(&BlockSig);
- RecoveryStatus = RecoveryStarted;
- changed = true;
- }
- if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_CONSISTENT))
+ /*
+ * RECOVERY_STARTED and RECOVERY_CONSISTENT signals are ignored in
+ * unexpected states. If the startup process quickly starts up, completes
+ * recovery, exits, we might process the death of the startup process
+ * first. We don't want to go back to recovery in that case.
+ */
+ if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED) &&
+ pmState == PM_STARTUP)
{
- RecoveryStatus = RecoveryConsistent;
- changed = true;
+ /* WAL redo has started. We're out of reinitialization. */
+ FatalError = false;
+
+ /*
+ * Crank up the background writer. It doesn't matter if this
+ * fails, we'll just try again later.
+ */
+ Assert(BgWriterPID == 0);
+ BgWriterPID = StartBackgroundWriter();
+
+ pmState = PM_RECOVERY;
}
- if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_COMPLETED))
+ if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_CONSISTENT) &&
+ pmState == PM_RECOVERY)
{
- RecoveryStatus = RecoveryCompleted;
- changed = true;
- }
-
- if (changed)
- PostmasterStateMachine();
-}
+ /*
+ * Load the flat authorization file into postmaster's cache. The
+ * startup process won't have recomputed this from the database yet,
+ * so we it may change following recovery.
+ */
+ load_role();
-/*
- * sigusr1_handler - handle signal conditions from child processes
- */
-static void
-sigusr1_handler(SIGNAL_ARGS)
-{
- int save_errno = errno;
+ /*
+ * Likewise, start other special children as needed.
+ */
+ Assert(PgStatPID == 0);
+ PgStatPID = pgstat_start();
- PG_SETMASK(&BlockSig);
+ /* XXX at this point we could accept read-only connections */
+ ereport(DEBUG1,
+ (errmsg("database system is in consistent recovery mode")));
- CheckRecoverySignals();
+ pmState = PM_RECOVERY_CONSISTENT;
+ }
if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE))
{
diff --git a/src/backend/storage/buffer/README b/src/backend/storage/buffer/README
index a7b81e37a7..bfacfea0f1 100644
--- a/src/backend/storage/buffer/README
+++ b/src/backend/storage/buffer/README
@@ -272,8 +272,4 @@ reasons mentioned under buffer access rules.
As of 8.4, background writer starts during recovery mode when there is
some form of potentially extended recovery to perform. It performs an
identical service to normal processing, except that checkpoints it
-writes are technically restartpoints. Flushing outstanding WAL for dirty
-buffers is also skipped, though there shouldn't ever be new WAL entries
-at that time in any case. We could choose to start background writer
-immediately but we hold off until we can prove the database is in a
-consistent state so that postmaster has a single, clean state change.
+writes are technically restartpoints.
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 3aafe348cd..04bf18ceec 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -265,7 +265,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid,
/*
* Remove any UnobservedXids remaining
*/
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
{
for (index = 0; index < nsubxids; index++)
UnobservedTransactionsRemoveXid(subxids[index], false);
@@ -283,7 +283,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid,
else
{
/* Shouldn't be trying to remove a live transaction here */
- Assert(IsRecoveryProcessingMode() || !TransactionIdIsValid(proc->xid));
+ Assert(RecoveryInProgress() || !TransactionIdIsValid(proc->xid));
}
for (index = 0; index < arrayP->numProcs; index++)
@@ -300,7 +300,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid,
/* Ooops */
LWLockRelease(ProcArrayLock);
- elog(IsRecoveryProcessingMode() ? ERROR : LOG,
+ elog(RecoveryInProgress() ? ERROR : LOG,
"failed to find proc %p in ProcArray", proc);
}
@@ -1371,7 +1371,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
int index;
/* Cannot look for individual databases during recovery */
- Assert(allDbs || !IsRecoveryProcessingMode());
+ Assert(allDbs || !RecoveryInProgress());
LWLockAcquire(ProcArrayLock, LW_SHARED);
@@ -1485,7 +1485,7 @@ GetSnapshotData(Snapshot snapshot)
* space allocation to allow for UnobservedXids, which never occur
* in normal running.
*/
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
snapshot->xip = (TransactionId *)
malloc(3 * arrayP->maxProcs * sizeof(TransactionId));
else
@@ -1510,7 +1510,7 @@ GetSnapshotData(Snapshot snapshot)
*/
LWLockAcquire(ProcArrayLock, LW_SHARED);
- if (IsRecoveryProcessingMode() && !arrayP->allowStandbySnapshots)
+ if (RecoveryInProgress() && !arrayP->allowStandbySnapshots)
{
LWLockRelease(ProcArrayLock);
ereport(ERROR,
@@ -1605,7 +1605,7 @@ GetSnapshotData(Snapshot snapshot)
/*
* Also check for unobserved xids. There is no need for us to specify
- * that this is only if IsRecoveryProcessingMode(), since the list will
+ * that this is only if RecoveryInProgress(), since the list will
* always be empty when normal processing begins and the test will be
* optimised to nearly nothing very quickly.
*/
@@ -2485,7 +2485,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
int tries;
/* Gives wrong answer in recovery, so make sure we don't use it */
- Assert(!IsRecoveryProcessingMode());
+ Assert(!RecoveryInProgress());
/* 50 tries with 100ms sleep between tries makes 5 sec total wait */
for (tries = 0; tries < 50; tries++)
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index b9cd501f6c..0154900e67 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -492,7 +492,7 @@ LockAcquire(const LOCKTAG *locktag,
if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
elog(ERROR, "unrecognized lock mode: %d", lockmode);
- if (IsRecoveryProcessingMode() &&
+ if (RecoveryInProgress() &&
locktag->locktag_type == LOCKTAG_OBJECT &&
lockmode > AccessShareLock)
ereport(ERROR,
@@ -834,7 +834,7 @@ LockAcquire(const LOCKTAG *locktag,
* to send a WAL message so that standby servers can see this event,
* if its an AccessExclusiveLock on a relation.
*/
- if (!IsRecoveryProcessingMode() && lockmode >= AccessExclusiveLock &&
+ if (!RecoveryInProgress() && lockmode >= AccessExclusiveLock &&
locktag->locktag_type == LOCKTAG_RELATION)
{
XLogRecData rdata;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index f1d67d928a..e6e0acb6e7 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1428,7 +1428,7 @@ ProcSendSignal(int pid)
{
PGPROC *proc = NULL;
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
{
/* use volatile pointer to prevent code rearrangement */
volatile PROC_HDR *procglobal = ProcGlobal;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 2480e712d9..e0d0412bf4 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -2674,7 +2674,7 @@ ProcessInterrupts(void)
switch (cancelMode)
{
case FATAL:
- Assert(IsRecoveryProcessingMode());
+ Assert(RecoveryInProgress());
ereport(FATAL,
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling session due to conflict with recovery")));
@@ -2689,7 +2689,7 @@ ProcessInterrupts(void)
* transaction tree and remove just enough
* subxacts to remove locks? Doubt it.
*/
- Assert(IsRecoveryProcessingMode());
+ Assert(RecoveryInProgress());
AbortOutOfAnyTransaction();
ereport(ERROR,
(errcode(ERRCODE_QUERY_CANCELED),
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 482f6d048c..65a9f2f6d8 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -2531,7 +2531,7 @@ GetCommandLogLevel(Node *parsetree)
void
PreventCommandDuringRecovery(void)
{
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
errmsg("cannot be run until recovery completes")));
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index bd3601c608..19b570d9c4 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -576,9 +576,7 @@ float4um(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 result;
- result = ((arg1 != 0) ? -(arg1) : arg1);
-
- CHECKFLOATVAL(result, isinf(arg1), true);
+ result = -arg1;
PG_RETURN_FLOAT4(result);
}
@@ -645,9 +643,7 @@ float8um(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 result;
- result = ((arg1 != 0) ? -(arg1) : arg1);
-
- CHECKFLOATVAL(result, isinf(arg1), true);
+ result = -arg1;
PG_RETURN_FLOAT8(result);
}
@@ -703,16 +699,16 @@ float8smaller(PG_FUNCTION_ARGS)
Datum
float4pl(PG_FUNCTION_ARGS)
{
- float8 arg1 = PG_GETARG_FLOAT4(0);
- float8 arg2 = PG_GETARG_FLOAT4(1);
+ float4 arg1 = PG_GETARG_FLOAT4(0);
+ float4 arg2 = PG_GETARG_FLOAT4(1);
float4 result;
result = arg1 + arg2;
/*
* There isn't any way to check for underflow of addition/subtraction
- * because numbers near the underflow value have been already been to the
- * point where we can't detect the that the two values were originally
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
* different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
* 1.4013e-45.
*/
@@ -757,7 +753,6 @@ float4div(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- /* Do division in float8, then check for overflow */
result = arg1 / arg2;
CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
@@ -2693,7 +2688,7 @@ width_bucket_float8(PG_FUNCTION_ARGS)
errmsg("operand, lower bound and upper bound cannot be NaN")));
/* Note that we allow "operand" to be infinite */
- if (is_infinite(bound1) || is_infinite(bound2))
+ if (isinf(bound1) || isinf(bound2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
errmsg("lower and upper bounds must be finite")));
diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c
index 81814e6e2b..0a4ee4b6c0 100644
--- a/src/backend/utils/adt/txid.c
+++ b/src/backend/utils/adt/txid.c
@@ -338,7 +338,7 @@ txid_current(PG_FUNCTION_ARGS)
txid val;
TxidEpoch state;
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot assign txid while recovery is in progress"),
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 18a2c7b51b..8bc5909d67 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -456,7 +456,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
* be called here if we are not in recovery processing mode.
*/
if (!bootstrap)
- (void) IsRecoveryProcessingMode();
+ (void) RecoveryInProgress();
/*
* Initialize the relation cache and the system catalog caches. Note that
@@ -496,7 +496,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
*/
if (!bootstrap)
{
- if (IsRecoveryProcessingMode())
+ if (RecoveryInProgress())
SetConfigOption("default_transaction_read_only", "true",
PGC_POSTMASTER, PGC_S_OVERRIDE);
StartTransactionCommand();
@@ -522,7 +522,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
*/
if (!bootstrap)
LockSharedObject(DatabaseRelationId, MyDatabaseId, 0,
- (IsRecoveryProcessingMode() ? AccessShareLock : RowExclusiveLock));
+ (RecoveryInProgress() ? AccessShareLock : RowExclusiveLock));
/*
* Recheck the flat file copy of pg_database to make sure the target
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 07e20d5324..e54f537479 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -86,7 +86,7 @@ static inline void
SetHintBits(HeapTupleHeader tuple, Buffer buffer,
uint16 infomask, TransactionId xid)
{
- if (!IsRecoveryProcessingMode() && TransactionIdIsValid(xid))
+ if (!RecoveryInProgress() && TransactionIdIsValid(xid))
{
/* NB: xid must be known committed here! */
XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 6cf171d455..5eda359a3e 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -487,6 +487,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te,
{
ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
_reconnectToDB(AH, te->tag);
+ ropt->dbname = strdup(te->tag);
}
}
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 43843c97ed..32a8ae6c2f 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1585,6 +1585,7 @@ dumpDatabase(Archive *AH)
i_encoding,
i_collate,
i_ctype,
+ i_frozenxid,
i_tablespace;
CatalogId dbCatId;
DumpId dbDumpId;
@@ -1594,6 +1595,7 @@ dumpDatabase(Archive *AH)
*collate,
*ctype,
*tablespace;
+ uint32 frozenxid;
datname = PQdb(g_conn);
@@ -1609,7 +1611,7 @@ dumpDatabase(Archive *AH)
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
- "datcollate, datctype, "
+ "datcollate, datctype, datfrozenxid, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
"shobj_description(oid, 'pg_database') AS description "
@@ -1623,7 +1625,7 @@ dumpDatabase(Archive *AH)
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
- "NULL AS datcollate, NULL AS datctype, "
+ "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
"shobj_description(oid, 'pg_database') AS description "
@@ -1637,7 +1639,7 @@ dumpDatabase(Archive *AH)
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
- "NULL AS datcollate, NULL AS datctype, "
+ "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
"FROM pg_database "
"WHERE datname = ",
@@ -1650,6 +1652,7 @@ dumpDatabase(Archive *AH)
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
"NULL AS datcollate, NULL AS datctype, "
+ "0 AS datfrozenxid, "
"NULL AS tablespace "
"FROM pg_database "
"WHERE datname = ",
@@ -1664,6 +1667,7 @@ dumpDatabase(Archive *AH)
"(%s datdba) AS dba, "
"pg_encoding_to_char(encoding) AS encoding, "
"NULL AS datcollate, NULL AS datctype, "
+ "0 AS datfrozenxid, "
"NULL AS tablespace "
"FROM pg_database "
"WHERE datname = ",
@@ -1696,6 +1700,7 @@ dumpDatabase(Archive *AH)
i_encoding = PQfnumber(res, "encoding");
i_collate = PQfnumber(res, "datcollate");
i_ctype = PQfnumber(res, "datctype");
+ i_frozenxid = PQfnumber(res, "datfrozenxid");
i_tablespace = PQfnumber(res, "tablespace");
dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
@@ -1704,6 +1709,7 @@ dumpDatabase(Archive *AH)
encoding = PQgetvalue(res, 0, i_encoding);
collate = PQgetvalue(res, 0, i_collate);
ctype = PQgetvalue(res, 0, i_ctype);
+ frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
tablespace = PQgetvalue(res, 0, i_tablespace);
appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
@@ -1728,6 +1734,15 @@ dumpDatabase(Archive *AH)
fmtId(tablespace));
appendPQExpBuffer(creaQry, ";\n");
+ if (binary_upgrade)
+ {
+ appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
+ appendPQExpBuffer(creaQry, "UPDATE pg_database\n"
+ "SET datfrozenxid = '%u'\n"
+ "WHERE datname = '%s';\n",
+ frozenxid, datname);
+ }
+
appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
fmtId(datname));
@@ -3114,6 +3129,7 @@ getTables(int *numTables)
int i_relhasindex;
int i_relhasrules;
int i_relhasoids;
+ int i_relfrozenxid;
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
@@ -3155,6 +3171,7 @@ getTables(int *numTables)
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
+ "c.relfrozenxid, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -3186,6 +3203,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, "
+ "relfrozenxid, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -3216,6 +3234,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, "
+ "0 AS relfrozenxid, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
@@ -3246,6 +3265,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, "
+ "0 AS relfrozenxid, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"NULL AS reltablespace, "
@@ -3272,6 +3292,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, "
+ "0 AS relfrozenxid, "
"NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
@@ -3293,6 +3314,7 @@ getTables(int *numTables)
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, "
"'t'::bool AS relhasoids, "
+ "0 AS relfrozenxid, "
"NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
@@ -3324,6 +3346,7 @@ getTables(int *numTables)
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, "
"'t'::bool AS relhasoids, "
+ "0 as relfrozenxid, "
"NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
@@ -3367,6 +3390,7 @@ getTables(int *numTables)
i_relhasindex = PQfnumber(res, "relhasindex");
i_relhasrules = PQfnumber(res, "relhasrules");
i_relhasoids = PQfnumber(res, "relhasoids");
+ i_relfrozenxid = PQfnumber(res, "relfrozenxid");
i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace");
@@ -3404,6 +3428,7 @@ getTables(int *numTables)
tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
+ tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
if (PQgetisnull(res, i, i_owning_tab))
{
@@ -9860,6 +9885,15 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
tbinfo->dobj.name);
}
}
+ appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
+ appendPQExpBuffer(q, "UPDATE pg_class\n"
+ "SET relfrozenxid = '%u'\n"
+ "WHERE relname = '%s'\n"
+ " AND relnamespace = "
+ "(SELECT oid FROM pg_namespace "
+ "WHERE nspname = CURRENT_SCHEMA);\n",
+ tbinfo->frozenxid,
+ tbinfo->dobj.name);
}
/* Loop dumping statistics and storage statements */
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 8869a5146a..8949f01482 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -226,6 +226,7 @@ typedef struct _tableInfo
bool hasrules; /* does it have any rules? */
bool hastriggers; /* does it have any triggers? */
bool hasoids; /* does it have OIDs? */
+ uint32 frozenxid; /* for restore frozen xid */
int ncheck; /* # of CHECK expressions */
/* these two are set only if table is a sequence owned by a column: */
Oid owning_tab; /* OID of table owning sequence */
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 55d15e9e18..2255a6716b 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -27,7 +27,7 @@ int optreset;
#endif
#include "dumputils.h"
-
+#include "pg_backup.h"
/* version string we expect back from pg_dump */
#define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
@@ -71,6 +71,8 @@ static int server_version;
static FILE *OPF;
static char *filename = NULL;
+static int binary_upgrade = 0;
+
int
main(int argc, char *argv[])
{
@@ -90,7 +92,6 @@ main(int argc, char *argv[])
const char *std_strings;
int c,
ret;
- int binary_upgrade = 0;
struct option long_options[] = {
{"binary-upgrade", no_argument, &binary_upgrade, 1}, /* not documented */
@@ -937,7 +938,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, "
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
- "datcollate, datctype, "
+ "datcollate, datctype, datfrozenxid, "
"datistemplate, datacl, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
@@ -947,7 +948,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, "
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
- "null::text AS datcollate, null::text AS datctype, "
+ "null::text AS datcollate, null::text AS datctype, datfrozenxid, "
"datistemplate, datacl, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
@@ -957,7 +958,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, "
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
- "null::text AS datcollate, null::text AS datctype, "
+ "null::text AS datcollate, null::text AS datctype, datfrozenxid, "
"datistemplate, datacl, -1 as datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
@@ -967,7 +968,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, "
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
- "null::text AS datcollate, null::text AS datctype, "
+ "null::text AS datcollate, null::text AS datctype, datfrozenxid, "
"datistemplate, datacl, -1 as datconnlimit, "
"'pg_default' AS dattablespace "
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
@@ -979,7 +980,7 @@ dumpCreateDB(PGconn *conn)
"(select usename from pg_shadow where usesysid=datdba), "
"(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
- "null::text AS datcollate, null::text AS datctype, "
+ "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid"
"datistemplate, '' as datacl, -1 as datconnlimit, "
"'pg_default' AS dattablespace "
"FROM pg_database d "
@@ -994,7 +995,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, "
"(select usename from pg_shadow where usesysid=datdba), "
"pg_encoding_to_char(d.encoding), "
- "null::text AS datcollate, null::text AS datctype, "
+ "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid"
"'f' as datistemplate, "
"'' as datacl, -1 as datconnlimit, "
"'pg_default' AS dattablespace "
@@ -1009,10 +1010,11 @@ dumpCreateDB(PGconn *conn)
char *dbencoding = PQgetvalue(res, i, 2);
char *dbcollate = PQgetvalue(res, i, 3);
char *dbctype = PQgetvalue(res, i, 4);
- char *dbistemplate = PQgetvalue(res, i, 5);
- char *dbacl = PQgetvalue(res, i, 6);
- char *dbconnlimit = PQgetvalue(res, i, 7);
- char *dbtablespace = PQgetvalue(res, i, 8);
+ uint32 dbfrozenxid = atooid(PQgetvalue(res, i, 5));
+ char *dbistemplate = PQgetvalue(res, i, 6);
+ char *dbacl = PQgetvalue(res, i, 7);
+ char *dbconnlimit = PQgetvalue(res, i, 8);
+ char *dbtablespace = PQgetvalue(res, i, 9);
char *fdbname;
fdbname = strdup(fmtId(dbname));
@@ -1076,6 +1078,15 @@ dumpCreateDB(PGconn *conn)
appendStringLiteralConn(buf, dbname, conn);
appendPQExpBuffer(buf, ";\n");
}
+
+ if (binary_upgrade)
+ {
+ appendPQExpBuffer(buf, "\n-- For binary upgrade, set datfrozenxid.\n");
+ appendPQExpBuffer(buf, "UPDATE pg_database\n"
+ "SET datfrozenxid = '%u'\n"
+ "WHERE datname = '%s';\n",
+ dbfrozenxid, fdbname);
+ }
}
if (!skip_acls &&
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index c0f78a1e05..55f1f415dd 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -15,11 +15,11 @@
static void vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
- const char *table,
+ bool freeze, const char *table,
const char *host, const char *port,
const char *username, bool password,
const char *progname, bool echo);
-static void vacuum_all_databases(bool full, bool verbose, bool analyze,
+static void vacuum_all_databases(bool full, bool verbose, bool analyze, bool freeze,
const char *host, const char *port,
const char *username, bool password,
const char *progname, bool echo, bool quiet);
@@ -39,6 +39,7 @@ main(int argc, char *argv[])
{"quiet", no_argument, NULL, 'q'},
{"dbname", required_argument, NULL, 'd'},
{"analyze", no_argument, NULL, 'z'},
+ {"freeze", no_argument, NULL, 'F'},
{"all", no_argument, NULL, 'a'},
{"table", required_argument, NULL, 't'},
{"full", no_argument, NULL, 'f'},
@@ -58,6 +59,7 @@ main(int argc, char *argv[])
bool echo = false;
bool quiet = false;
bool analyze = false;
+ bool freeze = false;
bool alldb = false;
char *table = NULL;
bool full = false;
@@ -68,7 +70,7 @@ main(int argc, char *argv[])
handle_help_version_opts(argc, argv, "vacuumdb", help);
- while ((c = getopt_long(argc, argv, "h:p:U:Weqd:zat:fv", long_options, &optindex)) != -1)
+ while ((c = getopt_long(argc, argv, "h:p:U:Weqd:zaFt:fv", long_options, &optindex)) != -1)
{
switch (c)
{
@@ -96,6 +98,9 @@ main(int argc, char *argv[])
case 'z':
analyze = true;
break;
+ case 'F':
+ freeze = true;
+ break;
case 'a':
alldb = true;
break;
@@ -145,7 +150,7 @@ main(int argc, char *argv[])
exit(1);
}
- vacuum_all_databases(full, verbose, analyze,
+ vacuum_all_databases(full, verbose, analyze, freeze,
host, port, username, password,
progname, echo, quiet);
}
@@ -161,7 +166,7 @@ main(int argc, char *argv[])
dbname = get_user_name(progname);
}
- vacuum_one_database(dbname, full, verbose, analyze, table,
+ vacuum_one_database(dbname, full, verbose, analyze, freeze, table,
host, port, username, password,
progname, echo);
}
@@ -172,7 +177,7 @@ main(int argc, char *argv[])
static void
vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
- const char *table,
+ bool freeze, const char *table,
const char *host, const char *port,
const char *username, bool password,
const char *progname, bool echo)
@@ -190,6 +195,8 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
appendPQExpBuffer(&sql, " VERBOSE");
if (analyze)
appendPQExpBuffer(&sql, " ANALYZE");
+ if (freeze)
+ appendPQExpBuffer(&sql, " FREEZE");
if (table)
appendPQExpBuffer(&sql, " %s", table);
appendPQExpBuffer(&sql, ";\n");
@@ -212,7 +219,7 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
static void
-vacuum_all_databases(bool full, bool verbose, bool analyze,
+vacuum_all_databases(bool full, bool verbose, bool analyze, bool freeze,
const char *host, const char *port,
const char *username, bool password,
const char *progname, bool echo, bool quiet)
@@ -235,7 +242,7 @@ vacuum_all_databases(bool full, bool verbose, bool analyze,
fflush(stdout);
}
- vacuum_one_database(dbname, full, verbose, analyze, NULL,
+ vacuum_one_database(dbname, full, verbose, analyze, freeze, NULL,
host, port, username, password,
progname, echo);
}
@@ -256,6 +263,7 @@ help(const char *progname)
printf(_(" -t, --table='TABLE[(COLUMNS)]' vacuum specific table only\n"));
printf(_(" -f, --full do full vacuuming\n"));
printf(_(" -z, --analyze update optimizer hints\n"));
+ printf(_(" -F, --freeze freeze row transaction information\n"));
printf(_(" -e, --echo show the commands being sent to the server\n"));
printf(_(" -q, --quiet don't write any messages\n"));
printf(_(" -v, --verbose write a lot of output\n"));
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 44971d823d..55198e97cc 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -136,6 +136,7 @@ typedef struct XLogRecData
} XLogRecData;
extern TimeLineID ThisTimeLineID; /* current TLI */
+
/*
* Prior to 8.4, all activity during recovery were carried out by Startup
* process. This local variable continues to be used in many parts of the
@@ -212,7 +213,7 @@ extern void RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup);
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, uint8 xl_info, char *rec);
-extern bool IsRecoveryProcessingMode(void);
+extern bool RecoveryInProgress(void);
extern int GetLatestReplicationDelay(void);
extern void RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup);
diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h
index 62dddfcf5e..4f0432ef91 100644
--- a/src/include/storage/pmsignal.h
+++ b/src/include/storage/pmsignal.h
@@ -24,7 +24,6 @@ typedef enum
{
PMSIGNAL_RECOVERY_STARTED, /* recovery has started */
PMSIGNAL_RECOVERY_CONSISTENT, /* recovery has reached consistent state */
- PMSIGNAL_RECOVERY_COMPLETED, /* recovery completed */
PMSIGNAL_PASSWORD_CHANGE, /* pg_auth file has changed */
PMSIGNAL_WAKEN_ARCHIVER, /* send a NOTIFY signal to xlog archiver */
PMSIGNAL_ROTATE_LOGFILE, /* send SIGUSR1 to syslogger to rotate logfile */
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 92f38ea1eb..ab4aed9c03 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -181,8 +181,12 @@ typedef struct PROC_HDR
/*
* We set aside some extra PGPROC structures for auxiliary processes,
* ie things that aren't full-fledged backends but need shmem access.
+ *
+ * Background writer, WAL writer, and autovacuum launcher run during
+ * normal operation. When recovery has just finished, the startup
+ * process can co-exist with them for a brief period before it exits.
*/
-#define NUM_AUXILIARY_PROCS 3
+#define NUM_AUXILIARY_PROCS 4
/* configurable options */
diff --git a/src/pl/plperl/expected/plperl.out b/src/pl/plperl/expected/plperl.out
index 708723d3e5..e1b0c75108 100644
--- a/src/pl/plperl/expected/plperl.out
+++ b/src/pl/plperl/expected/plperl.out
@@ -121,9 +121,9 @@ CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
];
$$ LANGUAGE plperl;
SELECT perl_set();
-ERROR: setof-composite-returning Perl function must call return_next with reference to hash
+ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
SELECT * FROM perl_set();
-ERROR: setof-composite-returning Perl function must call return_next with reference to hash
+ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
return [
{ f1 => 1, f2 => 'Hello', f3 => 'World' },
@@ -209,7 +209,7 @@ ERROR: a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM perl_record_set();
^
SELECT * FROM perl_record_set() AS (f1 integer, f2 text, f3 text);
-ERROR: setof-composite-returning Perl function must call return_next with reference to hash
+ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
CREATE OR REPLACE FUNCTION perl_record_set() RETURNS SETOF record AS $$
return [
{ f1 => 1, f2 => 'Hello', f3 => 'World' },
@@ -312,7 +312,7 @@ CREATE OR REPLACE FUNCTION foo_bad() RETURNS footype AS $$
return 42;
$$ LANGUAGE plperl;
SELECT * FROM foo_bad();
-ERROR: composite-returning Perl function must return reference to hash
+ERROR: composite-returning PL/Perl function must return reference to hash
CREATE OR REPLACE FUNCTION foo_bad() RETURNS footype AS $$
return [
[1, 2],
@@ -320,17 +320,17 @@ return [
];
$$ LANGUAGE plperl;
SELECT * FROM foo_bad();
-ERROR: composite-returning Perl function must return reference to hash
+ERROR: composite-returning PL/Perl function must return reference to hash
CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
return 42;
$$ LANGUAGE plperl;
SELECT * FROM foo_set_bad();
-ERROR: set-returning Perl function must return reference to array or use return_next
+ERROR: set-returning PL/Perl function must return reference to array or use return_next
CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
return {y => 3, z => 4};
$$ LANGUAGE plperl;
SELECT * FROM foo_set_bad();
-ERROR: set-returning Perl function must return reference to array or use return_next
+ERROR: set-returning PL/Perl function must return reference to array or use return_next
CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
return [
[1, 2],
@@ -338,7 +338,7 @@ return [
];
$$ LANGUAGE plperl;
SELECT * FROM foo_set_bad();
-ERROR: setof-composite-returning Perl function must call return_next with reference to hash
+ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
return [
{y => 3, z => 4}
diff --git a/src/pl/plperl/nls.mk b/src/pl/plperl/nls.mk
index 0064ff8d4f..84891d2f53 100644
--- a/src/pl/plperl/nls.mk
+++ b/src/pl/plperl/nls.mk
@@ -1,5 +1,5 @@
# $PostgreSQL$
CATALOG_NAME := plperl
AVAIL_LANGUAGES :=
-GETTEXT_FILES := plperl.c SPI.xs
-GETTEXT_TRIGGERS:= _ errmsg errdetail errdetail_log errhint errcontext croak Perl_croak
+GETTEXT_FILES := plperl.c SPI.c
+GETTEXT_TRIGGERS:= errmsg errdetail errdetail_log errhint errcontext
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 5f33ca6e47..2127a2369f 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -199,7 +199,7 @@ _PG_init(void)
pg_bindtextdomain(TEXTDOMAIN);
DefineCustomBoolVariable("plperl.use_strict",
- gettext_noop("If true, will compile trusted and untrusted perl code in strict mode"),
+ gettext_noop("If true, trusted and untrusted Perl code will be compiled in strict mode."),
NULL,
&plperl_use_strict,
false,
@@ -913,7 +913,7 @@ plperl_validator(PG_FUNCTION_ARGS)
proc->prorettype != VOIDOID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plperl functions cannot return type %s",
+ errmsg("PL/Perl functions cannot return type %s",
format_type_be(proc->prorettype))));
}
@@ -925,7 +925,7 @@ plperl_validator(PG_FUNCTION_ARGS)
if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plperl functions cannot take type %s",
+ errmsg("PL/Perl functions cannot accept type %s",
format_type_be(argtypes[i]))));
}
@@ -1280,7 +1280,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("set-returning Perl function must return "
+ errmsg("set-returning PL/Perl function must return "
"reference to array or use return_next")));
}
@@ -1313,7 +1313,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("composite-returning Perl function "
+ errmsg("composite-returning PL/Perl function "
"must return reference to hash")));
}
@@ -1438,7 +1438,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
{
ereport(WARNING,
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
- errmsg("ignoring modified tuple in DELETE trigger")));
+ errmsg("ignoring modified row in DELETE trigger")));
trv = NULL;
}
}
@@ -1446,8 +1446,8 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
- errmsg("result of Perl trigger function must be undef, "
- "\"SKIP\" or \"MODIFY\"")));
+ errmsg("result of PL/Perl trigger function must be undef, "
+ "\"SKIP\", or \"MODIFY\"")));
trv = NULL;
}
retval = PointerGetDatum(trv);
@@ -1612,7 +1612,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
free(prodesc);
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plperl functions cannot return type %s",
+ errmsg("PL/Perl functions cannot return type %s",
format_type_be(procStruct->prorettype))));
}
}
@@ -1659,7 +1659,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
free(prodesc);
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plperl functions cannot take type %s",
+ errmsg("PL/Perl functions cannot accept type %s",
format_type_be(procStruct->proargtypes.values[i]))));
}
@@ -1902,7 +1902,7 @@ plperl_return_next(SV *sv)
!(SvOK(sv) && SvTYPE(sv) == SVt_RV && SvTYPE(SvRV(sv)) == SVt_PVHV))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("setof-composite-returning Perl function "
+ errmsg("SETOF-composite-returning PL/Perl function "
"must call return_next with reference to hash")));
if (!current_call_data->ret_tdesc)
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 5599a4bd90..b8815c5dd1 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -1043,7 +1043,7 @@ for_control :
if ($2.scalar && $2.row)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("cursor FOR loop must have just one target variable")));
+ errmsg("cursor FOR loop must have only one target variable")));
/* create loop's private RECORD variable */
plpgsql_convert_ident($2.name, &varname, 1);
@@ -1131,7 +1131,7 @@ for_control :
if ($2.scalar && $2.row)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("integer FOR loop must have just one target variable")));
+ errmsg("integer FOR loop must have only one target variable")));
/* create loop's private variable */
plpgsql_convert_ident($2.name, &varname, 1);
@@ -1570,7 +1570,7 @@ stmt_open : K_OPEN lno cursor_variable
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error at \"%s\"",
yytext),
- errdetail("Expected FOR to open a reference cursor.")));
+ errdetail("Expected \"FOR\", to open a reference cursor.")));
}
tok = yylex();
@@ -1664,7 +1664,7 @@ cursor_variable : T_SCALAR
plpgsql_error_lineno = plpgsql_scanner_lineno();
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("\"%s\" must be of type cursor or refcursor",
+ errmsg("variable \"%s\" must be of type cursor or refcursor",
((PLpgSQL_var *) yylval.scalar)->refname)));
}
$$ = (PLpgSQL_var *) yylval.scalar;
@@ -2094,7 +2094,7 @@ read_datatype(int tok)
if (parenlevel != 0)
yyerror("mismatched parentheses");
else
- yyerror("incomplete datatype declaration");
+ yyerror("incomplete data type declaration");
}
/* Possible followers for datatype in a declaration */
if (tok == K_NOT || tok == K_ASSIGN || tok == K_DEFAULT)
@@ -2119,7 +2119,7 @@ read_datatype(int tok)
type_name = plpgsql_dstring_get(&ds);
if (type_name[0] == '\0')
- yyerror("missing datatype declaration");
+ yyerror("missing data type declaration");
plpgsql_error_lineno = lno; /* in case of error in parse_datatype */
@@ -2375,11 +2375,11 @@ make_return_stmt(int lineno)
break;
default:
- yyerror("RETURN must specify a record or row variable in function returning tuple");
+ yyerror("RETURN must specify a record or row variable in function returning row");
break;
}
if (yylex() != ';')
- yyerror("RETURN must specify a record or row variable in function returning tuple");
+ yyerror("RETURN must specify a record or row variable in function returning row");
}
else
{
@@ -2428,11 +2428,11 @@ make_return_next_stmt(int lineno)
break;
default:
- yyerror("RETURN NEXT must specify a record or row variable in function returning tuple");
+ yyerror("RETURN NEXT must specify a record or row variable in function returning row");
break;
}
if (yylex() != ';')
- yyerror("RETURN NEXT must specify a record or row variable in function returning tuple");
+ yyerror("RETURN NEXT must specify a record or row variable in function returning row");
}
else
new->expr = plpgsql_read_expression(';', ";");
@@ -2745,7 +2745,7 @@ check_label(const char *yytxt)
plpgsql_convert_ident(yytxt, &label_name, 1);
if (plpgsql_ns_lookup_label(label_name) == NULL)
- yyerror("no such label");
+ yyerror("label does not exist");
return label_name;
}
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 768daf98f1..9f9d30eb3f 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -415,7 +415,7 @@ do_compile(FunctionCallInfo fcinfo,
argdtype->ttype != PLPGSQL_TTYPE_ROW)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plpgsql functions cannot take type %s",
+ errmsg("PL/pgSQL functions cannot accept type %s",
format_type_be(argtypeid))));
/* Build variable and add to datum list */
@@ -534,7 +534,7 @@ do_compile(FunctionCallInfo fcinfo,
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plpgsql functions cannot return type %s",
+ errmsg("PL/pgSQL functions cannot return type %s",
format_type_be(rettypeid))));
}
@@ -576,7 +576,7 @@ do_compile(FunctionCallInfo fcinfo,
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("trigger functions cannot have declared arguments"),
- errhint("You probably want to use TG_NARGS and TG_ARGV instead.")));
+ errhint("The arguments of the trigger can be accessed through TG_NARGS and TG_ARGV instead.")));
/* Add the record for referencing NEW */
rec = plpgsql_build_record("new", 0, true);
@@ -766,7 +766,7 @@ plpgsql_compile_error_callback(void *arg)
}
if (plpgsql_error_funcname)
- errcontext("compile of PL/pgSQL function \"%s\" near line %d",
+ errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
plpgsql_error_funcname, plpgsql_error_lineno);
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 21e76020cc..538efc6e30 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -706,7 +706,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
{
validate_tupdesc_compat(trigdata->tg_relation->rd_att,
estate.rettupdesc,
- "returned tuple structure does not match table of trigger event");
+ "returned row structure does not match the structure of the triggering table");
/* Copy tuple to upper executor memory */
rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval));
}
@@ -765,24 +765,18 @@ plpgsql_exec_error_callback(void *arg)
*/
if (estate->err_stmt != NULL)
{
- /*
- * translator: last %s is a phrase such as "during statement block
- * local variable initialization"
- */
+ /* translator: last %s is a phrase such as "during statement block local variable initialization" */
errcontext("PL/pgSQL function \"%s\" line %d %s",
estate->err_func->fn_name,
estate->err_stmt->lineno,
- gettext(estate->err_text));
+ _(estate->err_text));
}
else
{
- /*
- * translator: last %s is a phrase such as "while storing call
- * arguments into local variables"
- */
+ /* translator: last %s is a phrase such as "while storing call arguments into local variables" */
errcontext("PL/pgSQL function \"%s\" %s",
estate->err_func->fn_name,
- gettext(estate->err_text));
+ _(estate->err_text));
}
}
else if (estate->err_stmt != NULL)
@@ -1677,7 +1671,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("lower bound of FOR loop cannot be NULL")));
+ errmsg("lower bound of FOR loop cannot be null")));
loop_value = DatumGetInt32(value);
exec_eval_cleanup(estate);
@@ -1692,7 +1686,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("upper bound of FOR loop cannot be NULL")));
+ errmsg("upper bound of FOR loop cannot be null")));
end_value = DatumGetInt32(value);
exec_eval_cleanup(estate);
@@ -1709,7 +1703,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("BY value of FOR loop cannot be NULL")));
+ errmsg("BY value of FOR loop cannot be null")));
step_value = DatumGetInt32(value);
exec_eval_cleanup(estate);
if (step_value <= 0)
@@ -2470,7 +2464,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
if (optionisnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("RAISE statement option cannot be NULL")));
+ errmsg("RAISE statement option cannot be null")));
extval = convert_value_to_string(optionvalue, optiontypeid);
@@ -2916,7 +2910,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("cannot EXECUTE a null querystring")));
+ errmsg("query string argument of EXECUTE is null")));
/* Get the C-String representation */
querystr = convert_value_to_string(query, restype);
@@ -2981,7 +2975,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
if (*ptr == 'S' || *ptr == 's')
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("EXECUTE of SELECT ... INTO is not implemented yet")));
+ errmsg("EXECUTE of SELECT ... INTO is not implemented")));
break;
}
@@ -3166,7 +3160,7 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("cannot EXECUTE a null querystring")));
+ errmsg("query string argument of EXECUTE is null")));
/* Get the C-String representation */
querystr = convert_value_to_string(queryD, restype);
@@ -3300,7 +3294,7 @@ exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
if (curvar->isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("cursor variable \"%s\" is NULL", curvar->refname)));
+ errmsg("cursor variable \"%s\" is null", curvar->refname)));
curname = TextDatumGetCString(curvar->value);
portal = SPI_cursor_find(curname);
@@ -3321,7 +3315,7 @@ exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("relative or absolute cursor position is NULL")));
+ errmsg("relative or absolute cursor position is null")));
exec_eval_cleanup(estate);
}
@@ -3396,7 +3390,7 @@ exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
if (curvar->isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("cursor variable \"%s\" is NULL", curvar->refname)));
+ errmsg("cursor variable \"%s\" is null", curvar->refname)));
curname = TextDatumGetCString(curvar->value);
portal = SPI_cursor_find(curname);
@@ -3463,7 +3457,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
if (*isNull && var->notnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("NULL cannot be assigned to variable \"%s\" declared NOT NULL",
+ errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
var->refname)));
/*
@@ -3720,8 +3714,8 @@ exec_assign_value(PLpgSQL_execstate *estate,
if (nsubscripts >= MAXDIM)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("number of array dimensions exceeds the maximum allowed, %d",
- MAXDIM)));
+ errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
+ nsubscripts, MAXDIM)));
subscripts[nsubscripts++] = arrayelem->subscript;
target = estate->datums[arrayelem->arrayparentno];
} while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
@@ -3757,7 +3751,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
if (subisnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("array subscript in assignment must not be NULL")));
+ errmsg("array subscript in assignment must not be null")));
}
/* Coerce source value to match array element type. */
@@ -5129,7 +5123,7 @@ static void
validate_tupdesc_compat(TupleDesc expected, TupleDesc returned, const char *msg)
{
int i;
- const char *dropped_column_type = gettext_noop("n/a (dropped column)");
+ const char *dropped_column_type = gettext_noop("N/A (dropped column)");
if (!expected || !returned)
ereport(ERROR,
@@ -5402,7 +5396,7 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery,
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("cannot EXECUTE a null querystring")));
+ errmsg("query string argument of EXECUTE is null")));
/* Get the C-String representation */
querystr = convert_value_to_string(query, restype);
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index c91bd6b8d9..c64c22c625 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -356,7 +356,7 @@ plpgsql_ns_rename(char *oldname, char *newname)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("there is no variable \"%s\" in the current block",
+ errmsg("variable \"%s\" does not exist in the current block",
oldname)));
}
@@ -412,7 +412,7 @@ plpgsql_convert_ident(const char *s, char **output, int numidents)
if (*s != '"') /* should not happen if lexer checked */
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("unterminated \" in name: %s", sstart)));
+ errmsg("unterminated \" in identifier: %s", sstart)));
s++;
*cp = '\0';
/* Truncate to NAMEDATALEN */
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 9d21fbdf82..ec8c02d7a1 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -159,7 +159,7 @@ plpgsql_validator(PG_FUNCTION_ARGS)
!IsPolymorphicType(proc->prorettype))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plpgsql functions cannot return type %s",
+ errmsg("PL/pgSQL functions cannot return type %s",
format_type_be(proc->prorettype))));
}
@@ -174,7 +174,7 @@ plpgsql_validator(PG_FUNCTION_ARGS)
if (!IsPolymorphicType(argtypes[i]))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plpgsql functions cannot take type %s",
+ errmsg("PL/pgSQL functions cannot accept type %s",
format_type_be(argtypes[i]))));
}
}
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index b5b0adb16d..99eb934dfc 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -254,7 +254,7 @@ dump { return O_DUMP; }
plpgsql_error_lineno = start_lineno;
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("unterminated comment")));
+ errmsg("unterminated /* comment")));
}
/* ----------
@@ -293,7 +293,7 @@ dump { return O_DUMP; }
plpgsql_error_lineno = start_lineno;
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("unterminated string")));
+ errmsg("unterminated quoted string")));
}
{dolqdelim} {
diff --git a/src/test/regress/expected/numerology.out b/src/test/regress/expected/numerology.out
index d404d9db68..0a2e66e919 100644
--- a/src/test/regress/expected/numerology.out
+++ b/src/test/regress/expected/numerology.out
@@ -92,7 +92,7 @@ SELECT f1 AS two, max(f3) AS max_float, min(f3) as min_float
ORDER BY two, max_float, min_float;
two | max_float | min_float
-----+----------------------+-----------------------
- 1 | 1.2345678901234e+200 | 0
+ 1 | 1.2345678901234e+200 | -0
2 | 0 | -1.2345678901234e+200
(2 rows)
@@ -104,7 +104,7 @@ SELECT f1 AS two, max(f3) AS max_float, min(f3) AS min_float
ORDER BY two, max_float, min_float;
two | max_float | min_float
-----+----------------------+-----------------------
- 1 | 1.2345678901234e+200 | 0
+ 1 | 1.2345678901234e+200 | -0
2 | 0 | -1.2345678901234e+200
(2 rows)
diff --git a/src/test/regress/expected/numerology_1.out b/src/test/regress/expected/numerology_1.out
new file mode 100644
index 0000000000..d404d9db68
--- /dev/null
+++ b/src/test/regress/expected/numerology_1.out
@@ -0,0 +1,136 @@
+--
+-- NUMEROLOGY
+-- Test various combinations of numeric types and functions.
+--
+--
+-- Test implicit type conversions
+-- This fails for Postgres v6.1 (and earlier?)
+-- so let's try explicit conversions for now - tgl 97/05/07
+--
+CREATE TABLE TEMP_FLOAT (f1 FLOAT8);
+INSERT INTO TEMP_FLOAT (f1)
+ SELECT float8(f1) FROM INT4_TBL;
+INSERT INTO TEMP_FLOAT (f1)
+ SELECT float8(f1) FROM INT2_TBL;
+SELECT '' AS ten, f1 FROM TEMP_FLOAT
+ ORDER BY f1;
+ ten | f1
+-----+-------------
+ | -2147483647
+ | -123456
+ | -32767
+ | -1234
+ | 0
+ | 0
+ | 1234
+ | 32767
+ | 123456
+ | 2147483647
+(10 rows)
+
+-- int4
+CREATE TABLE TEMP_INT4 (f1 INT4);
+INSERT INTO TEMP_INT4 (f1)
+ SELECT int4(f1) FROM FLOAT8_TBL
+ WHERE (f1 > -2147483647) AND (f1 < 2147483647);
+INSERT INTO TEMP_INT4 (f1)
+ SELECT int4(f1) FROM INT2_TBL;
+SELECT '' AS nine, f1 FROM TEMP_INT4
+ ORDER BY f1;
+ nine | f1
+------+--------
+ | -32767
+ | -1234
+ | -1004
+ | -35
+ | 0
+ | 0
+ | 0
+ | 1234
+ | 32767
+(9 rows)
+
+-- int2
+CREATE TABLE TEMP_INT2 (f1 INT2);
+INSERT INTO TEMP_INT2 (f1)
+ SELECT int2(f1) FROM FLOAT8_TBL
+ WHERE (f1 >= -32767) AND (f1 <= 32767);
+INSERT INTO TEMP_INT2 (f1)
+ SELECT int2(f1) FROM INT4_TBL
+ WHERE (f1 >= -32767) AND (f1 <= 32767);
+SELECT '' AS five, f1 FROM TEMP_INT2
+ ORDER BY f1;
+ five | f1
+------+-------
+ | -1004
+ | -35
+ | 0
+ | 0
+ | 0
+(5 rows)
+
+--
+-- Group-by combinations
+--
+CREATE TABLE TEMP_GROUP (f1 INT4, f2 INT4, f3 FLOAT8);
+INSERT INTO TEMP_GROUP
+ SELECT 1, (- i.f1), (- f.f1)
+ FROM INT4_TBL i, FLOAT8_TBL f;
+INSERT INTO TEMP_GROUP
+ SELECT 2, i.f1, f.f1
+ FROM INT4_TBL i, FLOAT8_TBL f;
+SELECT DISTINCT f1 AS two FROM TEMP_GROUP ORDER BY 1;
+ two
+-----
+ 1
+ 2
+(2 rows)
+
+SELECT f1 AS two, max(f3) AS max_float, min(f3) as min_float
+ FROM TEMP_GROUP
+ GROUP BY f1
+ ORDER BY two, max_float, min_float;
+ two | max_float | min_float
+-----+----------------------+-----------------------
+ 1 | 1.2345678901234e+200 | 0
+ 2 | 0 | -1.2345678901234e+200
+(2 rows)
+
+-- GROUP BY a result column name is not legal per SQL92, but we accept it
+-- anyway (if the name is not the name of any column exposed by FROM).
+SELECT f1 AS two, max(f3) AS max_float, min(f3) AS min_float
+ FROM TEMP_GROUP
+ GROUP BY two
+ ORDER BY two, max_float, min_float;
+ two | max_float | min_float
+-----+----------------------+-----------------------
+ 1 | 1.2345678901234e+200 | 0
+ 2 | 0 | -1.2345678901234e+200
+(2 rows)
+
+SELECT f1 AS two, (max(f3) + 1) AS max_plus_1, (min(f3) - 1) AS min_minus_1
+ FROM TEMP_GROUP
+ GROUP BY f1
+ ORDER BY two, min_minus_1;
+ two | max_plus_1 | min_minus_1
+-----+----------------------+-----------------------
+ 1 | 1.2345678901234e+200 | -1
+ 2 | 1 | -1.2345678901234e+200
+(2 rows)
+
+SELECT f1 AS two,
+ max(f2) + min(f2) AS max_plus_min,
+ min(f3) - 1 AS min_minus_1
+ FROM TEMP_GROUP
+ GROUP BY f1
+ ORDER BY two, min_minus_1;
+ two | max_plus_min | min_minus_1
+-----+--------------+-----------------------
+ 1 | 0 | -1
+ 2 | 0 | -1.2345678901234e+200
+(2 rows)
+
+DROP TABLE TEMP_INT2;
+DROP TABLE TEMP_INT4;
+DROP TABLE TEMP_FLOAT;
+DROP TABLE TEMP_GROUP;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 0fe279493f..66bd895f70 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2700,7 +2700,7 @@ begin
end loop flbl1;
end;
$$ language plpgsql;
-ERROR: no such label at or near "flbl1"
+ERROR: label does not exist at or near "flbl1"
LINE 5: end loop flbl1;
^
-- should fail: end label does not match start label
@@ -2714,7 +2714,7 @@ begin
end;
$$ language plpgsql;
ERROR: end label "outer_label" differs from block's label "inner_label"
-CONTEXT: compile of PL/pgSQL function "end_label3" near line 6
+CONTEXT: compilation of PL/pgSQL function "end_label3" near line 6
-- should fail: end label on a block without a start label
create function end_label4() returns void as $$
<<outer_label>>
@@ -2725,7 +2725,7 @@ begin
end;
$$ language plpgsql;
ERROR: end label "outer_label" specified for unlabelled block
-CONTEXT: compile of PL/pgSQL function "end_label4" near line 5
+CONTEXT: compilation of PL/pgSQL function "end_label4" near line 5
-- using list of scalars in fori and fore stmts
create function for_vect() returns void as $proc$
<<lbl>>declare a integer; b varchar; c varchar; r record;
@@ -3266,7 +3266,7 @@ begin
end;
$$ language plpgsql;
ERROR: cursor FOR loop must use a bound cursor variable
-CONTEXT: compile of PL/pgSQL function "forc_bad" near line 4
+CONTEXT: compilation of PL/pgSQL function "forc_bad" near line 4
-- test RETURN QUERY EXECUTE
create or replace function return_dquery()
returns setof int as $$