Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * gininsert.c
4 : : * insert routines for the postgres inverted index access method.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/access/gin/gininsert.c
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "access/gin_private.h"
18 : : #include "access/tableam.h"
19 : : #include "access/xloginsert.h"
20 : : #include "miscadmin.h"
21 : : #include "nodes/execnodes.h"
22 : : #include "storage/bufmgr.h"
23 : : #include "storage/predicate.h"
24 : : #include "utils/memutils.h"
25 : : #include "utils/rel.h"
26 : :
27 : : typedef struct
28 : : {
29 : : GinState ginstate;
30 : : double indtuples;
31 : : GinStatsData buildStats;
32 : : MemoryContext tmpCtx;
33 : : MemoryContext funcCtx;
34 : : BuildAccumulator accum;
35 : : } GinBuildState;
36 : :
37 : :
38 : : /*
39 : : * Adds array of item pointers to tuple's posting list, or
40 : : * creates posting tree and tuple pointing to tree in case
41 : : * of not enough space. Max size of tuple is defined in
42 : : * GinFormTuple(). Returns a new, modified index tuple.
43 : : * items[] must be in sorted order with no duplicates.
44 : : */
45 : : static IndexTuple
4846 tgl@sss.pgh.pa.us 46 :CBC 16339 : addItemPointersToLeafTuple(GinState *ginstate,
47 : : IndexTuple old,
48 : : ItemPointerData *items, uint32 nitem,
49 : : GinStatsData *buildStats, Buffer buffer)
50 : : {
51 : : OffsetNumber attnum;
52 : : Datum key;
53 : : GinNullCategory category;
54 : : IndexTuple res;
55 : : ItemPointerData *newItems,
56 : : *oldItems;
57 : : int oldNPosting,
58 : : newNPosting;
59 : : GinPostingList *compressedList;
60 : :
61 [ - + ]: 16339 : Assert(!GinIsPostingTree(old));
62 : :
63 : 16339 : attnum = gintuple_get_attrnum(ginstate, old);
64 : 16339 : key = gintuple_get_key(ginstate, old, &category);
65 : :
66 : : /* merge the old and new posting lists */
3735 heikki.linnakangas@i 67 : 16339 : oldItems = ginReadTuple(ginstate, attnum, old, &oldNPosting);
68 : :
3674 69 : 16339 : newItems = ginMergeItemPointers(items, nitem,
70 : : oldItems, oldNPosting,
71 : : &newNPosting);
72 : :
73 : : /* Compress the posting list, and try to a build tuple with room for it */
3735 74 : 16339 : res = NULL;
75 : 16339 : compressedList = ginCompressPostingList(newItems, newNPosting, GinMaxItemSize,
76 : : NULL);
77 : 16339 : pfree(newItems);
78 [ + - ]: 16339 : if (compressedList)
79 : : {
80 : 16339 : res = GinFormTuple(ginstate, attnum, key, category,
81 : : (char *) compressedList,
82 : 16339 : SizeOfGinPostingList(compressedList),
83 : : newNPosting,
84 : : false);
85 : 16339 : pfree(compressedList);
86 : : }
87 [ + + ]: 16339 : if (!res)
88 : : {
89 : : /* posting list would be too big, convert to posting tree */
90 : : BlockNumber postingRoot;
91 : :
92 : : /*
93 : : * Initialize posting tree with the old tuple's posting list. It's
94 : : * surely small enough to fit on one posting-tree page, and should
95 : : * already be in order with no duplicates.
96 : : */
4846 tgl@sss.pgh.pa.us 97 : 11 : postingRoot = createPostingTree(ginstate->index,
98 : : oldItems,
99 : : oldNPosting,
100 : : buildStats,
101 : : buffer);
102 : :
103 : : /* Now insert the TIDs-to-be-added into the posting tree */
3798 heikki.linnakangas@i 104 : 11 : ginInsertItemPointers(ginstate->index, postingRoot,
105 : : items, nitem,
106 : : buildStats);
107 : :
108 : : /* And build a new posting-tree-only result tuple */
3735 109 : 11 : res = GinFormTuple(ginstate, attnum, key, category, NULL, 0, 0, true);
4846 tgl@sss.pgh.pa.us 110 : 11 : GinSetPostingTree(res, postingRoot);
111 : : }
3735 heikki.linnakangas@i 112 : 16339 : pfree(oldItems);
113 : :
4846 tgl@sss.pgh.pa.us 114 : 16339 : return res;
115 : : }
116 : :
117 : : /*
118 : : * Build a fresh leaf tuple, either posting-list or posting-tree format
119 : : * depending on whether the given items list will fit.
120 : : * items[] must be in sorted order with no duplicates.
121 : : *
122 : : * This is basically the same logic as in addItemPointersToLeafTuple,
123 : : * but working from slightly different input.
124 : : */
125 : : static IndexTuple
126 : 344717 : buildFreshLeafTuple(GinState *ginstate,
127 : : OffsetNumber attnum, Datum key, GinNullCategory category,
128 : : ItemPointerData *items, uint32 nitem,
129 : : GinStatsData *buildStats, Buffer buffer)
130 : : {
3735 heikki.linnakangas@i 131 : 344717 : IndexTuple res = NULL;
132 : : GinPostingList *compressedList;
133 : :
134 : : /* try to build a posting list tuple with all the items */
135 : 344717 : compressedList = ginCompressPostingList(items, nitem, GinMaxItemSize, NULL);
136 [ + - ]: 344717 : if (compressedList)
137 : : {
138 : 344717 : res = GinFormTuple(ginstate, attnum, key, category,
139 : : (char *) compressedList,
140 : 344717 : SizeOfGinPostingList(compressedList),
141 : : nitem, false);
142 : 344717 : pfree(compressedList);
143 : : }
4846 tgl@sss.pgh.pa.us 144 [ + + ]: 344717 : if (!res)
145 : : {
146 : : /* posting list would be too big, build posting tree */
147 : : BlockNumber postingRoot;
148 : :
149 : : /*
150 : : * Build posting-tree-only result tuple. We do this first so as to
151 : : * fail quickly if the key is too big.
152 : : */
3735 heikki.linnakangas@i 153 : 50 : res = GinFormTuple(ginstate, attnum, key, category, NULL, 0, 0, true);
154 : :
155 : : /*
156 : : * Initialize a new posting tree with the TIDs.
157 : : */
3812 158 : 50 : postingRoot = createPostingTree(ginstate->index, items, nitem,
159 : : buildStats, buffer);
160 : :
161 : : /* And save the root link in the result tuple */
4846 tgl@sss.pgh.pa.us 162 : 50 : GinSetPostingTree(res, postingRoot);
163 : : }
164 : :
6557 teodor@sigaev.ru 165 : 344717 : return res;
166 : : }
167 : :
168 : : /*
169 : : * Insert one or more heap TIDs associated with the given key value.
170 : : * This will either add a single key entry, or enlarge a pre-existing entry.
171 : : *
172 : : * During an index build, buildStats is non-null and the counters
173 : : * it contains should be incremented as needed.
174 : : */
175 : : void
4846 tgl@sss.pgh.pa.us 176 : 385758 : ginEntryInsert(GinState *ginstate,
177 : : OffsetNumber attnum, Datum key, GinNullCategory category,
178 : : ItemPointerData *items, uint32 nitem,
179 : : GinStatsData *buildStats)
180 : : {
181 : : GinBtreeData btree;
182 : : GinBtreeEntryInsertData insertdata;
183 : : GinBtreeStack *stack;
184 : : IndexTuple itup;
185 : : Page page;
186 : :
2433 peter_e@gmx.net 187 : 385758 : insertdata.isDelete = false;
188 : :
4846 tgl@sss.pgh.pa.us 189 : 385758 : ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
1838 heikki.linnakangas@i 190 : 385758 : btree.isBuild = (buildStats != NULL);
191 : :
219 tmunro@postgresql.or 192 :GNC 385758 : stack = ginFindLeafPage(&btree, false, false);
2916 kgrittn@postgresql.o 193 :CBC 385758 : page = BufferGetPage(stack->buffer);
194 : :
6402 bruce@momjian.us 195 [ + + ]: 385758 : if (btree.findItem(&btree, stack))
196 : : {
197 : : /* found pre-existing entry */
6557 teodor@sigaev.ru 198 : 41039 : itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
199 : :
6402 bruce@momjian.us 200 [ + + ]: 41039 : if (GinIsPostingTree(itup))
201 : : {
202 : : /* add entries to existing posting tree */
203 : 24696 : BlockNumber rootPostingTree = GinGetPostingTree(itup);
204 : :
205 : : /* release all stack */
6557 teodor@sigaev.ru 206 : 24696 : LockBuffer(stack->buffer, GIN_UNLOCK);
6402 bruce@momjian.us 207 : 24696 : freeGinBtreeStack(stack);
208 : :
209 : : /* insert into posting tree */
3798 heikki.linnakangas@i 210 : 24696 : ginInsertItemPointers(ginstate->index, rootPostingTree,
211 : : items, nitem,
212 : : buildStats);
6557 teodor@sigaev.ru 213 : 24694 : return;
214 : : }
215 : :
1538 tmunro@postgresql.or 216 : 16343 : CheckForSerializableConflictIn(ginstate->index, NULL,
217 : : BufferGetBlockNumber(stack->buffer));
218 : : /* modify an existing leaf entry */
4846 tgl@sss.pgh.pa.us 219 : 16339 : itup = addItemPointersToLeafTuple(ginstate, itup,
220 : : items, nitem, buildStats, stack->buffer);
221 : :
2433 peter_e@gmx.net 222 : 16339 : insertdata.isDelete = true;
223 : : }
224 : : else
225 : : {
1538 tmunro@postgresql.or 226 : 344719 : CheckForSerializableConflictIn(ginstate->index, NULL,
227 : : BufferGetBlockNumber(stack->buffer));
228 : : /* no match, so construct a new leaf entry */
4846 tgl@sss.pgh.pa.us 229 : 344717 : itup = buildFreshLeafTuple(ginstate, attnum, key, category,
230 : : items, nitem, buildStats, stack->buffer);
231 : :
232 : : /*
233 : : * nEntries counts leaf tuples, so increment it only when we make a
234 : : * new one.
235 : : */
1623 236 [ + + ]: 344717 : if (buildStats)
237 : 74573 : buildStats->nEntries++;
238 : : }
239 : :
240 : : /* Insert the new or modified leaf tuple */
3791 heikki.linnakangas@i 241 : 361056 : insertdata.entry = itup;
242 : 361056 : ginInsertValue(&btree, stack, &insertdata, buildStats);
6402 bruce@momjian.us 243 : 361054 : pfree(itup);
244 : : }
245 : :
246 : : /*
247 : : * Extract index entries for a single indexable item, and add them to the
248 : : * BuildAccumulator's state.
249 : : *
250 : : * This function is used only during initial index creation.
251 : : */
252 : : static void
4846 tgl@sss.pgh.pa.us 253 : 434615 : ginHeapTupleBulkInsert(GinBuildState *buildstate, OffsetNumber attnum,
254 : : Datum value, bool isNull,
255 : : ItemPointer heapptr)
256 : : {
257 : : Datum *entries;
258 : : GinNullCategory *categories;
259 : : int32 nentries;
260 : : MemoryContext oldCtx;
261 : :
6487 teodor@sigaev.ru 262 : 434615 : oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
4846 tgl@sss.pgh.pa.us 263 : 434615 : entries = ginExtractEntries(buildstate->accum.ginstate, attnum,
264 : : value, isNull,
265 : : &nentries, &categories);
6487 teodor@sigaev.ru 266 : 434615 : MemoryContextSwitchTo(oldCtx);
267 : :
4846 tgl@sss.pgh.pa.us 268 : 434615 : ginInsertBAEntries(&buildstate->accum, heapptr, attnum,
269 : : entries, categories, nentries);
270 : :
271 : 434615 : buildstate->indtuples += nentries;
272 : :
6487 teodor@sigaev.ru 273 : 434615 : MemoryContextReset(buildstate->funcCtx);
6557 274 : 434615 : }
275 : :
276 : : static void
1619 andres@anarazel.de 277 : 434306 : ginBuildCallback(Relation index, ItemPointer tid, Datum *values,
278 : : bool *isnull, bool tupleIsAlive, void *state)
279 : : {
6402 bruce@momjian.us 280 : 434306 : GinBuildState *buildstate = (GinBuildState *) state;
281 : : MemoryContext oldCtx;
282 : : int i;
283 : :
6557 teodor@sigaev.ru 284 : 434306 : oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
285 : :
5421 bruce@momjian.us 286 [ + + ]: 868921 : for (i = 0; i < buildstate->ginstate.origTupdesc->natts; i++)
4846 tgl@sss.pgh.pa.us 287 : 434615 : ginHeapTupleBulkInsert(buildstate, (OffsetNumber) (i + 1),
1619 andres@anarazel.de 288 : 434615 : values[i], isnull[i], tid);
289 : :
290 : : /* If we've maxed out our available memory, dump everything to the index */
2866 rhaas@postgresql.org 291 [ - + ]: 434306 : if (buildstate->accum.allocatedMemory >= (Size) maintenance_work_mem * 1024L)
292 : : {
293 : : ItemPointerData *list;
294 : : Datum key;
295 : : GinNullCategory category;
296 : : uint32 nlist;
297 : : OffsetNumber attnum;
298 : :
5005 tgl@sss.pgh.pa.us 299 :UBC 0 : ginBeginBAScan(&buildstate->accum);
4846 300 : 0 : while ((list = ginGetBAEntry(&buildstate->accum,
2489 301 [ # # ]: 0 : &attnum, &key, &category, &nlist)) != NULL)
302 : : {
303 : : /* there could be many entries, so be willing to abort here */
5812 304 [ # # ]: 0 : CHECK_FOR_INTERRUPTS();
4846 305 : 0 : ginEntryInsert(&buildstate->ginstate, attnum, key, category,
306 : : list, nlist, &buildstate->buildStats);
307 : : }
308 : :
6557 teodor@sigaev.ru 309 : 0 : MemoryContextReset(buildstate->tmpCtx);
310 : 0 : ginInitBA(&buildstate->accum);
311 : : }
312 : :
6557 teodor@sigaev.ru 313 :CBC 434306 : MemoryContextSwitchTo(oldCtx);
314 : 434306 : }
315 : :
316 : : IndexBuildResult *
3010 tgl@sss.pgh.pa.us 317 : 157 : ginbuild(Relation heap, Relation index, IndexInfo *indexInfo)
318 : : {
319 : : IndexBuildResult *result;
320 : : double reltuples;
321 : : GinBuildState buildstate;
322 : : Buffer RootBuffer,
323 : : MetaBuffer;
324 : : ItemPointerData *list;
325 : : Datum key;
326 : : GinNullCategory category;
327 : : uint32 nlist;
328 : : MemoryContext oldCtx;
329 : : OffsetNumber attnum;
330 : :
6557 teodor@sigaev.ru 331 [ - + ]: 157 : if (RelationGetNumberOfBlocks(index) != 0)
6557 teodor@sigaev.ru 332 [ # # ]:UBC 0 : elog(ERROR, "index \"%s\" already contains data",
333 : : RelationGetRelationName(index));
334 : :
6557 teodor@sigaev.ru 335 :CBC 157 : initGinState(&buildstate.ginstate, index);
4928 tgl@sss.pgh.pa.us 336 : 157 : buildstate.indtuples = 0;
337 : 157 : memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
338 : :
339 : : /* initialize the meta page */
5500 340 : 157 : MetaBuffer = GinNewBuffer(index);
341 : :
342 : : /* initialize the root page */
343 : 157 : RootBuffer = GinNewBuffer(index);
344 : :
6557 teodor@sigaev.ru 345 : 157 : START_CRIT_SECTION();
5500 tgl@sss.pgh.pa.us 346 : 157 : GinInitMetabuffer(MetaBuffer);
347 : 157 : MarkBufferDirty(MetaBuffer);
348 : 157 : GinInitBuffer(RootBuffer, GIN_LEAF);
349 : 157 : MarkBufferDirty(RootBuffer);
350 : :
351 : :
352 : 157 : UnlockReleaseBuffer(MetaBuffer);
353 : 157 : UnlockReleaseBuffer(RootBuffer);
6557 teodor@sigaev.ru 354 [ - + ]: 157 : END_CRIT_SECTION();
355 : :
356 : : /* count the root as first entry page */
4928 tgl@sss.pgh.pa.us 357 : 157 : buildstate.buildStats.nEntryPages++;
358 : :
359 : : /*
360 : : * create a temporary memory context that is used to hold data not yet
361 : : * dumped out to the index
362 : : */
6557 teodor@sigaev.ru 363 : 157 : buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
364 : : "Gin build temporary context",
365 : : ALLOCSET_DEFAULT_SIZES);
366 : :
367 : : /*
368 : : * create a temporary memory context that is used for calling
369 : : * ginExtractEntries(), and can be reset after each tuple
370 : : */
3304 tgl@sss.pgh.pa.us 371 : 157 : buildstate.funcCtx = AllocSetContextCreate(CurrentMemoryContext,
372 : : "Gin build temporary context for user-defined function",
373 : : ALLOCSET_DEFAULT_SIZES);
374 : :
6557 teodor@sigaev.ru 375 : 157 : buildstate.accum.ginstate = &buildstate.ginstate;
6402 bruce@momjian.us 376 : 157 : ginInitBA(&buildstate.accum);
377 : :
378 : : /*
379 : : * Do the heap scan. We disallow sync scan here because dataPlaceToPage
380 : : * prefers to receive tuples in TID order.
381 : : */
1839 alvherre@alvh.no-ip. 382 : 157 : reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
383 : : ginBuildCallback, (void *) &buildstate,
384 : : NULL);
385 : :
386 : : /* dump remaining entries to the index */
6557 teodor@sigaev.ru 387 : 157 : oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
5005 tgl@sss.pgh.pa.us 388 : 157 : ginBeginBAScan(&buildstate.accum);
4846 389 : 74730 : while ((list = ginGetBAEntry(&buildstate.accum,
390 [ + + ]: 74730 : &attnum, &key, &category, &nlist)) != NULL)
391 : : {
392 : : /* there could be many entries, so be willing to abort here */
5812 393 [ - + ]: 74573 : CHECK_FOR_INTERRUPTS();
4846 394 : 74573 : ginEntryInsert(&buildstate.ginstate, attnum, key, category,
395 : : list, nlist, &buildstate.buildStats);
396 : : }
6557 teodor@sigaev.ru 397 : 157 : MemoryContextSwitchTo(oldCtx);
398 : :
3304 tgl@sss.pgh.pa.us 399 : 157 : MemoryContextDelete(buildstate.funcCtx);
6557 teodor@sigaev.ru 400 : 157 : MemoryContextDelete(buildstate.tmpCtx);
401 : :
402 : : /*
403 : : * Update metapage stats
404 : : */
4928 tgl@sss.pgh.pa.us 405 : 157 : buildstate.buildStats.nTotalPages = RelationGetNumberOfBlocks(index);
1838 heikki.linnakangas@i 406 : 157 : ginUpdateStats(index, &buildstate.buildStats, true);
407 : :
408 : : /*
409 : : * We didn't write WAL records as we built the index, so if WAL-logging is
410 : : * required, write all pages to the WAL now.
411 : : */
412 [ + + + + : 157 : if (RelationNeedsWAL(index))
- + - - ]
413 : : {
414 : 95 : log_newpage_range(index, MAIN_FORKNUM,
415 : : 0, RelationGetNumberOfBlocks(index),
416 : : true);
417 : : }
418 : :
419 : : /*
420 : : * Return statistics
421 : : */
6549 tgl@sss.pgh.pa.us 422 : 157 : result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
423 : :
424 : 157 : result->heap_tuples = reltuples;
425 : 157 : result->index_tuples = buildstate.indtuples;
426 : :
3010 427 : 157 : return result;
428 : : }
429 : :
430 : : /*
431 : : * ginbuildempty() -- build an empty gin index in the initialization fork
432 : : */
433 : : void
434 : 3 : ginbuildempty(Relation index)
435 : : {
436 : : Buffer RootBuffer,
437 : : MetaBuffer;
438 : :
439 : : /* An empty GIN index has two pages. */
235 tmunro@postgresql.or 440 : 3 : MetaBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
441 : : EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
442 : 3 : RootBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
443 : : EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
444 : :
445 : : /* Initialize and xlog metabuffer and root buffer. */
4855 rhaas@postgresql.org 446 : 3 : START_CRIT_SECTION();
447 : 3 : GinInitMetabuffer(MetaBuffer);
448 : 3 : MarkBufferDirty(MetaBuffer);
2355 tgl@sss.pgh.pa.us 449 : 3 : log_newpage_buffer(MetaBuffer, true);
4855 rhaas@postgresql.org 450 : 3 : GinInitBuffer(RootBuffer, GIN_LEAF);
451 : 3 : MarkBufferDirty(RootBuffer);
3784 heikki.linnakangas@i 452 : 3 : log_newpage_buffer(RootBuffer, false);
4855 rhaas@postgresql.org 453 [ - + ]: 3 : END_CRIT_SECTION();
454 : :
455 : : /* Unlock and release the buffers. */
456 : 3 : UnlockReleaseBuffer(MetaBuffer);
457 : 3 : UnlockReleaseBuffer(RootBuffer);
458 : 3 : }
459 : :
460 : : /*
461 : : * Insert index entries for a single indexable item during "normal"
462 : : * (non-fast-update) insertion
463 : : */
464 : : static void
4846 tgl@sss.pgh.pa.us 465 : 16948 : ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum,
466 : : Datum value, bool isNull,
467 : : ItemPointer item)
468 : : {
469 : : Datum *entries;
470 : : GinNullCategory *categories;
471 : : int32 i,
472 : : nentries;
473 : :
474 : 16948 : entries = ginExtractEntries(ginstate, attnum, value, isNull,
475 : : &nentries, &categories);
476 : :
6402 bruce@momjian.us 477 [ + + ]: 145071 : for (i = 0; i < nentries; i++)
4846 tgl@sss.pgh.pa.us 478 : 128133 : ginEntryInsert(ginstate, attnum, entries[i], categories[i],
479 : : item, 1, NULL);
6557 teodor@sigaev.ru 480 : 16938 : }
481 : :
482 : : bool
3010 tgl@sss.pgh.pa.us 483 : 149383 : gininsert(Relation index, Datum *values, bool *isnull,
484 : : ItemPointer ht_ctid, Relation heapRel,
485 : : IndexUniqueCheck checkUnique,
486 : : bool indexUnchanged,
487 : : IndexInfo *indexInfo)
488 : : {
2621 489 : 149383 : GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
490 : : MemoryContext oldCtx;
491 : : MemoryContext insertCtx;
492 : : int i;
493 : :
494 : : /* Initialize GinState cache if first call in this statement */
495 [ + + ]: 149383 : if (ginstate == NULL)
496 : : {
497 : 1003 : oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
498 : 1003 : ginstate = (GinState *) palloc(sizeof(GinState));
499 : 1003 : initGinState(ginstate, index);
500 : 1003 : indexInfo->ii_AmCache = (void *) ginstate;
501 : 1003 : MemoryContextSwitchTo(oldCtx);
502 : : }
503 : :
6557 teodor@sigaev.ru 504 : 149383 : insertCtx = AllocSetContextCreate(CurrentMemoryContext,
505 : : "Gin insert temporary context",
506 : : ALLOCSET_DEFAULT_SIZES);
507 : :
508 : 149383 : oldCtx = MemoryContextSwitchTo(insertCtx);
509 : :
5421 bruce@momjian.us 510 [ + - - + : 149383 : if (GinGetUseFastUpdate(index))
+ + + + ]
5500 tgl@sss.pgh.pa.us 511 : 132432 : {
512 : : GinTupleCollector collector;
513 : :
514 : 132435 : memset(&collector, 0, sizeof(GinTupleCollector));
515 : :
2621 516 [ + + ]: 324909 : for (i = 0; i < ginstate->origTupdesc->natts; i++)
517 : 192474 : ginHeapTupleFastCollect(ginstate, &collector,
4846 518 : 192474 : (OffsetNumber) (i + 1),
519 : 192474 : values[i], isnull[i],
520 : : ht_ctid);
521 : :
2621 522 : 132435 : ginHeapTupleFastInsert(ginstate, &collector);
523 : : }
524 : : else
525 : : {
526 [ + + ]: 33886 : for (i = 0; i < ginstate->origTupdesc->natts; i++)
527 : 16948 : ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
4846 528 : 16948 : values[i], isnull[i],
529 : : ht_ctid);
530 : : }
531 : :
6557 teodor@sigaev.ru 532 : 149370 : MemoryContextSwitchTo(oldCtx);
533 : 149370 : MemoryContextDelete(insertCtx);
534 : :
3010 tgl@sss.pgh.pa.us 535 : 149370 : return false;
536 : : }
|