Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * indexing.c
4 : * This file contains routines to support indexes defined on system
5 : * catalogs.
6 : *
7 : * Portions Copyright (c) 1996-2024, 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 : */
42 : CatalogIndexState
43 1350092 : CatalogOpenIndexes(Relation heapRel)
44 : {
45 : ResultRelInfo *resultRelInfo;
46 :
47 1350092 : resultRelInfo = makeNode(ResultRelInfo);
48 1350092 : resultRelInfo->ri_RangeTableIndex = 0; /* dummy */
49 1350092 : resultRelInfo->ri_RelationDesc = heapRel;
50 1350092 : resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
51 :
52 1350092 : ExecOpenIndices(resultRelInfo, false);
53 :
54 1350092 : return resultRelInfo;
55 : }
56 :
57 : /*
58 : * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
59 : */
60 : void
61 1350090 : CatalogCloseIndexes(CatalogIndexState indstate)
62 : {
63 1350090 : ExecCloseIndices(indstate);
64 1350090 : pfree(indstate);
65 1350090 : }
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 : */
74 : static void
75 2437868 : CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple,
76 : TU_UpdateIndexes updateIndexes)
77 : {
78 : int i;
79 : int numIndexes;
80 : RelationPtr relationDescs;
81 : Relation heapRelation;
82 : TupleTableSlot *slot;
83 : IndexInfo **indexInfoArray;
84 : Datum values[INDEX_MAX_KEYS];
85 : bool isnull[INDEX_MAX_KEYS];
86 2437868 : 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 2437868 : if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
95 312246 : 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 2303462 : numIndexes = indstate->ri_NumIndices;
105 2303462 : if (numIndexes == 0)
106 177840 : return;
107 2125622 : relationDescs = indstate->ri_IndexRelationDescs;
108 2125622 : indexInfoArray = indstate->ri_IndexRelationInfo;
109 2125622 : heapRelation = indstate->ri_RelationDesc;
110 :
111 : /* Need a slot to hold the tuple being examined */
112 2125622 : slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
113 : &TTSOpsHeapTuple);
114 2125622 : ExecStoreHeapTuple(heapTuple, slot, false);
115 :
116 : /*
117 : * for each index, form and insert the index tuple
118 : */
119 6730354 : for (i = 0; i < numIndexes; i++)
120 : {
121 : IndexInfo *indexInfo;
122 : Relation index;
123 :
124 4604734 : indexInfo = indexInfoArray[i];
125 4604734 : index = relationDescs[i];
126 :
127 : /* If the index is marked as read-only, ignore it */
128 4604734 : if (!indexInfo->ii_ReadyForInserts)
129 0 : 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 : {
145 : Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
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 4604734 : if (onlySummarized && !indexInfo->ii_Summarizing)
155 0 : 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 4604734 : 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 4604734 : 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 4604734 : index->rd_index->indisunique ?
176 : UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
177 : false,
178 : indexInfo);
179 : }
180 :
181 2125620 : ExecDropSingleTupleTableSlot(slot);
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 :
194 : static void
195 : CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
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 : */
232 : void
233 591722 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
234 : {
235 : CatalogIndexState indstate;
236 :
237 : CatalogTupleCheckConstraints(heapRel, tup);
238 :
239 591722 : indstate = CatalogOpenIndexes(heapRel);
240 :
241 591722 : simple_heap_insert(heapRel, tup);
242 :
243 591722 : CatalogIndexInsert(indstate, tup, TU_All);
244 591720 : CatalogCloseIndexes(indstate);
245 591720 : }
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 : */
255 : void
256 50240 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
257 : CatalogIndexState indstate)
258 : {
259 : CatalogTupleCheckConstraints(heapRel, tup);
260 :
261 50240 : simple_heap_insert(heapRel, tup);
262 :
263 50240 : CatalogIndexInsert(indstate, tup, TU_All);
264 50240 : }
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 : */
272 : void
273 645344 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
274 : int ntuples, CatalogIndexState indstate)
275 : {
276 : /* Nothing to do */
277 645344 : if (ntuples <= 0)
278 0 : return;
279 :
280 645344 : 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 2250852 : for (int i = 0; i < ntuples; i++)
288 : {
289 : bool should_free;
290 : HeapTuple tuple;
291 :
292 1605508 : tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
293 1605508 : tuple->t_tableOid = slot[i]->tts_tableOid;
294 1605508 : CatalogIndexInsert(indstate, tuple, TU_All);
295 :
296 1605508 : if (should_free)
297 0 : 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 : */
312 : void
313 158736 : CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
314 : {
315 : CatalogIndexState indstate;
316 158736 : TU_UpdateIndexes updateIndexes = TU_All;
317 :
318 : CatalogTupleCheckConstraints(heapRel, tup);
319 :
320 158736 : indstate = CatalogOpenIndexes(heapRel);
321 :
322 158736 : simple_heap_update(heapRel, otid, tup, &updateIndexes);
323 :
324 158736 : CatalogIndexInsert(indstate, tup, updateIndexes);
325 158736 : CatalogCloseIndexes(indstate);
326 158736 : }
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 : */
336 : void
337 31662 : CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
338 : CatalogIndexState indstate)
339 : {
340 31662 : TU_UpdateIndexes updateIndexes = TU_All;
341 :
342 : CatalogTupleCheckConstraints(heapRel, tup);
343 :
344 31662 : simple_heap_update(heapRel, otid, tup, &updateIndexes);
345 :
346 31662 : CatalogIndexInsert(indstate, tup, updateIndexes);
347 31662 : }
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 : */
364 : void
365 1172178 : CatalogTupleDelete(Relation heapRel, ItemPointer tid)
366 : {
367 1172178 : simple_heap_delete(heapRel, tid);
368 1172178 : }
|