Define __EXTENSIONS__ on Solaris, too.
[pgsql.git] / src / backend / catalog / indexing.c
blobd0d1abda58af3d6647b88e101e09e8b276b65af6
1 /*-------------------------------------------------------------------------
3 * indexing.c
4 * This file contains routines to support indexes defined on system
5 * catalogs.
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * src/backend/catalog/indexing.c
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
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"
29 * CatalogOpenIndexes - open the indexes on a system catalog.
31 * When inserting or updating tuples in a system catalog, call this
32 * to prepare to update the indexes for the catalog.
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.
42 CatalogIndexState
43 CatalogOpenIndexes(Relation heapRel)
45 ResultRelInfo *resultRelInfo;
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 */
52 ExecOpenIndices(resultRelInfo, false);
54 return resultRelInfo;
58 * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
60 void
61 CatalogCloseIndexes(CatalogIndexState indstate)
63 ExecCloseIndices(indstate);
64 pfree(indstate);
68 * CatalogIndexInsert - insert index entries for one catalog tuple
70 * This should be called for each inserted or updated catalog tuple.
72 * This is effectively a cut-down version of ExecInsertIndexTuples.
74 static void
75 CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple,
76 TU_UpdateIndexes updateIndexes)
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 bool onlySummarized = (updateIndexes == TU_Summarizing);
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.
93 #ifndef USE_ASSERT_CHECKING
94 if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
95 return;
96 #endif
98 /* When only updating summarized indexes, the tuple has to be HOT. */
99 Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
102 * Get information from the state structure. Fall out if nothing to do.
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;
111 /* Need a slot to hold the tuple being examined */
112 slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
113 &TTSOpsHeapTuple);
114 ExecStoreHeapTuple(heapTuple, slot, false);
117 * for each index, form and insert the index tuple
119 for (i = 0; i < numIndexes; i++)
121 IndexInfo *indexInfo;
122 Relation index;
124 indexInfo = indexInfoArray[i];
125 index = relationDescs[i];
127 /* If the index is marked as read-only, ignore it */
128 if (!indexInfo->ii_ReadyForInserts)
129 continue;
132 * Expressional and partial indexes on system catalogs are not
133 * supported, nor exclusion constraints, nor deferred uniqueness
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);
141 /* see earlier check above */
142 #ifdef USE_ASSERT_CHECKING
143 if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
145 Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
146 continue;
148 #endif /* USE_ASSERT_CHECKING */
151 * Skip insertions into non-summarizing indexes if we only need to
152 * update summarizing indexes.
154 if (onlySummarized && !indexInfo->ii_Summarizing)
155 continue;
158 * FormIndexDatum fills in its values and isnull parameters with the
159 * appropriate values for the column(s) of the index.
161 FormIndexDatum(indexInfo,
162 slot,
163 NULL, /* no expression eval to do */
164 values,
165 isnull);
168 * The index AM does the rest.
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 ?
176 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
177 false,
178 indexInfo);
181 ExecDropSingleTupleTableSlot(slot);
185 * Subroutine to verify that catalog constraints are honored.
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.
192 #ifdef USE_ASSERT_CHECKING
194 static void
195 CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup)
198 * Currently, the only constraints implemented for system catalogs are
199 * attnotnull constraints.
201 if (HeapTupleHasNulls(tup))
203 TupleDesc tupdesc = RelationGetDescr(heapRel);
204 bits8 *bp = tup->t_data->t_bits;
206 for (int attnum = 0; attnum < tupdesc->natts; attnum++)
208 Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
210 Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
215 #else /* !USE_ASSERT_CHECKING */
217 #define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0)
219 #endif /* USE_ASSERT_CHECKING */
222 * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
224 * Insert the tuple data in "tup" into the specified catalog relation.
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.)
232 void
233 CatalogTupleInsert(Relation heapRel, HeapTuple tup)
235 CatalogIndexState indstate;
237 CatalogTupleCheckConstraints(heapRel, tup);
239 indstate = CatalogOpenIndexes(heapRel);
241 simple_heap_insert(heapRel, tup);
243 CatalogIndexInsert(indstate, tup, TU_All);
244 CatalogCloseIndexes(indstate);
248 * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
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.
255 void
256 CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
257 CatalogIndexState indstate)
259 CatalogTupleCheckConstraints(heapRel, tup);
261 simple_heap_insert(heapRel, tup);
263 CatalogIndexInsert(indstate, tup, TU_All);
267 * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
269 * Insert multiple tuples into the given catalog relation at once, with an
270 * amortized cost of CatalogOpenIndexes.
272 void
273 CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
274 int ntuples, CatalogIndexState indstate)
276 /* Nothing to do */
277 if (ntuples <= 0)
278 return;
280 heap_multi_insert(heapRel, slot, ntuples,
281 GetCurrentCommandId(true), 0, NULL);
284 * There is no equivalent to heap_multi_insert for the catalog indexes, so
285 * we must loop over and insert individually.
287 for (int i = 0; i < ntuples; i++)
289 bool should_free;
290 HeapTuple tuple;
292 tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
293 tuple->t_tableOid = slot[i]->tts_tableOid;
294 CatalogIndexInsert(indstate, tuple, TU_All);
296 if (should_free)
297 heap_freetuple(tuple);
302 * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
304 * Update the tuple identified by "otid", replacing it with the data in "tup".
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.)
312 void
313 CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
315 CatalogIndexState indstate;
316 TU_UpdateIndexes updateIndexes = TU_All;
318 CatalogTupleCheckConstraints(heapRel, tup);
320 indstate = CatalogOpenIndexes(heapRel);
322 simple_heap_update(heapRel, otid, tup, &updateIndexes);
324 CatalogIndexInsert(indstate, tup, updateIndexes);
325 CatalogCloseIndexes(indstate);
329 * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
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.
336 void
337 CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
338 CatalogIndexState indstate)
340 TU_UpdateIndexes updateIndexes = TU_All;
342 CatalogTupleCheckConstraints(heapRel, tup);
344 simple_heap_update(heapRel, otid, tup, &updateIndexes);
346 CatalogIndexInsert(indstate, tup, updateIndexes);
350 * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
352 * Delete the tuple identified by "tid" in the specified catalog.
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.
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.
364 void
365 CatalogTupleDelete(Relation heapRel, ItemPointer tid)
367 simple_heap_delete(heapRel, tid);