diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/variable.c | 13 | ||||
-rw-r--r-- | src/backend/storage/lmgr/predicate.c | 13 | ||||
-rw-r--r-- | src/backend/utils/init/postinit.c | 9 |
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(); } |