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
|
|
|
*
|
2001-01-24 20:43:33 +01:00
|
|
|
* Portions Copyright (c) 1996-2001, 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-04-17 22:57:57 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.57 2002/04/17 20:57:56 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
|
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
|
|
|
( \
|
|
|
|
AssertMacro(RelationIsValid(relation)), \
|
|
|
|
AssertMacro(PointerIsValid(relation->rd_am)) \
|
|
|
|
)
|
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)), \
|
|
|
|
AssertMacro(RelationIsValid(scan->relation)), \
|
|
|
|
AssertMacro(PointerIsValid(scan->relation->rd_am)) \
|
|
|
|
)
|
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
|
|
|
( \
|
|
|
|
procedure = relation->rd_am->y, \
|
|
|
|
(!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
|
|
|
( \
|
|
|
|
procedure = scan->relation->rd_am->y, \
|
|
|
|
(!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
|
|
|
|
index_insert(Relation relation,
|
1997-09-08 23:56:23 +02:00
|
|
|
Datum *datum,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *nulls,
|
|
|
|
ItemPointer heap_t_ctid,
|
|
|
|
Relation heapRel)
|
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)
|
2000-06-13 09:35:40 +02:00
|
|
|
DatumGetPointer(OidFunctionCall5(procedure,
|
2000-05-30 06:25:00 +02:00
|
|
|
PointerGetDatum(relation),
|
|
|
|
PointerGetDatum(datum),
|
|
|
|
PointerGetDatum(nulls),
|
|
|
|
PointerGetDatum(heap_t_ctid),
|
2000-06-13 09:35:40 +02:00
|
|
|
PointerGetDatum(heapRel)));
|
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
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
IndexScanDesc
|
|
|
|
index_beginscan(Relation relation,
|
1997-09-07 07:04:48 +02:00
|
|
|
bool scanFromEnd,
|
|
|
|
uint16 numberOfKeys,
|
|
|
|
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);
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
RelationIncrementReferenceCount(relation);
|
|
|
|
|
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
|
|
|
*/
|
1998-12-15 13:47:01 +01:00
|
|
|
LockRelation(relation, AccessShareLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-01 04:41:36 +02:00
|
|
|
scan = (IndexScanDesc)
|
2000-05-30 06:25:00 +02:00
|
|
|
DatumGetPointer(OidFunctionCall4(procedure,
|
|
|
|
PointerGetDatum(relation),
|
|
|
|
BoolGetDatum(scanFromEnd),
|
|
|
|
UInt16GetDatum(numberOfKeys),
|
|
|
|
PointerGetDatum(key)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-22 21:16:24 +02:00
|
|
|
pgstat_initstats(&scan->xs_pgstat_info, relation);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_rescan - restart a scan of an index
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_rescan(IndexScanDesc scan, bool scanFromEnd, ScanKey key)
|
|
|
|
{
|
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);
|
|
|
|
|
2000-05-30 06:25:00 +02:00
|
|
|
OidFunctionCall3(procedure,
|
|
|
|
PointerGetDatum(scan),
|
|
|
|
BoolGetDatum(scanFromEnd),
|
|
|
|
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);
|
|
|
|
|
2000-05-30 06:25:00 +02:00
|
|
|
OidFunctionCall1(procedure, PointerGetDatum(scan));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
/* Release lock and refcount acquired by index_beginscan */
|
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
UnlockRelation(scan->relation, AccessShareLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
|
|
|
RelationDecrementReferenceCount(scan->relation);
|
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);
|
|
|
|
|
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_getnext - get the next tuple from a scan
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* A RetrieveIndexResult is a index tuple/heap tuple pair
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
RetrieveIndexResult
|
|
|
|
index_getnext(IndexScanDesc scan,
|
1997-09-07 07:04:48 +02:00
|
|
|
ScanDirection direction)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
RetrieveIndexResult result;
|
|
|
|
|
|
|
|
SCAN_CHECKS;
|
2000-03-15 00:52:01 +01:00
|
|
|
|
2001-06-22 21:16:24 +02:00
|
|
|
pgstat_count_index_scan(&scan->xs_pgstat_info);
|
|
|
|
|
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
|
|
|
*/
|
2000-03-15 00:52:01 +01:00
|
|
|
result = (RetrieveIndexResult)
|
2000-05-30 06:25:00 +02:00
|
|
|
DatumGetPointer(FunctionCall2(&scan->fn_getnext,
|
|
|
|
PointerGetDatum(scan),
|
|
|
|
Int32GetDatum(direction)));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-22 21:16:24 +02:00
|
|
|
if (result != NULL)
|
|
|
|
pgstat_count_index_getnext(&scan->xs_pgstat_info);
|
1997-09-07 07:04:48 +02:00
|
|
|
return result;
|
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 *
|
|
|
|
index_bulk_delete(Relation relation,
|
|
|
|
IndexBulkDeleteCallback callback,
|
|
|
|
void *callback_state)
|
|
|
|
{
|
|
|
|
RegProcedure procedure;
|
|
|
|
IndexBulkDeleteResult *result;
|
|
|
|
|
|
|
|
RELATION_CHECKS;
|
|
|
|
GET_REL_PROCEDURE(bulk_delete, ambulkdelete);
|
|
|
|
|
|
|
|
result = (IndexBulkDeleteResult *)
|
|
|
|
DatumGetPointer(OidFunctionCall3(procedure,
|
|
|
|
PointerGetDatum(relation),
|
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
|
|
|
|
index_cost_estimator(Relation relation)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.)
|
|
|
|
*/
|
|
|
|
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
|
|
|
}
|