*** a/src/backend/commands/variable.c --- b/src/backend/commands/variable.c *************** *** 600,616 **** check_XactIsoLevel(char **newval, void **extra, GucSource source) if (newXactIsoLevel != XactIsoLevel) { ! if (FirstSnapshotSet) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query"); return false; } ! /* We ignore a subtransaction setting it to the existing value. */ ! if (IsSubTransaction()) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction"); return false; } /* Can't go to serializable mode while recovery is still active */ --- 600,616 ---- if (newXactIsoLevel != XactIsoLevel) { ! /* We ignore a subtransaction setting it to the existing value. */ ! if (IsSubTransaction()) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("cannot set transaction isolation level in a subtransaction"); return false; } ! if (FirstSnapshotSet) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("transaction isolation level must be set before any query"); return false; } /* Can't go to serializable mode while recovery is still active */ *************** *** 665,677 **** check_transaction_deferrable(bool *newval, void **extra, GucSource source) if (IsSubTransaction()) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction"); return false; } if (FirstSnapshotSet) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query"); return false; } --- 665,677 ---- if (IsSubTransaction()) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("cannot set transaction deferrable state within a subtransaction"); return false; } if (FirstSnapshotSet) { GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION); ! GUC_check_errmsg("transaction deferrable state must be set before any query"); return false; } *** a/src/backend/utils/misc/guc.c --- b/src/backend/utils/misc/guc.c *************** *** 5287,5302 **** set_config_option(const char *name, const char *value, name))); return 0; } - if (!call_bool_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_bool_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else { --- 5287,5296 ---- *************** *** 5306,5311 **** set_config_option(const char *name, const char *value, --- 5300,5309 ---- context = conf->gen.reset_scontext; } + if (!call_bool_check_hook(conf, &newval, &newextra, + source, elevel)) + return 0; + if (prohibitValueChange) { if (*conf->variable != newval) *************** *** 5391,5406 **** set_config_option(const char *name, const char *value, newval, name, conf->min, conf->max))); return 0; } - if (!call_int_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_int_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else { --- 5389,5398 ---- *************** *** 5410,5415 **** set_config_option(const char *name, const char *value, --- 5402,5411 ---- context = conf->gen.reset_scontext; } + if (!call_int_check_hook(conf, &newval, &newextra, + source, elevel)) + return 0; + if (prohibitValueChange) { if (*conf->variable != newval) *************** *** 5492,5507 **** set_config_option(const char *name, const char *value, newval, name, conf->min, conf->max))); return 0; } - if (!call_real_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_real_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else { --- 5488,5497 ---- *************** *** 5511,5516 **** set_config_option(const char *name, const char *value, --- 5501,5510 ---- context = conf->gen.reset_scontext; } + if (!call_real_check_hook(conf, &newval, &newextra, + source, elevel)) + return 0; + if (prohibitValueChange) { if (*conf->variable != newval) *************** *** 5591,5603 **** set_config_option(const char *name, const char *value, */ if (conf->gen.flags & GUC_IS_NAME) truncate_identifier(newval, strlen(newval), true); - - if (!call_string_check_hook(conf, &newval, &newextra, - source, elevel)) - { - free(newval); - return 0; - } } else if (source == PGC_S_DEFAULT) { --- 5585,5590 ---- *************** *** 5610,5635 **** set_config_option(const char *name, const char *value, } else newval = NULL; - - if (!call_string_check_hook(conf, &newval, &newextra, - source, elevel)) - { - free(newval); - return 0; - } } else { ! /* ! * strdup not needed, since reset_val is already under ! * guc.c's control ! */ ! newval = conf->reset_val; newextra = conf->reset_extra; source = conf->gen.reset_source; context = conf->gen.reset_scontext; } if (prohibitValueChange) { /* newval shouldn't be NULL, so we're a bit sloppy here */ --- 5597,5626 ---- } else newval = NULL; } else { ! /* non-NULL reset_val must always get strdup'd */ ! if (conf->reset_val != NULL) ! { ! newval = guc_strdup(elevel, conf->reset_val); ! if (newval == NULL) ! return 0; ! } ! else ! newval = NULL; newextra = conf->reset_extra; source = conf->gen.reset_source; context = conf->gen.reset_scontext; } + if (!call_string_check_hook(conf, &newval, &newextra, + source, elevel)) + { + free(newval); + return 0; + } + if (prohibitValueChange) { /* newval shouldn't be NULL, so we're a bit sloppy here */ *************** *** 5721,5736 **** set_config_option(const char *name, const char *value, pfree(hintmsg); return 0; } - if (!call_enum_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_enum_check_hook(conf, &newval, &newextra, - source, elevel)) - return 0; } else { --- 5712,5721 ---- *************** *** 5740,5745 **** set_config_option(const char *name, const char *value, --- 5725,5734 ---- context = conf->gen.reset_scontext; } + if (!call_enum_check_hook(conf, &newval, &newextra, + source, elevel)) + return 0; + if (prohibitValueChange) { if (*conf->variable != newval) *** a/src/test/regress/expected/transactions.out --- b/src/test/regress/expected/transactions.out *************** *** 53,58 **** SELECT * FROM writetest; -- ok --- 53,82 ---- SET TRANSACTION READ WRITE; --fail ERROR: transaction read-write mode must be set before any query COMMIT; + SET default_transaction_read_only = FALSE; + SET default_transaction_isolation = 'read committed'; + BEGIN; + SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY; -- ok + SELECT * FROM writetest; -- ok + a + --- + (0 rows) + + RESET transaction_read_only; --fail + ERROR: transaction read-write mode must be set before any query + COMMIT; + BEGIN; + SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY; -- ok + SELECT * FROM writetest; -- ok + a + --- + (0 rows) + + RESET transaction_isolation; --fail + ERROR: transaction isolation level must be set before any query + COMMIT; + RESET default_transaction_read_only; + RESET default_transaction_isolation; BEGIN; SET TRANSACTION READ ONLY; -- ok SET TRANSACTION READ WRITE; -- ok *** a/src/test/regress/sql/transactions.sql --- b/src/test/regress/sql/transactions.sql *************** *** 45,50 **** SELECT * FROM writetest; -- ok --- 45,68 ---- SET TRANSACTION READ WRITE; --fail COMMIT; + SET default_transaction_read_only = FALSE; + SET default_transaction_isolation = 'read committed'; + + BEGIN; + SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY; -- ok + SELECT * FROM writetest; -- ok + RESET transaction_read_only; --fail + COMMIT; + + BEGIN; + SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY; -- ok + SELECT * FROM writetest; -- ok + RESET transaction_isolation; --fail + COMMIT; + + RESET default_transaction_read_only; + RESET default_transaction_isolation; + BEGIN; SET TRANSACTION READ ONLY; -- ok SET TRANSACTION READ WRITE; -- ok