OSDN Git Service

Cleanup of code for creating index entries. Functional indexes with
[pg-rex/syncrep.git] / src / backend / access / index / indexam.c
index 5681e7b..dc18b0d 100644 (file)
 /*-------------------------------------------------------------------------
  *
- * indexam.c--
- *    general index access method routines
+ * indexam.c
+ *       general index access method routines
  *
- * Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.12 1997/08/19 21:29:30 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.46 2000/07/14 22:17:30 tgl Exp $
  *
  * INTERFACE ROUTINES
- *     index_open      - open an index relation by relationId
- *     index_openr     - open a index relation by name
- *     index_close     - close a index relation
- *     index_beginscan - start a scan of an index
- *     index_rescan    - restart a scan of an index
- *     index_endscan   - end a scan
- *     index_insert    - insert an index tuple into a relation
- *     index_delete    - delete an item from an index relation
- *     index_markpos   - mark a scan position
- *     index_restrpos  - restore a scan position
- *     index_getnext   - get the next tuple from a scan
- * **  index_fetch     - retrieve tuple with tid
+ *             index_open              - open an index relation by relationId
+ *             index_openr             - open a index relation by name
+ *             index_close             - close a index relation
+ *             index_beginscan - start a scan of an index
+ *             index_rescan    - restart a scan of an index
+ *             index_endscan   - end a scan
+ *             index_insert    - insert an index tuple into a relation
+ *             index_delete    - delete an item from an index relation
+ *             index_markpos   - mark a scan position
+ *             index_restrpos  - restore a scan position
+ *             index_getnext   - get the next tuple from a scan
+ * **  index_fetch             - retrieve tuple with tid
  * **  index_replace   - replace a tuple
  * **  index_getattr   - get an attribute from an index tuple
- *     index_getprocid - get a support procedure id from the rel tuple
- *     
- *     IndexScanIsValid - check index scan
+ *             index_getprocid - get a support procedure id from the rel tuple
+ *
+ *             IndexScanIsValid - check index scan
  *
  * NOTES
- *     This file contains the index_ routines which used
- *     to be a scattered collection of stuff in access/genam.
+ *             This file contains the index_ routines which used
+ *             to be a scattered collection of stuff in access/genam.
  *
- *     The ** routines: index_fetch, index_replace, and index_getattr
- *     have not yet been implemented.  They may not be needed.
+ *             The ** routines: index_fetch, index_replace, and index_getattr
+ *             have not yet been implemented.  They may not be needed.
  *
  * old comments
- *     Scans are implemented as follows:
+ *             Scans are implemented as follows:
  *
- *     `0' represents an invalid item pointer.
- *     `-' represents an unknown item pointer.
- *     `X' represents a known item pointers.
- *     `+' represents known or invalid item pointers.
- *     `*' represents any item pointers.
+ *             `0' represents an invalid item pointer.
+ *             `-' represents an unknown item pointer.
+ *             `X' represents a known item pointers.
+ *             `+' represents known or invalid item pointers.
+ *             `*' represents any item pointers.
  *
- *     State is represented by a triple of these symbols in the order of
- *     previous, current, next.  Note that the case of reverse scans works
- *     identically.
+ *             State is represented by a triple of these symbols in the order of
+ *             previous, current, next.  Note that the case of reverse scans works
+ *             identically.
  *
- *             State   Result
- *     (1)     + + -   + 0 0           (if the next item pointer is invalid)
- *     (2)             + X -           (otherwise)
- *     (3)     * 0 0   * 0 0           (no change)
- *     (4)     + X 0   X 0 0           (shift)
- *     (5)     * + X   + X -           (shift, add unknown)
+ *                             State   Result
+ *             (1)             + + -   + 0 0                   (if the next item pointer is invalid)
+ *             (2)                             + X -                   (otherwise)
+ *             (3)             * 0 0   * 0 0                   (no change)
+ *             (4)             + X 0   X 0 0                   (shift)
+ *             (5)             * + X   + X -                   (shift, add unknown)
  *
- *     All other states cannot occur.
+ *             All other states cannot occur.
  *
- *     Note: It would be possible to cache the status of the previous and
- *           next item pointer using the flags.
+ *             Note: It would be possible to cache the status of the previous and
+ *                       next item pointer using the flags.
  *
  *-------------------------------------------------------------------------
  */
 
-#include <postgres.h>
-#include <access/genam.h>  
-#include <utils/relcache.h>
-#include <fmgr.h>
-#include <storage/lmgr.h>
-#include <access/heaptuple.h>
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "utils/relcache.h"
 
