Skip to content

Commit 3853664

Browse files
committed
Introduce GUC_NO_RESET flag.
Previously, the transaction-property GUCs such as transaction_isolation could be reset after starting a transaction, because we marked them as GUC_NO_RESET_ALL but still allowed a targeted RESET. That leads to assertion failures or worse, because those properties aren't supposed to change after we've acquired a transaction snapshot. There are some NO_RESET_ALL variables for which RESET is okay, so we can't just redefine the semantics of that flag. Instead introduce a separate GUC_NO_RESET flag. Mark "seed", as well as the transaction property GUCs, as GUC_NO_RESET. We have to disallow GUC_ACTION_SAVE as well as straight RESET, because otherwise a function having a "SET transaction_isolation" clause can still break things: the end-of-function restore action is equivalent to a RESET. No back-patch, as it's conceivable that someone is doing something this patch will forbid (like resetting one of these GUCs at transaction start, or "CREATE FUNCTION ... SET transaction_read_only = 1") and not running into problems with it today. Given how long we've had this issue and not noticed, the side effects in non-assert builds can't be too serious. Per bug #17385 from Andrew Bille. Masahiko Sawada Discussion: https://postgr.es/m/17385-9ee529fb091f0ce5@postgresql.org
1 parent 4148c8b commit 3853664

File tree

11 files changed

+103
-13
lines changed

11 files changed

+103
-13
lines changed

doc/src/sgml/func.sgml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24353,6 +24353,12 @@ SELECT collation for ('foo' COLLATE "de_DE");
2435324353
<command>SHOW ALL</command> commands.
2435424354
</entry>
2435524355
</row>
24356+
<row>
24357+
<entry><literal>NO_RESET</literal></entry>
24358+
<entry>Parameters with this flag do not support
24359+
<command>RESET</command> commands.
24360+
</entry>
24361+
</row>
2435624362
<row>
2435724363
<entry><literal>NO_RESET_ALL</literal></entry>
2435824364
<entry>Parameters with this flag are excluded from

src/backend/utils/misc/guc.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,6 +3243,26 @@ set_config_option_ext(const char *name, const char *value,
32433243
}
32443244
}
32453245

