Age Owner Branch data TLA 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
7923 tgl@sss.pgh.pa.us 43 :CBC 642707 : CatalogOpenIndexes(Relation heapRel)
44 : : {
45 : : ResultRelInfo *resultRelInfo;
46 : :
47 : 642707 : resultRelInfo = makeNode(ResultRelInfo);
2019 48 : 642707 : resultRelInfo->ri_RangeTableIndex = 0; /* dummy */
7923 49 : 642707 : resultRelInfo->ri_RelationDesc = heapRel;
7893 bruce@momjian.us 50 : 642707 : resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
51 : :
3264 andres@anarazel.de 52 : 642707 : ExecOpenIndices(resultRelInfo, false);
53 : :
7923 tgl@sss.pgh.pa.us 54 : 642707 : return resultRelInfo;
55 : : }
56 : :
57 : : /*
58 : : * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
59 : : */
60 : : void
61 : 642706 : CatalogCloseIndexes(CatalogIndexState indstate)
62 : : {
63 : 642706 : ExecCloseIndices(indstate);
64 : 642706 : pfree(indstate);
10141 scrappy@hub.org 65 : 642706 : }
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
391 tomas.vondra@postgre 75 : 1163678 : 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 : 1163678 : 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 [ - + - - ]: 1163678 : Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
100 : :
101 : : /*
102 : : * Get information from the state structure. Fall out if nothing to do.
103 : : */
7923 tgl@sss.pgh.pa.us 104 : 1163678 : numIndexes = indstate->ri_NumIndices;
6969 105 [ + + ]: 1163678 : if (numIndexes == 0)
106 : 77025 : return;
7923 107 : 1086653 : relationDescs = indstate->ri_IndexRelationDescs;
108 : 1086653 : indexInfoArray = indstate->ri_IndexRelationInfo;
109 : 1086653 : heapRelation = indstate->ri_RelationDesc;
110 : :
111 : : /* Need a slot to hold the tuple being examined */
1977 andres@anarazel.de 112 : 1086653 : slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
113 : : &TTSOpsHeapTuple);
2028 114 : 1086653 : ExecStoreHeapTuple(heapTuple, slot, false);
115 : :
116 : : /*
117 : : * for each index, form and insert the index tuple
118 : : */
7923 tgl@sss.pgh.pa.us 119 [ + + ]: 3443544 : for (i = 0; i < numIndexes; i++)
120 : : {
121 : : IndexInfo *indexInfo;
122 : : Relation index;
123 : :
124 : 2356892 : indexInfo = indexInfoArray[i];
1812 andres@anarazel.de 125 : 2356892 : index = relationDescs[i];
126 : :
127 : : /* If the index is marked as read-only, ignore it */
6051 tgl@sss.pgh.pa.us 128 [ - + ]: 2356892 : if (!indexInfo->ii_ReadyForInserts)
6051 tgl@sss.pgh.pa.us 129 :UBC 0 : continue;
130 : :
131 : : /*
132 : : * Expressional and partial indexes on system catalogs are not
133 : : * supported, nor exclusion constraints, nor deferred uniqueness
134 : : */
7627 tgl@sss.pgh.pa.us 135 [ - + ]:CBC 2356892 : Assert(indexInfo->ii_Expressions == NIL);
7923 136 [ - + ]: 2356892 : Assert(indexInfo->ii_Predicate == NIL);
5242 137 [ - + ]: 2356892 : Assert(indexInfo->ii_ExclusionOps == NULL);
1812 andres@anarazel.de 138 [ - + ]: 2356892 : Assert(index->rd_index->indimmediate);
2199 teodor@sigaev.ru 139 [ - + ]: 2356892 : Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
140 : :
141 : : /* see earlier check above */
142 : : #ifdef USE_ASSERT_CHECKING
391 tomas.vondra@postgre 143 [ + + + - ]: 2356892 : if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
144 : : {
1812 andres@anarazel.de 145 [ - + ]: 148239 : Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
146 : 148239 : 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 : : */
391 tomas.vondra@postgre 154 [ - + - - ]: 2208653 : if (onlySummarized && !indexInfo->ii_Summarizing)
391 tomas.vondra@postgre 155 :UBC 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 : : */
8675 tgl@sss.pgh.pa.us 161 :CBC 2208653 : 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 : : */
1811 andres@anarazel.de 170 : 2208653 : 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 : 2208653 : index->rd_index->indisunique ?
176 : : UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
177 : : false,
178 : : indexInfo);
179 : : }
180 : :
6969 tgl@sss.pgh.pa.us 181 : 1086652 : 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
1363 195 : 403605 : CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
196 : : {
197 : : /*
198 : : * Currently, the only constraints implemented for system catalogs are
199 : : * attnotnull constraints.
200 : : */
201 [ + + ]: 403605 : if (HeapTupleHasNulls(tup))
202 : : {
203 : 333313 : TupleDesc tupdesc = RelationGetDescr(heapRel);
204 : 333313 : bits8 *bp = tup->t_data->t_bits;
205 : :
206 [ + + ]: 9222301 : for (int attnum = 0; attnum < tupdesc->natts; attnum++)
207 : : {
208 : 8888988 : Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
209 : :
210 [ + + - + ]: 8888988 : Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
211 : : }
212 : : }
213 : 403605 : }
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
2630 alvherre@alvh.no-ip. 233 : 291587 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
234 : : {
235 : : CatalogIndexState indstate;
236 : :
1363 tgl@sss.pgh.pa.us 237 : 291587 : CatalogTupleCheckConstraints(heapRel, tup);
238 : :
2630 alvherre@alvh.no-ip. 239 : 291587 : indstate = CatalogOpenIndexes(heapRel);
240 : :
1972 andres@anarazel.de 241 : 291587 : simple_heap_insert(heapRel, tup);
242 : :
391 tomas.vondra@postgre 243 : 291587 : CatalogIndexInsert(indstate, tup, TU_All);
2630 alvherre@alvh.no-ip. 244 : 291586 : CatalogCloseIndexes(indstate);
245 : 291586 : }
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
2629 tgl@sss.pgh.pa.us 256 : 23018 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
257 : : CatalogIndexState indstate)
258 : : {
1363 259 : 23018 : CatalogTupleCheckConstraints(heapRel, tup);
260 : :
1972 andres@anarazel.de 261 : 23018 : simple_heap_insert(heapRel, tup);
262 : :
391 tomas.vondra@postgre 263 : 23018 : CatalogIndexInsert(indstate, tup, TU_All);
2629 tgl@sss.pgh.pa.us 264 : 23018 : }
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
1353 michael@paquier.xyz 273 : 301710 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
274 : : int ntuples, CatalogIndexState indstate)
275 : : {
276 : : /* Nothing to do */
277 [ - + ]: 301710 : if (ntuples <= 0)
1353 michael@paquier.xyz 278 :UBC 0 : return;
279 : :
1353 michael@paquier.xyz 280 :CBC 301710 : 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 [ + + ]: 1061783 : for (int i = 0; i < ntuples; i++)
288 : : {
289 : : bool should_free;
290 : : HeapTuple tuple;
291 : :
292 : 760073 : tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
293 : 760073 : tuple->t_tableOid = slot[i]->tts_tableOid;
391 tomas.vondra@postgre 294 : 760073 : CatalogIndexInsert(indstate, tuple, TU_All);
295 : :
1353 michael@paquier.xyz 296 [ - + ]: 760073 : if (should_free)
1353 michael@paquier.xyz 297 :UBC 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
2630 alvherre@alvh.no-ip. 313 :CBC 73296 : CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
314 : : {
315 : : CatalogIndexState indstate;
391 tomas.vondra@postgre 316 : 73296 : TU_UpdateIndexes updateIndexes = TU_All;
317 : :
1363 tgl@sss.pgh.pa.us 318 : 73296 : CatalogTupleCheckConstraints(heapRel, tup);
319 : :
7923 320 : 73296 : indstate = CatalogOpenIndexes(heapRel);
321 : :
391 tomas.vondra@postgre 322 : 73296 : simple_heap_update(heapRel, otid, tup, &updateIndexes);
323 : :
324 : 73296 : CatalogIndexInsert(indstate, tup, updateIndexes);
7923 tgl@sss.pgh.pa.us 325 : 73296 : CatalogCloseIndexes(indstate);
326 : 73296 : }
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
2629 337 : 15704 : CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
338 : : CatalogIndexState indstate)
339 : : {
391 tomas.vondra@postgre 340 : 15704 : TU_UpdateIndexes updateIndexes = TU_All;
341 : :
1363 tgl@sss.pgh.pa.us 342 : 15704 : CatalogTupleCheckConstraints(heapRel, tup);
343 : :
391 tomas.vondra@postgre 344 : 15704 : simple_heap_update(heapRel, otid, tup, &updateIndexes);
345 : :
346 : 15704 : CatalogIndexInsert(indstate, tup, updateIndexes);
2629 tgl@sss.pgh.pa.us 347 : 15704 : }
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 : 570169 : CatalogTupleDelete(Relation heapRel, ItemPointer tid)
366 : : {
367 : 570169 : simple_heap_delete(heapRel, tid);
368 : 570169 : }
|