@@ -68,6 +68,7 @@ typedef struct SeqTableData
68
68
{
69
69
struct SeqTableData * next ; /* link to next SeqTable object */
70
70
Oid relid ; /* pg_class OID of this sequence */
71
+ Oid filenode ; /* last seen relfilenode of this sequence */
71
72
LocalTransactionId lxid ; /* xact in which we last did a seq op */
72
73
bool last_valid ; /* do we have a valid "last" value? */
73
74
int64 last ; /* value last returned by nextval */
@@ -87,6 +88,7 @@ static SeqTable seqtab = NULL; /* Head of list of SeqTable items */
87
88
*/
88
89
static SeqTableData * last_used_seq = NULL ;
89
90
91
+ static void fill_seq_with_data (Relation rel , HeapTuple tuple );
90
92
static int64 nextval_internal (Oid relid );
91
93
static Relation open_share_lock (SeqTable seq );
92
94
static void init_sequence (Oid relid , SeqTable * p_elm , Relation * p_rel );
@@ -109,9 +111,6 @@ DefineSequence(CreateSeqStmt *seq)
109
111
CreateStmt * stmt = makeNode (CreateStmt );
110
112
Oid seqoid ;
111
113
Relation rel ;
112
- Buffer buf ;
113
- Page page ;
114
- sequence_magic * sm ;
115
114
HeapTuple tuple ;
116
115
TupleDesc tupDesc ;
117
116
Datum value [SEQ_COL_LASTCOL ];
@@ -211,6 +210,100 @@ DefineSequence(CreateSeqStmt *seq)
211
210
rel = heap_open (seqoid , AccessExclusiveLock );
212
211
tupDesc = RelationGetDescr (rel );
213
212
213
+ /* now initialize the sequence's data */
214
+ tuple = heap_form_tuple (tupDesc , value , null );
215
+ fill_seq_with_data (rel , tuple );
216
+
217
+ /* process OWNED BY if given */
218
+ if (owned_by )
219
+ process_owned_by (rel , owned_by );
220
+
221
+ heap_close (rel , NoLock );
222
+ }
223
+
224
+ /*
225
+ * Reset a sequence to its initial value.
226
+ *
227
+ * The change is made transactionally, so that on failure of the current
228
+ * transaction, the sequence will be restored to its previous state.
229
+ * We do that by creating a whole new relfilenode for the sequence; so this
230
+ * works much like the rewriting forms of ALTER TABLE.
231
+ *
232
+ * Caller is assumed to have acquired AccessExclusiveLock on the sequence,
233
+ * which must not be released until end of transaction. Caller is also
234
+ * responsible for permissions checking.
235
+ */
236
+ void
237
+ ResetSequence (Oid seq_relid )
238
+ {
239
+ Relation seq_rel ;
240
+ SeqTable elm ;
241
+ Form_pg_sequence seq ;
242
+ Buffer buf ;
243
+ Page page ;
244
+ HeapTuple tuple ;
245
+ HeapTupleData tupledata ;
246
+ ItemId lp ;
247
+
248
+ /*
249
+ * Read the old sequence. This does a bit more work than really
250
+ * necessary, but it's simple, and we do want to double-check that it's
251
+ * indeed a sequence.
252
+ */
253
+ init_sequence (seq_relid , & elm , & seq_rel );
254
+ seq = read_info (elm , seq_rel , & buf );
255
+
256
+ /*
257
+ * Copy the existing sequence tuple.
258
+ */
259
+ page = BufferGetPage (buf );
260
+ lp = PageGetItemId (page , FirstOffsetNumber );
261
+ Assert (ItemIdIsNormal (lp ));
262
+
263
+ tupledata .t_data = (HeapTupleHeader ) PageGetItem (page , lp );
264
+ tupledata .t_len = ItemIdGetLength (lp );
265
+ tuple = heap_copytuple (& tupledata );
266
+
267
+ /* Now we're done with the old page */
268
+ UnlockReleaseBuffer (buf );
269
+
270
+ /*
271
+ * Modify the copied tuple to execute the restart (compare the RESTART
272
+ * action in AlterSequence)
273
+ */
274
+ seq = (Form_pg_sequence ) GETSTRUCT (tuple );
275
+ seq -> last_value = seq -> start_value ;
276
+ seq -> is_called = false;
277
+ seq -> log_cnt = 1 ;
278
+
279
+ /*
280
+ * Create a new storage file for the sequence. We want to keep the
281
+ * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs.
282
+ */
283
+ RelationSetNewRelfilenode (seq_rel , InvalidTransactionId );
284
+
285
+ /*
286
+ * Insert the modified tuple into the new storage file.
287
+ */
288
+ fill_seq_with_data (seq_rel , tuple );
289
+
290
+ /* Clear local cache so that we don't think we have cached numbers */
291
+ /* Note that we do not change the currval() state */
292
+ elm -> cached = elm -> last ;
293
+
294
+ relation_close (seq_rel , NoLock );
295
+ }
296
+
297
+ /*
298
+ * Initialize a sequence's relation with the specified tuple as content
299
+ */
300
+ static void
301
+ fill_seq_with_data (Relation rel , HeapTuple tuple )
302
+ {
303
+ Buffer buf ;
304
+ Page page ;
305
+ sequence_magic * sm ;
306
+
214
307
/* Initialize first page of relation with special magic number */
215
308
216
309
buf = ReadBuffer (rel , P_NEW );
@@ -225,8 +318,7 @@ DefineSequence(CreateSeqStmt *seq)
225
318
/* hack: ensure heap_insert will insert on the just-created page */
226
319
RelationSetTargetBlock (rel , 0 );
227
320
228
- /* Now form & insert sequence tuple */
229
- tuple = heap_form_tuple (tupDesc , value , null );
321
+ /* Now insert sequence tuple */
230
322
simple_heap_insert (rel , tuple );
231
323
232
324
Assert (ItemPointerGetOffsetNumber (& (tuple -> t_self )) == FirstOffsetNumber );
@@ -306,12 +398,6 @@ DefineSequence(CreateSeqStmt *seq)
306
398
END_CRIT_SECTION ();
307
399
308
400
UnlockReleaseBuffer (buf );
309
-
310
- /* process OWNED BY if given */
311
- if (owned_by )
312
- process_owned_by (rel , owned_by );
313
-
314
- heap_close (rel , NoLock );
315
401
}
316
402
317
403
/*
@@ -323,29 +409,6 @@ void
323
409
AlterSequence (AlterSeqStmt * stmt )
324
410
{
325
411
Oid relid ;
326
-
327
- /* find sequence */
328
- relid = RangeVarGetRelid (stmt -> sequence , false);
329
-
330
- /* allow ALTER to sequence owner only */
331
- /* if you change this, see also callers of AlterSequenceInternal! */
332
- if (!pg_class_ownercheck (relid , GetUserId ()))
333
- aclcheck_error (ACLCHECK_NOT_OWNER , ACL_KIND_CLASS ,
334
- stmt -> sequence -> relname );
335
-
336
- /* do the work */
337
- AlterSequenceInternal (relid , stmt -> options );
338
- }
339
-
340
- /*
341
- * AlterSequenceInternal
342
- *
343
- * Same as AlterSequence except that the sequence is specified by OID
344
- * and we assume the caller already checked permissions.
345
- */
346
- void
347
- AlterSequenceInternal (Oid relid , List * options )
348
- {
349
412
SeqTable elm ;
350
413
Relation seqrel ;
351
414
Buffer buf ;
@@ -355,8 +418,14 @@ AlterSequenceInternal(Oid relid, List *options)
355
418
List * owned_by ;
356
419
357
420
/* open and AccessShareLock sequence */
421
+ relid = RangeVarGetRelid (stmt -> sequence , false);
358
422
init_sequence (relid , & elm , & seqrel );
359
423
424
+ /* allow ALTER to sequence owner only */
425
+ if (!pg_class_ownercheck (relid , GetUserId ()))
426
+ aclcheck_error (ACLCHECK_NOT_OWNER , ACL_KIND_CLASS ,
427
+ stmt -> sequence -> relname );
428
+
360
429
/* lock page' buffer and read tuple into new sequence structure */
361
430
seq = read_info (elm , seqrel , & buf );
362
431
page = BufferGetPage (buf );
@@ -365,7 +434,7 @@ AlterSequenceInternal(Oid relid, List *options)
365
434
memcpy (& new , seq , sizeof (FormData_pg_sequence ));
366
435
367
436
/* Check and set new values */
368
- init_params (options , false, & new , & owned_by );
437
+ init_params (stmt -> options , false, & new , & owned_by );
369
438
370
439
/* Clear local cache so that we don't think we have cached numbers */
371
440
/* Note that we do not change the currval() state */
@@ -937,6 +1006,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
937
1006
(errcode (ERRCODE_OUT_OF_MEMORY ),
938
1007
errmsg ("out of memory" )));
939
1008
elm -> relid = relid ;
1009
+ elm -> filenode = InvalidOid ;
940
1010
elm -> lxid = InvalidLocalTransactionId ;
941
1011
elm -> last_valid = false;
942
1012
elm -> last = elm -> cached = elm -> increment = 0 ;
@@ -955,6 +1025,18 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
955
1025
errmsg ("\"%s\" is not a sequence" ,
956
1026
RelationGetRelationName (seqrel ))));
957
1027
1028
+ /*
1029
+ * If the sequence has been transactionally replaced since we last saw it,
1030
+ * discard any cached-but-unissued values. We do not touch the currval()
1031
+ * state, however.
1032
+ */
1033
+ if (seqrel -> rd_rel -> relfilenode != elm -> filenode )
1034
+ {
1035
+ elm -> filenode = seqrel -> rd_rel -> relfilenode ;
1036
+ elm -> cached = elm -> last ;
1037
+ }
1038
+
1039
+ /* Return results */
958
1040
* p_elm = elm ;
959
1041
* p_rel = seqrel ;
960
1042
}
0 commit comments