PostgreSQL Source Code git master
amcmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * amcmds.c
4 * Routines for SQL commands that manipulate access methods.
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/commands/amcmds.c
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/htup_details.h"
17#include "access/table.h"
18#include "catalog/catalog.h"
19#include "catalog/dependency.h"
20#include "catalog/indexing.h"
22#include "catalog/pg_am.h"
23#include "catalog/pg_proc.h"
24#include "catalog/pg_type.h"
25#include "commands/defrem.h"
26#include "miscadmin.h"
27#include "parser/parse_func.h"
28#include "utils/builtins.h"
29#include "utils/lsyscache.h"
30#include "utils/rel.h"
31#include "utils/syscache.h"
32
33
34static Oid lookup_am_handler_func(List *handler_name, char amtype);
35static const char *get_am_type_string(char amtype);
36
37
38/*
39 * CreateAccessMethod
40 * Registers a new access method.
41 */
44{
45 Relation rel;
46 ObjectAddress myself;
47 ObjectAddress referenced;
48 Oid amoid;
49 Oid amhandler;
50 bool nulls[Natts_pg_am];
51 Datum values[Natts_pg_am];
52 HeapTuple tup;
53
54 rel = table_open(AccessMethodRelationId, RowExclusiveLock);
55
56 /* Must be superuser */
57 if (!superuser())
59 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
60 errmsg("permission denied to create access method \"%s\"",
61 stmt->amname),
62 errhint("Must be superuser to create an access method.")));
63
64 /* Check if name is used */
65 amoid = GetSysCacheOid1(AMNAME, Anum_pg_am_oid,
66 CStringGetDatum(stmt->amname));
67 if (OidIsValid(amoid))
68 {
71 errmsg("access method \"%s\" already exists",
72 stmt->amname)));
73 }
74
75 /*
76 * Get the handler function oid, verifying the AM type while at it.
77 */
78 amhandler = lookup_am_handler_func(stmt->handler_name, stmt->amtype);
79
80 /*
81 * Insert tuple into pg_am.
82 */
83 memset(values, 0, sizeof(values));
84 memset(nulls, false, sizeof(nulls));
85
86 amoid = GetNewOidWithIndex(rel, AmOidIndexId, Anum_pg_am_oid);
87 values[Anum_pg_am_oid - 1] = ObjectIdGetDatum(amoid);
88 values[Anum_pg_am_amname - 1] =
90 values[Anum_pg_am_amhandler - 1] = ObjectIdGetDatum(amhandler);
91 values[Anum_pg_am_amtype - 1] = CharGetDatum(stmt->amtype);
92
93 tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
94
95 CatalogTupleInsert(rel, tup);
96 heap_freetuple(tup);
97
98 myself.classId = AccessMethodRelationId;
99 myself.objectId = amoid;
100 myself.objectSubId = 0;
101
102 /* Record dependency on handler function */
103 referenced.classId = ProcedureRelationId;
104 referenced.objectId = amhandler;
105 referenced.objectSubId = 0;
106
107 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
108
110
111 InvokeObjectPostCreateHook(AccessMethodRelationId, amoid, 0);
112
114
115 return myself;
116}
117
118/*
119 * get_am_type_oid
120 * Worker for various get_am_*_oid variants
121 *
122 * If missing_ok is false, throw an error if access method not found. If
123 * true, just return InvalidOid.
124 *
125 * If amtype is not '\0', an error is raised if the AM found is not of the
126 * given type.
127 */
128static Oid
129get_am_type_oid(const char *amname, char amtype, bool missing_ok)
130{
131 HeapTuple tup;
132 Oid oid = InvalidOid;
133
134 tup = SearchSysCache1(AMNAME, CStringGetDatum(amname));
135 if (HeapTupleIsValid(tup))
136 {
137 Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
138
139 if (amtype != '\0' &&
140 amform->amtype != amtype)
142 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
143 errmsg("access method \"%s\" is not of type %s",
144 NameStr(amform->amname),
145 get_am_type_string(amtype))));
146
147 oid = amform->oid;
148 ReleaseSysCache(tup);
149 }
150
151 if (!OidIsValid(oid) && !missing_ok)
153 (errcode(ERRCODE_UNDEFINED_OBJECT),
154 errmsg("access method \"%s\" does not exist", amname)));
155 return oid;
156}
157
158/*
159 * get_index_am_oid - given an access method name, look up its OID
160 * and verify it corresponds to an index AM.
161 */
162Oid
163get_index_am_oid(const char *amname, bool missing_ok)
164{
165 return get_am_type_oid(amname, AMTYPE_INDEX, missing_ok);
166}
167
168/*
169 * get_table_am_oid - given an access method name, look up its OID
170 * and verify it corresponds to a table AM.
171 */
172Oid
173get_table_am_oid(const char *amname, bool missing_ok)
174{
175 return get_am_type_oid(amname, AMTYPE_TABLE, missing_ok);
176}
177
178/*
179 * get_am_oid - given an access method name, look up its OID.
180 * The type is not checked.
181 */
182Oid
183get_am_oid(const char *amname, bool missing_ok)
184{
185 return get_am_type_oid(amname, '\0', missing_ok);
186}
187
188/*
189 * get_am_name - given an access method OID, look up its name.
190 */
191char *
193{
194 HeapTuple tup;
195 char *result = NULL;
196
197 tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
198 if (HeapTupleIsValid(tup))
199 {
200 Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
201
202 result = pstrdup(NameStr(amform->amname));
203 ReleaseSysCache(tup);
204 }
205 return result;
206}
207
208/*
209 * Convert single-character access method type into string for error reporting.
210 */
211static const char *
213{
214 switch (amtype)
215 {
216 case AMTYPE_INDEX:
217 return "INDEX";
218 case AMTYPE_TABLE:
219 return "TABLE";
220 default:
221 /* shouldn't happen */
222 elog(ERROR, "invalid access method type '%c'", amtype);
223 return NULL; /* keep compiler quiet */
224 }
225}
226
227/*
228 * Convert a handler function name to an Oid. If the return type of the
229 * function doesn't match the given AM type, an error is raised.
230 *
231 * This function either return valid function Oid or throw an error.
232 */
233static Oid
234lookup_am_handler_func(List *handler_name, char amtype)
235{
236 Oid handlerOid;
237 Oid funcargtypes[1] = {INTERNALOID};
238 Oid expectedType = InvalidOid;
239
240 if (handler_name == NIL)
242 (errcode(ERRCODE_UNDEFINED_FUNCTION),
243 errmsg("handler function is not specified")));
244
245 /* handlers have one argument of type internal */
246 handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false);
247
248 /* check that handler has the correct return type */
249 switch (amtype)
250 {
251 case AMTYPE_INDEX:
252 expectedType = INDEX_AM_HANDLEROID;
253 break;
254 case AMTYPE_TABLE:
255 expectedType = TABLE_AM_HANDLEROID;
256 break;
257 default:
258 elog(ERROR, "unrecognized access method type \"%c\"", amtype);
259 }
260
261 if (get_func_rettype(handlerOid) != expectedType)
263 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
264 errmsg("function %s must return type %s",
265 get_func_name(handlerOid),
266 format_type_extended(expectedType, -1, 0))));
267
268 return handlerOid;
269}
ObjectAddress CreateAccessMethod(CreateAmStmt *stmt)
Definition: amcmds.c:43
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:173
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:163
static const char * get_am_type_string(char amtype)
Definition: amcmds.c:212
char * get_am_name(Oid amOid)
Definition: amcmds.c:192
static Oid get_am_type_oid(const char *amname, char amtype, bool missing_ok)
Definition: amcmds.c:129
Oid get_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:183
static Oid lookup_am_handler_func(List *handler_name, char amtype)
Definition: amcmds.c:234
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define NameStr(name)
Definition: c.h:703
#define OidIsValid(objectId)
Definition: c.h:732
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
char * format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
Definition: format_type.c:112
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define stmt
Definition: indent_codes.h:59
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1635
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1682
char * pstrdup(const char *in)
Definition: mcxt.c:1696
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2144
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
#define NIL
Definition: pg_list.h:68
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:538
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
Definition: pg_list.h:54
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40