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
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, 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
|
2002-09-04 22:31:48 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.62 2002/09/04 20:31:09 momjian 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
|
2002-03-26 20:17:02 +01:00
|
|
|
* index_openrv - open an index relation specified by a RangeVar
|
|
|
|
* index_openr - open a system index relation by name
|
2001-11-02 17:30:29 +01:00
|
|
|
* index_close - close an index relation
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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_markpos - mark a scan position
|
|
|
|
* index_restrpos - restore a scan position
|
|
|
|
* index_getnext - get the next tuple 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
|
|
|
|
* index_cost_estimator - fetch amcostestimate procedure OID
|
|
|
|
* index_getprocid - get a support procedure OID
|
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"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "utils/relcache.h"
|
1996-10-21 09:38:20 +02:00
|
|
|
|
2001-06-22 21:16:24 +02:00
|
|
|
#include "pgstat.h"
|
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
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#define GET_REL_PROCEDURE(x,y) \
|
1998-06-15 20:40:05 +02:00
|
|
|
( \
|
2002-05-21 01:51:44 +02:00
|
|
|
procedure = indexRelation->rd_am->y, \
|
1998-06-15 20:40:05 +02:00
|
|
|
(!RegProcedureIsValid(procedure)) ? \
|
|
|
|
elog(ERROR, "index_%s: invalid %s regproc", \
|
|
|
|
CppAsString(x), CppAsString(y)) \
|
|
|
|
: (void)NULL \
|
|
|
|
)
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#define GET_SCAN_PROCEDURE(x,y) \
|
1998-06-15 20:40:05 +02:00
|
|
|
( \
|
2002-05-21 01:51:44 +02:00
|
|
|
procedure = scan->indexRelation->rd_am->y, \
|
1998-06-15 20:40:05 +02:00
|
|
|
(!RegProcedureIsValid(procedure)) ? \
|
|
|
|
elog(ERROR, "index_%s: invalid %s regproc", \
|
|
|
|
CppAsString(x), CppAsString(y)) \
|
|
|
|
: (void)NULL \
|
|
|
|
)
|
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
|
|
|
*
|
2000-04-12 19:17:23 +02:00
|
|
|
* Note: we acquire no lock on the index. An AccessShareLock is
|
1999-09-18 21:08:25 +02:00
|
|
|
* acquired by index_beginscan (and released by index_endscan).
|
2001-11-02 17:30:29 +01:00
|
|
|
* Generally, the caller should already hold some type of lock on
|
|
|
|
* the parent relation to ensure that the index doesn't disappear.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
index_open(Oid relationId)
|
|
|
|
{
|
1999-09-18 21:08:25 +02:00
|
|
|
Relation r;
|
|
|
|
|
2001-11-02 17:30:29 +01:00
|
|
|
r = relation_open(relationId, NoLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
|
|
|
if (r->rd_rel->relkind != RELKIND_INDEX)
|
2001-11-02 17:30:29 +01:00
|
|
|
elog(ERROR, "%s is not an index relation",
|
|
|
|
RelationGetRelationName(r));
|
1999-09-18 21:08:25 +02:00
|
|
|
|
2001-06-22 21:16:24 +02:00
|
|
|
pgstat_initstats(&r->pgstat_info, r);
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
return r;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
2002-03-26 20:17:02 +01:00
|
|
|
* index_openrv - open an index relation specified
|
|
|
|
* by a RangeVar node
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-03-26 20:17:02 +01:00
|
|
|
* As above, but relation is specified by a RangeVar.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
Relation
|
2002-03-26 20:17:02 +01:00
|
|
|
index_openrv(const RangeVar *relation)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-09-18 21:08:25 +02:00
|
|
|
Relation r;
|
|
|
|
|
2002-03-26 20:17:02 +01:00
|
|
|
r = relation_openrv(relation, NoLock);
|
|
|
|
|
|
|
|
if (r->rd_rel->relkind != RELKIND_INDEX)
|
|
|
|
elog(ERROR, "%s is not an index relation",
|
|
|
|
RelationGetRelationName(r));
|
|
|
|
|
|
|
|
pgstat_initstats(&r->pgstat_info, r);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* index_openr - open a system index relation specified by name.
|
|
|
|
*
|
|
|
|
* As above, but the relation is specified by an unqualified name;
|
|
|
|
* it is assumed to live in the system catalog namespace.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
Relation
|
|
|
|
index_openr(const char *sysRelationName)
|
|
|
|
{
|
|
|
|
Relation r;
|
|
|
|
|
|
|
|
r = relation_openr(sysRelationName, NoLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
|
|
|
if (r->rd_rel->relkind != RELKIND_INDEX)
|
2001-11-02 17:30:29 +01:00
|
|
|
elog(ERROR, "%s is not an index relation",
|
|
|
|
RelationGetRelationName(r));
|
1999-09-18 21:08:25 +02:00
|
|
|
|
2001-06-22 21:16:24 +02:00
|
|
|
pgstat_initstats(&r->pgstat_info, r);
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
return r;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_close - close a index relation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* presently the relcache routines do all the work we need
|
|
|
|
* to open/close index relations.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_close(Relation relation)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
RelationClose(relation);
|
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
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
InsertIndexResult
|
2002-05-21 01:51:44 +02:00
|
|
|
index_insert(Relation indexRelation,
|
|
|
|
Datum *datums,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *nulls,
|
|
|
|
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
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
InsertIndexResult specificResult;
|
|
|
|
|
|
|
|
RELATION_CHECKS;
|
|
|
|
GET_REL_PROCEDURE(insert, aminsert);
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
specificResult = (InsertIndexResult)
|
2002-05-24 20:57:57 +02:00
|
|
|
DatumGetPointer(OidFunctionCall6(procedure,
|
2002-05-21 01:51:44 +02:00
|
|
|
PointerGetDatum(indexRelation),
|
|
|
|
PointerGetDatum(datums),
|
2000-05-30 06:25:00 +02:00
|
|
|
PointerGetDatum(nulls),
|
|
|
|
PointerGetDatum(heap_t_ctid),
|
2002-05-24 20:57:57 +02:00
|
|
|
PointerGetDatum(heapRelation),
|
|
|
|
BoolGetDatum(check_uniqueness)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-03 01:05:37 +02:00
|
|
|
/* must be pfree'ed */
|
1998-09-01 05:29:17 +02:00
|
|
|
return specificResult;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_beginscan - start a scan of an index
|
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
|
|
|
|
* no one deletes it (or the index) out from under us.
|
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-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
RELATION_CHECKS;
|
|
|
|
GET_REL_PROCEDURE(beginscan, ambeginscan);
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
RelationIncrementReferenceCount(indexRelation);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Acquire AccessShareLock for the duration of the scan
|
1999-09-18 21:08:25 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* 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...
|
1999-09-18 21:08:25 +02:00
|
|
|
*/
|
2002-05-21 01:51:44 +02:00
|
|
|
LockRelation(indexRelation, AccessShareLock);
|
1997-09-07 07:04:48 +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)
|
2002-05-21 01:51:44 +02:00
|
|
|
DatumGetPointer(OidFunctionCall3(procedure,
|
|
|
|
PointerGetDatum(indexRelation),
|
|
|
|
Int32GetDatum(nkeys),
|
2000-05-30 06:25:00 +02:00
|
|
|
PointerGetDatum(key)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
2002-09-04 22:31:48 +02:00
|
|
|
* Save additional parameters into the scandesc. Everything else was
|
|
|
|
* set up by RelationGetIndexScan.
|
2002-05-21 01:51:44 +02:00
|
|
|
*/
|
|
|
|
scan->heapRelation = heapRelation;
|
|
|
|
scan->xs_snapshot = snapshot;
|
2001-06-22 21:16:24 +02:00
|
|
|
|
2001-06-01 04:41:36 +02:00
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* 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.
|
2001-06-01 04:41:36 +02:00
|
|
|
*/
|
|
|
|
GET_SCAN_PROCEDURE(beginscan, amgettuple);
|
|
|
|
fmgr_info(procedure, &scan->fn_getnext);
|
|
|
|
|
|
|
|
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
|
2002-09-04 22:31:48 +02:00
|
|
|
* cannot change). Note that this is also called when first starting
|
2002-05-21 01:51:44 +02:00
|
|
|
* an indexscan; see RelationGetIndexScan.
|
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
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
|
|
|
GET_SCAN_PROCEDURE(rescan, amrescan);
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
scan->kill_prior_tuple = false; /* for safety */
|
|
|
|
scan->keys_are_unique = false; /* may be set by amrescan */
|
2002-05-24 20:57:57 +02:00
|
|
|
scan->got_tuple = false;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
OidFunctionCall2(procedure,
|
2000-05-30 06:25:00 +02:00
|
|
|
PointerGetDatum(scan),
|
|
|
|
PointerGetDatum(key));
|
2001-06-22 21:16:24 +02:00
|
|
|
|
|
|
|
pgstat_reset_index_scan(&scan->xs_pgstat_info);
|
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)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
|
|
|
GET_SCAN_PROCEDURE(endscan, amendscan);
|
|
|
|
|
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 */
|
2000-05-30 06:25:00 +02:00
|
|
|
OidFunctionCall1(procedure, PointerGetDatum(scan));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/* Release index lock and refcount acquired by index_beginscan */
|
1999-09-18 21:08:25 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
UnlockRelation(scan->indexRelation, AccessShareLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
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)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
|
|
|
GET_SCAN_PROCEDURE(markpos, ammarkpos);
|
|
|
|
|
2000-05-30 06:25:00 +02:00
|
|
|
OidFunctionCall1(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
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_restrpos(IndexScanDesc scan)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
|
|
|
GET_SCAN_PROCEDURE(restrpos, amrestrpos);
|
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
scan->kill_prior_tuple = false; /* for safety */
|
2002-05-24 20:57:57 +02:00
|
|
|
scan->got_tuple = false;
|
|
|
|
|
2000-05-30 06:25:00 +02:00
|
|
|
OidFunctionCall1(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
|
|
|
|
* at the next index_getnext or index_endscan). The index TID corresponding
|
|
|
|
* to the heap tuple can be obtained if needed from scan->currentItemData.
|
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;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2000-03-15 00:52:01 +01:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/* Release any previously held pin */
|
|
|
|
if (BufferIsValid(scan->xs_cbuf))
|
|
|
|
{
|
|
|
|
ReleaseBuffer(scan->xs_cbuf);
|
|
|
|
scan->xs_cbuf = InvalidBuffer;
|
|
|
|
}
|
|
|
|
|
2002-05-24 20:57:57 +02:00
|
|
|
/* just make sure this is false... */
|
|
|
|
scan->kill_prior_tuple = false;
|
|
|
|
|
|
|
|
/*
|
2002-09-04 22:31:48 +02:00
|
|
|
* Can skip entering the index AM if we already got a tuple and it
|
|
|
|
* must be unique.
|
2002-05-24 20:57:57 +02:00
|
|
|
*/
|
|
|
|
if (scan->keys_are_unique && scan->got_tuple)
|
|
|
|
return NULL;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
2002-05-24 20:57:57 +02:00
|
|
|
bool found;
|
|
|
|
uint16 sv_infomask;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
pgstat_count_index_scan(&scan->xs_pgstat_info);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The AM's gettuple proc finds the next tuple matching the scan
|
|
|
|
* keys. index_beginscan already set up fn_getnext.
|
|
|
|
*/
|
|
|
|
found = DatumGetBool(FunctionCall2(&scan->fn_getnext,
|
|
|
|
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)
|
|
|
|
return NULL; /* failure exit */
|
2002-05-24 20:57:57 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
|
|
|
* Fetch the heap tuple and see if it matches the snapshot.
|
|
|
|
*/
|
2002-05-24 20:57:57 +02:00
|
|
|
if (heap_fetch(scan->heapRelation, scan->xs_snapshot,
|
|
|
|
heapTuple, &scan->xs_cbuf, true,
|
|
|
|
&scan->xs_pgstat_info))
|
2002-05-21 01:51:44 +02:00
|
|
|
break;
|
2002-05-24 20:57:57 +02:00
|
|
|
|
2002-05-24 21:52:43 +02:00
|
|
|
/* Skip if no tuple at this location */
|
|
|
|
if (heapTuple->t_data == NULL)
|
|
|
|
continue; /* should we raise an error instead? */
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
/*
|
2002-05-24 20:57:57 +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.
|
|
|
|
*
|
|
|
|
* We told heap_fetch to keep a pin on the buffer, so we can
|
2002-09-04 22:31:48 +02:00
|
|
|
* re-access the tuple here. But we must re-lock the buffer
|
|
|
|
* first. Also, it's just barely possible for an update of hint
|
|
|
|
* bits to occur here.
|
2002-05-21 01:51:44 +02:00
|
|
|
*/
|
2002-05-24 20:57:57 +02:00
|
|
|
LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE);
|
|
|
|
sv_infomask = heapTuple->t_data->t_infomask;
|
|
|
|
|
|
|
|
if (HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin) ==
|
|
|
|
HEAPTUPLE_DEAD)
|
|
|
|
scan->kill_prior_tuple = true;
|
|
|
|
|
|
|
|
if (sv_infomask != heapTuple->t_data->t_infomask)
|
|
|
|
SetBufferCommitInfoNeedsSave(scan->xs_cbuf);
|
|
|
|
LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
|
|
|
|
ReleaseBuffer(scan->xs_cbuf);
|
|
|
|
scan->xs_cbuf = InvalidBuffer;
|
2002-05-21 01:51:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Success exit */
|
2002-05-24 20:57:57 +02:00
|
|
|
scan->got_tuple = true;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
pgstat_count_index_getnext(&scan->xs_pgstat_info);
|
|
|
|
|
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).
|
|
|
|
*
|
2002-05-21 01:51:44 +02:00
|
|
|
* On success (TRUE return), the found index TID is in scan->currentItemData,
|
|
|
|
* and its heap TID is in scan->xs_ctup.t_self. scan->xs_cbuf is untouched.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
index_getnext_indexitem(IndexScanDesc scan,
|
|
|
|
ScanDirection direction)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
bool found;
|
2002-05-21 01:51:44 +02:00
|
|
|
|
|
|
|
SCAN_CHECKS;
|
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
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* have the am's gettuple proc do all the work. index_beginscan
|
|
|
|
* already set up fn_getnext.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-05-21 01:51:44 +02:00
|
|
|
found = DatumGetBool(FunctionCall2(&scan->fn_getnext,
|
|
|
|
PointerGetDatum(scan),
|
|
|
|
Int32GetDatum(direction)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
return found;
|
1996-07-09 08:22:35 +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
|
|
|
/* ----------------
|
|
|
|
* index_bulk_delete - do mass deletion of index entries
|
|
|
|
*
|
|
|
|
* callback routine tells whether a given main-heap tuple is
|
|
|
|
* to be deleted
|
|
|
|
*
|
|
|
|
* return value is an optional palloc'd struct of statistics
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
IndexBulkDeleteResult *
|
2002-05-21 01:51:44 +02:00
|
|
|
index_bulk_delete(Relation indexRelation,
|
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)
|
|
|
|
{
|
|
|
|
RegProcedure procedure;
|
|
|
|
IndexBulkDeleteResult *result;
|
|
|
|
|
|
|
|
RELATION_CHECKS;
|
|
|
|
GET_REL_PROCEDURE(bulk_delete, ambulkdelete);
|
|
|
|
|
|
|
|
result = (IndexBulkDeleteResult *)
|
|
|
|
DatumGetPointer(OidFunctionCall3(procedure,
|
2002-05-21 01:51:44 +02:00
|
|
|
PointerGetDatum(indexRelation),
|
2001-10-25 07:50: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;
|
|
|
|
}
|
|
|
|
|
2000-01-23 00:50:30 +01:00
|
|
|
/* ----------------
|
|
|
|
* index_cost_estimator
|
|
|
|
*
|
|
|
|
* Fetch the amcostestimate procedure OID for an index.
|
|
|
|
*
|
|
|
|
* 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
|
2002-05-21 01:51:44 +02:00
|
|
|
index_cost_estimator(Relation indexRelation)
|
2000-01-23 00:50:30 +01:00
|
|
|
{
|
|
|
|
RegProcedure procedure;
|
|
|
|
|
|
|
|
RELATION_CHECKS;
|
|
|
|
GET_REL_PROCEDURE(cost_estimator, amcostestimate);
|
|
|
|
|
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This routine returns the requested 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
|
|
|
|
* support procs in the relcache.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
struct FmgrInfo *
|
|
|
|
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];
|
|
|
|
|
|
|
|
/*
|
2002-09-04 22:31:48 +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))
|
|
|
|
elog(ERROR, "Missing support function %d for attribute %d of index %s",
|
|
|
|
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
|
|
|
}
|