-/* ----------------
- *   undefine macros we aren't going to use that would otherwise
- *   get in our way..  delete is defined in c.h and the am's are
- *   defined in heapam.h
- * ----------------
- */
-#undef delete
-#undef aminsert
-#undef amdelete
-#undef ambeginscan
-#undef amrescan
-#undef amendscan
-#undef ammarkpos
-#undef amrestrpos
-#undef amgettuple
 
 /* ----------------------------------------------------------------
- *                 macros used in index_ routines
+ *                                     macros used in index_ routines
  * ----------------------------------------------------------------
  */
 #define RELATION_CHECKS \
-Assert(RelationIsValid(relation)); \
-        Assert(PointerIsValid(relation->rd_am))
-     
+( \
+       AssertMacro(RelationIsValid(relation)), \
+       AssertMacro(PointerIsValid(relation->rd_am)) \
+)
+
 #define SCAN_CHECKS \
-     Assert(IndexScanIsValid(scan)); \
-        Assert(RelationIsValid(scan->relation)); \
-        Assert(PointerIsValid(scan->relation->rd_am))
-     
+( \
+       AssertMacro(IndexScanIsValid(scan)), \
+       AssertMacro(RelationIsValid(scan->relation)), \
+       AssertMacro(PointerIsValid(scan->relation->rd_am)) \
+)
+
 #define GET_REL_PROCEDURE(x,y) \
-        procedure = relation->rd_am->y; \
-        if (! RegProcedureIsValid(procedure)) \
-        elog(WARN, "index_%s: invalid %s regproc", \
-             CppAsString(x), CppAsString(y))
-     
+( \
+       procedure = relation->rd_am->y, \
+       (!RegProcedureIsValid(procedure)) ? \
+               elog(ERROR, "index_%s: invalid %s regproc", \
+                       CppAsString(x), CppAsString(y)) \
+       : (void)NULL \
+)
+
 #define GET_SCAN_PROCEDURE(x,y) \
