diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index d2504de2190..90e910f343f 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.47 2005/04/14 20:03:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.48 2005/05/27 23:31:20 tgl Exp $ * * NOTES * many of the old access method routines have been turned into @@ -86,6 +86,7 @@ RelationGetIndexScan(Relation indexRelation, else scan->keyData = NULL; + scan->is_multiscan = false; /* caller may change this */ scan->kill_prior_tuple = false; scan->ignore_killed_tuples = true; /* default setting */ scan->keys_are_unique = false; /* may be set by index AM */ @@ -101,10 +102,6 @@ RelationGetIndexScan(Relation indexRelation, scan->xs_ctup.t_data = NULL; scan->xs_cbuf = InvalidBuffer; - /* mark cached function lookup data invalid; it will be set later */ - scan->fn_getnext.fn_oid = InvalidOid; - scan->fn_getmulti.fn_oid = InvalidOid; - scan->unique_tuple_pos = 0; scan->unique_tuple_mark = 0; diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 13b04a06b17..81c2114976e 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.81 2005/05/15 21:19:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.82 2005/05/27 23:31:20 tgl Exp $ * * INTERFACE ROUTINES * index_open - open an index relation by relation OID @@ -27,6 +27,7 @@ * index_vacuum_cleanup - post-deletion cleanup of an index * index_cost_estimator - fetch amcostestimate procedure OID * index_getprocid - get a support procedure OID + * index_getprocinfo - get a support procedure's lookup info * * NOTES * This file contains the index_ routines which used @@ -87,20 +88,28 @@ ) #define GET_REL_PROCEDURE(pname) \ -( \ - procedure = indexRelation->rd_am->pname, \ - (!RegProcedureIsValid(procedure)) ? \ - elog(ERROR, "invalid %s regproc", CppAsString(pname)) \ - : (void)NULL \ -) +do { \ + procedure = &indexRelation->rd_aminfo->pname; \ + if (!OidIsValid(procedure->fn_oid)) \ + { \ + RegProcedure procOid = indexRelation->rd_am->pname; \ + if (!RegProcedureIsValid(procOid)) \ + elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ + fmgr_info_cxt(procOid, procedure, indexRelation->rd_indexcxt); \ + } \ +} while(0) #define GET_SCAN_PROCEDURE(pname) \ -( \ - procedure = scan->indexRelation->rd_am->pname, \ - (!RegProcedureIsValid(procedure)) ? \ - elog(ERROR, "invalid %s regproc", CppAsString(pname)) \ - : (void)NULL \ -) +do { \ + procedure = &scan->indexRelation->rd_aminfo->pname; \ + if (!OidIsValid(procedure->fn_oid)) \ + { \ + RegProcedure procOid = scan->indexRelation->rd_am->pname; \ + if (!RegProcedureIsValid(procOid)) \ + elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ + fmgr_info_cxt(procOid, procedure, scan->indexRelation->rd_indexcxt); \ + } \ +} while(0) static IndexScanDesc index_beginscan_internal(Relation indexRelation, int nkeys, ScanKey key); @@ -196,7 +205,7 @@ index_insert(Relation indexRelation, Relation heapRelation, bool check_uniqueness) { - RegProcedure procedure; + FmgrInfo *procedure; RELATION_CHECKS; GET_REL_PROCEDURE(aminsert); @@ -204,13 +213,13 @@ index_insert(Relation indexRelation, /* * have the am's insert proc do all the work. */ - return DatumGetBool(OidFunctionCall6(procedure, - PointerGetDatum(indexRelation), - PointerGetDatum(values), - PointerGetDatum(isnull), - PointerGetDatum(heap_t_ctid), - PointerGetDatum(heapRelation), - BoolGetDatum(check_uniqueness))); + return DatumGetBool(FunctionCall6(procedure, + PointerGetDatum(indexRelation), + PointerGetDatum(values), + PointerGetDatum(isnull), + PointerGetDatum(heap_t_ctid), + PointerGetDatum(heapRelation), + BoolGetDatum(check_uniqueness))); } /* @@ -229,7 +238,6 @@ index_beginscan(Relation heapRelation, int nkeys, ScanKey key) { IndexScanDesc scan; - RegProcedure procedure; scan = index_beginscan_internal(indexRelation, nkeys, key); @@ -237,17 +245,10 @@ index_beginscan(Relation heapRelation, * Save additional parameters into the scandesc. Everything else was * set up by RelationGetIndexScan. */ + scan->is_multiscan = false; scan->heapRelation = heapRelation; scan->xs_snapshot = snapshot; - /* - * We want to look up the amgettuple procedure just once per scan, not - * once per index_getnext call. So do it here and save the fmgr info - * result in the scan descriptor. - */ - GET_SCAN_PROCEDURE(amgettuple); - fmgr_info(procedure, &scan->fn_getnext); - return scan; } @@ -263,7 +264,6 @@ index_beginscan_multi(Relation indexRelation, int nkeys, ScanKey key) { IndexScanDesc scan; - RegProcedure procedure; scan = index_beginscan_internal(indexRelation, nkeys, key); @@ -271,16 +271,9 @@ index_beginscan_multi(Relation indexRelation, * Save additional parameters into the scandesc. Everything else was * set up by RelationGetIndexScan. */ + scan->is_multiscan = true; scan->xs_snapshot = snapshot; - /* - * We want to look up the amgetmulti procedure just once per scan, not - * once per index_getmulti call. So do it here and save the fmgr info - * result in the scan descriptor. - */ - GET_SCAN_PROCEDURE(amgetmulti); - fmgr_info(procedure, &scan->fn_getmulti); - return scan; } @@ -292,7 +285,7 @@ index_beginscan_internal(Relation indexRelation, int nkeys, ScanKey key) { IndexScanDesc scan; - RegProcedure procedure; + FmgrInfo *procedure; RELATION_CHECKS; GET_REL_PROCEDURE(ambeginscan); @@ -312,10 +305,10 @@ index_beginscan_internal(Relation indexRelation, * Tell the AM to open a scan. */ scan = (IndexScanDesc) - DatumGetPointer(OidFunctionCall3(procedure, - PointerGetDatum(indexRelation), - Int32GetDatum(nkeys), - PointerGetDatum(key))); + DatumGetPointer(FunctionCall3(procedure, + PointerGetDatum(indexRelation), + Int32GetDatum(nkeys), + PointerGetDatum(key))); return scan; } @@ -335,7 +328,7 @@ index_beginscan_internal(Relation indexRelation, void index_rescan(IndexScanDesc scan, ScanKey key) { - RegProcedure procedure; + FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(amrescan); @@ -353,9 +346,9 @@ index_rescan(IndexScanDesc scan, ScanKey key) scan->unique_tuple_pos = 0; scan->unique_tuple_mark = 0; - OidFunctionCall2(procedure, - PointerGetDatum(scan), - PointerGetDatum(key)); + FunctionCall2(procedure, + PointerGetDatum(scan), + PointerGetDatum(key)); pgstat_reset_index_scan(&scan->xs_pgstat_info); } @@ -367,7 +360,7 @@ index_rescan(IndexScanDesc scan, ScanKey key) void index_endscan(IndexScanDesc scan) { - RegProcedure procedure; + FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(amendscan); @@ -380,7 +373,7 @@ index_endscan(IndexScanDesc scan) } /* End the AM's scan */ - OidFunctionCall1(procedure, PointerGetDatum(scan)); + FunctionCall1(procedure, PointerGetDatum(scan)); /* Release index lock and refcount acquired by index_beginscan */ @@ -399,14 +392,14 @@ index_endscan(IndexScanDesc scan) void index_markpos(IndexScanDesc scan) { - RegProcedure procedure; + FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(ammarkpos); scan->unique_tuple_mark = scan->unique_tuple_pos; - OidFunctionCall1(procedure, PointerGetDatum(scan)); + FunctionCall1(procedure, PointerGetDatum(scan)); } /* ---------------- @@ -420,7 +413,7 @@ index_markpos(IndexScanDesc scan) void index_restrpos(IndexScanDesc scan) { - RegProcedure procedure; + FmgrInfo *procedure; SCAN_CHECKS; GET_SCAN_PROCEDURE(amrestrpos); @@ -434,7 +427,7 @@ index_restrpos(IndexScanDesc scan) */ scan->unique_tuple_pos = scan->unique_tuple_mark; - OidFunctionCall1(procedure, PointerGetDatum(scan)); + FunctionCall1(procedure, PointerGetDatum(scan)); } /* ---------------- @@ -451,8 +444,10 @@ HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction) { HeapTuple heapTuple = &scan->xs_ctup; + FmgrInfo *procedure; SCAN_CHECKS; + GET_SCAN_PROCEDURE(amgettuple); /* * If we already got a tuple and it must be unique, there's no need to @@ -525,9 +520,9 @@ index_getnext(IndexScanDesc scan, ScanDirection direction) /* * The AM's gettuple proc finds the next tuple matching the scan - * keys. index_beginscan already set up fn_getnext. + * keys. */ - found = DatumGetBool(FunctionCall2(&scan->fn_getnext, + found = DatumGetBool(FunctionCall2(procedure, PointerGetDatum(scan), Int32GetDatum(direction))); @@ -605,18 +600,19 @@ bool index_getnext_indexitem(IndexScanDesc scan, ScanDirection direction) { + FmgrInfo *procedure; bool found; SCAN_CHECKS; + GET_SCAN_PROCEDURE(amgettuple); /* just make sure this is false... */ scan->kill_prior_tuple = false; /* - * have the am's gettuple proc do all the work. index_beginscan - * already set up fn_getnext. + * have the am's gettuple proc do all the work. */ - found = DatumGetBool(FunctionCall2(&scan->fn_getnext, + found = DatumGetBool(FunctionCall2(procedure, PointerGetDatum(scan), Int32GetDatum(direction))); @@ -641,18 +637,19 @@ index_getmulti(IndexScanDesc scan, ItemPointer tids, int32 max_tids, int32 *returned_tids) { + FmgrInfo *procedure; bool found; SCAN_CHECKS; + GET_SCAN_PROCEDURE(amgetmulti); /* just make sure this is false... */ scan->kill_prior_tuple = false; /* - * have the am's getmulti proc do all the work. index_beginscan_multi - * already set up fn_getmulti. + * have the am's getmulti proc do all the work. */ - found = DatumGetBool(FunctionCall4(&scan->fn_getmulti, + found = DatumGetBool(FunctionCall4(procedure, PointerGetDatum(scan), PointerGetDatum(tids), Int32GetDatum(max_tids), @@ -675,17 +672,17 @@ index_bulk_delete(Relation indexRelation, IndexBulkDeleteCallback callback, void *callback_state) { - RegProcedure procedure; + FmgrInfo *procedure; IndexBulkDeleteResult *result; RELATION_CHECKS; GET_REL_PROCEDURE(ambulkdelete); result = (IndexBulkDeleteResult *) - DatumGetPointer(OidFunctionCall3(procedure, - PointerGetDatum(indexRelation), - PointerGetDatum((Pointer) callback), - PointerGetDatum(callback_state))); + DatumGetPointer(FunctionCall3(procedure, + PointerGetDatum(indexRelation), + PointerGetDatum((Pointer) callback), + PointerGetDatum(callback_state))); return result; } @@ -701,7 +698,7 @@ index_vacuum_cleanup(Relation indexRelation, IndexVacuumCleanupInfo *info, IndexBulkDeleteResult *stats) { - RegProcedure procedure; + FmgrInfo *procedure; IndexBulkDeleteResult *result; RELATION_CHECKS; @@ -713,9 +710,9 @@ index_vacuum_cleanup(Relation indexRelation, GET_REL_PROCEDURE(amvacuumcleanup); result = (IndexBulkDeleteResult *) - DatumGetPointer(OidFunctionCall3(procedure, - PointerGetDatum(indexRelation), - PointerGetDatum((Pointer) info), + DatumGetPointer(FunctionCall3(procedure, + PointerGetDatum(indexRelation), + PointerGetDatum((Pointer) info), PointerGetDatum((Pointer) stats))); return result; @@ -734,12 +731,12 @@ index_vacuum_cleanup(Relation indexRelation, RegProcedure index_cost_estimator(Relation indexRelation) { - RegProcedure procedure; + FmgrInfo *procedure; RELATION_CHECKS; GET_REL_PROCEDURE(amcostestimate); - return procedure; + return procedure->fn_oid; } /* ---------------- @@ -785,9 +782,13 @@ index_getprocid(Relation irel, * * This routine allows index AMs to keep fmgr lookup info for * support procs in the relcache. + * + * Note: the return value points into cached data that will be lost during + * any relcache rebuild! Therefore, either use the callinfo right away, + * or save it only after having acquired some type of lock on the index rel. * ---------------- */ -struct FmgrInfo * +FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum) diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index c4dc65f784a..3123eca518e 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.223 2005/05/11 01:26:02 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.224 2005/05/27 23:31:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -904,6 +904,9 @@ RelationInitIndexAccessInfo(Relation relation) /* * Allocate arrays to hold data */ + relation->rd_aminfo = (RelationAmInfo *) + MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); + if (amstrategies > 0) operator = (Oid *) MemoryContextAllocZero(indexcxt, @@ -931,8 +934,8 @@ RelationInitIndexAccessInfo(Relation relation) relation->rd_supportinfo = supportinfo; /* - * Fill the operator and support procedure OID arrays. (supportinfo is - * left as zeroes, and is filled on-the-fly when used) + * Fill the operator and support procedure OID arrays. (aminfo and + * supportinfo are left as zeroes, and are filled on-the-fly when used) */ IndexSupportInitialize(relation->rd_indclass, operator, support, @@ -3015,7 +3018,9 @@ load_relcache_init_file(void) rel->rd_support = support; - /* add a zeroed support-fmgr-info vector */ + /* set up zeroed fmgr-info vectors */ + rel->rd_aminfo = (RelationAmInfo *) + MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); nsupport = relform->relnatts * am->amsupport; rel->rd_supportinfo = (FmgrInfo *) MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo)); @@ -3031,6 +3036,7 @@ load_relcache_init_file(void) Assert(rel->rd_indclass == NULL); Assert(rel->rd_am == NULL); Assert(rel->rd_indexcxt == NULL); + Assert(rel->rd_aminfo == NULL); Assert(rel->rd_operator == NULL); Assert(rel->rd_support == NULL); Assert(rel->rd_supportinfo == NULL); diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 422e107ec51..3ad0a3d4b2c 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.50 2005/04/14 20:03:27 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.51 2005/05/27 23:31:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -104,7 +104,7 @@ extern IndexBulkDeleteResult *index_vacuum_cleanup(Relation indexRelation, extern RegProcedure index_cost_estimator(Relation indexRelation); extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum); -extern struct FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum, +extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum); /* diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h index 1cb40445ea4..f84a84b6f7e 100644 --- a/src/include/access/relscan.h +++ b/src/include/access/relscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.38 2005/03/27 23:53:04 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.39 2005/05/27 23:31:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -40,9 +40,8 @@ typedef HeapScanDescData *HeapScanDesc; /* * We use the same IndexScanDescData structure for both amgettuple-based - * and amgetmulti-based index scans. Which one is being used can be told - * by looking at fn_getnext and fn_getmulti, only one of which will be - * initialized. Some fields are only relevant in amgettuple-based scans. + * and amgetmulti-based index scans. Some fields are only relevant in + * amgettuple-based scans. */ typedef struct IndexScanDescData { @@ -52,6 +51,7 @@ typedef struct IndexScanDescData Snapshot xs_snapshot; /* snapshot to see */ int numberOfKeys; /* number of scan keys */ ScanKey keyData; /* array of scan key descriptors */ + bool is_multiscan; /* TRUE = using amgetmulti */ /* signaling to index AM about killing index tuples */ bool kill_prior_tuple; /* last-returned tuple is dead */ @@ -75,9 +75,6 @@ typedef struct IndexScanDescData Buffer xs_cbuf; /* current heap buffer in scan, if any */ /* NB: if xs_cbuf is not InvalidBuffer, we hold a pin on that buffer */ - FmgrInfo fn_getnext; /* cached lookup info for AM's getnext fn */ - FmgrInfo fn_getmulti; /* cached lookup info for AM's getmulti fn */ - /* * If keys_are_unique and got_tuple are both true, we stop calling the * index AM; it is then necessary for index_getnext to keep track of diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index b6a1712efa7..e3f636b83d8 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.83 2005/03/29 00:17:18 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.84 2005/05/27 23:31:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,7 @@ #include "catalog/pg_am.h" #include "catalog/pg_class.h" #include "catalog/pg_index.h" +#include "fmgr.h" #include "rewrite/prs2lock.h" #include "storage/block.h" #include "storage/relfilenode.h" @@ -99,6 +100,27 @@ typedef struct PgStat_Info } PgStat_Info; +/* + * Cached lookup information for the index access method functions defined + * by the pg_am row associated with an index relation. + */ +typedef struct RelationAmInfo +{ + FmgrInfo aminsert; + FmgrInfo ambeginscan; + FmgrInfo amgettuple; + FmgrInfo amgetmulti; + FmgrInfo amrescan; + FmgrInfo amendscan; + FmgrInfo ammarkpos; + FmgrInfo amrestrpos; + FmgrInfo ambuild; + FmgrInfo ambulkdelete; + FmgrInfo amvacuumcleanup; + FmgrInfo amcostestimate; +} RelationAmInfo; + + /* * Here are the contents of a relation cache entry. */ @@ -150,11 +172,10 @@ typedef struct RelationData * that restriction. */ MemoryContext rd_indexcxt; /* private memory cxt for this stuff */ + RelationAmInfo *rd_aminfo; /* lookup info for funcs found in pg_am */ Oid *rd_operator; /* OIDs of index operators */ RegProcedure *rd_support; /* OIDs of support procedures */ - struct FmgrInfo *rd_supportinfo; /* lookup info for support - * procedures */ - /* "struct FmgrInfo" avoids need to include fmgr.h here */ + FmgrInfo *rd_supportinfo; /* lookup info for support procedures */ List *rd_indexprs; /* index expression trees, if any */ List *rd_indpred; /* index predicate tree, if any */