aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/variable.c13
-rw-r--r--src/backend/storage/lmgr/predicate.c13
-rw-r--r--src/backend/utils/init/postinit.c9
3 files changed, 33 insertions, 2 deletions
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 8550869db3d..3eb911c5cc5 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -569,11 +569,16 @@ show_log_timezone(void)
* read-only may be changed to read-write only when in a top-level transaction
* that has not yet taken an initial snapshot. Can't do it in a hot standby
* slave, either.
+ *
+ * If we are not in a transaction at all, just allow the change; it means
+ * nothing since XactReadOnly will be reset by the next StartTransaction().
+ * The IsTransactionState() test protects us against trying to check
+ * RecoveryInProgress() in contexts where shared memory is not accessible.
*/
bool
check_transaction_read_only(bool *newval, void **extra, GucSource source)
{
- if (*newval == false && XactReadOnly)
+ if (*newval == false && XactReadOnly && IsTransactionState())
{
/* Can't go to r/w mode inside a r/o transaction */
if (IsSubTransaction())
@@ -592,6 +597,7 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
/* Can't go to r/w mode while recovery is still active */
if (RecoveryInProgress())
{
+ GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
GUC_check_errmsg("cannot set transaction read-write mode during recovery");
return false;
}
@@ -605,6 +611,8 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
*
* We allow idempotent changes at any time, but otherwise this can only be
* changed in a toplevel transaction that has not yet taken a snapshot.
+ *
+ * As in check_transaction_read_only, allow it if not inside a transaction.
*/
bool
check_XactIsoLevel(char **newval, void **extra, GucSource source)
@@ -634,7 +642,7 @@ check_XactIsoLevel(char **newval, void **extra, GucSource source)
else
return false;
- if (newXactIsoLevel != XactIsoLevel)
+ if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
{
if (FirstSnapshotSet)
{
@@ -652,6 +660,7 @@ check_XactIsoLevel(char **newval, void **extra, GucSource source)
/* Can't go to serializable mode while recovery is still active */
if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
{
+ GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
GUC_check_errmsg("cannot use serializable mode in a hot standby");
GUC_check_errhint("You can use REPEATABLE READ instead.");
return false;
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 532dedf959b..56f5fb31fee 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1559,6 +1559,19 @@ RegisterSerializableTransaction(Snapshot snapshot)
Assert(IsolationIsSerializable());
/*
+ * Can't use serializable mode while recovery is still active, as it is,
+ * for example, on a hot standby. We could get here despite the check
+ * in check_XactIsoLevel() if default_transaction_isolation is set to
+ * serializable, so phrase the hint accordingly.
+ */
+ if (RecoveryInProgress())
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot use serializable mode in a hot standby"),
+ errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
+ errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
+
+ /*
* A special optimization is available for SERIALIZABLE READ ONLY
* DEFERRABLE transactions -- we can wait for a suitable snapshot and
* thereby avoid all SSI overhead once it's running..
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 94f92dd7343..dfe338c2bfe 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -574,6 +574,15 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/* statement_timestamp must be set for timeouts to work correctly */
SetCurrentStatementStartTimestamp();
StartTransactionCommand();
+
+ /*
+ * transaction_isolation will have been set to the default by the
+ * above. If the default is "serializable", and we are in hot
+ * standby, we will fail if we don't change it to something lower.
+ * Fortunately, "read committed" is plenty good enough.
+ */
+ XactIsoLevel = XACT_READ_COMMITTED;
+
(void) GetTransactionSnapshot();
}