LCOV - code coverage report
Current view: top level - src/backend/access/index - amapi.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 62.3 % 61 38
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * amapi.c
       4              :  *    Support routines for API for Postgres index access methods.
       5              :  *
       6              :  * Copyright (c) 2015-2026, 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 we expect to be statically allocated.
      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              : const IndexAmRoutine *
      33      1795057 : GetIndexAmRoutine(Oid amhandler)
      34              : {
      35              :     Datum       datum;
      36              :     const IndexAmRoutine *routine;
      37              : 
      38      1795057 :     datum = OidFunctionCall0(amhandler);
      39      1795057 :     routine = (const IndexAmRoutine *) DatumGetPointer(datum);
      40              : 
      41      1795057 :     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              :     /* Assert that all required callbacks are present. */
      46              :     Assert(routine->ambuild != NULL);
      47              :     Assert(routine->ambuildempty != NULL);
      48              :     Assert(routine->aminsert != NULL);
      49              :     Assert(routine->ambulkdelete != NULL);
      50              :     Assert(routine->amvacuumcleanup != NULL);
      51              :     Assert(routine->amcostestimate != NULL);
      52              :     Assert(routine->amoptions != NULL);
      53              :     Assert(routine->amvalidate != NULL);
      54              :     Assert(routine->ambeginscan != NULL);
      55              :     Assert(routine->amrescan != NULL);
      56              :     Assert(routine->amendscan != NULL);
      57              : 
      58      1795057 :     return routine;
      59              : }
      60              : 
      61              : /*
      62              :  * GetIndexAmRoutineByAmId - look up the handler of the index access method
      63              :  * with the given OID, and get its IndexAmRoutine struct.
      64              :  *
      65              :  * If the given OID isn't a valid index access method, returns NULL if
      66              :  * noerror is true, else throws error.
      67              :  */
      68              : const IndexAmRoutine *
      69        93957 : GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
      70              : {
      71              :     HeapTuple   tuple;
      72              :     Form_pg_am  amform;
      73              :     regproc     amhandler;
      74              : 
      75              :     /* Get handler function OID for the access method */
      76        93957 :     tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
      77        93957 :     if (!HeapTupleIsValid(tuple))
      78              :     {
      79            0 :         if (noerror)
      80            0 :             return NULL;
      81            0 :         elog(ERROR, "cache lookup failed for access method %u",
      82              :              amoid);
      83              :     }
      84        93957 :     amform = (Form_pg_am) GETSTRUCT(tuple);
      85              : 
      86              :     /* Check if it's an index access method as opposed to some other AM */
      87        93957 :     if (amform->amtype != AMTYPE_INDEX)
      88              :     {
      89            0 :         if (noerror)
      90              :         {
      91            0 :             ReleaseSysCache(tuple);
      92            0 :             return NULL;
      93              :         }
      94            0 :         ereport(ERROR,
      95              :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
      96              :                  errmsg("access method \"%s\" is not of type %s",
      97              :                         NameStr(amform->amname), "INDEX")));
      98              :     }
      99              : 
     100        93957 :     amhandler = amform->amhandler;
     101              : 
     102              :     /* Complain if handler OID is invalid */
     103        93957 :     if (!RegProcedureIsValid(amhandler))
     104              :     {
     105            0 :         if (noerror)
     106              :         {
     107            0 :             ReleaseSysCache(tuple);
     108            0 :             return NULL;
     109              :         }
     110            0 :         ereport(ERROR,
     111              :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     112              :                  errmsg("index access method \"%s\" does not have a handler",
     113              :                         NameStr(amform->amname))));
     114              :     }
     115              : 
     116        93957 :     ReleaseSysCache(tuple);
     117              : 
     118              :     /* And finally, call the handler function to get the API struct. */
     119        93957 :     return GetIndexAmRoutine(amhandler);
     120              : }
     121              : 
     122              : 
     123              : /*
     124              :  * IndexAmTranslateStrategy - given an access method and strategy, get the
     125              :  * corresponding compare type.
     126              :  *
     127              :  * If missing_ok is false, throw an error if no compare type is found.  If
     128              :  * true, just return COMPARE_INVALID.
     129              :  */
     130              : CompareType
     131      1670983 : IndexAmTranslateStrategy(StrategyNumber strategy, Oid amoid, Oid opfamily, bool missing_ok)
     132              : {
     133              :     CompareType result;
     134              :     const IndexAmRoutine *amroutine;
     135              : 
     136              :     /* shortcut for common case */
     137      1670983 :     if (amoid == BTREE_AM_OID &&
     138      1670983 :         (strategy > InvalidStrategy && strategy <= BTMaxStrategyNumber))
     139      1670983 :         return (CompareType) strategy;
     140              : 
     141            0 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
     142            0 :     if (amroutine->amtranslatestrategy)
     143            0 :         result = amroutine->amtranslatestrategy(strategy, opfamily);
     144              :     else
     145            0 :         result = COMPARE_INVALID;
     146              : 
     147            0 :     if (!missing_ok && result == COMPARE_INVALID)
     148            0 :         elog(ERROR, "could not translate strategy number %d for index AM %u", strategy, amoid);
     149              : 
     150            0 :     return result;
     151              : }
     152              : 
     153              : /*
     154              :  * IndexAmTranslateCompareType - given an access method and compare type, get
     155              :  * the corresponding strategy number.
     156              :  *
     157              :  * If missing_ok is false, throw an error if no strategy is found correlating
     158              :  * to the given cmptype.  If true, just return InvalidStrategy.
     159              :  */
     160              : StrategyNumber
     161      1584370 : IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
     162              : {
     163              :     StrategyNumber result;
     164              :     const IndexAmRoutine *amroutine;
     165              : 
     166              :     /* shortcut for common case */
     167      1584370 :     if (amoid == BTREE_AM_OID &&
     168      1583059 :         (cmptype > COMPARE_INVALID && cmptype <= COMPARE_GT))
     169      1583059 :         return (StrategyNumber) cmptype;
     170              : 
     171         1311 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
     172         1311 :     if (amroutine->amtranslatecmptype)
     173         1311 :         result = amroutine->amtranslatecmptype(cmptype, opfamily);
     174              :     else
     175            0 :         result = InvalidStrategy;
     176              : 
     177         1311 :     if (!missing_ok && result == InvalidStrategy)
     178            0 :         elog(ERROR, "could not translate compare type %u for index AM %u", cmptype, amoid);
     179              : 
     180         1311 :     return result;
     181              : }
     182              : 
     183              : /*
     184              :  * Ask appropriate access method to validate the specified opclass.
     185              :  */
     186              : Datum
     187          638 : amvalidate(PG_FUNCTION_ARGS)
     188              : {
     189          638 :     Oid         opclassoid = PG_GETARG_OID(0);
     190              :     bool        result;
     191              :     HeapTuple   classtup;
     192              :     Form_pg_opclass classform;
     193              :     Oid         amoid;
     194              :     const IndexAmRoutine *amroutine;
     195              : 
     196          638 :     classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
     197          638 :     if (!HeapTupleIsValid(classtup))
     198            0 :         elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
     199          638 :     classform = (Form_pg_opclass) GETSTRUCT(classtup);
     200              : 
     201          638 :     amoid = classform->opcmethod;
     202              : 
     203          638 :     ReleaseSysCache(classtup);
     204              : 
     205          638 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
     206              : 
     207          638 :     if (amroutine->amvalidate == NULL)
     208            0 :         elog(ERROR, "function amvalidate is not defined for index access method %u",
     209              :              amoid);
     210              : 
     211          638 :     result = amroutine->amvalidate(opclassoid);
     212              : 
     213          638 :     PG_RETURN_BOOL(result);
     214              : }
        

Generated by: LCOV version 2.0-1