3246+
/* Disallow resetting and saving GUC_NO_RESET values */
3247+
if (record->flags & GUC_NO_RESET)
3248+
{
3249+
if (value == NULL)
3250+
{
3251+
ereport(elevel,
3252+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3253+
errmsg("parameter \"%s\" cannot be reset", name)));
3254+
return 0;
3255+
}
3256+
if (action == GUC_ACTION_SAVE)
3257+
{
3258+
ereport(elevel,
3259+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3260+
errmsg("parameter \"%s\" cannot be set locally in functions",
3261+
name)));
3262+
return 0;
3263+
}
3264+
}
3265+
32463266
/*
32473267
* Should we set reset/stacked values? (If so, the behavior is not
32483268
* transactional.) This is done either when we get a default value from

src/backend/utils/misc/guc_funcs.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,6 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
141141
WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
142142
/* fall through */
143143
case VAR_RESET:
144-
if (strcmp(stmt->name, "transaction_isolation") == 0)
145-
WarnNoTransactionBlock(isTopLevel, "RESET TRANSACTION");
146-
147144
(void) set_config_option(stmt->name,
148145
NULL,
149146
(superuser() ? PGC_SUSET : PGC_USERSET),
@@ -539,7 +536,7 @@ ShowAllGUCConfig(DestReceiver *dest)
539536
Datum
540537
pg_settings_get_flags(PG_FUNCTION_ARGS)
541538
{
542-
#define MAX_GUC_FLAGS 5
539+
#define MAX_GUC_FLAGS 6
543540
char *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
544541
struct config_generic *record;
545542
int cnt = 0;
@@ -554,6 +551,8 @@ pg_settings_get_flags(PG_FUNCTION_ARGS)
554551

555552
if (record->flags & GUC_EXPLAIN)
556553
flags[cnt++] = CStringGetTextDatum("EXPLAIN");
554+
if (record->flags & GUC_NO_RESET)
555+
flags[cnt++] = CStringGetTextDatum("NO_RESET");
557556
if (record->flags & GUC_NO_RESET_ALL)
558557
flags[cnt++] = CStringGetTextDatum("NO_RESET_ALL");
559558
if (record->flags & GUC_NO_SHOW_ALL)

src/backend/utils/misc/guc_tables.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,7 +1505,7 @@ struct config_bool ConfigureNamesBool[] =
15051505
{"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
15061506
gettext_noop("Sets the current transaction's read-only status."),
15071507
NULL,
1508-
GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1508+
GUC_NO_RESET | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
15091509
},
15101510
&XactReadOnly,
15111511
false,
@@ -1524,7 +1524,7 @@ struct config_bool ConfigureNamesBool[] =
15241524
{"transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT,
15251525
gettext_noop("Whether to defer a read-only serializable transaction until it can be executed with no possible serialization failures."),
15261526
NULL,
1527-
GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1527+
GUC_NO_RESET | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
15281528
},
15291529
&XactDeferrable,
15301530
false,
@@ -3606,7 +3606,7 @@ struct config_real ConfigureNamesReal[] =
36063606
{"seed", PGC_USERSET, UNGROUPED,
36073607
gettext_noop("Sets the seed for random-number generation."),
36083608
NULL,
3609-
GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3609+
GUC_NO_SHOW_ALL | GUC_NO_RESET | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
36103610
},
36113611
&phony_random_seed,
36123612
0.0, -1.0, 1.0,
@@ -4557,7 +4557,7 @@ struct config_enum ConfigureNamesEnum[] =
45574557
{"transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
45584558
gettext_noop("Sets the current transaction's isolation level."),
45594559
NULL,
4560-
GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
4560+
GUC_NO_RESET | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
45614561
},
45624562
&XactIsoLevel,
45634563
XACT_READ_COMMITTED, isolation_level_options,

src/include/utils/guc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ typedef enum
207207
#define GUC_LIST_INPUT 0x0001 /* input can be list format */
208208
#define GUC_LIST_QUOTE 0x0002 /* double-quote list elements */
209209
#define GUC_NO_SHOW_ALL 0x0004 /* exclude from SHOW ALL */
210+
#define GUC_NO_RESET 0x400000 /* disallow RESET and SAVE */
210211
#define GUC_NO_RESET_ALL 0x0008 /* exclude from RESET ALL */
211212
#define GUC_REPORT 0x0010 /* auto-report changes to client */
212213
#define GUC_NOT_IN_SAMPLE 0x0020 /* not in postgresql.conf.sample */

src/pl/plpgsql/src/expected/plpgsql_transaction.out

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,16 +576,15 @@ BEGIN
576576
PERFORM 1;
577577
RAISE INFO '%', current_setting('transaction_isolation');
578578
COMMIT;
579-
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
580-
RESET TRANSACTION ISOLATION LEVEL;
579+
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
581580
PERFORM 1;
582581
RAISE INFO '%', current_setting('transaction_isolation');
583582
COMMIT;
584583
END;
585584
$$;
586585
INFO: read committed
587586
INFO: repeatable read
588-
INFO: read committed
587+
INFO: serializable
589588
-- error cases
590589
DO LANGUAGE plpgsql $$
591590
BEGIN

src/pl/plpgsql/src/sql/plpgsql_transaction.sql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,8 +481,7 @@ BEGIN
481481
PERFORM 1;
482482
RAISE INFO '%', current_setting('transaction_isolation');
483483
COMMIT;
484-
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
485-
RESET TRANSACTION ISOLATION LEVEL;
484+
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
486485
PERFORM 1;
487486
RAISE INFO '%', current_setting('transaction_isolation');
488487
COMMIT;

src/test/regress/expected/guc.out

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ SELECT pg_settings_get_flags('does_not_exist');
839839

840840
CREATE TABLE tab_settings_flags AS SELECT name, category,
841841
'EXPLAIN' = ANY(flags) AS explain,
842+
'NO_RESET' = ANY(flags) AS no_reset,
842843
'NO_RESET_ALL' = ANY(flags) AS no_reset_all,
843844
'NO_SHOW_ALL' = ANY(flags) AS no_show_all,
844845
'NOT_IN_SAMPLE' = ANY(flags) AS not_in_sample,
@@ -906,4 +907,12 @@ SELECT name FROM tab_settings_flags
906907
------
907908
(0 rows)
908909

910+
-- NO_RESET implies NO_RESET_ALL.
911+
SELECT name FROM tab_settings_flags
912+
WHERE no_reset AND NOT no_reset_all
913+
ORDER BY 1;
914+
name
915+
------
916+
(0 rows)
917+
909918
DROP TABLE tab_settings_flags;

src/test/regress/expected/transactions.out

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,40 @@ SELECT * FROM xacttest;
4444
777 | 777.777
4545
(5 rows)
4646

47+
-- Test that transaction characteristics cannot be reset.
48+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
49+
SELECT COUNT(*) FROM xacttest;
50+
count
51+
-------
52+
5
53+
(1 row)
54+
55+
RESET transaction_isolation; -- error
56+
ERROR: parameter "transaction_isolation" cannot be reset
57+
END;
58+
BEGIN TRANSACTION READ ONLY;
59+
SELECT COUNT(*) FROM xacttest;
60+
count
61+
-------
62+
5
63+
(1 row)
64+
65+
RESET transaction_read_only; -- error
66+
ERROR: parameter "transaction_read_only" cannot be reset
67+
END;
68+
BEGIN TRANSACTION DEFERRABLE;
69+
SELECT COUNT(*) FROM xacttest;
70+
count
71+
-------
72+
5
73+
(1 row)
74+
75+
RESET transaction_deferrable; -- error
76+
ERROR: parameter "transaction_deferrable" cannot be reset
77+
END;
78+
CREATE FUNCTION errfunc() RETURNS int LANGUAGE SQL AS 'SELECT 1'
79+
SET transaction_read_only = on; -- error
80+
ERROR: parameter "transaction_read_only" cannot be set locally in functions
4781
-- Read-only tests
4882
CREATE TABLE writetest (a int);
4983
CREATE TEMPORARY TABLE temptest (a int);

src/test/regress/sql/guc.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ SELECT pg_settings_get_flags(NULL);
324324
SELECT pg_settings_get_flags('does_not_exist');
325325
CREATE TABLE tab_settings_flags AS SELECT name, category,
326326
'EXPLAIN' = ANY(flags) AS explain,
327+
'NO_RESET' = ANY(flags) AS no_reset,
327328
'NO_RESET_ALL' = ANY(flags) AS no_reset_all,
328329
'NO_SHOW_ALL' = ANY(flags) AS no_show_all,
329330
'NOT_IN_SAMPLE' = ANY(flags) AS not_in_sample,
@@ -360,4 +361,8 @@ SELECT name FROM tab_settings_flags
360361
SELECT name FROM tab_settings_flags
361362
WHERE no_show_all AND NOT not_in_sample
362363
ORDER BY 1;
364+
-- NO_RESET implies NO_RESET_ALL.
365+
SELECT name FROM tab_settings_flags
366+
WHERE no_reset AND NOT no_reset_all
367+
ORDER BY 1;
363368
DROP TABLE tab_settings_flags;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy