/* * gistinsert -- wrapper for GiST tuple insertion. * * This is the public interface routine for tuple insertion in GiSTs. * It doesn't do any work; just locks the relation and passes the buck. */ Datum gistinsert(PG_FUNCTION_ARGS) { Relation r = (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); #ifdef NOT_USED Relation heapRel = (Relation) PG_GETARG_POINTER(4); bool checkUnique = PG_GETARG_BOOL(5); #endif IndexTuple itup; GISTSTATE giststate; MemoryContext oldCtx; MemoryContext insertCtx; insertCtx = createTempGistContext(); oldCtx = MemoryContextSwitchTo(insertCtx); initGISTstate(&giststate, r); itup = gistFormTuple(&giststate, r, values, isnull, true /* size is currently bogus */ ); itup->t_tid = *ht_ctid; gistdoinsert(r, itup, 0, &giststate); /* cleanup */ freeGISTstate(&giststate); MemoryContextSwitchTo(oldCtx); MemoryContextDelete(insertCtx); PG_RETURN_BOOL(true); }
/* * gistinsert -- wrapper for GiST tuple insertion. * * This is the public interface routine for tuple insertion in GiSTs. * It doesn't do any work; just locks the relation and passes the buck. */ bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique) { IndexTuple itup; GISTSTATE *giststate; MemoryContext oldCxt; giststate = initGISTstate(r); /* * 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, values, isnull, true /* size is currently bogus */ ); itup->t_tid = *ht_ctid; gistdoinsert(r, itup, 0, giststate); /* cleanup */ MemoryContextSwitchTo(oldCxt); freeGISTstate(giststate); return false; }
/* * gistinsert -- wrapper for GiST tuple insertion. * * This is the public interface routine for tuple insertion in GiSTs. * It doesn't do any work; just locks the relation and passes the buck. */ bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, IndexInfo *indexInfo) { GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache; IndexTuple itup; MemoryContext oldCxt; /* 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); } oldCxt = MemoryContextSwitchTo(giststate->tempCxt); itup = gistFormTuple(giststate, r, values, isnull, true /* size is currently bogus */ ); itup->t_tid = *ht_ctid; gistdoinsert(r, itup, 0, giststate); /* cleanup */ MemoryContextSwitchTo(oldCxt); MemoryContextReset(giststate->tempCxt); return false; }
/* * gistinsert -- wrapper for GiST tuple insertion. * * This is the public interface routine for tuple insertion in GiSTs. * It doesn't do any work; just locks the relation and passes the buck. */ Datum gistinsert(PG_FUNCTION_ARGS) { Relation r = (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); #ifdef NOT_USED Relation heapRel = (Relation) PG_GETARG_POINTER(4); IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5); #endif IndexTuple itup; GISTSTATE *giststate; MemoryContext oldCxt; giststate = initGISTstate(r); /* * 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, values, isnull, true /* size is currently bogus */ ); itup->t_tid = *ht_ctid; gistdoinsert(r, itup, 0, giststate); /* cleanup */ MemoryContextSwitchTo(oldCxt); freeGISTstate(giststate); PG_RETURN_BOOL(false); }
/* * Per-tuple callback from IndexBuildHeapScan */ static void gistbuildCallback(Relation index, ItemPointer tupleId, Datum *values, bool *isnull, bool tupleIsAlive __attribute__((unused)), void *state) { GISTBuildState *buildstate = (GISTBuildState *) state; IndexTuple itup; MemoryContext oldCtx; oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx); /* form an index tuple and point it at the heap tuple */ itup = gistFormTuple(&buildstate->giststate, index, values, isnull, true /* size is currently bogus */ ); itup->t_tid = *tupleId; /* * Since we already have the index relation locked, we call gistdoinsert * directly. Normal access method calls dispatch through gistinsert, * which locks the relation for write. This is the right thing to do if * you're inserting single tups, but not when you're initializing the * whole index at once. * * In this path we respect the fillfactor setting, whereas insertions * after initial build do not. */ gistdoinsert(index, itup, RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR), &buildstate->giststate); buildstate->indtuples += 1; MemoryContextSwitchTo(oldCtx); MemoryContextReset(buildstate->tmpCtx); }
/* * Per-tuple callback from IndexBuildHeapScan. */ static void gistBuildCallback(Relation index, HeapTuple htup, Datum *values, bool *isnull, bool tupleIsAlive, void *state) { GISTBuildState *buildstate = (GISTBuildState *) state; IndexTuple itup; MemoryContext oldCtx; oldCtx = MemoryContextSwitchTo(buildstate->giststate->tempCxt); /* form an index tuple and point it at the heap tuple */ itup = gistFormTuple(buildstate->giststate, index, values, isnull, true); itup->t_tid = htup->t_self; if (buildstate->bufferingMode == GIST_BUFFERING_ACTIVE) { /* We have buffers, so use them. */ gistBufferingBuildInsert(buildstate, itup); } else { /* * There's no buffers (yet). Since we already have the index relation * locked, we call gistdoinsert directly. */ gistdoinsert(index, itup, buildstate->freespace, buildstate->giststate); } /* Update tuple count and total size. */ buildstate->indtuples += 1; buildstate->indtuplesSize += IndexTupleSize(itup); MemoryContextSwitchTo(oldCtx); MemoryContextReset(buildstate->giststate->tempCxt); if (buildstate->bufferingMode == GIST_BUFFERING_ACTIVE && buildstate->indtuples % BUFFERING_MODE_TUPLE_SIZE_STATS_TARGET == 0) { /* Adjust the target buffer size now */ buildstate->gfbb->pagesPerBuffer = calculatePagesPerBuffer(buildstate, buildstate->gfbb->levelStep); } /* * In 'auto' mode, check if the index has grown too large to fit in cache, * and switch to buffering mode if it has. * * To avoid excessive calls to smgrnblocks(), only check this every * BUFFERING_MODE_SWITCH_CHECK_STEP index tuples */ if ((buildstate->bufferingMode == GIST_BUFFERING_AUTO && buildstate->indtuples % BUFFERING_MODE_SWITCH_CHECK_STEP == 0 && effective_cache_size < smgrnblocks(index->rd_smgr, MAIN_FORKNUM)) || (buildstate->bufferingMode == GIST_BUFFERING_STATS && buildstate->indtuples >= BUFFERING_MODE_TUPLE_SIZE_STATS_TARGET)) { /* * Index doesn't fit in effective cache anymore. Try to switch to * buffering build mode. */ gistInitBuffering(buildstate); } }
/* * gistinsert -- wrapper for GiST tuple insertion. * * This is the public interface routine for tuple insertion in GiSTs. * It doesn't do any work; just locks the relation and passes the buck. */ Datum gistinsert(PG_FUNCTION_ARGS) { Relation r = (Relation) PG_GETARG_POINTER(0); Datum *datum = (Datum *) PG_GETARG_POINTER(1); char *nulls = (char *) PG_GETARG_POINTER(2); ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3); #ifdef NOT_USED Relation heapRel = (Relation) PG_GETARG_POINTER(4); bool checkUnique = PG_GETARG_BOOL(5); #endif InsertIndexResult res; IndexTuple itup; GISTSTATE giststate; GISTENTRY tmpentry; int i; bool compvec[INDEX_MAX_KEYS]; /* * Since GIST is not marked "amconcurrent" in pg_am, caller should * have acquired exclusive lock on index relation. We need no locking * here. */ /* GiST cannot index tuples with leading NULLs */ if (nulls[0] == 'n') { res = NULL; PG_RETURN_POINTER(res); } initGISTstate(&giststate, r); /* immediately compress keys to normalize */ for (i = 0; i < r->rd_att->natts; i++) { if (nulls[i] == 'n') { datum[i] = (Datum) 0; compvec[i] = FALSE; } else { gistcentryinit(&giststate, i, &tmpentry, datum[i], NULL, NULL, (OffsetNumber) 0, -1 /* size is currently bogus */ , TRUE, FALSE); if (datum[i] != tmpentry.key && !(isAttByVal(&giststate, i))) compvec[i] = TRUE; else compvec[i] = FALSE; datum[i] = tmpentry.key; } } itup = index_formtuple(giststate.tupdesc, datum, nulls); itup->t_tid = *ht_ctid; res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); gistdoinsert(r, itup, &res, &giststate); for (i = 0; i < r->rd_att->natts; i++) if (compvec[i] == TRUE) pfree(DatumGetPointer(datum[i])); pfree(itup); freeGISTstate(&giststate); PG_RETURN_POINTER(res); }
/* * Per-tuple callback from IndexBuildHeapScan */ static void gistbuildCallback(Relation index, HeapTuple htup, Datum *attdata, char *nulls, bool tupleIsAlive, void *state) { GISTBuildState *buildstate = (GISTBuildState *) state; IndexTuple itup; bool compvec[INDEX_MAX_KEYS]; GISTENTRY tmpcentry; int i; /* GiST cannot index tuples with leading NULLs */ if (nulls[0] == 'n') return; /* immediately compress keys to normalize */ for (i = 0; i < buildstate->numindexattrs; i++) { if (nulls[i] == 'n') { attdata[i] = (Datum) 0; compvec[i] = FALSE; } else { gistcentryinit(&buildstate->giststate, i, &tmpcentry, attdata[i], NULL, NULL, (OffsetNumber) 0, -1 /* size is currently bogus */ , TRUE, FALSE); if (attdata[i] != tmpcentry.key && !(isAttByVal(&buildstate->giststate, i))) compvec[i] = TRUE; else compvec[i] = FALSE; attdata[i] = tmpcentry.key; } } /* form an index tuple and point it at the heap tuple */ itup = index_formtuple(buildstate->giststate.tupdesc, attdata, nulls); itup->t_tid = htup->t_self; /* * Since we already have the index relation locked, we call * gistdoinsert directly. Normal access method calls dispatch through * gistinsert, which locks the relation for write. This is the right * thing to do if you're inserting single tups, but not when you're * initializing the whole index at once. */ gistdoinsert(index, itup, NULL, &buildstate->giststate); buildstate->indtuples += 1; for (i = 0; i < buildstate->numindexattrs; i++) if (compvec[i]) pfree(DatumGetPointer(attdata[i])); pfree(itup); }