Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * amapi.c
4 : * Support routines for API for Postgres index access methods.
5 : *
6 : * Copyright (c) 2015-2017, PostgreSQL Global Development Group
7 : *
8 : *
9 : * IDENTIFICATION
10 : * src/backend/access/index/amapi.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 : #include "postgres.h"
15 :
16 : #include "access/amapi.h"
17 : #include "access/htup_details.h"
18 : #include "catalog/pg_am.h"
19 : #include "catalog/pg_opclass.h"
20 : #include "utils/builtins.h"
21 : #include "utils/syscache.h"
22 :
23 :
24 : /*
25 : * GetIndexAmRoutine - call the specified access method handler routine to get
26 : * its IndexAmRoutine struct, which will be palloc'd in the caller's context.
27 : *
28 : * Note that if the amhandler function is built-in, this will not involve
29 : * any catalog access. It's therefore safe to use this while bootstrapping
30 : * indexes for the system catalogs. relcache.c relies on that.
31 : */
32 : IndexAmRoutine *
33 35579 : GetIndexAmRoutine(Oid amhandler)
34 : {
35 : Datum datum;
36 : IndexAmRoutine *routine;
37 :
38 35579 : datum = OidFunctionCall0(amhandler);
39 35579 : routine = (IndexAmRoutine *) DatumGetPointer(datum);
40 :
41 35579 : if (routine == NULL || !IsA(routine, IndexAmRoutine))
42 0 : elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
43 : amhandler);
44 :
45 35579 : return routine;
46 : }
47 :
48 : /*
49 : * GetIndexAmRoutineByAmId - look up the handler of the index access method
50 : * with the given OID, and get its IndexAmRoutine struct.
51 : *
52 : * If the given OID isn't a valid index access method, returns NULL if
53 : * noerror is true, else throws error.
54 : */
55 : IndexAmRoutine *
56 1830 : GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
57 : {
58 : HeapTuple tuple;
59 : Form_pg_am amform;
60 : regproc amhandler;
61 :
62 : /* Get handler function OID for the access method */
63 1830 : tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
64 1830 : if (!HeapTupleIsValid(tuple))
65 : {
66 0 : if (noerror)
67 0 : return NULL;
68 0 : elog(ERROR, "cache lookup failed for access method %u",
69 : amoid);
70 : }
71 1830 : amform = (Form_pg_am) GETSTRUCT(tuple);
72 :
73 : /* Check if it's an index access method as opposed to some other AM */
74 1830 : if (amform->amtype != AMTYPE_INDEX)
75 : {
76 0 : if (noerror)
77 : {
78 0 : ReleaseSysCache(tuple);
79 0 : return NULL;
80 : }
81 0 : ereport(ERROR,
82 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
83 : errmsg("access method \"%s\" is not of type %s",
84 : NameStr(amform->amname), "INDEX")));
85 : }
86 :
87 1830 : amhandler = amform->amhandler;
88 :
89 : /* Complain if handler OID is invalid */
90 1830 : if (!RegProcedureIsValid(amhandler))
91 : {
92 0 : if (noerror)
93 : {
94 0 : ReleaseSysCache(tuple);
95 0 : return NULL;
96 : }
97 0 : ereport(ERROR,
98 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
99 : errmsg("index access method \"%s\" does not have a handler",
100 : NameStr(amform->amname))));
101 : }
102 :
103 1830 : ReleaseSysCache(tuple);
104 :
105 : /* And finally, call the handler function to get the API struct. */
106 1830 : return GetIndexAmRoutine(amhandler);
107 : }
108 :
109 :
110 : /*
111 : * Ask appropriate access method to validate the specified opclass.
112 : */
113 : Datum
114 133 : amvalidate(PG_FUNCTION_ARGS)
115 : {
116 133 : Oid opclassoid = PG_GETARG_OID(0);
117 : bool result;
118 : HeapTuple classtup;
119 : Form_pg_opclass classform;
120 : Oid amoid;
121 : IndexAmRoutine *amroutine;
122 :
123 133 : classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
124 133 : if (!HeapTupleIsValid(classtup))
125 0 : elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
126 133 : classform = (Form_pg_opclass) GETSTRUCT(classtup);
127 :
128 133 : amoid = classform->opcmethod;
129 :
130 133 : ReleaseSysCache(classtup);
131 :
132 133 : amroutine = GetIndexAmRoutineByAmId(amoid, false);
133 :
134 133 : if (amroutine->amvalidate == NULL)
135 0 : elog(ERROR, "function amvalidate is not defined for index access method %u",
136 : amoid);
137 :
138 133 : result = amroutine->amvalidate(opclassoid);
139 :
140 133 : pfree(amroutine);
141 :
142 133 : PG_RETURN_BOOL(result);
143 : }
|