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