@@ -101,7 +101,9 @@ static Form_pg_sequence_data read_seq_tuple(Relation rel,
101
101
static void init_params (ParseState * pstate , List * options , bool for_identity ,
102
102
bool isInit ,
103
103
Form_pg_sequence seqform ,
104
- Form_pg_sequence_data seqdataform , List * * owned_by );
104
+ Form_pg_sequence_data seqdataform ,
105
+ bool * need_seq_rewrite ,
106
+ List * * owned_by );
105
107
static void do_setval (Oid relid , int64 next , bool iscalled );
106
108
static void process_owned_by (Relation seqrel , List * owned_by , bool for_identity );
107
109
@@ -115,6 +117,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
115
117
{
116
118
FormData_pg_sequence seqform ;
117
119
FormData_pg_sequence_data seqdataform ;
120
+ bool need_seq_rewrite ;
118
121
List * owned_by ;
119
122
CreateStmt * stmt = makeNode (CreateStmt );
120
123
Oid seqoid ;
@@ -153,7 +156,9 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
153
156
}
154
157
155
158
/* Check and set all option values */
156
- init_params (pstate , seq -> options , seq -> for_identity , true, & seqform , & seqdataform , & owned_by );
159
+ init_params (pstate , seq -> options , seq -> for_identity , true,
160
+ & seqform , & seqdataform ,
161
+ & need_seq_rewrite , & owned_by );
157
162
158
163
/*
159
164
* Create relation (and fill value[] and null[] for the tuple)
@@ -417,6 +422,7 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
417
422
HeapTupleData datatuple ;
418
423
Form_pg_sequence seqform ;
419
424
Form_pg_sequence_data newdataform ;
425
+ bool need_seq_rewrite ;
420
426
List * owned_by ;
421
427
ObjectAddress address ;
422
428
Relation rel ;
@@ -461,35 +467,41 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
461
467
UnlockReleaseBuffer (buf );
462
468
463
469
/* Check and set new values */
464
- init_params (pstate , stmt -> options , stmt -> for_identity , false, seqform ,
465
- newdataform , & owned_by );
470
+ init_params (pstate , stmt -> options , stmt -> for_identity , false,
471
+ seqform , newdataform ,
472
+ & need_seq_rewrite , & owned_by );
466
473
467
474
/* Clear local cache so that we don't think we have cached numbers */
468
475
/* Note that we do not change the currval() state */
469
476
elm -> cached = elm -> last ;
470
477
471
- /* check the comment above nextval_internal()'s equivalent call. */
472
- if (RelationNeedsWAL (seqrel ))
473
- GetTopTransactionId ();
478
+ /* If needed, rewrite the sequence relation itself */
479
+ if (need_seq_rewrite )
480
+ {
481
+ /* check the comment above nextval_internal()'s equivalent call. */
482
+ if (RelationNeedsWAL (seqrel ))
483
+ GetTopTransactionId ();
474
484
475
- /*
476
- * Create a new storage file for the sequence, making the state changes
477
- * transactional. We want to keep the sequence's relfrozenxid at 0, since
478
- * it won't contain any unfrozen XIDs. Same with relminmxid, since a
479
- * sequence will never contain multixacts.
480
- */
481
- RelationSetNewRelfilenode (seqrel , seqrel -> rd_rel -> relpersistence ,
482
- InvalidTransactionId , InvalidMultiXactId );
485
+ /*
486
+ * Create a new storage file for the sequence, making the state
487
+ * changes transactional. We want to keep the sequence's relfrozenxid
488
+ * at 0, since it won't contain any unfrozen XIDs. Same with
489
+ * relminmxid, since a sequence will never contain multixacts.
490
+ */
491
+ RelationSetNewRelfilenode (seqrel , seqrel -> rd_rel -> relpersistence ,
492
+ InvalidTransactionId , InvalidMultiXactId );
483
493
484
- /*
485
- * Insert the modified tuple into the new storage file.
486
- */
487
- fill_seq_with_data (seqrel , newdatatuple );
494
+ /*
495
+ * Insert the modified tuple into the new storage file.
496
+ */
497
+ fill_seq_with_data (seqrel , newdatatuple );
498
+ }
488
499
489
500
/* process OWNED BY if given */
490
501
if (owned_by )
491
502
process_owned_by (seqrel , owned_by , stmt -> for_identity );
492
503
504
+ /* update the pg_sequence tuple (we could skip this in some cases...) */
493
505
CatalogTupleUpdate (rel , & seqtuple -> t_self , seqtuple );
494
506
495
507
InvokeObjectPostAlterHook (RelationRelationId , relid , 0 );
@@ -1204,19 +1216,28 @@ read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
1204
1216
/*
1205
1217
* init_params: process the options list of CREATE or ALTER SEQUENCE, and
1206
1218
* store the values into appropriate fields of seqform, for changes that go
1207
- * into the pg_sequence catalog, and seqdataform for changes to the sequence
1208
- * relation itself. Set *changed_seqform to true if seqform was changed
1209
- * (interesting for ALTER SEQUENCE). Also set *owned_by to any OWNED BY
1210
- * option, or to NIL if there is none.
1219
+ * into the pg_sequence catalog, and fields of seqdataform for changes to the
1220
+ * sequence relation itself. Set *need_seq_rewrite to true if we changed any
1221
+ * parameters that require rewriting the sequence's relation (interesting for
1222
+ * ALTER SEQUENCE). Also set *owned_by to any OWNED BY option, or to NIL if
1223
+ * there is none.
1211
1224
*
1212
1225
* If isInit is true, fill any unspecified options with default values;
1213
1226
* otherwise, do not change existing options that aren't explicitly overridden.
1227
+ *
1228
+ * Note: we force a sequence rewrite whenever we change parameters that affect
1229
+ * generation of future sequence values, even if the seqdataform per se is not
1230
+ * changed. This allows ALTER SEQUENCE to behave transactionally. Currently,
1231
+ * the only option that doesn't cause that is OWNED BY. It's *necessary* for
1232
+ * ALTER SEQUENCE OWNED BY to not rewrite the sequence, because that would
1233
+ * break pg_upgrade by causing unwanted changes in the sequence's relfilenode.
1214
1234
*/
1215
1235
static void
1216
1236
init_params (ParseState * pstate , List * options , bool for_identity ,
1217
1237
bool isInit ,
1218
1238
Form_pg_sequence seqform ,
1219
1239
Form_pg_sequence_data seqdataform ,
1240
+ bool * need_seq_rewrite ,
1220
1241
List * * owned_by )
1221
1242
{
1222
1243
DefElem * as_type = NULL ;
@@ -1231,6 +1252,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1231
1252
bool reset_max_value = false;
1232
1253
bool reset_min_value = false;
1233
1254
1255
+ * need_seq_rewrite = false;
1234
1256
* owned_by = NIL ;
1235
1257
1236
1258
foreach (option , options )
@@ -1245,6 +1267,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1245
1267
errmsg ("conflicting or redundant options" ),
1246
1268
parser_errposition (pstate , defel -> location )));
1247
1269
as_type = defel ;
1270
+ * need_seq_rewrite = true;
1248
1271
}
1249
1272
else if (strcmp (defel -> defname , "increment" ) == 0 )
1250
1273
{
@@ -1254,6 +1277,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1254
1277
errmsg ("conflicting or redundant options" ),
1255
1278
parser_errposition (pstate , defel -> location )));
1256
1279
increment_by = defel ;
1280
+ * need_seq_rewrite = true;
1257
1281
}
1258
1282
else if (strcmp (defel -> defname , "start" ) == 0 )
1259
1283
{
@@ -1263,6 +1287,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1263
1287
errmsg ("conflicting or redundant options" ),
1264
1288
parser_errposition (pstate , defel -> location )));
1265
1289
start_value = defel ;
1290
+ * need_seq_rewrite = true;
1266
1291
}
1267
1292
else if (strcmp (defel -> defname , "restart" ) == 0 )
1268
1293
{
@@ -1272,6 +1297,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1272
1297
errmsg ("conflicting or redundant options" ),
1273
1298
parser_errposition (pstate , defel -> location )));
1274
1299
restart_value = defel ;
1300
+ * need_seq_rewrite = true;
1275
1301
}
1276
1302
else if (strcmp (defel -> defname , "maxvalue" ) == 0 )
1277
1303
{
@@ -1281,6 +1307,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1281
1307
errmsg ("conflicting or redundant options" ),
1282
1308
parser_errposition (pstate , defel -> location )));
1283
1309
max_value = defel ;
1310
+ * need_seq_rewrite = true;
1284
1311
}
1285
1312
else if (strcmp (defel -> defname , "minvalue" ) == 0 )
1286
1313
{
@@ -1290,6 +1317,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1290
1317
errmsg ("conflicting or redundant options" ),
1291
1318
parser_errposition (pstate , defel -> location )));
1292
1319
min_value = defel ;
1320
+ * need_seq_rewrite = true;
1293
1321
}
1294
1322
else if (strcmp (defel -> defname , "cache" ) == 0 )
1295
1323
{
@@ -1299,6 +1327,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1299
1327
errmsg ("conflicting or redundant options" ),
1300
1328
parser_errposition (pstate , defel -> location )));
1301
1329
cache_value = defel ;
1330
+ * need_seq_rewrite = true;
1302
1331
}
1303
1332
else if (strcmp (defel -> defname , "cycle" ) == 0 )
1304
1333
{
@@ -1308,6 +1337,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
1308
1337
errmsg ("conflicting or redundant options" ),
1309
1338
parser_errposition (pstate , defel -> location )));
1310
1339
is_cycled = defel ;
1340
+ * need_seq_rewrite = true;
1311
1341
}
1312
1342
else if (strcmp (defel -> defname , "owned_by" ) == 0 )
1313
1343
{
0 commit comments