Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * sequence.c
4 : * PostgreSQL sequences support code.
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/commands/sequence.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/bufmask.h"
18 : #include "access/htup_details.h"
19 : #include "access/multixact.h"
20 : #include "access/transam.h"
21 : #include "access/xact.h"
22 : #include "access/xlog.h"
23 : #include "access/xloginsert.h"
24 : #include "access/xlogutils.h"
25 : #include "catalog/dependency.h"
26 : #include "catalog/indexing.h"
27 : #include "catalog/namespace.h"
28 : #include "catalog/objectaccess.h"
29 : #include "catalog/pg_sequence.h"
30 : #include "catalog/pg_type.h"
31 : #include "commands/defrem.h"
32 : #include "commands/sequence.h"
33 : #include "commands/tablecmds.h"
34 : #include "funcapi.h"
35 : #include "miscadmin.h"
36 : #include "nodes/makefuncs.h"
37 : #include "parser/parse_type.h"
38 : #include "storage/lmgr.h"
39 : #include "storage/proc.h"
40 : #include "storage/smgr.h"
41 : #include "utils/acl.h"
42 : #include "utils/builtins.h"
43 : #include "utils/lsyscache.h"
44 : #include "utils/resowner.h"
45 : #include "utils/syscache.h"
46 : #include "utils/varlena.h"
47 :
48 :
49 : /*
50 : * We don't want to log each fetching of a value from a sequence,
51 : * so we pre-log a few fetches in advance. In the event of
52 : * crash we can lose (skip over) as many values as we pre-logged.
53 : */
54 : #define SEQ_LOG_VALS 32
55 :
56 : /*
57 : * The "special area" of a sequence's buffer page looks like this.
58 : */
59 : #define SEQ_MAGIC 0x1717
60 :
61 : typedef struct sequence_magic
62 : {
63 : uint32 magic;
64 : } sequence_magic;
65 :
66 : /*
67 : * We store a SeqTable item for every sequence we have touched in the current
68 : * session. This is needed to hold onto nextval/currval state. (We can't
69 : * rely on the relcache, since it's only, well, a cache, and may decide to
70 : * discard entries.)
71 : */
72 : typedef struct SeqTableData
73 : {
74 : Oid relid; /* pg_class OID of this sequence (hash key) */
75 : Oid filenode; /* last seen relfilenode of this sequence */
76 : LocalTransactionId lxid; /* xact in which we last did a seq op */
77 : bool last_valid; /* do we have a valid "last" value? */
78 : int64 last; /* value last returned by nextval */
79 : int64 cached; /* last value already cached for nextval */
80 : /* if last != cached, we have not used up all the cached values */
81 : int64 increment; /* copy of sequence's increment field */
82 : /* note that increment is zero until we first do nextval_internal() */
83 : } SeqTableData;
84 :
85 : typedef SeqTableData *SeqTable;
86 :
87 : static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */
88 :
89 : /*
90 : * last_used_seq is updated by nextval() to point to the last used
91 : * sequence.
92 : */
93 : static SeqTableData *last_used_seq = NULL;
94 :
95 : static void fill_seq_with_data(Relation rel, HeapTuple tuple);
96 : static Relation lock_and_open_sequence(SeqTable seq);
97 : static void create_seq_hashtable(void);
98 : static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
99 : static Form_pg_sequence_data read_seq_tuple(Relation rel,
100 : Buffer *buf, HeapTuple seqdatatuple);
101 : static void init_params(ParseState *pstate, List *options, bool for_identity,
102 : bool isInit,
103 : Form_pg_sequence seqform,
104 : Form_pg_sequence_data seqdataform,
105 : bool *need_seq_rewrite,
106 : List **owned_by);
107 : static void do_setval(Oid relid, int64 next, bool iscalled);
108 : static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity);
109 :
110 :
111 : /*
112 : * DefineSequence
113 : * Creates a new sequence relation
114 : */
115 : ObjectAddress
116 150 : DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
117 : {
118 : FormData_pg_sequence seqform;
119 : FormData_pg_sequence_data seqdataform;
120 : bool need_seq_rewrite;
121 : List *owned_by;
122 150 : CreateStmt *stmt = makeNode(CreateStmt);
123 : Oid seqoid;
124 : ObjectAddress address;
125 : Relation rel;
126 : HeapTuple tuple;
127 : TupleDesc tupDesc;
128 : Datum value[SEQ_COL_LASTCOL];
129 : bool null[SEQ_COL_LASTCOL];
130 : Datum pgs_values[Natts_pg_sequence];
131 : bool pgs_nulls[Natts_pg_sequence];
132 : int i;
133 :
134 : /* Unlogged sequences are not implemented -- not clear if useful. */
135 150 : if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
136 1 : ereport(ERROR,
137 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
138 : errmsg("unlogged sequences are not supported")));
139 :
140 : /*
141 : * If if_not_exists was given and a relation with the same name already
142 : * exists, bail out. (Note: we needn't check this when not if_not_exists,
143 : * because DefineRelation will complain anyway.)
144 : */
145 149 : if (seq->if_not_exists)
146 : {
147 1 : RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid);
148 1 : if (OidIsValid(seqoid))
149 : {
150 1 : ereport(NOTICE,
151 : (errcode(ERRCODE_DUPLICATE_TABLE),
152 : errmsg("relation \"%s\" already exists, skipping",
153 : seq->sequence->relname)));
154 1 : return InvalidObjectAddress;
155 : }
156 : }
157 :
158 : /* Check and set all option values */
159 148 : init_params(pstate, seq->options, seq->for_identity, true,
160 : &seqform, &seqdataform,
161 : &need_seq_rewrite, &owned_by);
162 :
163 : /*
164 : * Create relation (and fill value[] and null[] for the tuple)
165 : */
166 136 : stmt->tableElts = NIL;
167 544 : for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
168 : {
169 408 : ColumnDef *coldef = makeNode(ColumnDef);
170 :
171 408 : coldef->inhcount = 0;
172 408 : coldef->is_local = true;
173 408 : coldef->is_not_null = true;
174 408 : coldef->is_from_type = false;
175 408 : coldef->is_from_parent = false;
176 408 : coldef->storage = 0;
177 408 : coldef->raw_default = NULL;
178 408 : coldef->cooked_default = NULL;
179 408 : coldef->collClause = NULL;
180 408 : coldef->collOid = InvalidOid;
181 408 : coldef->constraints = NIL;
182 408 : coldef->location = -1;
183 :
184 408 : null[i - 1] = false;
185 :
186 408 : switch (i)
187 : {
188 : case SEQ_COL_LASTVAL:
189 136 : coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
190 136 : coldef->colname = "last_value";
191 136 : value[i - 1] = Int64GetDatumFast(seqdataform.last_value);
192 136 : break;
193 : case SEQ_COL_LOG:
194 136 : coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
195 136 : coldef->colname = "log_cnt";
196 136 : value[i - 1] = Int64GetDatum((int64) 0);
197 136 : break;
198 : case SEQ_COL_CALLED:
199 136 : coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
200 136 : coldef->colname = "is_called";
201 136 : value[i - 1] = BoolGetDatum(false);
202 136 : break;
203 : }
204 408 : stmt->tableElts = lappend(stmt->tableElts, coldef);
205 : }
206 :
207 136 : stmt->relation = seq->sequence;
208 136 : stmt->inhRelations = NIL;
209 136 : stmt->constraints = NIL;
210 136 : stmt->options = NIL;
211 136 : stmt->oncommit = ONCOMMIT_NOOP;
212 136 : stmt->tablespacename = NULL;
213 136 : stmt->if_not_exists = seq->if_not_exists;
214 :
215 136 : address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
216 136 : seqoid = address.objectId;
217 136 : Assert(seqoid != InvalidOid);
218 :
219 136 : rel = heap_open(seqoid, AccessExclusiveLock);
220 136 : tupDesc = RelationGetDescr(rel);
221 :
222 : /* now initialize the sequence's data */
223 136 : tuple = heap_form_tuple(tupDesc, value, null);
224 136 : fill_seq_with_data(rel, tuple);
225 :
226 : /* process OWNED BY if given */
227 136 : if (owned_by)
228 4 : process_owned_by(rel, owned_by, seq->for_identity);
229 :
230 132 : heap_close(rel, NoLock);
231 :
232 : /* fill in pg_sequence */
233 132 : rel = heap_open(SequenceRelationId, RowExclusiveLock);
234 132 : tupDesc = RelationGetDescr(rel);
235 :
236 132 : memset(pgs_nulls, 0, sizeof(pgs_nulls));
237 :
238 132 : pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid);
239 132 : pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid);
240 132 : pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart);
241 132 : pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement);
242 132 : pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax);
243 132 : pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin);
244 132 : pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache);
245 132 : pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle);
246 :
247 132 : tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls);
248 132 : CatalogTupleInsert(rel, tuple);
249 :
250 132 : heap_freetuple(tuple);
251 132 : heap_close(rel, RowExclusiveLock);
252 :
253 132 : return address;
254 : }
255 :
256 : /*
257 : * Reset a sequence to its initial value.
258 : *
259 : * The change is made transactionally, so that on failure of the current
260 : * transaction, the sequence will be restored to its previous state.
261 : * We do that by creating a whole new relfilenode for the sequence; so this
262 : * works much like the rewriting forms of ALTER TABLE.
263 : *
264 : * Caller is assumed to have acquired AccessExclusiveLock on the sequence,
265 : * which must not be released until end of transaction. Caller is also
266 : * responsible for permissions checking.
267 : */
268 : void
269 5 : ResetSequence(Oid seq_relid)
270 : {
271 : Relation seq_rel;
272 : SeqTable elm;
273 : Form_pg_sequence_data seq;
274 : Buffer buf;
275 : HeapTupleData seqdatatuple;
276 : HeapTuple tuple;
277 : HeapTuple pgstuple;
278 : Form_pg_sequence pgsform;
279 : int64 startv;
280 :
281 : /*
282 : * Read the old sequence. This does a bit more work than really
283 : * necessary, but it's simple, and we do want to double-check that it's
284 : * indeed a sequence.
285 : */
286 5 : init_sequence(seq_relid, &elm, &seq_rel);
287 5 : (void) read_seq_tuple(seq_rel, &buf, &seqdatatuple);
288 :
289 5 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(seq_relid));
290 5 : if (!HeapTupleIsValid(pgstuple))
291 0 : elog(ERROR, "cache lookup failed for sequence %u", seq_relid);
292 5 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
293 5 : startv = pgsform->seqstart;
294 5 : ReleaseSysCache(pgstuple);
295 :
296 : /*
297 : * Copy the existing sequence tuple.
298 : */
299 5 : tuple = heap_copytuple(&seqdatatuple);
300 :
301 : /* Now we're done with the old page */
302 5 : UnlockReleaseBuffer(buf);
303 :
304 : /*
305 : * Modify the copied tuple to execute the restart (compare the RESTART
306 : * action in AlterSequence)
307 : */
308 5 : seq = (Form_pg_sequence_data) GETSTRUCT(tuple);
309 5 : seq->last_value = startv;
310 5 : seq->is_called = false;
311 5 : seq->log_cnt = 0;
312 :
313 : /*
314 : * Create a new storage file for the sequence. We want to keep the
315 : * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs.
316 : * Same with relminmxid, since a sequence will never contain multixacts.
317 : */
318 5 : RelationSetNewRelfilenode(seq_rel, seq_rel->rd_rel->relpersistence,
319 : InvalidTransactionId, InvalidMultiXactId);
320 :
321 : /*
322 : * Insert the modified tuple into the new storage file.
323 : */
324 5 : fill_seq_with_data(seq_rel, tuple);
325 :
326 : /* Clear local cache so that we don't think we have cached numbers */
327 : /* Note that we do not change the currval() state */
328 5 : elm->cached = elm->last;
329 :
330 5 : relation_close(seq_rel, NoLock);
331 5 : }
332 :
333 : /*
334 : * Initialize a sequence's relation with the specified tuple as content
335 : */
336 : static void
337 159 : fill_seq_with_data(Relation rel, HeapTuple tuple)
338 : {
339 : Buffer buf;
340 : Page page;
341 : sequence_magic *sm;
342 : OffsetNumber offnum;
343 :
344 : /* Initialize first page of relation with special magic number */
345 :
346 159 : buf = ReadBuffer(rel, P_NEW);
347 159 : Assert(BufferGetBlockNumber(buf) == 0);
348 :
349 159 : page = BufferGetPage(buf);
350 :
351 159 : PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
352 159 : sm = (sequence_magic *) PageGetSpecialPointer(page);
353 159 : sm->magic = SEQ_MAGIC;
354 :
355 : /* Now insert sequence tuple */
356 :
357 159 : LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
358 :
359 : /*
360 : * Since VACUUM does not process sequences, we have to force the tuple to
361 : * have xmin = FrozenTransactionId now. Otherwise it would become
362 : * invisible to SELECTs after 2G transactions. It is okay to do this
363 : * because if the current transaction aborts, no other xact will ever
364 : * examine the sequence tuple anyway.
365 : */
366 159 : HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
367 159 : HeapTupleHeaderSetXminFrozen(tuple->t_data);
368 159 : HeapTupleHeaderSetCmin(tuple->t_data, FirstCommandId);
369 159 : HeapTupleHeaderSetXmax(tuple->t_data, InvalidTransactionId);
370 159 : tuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
371 159 : ItemPointerSet(&tuple->t_data->t_ctid, 0, FirstOffsetNumber);
372 :
373 : /* check the comment above nextval_internal()'s equivalent call. */
374 159 : if (RelationNeedsWAL(rel))
375 143 : GetTopTransactionId();
376 :
377 159 : START_CRIT_SECTION();
378 :
379 159 : MarkBufferDirty(buf);
380 :
381 159 : offnum = PageAddItem(page, (Item) tuple->t_data, tuple->t_len,
382 : InvalidOffsetNumber, false, false);
383 159 : if (offnum != FirstOffsetNumber)
384 0 : elog(ERROR, "failed to add sequence tuple to page");
385 :
386 : /* XLOG stuff */
387 159 : if (RelationNeedsWAL(rel))
388 : {
389 : xl_seq_rec xlrec;
390 : XLogRecPtr recptr;
391 :
392 143 : XLogBeginInsert();
393 143 : XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
394 :
395 143 : xlrec.node = rel->rd_node;
396 :
397 143 : XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
398 143 : XLogRegisterData((char *) tuple->t_data, tuple->t_len);
399 :
400 143 : recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
401 :
402 143 : PageSetLSN(page, recptr);
403 : }
404 :
405 159 : END_CRIT_SECTION();
406 :
407 159 : UnlockReleaseBuffer(buf);
408 159 : }
409 :
410 : /*
411 : * AlterSequence
412 : *
413 : * Modify the definition of a sequence relation
414 : */
415 : ObjectAddress
416 105 : AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
417 : {
418 : Oid relid;
419 : SeqTable elm;
420 : Relation seqrel;
421 : Buffer buf;
422 : HeapTupleData datatuple;
423 : Form_pg_sequence seqform;
424 : Form_pg_sequence_data newdataform;
425 : bool need_seq_rewrite;
426 : List *owned_by;
427 : ObjectAddress address;
428 : Relation rel;
429 : HeapTuple seqtuple;
430 : HeapTuple newdatatuple;
431 :
432 : /* Open and lock sequence, and check for ownership along the way. */
433 105 : relid = RangeVarGetRelidExtended(stmt->sequence,
434 : ShareRowExclusiveLock,
435 105 : stmt->missing_ok,
436 : false,
437 : RangeVarCallbackOwnsRelation,
438 : NULL);
439 104 : if (relid == InvalidOid)
440 : {
441 1 : ereport(NOTICE,
442 : (errmsg("relation \"%s\" does not exist, skipping",
443 : stmt->sequence->relname)));
444 1 : return InvalidObjectAddress;
445 : }
446 :
447 103 : init_sequence(relid, &elm, &seqrel);
448 :
449 102 : rel = heap_open(SequenceRelationId, RowExclusiveLock);
450 102 : seqtuple = SearchSysCacheCopy1(SEQRELID,
451 : ObjectIdGetDatum(relid));
452 102 : if (!HeapTupleIsValid(seqtuple))
453 0 : elog(ERROR, "cache lookup failed for sequence %u",
454 : relid);
455 :
456 102 : seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
457 :
458 : /* lock page's buffer and read tuple into new sequence structure */
459 102 : (void) read_seq_tuple(seqrel, &buf, &datatuple);
460 :
461 : /* copy the existing sequence data tuple, so it can be modified locally */
462 102 : newdatatuple = heap_copytuple(&datatuple);
463 102 : newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
464 :
465 102 : UnlockReleaseBuffer(buf);
466 :
467 : /* Check and set new values */
468 102 : init_params(pstate, stmt->options, stmt->for_identity, false,
469 : seqform, newdataform,
470 : &need_seq_rewrite, &owned_by);
471 :
472 : /* Clear local cache so that we don't think we have cached numbers */
473 : /* Note that we do not change the currval() state */
474 97 : elm->cached = elm->last;
475 :
476 : /* If needed, rewrite the sequence relation itself */
477 97 : if (need_seq_rewrite)
478 : {
479 : /* check the comment above nextval_internal()'s equivalent call. */
480 18 : if (RelationNeedsWAL(seqrel))
481 18 : GetTopTransactionId();
482 :
483 : /*
484 : * Create a new storage file for the sequence, making the state
485 : * changes transactional. We want to keep the sequence's relfrozenxid
486 : * at 0, since it won't contain any unfrozen XIDs. Same with
487 : * relminmxid, since a sequence will never contain multixacts.
488 : */
489 18 : RelationSetNewRelfilenode(seqrel, seqrel->rd_rel->relpersistence,
490 : InvalidTransactionId, InvalidMultiXactId);
491 :
492 : /*
493 : * Insert the modified tuple into the new storage file.
494 : */
495 18 : fill_seq_with_data(seqrel, newdatatuple);
496 : }
497 :
498 : /* process OWNED BY if given */
499 97 : if (owned_by)
500 78 : process_owned_by(seqrel, owned_by, stmt->for_identity);
501 :
502 : /* update the pg_sequence tuple (we could skip this in some cases...) */
503 96 : CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
504 :
505 96 : InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
506 :
507 96 : ObjectAddressSet(address, RelationRelationId, relid);
508 :
509 96 : heap_close(rel, RowExclusiveLock);
510 96 : relation_close(seqrel, NoLock);
511 :
512 96 : return address;
513 : }
514 :
515 : void
516 85 : DeleteSequenceTuple(Oid relid)
517 : {
518 : Relation rel;
519 : HeapTuple tuple;
520 :
521 85 : rel = heap_open(SequenceRelationId, RowExclusiveLock);
522 :
523 85 : tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
524 85 : if (!HeapTupleIsValid(tuple))
525 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
526 :
527 85 : CatalogTupleDelete(rel, &tuple->t_self);
528 :
529 85 : ReleaseSysCache(tuple);
530 85 : heap_close(rel, RowExclusiveLock);
531 85 : }
532 :
533 : /*
534 : * Note: nextval with a text argument is no longer exported as a pg_proc
535 : * entry, but we keep it around to ease porting of C code that may have
536 : * called the function directly.
537 : */
538 : Datum
539 7 : nextval(PG_FUNCTION_ARGS)
540 : {
541 7 : text *seqin = PG_GETARG_TEXT_PP(0);
542 : RangeVar *sequence;
543 : Oid relid;
544 :
545 7 : sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
546 :
547 : /*
548 : * XXX: This is not safe in the presence of concurrent DDL, but acquiring
549 : * a lock here is more expensive than letting nextval_internal do it,
550 : * since the latter maintains a cache that keeps us from hitting the lock
551 : * manager more than once per transaction. It's not clear whether the
552 : * performance penalty is material in practice, but for now, we do it this
553 : * way.
554 : */
555 7 : relid = RangeVarGetRelid(sequence, NoLock, false);
556 :
557 7 : PG_RETURN_INT64(nextval_internal(relid, true));
558 : }
559 :
560 : Datum
561 477 : nextval_oid(PG_FUNCTION_ARGS)
562 : {
563 477 : Oid relid = PG_GETARG_OID(0);
564 :
565 477 : PG_RETURN_INT64(nextval_internal(relid, true));
566 : }
567 :
568 : int64
569 514 : nextval_internal(Oid relid, bool check_permissions)
570 : {
571 : SeqTable elm;
572 : Relation seqrel;
573 : Buffer buf;
574 : Page page;
575 : HeapTuple pgstuple;
576 : Form_pg_sequence pgsform;
577 : HeapTupleData seqdatatuple;
578 : Form_pg_sequence_data seq;
579 : int64 incby,
580 : maxv,
581 : minv,
582 : cache,
583 : log,
584 : fetch,
585 : last;
586 : int64 result,
587 : next,
588 514 : rescnt = 0;
589 : bool cycle;
590 514 : bool logit = false;
591 :
592 : /* open and lock sequence */
593 514 : init_sequence(relid, &elm, &seqrel);
594 :
595 998 : if (check_permissions &&
596 484 : pg_class_aclcheck(elm->relid, GetUserId(),
597 : ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
598 1 : ereport(ERROR,
599 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
600 : errmsg("permission denied for sequence %s",
601 : RelationGetRelationName(seqrel))));
602 :
603 : /* read-only transactions may only modify temp sequences */
604 513 : if (!seqrel->rd_islocaltemp)
605 292 : PreventCommandIfReadOnly("nextval()");
606 :
607 : /*
608 : * Forbid this during parallel operation because, to make it work, the
609 : * cooperating backends would need to share the backend-local cached
610 : * sequence information. Currently, we don't support that.
611 : */
612 512 : PreventCommandIfParallelMode("nextval()");
613 :
614 512 : if (elm->last != elm->cached) /* some numbers were cached */
615 : {
616 2 : Assert(elm->last_valid);
617 2 : Assert(elm->increment != 0);
618 2 : elm->last += elm->increment;
619 2 : relation_close(seqrel, NoLock);
620 2 : last_used_seq = elm;
621 2 : return elm->last;
622 : }
623 :
624 510 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
625 510 : if (!HeapTupleIsValid(pgstuple))
626 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
627 510 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
628 510 : incby = pgsform->seqincrement;
629 510 : maxv = pgsform->seqmax;
630 510 : minv = pgsform->seqmin;
631 510 : cache = pgsform->seqcache;
632 510 : cycle = pgsform->seqcycle;
633 510 : ReleaseSysCache(pgstuple);
634 :
635 : /* lock page' buffer and read tuple */
636 510 : seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
637 510 : page = BufferGetPage(buf);
638 :
639 510 : elm->increment = incby;
640 510 : last = next = result = seq->last_value;
641 510 : fetch = cache;
642 510 : log = seq->log_cnt;
643 :
644 510 : if (!seq->is_called)
645 : {
646 115 : rescnt++; /* return last_value if not is_called */
647 115 : fetch--;
648 : }
649 :
650 : /*
651 : * Decide whether we should emit a WAL log record. If so, force up the
652 : * fetch count to grab SEQ_LOG_VALS more values than we actually need to
653 : * cache. (These will then be usable without logging.)
654 : *
655 : * If this is the first nextval after a checkpoint, we must force a new
656 : * WAL record to be written anyway, else replay starting from the
657 : * checkpoint would fail to advance the sequence past the logged values.
658 : * In this case we may as well fetch extra values.
659 : */
660 510 : if (log < fetch || !seq->is_called)
661 : {
662 : /* forced log to satisfy local demand for values */
663 122 : fetch = log = fetch + SEQ_LOG_VALS;
664 122 : logit = true;
665 : }
666 : else
667 : {
668 388 : XLogRecPtr redoptr = GetRedoRecPtr();
669 :
670 388 : if (PageGetLSN(page) <= redoptr)
671 : {
672 : /* last update of seq was before checkpoint */
673 186 : fetch = log = fetch + SEQ_LOG_VALS;
674 186 : logit = true;
675 : }
676 : }
677 :
678 11048 : while (fetch) /* try to fetch cache [+ log ] numbers */
679 : {
680 : /*
681 : * Check MAXVALUE for ascending sequences and MINVALUE for descending
682 : * sequences
683 : */
684 10036 : if (incby > 0)
685 : {
686 : /* ascending sequence */
687 9980 : if ((maxv >= 0 && next > maxv - incby) ||
688 0 : (maxv < 0 && next + incby > maxv))
689 : {
690 5 : if (rescnt > 0)
691 3 : break; /* stop fetching */
692 2 : if (!cycle)
693 : {
694 : char buf[100];
695 :
696 1 : snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
697 1 : ereport(ERROR,
698 : (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
699 : errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
700 : RelationGetRelationName(seqrel), buf)));
701 : }
702 1 : next = minv;
703 : }
704 : else
705 9975 : next += incby;
706 : }
707 : else
708 : {
709 : /* descending sequence */
710 56 : if ((minv < 0 && next < minv - incby) ||
711 0 : (minv >= 0 && next + incby < minv))
712 : {
713 5 : if (rescnt > 0)
714 3 : break; /* stop fetching */
715 2 : if (!cycle)
716 : {
717 : char buf[100];
718 :
719 1 : snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
720 1 : ereport(ERROR,
721 : (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
722 : errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
723 : RelationGetRelationName(seqrel), buf)));
724 : }
725 1 : next = maxv;
726 : }
727 : else
728 51 : next += incby;
729 : }
730 10028 : fetch--;
731 10028 : if (rescnt < cache)
732 : {
733 402 : log--;
734 402 : rescnt++;
735 402 : last = next;
736 402 : if (rescnt == 1) /* if it's first result - */
737 393 : result = next; /* it's what to return */
738 : }
739 : }
740 :
741 508 : log -= fetch; /* adjust for any unfetched numbers */
742 508 : Assert(log >= 0);
743 :
744 : /* save info in local cache */
745 508 : elm->last = result; /* last returned number */
746 508 : elm->cached = last; /* last fetched number */
747 508 : elm->last_valid = true;
748 :
749 508 : last_used_seq = elm;
750 :
751 : /*
752 : * If something needs to be WAL logged, acquire an xid, so this
753 : * transaction's commit will trigger a WAL flush and wait for syncrep.
754 : * It's sufficient to ensure the toplevel transaction has an xid, no need
755 : * to assign xids subxacts, that'll already trigger an appropriate wait.
756 : * (Have to do that here, so we're outside the critical section)
757 : */
758 508 : if (logit && RelationNeedsWAL(seqrel))
759 85 : GetTopTransactionId();
760 :
761 : /* ready to change the on-disk (or really, in-buffer) tuple */
762 508 : START_CRIT_SECTION();
763 :
764 : /*
765 : * We must mark the buffer dirty before doing XLogInsert(); see notes in
766 : * SyncOneBuffer(). However, we don't apply the desired changes just yet.
767 : * This looks like a violation of the buffer update protocol, but it is in
768 : * fact safe because we hold exclusive lock on the buffer. Any other
769 : * process, including a checkpoint, that tries to examine the buffer
770 : * contents will block until we release the lock, and then will see the
771 : * final state that we install below.
772 : */
773 508 : MarkBufferDirty(buf);
774 :
775 : /* XLOG stuff */
776 508 : if (logit && RelationNeedsWAL(seqrel))
777 : {
778 : xl_seq_rec xlrec;
779 : XLogRecPtr recptr;
780 :
781 : /*
782 : * We don't log the current state of the tuple, but rather the state
783 : * as it would appear after "log" more fetches. This lets us skip
784 : * that many future WAL records, at the cost that we lose those
785 : * sequence values if we crash.
786 : */
787 85 : XLogBeginInsert();
788 85 : XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
789 :
790 : /* set values that will be saved in xlog */
791 85 : seq->last_value = next;
792 85 : seq->is_called = true;
793 85 : seq->log_cnt = 0;
794 :
795 85 : xlrec.node = seqrel->rd_node;
796 :
797 85 : XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
798 85 : XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
799 :
800 85 : recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
801 :
802 85 : PageSetLSN(page, recptr);
803 : }
804 :
805 : /* Now update sequence tuple to the intended final state */
806 508 : seq->last_value = last; /* last fetched number */
807 508 : seq->is_called = true;
808 508 : seq->log_cnt = log; /* how much is logged */
809 :
810 508 : END_CRIT_SECTION();
811 :
812 508 : UnlockReleaseBuffer(buf);
813 :
814 508 : relation_close(seqrel, NoLock);
815 :
816 508 : return result;
817 : }
818 :
819 : Datum
820 19 : currval_oid(PG_FUNCTION_ARGS)
821 : {
822 19 : Oid relid = PG_GETARG_OID(0);
823 : int64 result;
824 : SeqTable elm;
825 : Relation seqrel;
826 :
827 : /* open and lock sequence */
828 19 : init_sequence(relid, &elm, &seqrel);
829 :
830 19 : if (pg_class_aclcheck(elm->relid, GetUserId(),
831 : ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
832 1 : ereport(ERROR,
833 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
834 : errmsg("permission denied for sequence %s",
835 : RelationGetRelationName(seqrel))));
836 :
837 18 : if (!elm->last_valid)
838 1 : ereport(ERROR,
839 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
840 : errmsg("currval of sequence \"%s\" is not yet defined in this session",
841 : RelationGetRelationName(seqrel))));
842 :
843 17 : result = elm->last;
844 :
845 17 : relation_close(seqrel, NoLock);
846 :
847 17 : PG_RETURN_INT64(result);
848 : }
849 :
850 : Datum
851 8 : lastval(PG_FUNCTION_ARGS)
852 : {
853 : Relation seqrel;
854 : int64 result;
855 :
856 8 : if (last_used_seq == NULL)
857 1 : ereport(ERROR,
858 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
859 : errmsg("lastval is not yet defined in this session")));
860 :
861 : /* Someone may have dropped the sequence since the last nextval() */
862 7 : if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
863 1 : ereport(ERROR,
864 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
865 : errmsg("lastval is not yet defined in this session")));
866 :
867 6 : seqrel = lock_and_open_sequence(last_used_seq);
868 :
869 : /* nextval() must have already been called for this sequence */
870 6 : Assert(last_used_seq->last_valid);
871 :
872 6 : if (pg_class_aclcheck(last_used_seq->relid, GetUserId(),
873 : ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
874 1 : ereport(ERROR,
875 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
876 : errmsg("permission denied for sequence %s",
877 : RelationGetRelationName(seqrel))));
878 :
879 5 : result = last_used_seq->last;
880 5 : relation_close(seqrel, NoLock);
881 :
882 5 : PG_RETURN_INT64(result);
883 : }
884 :
885 : /*
886 : * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
887 : *
888 : * Note that the 3 arg version (which sets the is_called flag) is
889 : * only for use in pg_dump, and setting the is_called flag may not
890 : * work if multiple users are attached to the database and referencing
891 : * the sequence (unlikely if pg_dump is restoring it).
892 : *
893 : * It is necessary to have the 3 arg version so that pg_dump can
894 : * restore the state of a sequence exactly during data-only restores -
895 : * it is the only way to clear the is_called flag in an existing
896 : * sequence.
897 : */
898 : static void
899 54 : do_setval(Oid relid, int64 next, bool iscalled)
900 : {
901 : SeqTable elm;
902 : Relation seqrel;
903 : Buffer buf;
904 : HeapTupleData seqdatatuple;
905 : Form_pg_sequence_data seq;
906 : HeapTuple pgstuple;
907 : Form_pg_sequence pgsform;
908 : int64 maxv,
909 : minv;
910 :
911 : /* open and lock sequence */
912 54 : init_sequence(relid, &elm, &seqrel);
913 :
914 54 : if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
915 1 : ereport(ERROR,
916 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
917 : errmsg("permission denied for sequence %s",
918 : RelationGetRelationName(seqrel))));
919 :
920 53 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
921 53 : if (!HeapTupleIsValid(pgstuple))
922 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
923 53 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
924 53 : maxv = pgsform->seqmax;
925 53 : minv = pgsform->seqmin;
926 53 : ReleaseSysCache(pgstuple);
927 :
928 : /* read-only transactions may only modify temp sequences */
929 53 : if (!seqrel->rd_islocaltemp)
930 10 : PreventCommandIfReadOnly("setval()");
931 :
932 : /*
933 : * Forbid this during parallel operation because, to make it work, the
934 : * cooperating backends would need to share the backend-local cached
935 : * sequence information. Currently, we don't support that.
936 : */
937 52 : PreventCommandIfParallelMode("setval()");
938 :
939 : /* lock page' buffer and read tuple */
940 52 : seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
941 :
942 52 : if ((next < minv) || (next > maxv))
943 : {
944 : char bufv[100],
945 : bufm[100],
946 : bufx[100];
947 :
948 2 : snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
949 2 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, minv);
950 2 : snprintf(bufx, sizeof(bufx), INT64_FORMAT, maxv);
951 2 : ereport(ERROR,
952 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
953 : errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
954 : bufv, RelationGetRelationName(seqrel),
955 : bufm, bufx)));
956 : }
957 :
958 : /* Set the currval() state only if iscalled = true */
959 50 : if (iscalled)
960 : {
961 6 : elm->last = next; /* last returned number */
962 6 : elm->last_valid = true;
963 : }
964 :
965 : /* In any case, forget any future cached numbers */
966 50 : elm->cached = elm->last;
967 :
968 : /* check the comment above nextval_internal()'s equivalent call. */
969 50 : if (RelationNeedsWAL(seqrel))
970 7 : GetTopTransactionId();
971 :
972 : /* ready to change the on-disk (or really, in-buffer) tuple */
973 50 : START_CRIT_SECTION();
974 :
975 50 : seq->last_value = next; /* last fetched number */
976 50 : seq->is_called = iscalled;
977 50 : seq->log_cnt = 0;
978 :
979 50 : MarkBufferDirty(buf);
980 :
981 : /* XLOG stuff */
982 50 : if (RelationNeedsWAL(seqrel))
983 : {
984 : xl_seq_rec xlrec;
985 : XLogRecPtr recptr;
986 7 : Page page = BufferGetPage(buf);
987 :
988 7 : XLogBeginInsert();
989 7 : XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
990 :
991 7 : xlrec.node = seqrel->rd_node;
992 7 : XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
993 7 : XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
994 :
995 7 : recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
996 :
997 7 : PageSetLSN(page, recptr);
998 : }
999 :
1000 50 : END_CRIT_SECTION();
1001 :
1002 50 : UnlockReleaseBuffer(buf);
1003 :
1004 50 : relation_close(seqrel, NoLock);
1005 50 : }
1006 :
1007 : /*
1008 : * Implement the 2 arg setval procedure.
1009 : * See do_setval for discussion.
1010 : */
1011 : Datum
1012 10 : setval_oid(PG_FUNCTION_ARGS)
1013 : {
1014 10 : Oid relid = PG_GETARG_OID(0);
1015 10 : int64 next = PG_GETARG_INT64(1);
1016 :
1017 10 : do_setval(relid, next, true);
1018 :
1019 6 : PG_RETURN_INT64(next);
1020 : }
1021 :
1022 : /*
1023 : * Implement the 3 arg setval procedure.
1024 : * See do_setval for discussion.
1025 : */
1026 : Datum
1027 44 : setval3_oid(PG_FUNCTION_ARGS)
1028 : {
1029 44 : Oid relid = PG_GETARG_OID(0);
1030 44 : int64 next = PG_GETARG_INT64(1);
1031 44 : bool iscalled = PG_GETARG_BOOL(2);
1032 :
1033 44 : do_setval(relid, next, iscalled);
1034 :
1035 44 : PG_RETURN_INT64(next);
1036 : }
1037 :
1038 :
1039 : /*
1040 : * Open the sequence and acquire lock if needed
1041 : *
1042 : * If we haven't touched the sequence already in this transaction,
1043 : * we need to acquire a lock. We arrange for the lock to
1044 : * be owned by the top transaction, so that we don't need to do it
1045 : * more than once per xact.
1046 : */
1047 : static Relation
1048 720 : lock_and_open_sequence(SeqTable seq)
1049 : {
1050 720 : LocalTransactionId thislxid = MyProc->lxid;
1051 :
1052 : /* Get the lock if not already held in this xact */
1053 720 : if (seq->lxid != thislxid)
1054 : {
1055 : ResourceOwner currentOwner;
1056 :
1057 486 : currentOwner = CurrentResourceOwner;
1058 486 : PG_TRY();
1059 : {
1060 486 : CurrentResourceOwner = TopTransactionResourceOwner;
1061 486 : LockRelationOid(seq->relid, RowExclusiveLock);
1062 : }
1063 0 : PG_CATCH();
1064 : {
1065 : /* Ensure CurrentResourceOwner is restored on error */
1066 0 : CurrentResourceOwner = currentOwner;
1067 0 : PG_RE_THROW();
1068 : }
1069 486 : PG_END_TRY();
1070 486 : CurrentResourceOwner = currentOwner;
1071 :
1072 : /* Flag that we have a lock in the current xact */
1073 486 : seq->lxid = thislxid;
1074 : }
1075 :
1076 : /* We now know we have the lock, and can safely open the rel */
1077 720 : return relation_open(seq->relid, NoLock);
1078 : }
1079 :
1080 : /*
1081 : * Creates the hash table for storing sequence data
1082 : */
1083 : static void
1084 35 : create_seq_hashtable(void)
1085 : {
1086 : HASHCTL ctl;
1087 :
1088 35 : memset(&ctl, 0, sizeof(ctl));
1089 35 : ctl.keysize = sizeof(Oid);
1090 35 : ctl.entrysize = sizeof(SeqTableData);
1091 :
1092 35 : seqhashtab = hash_create("Sequence values", 16, &ctl,
1093 : HASH_ELEM | HASH_BLOBS);
1094 35 : }
1095 :
1096 : /*
1097 : * Given a relation OID, open and lock the sequence. p_elm and p_rel are
1098 : * output parameters.
1099 : */
1100 : static void
1101 714 : init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
1102 : {
1103 : SeqTable elm;
1104 : Relation seqrel;
1105 : bool found;
1106 :
1107 : /* Find or create a hash table entry for this sequence */
1108 714 : if (seqhashtab == NULL)
1109 35 : create_seq_hashtable();
1110 :
1111 714 : elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
1112 :
1113 : /*
1114 : * Initialize the new hash table entry if it did not exist already.
1115 : *
1116 : * NOTE: seqtable entries are stored for the life of a backend (unless
1117 : * explicitly discarded with DISCARD). If the sequence itself is deleted
1118 : * then the entry becomes wasted memory, but it's small enough that this
1119 : * should not matter.
1120 : */
1121 714 : if (!found)
1122 : {
1123 : /* relid already filled in */
1124 134 : elm->filenode = InvalidOid;
1125 134 : elm->lxid = InvalidLocalTransactionId;
1126 134 : elm->last_valid = false;
1127 134 : elm->last = elm->cached = 0;
1128 : }
1129 :
1130 : /*
1131 : * Open the sequence relation.
1132 : */
1133 714 : seqrel = lock_and_open_sequence(elm);
1134 :
1135 714 : if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
1136 1 : ereport(ERROR,
1137 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1138 : errmsg("\"%s\" is not a sequence",
1139 : RelationGetRelationName(seqrel))));
1140 :
1141 : /*
1142 : * If the sequence has been transactionally replaced since we last saw it,
1143 : * discard any cached-but-unissued values. We do not touch the currval()
1144 : * state, however.
1145 : */
1146 713 : if (seqrel->rd_rel->relfilenode != elm->filenode)
1147 : {
1148 149 : elm->filenode = seqrel->rd_rel->relfilenode;
1149 149 : elm->cached = elm->last;
1150 : }
1151 :
1152 : /* Return results */
1153 713 : *p_elm = elm;
1154 713 : *p_rel = seqrel;
1155 713 : }
1156 :
1157 :
1158 : /*
1159 : * Given an opened sequence relation, lock the page buffer and find the tuple
1160 : *
1161 : * *buf receives the reference to the pinned-and-ex-locked buffer
1162 : * *seqdatatuple receives the reference to the sequence tuple proper
1163 : * (this arg should point to a local variable of type HeapTupleData)
1164 : *
1165 : * Function's return value points to the data payload of the tuple
1166 : */
1167 : static Form_pg_sequence_data
1168 688 : read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
1169 : {
1170 : Page page;
1171 : ItemId lp;
1172 : sequence_magic *sm;
1173 : Form_pg_sequence_data seq;
1174 :
1175 688 : *buf = ReadBuffer(rel, 0);
1176 688 : LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
1177 :
1178 688 : page = BufferGetPage(*buf);
1179 688 : sm = (sequence_magic *) PageGetSpecialPointer(page);
1180 :
1181 688 : if (sm->magic != SEQ_MAGIC)
1182 0 : elog(ERROR, "bad magic number in sequence \"%s\": %08X",
1183 : RelationGetRelationName(rel), sm->magic);
1184 :
1185 688 : lp = PageGetItemId(page, FirstOffsetNumber);
1186 688 : Assert(ItemIdIsNormal(lp));
1187 :
1188 : /* Note we currently only bother to set these two fields of *seqdatatuple */
1189 688 : seqdatatuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1190 688 : seqdatatuple->t_len = ItemIdGetLength(lp);
1191 :
1192 : /*
1193 : * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on
1194 : * a sequence, which would leave a non-frozen XID in the sequence tuple's
1195 : * xmax, which eventually leads to clog access failures or worse. If we
1196 : * see this has happened, clean up after it. We treat this like a hint
1197 : * bit update, ie, don't bother to WAL-log it, since we can certainly do
1198 : * this again if the update gets lost.
1199 : */
1200 688 : Assert(!(seqdatatuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
1201 688 : if (HeapTupleHeaderGetRawXmax(seqdatatuple->t_data) != InvalidTransactionId)
1202 : {
1203 0 : HeapTupleHeaderSetXmax(seqdatatuple->t_data, InvalidTransactionId);
1204 0 : seqdatatuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
1205 0 : seqdatatuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
1206 0 : MarkBufferDirtyHint(*buf, true);
1207 : }
1208 :
1209 688 : seq = (Form_pg_sequence_data) GETSTRUCT(seqdatatuple);
1210 :
1211 688 : return seq;
1212 : }
1213 :
1214 : /*
1215 : * init_params: process the options list of CREATE or ALTER SEQUENCE, and
1216 : * store the values into appropriate fields of seqform, for changes that go
1217 : * into the pg_sequence catalog, and fields of seqdataform for changes to the
1218 : * sequence relation itself. Set *need_seq_rewrite to true if we changed any
1219 : * parameters that require rewriting the sequence's relation (interesting for
1220 : * ALTER SEQUENCE). Also set *owned_by to any OWNED BY option, or to NIL if
1221 : * there is none.
1222 : *
1223 : * If isInit is true, fill any unspecified options with default values;
1224 : * otherwise, do not change existing options that aren't explicitly overridden.
1225 : *
1226 : * Note: we force a sequence rewrite whenever we change parameters that affect
1227 : * generation of future sequence values, even if the seqdataform per se is not
1228 : * changed. This allows ALTER SEQUENCE to behave transactionally. Currently,
1229 : * the only option that doesn't cause that is OWNED BY. It's *necessary* for
1230 : * ALTER SEQUENCE OWNED BY to not rewrite the sequence, because that would
1231 : * break pg_upgrade by causing unwanted changes in the sequence's relfilenode.
1232 : */
1233 : static void
1234 250 : init_params(ParseState *pstate, List *options, bool for_identity,
1235 : bool isInit,
1236 : Form_pg_sequence seqform,
1237 : Form_pg_sequence_data seqdataform,
1238 : bool *need_seq_rewrite,
1239 : List **owned_by)
1240 : {
1241 250 : DefElem *as_type = NULL;
1242 250 : DefElem *start_value = NULL;
1243 250 : DefElem *restart_value = NULL;
1244 250 : DefElem *increment_by = NULL;
1245 250 : DefElem *max_value = NULL;
1246 250 : DefElem *min_value = NULL;
1247 250 : DefElem *cache_value = NULL;
1248 250 : DefElem *is_cycled = NULL;
1249 : ListCell *option;
1250 250 : bool reset_max_value = false;
1251 250 : bool reset_min_value = false;
1252 :
1253 250 : *need_seq_rewrite = false;
1254 250 : *owned_by = NIL;
1255 :
1256 506 : foreach(option, options)
1257 : {
1258 256 : DefElem *defel = (DefElem *) lfirst(option);
1259 :
1260 256 : if (strcmp(defel->defname, "as") == 0)
1261 : {
1262 107 : if (as_type)
1263 0 : ereport(ERROR,
1264 : (errcode(ERRCODE_SYNTAX_ERROR),
1265 : errmsg("conflicting or redundant options"),
1266 : parser_errposition(pstate, defel->location)));
1267 107 : as_type = defel;
1268 107 : *need_seq_rewrite = true;
1269 : }
1270 149 : else if (strcmp(defel->defname, "increment") == 0)
1271 : {
1272 16 : if (increment_by)
1273 0 : ereport(ERROR,
1274 : (errcode(ERRCODE_SYNTAX_ERROR),
1275 : errmsg("conflicting or redundant options"),
1276 : parser_errposition(pstate, defel->location)));
1277 16 : increment_by = defel;
1278 16 : *need_seq_rewrite = true;
1279 : }
1280 133 : else if (strcmp(defel->defname, "start") == 0)
1281 : {
1282 12 : if (start_value)
1283 0 : ereport(ERROR,
1284 : (errcode(ERRCODE_SYNTAX_ERROR),
1285 : errmsg("conflicting or redundant options"),
1286 : parser_errposition(pstate, defel->location)));
1287 12 : start_value = defel;
1288 12 : *need_seq_rewrite = true;
1289 : }
1290 121 : else if (strcmp(defel->defname, "restart") == 0)
1291 : {
1292 11 : if (restart_value)
1293 0 : ereport(ERROR,
1294 : (errcode(ERRCODE_SYNTAX_ERROR),
1295 : errmsg("conflicting or redundant options"),
1296 : parser_errposition(pstate, defel->location)));
1297 11 : restart_value = defel;
1298 11 : *need_seq_rewrite = true;
1299 : }
1300 110 : else if (strcmp(defel->defname, "maxvalue") == 0)
1301 : {
1302 9 : if (max_value)
1303 0 : ereport(ERROR,
1304 : (errcode(ERRCODE_SYNTAX_ERROR),
1305 : errmsg("conflicting or redundant options"),
1306 : parser_errposition(pstate, defel->location)));
1307 9 : max_value = defel;
1308 9 : *need_seq_rewrite = true;
1309 : }
1310 101 : else if (strcmp(defel->defname, "minvalue") == 0)
1311 : {
1312 10 : if (min_value)
1313 0 : ereport(ERROR,
1314 : (errcode(ERRCODE_SYNTAX_ERROR),
1315 : errmsg("conflicting or redundant options"),
1316 : parser_errposition(pstate, defel->location)));
1317 10 : min_value = defel;
1318 10 : *need_seq_rewrite = true;
1319 : }
1320 91 : else if (strcmp(defel->defname, "cache") == 0)
1321 : {
1322 3 : if (cache_value)
1323 0 : ereport(ERROR,
1324 : (errcode(ERRCODE_SYNTAX_ERROR),
1325 : errmsg("conflicting or redundant options"),
1326 : parser_errposition(pstate, defel->location)));
1327 3 : cache_value = defel;
1328 3 : *need_seq_rewrite = true;
1329 : }
1330 88 : else if (strcmp(defel->defname, "cycle") == 0)
1331 : {
1332 6 : if (is_cycled)
1333 0 : ereport(ERROR,
1334 : (errcode(ERRCODE_SYNTAX_ERROR),
1335 : errmsg("conflicting or redundant options"),
1336 : parser_errposition(pstate, defel->location)));
1337 6 : is_cycled = defel;
1338 6 : *need_seq_rewrite = true;
1339 : }
1340 82 : else if (strcmp(defel->defname, "owned_by") == 0)
1341 : {
1342 82 : if (*owned_by)
1343 0 : ereport(ERROR,
1344 : (errcode(ERRCODE_SYNTAX_ERROR),
1345 : errmsg("conflicting or redundant options"),
1346 : parser_errposition(pstate, defel->location)));
1347 82 : *owned_by = defGetQualifiedName(defel);
1348 : }
1349 0 : else if (strcmp(defel->defname, "sequence_name") == 0)
1350 : {
1351 : /*
1352 : * The parser allows this, but it is only for identity columns, in
1353 : * which case it is filtered out in parse_utilcmd.c. We only get
1354 : * here if someone puts it into a CREATE SEQUENCE.
1355 : */
1356 0 : ereport(ERROR,
1357 : (errcode(ERRCODE_SYNTAX_ERROR),
1358 : errmsg("invalid sequence option SEQUENCE NAME"),
1359 : parser_errposition(pstate, defel->location)));
1360 : }
1361 : else
1362 0 : elog(ERROR, "option \"%s\" not recognized",
1363 : defel->defname);
1364 : }
1365 :
1366 : /*
1367 : * We must reset log_cnt when isInit or when changing any parameters that
1368 : * would affect future nextval allocations.
1369 : */
1370 250 : if (isInit)
1371 148 : seqdataform->log_cnt = 0;
1372 :
1373 : /* AS type */
1374 250 : if (as_type != NULL)
1375 : {
1376 107 : Oid newtypid = typenameTypeId(pstate, defGetTypeName(as_type));
1377 :
1378 106 : if (newtypid != INT2OID &&
1379 9 : newtypid != INT4OID &&
1380 : newtypid != INT8OID)
1381 4 : ereport(ERROR,
1382 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1383 : for_identity
1384 : ? errmsg("identity column type must be smallint, integer, or bigint")
1385 : : errmsg("sequence type must be smallint, integer, or bigint")));
1386 :
1387 102 : if (!isInit)
1388 : {
1389 : /*
1390 : * When changing type and the old sequence min/max values were the
1391 : * min/max of the old type, adjust sequence min/max values to
1392 : * min/max of new type. (Otherwise, the user chose explicit
1393 : * min/max values, which we'll leave alone.)
1394 : */
1395 18 : if ((seqform->seqtypid == INT2OID && seqform->seqmax == PG_INT16_MAX) ||
1396 17 : (seqform->seqtypid == INT4OID && seqform->seqmax == PG_INT32_MAX) ||
1397 4 : (seqform->seqtypid == INT8OID && seqform->seqmax == PG_INT64_MAX))
1398 7 : reset_max_value = true;
1399 19 : if ((seqform->seqtypid == INT2OID && seqform->seqmin == PG_INT16_MIN) ||
1400 21 : (seqform->seqtypid == INT4OID && seqform->seqmin == PG_INT32_MIN) ||
1401 7 : (seqform->seqtypid == INT8OID && seqform->seqmin == PG_INT64_MIN))
1402 4 : reset_min_value = true;
1403 : }
1404 :
1405 102 : seqform->seqtypid = newtypid;
1406 : }
1407 143 : else if (isInit)
1408 : {
1409 53 : seqform->seqtypid = INT8OID;
1410 : }
1411 :
1412 : /* INCREMENT BY */
1413 245 : if (increment_by != NULL)
1414 : {
1415 16 : seqform->seqincrement = defGetInt64(increment_by);
1416 16 : if (seqform->seqincrement == 0)
1417 1 : ereport(ERROR,
1418 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1419 : errmsg("INCREMENT must not be zero")));
1420 15 : seqdataform->log_cnt = 0;
1421 : }
1422 229 : else if (isInit)
1423 : {
1424 132 : seqform->seqincrement = 1;
1425 : }
1426 :
1427 : /* CYCLE */
1428 244 : if (is_cycled != NULL)
1429 : {
1430 6 : seqform->seqcycle = intVal(is_cycled->arg);
1431 6 : Assert(BoolIsValid(seqform->seqcycle));
1432 6 : seqdataform->log_cnt = 0;
1433 : }
1434 238 : else if (isInit)
1435 : {
1436 142 : seqform->seqcycle = false;
1437 : }
1438 :
1439 : /* MAXVALUE (null arg means NO MAXVALUE) */
1440 244 : if (max_value != NULL && max_value->arg)
1441 : {
1442 9 : seqform->seqmax = defGetInt64(max_value);
1443 9 : seqdataform->log_cnt = 0;
1444 : }
1445 235 : else if (isInit || max_value != NULL || reset_max_value)
1446 : {
1447 145 : if (seqform->seqincrement > 0 || reset_max_value)
1448 : {
1449 : /* ascending seq */
1450 280 : if (seqform->seqtypid == INT2OID)
1451 11 : seqform->seqmax = PG_INT16_MAX;
1452 129 : else if (seqform->seqtypid == INT4OID)
1453 77 : seqform->seqmax = PG_INT32_MAX;
1454 : else
1455 52 : seqform->seqmax = PG_INT64_MAX;
1456 : }
1457 : else
1458 5 : seqform->seqmax = -1; /* descending seq */
1459 145 : seqdataform->log_cnt = 0;
1460 : }
1461 :
1462 244 : if ((seqform->seqtypid == INT2OID && (seqform->seqmax < PG_INT16_MIN || seqform->seqmax > PG_INT16_MAX))
1463 393 : || (seqform->seqtypid == INT4OID && (seqform->seqmax < PG_INT32_MIN || seqform->seqmax > PG_INT32_MAX))
1464 242 : || (seqform->seqtypid == INT8OID && (seqform->seqmax < PG_INT64_MIN || seqform->seqmax > PG_INT64_MAX)))
1465 : {
1466 : char bufx[100];
1467 :
1468 2 : snprintf(bufx, sizeof(bufx), INT64_FORMAT, seqform->seqmax);
1469 :
1470 2 : ereport(ERROR,
1471 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1472 : errmsg("MAXVALUE (%s) is out of range for sequence data type %s",
1473 : bufx, format_type_be(seqform->seqtypid))));
1474 : }
1475 :
1476 : /* MINVALUE (null arg means NO MINVALUE) */
1477 242 : if (min_value != NULL && min_value->arg)
1478 : {
1479 10 : seqform->seqmin = defGetInt64(min_value);
1480 10 : seqdataform->log_cnt = 0;
1481 : }
1482 232 : else if (isInit || min_value != NULL || reset_min_value)
1483 : {
1484 140 : if (seqform->seqincrement < 0 || reset_min_value)
1485 : {
1486 : /* descending seq */
1487 18 : if (seqform->seqtypid == INT2OID)
1488 3 : seqform->seqmin = PG_INT16_MIN;
1489 6 : else if (seqform->seqtypid == INT4OID)
1490 4 : seqform->seqmin = PG_INT32_MIN;
1491 : else
1492 2 : seqform->seqmin = PG_INT64_MIN;
1493 : }
1494 : else
1495 131 : seqform->seqmin = 1; /* ascending seq */
1496 140 : seqdataform->log_cnt = 0;
1497 : }
1498 :
1499 242 : if ((seqform->seqtypid == INT2OID && (seqform->seqmin < PG_INT16_MIN || seqform->seqmin > PG_INT16_MAX))
1500 391 : || (seqform->seqtypid == INT4OID && (seqform->seqmin < PG_INT32_MIN || seqform->seqmin > PG_INT32_MAX))
1501 240 : || (seqform->seqtypid == INT8OID && (seqform->seqmin < PG_INT64_MIN || seqform->seqmin > PG_INT64_MAX)))
1502 : {
1503 : char bufm[100];
1504 :
1505 2 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin);
1506 :
1507 2 : ereport(ERROR,
1508 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1509 : errmsg("MINVALUE (%s) is out of range for sequence data type %s",
1510 : bufm, format_type_be(seqform->seqtypid))));
1511 : }
1512 :
1513 : /* crosscheck min/max */
1514 240 : if (seqform->seqmin >= seqform->seqmax)
1515 : {
1516 : char bufm[100],
1517 : bufx[100];
1518 :
1519 2 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin);
1520 2 : snprintf(bufx, sizeof(bufx), INT64_FORMAT, seqform->seqmax);
1521 2 : ereport(ERROR,
1522 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1523 : errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
1524 : bufm, bufx)));
1525 : }
1526 :
1527 : /* START WITH */
1528 238 : if (start_value != NULL)
1529 : {
1530 12 : seqform->seqstart = defGetInt64(start_value);
1531 : }
1532 226 : else if (isInit)
1533 : {
1534 130 : if (seqform->seqincrement > 0)
1535 126 : seqform->seqstart = seqform->seqmin; /* ascending seq */
1536 : else
1537 4 : seqform->seqstart = seqform->seqmax; /* descending seq */
1538 : }
1539 :
1540 : /* crosscheck START */
1541 238 : if (seqform->seqstart < seqform->seqmin)
1542 : {
1543 : char bufs[100],
1544 : bufm[100];
1545 :
1546 1 : snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqform->seqstart);
1547 1 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin);
1548 1 : ereport(ERROR,
1549 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1550 : errmsg("START value (%s) cannot be less than MINVALUE (%s)",
1551 : bufs, bufm)));
1552 : }
1553 237 : if (seqform->seqstart > seqform->seqmax)
1554 : {
1555 : char bufs[100],
1556 : bufm[100];
1557 :
1558 1 : snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqform->seqstart);
1559 1 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmax);
1560 1 : ereport(ERROR,
1561 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1562 : errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
1563 : bufs, bufm)));
1564 : }
1565 :
1566 : /* RESTART [WITH] */
1567 236 : if (restart_value != NULL)
1568 : {
1569 11 : if (restart_value->arg != NULL)
1570 8 : seqdataform->last_value = defGetInt64(restart_value);
1571 : else
1572 3 : seqdataform->last_value = seqform->seqstart;
1573 11 : seqdataform->is_called = false;
1574 11 : seqdataform->log_cnt = 0;
1575 : }
1576 225 : else if (isInit)
1577 : {
1578 137 : seqdataform->last_value = seqform->seqstart;
1579 137 : seqdataform->is_called = false;
1580 : }
1581 :
1582 : /* crosscheck RESTART (or current value, if changing MIN/MAX) */
1583 236 : if (seqdataform->last_value < seqform->seqmin)
1584 : {
1585 : char bufs[100],
1586 : bufm[100];
1587 :
1588 1 : snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqdataform->last_value);
1589 1 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin);
1590 1 : ereport(ERROR,
1591 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1592 : errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
1593 : bufs, bufm)));
1594 : }
1595 235 : if (seqdataform->last_value > seqform->seqmax)
1596 : {
1597 : char bufs[100],
1598 : bufm[100];
1599 :
1600 1 : snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqdataform->last_value);
1601 1 : snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmax);
1602 1 : ereport(ERROR,
1603 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1604 : errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
1605 : bufs, bufm)));
1606 : }
1607 :
1608 : /* CACHE */
1609 234 : if (cache_value != NULL)
1610 : {
1611 3 : seqform->seqcache = defGetInt64(cache_value);
1612 3 : if (seqform->seqcache <= 0)
1613 : {
1614 : char buf[100];
1615 :
1616 1 : snprintf(buf, sizeof(buf), INT64_FORMAT, seqform->seqcache);
1617 1 : ereport(ERROR,
1618 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1619 : errmsg("CACHE (%s) must be greater than zero",
1620 : buf)));
1621 : }
1622 2 : seqdataform->log_cnt = 0;
1623 : }
1624 231 : else if (isInit)
1625 : {
1626 134 : seqform->seqcache = 1;
1627 : }
1628 233 : }
1629 :
1630 : /*
1631 : * Process an OWNED BY option for CREATE/ALTER SEQUENCE
1632 : *
1633 : * Ownership permissions on the sequence are already checked,
1634 : * but if we are establishing a new owned-by dependency, we must
1635 : * enforce that the referenced table has the same owner and namespace
1636 : * as the sequence.
1637 : */
1638 : static void
1639 82 : process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
1640 : {
1641 : DependencyType deptype;
1642 : int nnames;
1643 : Relation tablerel;
1644 : AttrNumber attnum;
1645 :
1646 82 : deptype = for_identity ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO;
1647 :
1648 82 : nnames = list_length(owned_by);
1649 82 : Assert(nnames > 0);
1650 82 : if (nnames == 1)
1651 : {
1652 : /* Must be OWNED BY NONE */
1653 2 : if (strcmp(strVal(linitial(owned_by)), "none") != 0)
1654 1 : ereport(ERROR,
1655 : (errcode(ERRCODE_SYNTAX_ERROR),
1656 : errmsg("invalid OWNED BY option"),
1657 : errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
1658 1 : tablerel = NULL;
1659 1 : attnum = 0;
1660 : }
1661 : else
1662 : {
1663 : List *relname;
1664 : char *attrname;
1665 : RangeVar *rel;
1666 :
1667 : /* Separate relname and attr name */
1668 80 : relname = list_truncate(list_copy(owned_by), nnames - 1);
1669 80 : attrname = strVal(lfirst(list_tail(owned_by)));
1670 :
1671 : /* Open and lock rel to ensure it won't go away meanwhile */
1672 80 : rel = makeRangeVarFromNameList(relname);
1673 80 : tablerel = relation_openrv(rel, AccessShareLock);
1674 :
1675 : /* Must be a regular or foreign table */
1676 82 : if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
1677 2 : tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
1678 1 : tablerel->rd_rel->relkind == RELKIND_VIEW ||
1679 1 : tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
1680 1 : ereport(ERROR,
1681 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1682 : errmsg("referenced relation \"%s\" is not a table or foreign table",
1683 : RelationGetRelationName(tablerel))));
1684 :
1685 : /* We insist on same owner and schema */
1686 79 : if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
1687 0 : ereport(ERROR,
1688 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1689 : errmsg("sequence must have same owner as table it is linked to")));
1690 79 : if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
1691 1 : ereport(ERROR,
1692 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1693 : errmsg("sequence must be in same schema as table it is linked to")));
1694 :
1695 : /* Now, fetch the attribute number from the system cache */
1696 78 : attnum = get_attnum(RelationGetRelid(tablerel), attrname);
1697 78 : if (attnum == InvalidAttrNumber)
1698 1 : ereport(ERROR,
1699 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1700 : errmsg("column \"%s\" of relation \"%s\" does not exist",
1701 : attrname, RelationGetRelationName(tablerel))));
1702 : }
1703 :
1704 : /*
1705 : * Catch user explicitly running OWNED BY on identity sequence.
1706 : */
1707 78 : if (deptype == DEPENDENCY_AUTO)
1708 : {
1709 : Oid tableId;
1710 : int32 colId;
1711 :
1712 64 : if (sequenceIsOwned(RelationGetRelid(seqrel), DEPENDENCY_INTERNAL, &tableId, &colId))
1713 1 : ereport(ERROR,
1714 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1715 : errmsg("cannot change ownership of identity sequence"),
1716 : errdetail("Sequence \"%s\" is linked to table \"%s\".",
1717 : RelationGetRelationName(seqrel),
1718 : get_rel_name(tableId))));
1719 : }
1720 :
1721 : /*
1722 : * OK, we are ready to update pg_depend. First remove any existing
1723 : * dependencies for the sequence, then optionally add a new one.
1724 : */
1725 77 : deleteDependencyRecordsForClass(RelationRelationId, RelationGetRelid(seqrel),
1726 : RelationRelationId, deptype);
1727 :
1728 77 : if (tablerel)
1729 : {
1730 : ObjectAddress refobject,
1731 : depobject;
1732 :
1733 77 : refobject.classId = RelationRelationId;
1734 77 : refobject.objectId = RelationGetRelid(tablerel);
1735 77 : refobject.objectSubId = attnum;
1736 77 : depobject.classId = RelationRelationId;
1737 77 : depobject.objectId = RelationGetRelid(seqrel);
1738 77 : depobject.objectSubId = 0;
1739 77 : recordDependencyOn(&depobject, &refobject, deptype);
1740 : }
1741 :
1742 : /* Done, but hold lock until commit */
1743 77 : if (tablerel)
1744 77 : relation_close(tablerel, NoLock);
1745 77 : }
1746 :
1747 :
1748 : /*
1749 : * Return sequence parameters in a list of the form created by the parser.
1750 : */
1751 : List *
1752 1 : sequence_options(Oid relid)
1753 : {
1754 : HeapTuple pgstuple;
1755 : Form_pg_sequence pgsform;
1756 1 : List *options = NIL;
1757 :
1758 1 : pgstuple = SearchSysCache1(SEQRELID, relid);
1759 1 : if (!HeapTupleIsValid(pgstuple))
1760 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
1761 1 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1762 :
1763 1 : options = lappend(options, makeDefElem("cache", (Node *) makeInteger(pgsform->seqcache), -1));
1764 1 : options = lappend(options, makeDefElem("cycle", (Node *) makeInteger(pgsform->seqcycle), -1));
1765 1 : options = lappend(options, makeDefElem("increment", (Node *) makeInteger(pgsform->seqincrement), -1));
1766 1 : options = lappend(options, makeDefElem("maxvalue", (Node *) makeInteger(pgsform->seqmax), -1));
1767 1 : options = lappend(options, makeDefElem("minvalue", (Node *) makeInteger(pgsform->seqmin), -1));
1768 1 : options = lappend(options, makeDefElem("start", (Node *) makeInteger(pgsform->seqstart), -1));
1769 :
1770 1 : ReleaseSysCache(pgstuple);
1771 :
1772 1 : return options;
1773 : }
1774 :
1775 : /*
1776 : * Return sequence parameters (formerly for use by information schema)
1777 : */
1778 : Datum
1779 1 : pg_sequence_parameters(PG_FUNCTION_ARGS)
1780 : {
1781 1 : Oid relid = PG_GETARG_OID(0);
1782 : TupleDesc tupdesc;
1783 : Datum values[7];
1784 : bool isnull[7];
1785 : HeapTuple pgstuple;
1786 : Form_pg_sequence pgsform;
1787 :
1788 1 : if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK)
1789 0 : ereport(ERROR,
1790 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1791 : errmsg("permission denied for sequence %s",
1792 : get_rel_name(relid))));
1793 :
1794 1 : tupdesc = CreateTemplateTupleDesc(7, false);
1795 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
1796 : INT8OID, -1, 0);
1797 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value",
1798 : INT8OID, -1, 0);
1799 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "maximum_value",
1800 : INT8OID, -1, 0);
1801 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "increment",
1802 : INT8OID, -1, 0);
1803 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option",
1804 : BOOLOID, -1, 0);
1805 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "cache_size",
1806 : INT8OID, -1, 0);
1807 1 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "data_type",
1808 : OIDOID, -1, 0);
1809 :
1810 1 : BlessTupleDesc(tupdesc);
1811 :
1812 1 : memset(isnull, 0, sizeof(isnull));
1813 :
1814 1 : pgstuple = SearchSysCache1(SEQRELID, relid);
1815 1 : if (!HeapTupleIsValid(pgstuple))
1816 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
1817 1 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1818 :
1819 1 : values[0] = Int64GetDatum(pgsform->seqstart);
1820 1 : values[1] = Int64GetDatum(pgsform->seqmin);
1821 1 : values[2] = Int64GetDatum(pgsform->seqmax);
1822 1 : values[3] = Int64GetDatum(pgsform->seqincrement);
1823 1 : values[4] = BoolGetDatum(pgsform->seqcycle);
1824 1 : values[5] = Int64GetDatum(pgsform->seqcache);
1825 1 : values[6] = ObjectIdGetDatum(pgsform->seqtypid);
1826 :
1827 1 : ReleaseSysCache(pgstuple);
1828 :
1829 1 : return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
1830 : }
1831 :
1832 : /*
1833 : * Return the last value from the sequence
1834 : *
1835 : * Note: This has a completely different meaning than lastval().
1836 : */
1837 : Datum
1838 19 : pg_sequence_last_value(PG_FUNCTION_ARGS)
1839 : {
1840 19 : Oid relid = PG_GETARG_OID(0);
1841 : SeqTable elm;
1842 : Relation seqrel;
1843 : Buffer buf;
1844 : HeapTupleData seqtuple;
1845 : Form_pg_sequence_data seq;
1846 : bool is_called;
1847 : int64 result;
1848 :
1849 : /* open and lock sequence */
1850 19 : init_sequence(relid, &elm, &seqrel);
1851 :
1852 19 : if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
1853 0 : ereport(ERROR,
1854 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1855 : errmsg("permission denied for sequence %s",
1856 : RelationGetRelationName(seqrel))));
1857 :
1858 19 : seq = read_seq_tuple(seqrel, &buf, &seqtuple);
1859 :
1860 19 : is_called = seq->is_called;
1861 19 : result = seq->last_value;
1862 :
1863 19 : UnlockReleaseBuffer(buf);
1864 19 : relation_close(seqrel, NoLock);
1865 :
1866 19 : if (is_called)
1867 8 : PG_RETURN_INT64(result);
1868 : else
1869 11 : PG_RETURN_NULL();
1870 : }
1871 :
1872 :
1873 : void
1874 0 : seq_redo(XLogReaderState *record)
1875 : {
1876 0 : XLogRecPtr lsn = record->EndRecPtr;
1877 0 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1878 : Buffer buffer;
1879 : Page page;
1880 : Page localpage;
1881 : char *item;
1882 : Size itemsz;
1883 0 : xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1884 : sequence_magic *sm;
1885 :
1886 0 : if (info != XLOG_SEQ_LOG)
1887 0 : elog(PANIC, "seq_redo: unknown op code %u", info);
1888 :
1889 0 : buffer = XLogInitBufferForRedo(record, 0);
1890 0 : page = (Page) BufferGetPage(buffer);
1891 :
1892 : /*
1893 : * We always reinit the page. However, since this WAL record type is also
1894 : * used for updating sequences, it's possible that a hot-standby backend
1895 : * is examining the page concurrently; so we mustn't transiently trash the
1896 : * buffer. The solution is to build the correct new page contents in
1897 : * local workspace and then memcpy into the buffer. Then only bytes that
1898 : * are supposed to change will change, even transiently. We must palloc
1899 : * the local page for alignment reasons.
1900 : */
1901 0 : localpage = (Page) palloc(BufferGetPageSize(buffer));
1902 :
1903 0 : PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1904 0 : sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1905 0 : sm->magic = SEQ_MAGIC;
1906 :
1907 0 : item = (char *) xlrec + sizeof(xl_seq_rec);
1908 0 : itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1909 :
1910 0 : if (PageAddItem(localpage, (Item) item, itemsz,
1911 : FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1912 0 : elog(PANIC, "seq_redo: failed to add item to page");
1913 :
1914 0 : PageSetLSN(localpage, lsn);
1915 :
1916 0 : memcpy(page, localpage, BufferGetPageSize(buffer));
1917 0 : MarkBufferDirty(buffer);
1918 0 : UnlockReleaseBuffer(buffer);
1919 :
1920 0 : pfree(localpage);
1921 0 : }
1922 :
1923 : /*
1924 : * Flush cached sequence information.
1925 : */
1926 : void
1927 3 : ResetSequenceCaches(void)
1928 : {
1929 3 : if (seqhashtab)
1930 : {
1931 2 : hash_destroy(seqhashtab);
1932 2 : seqhashtab = NULL;
1933 : }
1934 :
1935 3 : last_used_seq = NULL;
1936 3 : }
1937 :
1938 : /*
1939 : * Mask a Sequence page before performing consistency checks on it.
1940 : */
1941 : void
1942 0 : seq_mask(char *page, BlockNumber blkno)
1943 : {
1944 0 : mask_page_lsn(page);
1945 :
1946 0 : mask_unused_space(page);
1947 0 : }
|