1 /*-------------------------------------------------------------------------
4 * This file contains routines to support indexes defined on system
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/catalog/indexing.c
14 *-------------------------------------------------------------------------
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.
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);
58 * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
61 CatalogCloseIndexes(CatalogIndexState indstate
)
63 ExecCloseIndices(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.
75 CatalogIndexInsert(CatalogIndexState indstate
, HeapTuple heapTuple
,
76 TU_UpdateIndexes updateIndexes
)
80 RelationPtr relationDescs
;
81 Relation heapRelation
;
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
93 #ifndef USE_ASSERT_CHECKING
94 if (HeapTupleIsHeapOnly(heapTuple
) && !onlySummarized
)
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
;
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
),
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
;
124 indexInfo
= indexInfoArray
[i
];
125 index
= relationDescs
[i
];
127 /* If the index is marked as read-only, ignore it */
128 if (!indexInfo
->ii_ReadyForInserts
)
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
)));
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
)
158 * FormIndexDatum fills in its values and isnull parameters with the
159 * appropriate values for the column(s) of the index.
161 FormIndexDatum(indexInfo
,
163 NULL
, /* no expression eval to do */
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 */
175 index
->rd_index
->indisunique
?
176 UNIQUE_CHECK_YES
: UNIQUE_CHECK_NO
,
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
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.)
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.
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.
273 CatalogTuplesMultiInsertWithInfo(Relation heapRel
, TupleTableSlot
**slot
,
274 int ntuples
, CatalogIndexState indstate
)
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
++)
292 tuple
= ExecFetchSlotHeapTuple(slot
[i
], true, &should_free
);
293 tuple
->t_tableOid
= slot
[i
]->tts_tableOid
;
294 CatalogIndexInsert(indstate
, tuple
, TU_All
);
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.)
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.
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.
365 CatalogTupleDelete(Relation heapRel
, ItemPointer tid
)
367 simple_heap_delete(heapRel
, tid
);