-        procedure = scan->relation->rd_am->y; \
-        if (! RegProcedureIsValid(procedure)) \
-        elog(WARN, "index_%s: invalid %s regproc", \
-             CppAsString(x), CppAsString(y))
-     
-     
+( \
+       procedure = scan->relation->rd_am->y, \
+       (!RegProcedureIsValid(procedure)) ? \
+               elog(ERROR, "index_%s: invalid %s regproc", \
+                       CppAsString(x), CppAsString(y)) \
+       : (void)NULL \
+)
+
+
 /* ----------------------------------------------------------------
- *                index_ interface functions
+ *                                index_ interface functions
  * ----------------------------------------------------------------
  */
 /* ----------------
- *     index_open - open an index relation by relationId
+ *             index_open - open an index relation by relationId
  *
- *     presently the relcache routines do all the work we need
- *     to open/close index relations.
+ *             presently the relcache routines do all the work we need
+ *             to open/close index relations.  However, callers of index_open
+ *             expect it to succeed, so we need to check for a failure return.
+ *
+ *             Note: we acquire no lock on the index.  An AccessShareLock is
+ *             acquired by index_beginscan (and released by index_endscan).
  * ----------------
  */
 Relation
 index_open(Oid relationId)
 {
-    return RelationIdGetRelation(relationId);
+       Relation        r;
+
+       r = RelationIdGetRelation(relationId);
+
+       if (!RelationIsValid(r))
+               elog(ERROR, "Index %u does not exist", relationId);
+
+       if (r->rd_rel->relkind != RELKIND_INDEX)
+               elog(ERROR, "%s is not an index relation", RelationGetRelationName(r));
+
+       return r;
 }
 
 /* ----------------
- *     index_openr - open a index relation by name
+ *             index_openr - open a index relation by name
  *
- *     presently the relcache routines do all the work we need
- *     to open/close index relations.
+ *             As above, but lookup by name instead of OID.
  * ----------------
  */
 Relation
 index_openr(char *relationName)
 {
-    return RelationNameGetRelation(relationName);
+       Relation        r;
+
+       r = RelationNameGetRelation(relationName);
+
+       if (!RelationIsValid(r))
+               elog(ERROR, "Index '%s' does not exist", relationName);
+
+       if (r->rd_rel->relkind != RELKIND_INDEX)
+               elog(ERROR, "%s is not an index relation", RelationGetRelationName(r));
+
+       return r;
 }
 
 /* ----------------
- *     index_close - close a index relation
+ *             index_close - close a index relation
  *
- *     presently the relcache routines do all the work we need
- *     to open/close index relations.
+ *             presently the relcache routines do all the work we need
+ *             to open/close index relations.
  * ----------------
  */
 void
 index_close(Relation relation)
 {
-    RelationClose(relation);
+       RelationClose(relation);
 }
 
 /* ----------------
- *     index_insert - insert an index tuple into a relation
+ *             index_insert - insert an index tuple into a relation
  * ----------------
  */
 InsertIndexResult
 index_insert(Relation relation,
-            Datum *datum,
-            char *nulls,
-            ItemPointer heap_t_ctid,
-            Relation heapRel)
+                        Datum *datum,
+                        char *nulls,
+                        ItemPointer heap_t_ctid,
+                        Relation heapRel)
 {
-    RegProcedure               procedure;
-    InsertIndexResult          specificResult;
-    
-    RELATION_CHECKS;
-    GET_REL_PROCEDURE(insert,aminsert);
-    
-    /* ----------------
-     * have the am's insert proc do all the work.  
-     * ----------------
-     */
-    specificResult = (InsertIndexResult)
-       fmgr(procedure, relation, datum, nulls, heap_t_ctid, heapRel, NULL);
-    
-    /* ----------------
-     * the insert proc is supposed to return a "specific result" and
-     *  this routine has to return a "general result" so after we get
-     *  something back from the insert proc, we allocate a
-     *  "general result" and copy some crap between the two.
-     *
-     *  As far as I'm concerned all this result shit is needlessly c
-     *  omplicated and should be eliminated.  -cim 1/19/91
-     *
-     *  mao concurs.  regardless of how we feel here, however, it is
-     *  important to free memory we don't intend to return to anyone.
-     *  2/28/91
-     *
-     *  this "general result" crap is now gone. -ay 3/6/95
-     * ----------------
-     */
-    
-    return (specificResult);
+       RegProcedure procedure;
+       InsertIndexResult specificResult;
+
+       RELATION_CHECKS;
+       GET_REL_PROCEDURE(insert, aminsert);
+
+       /* ----------------
+        *      have the am's insert proc do all the work.
+        * ----------------
+        */
+       specificResult = (InsertIndexResult)
+               DatumGetPointer(OidFunctionCall5(procedure,
+                                                                                PointerGetDatum(relation),
+                                                                                PointerGetDatum(datum),
+                                                                                PointerGetDatum(nulls),
+                                                                                PointerGetDatum(heap_t_ctid),
+                                                                                PointerGetDatum(heapRel)));
+
+       /* must be pfree'ed */
+       return specificResult;
 }
 
 /* ----------------
- *     index_delete - delete an item from an index relation
+ *             index_delete - delete an item from an index relation
  * ----------------
  */
 void
 index_delete(Relation relation, ItemPointer indexItem)
 {
-    RegProcedure       procedure;
-    
-    RELATION_CHECKS;
-    GET_REL_PROCEDURE(delete,amdelete);
-    
-    fmgr(procedure, relation, indexItem);    
+       RegProcedure procedure;
+
+       RELATION_CHECKS;
+       GET_REL_PROCEDURE(delete, amdelete);
+
+       OidFunctionCall2(procedure,
+                                        PointerGetDatum(relation),
+                                        PointerGetDatum(indexItem));
 }
 
 /* ----------------
- *     index_beginscan - start a scan of an index
+ *             index_beginscan - start a scan of an index
  * ----------------
  */
 IndexScanDesc
 index_beginscan(Relation relation,
-               bool scanFromEnd,
-               uint16 numberOfKeys,
-               ScanKey key)
+                               bool scanFromEnd,
+                               uint16 numberOfKeys,
+                               ScanKey key)
 {
-    IndexScanDesc      scandesc;
-    RegProcedure       procedure;
-    
-    RELATION_CHECKS;
-    GET_REL_PROCEDURE(beginscan,ambeginscan);
-    
-    RelationSetRIntentLock(relation);
-    
-    scandesc = (IndexScanDesc)
-       fmgr(procedure, relation, scanFromEnd, numberOfKeys, key);
-    
-    return scandesc;
+       IndexScanDesc scandesc;
+       RegProcedure procedure;
+
+       RELATION_CHECKS;
+       GET_REL_PROCEDURE(beginscan, ambeginscan);
+
+       RelationIncrementReferenceCount(relation);
+
+       /* ----------------
+        *      Acquire AccessShareLock for the duration of the scan
+        *
+        *      Note: we could get an SI inval message here and consequently have
+        *      to rebuild the relcache entry.  The refcount increment above
+        *      ensures that we will rebuild it and not just flush it...
+        * ----------------
+        */
+       LockRelation(relation, AccessShareLock);
+
+       scandesc = (IndexScanDesc)
+               DatumGetPointer(OidFunctionCall4(procedure,
+                                                                                PointerGetDatum(relation),
+                                                                                BoolGetDatum(scanFromEnd),
+                                                                                UInt16GetDatum(numberOfKeys),
+                                                                                PointerGetDatum(key)));
+
+       return scandesc;
 }
 
 /* ----------------
- *     index_rescan  - restart a scan of an index
+ *             index_rescan  - restart a scan of an index
  * ----------------
  */
 void
 index_rescan(IndexScanDesc scan, bool scanFromEnd, ScanKey key)
 {
-    RegProcedure       procedure;
-    
-    SCAN_CHECKS;
-    GET_SCAN_PROCEDURE(rescan,amrescan);
-    
-    fmgr(procedure, scan, scanFromEnd, key);
+       RegProcedure procedure;
+
+       SCAN_CHECKS;
+       GET_SCAN_PROCEDURE(rescan, amrescan);
+
+       OidFunctionCall3(procedure,
+                                        PointerGetDatum(scan),
+                                        BoolGetDatum(scanFromEnd),
+                                        PointerGetDatum(key));
 }
 
 /* ----------------
- *     index_endscan - end a scan
+ *             index_endscan - end a scan
  * ----------------
  */
 void
 index_endscan(IndexScanDesc scan)
 {
-    RegProcedure       procedure;
-    
-    SCAN_CHECKS;
-    GET_SCAN_PROCEDURE(endscan,amendscan);
-    
-    fmgr(procedure, scan);
-    
-    RelationUnsetRIntentLock(scan->relation);
+       RegProcedure procedure;
+
+       SCAN_CHECKS;
+       GET_SCAN_PROCEDURE(endscan, amendscan);
+
+       OidFunctionCall1(procedure, PointerGetDatum(scan));
+
+       /* Release lock and refcount acquired by index_beginscan */
+
+       UnlockRelation(scan->relation, AccessShareLock);
+
+       RelationDecrementReferenceCount(scan->relation);
+
+       /* Release the scan data structure itself */
+       IndexScanEnd(scan);
 }
 
