mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler function. All the data formerly obtained from pg_am is now provided in a C struct returned by the handler function. This is similar to the designs we've adopted for FDWs and tablesample methods. There are multiple advantages. For one, the index AM's support functions are now simple C functions, making them faster to call and much less error-prone, since the C compiler can now check function signatures. For another, this will make it far more practical to define index access methods in installable extensions. A disadvantage is that SQL-level code can no longer see attributes of index AMs; in particular, some of the crosschecks in the opr_sanity regression test are no longer possible from SQL. We've addressed that by adding a facility for the index AM to perform such checks instead. (Much more could be done in that line, but for now we're content if the amvalidate functions more or less replace what opr_sanity used to do.) We might also want to expose some sort of reporting functionality, but this patch doesn't do that. Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily editorialized on by me.
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "storage/smgr.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "utils/index_selfuncs.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
@@ -77,14 +77,55 @@ static void btvacuumpage(BTVacState *vstate, BlockNumber blkno,
|
||||
|
||||
|
||||
/*
|
||||
* btbuild() -- build a new btree index.
|
||||
* Btree handler function: return IndexAmRoutine with access method parameters
|
||||
* and callbacks.
|
||||
*/
|
||||
Datum
|
||||
btbuild(PG_FUNCTION_ARGS)
|
||||
bthandler(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
||||
|
||||
amroutine->amstrategies = 5;
|
||||
amroutine->amsupport = 2;
|
||||
amroutine->amcanorder = true;
|
||||
amroutine->amcanorderbyop = false;
|
||||
amroutine->amcanbackward = true;
|
||||
amroutine->amcanunique = true;
|
||||
amroutine->amcanmulticol = true;
|
||||
amroutine->amoptionalkey = true;
|
||||
amroutine->amsearcharray = true;
|
||||
amroutine->amsearchnulls = true;
|
||||
amroutine->amstorage = false;
|
||||
amroutine->amclusterable = true;
|
||||
amroutine->ampredlocks = true;
|
||||
amroutine->amkeytype = InvalidOid;
|
||||
|
||||
amroutine->ambuild = btbuild;
|
||||
amroutine->ambuildempty = btbuildempty;
|
||||
amroutine->aminsert = btinsert;
|
||||
amroutine->ambulkdelete = btbulkdelete;
|
||||
amroutine->amvacuumcleanup = btvacuumcleanup;
|
||||
amroutine->amcanreturn = btcanreturn;
|
||||
amroutine->amcostestimate = btcostestimate;
|
||||
amroutine->amoptions = btoptions;
|
||||
amroutine->amvalidate = btvalidate;
|
||||
amroutine->ambeginscan = btbeginscan;
|
||||
amroutine->amrescan = btrescan;
|
||||
amroutine->amgettuple = btgettuple;
|
||||
amroutine->amgetbitmap = btgetbitmap;
|
||||
amroutine->amendscan = btendscan;
|
||||
amroutine->ammarkpos = btmarkpos;
|
||||
amroutine->amrestrpos = btrestrpos;
|
||||
|
||||
PG_RETURN_POINTER(amroutine);
|
||||
}
|
||||
|
||||
/*
|
||||
* btbuild() -- build a new btree index.
|
||||
*/
|
||||
IndexBuildResult *
|
||||
btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
|
||||
{
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
IndexBuildResult *result;
|
||||
double reltuples;
|
||||
BTBuildState buildstate;
|
||||
@@ -156,7 +197,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
result->heap_tuples = reltuples;
|
||||
result->index_tuples = buildstate.indtuples;
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,10 +232,9 @@ btbuildCallback(Relation index,
|
||||
/*
|
||||
* btbuildempty() -- build an empty btree index in the initialization fork
|
||||
*/
|
||||
Datum
|
||||
btbuildempty(PG_FUNCTION_ARGS)
|
||||
void
|
||||
btbuildempty(Relation index)
|
||||
{
|
||||
Relation index = (Relation) PG_GETARG_POINTER(0);
|
||||
Page metapage;
|
||||
|
||||
/* Construct metapage. */
|
||||
@@ -215,8 +255,6 @@ btbuildempty(PG_FUNCTION_ARGS)
|
||||
* checkpoint may have moved the redo pointer past our xlog record.
|
||||
*/
|
||||
smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -225,15 +263,11 @@ btbuildempty(PG_FUNCTION_ARGS)
|
||||
* Descend the tree recursively, find the appropriate location for our
|
||||
* new tuple, and put it there.
|
||||
*/
|
||||
Datum
|
||||
btinsert(PG_FUNCTION_ARGS)
|
||||
bool
|
||||
btinsert(Relation rel, Datum *values, bool *isnull,
|
||||
ItemPointer ht_ctid, Relation heapRel,
|
||||
IndexUniqueCheck checkUnique)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
Datum *values = (Datum *) PG_GETARG_POINTER(1);
|
||||
bool *isnull = (bool *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
|
||||
bool result;
|
||||
IndexTuple itup;
|
||||
|
||||
@@ -245,17 +279,15 @@ btinsert(PG_FUNCTION_ARGS)
|
||||
|
||||
pfree(itup);
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* btgettuple() -- Get the next tuple in the scan.
|
||||
*/
|
||||
Datum
|
||||
btgettuple(PG_FUNCTION_ARGS)
|
||||
bool
|
||||
btgettuple(IndexScanDesc scan, ScanDirection dir)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
bool res;
|
||||
|
||||
@@ -271,7 +303,7 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* punt if we have any unsatisfiable array keys */
|
||||
if (so->numArrayKeys < 0)
|
||||
PG_RETURN_BOOL(false);
|
||||
return false;
|
||||
|
||||
_bt_start_array_keys(scan, dir);
|
||||
}
|
||||
@@ -321,17 +353,15 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||
/* ... otherwise see if we have more array keys to deal with */
|
||||
} while (so->numArrayKeys && _bt_advance_array_keys(scan, dir));
|
||||
|
||||
PG_RETURN_BOOL(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* btgetbitmap() -- gets all matching tuples, and adds them to a bitmap
|
||||
*/
|
||||
Datum
|
||||
btgetbitmap(PG_FUNCTION_ARGS)
|
||||
int64
|
||||
btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
int64 ntids = 0;
|
||||
ItemPointer heapTid;
|
||||
@@ -343,7 +373,7 @@ btgetbitmap(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* punt if we have any unsatisfiable array keys */
|
||||
if (so->numArrayKeys < 0)
|
||||
PG_RETURN_INT64(ntids);
|
||||
return ntids;
|
||||
|
||||
_bt_start_array_keys(scan, ForwardScanDirection);
|
||||
}
|
||||
@@ -381,18 +411,15 @@ btgetbitmap(PG_FUNCTION_ARGS)
|
||||
/* Now see if we have more array keys to deal with */
|
||||
} while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection));
|
||||
|
||||
PG_RETURN_INT64(ntids);
|
||||
return ntids;
|
||||
}
|
||||
|
||||
/*
|
||||
* btbeginscan() -- start a scan on a btree index
|
||||
*/
|
||||
Datum
|
||||
btbeginscan(PG_FUNCTION_ARGS)
|
||||
IndexScanDesc
|
||||
btbeginscan(Relation rel, int nkeys, int norderbys)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
int nkeys = PG_GETARG_INT32(1);
|
||||
int norderbys = PG_GETARG_INT32(2);
|
||||
IndexScanDesc scan;
|
||||
BTScanOpaque so;
|
||||
|
||||
@@ -430,19 +457,16 @@ btbeginscan(PG_FUNCTION_ARGS)
|
||||
|
||||
scan->opaque = so;
|
||||
|
||||
PG_RETURN_POINTER(scan);
|
||||
return scan;
|
||||
}
|
||||
|
||||
/*
|
||||
* btrescan() -- rescan an index relation
|
||||
*/
|
||||
Datum
|
||||
btrescan(PG_FUNCTION_ARGS)
|
||||
void
|
||||
btrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
|
||||
ScanKey orderbys, int norderbys)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
|
||||
|
||||
/* remaining arguments are ignored */
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
|
||||
/* we aren't holding any read locks, but gotta drop the pins */
|
||||
@@ -493,17 +517,14 @@ btrescan(PG_FUNCTION_ARGS)
|
||||
|
||||
/* If any keys are SK_SEARCHARRAY type, set up array-key info */
|
||||
_bt_preprocess_array_keys(scan);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
* btendscan() -- close down a scan
|
||||
*/
|
||||
Datum
|
||||
btendscan(PG_FUNCTION_ARGS)
|
||||
void
|
||||
btendscan(IndexScanDesc scan)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
|
||||
/* we aren't holding any read locks, but gotta drop the pins */
|
||||
@@ -532,17 +553,14 @@ btendscan(PG_FUNCTION_ARGS)
|
||||
pfree(so->currTuples);
|
||||
/* so->markTuples should not be pfree'd, see btrescan */
|
||||
pfree(so);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
* btmarkpos() -- save current scan position
|
||||
*/
|
||||
Datum
|
||||
btmarkpos(PG_FUNCTION_ARGS)
|
||||
void
|
||||
btmarkpos(IndexScanDesc scan)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
|
||||
/* There may be an old mark with a pin (but no lock). */
|
||||
@@ -565,17 +583,14 @@ btmarkpos(PG_FUNCTION_ARGS)
|
||||
/* Also record the current positions of any array keys */
|
||||
if (so->numArrayKeys)
|
||||
_bt_mark_array_keys(scan);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
* btrestrpos() -- restore scan to last saved position
|
||||
*/
|
||||
Datum
|
||||
btrestrpos(PG_FUNCTION_ARGS)
|
||||
void
|
||||
btrestrpos(IndexScanDesc scan)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
BTScanOpaque so = (BTScanOpaque) scan->opaque;
|
||||
|
||||
/* Restore the marked positions of any array keys */
|
||||
@@ -643,8 +658,6 @@ btrestrpos(PG_FUNCTION_ARGS)
|
||||
else
|
||||
BTScanPosInvalidate(so->currPos);
|
||||
}
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -654,13 +667,10 @@ btrestrpos(PG_FUNCTION_ARGS)
|
||||
*
|
||||
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
||||
*/
|
||||
Datum
|
||||
btbulkdelete(PG_FUNCTION_ARGS)
|
||||
IndexBulkDeleteResult *
|
||||
btbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
|
||||
IndexBulkDeleteCallback callback, void *callback_state)
|
||||
{
|
||||
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
|
||||
IndexBulkDeleteResult *volatile stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
|
||||
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
|
||||
void *callback_state = (void *) PG_GETARG_POINTER(3);
|
||||
Relation rel = info->index;
|
||||
BTCycleId cycleid;
|
||||
|
||||
@@ -679,7 +689,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel));
|
||||
_bt_end_vacuum(rel);
|
||||
|
||||
PG_RETURN_POINTER(stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -687,15 +697,12 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
*
|
||||
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
||||
*/
|
||||
Datum
|
||||
btvacuumcleanup(PG_FUNCTION_ARGS)
|
||||
IndexBulkDeleteResult *
|
||||
btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
|
||||
{
|
||||
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
|
||||
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
|
||||
|
||||
/* No-op in ANALYZE ONLY mode */
|
||||
if (info->analyze_only)
|
||||
PG_RETURN_POINTER(stats);
|
||||
return stats;
|
||||
|
||||
/*
|
||||
* If btbulkdelete was called, we need not do anything, just return the
|
||||
@@ -727,7 +734,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
||||
stats->num_index_tuples = info->num_heap_tuples;
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1148,8 +1155,8 @@ restart:
|
||||
*
|
||||
* btrees always do, so this is trivial.
|
||||
*/
|
||||
Datum
|
||||
btcanreturn(PG_FUNCTION_ARGS)
|
||||
bool
|
||||
btcanreturn(Relation index, int attno)
|
||||
{
|
||||
PG_RETURN_BOOL(true);
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user