Skip to content

Commit 91c97f1

Browse files
michaelpqCommitfest Bot
authored andcommitted
Sequence access methods - backend support
The "seqlocal" sequence AM is now plugged in as a handler in the relcache, and a set of callbacks in sequenceam.h.
1 parent 1744587 commit 91c97f1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+697
-184
lines changed

src/backend/access/sequence/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ subdir = src/backend/access/sequence
1212
top_builddir = ../../../..
1313
include $(top_builddir)/src/Makefile.global
1414

15-
OBJS = seqlocalam.o seqlocalxlog.o sequence.o
15+
OBJS = seqlocalam.o seqlocalxlog.o sequence.o sequenceamapi.o
1616

1717
include $(top_srcdir)/src/backend/common.mk

src/backend/access/sequence/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ backend_sources += files(
44
'seqlocalam.c',
55
'seqlocalxlog.c',
66
'sequence.c',
7+
'sequenceamapi.c',
78
)

src/backend/access/sequence/seqlocalam.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
#include "access/htup_details.h"
1919
#include "access/multixact.h"
2020
#include "access/seqlocalam.h"
21+
#include "access/sequenceam.h"
2122
#include "access/xact.h"
2223
#include "access/xloginsert.h"
2324
#include "access/xlogutils.h"
2425
#include "catalog/storage_xlog.h"
2526
#include "commands/tablecmds.h"
2627
#include "miscadmin.h"
2728
#include "nodes/makefuncs.h"
29+
#include "utils/builtins.h"
2830

2931