-#ifdef NOT_USED
 /* ----------------
- *     index_markpos  - mark a scan position
+ *             index_markpos  - mark a scan position
  * ----------------
  */
 void
 index_markpos(IndexScanDesc scan)
 {
-    RegProcedure       procedure;
-    
-    SCAN_CHECKS;
-    GET_SCAN_PROCEDURE(markpos,ammarkpos);
-    
-    fmgr(procedure, scan);
+       RegProcedure procedure;
+
+       SCAN_CHECKS;
+       GET_SCAN_PROCEDURE(markpos, ammarkpos);
+
+       OidFunctionCall1(procedure, PointerGetDatum(scan));
 }
-#endif
 
-#ifdef NOT_USED
 /* ----------------
- *     index_restrpos  - restore a scan position
+ *             index_restrpos  - restore a scan position
  * ----------------
  */
 void
 index_restrpos(IndexScanDesc scan)
 {
-    RegProcedure       procedure;
-    
-    SCAN_CHECKS;
-    GET_SCAN_PROCEDURE(restrpos,amrestrpos);
-    
-    fmgr(procedure, scan);
+       RegProcedure procedure;
+
+       SCAN_CHECKS;
+       GET_SCAN_PROCEDURE(restrpos, amrestrpos);
+
+       OidFunctionCall1(procedure, PointerGetDatum(scan));
 }
