*/
bool
blinsert(Relation index, Datum *values, bool *isnull,
- ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique)
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
BloomState blstate;
BloomTuple *itup;
/* index access method interface functions */
extern bool blinsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern IndexScanDesc blbeginscan(Relation r, int nkeys, int norderbys);
extern int64 blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
extern void blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
bool *isnull,
ItemPointer heap_tid,
Relation heapRelation,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo);
</programlisting>
Insert a new tuple into an existing index. The <literal>values</> and
<literal>isnull</> arrays give the key values to be indexed, and
indexed, <function>aminsert</> should just return without doing anything.
</para>
+ <para>
+ If the index AM wishes to cache data across successive index insertions
+ within a SQL statement, it can allocate space
+ in <literal>indexInfo->ii_Context</literal> and store a pointer to the
+ data in <literal>indexInfo->ii_AmCache</literal> (which will be NULL
+ initially).
+ </para>
+
<para>
<programlisting>
IndexBulkDeleteResult *
bool
brininsert(Relation idxRel, Datum *values, bool *nulls,
ItemPointer heaptid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
BlockNumber pagesPerRange;
- BrinDesc *bdesc = NULL;
+ BrinDesc *bdesc = (BrinDesc *) indexInfo->ii_AmCache;
BrinRevmap *revmap;
Buffer buf = InvalidBuffer;
MemoryContext tupcxt = NULL;
- MemoryContext oldcxt = NULL;
+ MemoryContext oldcxt = CurrentMemoryContext;
revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL);
if (!brtup)
break;
- /* First time through? */
+ /* First time through in this statement? */
if (bdesc == NULL)
{
+ MemoryContextSwitchTo(indexInfo->ii_Context);
bdesc = brin_build_desc(idxRel);
+ indexInfo->ii_AmCache = (void *) bdesc;
+ MemoryContextSwitchTo(oldcxt);
+ }
+ /* First time through in this brininsert call? */
+ if (tupcxt == NULL)
+ {
tupcxt = AllocSetContextCreate(CurrentMemoryContext,
"brininsert cxt",
ALLOCSET_DEFAULT_SIZES);
- oldcxt = MemoryContextSwitchTo(tupcxt);
+ MemoryContextSwitchTo(tupcxt);
}
dtup = brin_deform_tuple(bdesc, brtup);
brinRevmapTerminate(revmap);
if (BufferIsValid(buf))
ReleaseBuffer(buf);
- if (bdesc != NULL)
- {
- brin_free_desc(bdesc);
- MemoryContextSwitchTo(oldcxt);
+ MemoryContextSwitchTo(oldcxt);
+ if (tupcxt != NULL)
MemoryContextDelete(tupcxt);
- }
return false;
}
bool
gininsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
- GinState ginstate;
+ GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
MemoryContext oldCtx;
MemoryContext insertCtx;
int i;
+ /* Initialize GinState cache if first call in this statement */
+ if (ginstate == NULL)
+ {
+ oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
+ ginstate = (GinState *) palloc(sizeof(GinState));
+ initGinState(ginstate, index);
+ indexInfo->ii_AmCache = (void *) ginstate;
+ MemoryContextSwitchTo(oldCtx);
+ }
+
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin insert temporary context",
ALLOCSET_DEFAULT_SIZES);
oldCtx = MemoryContextSwitchTo(insertCtx);
- initGinState(&ginstate, index);
-
if (GinGetUseFastUpdate(index))
{
GinTupleCollector collector;
memset(&collector, 0, sizeof(GinTupleCollector));
- for (i = 0; i < ginstate.origTupdesc->natts; i++)
- ginHeapTupleFastCollect(&ginstate, &collector,
+ for (i = 0; i < ginstate->origTupdesc->natts; i++)
+ ginHeapTupleFastCollect(ginstate, &collector,
(OffsetNumber) (i + 1),
values[i], isnull[i],
ht_ctid);
- ginHeapTupleFastInsert(&ginstate, &collector);
+ ginHeapTupleFastInsert(ginstate, &collector);
}
else
{
- for (i = 0; i < ginstate.origTupdesc->natts; i++)
- ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1),
+ for (i = 0; i < ginstate->origTupdesc->natts; i++)
+ ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
values[i], isnull[i],
ht_ctid);
}
#include "access/gistscan.h"
#include "catalog/pg_collation.h"
#include "miscadmin.h"
+#include "nodes/execnodes.h"
#include "utils/builtins.h"
#include "utils/index_selfuncs.h"
#include "utils/memutils.h"
bool
gistinsert(Relation r, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
+ GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
IndexTuple itup;
- GISTSTATE *giststate;
MemoryContext oldCxt;
- giststate = initGISTstate(r);
+ /* Initialize GISTSTATE cache if first call in this statement */
+ if (giststate == NULL)
+ {
+ oldCxt = MemoryContextSwitchTo(indexInfo->ii_Context);
+ giststate = initGISTstate(r);
+ giststate->tempCxt = createTempGistContext();
+ indexInfo->ii_AmCache = (void *) giststate;
+ MemoryContextSwitchTo(oldCxt);
+ }
- /*
- * We use the giststate's scan context as temp context too. This means
- * that any memory leaked by the support functions is not reclaimed until
- * end of insert. In most cases, we aren't going to call the support
- * functions very many times before finishing the insert, so this seems
- * cheaper than resetting a temp context for each function call.
- */
oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
itup = gistFormTuple(giststate, r,
/* cleanup */
MemoryContextSwitchTo(oldCxt);
- freeGISTstate(giststate);
+ MemoryContextReset(giststate->tempCxt);
return false;
}
bool
hashinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
Datum index_values[1];
bool index_isnull[1];
* Create the index entry. We cheat a little here by not using
* FormIndexDatum: this relies on the knowledge that the index columns
* are the same as the initial columns of the table for all the
- * indexes.
+ * indexes. We also cheat by not providing an IndexInfo: this is okay
+ * for now because btree doesn't need one, but we might have to be
+ * more honest someday.
*
* Note also that there had better not be any user-created index on
* the TOAST table, since we don't bother to update anything else.
&(toasttup->t_self),
toastrel,
toastidxs[i]->rd_index->indisunique ?
- UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ NULL);
}
/*
bool *isnull,
ItemPointer heap_t_ctid,
Relation heapRelation,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
RELATION_CHECKS;
CHECK_REL_PROCEDURE(aminsert);
return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
heap_t_ctid, heapRelation,
- checkUnique);
+ checkUnique, indexInfo);
}
/*
bool
btinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
bool result;
IndexTuple itup;
bool
spginsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
SpGistState spgstate;
MemoryContext oldCtx;
ii->ii_Concurrent = false;
ii->ii_BrokenHotChain = false;
+ /* set up for possible use by index AM */
+ ii->ii_AmCache = NULL;
+ ii->ii_Context = CurrentMemoryContext;
+
return ii;
}
&rootTuple,
heapRelation,
indexInfo->ii_Unique ?
- UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ indexInfo);
state->tups_inserted += 1;
}
&(heapTuple->t_self), /* tid of heap tuple */
heapRelation,
relationDescs[i]->rd_index->indisunique ?
- UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ indexInfo);
}
ExecDropSingleTupleTableSlot(slot);
indexInfo->ii_ReadyForInserts = true;
indexInfo->ii_Concurrent = false;
indexInfo->ii_BrokenHotChain = false;
+ indexInfo->ii_AmCache = NULL;
+ indexInfo->ii_Context = CurrentMemoryContext;
collationObjectId[0] = InvalidOid;
collationObjectId[1] = InvalidOid;
* index will know about.
*/
index_insert(indexRel, values, isnull, &(new_row->t_self),
- trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
+ trigdata->tg_relation, UNIQUE_CHECK_EXISTING,
+ indexInfo);
}
else
{
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
+ indexInfo->ii_AmCache = NULL;
+ indexInfo->ii_Context = CurrentMemoryContext;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
indexInfo->ii_ReadyForInserts = !stmt->concurrent;
indexInfo->ii_Concurrent = stmt->concurrent;
indexInfo->ii_BrokenHotChain = false;
+ indexInfo->ii_AmCache = NULL;
+ indexInfo->ii_Context = CurrentMemoryContext;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
isnull, /* null flags */
tupleid, /* tid of heap tuple */
heapRelation, /* heap relation */
- checkUnique); /* type of uniqueness check to do */
+ checkUnique, /* type of uniqueness check to do */
+ indexInfo); /* index AM may need this */
/*
* If the index has an associated exclusion constraint, check that.
bool *isnull,
ItemPointer heap_tid,
Relation heapRelation,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
/* bulk delete */
typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info,
extern void brinbuildempty(Relation index);
extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
ItemPointer heaptid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
#include "utils/relcache.h"
#include "utils/snapshot.h"
+/* We don't want this file to depend on execnodes.h. */
+struct IndexInfo;
+
/*
* Struct for statistics returned by ambuild
*/
Datum *values, bool *isnull,
ItemPointer heap_t_ctid,
Relation heapRelation,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern IndexScanDesc index_beginscan(Relation heapRelation,
Relation indexRelation,
extern void ginbuildempty(Relation index);
extern bool gininsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern void ginEntryInsert(GinState *ginstate,
OffsetNumber attnum, Datum key, GinNullCategory category,
ItemPointerData *items, uint32 nitem,
extern void gistbuildempty(Relation index);
extern bool gistinsert(Relation r, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
extern void hashbuildempty(Relation index);
extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
extern void btbuildempty(Relation index);
extern bool btinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys);
extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
extern void spgbuildempty(Relation index);
extern bool spginsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique);
+ IndexUniqueCheck checkUnique,
+ struct IndexInfo *indexInfo);
/* spgscan.c */
extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz);
* ReadyForInserts is it valid for inserts?
* Concurrent are we doing a concurrent index build?
* BrokenHotChain did we detect any broken HOT chains?
+ * AmCache private cache area for index AM
+ * Context memory context holding this IndexInfo
*
* ii_Concurrent and ii_BrokenHotChain are used only during index build;
* they're conventionally set to false otherwise.
bool ii_ReadyForInserts;
bool ii_Concurrent;
bool ii_BrokenHotChain;
+ void *ii_AmCache;
+ MemoryContext ii_Context;
} IndexInfo;
/* ----------------