1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* indexam.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* general index access method routines
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2007-01-05 23:20:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2007-05-27 05:50:39 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.98 2007/05/27 03:50:38 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* INTERFACE ROUTINES
|
2001-11-02 17:30:29 +01:00
|
|
|
* index_open - open an index relation by relation OID
|
|
|
|
* index_close - close an index relation
|
2005-03-28 01:53:05 +02:00
|
|
|
* index_beginscan - start a scan of an index with amgettuple
|
|
|
|
* index_beginscan_multi - start a scan of an index with amgetmulti
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_rescan - restart a scan of an index
|
|
|
|
* index_endscan - end a scan
|
|
|
|
* index_insert - insert an index tuple into a relation
|
|
|
|
* index_markpos - mark a scan position
|
|
|
|
* index_restrpos - restore a scan position
|
|
|
|
* index_getnext - get the next tuple from a scan
|
2005-03-28 01:53:05 +02:00
|
|
|
* index_getmulti - get multiple tuples from a scan
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* index_bulk_delete - bulk deletion of index tuples
|
2003-02-22 01:45:05 +01:00
|
|
|
* index_vacuum_cleanup - post-deletion cleanup of an index
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* index_getprocid - get a support procedure OID
|
2005-05-28 01:31:21 +02:00
|
|
|
* index_getprocinfo - get a support procedure's lookup info
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
* This file contains the index_ routines which used
|
|
|
|
* to be a scattered collection of stuff in access/genam.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* old comments
|
1997-09-07 07:04:48 +02:00
|
|
|
* Scans are implemented as follows:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* `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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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)
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* All other states cannot occur.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Note: It would be possible to cache the status of the previous and
|
|
|
|
* next item pointer using the flags.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "access/genam.h"
|
|
|
|
#include "access/heapam.h"
|
2005-10-06 04:29:23 +02:00
|
|
|
#include "pgstat.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "utils/relcache.h"
|
1996-10-21 09:38:20 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* macros used in index_ routines
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#define RELATION_CHECKS \
|
1998-06-15 20:40:05 +02:00
|
|
|
( \
|
2002-05-21 01:51:44 +02:00
|
|
|
AssertMacro(RelationIsValid(indexRelation)), \
|
|
|
|
AssertMacro(PointerIsValid(indexRelation->rd_am)) \
|
1998-06-15 20:40:05 +02:00
|
|
|
)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#define SCAN_CHECKS \
|
1998-06-15 20:40:05 +02:00
|
|
|
( \
|
|
|
|
AssertMacro(IndexScanIsValid(scan)), \
|
2002-05-21 01:51:44 +02:00
|
|
|
AssertMacro(RelationIsValid(scan->indexRelation)), \
|
|
|
|
AssertMacro(PointerIsValid(scan->indexRelation->rd_am)) \
|
1998-06-15 20:40:05 +02:00
|
|
|
)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
#define GET_REL_PROCEDURE(pname) \
|
2005-05-28 01:31:21 +02:00
|
|
|
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)
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
#define GET_SCAN_PROCEDURE(pname) \
|
2005-05-28 01:31:21 +02:00
|
|
|
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)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
static IndexScanDesc index_beginscan_internal(Relation indexRelation,
|
2005-10-15 04:49:52 +02:00
|
|
|
int nkeys, ScanKey key);
|
2005-03-28 01:53:05 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_ interface functions
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2001-11-02 17:30:29 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
2001-11-02 17:30:29 +01:00
|
|
|
* index_open - open an index relation by relation OID
|
1999-09-18 21:08:25 +02:00
|
|
|
*
|
2006-07-31 22:09:10 +02:00
|
|
|
* If lockmode is not "NoLock", the specified kind of lock is
|
2006-10-04 02:30:14 +02:00
|
|
|
* obtained on the index. (Generally, NoLock should only be
|
2006-07-31 22:09:10 +02:00
|
|
|
* used if the caller knows it has some appropriate lock on the
|
|
|
|
* index already.)
|
|
|
|
*
|
|
|
|
* An error is raised if the index does not exist.
|
2001-11-02 17:30:29 +01:00
|
|
|
*
|
|
|
|
* This is a convenience routine adapted for indexscan use.
|
|
|
|
* Some callers may prefer to use relation_open directly.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
Relation
|
2006-07-31 22:09:10 +02:00
|
|
|
index_open(Oid relationId, LOCKMODE lockmode)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-09-18 21:08:25 +02:00
|
|
|
Relation r;
|
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
r = relation_open(relationId, lockmode);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
|
|
|
if (r->rd_rel->relkind != RELKIND_INDEX)
|
2003-07-21 22:29:40 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("\"%s\" is not an index",
|
2003-07-21 22:29:40 +02:00
|
|
|
RelationGetRelationName(r))));
|
1999-09-18 21:08:25 +02:00
|
|
|
|
|
|
|
return r;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
2006-07-31 22:09:10 +02:00
|
|
|
* index_close - close an index relation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-07-31 22:09:10 +02:00
|
|
|
* If lockmode is not "NoLock", we then release the specified lock.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-07-31 22:09:10 +02:00
|
|
|
* Note that it is often sensible to hold a lock beyond index_close;
|
|
|
|
* in that case, the lock is released automatically at xact end.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2006-07-31 22:09:10 +02:00
|
|
|
index_close(Relation relation, LOCKMODE lockmode)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2006-07-31 22:09:10 +02:00
|
|
|
LockRelId relid = relation->rd_lockInfo.lockRelId;
|
|
|
|
|
|
|
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
|
|
|
|
|
|
|
/* The relcache does the real work... */
|
1997-09-07 07:04:48 +02:00
|
|
|
RelationClose(relation);
|
2006-07-31 22:09:10 +02:00
|
|
|
|
|
|
|
if (lockmode != NoLock)
|
|
|
|
UnlockRelationId(&relid, lockmode);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_insert - insert an index tuple into a relation
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2005-03-21 02:24:04 +01:00
|
|
|
bool
|
2002-05-21 01:51:44 +02:00
|
|
|
index_insert(Relation indexRelation,
|
2005-03-21 02:24:04 +01:00
|
|
|
Datum *values,
|
|
|
|
bool *isnull,
|
1997-09-07 07:04:48 +02:00
|
|
|
ItemPointer heap_t_ctid,
|
2002-05-24 20:57:57 +02:00
|
|
|
Relation heapRelation,
|
|
|
|
bool check_uniqueness)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
RELATION_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_REL_PROCEDURE(aminsert);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* have the am's insert proc do all the work.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
return DatumGetBool(FunctionCall6(procedure,
|
|
|
|
PointerGetDatum(indexRelation),
|
|
|
|
PointerGetDatum(values),
|
|
|
|
PointerGetDatum(isnull),
|
|
|
|
PointerGetDatum(heap_t_ctid),
|
|
|
|
PointerGetDatum(heapRelation),
|
|
|
|
BoolGetDatum(check_uniqueness)));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
/*
|
|
|
|
* index_beginscan - start a scan of an index with amgettuple
|
2002-05-21 01:51:44 +02:00
|
|
|
*
|
|
|
|
* Note: heapRelation may be NULL if there is no intention of calling
|
|
|
|
* index_getnext on this scan; index_getnext_indexitem will not use the
|
|
|
|
* heapRelation link (nor the snapshot). However, the caller had better
|
|
|
|
* be holding some kind of lock on the heap relation in any case, to ensure
|
2006-10-04 02:30:14 +02:00
|
|
|
* no one deletes it (or the index) out from under us. Caller must also
|
2006-07-31 22:09:10 +02:00
|
|
|
* be holding a lock on the index.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
IndexScanDesc
|
2002-05-21 01:51:44 +02:00
|
|
|
index_beginscan(Relation heapRelation,
|
|
|
|
Relation indexRelation,
|
|
|
|
Snapshot snapshot,
|
|
|
|
int nkeys, ScanKey key)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-06-01 04:41:36 +02:00
|
|
|
IndexScanDesc scan;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
scan = index_beginscan_internal(indexRelation, nkeys, key);
|
2005-03-28 01:53:05 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Save additional parameters into the scandesc. Everything else was set
|
|
|
|
* up by RelationGetIndexScan.
|
2005-03-28 01:53:05 +02:00
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
scan->is_multiscan = false;
|
2005-03-28 01:53:05 +02:00
|
|
|
scan->heapRelation = heapRelation;
|
|
|
|
scan->xs_snapshot = snapshot;
|
|
|
|
|
|
|
|
return scan;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* index_beginscan_multi - start a scan of an index with amgetmulti
|
|
|
|
*
|
|
|
|
* As above, caller had better be holding some lock on the parent heap
|
|
|
|
* relation, even though it's not explicitly mentioned here.
|
|
|
|
*/
|
|
|
|
IndexScanDesc
|
|
|
|
index_beginscan_multi(Relation indexRelation,
|
|
|
|
Snapshot snapshot,
|
|
|
|
int nkeys, ScanKey key)
|
|
|
|
{
|
|
|
|
IndexScanDesc scan;
|
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
scan = index_beginscan_internal(indexRelation, nkeys, key);
|
2005-03-28 01:53:05 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Save additional parameters into the scandesc. Everything else was set
|
|
|
|
* up by RelationGetIndexScan.
|
2005-03-28 01:53:05 +02:00
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
scan->is_multiscan = true;
|
2005-03-28 01:53:05 +02:00
|
|
|
scan->xs_snapshot = snapshot;
|
|
|
|
|
|
|
|
return scan;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* index_beginscan_internal --- common code for index_beginscan variants
|
|
|
|
*/
|
|
|
|
static IndexScanDesc
|
|
|
|
index_beginscan_internal(Relation indexRelation,
|
|
|
|
int nkeys, ScanKey key)
|
|
|
|
{
|
|
|
|
IndexScanDesc scan;
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
2005-03-28 01:53:05 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
RELATION_CHECKS;
|
2006-07-31 22:09:10 +02:00
|
|
|
GET_REL_PROCEDURE(ambeginscan);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-27 14:45:23 +02:00
|
|
|
/*
|
2006-07-31 22:09:10 +02:00
|
|
|
* We hold a reference count to the relcache entry throughout the scan.
|
2005-06-27 14:45:23 +02:00
|
|
|
*/
|
2006-07-31 22:09:10 +02:00
|
|
|
RelationIncrementReferenceCount(indexRelation);
|
2005-06-27 14:45:23 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
|
|
|
* Tell the AM to open a scan.
|
|
|
|
*/
|
2001-06-01 04:41:36 +02:00
|
|
|
scan = (IndexScanDesc)
|
2005-05-28 01:31:21 +02:00
|
|
|
DatumGetPointer(FunctionCall3(procedure,
|
|
|
|
PointerGetDatum(indexRelation),
|
|
|
|
Int32GetDatum(nkeys),
|
|
|
|
PointerGetDatum(key)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-01 04:41:36 +02:00
|
|
|
return scan;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
2002-05-21 01:51:44 +02:00
|
|
|
* index_rescan - (re)start a scan of an index
|
|
|
|
*
|
|
|
|
* The caller may specify a new set of scankeys (but the number of keys
|
2003-08-04 02:43:34 +02:00
|
|
|
* cannot change). To restart the scan without changing keys, pass NULL
|
2003-03-24 00:01:03 +01:00
|
|
|
* for the key array.
|
|
|
|
*
|
|
|
|
* Note that this is also called when first starting an indexscan;
|
|
|
|
* see RelationGetIndexScan. Keys *must* be passed in that case,
|
|
|
|
* unless scan->numberOfKeys is zero.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2002-05-21 01:51:44 +02:00
|
|
|
index_rescan(IndexScanDesc scan, ScanKey key)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_SCAN_PROCEDURE(amrescan);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-04-21 20:24:26 +02:00
|
|
|
/* Release any held pin on a heap page */
|
|
|
|
if (BufferIsValid(scan->xs_cbuf))
|
|
|
|
{
|
|
|
|
ReleaseBuffer(scan->xs_cbuf);
|
|
|
|
scan->xs_cbuf = InvalidBuffer;
|
|
|
|
}
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
scan->kill_prior_tuple = false; /* for safety */
|
2002-05-24 20:57:57 +02:00
|
|
|
|
2005-05-28 01:31:21 +02:00
|
|
|
FunctionCall2(procedure,
|
|
|
|
PointerGetDatum(scan),
|
|
|
|
PointerGetDatum(key));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_endscan - end a scan
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_endscan(IndexScanDesc scan)
|
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_SCAN_PROCEDURE(amendscan);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/* Release any held pin on a heap page */
|
|
|
|
if (BufferIsValid(scan->xs_cbuf))
|
|
|
|
{
|
|
|
|
ReleaseBuffer(scan->xs_cbuf);
|
|
|
|
scan->xs_cbuf = InvalidBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* End the AM's scan */
|
2005-05-28 01:31:21 +02:00
|
|
|
FunctionCall1(procedure, PointerGetDatum(scan));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
/* Release index refcount acquired by index_beginscan */
|
2002-05-21 01:51:44 +02:00
|
|
|
RelationDecrementReferenceCount(scan->indexRelation);
|
1999-12-30 06:05:13 +01:00
|
|
|
|
|
|
|
/* Release the scan data structure itself */
|
|
|
|
IndexScanEnd(scan);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_markpos - mark a scan position
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_markpos(IndexScanDesc scan)
|
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_SCAN_PROCEDURE(ammarkpos);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-05-28 01:31:21 +02:00
|
|
|
FunctionCall1(procedure, PointerGetDatum(scan));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_restrpos - restore a scan position
|
2005-05-15 23:19:55 +02:00
|
|
|
*
|
|
|
|
* NOTE: this only restores the internal scan state of the index AM.
|
|
|
|
* The current result tuple (scan->xs_ctup) doesn't change. See comments
|
|
|
|
* for ExecRestrPos().
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_restrpos(IndexScanDesc scan)
|
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_SCAN_PROCEDURE(amrestrpos);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
scan->kill_prior_tuple = false; /* for safety */
|
2003-01-08 20:41:40 +01:00
|
|
|
|
2005-05-28 01:31:21 +02:00
|
|
|
FunctionCall1(procedure, PointerGetDatum(scan));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
2002-05-21 01:51:44 +02:00
|
|
|
* index_getnext - get the next heap tuple from a scan
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-05-21 01:51:44 +02:00
|
|
|
* The result is the next heap tuple satisfying the scan keys and the
|
2002-09-04 22:31:48 +02:00
|
|
|
* snapshot, or NULL if no more matching tuples exist. On success,
|
2002-05-21 01:51:44 +02:00
|
|
|
* the buffer containing the heap tuple is pinned (the pin will be dropped
|
2006-05-07 03:21:30 +02:00
|
|
|
* at the next index_getnext or index_endscan).
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2002-05-21 01:51:44 +02:00
|
|
|
HeapTuple
|
|
|
|
index_getnext(IndexScanDesc scan, ScanDirection direction)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-05-24 20:57:57 +02:00
|
|
|
HeapTuple heapTuple = &scan->xs_ctup;
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-05-28 01:31:21 +02:00
|
|
|
GET_SCAN_PROCEDURE(amgettuple);
|
2000-03-15 00:52:01 +01:00
|
|
|
|
2002-05-24 20:57:57 +02:00
|
|
|
/* just make sure this is false... */
|
|
|
|
scan->kill_prior_tuple = false;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
2002-05-24 20:57:57 +02:00
|
|
|
bool found;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The AM's gettuple proc finds the next tuple matching the scan keys.
|
2002-05-21 01:51:44 +02:00
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
found = DatumGetBool(FunctionCall2(procedure,
|
2002-05-21 01:51:44 +02:00
|
|
|
PointerGetDatum(scan),
|
|
|
|
Int32GetDatum(direction)));
|
2002-05-24 20:57:57 +02:00
|
|
|
|
|
|
|
/* Reset kill flag immediately for safety */
|
|
|
|
scan->kill_prior_tuple = false;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
if (!found)
|
2004-04-21 20:24:26 +02:00
|
|
|
{
|
|
|
|
/* Release any held pin on a heap page */
|
|
|
|
if (BufferIsValid(scan->xs_cbuf))
|
|
|
|
{
|
|
|
|
ReleaseBuffer(scan->xs_cbuf);
|
|
|
|
scan->xs_cbuf = InvalidBuffer;
|
|
|
|
}
|
2002-05-21 01:51:44 +02:00
|
|
|
return NULL; /* failure exit */
|
2004-04-21 20:24:26 +02:00
|
|
|
}
|
2002-05-24 20:57:57 +02:00
|
|
|
|
2007-05-27 05:50:39 +02:00
|
|
|
pgstat_count_index_tuples(scan->indexRelation, 1);
|
2005-10-06 04:29:23 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
|
|
|
* Fetch the heap tuple and see if it matches the snapshot.
|
|
|
|
*/
|
2004-04-21 20:24:26 +02:00
|
|
|
if (heap_release_fetch(scan->heapRelation, scan->xs_snapshot,
|
|
|
|
heapTuple, &scan->xs_cbuf, true,
|
2007-05-27 05:50:39 +02:00
|
|
|
scan->indexRelation))
|
2002-05-21 01:51:44 +02:00
|
|
|
break;
|
2002-05-24 20:57:57 +02:00
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
/* Skip if no undeleted tuple at this location */
|
2002-05-24 21:52:43 +02:00
|
|
|
if (heapTuple->t_data == NULL)
|
2005-03-28 01:53:05 +02:00
|
|
|
continue;
|
2002-05-24 21:52:43 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If we can't see it, maybe no one else can either. Check to see if
|
|
|
|
* the tuple is dead to all transactions. If so, signal the index AM
|
|
|
|
* to not return it on future indexscans.
|
2002-05-24 20:57:57 +02:00
|
|
|
*
|
2004-04-21 20:24:26 +02:00
|
|
|
* We told heap_release_fetch to keep a pin on the buffer, so we can
|
2004-10-16 00:40:29 +02:00
|
|
|
* re-access the tuple here. But we must re-lock the buffer first.
|
2002-05-21 01:51:44 +02:00
|
|
|
*/
|
2002-05-24 20:57:57 +02:00
|
|
|
LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE);
|
|
|
|
|
2004-10-16 00:40:29 +02:00
|
|
|
if (HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin,
|
|
|
|
scan->xs_cbuf) == HEAPTUPLE_DEAD)
|
2002-05-24 20:57:57 +02:00
|
|
|
scan->kill_prior_tuple = true;
|
|
|
|
|
|
|
|
LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
|
2002-05-21 01:51:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Success exit */
|
2002-05-24 20:57:57 +02:00
|
|
|
return heapTuple;
|
2002-05-21 01:51:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* index_getnext_indexitem - get the next index tuple from a scan
|
|
|
|
*
|
2002-05-24 20:57:57 +02:00
|
|
|
* Finds the next index tuple satisfying the scan keys. Note that the
|
|
|
|
* corresponding heap tuple is not accessed, and thus no time qual (snapshot)
|
|
|
|
* check is done, other than the index AM's internal check for killed tuples
|
|
|
|
* (which most callers of this routine will probably want to suppress by
|
|
|
|
* setting scan->ignore_killed_tuples = false).
|
|
|
|
*
|
2006-05-07 03:21:30 +02:00
|
|
|
* On success (TRUE return), the heap TID of the found index entry is in
|
|
|
|
* scan->xs_ctup.t_self. scan->xs_cbuf is untouched.
|
2002-05-21 01:51:44 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
index_getnext_indexitem(IndexScanDesc scan,
|
|
|
|
ScanDirection direction)
|
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
2002-09-04 22:31:48 +02:00
|
|
|
bool found;
|
2002-05-21 01:51:44 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-05-28 01:31:21 +02:00
|
|
|
GET_SCAN_PROCEDURE(amgettuple);
|
2001-06-22 21:16:24 +02:00
|
|
|
|
2002-05-24 20:57:57 +02:00
|
|
|
/* just make sure this is false... */
|
|
|
|
scan->kill_prior_tuple = false;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-05-28 01:31:21 +02:00
|
|
|
* have the am's gettuple proc do all the work.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
found = DatumGetBool(FunctionCall2(procedure,
|
2002-05-21 01:51:44 +02:00
|
|
|
PointerGetDatum(scan),
|
|
|
|
Int32GetDatum(direction)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-10-06 04:29:23 +02:00
|
|
|
if (found)
|
2007-05-27 05:50:39 +02:00
|
|
|
pgstat_count_index_tuples(scan->indexRelation, 1);
|
2005-10-06 04:29:23 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
return found;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
/* ----------------
|
|
|
|
* index_getmulti - get multiple tuples from an index scan
|
|
|
|
*
|
|
|
|
* Collects the TIDs of multiple heap tuples satisfying the scan keys.
|
|
|
|
* Since there's no interlock between the index scan and the eventual heap
|
|
|
|
* access, this is only safe to use with MVCC-based snapshots: the heap
|
|
|
|
* item slot could have been replaced by a newer tuple by the time we get
|
|
|
|
* to it.
|
|
|
|
*
|
|
|
|
* A TRUE result indicates more calls should occur; a FALSE result says the
|
|
|
|
* scan is done. *returned_tids could be zero or nonzero in either case.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
index_getmulti(IndexScanDesc scan,
|
|
|
|
ItemPointer tids, int32 max_tids,
|
|
|
|
int32 *returned_tids)
|
|
|
|
{
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
2005-03-28 01:53:05 +02:00
|
|
|
bool found;
|
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2005-05-28 01:31:21 +02:00
|
|
|
GET_SCAN_PROCEDURE(amgetmulti);
|
2005-03-28 01:53:05 +02:00
|
|
|
|
|
|
|
/* just make sure this is false... */
|
|
|
|
scan->kill_prior_tuple = false;
|
|
|
|
|
|
|
|
/*
|
2005-05-28 01:31:21 +02:00
|
|
|
* have the am's getmulti proc do all the work.
|
2005-03-28 01:53:05 +02:00
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
found = DatumGetBool(FunctionCall4(procedure,
|
2005-03-28 01:53:05 +02:00
|
|
|
PointerGetDatum(scan),
|
|
|
|
PointerGetDatum(tids),
|
|
|
|
Int32GetDatum(max_tids),
|
|
|
|
PointerGetDatum(returned_tids)));
|
|
|
|
|
2007-05-27 05:50:39 +02:00
|
|
|
pgstat_count_index_tuples(scan->indexRelation, *returned_tids);
|
2005-10-06 04:29:23 +02:00
|
|
|
|
2005-03-28 01:53:05 +02:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/* ----------------
|
|
|
|
* index_bulk_delete - do mass deletion of index entries
|
|
|
|
*
|
|
|
|
* callback routine tells whether a given main-heap tuple is
|
|
|
|
* to be deleted
|
2006-10-04 02:30:14 +02:00
|
|
|
*
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* return value is an optional palloc'd struct of statistics
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
IndexBulkDeleteResult *
|
2006-05-03 00:25:10 +02:00
|
|
|
index_bulk_delete(IndexVacuumInfo *info,
|
|
|
|
IndexBulkDeleteResult *stats,
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
IndexBulkDeleteCallback callback,
|
|
|
|
void *callback_state)
|
|
|
|
{
|
2006-05-03 00:25:10 +02:00
|
|
|
Relation indexRelation = info->index;
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
IndexBulkDeleteResult *result;
|
|
|
|
|
|
|
|
RELATION_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_REL_PROCEDURE(ambulkdelete);
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
|
|
|
result = (IndexBulkDeleteResult *)
|
2006-05-03 00:25:10 +02:00
|
|
|
DatumGetPointer(FunctionCall4(procedure,
|
|
|
|
PointerGetDatum(info),
|
|
|
|
PointerGetDatum(stats),
|
2005-05-28 01:31:21 +02:00
|
|
|
PointerGetDatum((Pointer) callback),
|
|
|
|
PointerGetDatum(callback_state)));
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-02-22 01:45:05 +01:00
|
|
|
/* ----------------
|
|
|
|
* index_vacuum_cleanup - do post-deletion cleanup of an index
|
|
|
|
*
|
|
|
|
* return value is an optional palloc'd struct of statistics
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
IndexBulkDeleteResult *
|
2006-05-03 00:25:10 +02:00
|
|
|
index_vacuum_cleanup(IndexVacuumInfo *info,
|
2003-02-22 01:45:05 +01:00
|
|
|
IndexBulkDeleteResult *stats)
|
|
|
|
{
|
2006-05-03 00:25:10 +02:00
|
|
|
Relation indexRelation = info->index;
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *procedure;
|
2003-02-22 01:45:05 +01:00
|
|
|
IndexBulkDeleteResult *result;
|
|
|
|
|
|
|
|
RELATION_CHECKS;
|
2005-03-28 01:53:05 +02:00
|
|
|
GET_REL_PROCEDURE(amvacuumcleanup);
|
2003-02-22 01:45:05 +01:00
|
|
|
|
|
|
|
result = (IndexBulkDeleteResult *)
|
2006-05-03 00:25:10 +02:00
|
|
|
DatumGetPointer(FunctionCall2(procedure,
|
|
|
|
PointerGetDatum(info),
|
|
|
|
PointerGetDatum(stats)));
|
2003-02-22 01:45:05 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_getprocid
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-12-23 01:43:13 +01:00
|
|
|
* Index access methods typically require support routines that are
|
|
|
|
* not directly the implementation of any WHERE-clause query operator
|
|
|
|
* and so cannot be kept in pg_amop. Instead, such routines are kept
|
|
|
|
* in pg_amproc. These registered procedure OIDs are assigned numbers
|
|
|
|
* according to a convention established 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
|
1997-09-07 07:04:48 +02:00
|
|
|
* each attribute on which an index is defined.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-12-23 01:43:13 +01:00
|
|
|
* As of Postgres 8.3, support routines within an operator family
|
|
|
|
* are further subdivided by the "left type" and "right type" of the
|
|
|
|
* query operator(s) that they support. The "default" functions for a
|
|
|
|
* particular indexed attribute are those with both types equal to
|
|
|
|
* the index opclass' opcintype (note that this is subtly different
|
|
|
|
* from the indexed attribute's own type: it may be a binary-compatible
|
|
|
|
* type instead). Only the default functions are stored in relcache
|
|
|
|
* entries --- access methods can use the syscache to look up non-default
|
|
|
|
* functions.
|
|
|
|
*
|
|
|
|
* This routine returns the requested default procedure OID for a
|
|
|
|
* particular indexed attribute.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
RegProcedure
|
|
|
|
index_getprocid(Relation irel,
|
1997-09-07 07:04:48 +02:00
|
|
|
AttrNumber attnum,
|
|
|
|
uint16 procnum)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure *loc;
|
2001-05-31 20:16:55 +02:00
|
|
|
int nproc;
|
2001-10-07 01:21:45 +02:00
|
|
|
int procindex;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-05-31 20:16:55 +02:00
|
|
|
nproc = irel->rd_am->amsupport;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-10-07 01:21:45 +02:00
|
|
|
Assert(procnum > 0 && procnum <= (uint16) nproc);
|
|
|
|
|
|
|
|
procindex = (nproc * (attnum - 1)) + (procnum - 1);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
loc = irel->rd_support;
|
|
|
|
|
|
|
|
Assert(loc != NULL);
|
|
|
|
|
2001-10-07 01:21:45 +02:00
|
|
|
return loc[procindex];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* index_getprocinfo
|
|
|
|
*
|
|
|
|
* This routine allows index AMs to keep fmgr lookup info for
|
2006-12-23 01:43:13 +01:00
|
|
|
* support procs in the relcache. As above, only the "default"
|
|
|
|
* functions for any particular indexed attribute are cached.
|
2005-05-28 01:31:21 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2001-10-07 01:21:45 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2005-05-28 01:31:21 +02:00
|
|
|
FmgrInfo *
|
2001-10-07 01:21:45 +02:00
|
|
|
index_getprocinfo(Relation irel,
|
|
|
|
AttrNumber attnum,
|
|
|
|
uint16 procnum)
|
|
|
|
{
|
|
|
|
FmgrInfo *locinfo;
|
|
|
|
int nproc;
|
|
|
|
int procindex;
|
|
|
|
|
|
|
|
nproc = irel->rd_am->amsupport;
|
|
|
|
|
|
|
|
Assert(procnum > 0 && procnum <= (uint16) nproc);
|
|
|
|
|
|
|
|
procindex = (nproc * (attnum - 1)) + (procnum - 1);
|
|
|
|
|
|
|
|
locinfo = irel->rd_supportinfo;
|
|
|
|
|
|
|
|
Assert(locinfo != NULL);
|
|
|
|
|
|
|
|
locinfo += procindex;
|
|
|
|
|
|
|
|
/* Initialize the lookup info if first time through */
|
|
|
|
if (locinfo->fn_oid == InvalidOid)
|
|
|
|
{
|
|
|
|
RegProcedure *loc = irel->rd_support;
|
2002-04-17 22:57:57 +02:00
|
|
|
RegProcedure procId;
|
2001-10-07 01:21:45 +02:00
|
|
|
|
|
|
|
Assert(loc != NULL);
|
|
|
|
|
2002-04-17 22:57:57 +02:00
|
|
|
procId = loc[procindex];
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Complain if function was not found during IndexSupportInitialize.
|
|
|
|
* This should not happen unless the system tables contain bogus
|
|
|
|
* entries for the index opclass. (If an AM wants to allow a support
|
|
|
|
* function to be optional, it can use index_getprocid.)
|
2002-04-17 22:57:57 +02:00
|
|
|
*/
|
|
|
|
if (!RegProcedureIsValid(procId))
|
2003-07-21 22:29:40 +02:00
|
|
|
elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
|
2002-04-17 22:57:57 +02:00
|
|
|
procnum, attnum, RelationGetRelationName(irel));
|
|
|
|
|
|
|
|
fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
|
2001-10-07 01:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return locinfo;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|