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 | */ |
41 | CatalogIndexState |
42 | CatalogOpenIndexes(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 | */ |
59 | void |
60 | CatalogCloseIndexes(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 | */ |
73 | static void |
74 | CatalogIndexInsert(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 | */ |
182 | void |
183 | CatalogTupleInsert(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 | */ |
203 | void |
204 | CatalogTupleInsertWithInfo(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 | */ |
223 | void |
224 | CatalogTupleUpdate(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 | */ |
244 | void |
245 | CatalogTupleUpdateWithInfo(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 | */ |
268 | void |
269 | CatalogTupleDelete(Relation heapRel, ItemPointer tid) |
270 | { |
271 | simple_heap_delete(heapRel, tid); |
272 | } |
273 | |