Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 165009a

Browse files
michaelpqCommitfest Bot
authored and
Commitfest Bot
committed
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 e43ebff commit 165009a

40 files changed

+695
-182
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
@@ -17,13 +17,15 @@
1717

1818
#include "access/multixact.h"
1919
#include "access/seqlocalam.h"
20+
#include "access/sequenceam.h"
2021
#include "access/xact.h"
2122
#include "access/xloginsert.h"
2223
#include "access/xlogutils.h"
2324
#include "catalog/storage_xlog.h"
2425
#include "commands/tablecmds.h"
2526
#include "miscadmin.h"
2627
#include "nodes/makefuncs.h"
28+
#include "utils/builtins.h"
2729

2830

2931
/*
@@ -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, int64 *last_value, bool *is_called)
605607
{
606608
Buffer buf;
@@ -621,7 +623,7 @@ seq_local_get_state(Relation rel, int64 *last_value, bool *is_called)
621623
*
622624
* Persistence change for the local sequence Relation.
623625
*/
624-
void
626+
static void
625627
seq_local_change_persistence(Relation rel, char newrelpersistence)
626628
{
627629
Buffer buf;
@@ -632,3 +634,24 @@ seq_local_change_persistence(Relation rel, char newrelpersistence)
632634
fill_seq_with_data(rel, &seqdatatuple);
633635
UnlockReleaseBuffer(buf);
634636
}
637+
638+
/* ------------------------------------------------------------------------
639+
* Definition of the local sequence access method.
640+
* ------------------------------------------------------------------------
641+
*/
642+
static const SequenceAmRoutine seq_local_methods = {
643+
.type = T_SequenceAmRoutine,
644+
.get_table_am = seq_local_get_table_am,
645+
.init = seq_local_init,
646+
.nextval = seq_local_nextval,
647+
.setval = seq_local_setval,
648+
.reset = seq_local_reset,
649+
.get_state = seq_local_get_state,
650+
.change_persistence = seq_local_change_persistence
651+
};
652+
653+
Datum
654+
seq_local_sequenceam_handler(PG_FUNCTION_ARGS)
655+
{
656+
PG_RETURN_POINTER(&seq_local_methods);
657+
}

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

src/backend/catalog/heap.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1480,9 +1480,13 @@ heap_create_with_catalog(const char *relname,
14801480
* No need to add an explicit dependency for the toast table, as the
14811481
* main table depends on it. Partitioned tables may not have an
14821482
* access method set.
1483+
*
1484+
* Sequences and tables are created with their access method ID
1485+
* given by the caller of this function.
14831486
*/
14841487
if ((RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE) ||
1485-
(relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)))
1488+
(relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)) ||
1489+
RELKIND_HAS_SEQUENCE_AM(relkind))
14861490
{
14871491
ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
14881492
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)