-#endif
 
 /* ----------------
- *     index_getnext - get the next tuple from a scan
+ *             index_getnext - get the next tuple from a scan
  *
- *     A RetrieveIndexResult is a index tuple/heap tuple pair
+ *             A RetrieveIndexResult is a index tuple/heap tuple pair
  * ----------------
  */
 RetrieveIndexResult
 index_getnext(IndexScanDesc scan,
-             ScanDirection direction)
+                         ScanDirection direction)
 {
-    RegProcedure               procedure;
-    RetrieveIndexResult                result;
-    
-    SCAN_CHECKS;
-    GET_SCAN_PROCEDURE(getnext,amgettuple);
-    
-    /* ----------------
-     * have the am's gettuple proc do all the work.  
-     * ----------------
-     */
-    result = (RetrieveIndexResult)
-       fmgr(procedure, scan, direction);
-    
-    return result;
+       RetrieveIndexResult result;
+
+       SCAN_CHECKS;
+
+       /* ----------------
+        *      Look up the access procedure only once per scan.
+        * ----------------
+        */
+       if (scan->fn_getnext.fn_oid == InvalidOid)
+       {
+               RegProcedure procedure;
+
+               GET_SCAN_PROCEDURE(getnext, amgettuple);
+               fmgr_info(procedure, &scan->fn_getnext);
+       }
+
+       /* ----------------
+        *      have the am's gettuple proc do all the work.
+        * ----------------
+        */
+       result = (RetrieveIndexResult)
+               DatumGetPointer(FunctionCall2(&scan->fn_getnext,
+                                                                         PointerGetDatum(scan),
+                                                                         Int32GetDatum(direction)));
+
+       return result;
 }
 
 /* ----------------
- *     index_getprocid
+ *             index_cost_estimator
  *
- *     Some indexed access methods may require support routines that are
- *     not in the operator class/operator model imposed by pg_am.  These
- *     access methods may store the OIDs of registered procedures they
- *     need in pg_amproc.  These registered procedure OIDs are ordered in
- *     a way that makes sense to the access method, and used only by the
- *     access method.  The general index code doesn't know anything about
- *     the routines involved; it just builds an ordered list of them for
- *     each attribute on which an index is defined.
+ *             Fetch the amcostestimate procedure OID for an index.
  *
- *     This routine returns the requested procedure OID for a particular
- *     indexed attribute.
+ *             We could combine fetching and calling the procedure,
+ *             as index_insert does for example; but that would require
+ *             importing a bunch of planner/optimizer stuff into this file.
  * ----------------
  */
 RegProcedure
-index_getprocid(Relation irel,
-               AttrNumber attnum,
-               uint16 procnum)
+index_cost_estimator(Relation relation)
 {
-    RegProcedure *loc;
-    int natts;
-    
-    natts = irel->rd_rel->relnatts;
-    
-    loc = irel->rd_support;
-
-    Assert(loc != NULL);
-    
-    return (loc[(natts * (procnum - 1)) + (attnum - 1)]);
+       RegProcedure procedure;
+
+       RELATION_CHECKS;
+       GET_REL_PROCEDURE(cost_estimator, amcostestimate);
+
+       return procedure;
 }
 
-Datum
-GetIndexValue(HeapTuple tuple,
-             TupleDesc hTupDesc,
-             int attOff,
-             AttrNumber attrNums[],
-             FuncIndexInfo *fInfo,
-             bool *attNull,
-             Buffer buffer)
+/* ----------------
+ *             index_getprocid
+ *
+ *             Some indexed access methods may require support routines that are
+ *             not in the operator class/operator model imposed by pg_am.      These
+ *             access methods may store the OIDs of registered procedures they
+ *             need in pg_amproc.      These registered procedure OIDs are ordered in
+ *             a way that makes sense to the access method, and used only by the
+ *             access method.  The general index code doesn't know anything about
+ *             the routines involved; it just builds an ordered list of them for
+ *             each attribute on which an index is defined.
+ *
+ *             This routine returns the requested procedure OID for a particular
+ *             indexed attribute.
+ * ----------------
+ */
+RegProcedure
+index_getprocid(Relation irel,
+                               AttrNumber attnum,
+                               uint16 procnum)
 {
-    Datum returnVal;
-    bool       isNull;
-    
-    if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid) {
-       int i;
-       Datum *attData = (Datum *)palloc(FIgetnArgs(fInfo)*sizeof(Datum));
-       
-       for (i = 0; i < FIgetnArgs(fInfo); i++) {
-           attData[i] = (Datum) heap_getattr(tuple, 
-                                             buffer, 
-                                             attrNums[i], 
-                                             hTupDesc,
-                                             attNull);
-       }
-       returnVal = (Datum)fmgr_array_args(FIgetProcOid(fInfo),
-                                          FIgetnArgs(fInfo),
-                                          (char **) attData,
-                                          &isNull);
-       pfree(attData);
-       *attNull = FALSE;
-    }else {
-       returnVal = (Datum) heap_getattr(tuple, buffer, attrNums[attOff], 
-                                        hTupDesc, attNull);
-    }
-    return returnVal;
+       RegProcedure *loc;
+       int                     natts;
+
+       natts = irel->rd_rel->relnatts;
+
+       loc = irel->rd_support;
+
+       Assert(loc != NULL);
+
+       return loc[(natts * (procnum - 1)) + (attnum - 1)];
 }