PostgreSQL Source Code git master
indexing.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * indexing.c
4 * This file contains routines to support indexes defined on system
5 * catalogs.
6 *
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/catalog/indexing.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
18#include "access/genam.h"
19#include "access/heapam.h"
20#include "access/htup_details.h"
21#include "access/xact.h"
22#include "catalog/index.h"
23#include "catalog/indexing.h"
24#include "executor/executor.h"
25#include "utils/rel.h"
26
27
28/*
29 * CatalogOpenIndexes - open the indexes on a system catalog.
30 *
31 * When inserting or updating tuples in a system catalog, call this
32 * to prepare to update the indexes for the catalog.
33 *
34 * In the current implementation, we share code for opening/closing the
35 * indexes with execUtils.c. But we do not use ExecInsertIndexTuples,
36 * because we don't want to create an EState. This implies that we
37 * do not support partial or expressional indexes on system catalogs,
38 * nor can we support generalized exclusion constraints.
39 * This could be fixed with localized changes here if we wanted to pay
40 * the extra overhead of building an EState.
41 */
44{
45 ResultRelInfo *resultRelInfo;
46
47 resultRelInfo = makeNode(ResultRelInfo);
48 resultRelInfo->ri_RangeTableIndex = 0; /* dummy */
49 resultRelInfo->ri_RelationDesc = heapRel;
50 resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
51
52 ExecOpenIndices(resultRelInfo, false);
53
54 return resultRelInfo;
55}
56
57/*
58 * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
59 */
60void
62{
63 ExecCloseIndices(indstate);
64 pfree(indstate);
65}
66
67/*
68 * CatalogIndexInsert - insert index entries for one catalog tuple
69 *
70 * This should be called for each inserted or updated catalog tuple.
71 *
72 * This is effectively a cut-down version of ExecInsertIndexTuples.
73 */
74static void
76 TU_UpdateIndexes updateIndexes)
77{
78 int i;
79 int numIndexes;
80 RelationPtr relationDescs;
81 Relation heapRelation;
82 TupleTableSlot *slot;
83 IndexInfo **indexInfoArray;
85 bool isnull[INDEX_MAX_KEYS];
86 bool onlySummarized = (updateIndexes == TU_Summarizing);
87
88 /*
89 * HOT update does not require index inserts. But with asserts enabled we
90 * want to check that it'd be legal to currently insert into the
91 * table/index.
92 */
93#ifndef USE_ASSERT_CHECKING
94 if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
95 return;
96#endif
97
98 /* When only updating summarized indexes, the tuple has to be HOT. */
99 Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
100
101 /*
102 * Get information from the state structure. Fall out if nothing to do.
103 */
104 numIndexes = indstate->ri_NumIndices;
105 if (numIndexes == 0)
106 return;
107 relationDescs = indstate->ri_IndexRelationDescs;
108 indexInfoArray = indstate->ri_IndexRelationInfo;
109 heapRelation = indstate->ri_RelationDesc;
110
111 /* Need a slot to hold the tuple being examined */
112 slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
114 ExecStoreHeapTuple(heapTuple, slot, false);
115
116 /*
117 * for each index, form and insert the index tuple
118 */
119 for (i = 0; i < numIndexes; i++)
120 {
121 IndexInfo *indexInfo;
123
124 indexInfo = indexInfoArray[i];
125 index = relationDescs[i];
126
127 /* If the index is marked as read-only, ignore it */
128 if (!indexInfo->ii_ReadyForInserts)
129 continue;
130
131 /*
132 * Expressional and partial indexes on system catalogs are not
133 * supported, nor exclusion constraints, nor deferred uniqueness
134 */
135 Assert(indexInfo->ii_Expressions == NIL);
136 Assert(indexInfo->ii_Predicate == NIL);
137 Assert(indexInfo->ii_ExclusionOps == NULL);
138 Assert(index->rd_index->indimmediate);
139 Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
140
141 /* see earlier check above */
142#ifdef USE_ASSERT_CHECKING
143 if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
144 {
146 continue;
147 }
148#endif /* USE_ASSERT_CHECKING */
149
150 /*
151 * Skip insertions into non-summarizing indexes if we only need to
152 * update summarizing indexes.
153 */
154 if (onlySummarized && !indexInfo->ii_Summarizing)
155 continue;
156
157 /*
158 * FormIndexDatum fills in its values and isnull parameters with the
159 * appropriate values for the column(s) of the index.
160 */
161 FormIndexDatum(indexInfo,
162 slot,
163 NULL, /* no expression eval to do */
164 values,
165 isnull);
166
167 /*
168 * The index AM does the rest.
169 */
170 index_insert(index, /* index relation */
171 values, /* array of index Datums */
172 isnull, /* is-null flags */
173 &(heapTuple->t_self), /* tid of heap tuple */
174 heapRelation,
175 index->rd_index->indisunique ?
177 false,
178 indexInfo);
179 }
180
182}
183
184/*
185 * Subroutine to verify that catalog constraints are honored.
186 *
187 * Tuples inserted via CatalogTupleInsert/CatalogTupleUpdate are generally
188 * "hand made", so that it's possible that they fail to satisfy constraints
189 * that would be checked if they were being inserted by the executor. That's
190 * a coding error, so we only bother to check for it in assert-enabled builds.
191 */
192#ifdef USE_ASSERT_CHECKING
193
194static void
196{
197 /*
198 * Currently, the only constraints implemented for system catalogs are
199 * attnotnull constraints.
200 */
201 if (HeapTupleHasNulls(tup))
202 {
203 TupleDesc tupdesc = RelationGetDescr(heapRel);
204 bits8 *bp = tup->t_data->t_bits;
205
206 for (int attnum = 0; attnum < tupdesc->natts; attnum++)
207 {
208 Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
209
210 Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
211 }
212 }
213}
214
215#else /* !USE_ASSERT_CHECKING */
216
217#define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0)
218
219#endif /* USE_ASSERT_CHECKING */
220
221/*
222 * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
223 *
224 * Insert the tuple data in "tup" into the specified catalog relation.
225 *
226 * This is a convenience routine for the common case of inserting a single
227 * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
228 * current. Avoid using it for multiple tuples, since opening the indexes
229 * and building the index info structures is moderately expensive.
230 * (Use CatalogTupleInsertWithInfo in such cases.)
231 */
232void
234{
235 CatalogIndexState indstate;
236
237 CatalogTupleCheckConstraints(heapRel, tup);
238
239 indstate = CatalogOpenIndexes(heapRel);
240
241 simple_heap_insert(heapRel, tup);
242
243 CatalogIndexInsert(indstate, tup, TU_All);
244 CatalogCloseIndexes(indstate);
245}
246
247/*
248 * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
249 *
250 * This should be used when it's important to amortize CatalogOpenIndexes/
251 * CatalogCloseIndexes work across multiple insertions. At some point we
252 * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
253 * so that callers needn't trouble over this ... but we don't do so today.
254 */
255void
257 CatalogIndexState indstate)
258{
259 CatalogTupleCheckConstraints(heapRel, tup);
260
261 simple_heap_insert(heapRel, tup);
262
263 CatalogIndexInsert(indstate, tup, TU_All);
264}
265
266/*
267 * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
268 *
269 * Insert multiple tuples into the given catalog relation at once, with an
270 * amortized cost of CatalogOpenIndexes.
271 */
272void
274 int ntuples, CatalogIndexState indstate)
275{
276 /* Nothing to do */
277 if (ntuples <= 0)
278 return;
279
280 heap_multi_insert(heapRel, slot, ntuples,
281 GetCurrentCommandId(true), 0, NULL);
282
283 /*
284 * There is no equivalent to heap_multi_insert for the catalog indexes, so
285 * we must loop over and insert individually.
286 */
287 for (int i = 0; i < ntuples; i++)
288 {
289 bool should_free;
290 HeapTuple tuple;
291
292 tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
293 tuple->t_tableOid = slot[i]->tts_tableOid;
294 CatalogIndexInsert(indstate, tuple, TU_All);
295
296 if (should_free)
297 heap_freetuple(tuple);
298 }
299}
300
301/*
302 * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
303 *
304 * Update the tuple identified by "otid", replacing it with the data in "tup".
305 *
306 * This is a convenience routine for the common case of updating a single
307 * tuple in a system catalog; it updates one heap tuple, keeping indexes
308 * current. Avoid using it for multiple tuples, since opening the indexes
309 * and building the index info structures is moderately expensive.
310 * (Use CatalogTupleUpdateWithInfo in such cases.)
311 */
312void
314{
315 CatalogIndexState indstate;
316 TU_UpdateIndexes updateIndexes = TU_All;
317
318 CatalogTupleCheckConstraints(heapRel, tup);
319
320 indstate = CatalogOpenIndexes(heapRel);
321
322 simple_heap_update(heapRel, otid, tup, &updateIndexes);
323
324 CatalogIndexInsert(indstate, tup, updateIndexes);
325 CatalogCloseIndexes(indstate);
326}
327
328/*
329 * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
330 *
331 * This should be used when it's important to amortize CatalogOpenIndexes/
332 * CatalogCloseIndexes work across multiple updates. At some point we
333 * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
334 * so that callers needn't trouble over this ... but we don't do so today.
335 */
336void
338 CatalogIndexState indstate)
339{
340 TU_UpdateIndexes updateIndexes = TU_All;
341
342 CatalogTupleCheckConstraints(heapRel, tup);
343
344 simple_heap_update(heapRel, otid, tup, &updateIndexes);
345
346 CatalogIndexInsert(indstate, tup, updateIndexes);
347}
348
349/*
350 * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
351 *
352 * Delete the tuple identified by "tid" in the specified catalog.
353 *
354 * With Postgres heaps, there is no index work to do at deletion time;
355 * cleanup will be done later by VACUUM. However, callers of this function
356 * shouldn't have to know that; we'd like a uniform abstraction for all
357 * catalog tuple changes. Hence, provide this currently-trivial wrapper.
358 *
359 * The abstraction is a bit leaky in that we don't provide an optimized
360 * CatalogTupleDeleteWithInfo version, because there is currently nothing to
361 * optimize. If we ever need that, rather than touching a lot of call sites,
362 * it might be better to do something about caching CatalogIndexState.
363 */
364void
366{
367 simple_heap_delete(heapRel, tid);
368}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define Assert(condition)
Definition: c.h:815
uint8 bits8
Definition: c.h:495
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:236
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:160
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1441
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1831
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1539
@ UNIQUE_CHECK_NO
Definition: genam.h:119
@ UNIQUE_CHECK_YES
Definition: genam.h:120
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:3118
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup, TU_UpdateIndexes *update_indexes)
Definition: heapam.c:4406
void simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2639
void heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, int options, BulkInsertState bistate)
Definition: heapam.c:2277
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
static bool HeapTupleHasNulls(const HeapTupleData *tuple)
Definition: htup_details.h:738
static bool HeapTupleIsHeapOnly(const HeapTupleData *tuple)
Definition: htup_details.h:786
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4113
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2730
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: indexam.c:213
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
static void CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple, TU_UpdateIndexes updateIndexes)
Definition: indexing.c:75
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
#define CatalogTupleCheckConstraints(heapRel, tup)
Definition: indexing.c:217
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:256
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:337
int i
Definition: isn.c:72
void pfree(void *pointer)
Definition: mcxt.c:1521
#define makeNode(_type_)
Definition: nodes.h:155
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define INDEX_MAX_KEYS
#define NIL
Definition: pg_list.h:68
uintptr_t Datum
Definition: postgres.h:69
#define RelationGetRelid(relation)
Definition: rel.h:512
#define RelationGetDescr(relation)
Definition: rel.h:538
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:178
Oid * ii_ExclusionOps
Definition: execnodes.h:202
int ii_NumIndexKeyAttrs
Definition: execnodes.h:196
List * ii_Expressions
Definition: execnodes.h:198
bool ii_Summarizing
Definition: execnodes.h:215
bool ii_ReadyForInserts
Definition: execnodes.h:210
List * ii_Predicate
Definition: execnodes.h:200
int ri_NumIndices
Definition: execnodes.h:477
Relation ri_RelationDesc
Definition: execnodes.h:474
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:480
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:509
Index ri_RangeTableIndex
Definition: execnodes.h:471
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:483
Oid tts_tableOid
Definition: tuptable.h:130
Definition: type.h:96
TU_UpdateIndexes
Definition: tableam.h:117
@ TU_Summarizing
Definition: tableam.h:125
@ TU_All
Definition: tableam.h:122
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154
static bool att_isnull(int ATT, const bits8 *BITS)
Definition: tupmacs.h:26
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:828