1/*-------------------------------------------------------------------------
2 *
3 * indexing.c
4 * This file contains routines to support indexes defined on system
5 * catalogs.
6 *
7 * Portions Copyright (c) 1996-2019, 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 "catalog/index.h"
22#include "catalog/indexing.h"
23#include "executor/executor.h"
24#include "utils/rel.h"
25
26
27/*
28 * CatalogOpenIndexes - open the indexes on a system catalog.
29 *
30 * When inserting or updating tuples in a system catalog, call this
31 * to prepare to update the indexes for the catalog.
32 *
33 * In the current implementation, we share code for opening/closing the
34 * indexes with execUtils.c. But we do not use ExecInsertIndexTuples,
35 * because we don't want to create an EState. This implies that we
36 * do not support partial or expressional indexes on system catalogs,
37 * nor can we support generalized exclusion constraints.
38 * This could be fixed with localized changes here if we wanted to pay
39 * the extra overhead of building an EState.
40 */
41CatalogIndexState
42CatalogOpenIndexes(Relation heapRel)
43{
44 ResultRelInfo *resultRelInfo;
45
46 resultRelInfo = makeNode(ResultRelInfo);
47 resultRelInfo->ri_RangeTableIndex = 0; /* dummy */
48 resultRelInfo->ri_RelationDesc = heapRel;
49 resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
50
51 ExecOpenIndices(resultRelInfo, false);
52
53 return resultRelInfo;
54}
55
56/*
57 * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
58 */
59void
60CatalogCloseIndexes(CatalogIndexState indstate)
61{
62 ExecCloseIndices(indstate);
63 pfree(indstate);
64}
65
66/*
67 * CatalogIndexInsert - insert index entries for one catalog tuple
68 *
69 * This should be called for each inserted or updated catalog tuple.
70 *
71 * This is effectively a cut-down version of ExecInsertIndexTuples.
72 */
73static void
74CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
75{
76 int i;
77 int numIndexes;
78 RelationPtr relationDescs;
79 Relation heapRelation;
80 TupleTableSlot *slot;
81 IndexInfo **indexInfoArray;
82 Datum values[INDEX_MAX_KEYS];
83 bool isnull[INDEX_MAX_KEYS];
84
85 /*
86 * HOT update does not require index inserts. But with asserts enabled we
87 * want to check that it'd be legal to currently insert into the
88 * table/index.
89 */
90#ifndef USE_ASSERT_CHECKING
91 if (HeapTupleIsHeapOnly(heapTuple))
92 return;
93#endif
94
95 /*
96 * Get information from the state structure. Fall out if nothing to do.
97 */
98 numIndexes = indstate->ri_NumIndices;
99 if (numIndexes == 0)
100 return;
101 relationDescs = indstate->ri_IndexRelationDescs;
102 indexInfoArray = indstate->ri_IndexRelationInfo;
103 heapRelation = indstate->ri_RelationDesc;
104
105 /* Need a slot to hold the tuple being examined */
106 slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
107 &TTSOpsHeapTuple);
108 ExecStoreHeapTuple(heapTuple, slot, false);
109
110 /*
111 * for each index, form and insert the index tuple
112 */
113 for (i = 0; i < numIndexes; i++)
114 {
115 IndexInfo *indexInfo;
116 Relation index;
117
118 indexInfo = indexInfoArray[i];
119 index = relationDescs[i];
120
121 /* If the index is marked as read-only, ignore it */
122 if (!indexInfo->ii_ReadyForInserts)
123 continue;
124
125 /*
126 * Expressional and partial indexes on system catalogs are not
127 * supported, nor exclusion constraints, nor deferred uniqueness
128 */
129 Assert(indexInfo->ii_Expressions == NIL);
130 Assert(indexInfo->ii_Predicate == NIL);
131 Assert(indexInfo->ii_ExclusionOps == NULL);
132 Assert(index->rd_index->indimmediate);
133 Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
134
135 /* see earlier check above */
136#ifdef USE_ASSERT_CHECKING
137 if (HeapTupleIsHeapOnly(heapTuple))
138 {
139 Assert(!ReindexIsProcessingIndex(RelationGetRelid(index)));
140 continue;
141 }
142#endif /* USE_ASSERT_CHECKING */
143
144 /*
145 * FormIndexDatum fills in its values and isnull parameters with the
146 * appropriate values for the column(s) of the index.
147 */
148 FormIndexDatum(indexInfo,
149 slot,
150 NULL, /* no expression eval to do */
151 values,
152 isnull);
153
154 /*
155 * The index AM does the rest.
156 */
157 index_insert(index, /* index relation */
158 values, /* array of index Datums */
159 isnull, /* is-null flags */
160 &(heapTuple->t_self), /* tid of heap tuple */
161 heapRelation,
162 index->rd_index->indisunique ?
163 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
164 indexInfo);
165 }
166
167 ExecDropSingleTupleTableSlot(slot);
168}
169
170/*
171 * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
172 *
173 * Insert the tuple data in "tup" into the specified catalog relation.
174 * The Oid of the inserted tuple is returned.
175 *
176 * This is a convenience routine for the common case of inserting a single
177 * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
178 * current. Avoid using it for multiple tuples, since opening the indexes
179 * and building the index info structures is moderately expensive.
180 * (Use CatalogTupleInsertWithInfo in such cases.)
181 */
182void
183CatalogTupleInsert(Relation heapRel, HeapTuple tup)
184{
185 CatalogIndexState indstate;
186
187 indstate = CatalogOpenIndexes(heapRel);
188
189 simple_heap_insert(heapRel, tup);
190
191 CatalogIndexInsert(indstate, tup);
192 CatalogCloseIndexes(indstate);
193}
194
195/*
196 * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
197 *
198 * This should be used when it's important to amortize CatalogOpenIndexes/
199 * CatalogCloseIndexes work across multiple insertions. At some point we
200 * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
201 * so that callers needn't trouble over this ... but we don't do so today.
202 */
203void
204CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
205 CatalogIndexState indstate)
206{
207 simple_heap_insert(heapRel, tup);
208
209 CatalogIndexInsert(indstate, tup);
210}
211
212/*
213 * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
214 *
215 * Update the tuple identified by "otid", replacing it with the data in "tup".
216 *
217 * This is a convenience routine for the common case of updating a single
218 * tuple in a system catalog; it updates one heap tuple, keeping indexes
219 * current. Avoid using it for multiple tuples, since opening the indexes
220 * and building the index info structures is moderately expensive.
221 * (Use CatalogTupleUpdateWithInfo in such cases.)
222 */
223void
224CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
225{
226 CatalogIndexState indstate;
227
228 indstate = CatalogOpenIndexes(heapRel);
229
230 simple_heap_update(heapRel, otid, tup);
231
232 CatalogIndexInsert(indstate, tup);
233 CatalogCloseIndexes(indstate);
234}
235
236/*
237 * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
238 *
239 * This should be used when it's important to amortize CatalogOpenIndexes/
240 * CatalogCloseIndexes work across multiple updates. At some point we
241 * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
242 * so that callers needn't trouble over this ... but we don't do so today.
243 */
244void
245CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
246 CatalogIndexState indstate)
247{
248 simple_heap_update(heapRel, otid, tup);
249
250 CatalogIndexInsert(indstate, tup);
251}
252
253/*
254 * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
255 *
256 * Delete the tuple identified by "tid" in the specified catalog.
257 *
258 * With Postgres heaps, there is no index work to do at deletion time;
259 * cleanup will be done later by VACUUM. However, callers of this function
260 * shouldn't have to know that; we'd like a uniform abstraction for all
261 * catalog tuple changes. Hence, provide this currently-trivial wrapper.
262 *
263 * The abstraction is a bit leaky in that we don't provide an optimized
264 * CatalogTupleDeleteWithInfo version, because there is currently nothing to
265 * optimize. If we ever need that, rather than touching a lot of call sites,
266 * it might be better to do something about caching CatalogIndexState.
267 */
268void
269CatalogTupleDelete(Relation heapRel, ItemPointer tid)
270{
271 simple_heap_delete(heapRel, tid);
272}
273