Age Owner 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-2023, 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
7552 tgl 43 CBC 2201807 : CatalogOpenIndexes(Relation heapRel)
44 : {
45 : ResultRelInfo *resultRelInfo;
46 :
47 2201807 : resultRelInfo = makeNode(ResultRelInfo);
1648 48 2201807 : resultRelInfo->ri_RangeTableIndex = 0; /* dummy */
7552 49 2201807 : resultRelInfo->ri_RelationDesc = heapRel;
7522 bruce 50 2201807 : resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
51 :
2893 andres 52 2201807 : ExecOpenIndices(resultRelInfo, false);
53 :
7552 tgl 54 2201807 : return resultRelInfo;
55 : }
56 :
57 : /*
58 : * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
59 : */
60 : void
61 2201806 : CatalogCloseIndexes(CatalogIndexState indstate)
62 : {
63 2201806 : ExecCloseIndices(indstate);
64 2201806 : pfree(indstate);
9770 scrappy 65 2201806 : }
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
20 tomas.vondra 75 GNC 3684548 : 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 3684548 : bool onlySummarized = (updateIndexes == TU_Summarizing);
87 :
1441 andres 88 ECB : /*
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. */
20 tomas.vondra 99 GNC 3684548 : Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
100 :
101 : /*
102 : * Get information from the state structure. Fall out if nothing to do.
103 : */
7552 tgl 104 CBC 3684548 : numIndexes = indstate->ri_NumIndices;
6598 tgl 105 GIC 3684548 : if (numIndexes == 0)
106 601765 : return;
7552 107 3082783 : relationDescs = indstate->ri_IndexRelationDescs;
108 3082783 : indexInfoArray = indstate->ri_IndexRelationInfo;
7552 tgl 109 CBC 3082783 : heapRelation = indstate->ri_RelationDesc;
6598 tgl 110 ECB :
111 : /* Need a slot to hold the tuple being examined */
1606 andres 112 CBC 3082783 : slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
1606 andres 113 ECB : &TTSOpsHeapTuple);
1657 andres 114 CBC 3082783 : ExecStoreHeapTuple(heapTuple, slot, false);
115 :
116 : /*
7552 tgl 117 ECB : * for each index, form and insert the index tuple
118 : */
7552 tgl 119 CBC 9135002 : for (i = 0; i < numIndexes; i++)
120 : {
121 : IndexInfo *indexInfo;
122 : Relation index;
123 :
124 6052220 : indexInfo = indexInfoArray[i];
1441 andres 125 GIC 6052220 : index = relationDescs[i];
126 :
127 : /* If the index is marked as read-only, ignore it */
5680 tgl 128 6052220 : if (!indexInfo->ii_ReadyForInserts)
5680 tgl 129 LBC 0 : continue;
5680 tgl 130 ECB :
131 : /*
132 : * Expressional and partial indexes on system catalogs are not
4871 133 : * supported, nor exclusion constraints, nor deferred uniqueness
7256 tgl 134 EUB : */
7256 tgl 135 GIC 6052220 : Assert(indexInfo->ii_Expressions == NIL);
7552 136 6052220 : Assert(indexInfo->ii_Predicate == NIL);
4871 137 6052220 : Assert(indexInfo->ii_ExclusionOps == NULL);
1441 andres 138 6052220 : Assert(index->rd_index->indimmediate);
1828 teodor 139 6052220 : Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
7552 tgl 140 ECB :
1441 andres 141 : /* see earlier check above */
142 : #ifdef USE_ASSERT_CHECKING
20 tomas.vondra 143 GNC 6052220 : if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
1441 andres 144 ECB : {
1441 andres 145 GIC 372809 : Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
146 372809 : continue;
147 : }
1440 andres 148 ECB : #endif /* USE_ASSERT_CHECKING */
149 :
150 : /*
151 : * Skip insertions into non-summarizing indexes if we only need
152 : * to update summarizing indexes.
153 : */
20 tomas.vondra 154 GNC 5679411 : if (onlySummarized && !indexInfo->ii_Summarizing)
20 tomas.vondra 155 UNC 0 : continue;
156 :
7552 tgl 157 ECB : /*
6385 bruce 158 : * FormIndexDatum fills in its values and isnull parameters with the
159 : * appropriate values for the column(s) of the index.
160 : */
8304 tgl 161 GIC 5679411 : FormIndexDatum(indexInfo,
162 : slot,
163 : NULL, /* no expression eval to do */
164 : values,
165 : isnull);
9345 bruce 166 ECB :
7552 tgl 167 EUB : /*
168 : * The index AM does the rest.
169 : */
1440 andres 170 GIC 5679411 : index_insert(index, /* index relation */
171 : values, /* array of index Datums */
172 : isnull, /* is-null flags */
2118 tgl 173 ECB : &(heapTuple->t_self), /* tid of heap tuple */
174 : heapRelation,
1440 andres 175 GIC 5679411 : index->rd_index->indisunique ?
176 : UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
177 : false,
178 : indexInfo);
179 : }
180 :
6598 tgl 181 3082782 : ExecDropSingleTupleTableSlot(slot);
9770 scrappy 182 ECB : }
183 :
184 : /*
185 : * Subroutine to verify that catalog constraints are honored.
186 : *
992 tgl 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
992 tgl 195 GIC 1576638 : CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
196 : {
197 : /*
198 : * Currently, the only constraints implemented for system catalogs are
199 : * attnotnull constraints.
200 : */
201 1576638 : if (HeapTupleHasNulls(tup))
202 : {
203 1227024 : TupleDesc tupdesc = RelationGetDescr(heapRel);
204 1227024 : bits8 *bp = tup->t_data->t_bits;
205 :
206 30099598 : for (int attnum = 0; attnum < tupdesc->natts; attnum++)
992 tgl 207 ECB : {
992 tgl 208 GIC 28872574 : Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
209 :
210 28872574 : Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
211 : }
212 : }
992 tgl 213 CBC 1576638 : }
214 :
992 tgl 215 ECB : #else /* !USE_ASSERT_CHECKING */
216 :
217 : #define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0)
218 :
219 : #endif /* USE_ASSERT_CHECKING */
220 :
221 : /*
2259 alvherre 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.
2258 tgl 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
2259 alvherre 233 GIC 1244023 : CatalogTupleInsert(Relation heapRel, HeapTuple tup)
234 : {
235 : CatalogIndexState indstate;
236 :
992 tgl 237 1244023 : CatalogTupleCheckConstraints(heapRel, tup);
238 :
2259 alvherre 239 1244023 : indstate = CatalogOpenIndexes(heapRel);
240 :
1601 andres 241 1244023 : simple_heap_insert(heapRel, tup);
242 :
20 tomas.vondra 243 GNC 1244023 : CatalogIndexInsert(indstate, tup, TU_All);
2259 alvherre 244 GIC 1244022 : CatalogCloseIndexes(indstate);
2259 alvherre 245 CBC 1244022 : }
246 :
247 : /*
248 : * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
2258 tgl 249 ECB : *
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 : */
1601 andres 255 : void
2258 tgl 256 CBC 131381 : CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
2258 tgl 257 ECB : CatalogIndexState indstate)
258 : {
992 tgl 259 GIC 131381 : CatalogTupleCheckConstraints(heapRel, tup);
260 :
1601 andres 261 131381 : simple_heap_insert(heapRel, tup);
262 :
20 tomas.vondra 263 GNC 131381 : CatalogIndexInsert(indstate, tup, TU_All);
2258 tgl 264 GIC 131381 : }
265 :
266 : /*
267 : * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
982 michael 268 ECB : *
269 : * Insert multiple tuples into the given catalog relation at once, with an
270 : * amortized cost of CatalogOpenIndexes.
271 : */
272 : void
982 michael 273 CBC 808773 : CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
274 : int ntuples, CatalogIndexState indstate)
982 michael 275 ECB : {
276 : /* Nothing to do */
982 michael 277 GIC 808773 : if (ntuples <= 0)
982 michael 278 UIC 0 : return;
279 :
982 michael 280 GIC 808773 : 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
982 michael 285 ECB : * we must loop over and insert individually.
286 : */
982 michael 287 GIC 2916683 : for (int i = 0; i < ntuples; i++)
288 : {
982 michael 289 ECB : bool should_free;
982 michael 290 EUB : HeapTuple tuple;
291 :
982 michael 292 CBC 2107910 : tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
982 michael 293 GIC 2107910 : tuple->t_tableOid = slot[i]->tts_tableOid;
20 tomas.vondra 294 GNC 2107910 : CatalogIndexInsert(indstate, tuple, TU_All);
295 :
982 michael 296 GIC 2107910 : if (should_free)
982 michael 297 UIC 0 : heap_freetuple(tuple);
298 : }
982 michael 299 ECB : }
300 :
301 : /*
302 : * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
303 : *
2258 tgl 304 : * Update the tuple identified by "otid", replacing it with the data in "tup".
305 : *
2259 alvherre 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
2258 tgl 308 : * current. Avoid using it for multiple tuples, since opening the indexes
2258 tgl 309 EUB : * and building the index info structures is moderately expensive.
310 : * (Use CatalogTupleUpdateWithInfo in such cases.)
311 : */
312 : void
2259 alvherre 313 GIC 187858 : CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
314 : {
315 : CatalogIndexState indstate;
20 tomas.vondra 316 GNC 187858 : TU_UpdateIndexes updateIndexes = TU_All;
317 :
992 tgl 318 GIC 187858 : CatalogTupleCheckConstraints(heapRel, tup);
319 :
7552 320 187858 : indstate = CatalogOpenIndexes(heapRel);
321 :
20 tomas.vondra 322 GNC 187858 : simple_heap_update(heapRel, otid, tup, &updateIndexes);
323 :
324 187858 : CatalogIndexInsert(indstate, tup, updateIndexes);
7552 tgl 325 GIC 187858 : CatalogCloseIndexes(indstate);
7552 tgl 326 CBC 187858 : }
327 :
328 : /*
2258 tgl 329 ECB : * 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
2258 tgl 337 CBC 13376 : CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
2258 tgl 338 ECB : CatalogIndexState indstate)
339 : {
20 tomas.vondra 340 GNC 13376 : TU_UpdateIndexes updateIndexes = TU_All;
341 :
992 tgl 342 GIC 13376 : CatalogTupleCheckConstraints(heapRel, tup);
343 :
20 tomas.vondra 344 GNC 13376 : simple_heap_update(heapRel, otid, tup, &updateIndexes);
345 :
346 13376 : CatalogIndexInsert(indstate, tup, updateIndexes);
2258 tgl 347 GIC 13376 : }
348 :
349 : /*
350 : * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
351 : *
2258 tgl 352 ECB : * 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
2258 tgl 365 GIC 534713 : CatalogTupleDelete(Relation heapRel, ItemPointer tid)
366 : {
367 534713 : simple_heap_delete(heapRel, tid);
368 534713 : }
|