3032
/*
@@ -230,10 +232,10 @@ fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
230232
* Allocate a new value for a local sequence, based on the sequence
231233
* configuration.
232234
*/
233-
int64
235+
static int64
234236
seq_local_nextval(Relation rel, int64 incby, int64 maxv,
235-
int64 minv, int64 cache, bool cycle,
236-
int64 *last)
237+
int64 minv, int64 cache, bool cycle,
238+
int64 *last)
237239
{
238240
int64 result;
239241
int64 fetch;
@@ -417,7 +419,7 @@ seq_local_nextval(Relation rel, int64 incby, int64 maxv,
417419
*
418420
* Return the table access method used by this sequence.
419421
*/
420-
const char *
422+
static const char *
421423
seq_local_get_table_am(void)
422424
{
423425
return "heap";
@@ -432,7 +434,7 @@ seq_local_get_table_am(void)
432434
* inserted after the relation has been created, filling in its heap
433435
* table.
434436
*/
435-
void
437+
static void
436438
seq_local_init(Relation rel, int64 last_value, bool is_called)
437439
{
438440
Datum value[SEQ_LOCAL_COL_LASTCOL];
@@ -499,7 +501,7 @@ seq_local_init(Relation rel, int64 last_value, bool is_called)
499501
*
500502
* Callback for setval().
501503
*/
502-
void
504+
static void
503505
seq_local_setval(Relation rel, int64 next, bool iscalled)
504506
{
505507
Buffer buf;
@@ -547,7 +549,7 @@ seq_local_setval(Relation rel, int64 next, bool iscalled)
547549
* Perform a hard reset on the local sequence, rewriting its heap data
548550
* entirely.
549551
*/
550-
void
552+
static void
551553
seq_local_reset(Relation rel, int64 startv, bool is_called, bool reset_state)
552554
{
553555
Form_pg_seq_local_data seq;
@@ -600,7 +602,7 @@ seq_local_reset(Relation rel, int64 startv, bool is_called, bool reset_state)
600602
*
601603
* Retrieve the state of a local sequence.
602604
*/
603-
void
605+
static void
604606
seq_local_get_state(Relation rel,
605607
int64 *last_value,
606608
bool *is_called,
@@ -627,7 +629,7 @@ seq_local_get_state(Relation rel,
627629
*
628630
* Persistence change for the local sequence Relation.
629631
*/
630-
void
632+
static void
631633
seq_local_change_persistence(Relation rel, char newrelpersistence)
632634
{
633635
Buffer buf;
@@ -638,3 +640,24 @@ seq_local_change_persistence(Relation rel, char newrelpersistence)
638640
fill_seq_with_data(rel, &seqdatatuple);
639641
UnlockReleaseBuffer(buf);
640642
}
643+
644+
/* ------------------------------------------------------------------------
645+
* Definition of the local sequence access method.
646+
* ------------------------------------------------------------------------
647+
*/
648+
static const SequenceAmRoutine seq_local_methods = {
649+
.type = T_SequenceAmRoutine,
650+
.get_table_am = seq_local_get_table_am,
651+
.init = seq_local_init,
652+
.nextval = seq_local_nextval,
653+
.setval = seq_local_setval,
654+
.reset = seq_local_reset,
655+
.get_state = seq_local_get_state,
656+
.change_persistence = seq_local_change_persistence
657+
};
658+
659+
Datum
660+
seq_local_sequenceam_handler(PG_FUNCTION_ARGS)
661+
{
662+
PG_RETURN_POINTER(&seq_local_methods);
663+
}

src/backend/access/sequence/sequence.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
*
1414
* NOTES
1515
* This file contains sequence_ routines that implement access to sequences
16-
* (in contrast to other relation types like indexes).
16+
* (in contrast to other relation types like indexes) that are independent
17+
* of individual sequence access methods.
1718
*
1819
*-------------------------------------------------------------------------
1920
*/
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* sequenceamapi.c
4+
* general sequence access method routines
5+
*
6+
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
*
10+
* IDENTIFICATION
11+
* src/backend/access/sequence/sequenceamapi.c
12+
*
13+
*
14+
* Sequence access method allows the SQL Standard Sequence objects to be
15+
* managed according to either the default access method or a pluggable
16+
* replacement. Each sequence can only use one access method at a time,
17+
* though different sequence access methods can be in use by different
18+
* sequences at the same time.
19+
*
20+
* -------------------------------------------------------------------------
21+
*/
22+
23+
#include "postgres.h"
24+
25+
#include "access/htup_details.h"
26+
#include "access/sequenceam.h"
27+
#include "access/xact.h"
28+
#include "catalog/pg_am.h"
29+
#include "commands/defrem.h"
30+
#include "miscadmin.h"
31+
#include "utils/guc_hooks.h"
32+
#include "utils/syscache.h"
33+
34+
35+
/* GUC */
36+
char *default_sequence_access_method = DEFAULT_SEQUENCE_ACCESS_METHOD;
37+
38+
/*
39+
* GetSequenceAmRoutine
40+
* Call the specified access method handler routine to get its
41+
* SequenceAmRoutine struct, which will be palloc'd in the caller's
42+
* memory context.
43+
*/
44+
const SequenceAmRoutine *
45+
GetSequenceAmRoutine(Oid amhandler)
46+
{
47+
Datum datum;
48+
SequenceAmRoutine *routine;
49+
50+
datum = OidFunctionCall0(amhandler);
51+
routine = (SequenceAmRoutine *) DatumGetPointer(datum);
52+
53+
if (routine == NULL || !IsA(routine, SequenceAmRoutine))
54+
elog(ERROR, "sequence access method handler %u did not return a SequenceAmRoutine struct",
55+
amhandler);
56+
57+
/*
58+
* Assert that all required callbacks are present. That makes it a bit
59+
* easier to keep AMs up to date, e.g. when forward porting them to a new
60+
* major version.
61+
*/
62+
Assert(routine->get_table_am != NULL);
63+
Assert(routine->init != NULL);
64+
Assert(routine->nextval != NULL);
65+
Assert(routine->setval != NULL);
66+
Assert(routine->reset != NULL);
67+
Assert(routine->get_state != NULL);
68+
Assert(routine->change_persistence != NULL);
69+
70+
return routine;
71+
}
72+
73+
/*
74+
* GetSequenceAmRoutineId
75+
* Call pg_am and retrieve the OID of the access method handler.
76+
*/
77+
Oid
78+
GetSequenceAmRoutineId(Oid amoid)
79+
{
80+
Oid amhandleroid;
81+
HeapTuple tuple;
82+
Form_pg_am aform;
83+
84+
tuple = SearchSysCache1(AMOID,
85+
ObjectIdGetDatum(amoid));
86+
if (!HeapTupleIsValid(tuple))
87+
elog(ERROR, "cache lookup failed for access method %u", amoid);
88+
aform = (Form_pg_am) GETSTRUCT(tuple);
89+
Assert(aform->amtype == AMTYPE_SEQUENCE);
90+
amhandleroid = aform->amhandler;
91+
ReleaseSysCache(tuple);
92+
93+
return amhandleroid;
94+
}
95+
96+
/* check_hook: validate new default_sequence_access_method */
97+
bool
98+
check_default_sequence_access_method(char **newval, void **extra,
99+
GucSource source)
100+
{
101+
if (**newval == '\0')
102+
{
103+
GUC_check_errdetail("%s cannot be empty.",
104+
"default_sequence_access_method");
105+
return false;
106+
}
107+
108+
if (strlen(*newval) >= NAMEDATALEN)
109+
{
110+
GUC_check_errdetail("%s is too long (maximum %d characters).",
111+
"default_sequence_access_method", NAMEDATALEN - 1);
112+
return false;
113+
}
114+
115+
/*
116+
* If we aren't inside a transaction, or not connected to a database, we
117+
* cannot do the catalog access necessary to verify the method. Must
118+
* accept the value on faith.
119+
*/
120+
if (IsTransactionState() && MyDatabaseId != InvalidOid)
121+
{
122+
if (!OidIsValid(get_sequence_am_oid(*newval, true)))
123+
{
124+
/*
125+
* When source == PGC_S_TEST, don't throw a hard error for a
126+
* nonexistent sequence access method, only a NOTICE. See comments
127+
* in guc.h.
128+
*/
129+
if (source == PGC_S_TEST)
130+
{
131+
ereport(NOTICE,
132+
(errcode(ERRCODE_UNDEFINED_OBJECT),
133+
errmsg("sequence access method \"%s\" does not exist",
134+
*newval)));
135+
}
136+
else
137+
{
138+
GUC_check_errdetail("sequence access method \"%s\" does not exist.",
139+
*newval);
140+
return false;
141+
}
142+
}
143+
}
144+
145+
return true;
146+
}

src/backend/catalog/heap.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1490,9 +1490,13 @@ heap_create_with_catalog(const char *relname,
14901490
* No need to add an explicit dependency for the toast table, as the
14911491
* main table depends on it. Partitioned tables may not have an
14921492
* access method set.
1493+
*
1494+
* Sequences and tables are created with their access method ID
1495+
* given by the caller of this function.
14931496
*/
14941497
if ((RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE) ||
1495-
(relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)))
1498+
(relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)) ||
1499+
RELKIND_HAS_SEQUENCE_AM(relkind))
14961500
{
14971501
ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
14981502
add_exact_object_address(&referenced, addrs);

src/backend/commands/amcmds.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "access/htup_details.h"
1717
#include "access/table.h"
18+
#include "access/sequenceam.h"
1819
#include "catalog/catalog.h"
1920
#include "catalog/dependency.h"
2021
#include "catalog/indexing.h"
@@ -175,6 +176,16 @@ get_table_am_oid(const char *amname, bool missing_ok)
175176
return get_am_type_oid(amname, AMTYPE_TABLE, missing_ok);
176177
}
177178

179+
/*
180+
* get_sequence_am_oid - given an access method name, look up its OID
181+
* and verify it corresponds to an sequence AM.
182+
*/
183+
Oid
184+
get_sequence_am_oid(const char *amname, bool missing_ok)
185+
{
186+
return get_am_type_oid(amname, AMTYPE_SEQUENCE, missing_ok);
187+
}
188+
178189
/*
179190
* get_am_oid - given an access method name, look up its OID.
180191
* The type is not checked.
@@ -215,6 +226,8 @@ get_am_type_string(char amtype)
215226
{
216227
case AMTYPE_INDEX:
217228
return "INDEX";
229+
case AMTYPE_SEQUENCE:
230+
return "SEQUENCE";
218231
case AMTYPE_TABLE:
219232
return "TABLE";
220233
default:
@@ -251,6 +264,9 @@ lookup_am_handler_func(List *handler_name, char amtype)
251264
case AMTYPE_INDEX:
252265
expectedType = INDEX_AM_HANDLEROID;
253266
break;
267+
case AMTYPE_SEQUENCE:
268+
expectedType = SEQUENCE_AM_HANDLEROID;
269+
break;
254270
case AMTYPE_TABLE:
255271
expectedType = TABLE_AM_HANDLEROID;
256272
break;

0 commit comments

Comments
 (0)