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 * 33 2870566 : GetIndexAmRoutine(Oid amhandler) 34 : { 35 : Datum datum; 36 : IndexAmRoutine *routine; 37 : 38 2870566 : datum = OidFunctionCall0(amhandler); 39 2870566 : routine = (IndexAmRoutine *) DatumGetPointer(datum); 40 : 41 2870566 : 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 2870566 : 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 49664 : 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 49664 : tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid)); 64 49664 : 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 49664 : amform = (Form_pg_am) GETSTRUCT(tuple); 72 : 73 : /* Check if it's an index access method as opposed to some other AM */ 74 49664 : 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 49664 : amhandler = amform->amhandler; 88 : 89 : /* Complain if handler OID is invalid */ 90 49664 : 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 49664 : ReleaseSysCache(tuple); 104 : 105 : /* And finally, call the handler function to get the API struct. */ 106 49664 : return GetIndexAmRoutine(amhandler); 107 : } 108 : 109 : 110 : /* 111 : * Ask appropriate access method to validate the specified opclass. 112 : */ 113 : Datum 114 1264 : amvalidate(PG_FUNCTION_ARGS) 115 : { 116 1264 : 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 1264 : classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid)); 124 1264 : if (!HeapTupleIsValid(classtup)) 125 0 : elog(ERROR, "cache lookup failed for operator class %u", opclassoid); 126 1264 : classform = (Form_pg_opclass) GETSTRUCT(classtup); 127 : 128 1264 : amoid = classform->opcmethod; 129 : 130 1264 : ReleaseSysCache(classtup); 131 : 132 1264 : amroutine = GetIndexAmRoutineByAmId(amoid, false); 133 : 134 1264 : if (amroutine->amvalidate == NULL) 135 0 : elog(ERROR, "function amvalidate is not defined for index access method %u", 136 : amoid); 137 : 138 1264 : result = amroutine->amvalidate(opclassoid); 139 : 140 1264 : pfree(amroutine); 141 : 142 1264 : PG_RETURN_BOOL(result); 143 : }