Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * amapi.c
4 : : * Support routines for API for Postgres index access methods.
5 : : *
6 : : * Copyright (c) 2015-2024, 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/fmgrprotos.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 *
3010 tgl@sss.pgh.pa.us 33 :CBC 1412990 : GetIndexAmRoutine(Oid amhandler)
34 : : {
35 : : Datum datum;
36 : : IndexAmRoutine *routine;
37 : :
38 : 1412990 : datum = OidFunctionCall0(amhandler);
39 : 1412990 : routine = (IndexAmRoutine *) DatumGetPointer(datum);
40 : :
41 [ + - - + ]: 1412990 : if (routine == NULL || !IsA(routine, IndexAmRoutine))
3010 tgl@sss.pgh.pa.us 42 [ # # ]:UBC 0 : elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
43 : : amhandler);
44 : :
3010 tgl@sss.pgh.pa.us 45 :CBC 1412990 : 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 *
2801 56 : 95907 : 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 */
3010 63 : 95907 : tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
64 [ - + ]: 95907 : if (!HeapTupleIsValid(tuple))
65 : : {
2801 tgl@sss.pgh.pa.us 66 [ # # ]:UBC 0 : if (noerror)
67 : 0 : return NULL;
3010 68 [ # # ]: 0 : elog(ERROR, "cache lookup failed for access method %u",
69 : : amoid);
70 : : }
3010 tgl@sss.pgh.pa.us 71 :CBC 95907 : amform = (Form_pg_am) GETSTRUCT(tuple);
72 : :
73 : : /* Check if it's an index access method as opposed to some other AM */
2944 alvherre@alvh.no-ip. 74 [ - + ]: 95907 : if (amform->amtype != AMTYPE_INDEX)
75 : : {
2801 tgl@sss.pgh.pa.us 76 [ # # ]:UBC 0 : if (noerror)
77 : : {
78 : 0 : ReleaseSysCache(tuple);
79 : 0 : return NULL;
80 : : }
2944 alvherre@alvh.no-ip. 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 : :
3010 tgl@sss.pgh.pa.us 87 :CBC 95907 : amhandler = amform->amhandler;
88 : :
89 : : /* Complain if handler OID is invalid */
90 [ - + ]: 95907 : if (!RegProcedureIsValid(amhandler))
91 : : {
2801 tgl@sss.pgh.pa.us 92 [ # # ]:UBC 0 : if (noerror)
93 : : {
94 : 0 : ReleaseSysCache(tuple);
95 : 0 : return NULL;
96 : : }
3010 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 : :
3010 tgl@sss.pgh.pa.us 103 :CBC 95907 : ReleaseSysCache(tuple);
104 : :
105 : : /* And finally, call the handler function to get the API struct. */
106 : 95907 : return GetIndexAmRoutine(amhandler);
107 : : }
108 : :
109 : :
110 : : /*
111 : : * Ask appropriate access method to validate the specified opclass.
112 : : */
113 : : Datum
114 : 632 : amvalidate(PG_FUNCTION_ARGS)
115 : : {
116 : 632 : 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 : 632 : classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
124 [ - + ]: 632 : if (!HeapTupleIsValid(classtup))
3010 tgl@sss.pgh.pa.us 125 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
3010 tgl@sss.pgh.pa.us 126 :CBC 632 : classform = (Form_pg_opclass) GETSTRUCT(classtup);
127 : :
128 : 632 : amoid = classform->opcmethod;
129 : :
130 : 632 : ReleaseSysCache(classtup);
131 : :
2801 132 : 632 : amroutine = GetIndexAmRoutineByAmId(amoid, false);
133 : :
3010 134 [ - + ]: 632 : if (amroutine->amvalidate == NULL)
3010 tgl@sss.pgh.pa.us 135 [ # # ]:UBC 0 : elog(ERROR, "function amvalidate is not defined for index access method %u",
136 : : amoid);
137 : :
3010 tgl@sss.pgh.pa.us 138 :CBC 632 : result = amroutine->amvalidate(opclassoid);
139 : :
140 : 632 : pfree(amroutine);
141 : :
142 : 632 : PG_RETURN_BOOL(result);
143 : : }
|