/* ---------------- * index_insert - insert an index tuple into a relation * ---------------- */ bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique) { FmgrInfo *procedure; RELATION_CHECKS; GET_REL_PROCEDURE(aminsert); if (!(indexRelation->rd_am->ampredlocks)) CheckForSerializableConflictIn(indexRelation, (HeapTuple) NULL, InvalidBuffer); /* * have the am's insert proc do all the work. */ return DatumGetBool(FunctionCall6(procedure, PointerGetDatum(indexRelation), PointerGetDatum(values), PointerGetDatum(isnull), PointerGetDatum(heap_t_ctid), PointerGetDatum(heapRelation), Int32GetDatum((int32) checkUnique))); }
/* ---------------- * An extended workhorse version of gistinserttuple(). This version allows * inserting multiple tuples, or replacing a single tuple with multiple tuples. * This is used to recursively update the downlinks in the parent when a page * is split. * * If leftchild and rightchild are valid, we're inserting/replacing the * downlink for rightchild, and leftchild is its left sibling. We clear the * F_FOLLOW_RIGHT flag and update NSN on leftchild, atomically with the * insertion of the downlink. * * To avoid holding locks for longer than necessary, when recursing up the * tree to update the parents, the locking is a bit peculiar here. On entry, * the caller must hold an exclusive lock on stack->buffer, as well as * leftchild and rightchild if given. On return: * * - Lock on stack->buffer is released, if 'unlockbuf' is true. The page is * always kept pinned, however. * - Lock on 'leftchild' is released, if 'unlockleftchild' is true. The page * is kept pinned. * - Lock and pin on 'rightchild' are always released. * * Returns 'true' if the page had to be split. Note that if the page was * split, the inserted/updated tuples might've been inserted to a right * sibling of stack->buffer instead of stack->buffer itself. */ static bool gistinserttuples(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple *tuples, int ntup, OffsetNumber oldoffnum, Buffer leftchild, Buffer rightchild, bool unlockbuf, bool unlockleftchild) { List *splitinfo; bool is_split; /* * Check for any rw conflicts (in serializable isolation level) just * before we intend to modify the page */ CheckForSerializableConflictIn(state->r, NULL, stack->buffer); /* Insert the tuple(s) to the page, splitting the page if necessary */ is_split = gistplacetopage(state->r, state->freespace, giststate, stack->buffer, tuples, ntup, oldoffnum, NULL, leftchild, &splitinfo, true, state->heapRel, state->is_build); /* * Before recursing up in case the page was split, release locks on the * child pages. We don't need to keep them locked when updating the * parent. */ if (BufferIsValid(rightchild)) UnlockReleaseBuffer(rightchild); if (BufferIsValid(leftchild) && unlockleftchild) LockBuffer(leftchild, GIST_UNLOCK); /* * If we had to split, insert/update the downlinks in the parent. If the * caller requested us to release the lock on stack->buffer, tell * gistfinishsplit() to do that as soon as it's safe to do so. If we * didn't have to split, release it ourselves. */ if (splitinfo) gistfinishsplit(state, stack, giststate, splitinfo, unlockbuf); else if (unlockbuf) LockBuffer(stack->buffer, GIST_UNLOCK); return is_split; }
/* ---------------- * index_insert - insert an index tuple into a relation * ---------------- */ bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo) { RELATION_CHECKS; CHECK_REL_PROCEDURE(aminsert); if (!(indexRelation->rd_amroutine->ampredlocks)) CheckForSerializableConflictIn(indexRelation, (HeapTuple) NULL, InvalidBuffer); return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull, heap_t_ctid, heapRelation, checkUnique, indexInfo); }
/* * Insert one or more heap TIDs associated with the given key value. * This will either add a single key entry, or enlarge a pre-existing entry. * * During an index build, buildStats is non-null and the counters * it contains should be incremented as needed. */ void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats) { GinBtreeData btree; GinBtreeEntryInsertData insertdata; GinBtreeStack *stack; IndexTuple itup; Page page; insertdata.isDelete = false; /* During index build, count the to-be-inserted entry */ if (buildStats) buildStats->nEntries++; ginPrepareEntryScan(&btree, attnum, key, category, ginstate); stack = ginFindLeafPage(&btree, false, NULL); page = BufferGetPage(stack->buffer); if (btree.findItem(&btree, stack)) { /* found pre-existing entry */ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off)); if (GinIsPostingTree(itup)) { /* add entries to existing posting tree */ BlockNumber rootPostingTree = GinGetPostingTree(itup); /* release all stack */ LockBuffer(stack->buffer, GIN_UNLOCK); freeGinBtreeStack(stack); /* insert into posting tree */ ginInsertItemPointers(ginstate->index, rootPostingTree, items, nitem, buildStats); return; } CheckForSerializableConflictIn(ginstate->index, NULL, stack->buffer); /* modify an existing leaf entry */ itup = addItemPointersToLeafTuple(ginstate, itup, items, nitem, buildStats, stack->buffer); insertdata.isDelete = true; } else { CheckForSerializableConflictIn(ginstate->index, NULL, stack->buffer); /* no match, so construct a new leaf entry */ itup = buildFreshLeafTuple(ginstate, attnum, key, category, items, nitem, buildStats, stack->buffer); } /* Insert the new or modified leaf tuple */ insertdata.entry = itup; ginInsertValue(&btree, stack, &insertdata, buildStats); pfree(itup); }