PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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/heapam.h"
17 #include "access/htup_details.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_am.h"
21 #include "catalog/pg_proc.h"
22 #include "catalog/pg_type.h"
23 #include "commands/defrem.h"
24 #include "miscadmin.h"
25 #include "parser/parse_func.h"
26 #include "utils/builtins.h"
27 #include "utils/lsyscache.h"
28 #include "utils/rel.h"
29 #include "utils/syscache.h"
30 
31 
32 static Oid lookup_index_am_handler_func(List *handler_name, char amtype);
33 static const char *get_am_type_string(char amtype);
34 
35 
36 /*
37  * CreateAccessMethod
38  * Registers a new access method.
39  */
42 {
43  Relation rel;
44  ObjectAddress myself;
45  ObjectAddress referenced;
46  Oid amoid;
47  Oid amhandler;
48  bool nulls[Natts_pg_am];
50  HeapTuple tup;
51 
53 
54  /* Must be super user */
55  if (!superuser())
56  ereport(ERROR,
57  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
58  errmsg("permission denied to create access method \"%s\"",
59  stmt->amname),
60  errhint("Must be superuser to create an access method.")));
61 
62  /* Check if name is used */
64  if (OidIsValid(amoid))
65  {
66  ereport(ERROR,
68  errmsg("access method \"%s\" already exists",
69  stmt->amname)));
70  }
71 
72  /*
73  * Get the handler function oid, verifying the AM type while at it.
74  */
75  amhandler = lookup_index_am_handler_func(stmt->handler_name, stmt->amtype);
76 
77  /*
78  * Insert tuple into pg_am.
79  */
80  memset(values, 0, sizeof(values));
81  memset(nulls, false, sizeof(nulls));
82 
83  values[Anum_pg_am_amname - 1] =
85  values[Anum_pg_am_amhandler - 1] = ObjectIdGetDatum(amhandler);
86  values[Anum_pg_am_amtype - 1] = CharGetDatum(stmt->amtype);
87 
88  tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
89 
90  amoid = CatalogTupleInsert(rel, tup);
91  heap_freetuple(tup);
92 
94  myself.objectId = amoid;
95  myself.objectSubId = 0;
96 
97  /* Record dependency on handler function */
98  referenced.classId = ProcedureRelationId;
99  referenced.objectId = amhandler;
100  referenced.objectSubId = 0;
101 
102  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
103 
104  recordDependencyOnCurrentExtension(&myself, false);
105 
107 
108  return myself;
109 }
110 
111 /*
112  * Guts of access method deletion.
113  */
114 void
116 {
117  Relation relation;
118  HeapTuple tup;
119 
120  if (!superuser())
121  ereport(ERROR,
122  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
123  errmsg("must be superuser to drop access methods")));
124 
126 
127  tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
128  if (!HeapTupleIsValid(tup))
129  elog(ERROR, "cache lookup failed for access method %u", amOid);
130 
131  CatalogTupleDelete(relation, &tup->t_self);
132 
133  ReleaseSysCache(tup);
134 
135  heap_close(relation, RowExclusiveLock);
136 }
137 
138 /*
139  * get_am_type_oid
140  * Worker for various get_am_*_oid variants
141  *
142  * If missing_ok is false, throw an error if access method not found. If
143  * true, just return InvalidOid.
144  *
145  * If amtype is not '\0', an error is raised if the AM found is not of the
146  * given type.
147  */
148 static Oid
149 get_am_type_oid(const char *amname, char amtype, bool missing_ok)
150 {
151  HeapTuple tup;
152  Oid oid = InvalidOid;
153 
154  tup = SearchSysCache1(AMNAME, CStringGetDatum(amname));
155  if (HeapTupleIsValid(tup))
156  {
157  Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
158 
159  if (amtype != '\0' &&
160  amform->amtype != amtype)
161  ereport(ERROR,
162  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
163  errmsg("access method \"%s\" is not of type %s",
164  NameStr(amform->amname),
165  get_am_type_string(amtype))));
166 
167  oid = HeapTupleGetOid(tup);
168  ReleaseSysCache(tup);
169  }
170 
171  if (!OidIsValid(oid) && !missing_ok)
172  ereport(ERROR,
173  (errcode(ERRCODE_UNDEFINED_OBJECT),
174  errmsg("access method \"%s\" does not exist", amname)));
175  return oid;
176 }
177 
178 /*
179  * get_index_am_oid - given an access method name, look up its OID
180  * and verify it corresponds to an index AM.
181  */
182 Oid
183 get_index_am_oid(const char *amname, bool missing_ok)
184 {
185  return get_am_type_oid(amname, AMTYPE_INDEX, missing_ok);
186 }
187 
188 /*
189  * get_am_oid - given an access method name, look up its OID.
190  * The type is not checked.
191  */
192 Oid
193 get_am_oid(const char *amname, bool missing_ok)
194 {
195  return get_am_type_oid(amname, '\0', missing_ok);
196 }
197 
198 /*
199  * get_am_name - given an access method OID name and type, look up its name.
200  */
201 char *
203 {
204  HeapTuple tup;
205  char *result = NULL;
206 
207  tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
208  if (HeapTupleIsValid(tup))
209  {
210  Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
211 
212  result = pstrdup(NameStr(amform->amname));
213  ReleaseSysCache(tup);
214  }
215  return result;
216 }
217 
218 /*
219  * Convert single-character access method type into string for error reporting.
220  */
221 static const char *
222 get_am_type_string(char amtype)
223 {
224  switch (amtype)
225  {
226  case AMTYPE_INDEX:
227  return "INDEX";
228  default:
229  /* shouldn't happen */
230  elog(ERROR, "invalid access method type '%c'", amtype);
231  return NULL; /* keep compiler quiet */
232  }
233 }
234 
235 /*
236  * Convert a handler function name to an Oid. If the return type of the
237  * function doesn't match the given AM type, an error is raised.
238  *
239  * This function either return valid function Oid or throw an error.
240  */
241 static Oid
242 lookup_index_am_handler_func(List *handler_name, char amtype)
243 {
244  Oid handlerOid;
245  static const Oid funcargtypes[1] = {INTERNALOID};
246 
247  if (handler_name == NIL)
248  ereport(ERROR,
249  (errcode(ERRCODE_UNDEFINED_FUNCTION),
250  errmsg("handler function is not specified")));
251 
252  /* handlers have one argument of type internal */
253  handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false);
254 
255  /* check that handler has the correct return type */
256  switch (amtype)
257  {
258  case AMTYPE_INDEX:
259  if (get_func_rettype(handlerOid) != INDEX_AM_HANDLEROID)
260  ereport(ERROR,
261  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
262  errmsg("function %s must return type %s",
263  NameListToString(handler_name),
264  "index_am_handler")));
265  break;
266  default:
267  elog(ERROR, "unrecognized access method type \"%c\"", amtype);
268  }
269 
270  return handlerOid;
271 }
#define NIL
Definition: pg_list.h:69
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
static const char * get_am_type_string(char amtype)
Definition: amcmds.c:222
Oid get_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:193
Definition: syscache.h:36
#define RelationGetDescr(relation)
Definition: rel.h:428
#define ProcedureRelationId
Definition: pg_proc.h:33
char * pstrdup(const char *in)
Definition: mcxt.c:1077
static Oid get_am_type_oid(const char *amname, char amtype, bool missing_ok)
Definition: amcmds.c:149
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define INDEX_AM_HANDLEROID
Definition: pg_type.h:710
return result
Definition: formatting.c:1633
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:584
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
void RemoveAccessMethodById(Oid amOid)
Definition: amcmds.c:115
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1459
#define GetSysCacheOid1(cacheId, key1)
Definition: syscache.h:183
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
char * amname
Definition: parsenodes.h:2334
ItemPointerData t_self
Definition: htup.h:65
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:183
#define AccessMethodRelationId
Definition: pg_am.h:32
char * get_am_name(Oid amOid)
Definition: amcmds.c:202
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:584
static Oid lookup_index_am_handler_func(List *handler_name, char amtype)
Definition: amcmds.c:242
#define ereport(elevel, rest)
Definition: elog.h:122
#define Anum_pg_am_amtype
Definition: pg_am.h:55
#define AMTYPE_INDEX
Definition: pg_am.h:61
char * NameListToString(List *names)
Definition: namespace.c:3063
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
List * handler_name
Definition: parsenodes.h:2335
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define InvalidOid
Definition: postgres_ext.h:36
#define INTERNALOID
Definition: pg_type.h:698
#define Anum_pg_am_amhandler
Definition: pg_am.h:54
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:139
#define Natts_pg_am
Definition: pg_am.h:52
#define CharGetDatum(X)
Definition: postgres.h:422
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1929
static Datum values[MAXATTR]
Definition: bootstrap.c:163
FormData_pg_am * Form_pg_am
Definition: pg_am.h:46
#define Anum_pg_am_amname
Definition: pg_am.h:53
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:499
ObjectAddress CreateAccessMethod(CreateAmStmt *stmt)
Definition: amcmds.c:41
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: pg_list.h:45