PostgreSQL Source Code  git master
indexing.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * indexing.c
4  * This file contains routines to support indexes defined on system
5  * catalogs.
6  *
7  * Portions Copyright (c) 1996-2021, 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  */
44 {
45  ResultRelInfo *resultRelInfo;
46 
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 */
51 
52  ExecOpenIndices(resultRelInfo, false);
53 
54  return resultRelInfo;
55 }
56 
57 /*
58  * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
59  */
60 void
62 {
63  ExecCloseIndices(indstate);
64  pfree(indstate);
65 }
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
76 {
77  int i;
78  int numIndexes;
79  RelationPtr relationDescs;
80  Relation heapRelation;
81  TupleTableSlot *slot;
82  IndexInfo **indexInfoArray;
84  bool isnull[INDEX_MAX_KEYS];
85 
86  /*
87  * HOT update does not require index inserts. But with asserts enabled we
88  * want to check that it'd be legal to currently insert into the
89  * table/index.
90  */
91 #ifndef USE_ASSERT_CHECKING
92  if (HeapTupleIsHeapOnly(heapTuple))
93  return;
94 #endif
95 
96  /*
97  * Get information from the state structure. Fall out if nothing to do.
98  */
99  numIndexes = indstate->ri_NumIndices;
100  if (numIndexes == 0)
101  return;
102  relationDescs = indstate->ri_IndexRelationDescs;
103  indexInfoArray = indstate->ri_IndexRelationInfo;
104  heapRelation = indstate->ri_RelationDesc;
105 
106  /* Need a slot to hold the tuple being examined */
107  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
108  &TTSOpsHeapTuple);
109  ExecStoreHeapTuple(heapTuple, slot, false);
110 
111  /*
112  * for each index, form and insert the index tuple
113  */
114  for (i = 0; i < numIndexes; i++)
115  {
116  IndexInfo *indexInfo;
117  Relation index;
118 
119  indexInfo = indexInfoArray[i];
120  index = relationDescs[i];
121 
122  /* If the index is marked as read-only, ignore it */
123  if (!indexInfo->ii_ReadyForInserts)
124  continue;
125 
126  /*
127  * Expressional and partial indexes on system catalogs are not
128  * supported, nor exclusion constraints, nor deferred uniqueness
129  */
130  Assert(indexInfo->ii_Expressions == NIL);
131  Assert(indexInfo->ii_Predicate == NIL);
132  Assert(indexInfo->ii_ExclusionOps == NULL);
133  Assert(index->rd_index->indimmediate);
134  Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
135 
136  /* see earlier check above */
137 #ifdef USE_ASSERT_CHECKING
138  if (HeapTupleIsHeapOnly(heapTuple))
139  {
141  continue;
142  }
143 #endif /* USE_ASSERT_CHECKING */
144 
145  /*
146  * FormIndexDatum fills in its values and isnull parameters with the
147  * appropriate values for the column(s) of the index.
148  */
149  FormIndexDatum(indexInfo,
150  slot,
151  NULL, /* no expression eval to do */
152  values,
153  isnull);
154 
155  /*
156  * The index AM does the rest.
157  */
158  index_insert(index, /* index relation */
159  values, /* array of index Datums */
160  isnull, /* is-null flags */
161  &(heapTuple->t_self), /* tid of heap tuple */
162  heapRelation,
163  index->rd_index->indisunique ?
165  false,
166  indexInfo);
167  }
168 
170 }
171 
172 /*
173  * Subroutine to verify that catalog constraints are honored.
174  *
175  * Tuples inserted via CatalogTupleInsert/CatalogTupleUpdate are generally
176  * "hand made", so that it's possible that they fail to satisfy constraints
177  * that would be checked if they were being inserted by the executor. That's
178  * a coding error, so we only bother to check for it in assert-enabled builds.
179  */
180 #ifdef USE_ASSERT_CHECKING
181 
182 static void
184 {
185  /*
186  * Currently, the only constraints implemented for system catalogs are
187  * attnotnull constraints.
188  */
189  if (HeapTupleHasNulls(tup))
190  {
191  TupleDesc tupdesc = RelationGetDescr(heapRel);
192  bits8 *bp = tup->t_data->t_bits;
193 
194  for (int attnum = 0; attnum < tupdesc->natts; attnum++)
195  {
196  Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
197 
198  Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
199  }
200  }
201 }
202 
203 #else /* !USE_ASSERT_CHECKING */
204 
205 #define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0)
206 
207 #endif /* USE_ASSERT_CHECKING */
208 
209 /*
210  * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
211  *
212  * Insert the tuple data in "tup" into the specified catalog relation.
213  * The Oid of the inserted tuple is returned.
214  *
215  * This is a convenience routine for the common case of inserting a single
216  * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
217  * current. Avoid using it for multiple tuples, since opening the indexes
218  * and building the index info structures is moderately expensive.
219  * (Use CatalogTupleInsertWithInfo in such cases.)
220  */
221 void
223 {
224  CatalogIndexState indstate;
225 
226  CatalogTupleCheckConstraints(heapRel, tup);
227 
228  indstate = CatalogOpenIndexes(heapRel);
229 
230  simple_heap_insert(heapRel, tup);
231 
232  CatalogIndexInsert(indstate, tup);
233  CatalogCloseIndexes(indstate);
234 }
235 
236 /*
237  * CatalogTupleInsertWithInfo - 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 insertions. 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
246  CatalogIndexState indstate)
247 {
248  CatalogTupleCheckConstraints(heapRel, tup);
249 
250  simple_heap_insert(heapRel, tup);
251 
252  CatalogIndexInsert(indstate, tup);
253 }
254 
255 /*
256  * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
257  *
258  * Insert multiple tuples into the given catalog relation at once, with an
259  * amortized cost of CatalogOpenIndexes.
260  */
261 void
263  int ntuples, CatalogIndexState indstate)
264 {
265  /* Nothing to do */
266  if (ntuples <= 0)
267  return;
268 
269  heap_multi_insert(heapRel, slot, ntuples,
270  GetCurrentCommandId(true), 0, NULL);
271 
272  /*
273  * There is no equivalent to heap_multi_insert for the catalog indexes, so
274  * we must loop over and insert individually.
275  */
276  for (int i = 0; i < ntuples; i++)
277  {
278  bool should_free;
279  HeapTuple tuple;
280 
281  tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
282  tuple->t_tableOid = slot[i]->tts_tableOid;
283  CatalogIndexInsert(indstate, tuple);
284 
285  if (should_free)
286  heap_freetuple(tuple);
287  }
288 }
289 
290 /*
291  * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
292  *
293  * Update the tuple identified by "otid", replacing it with the data in "tup".
294  *
295  * This is a convenience routine for the common case of updating a single
296  * tuple in a system catalog; it updates one heap tuple, keeping indexes
297  * current. Avoid using it for multiple tuples, since opening the indexes
298  * and building the index info structures is moderately expensive.
299  * (Use CatalogTupleUpdateWithInfo in such cases.)
300  */
301 void
303 {
304  CatalogIndexState indstate;
305 
306  CatalogTupleCheckConstraints(heapRel, tup);
307 
308  indstate = CatalogOpenIndexes(heapRel);
309 
310  simple_heap_update(heapRel, otid, tup);
311 
312  CatalogIndexInsert(indstate, tup);
313  CatalogCloseIndexes(indstate);
314 }
315 
316 /*
317  * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
318  *
319  * This should be used when it's important to amortize CatalogOpenIndexes/
320  * CatalogCloseIndexes work across multiple updates. At some point we
321  * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
322  * so that callers needn't trouble over this ... but we don't do so today.
323  */
324 void
326  CatalogIndexState indstate)
327 {
328  CatalogTupleCheckConstraints(heapRel, tup);
329 
330  simple_heap_update(heapRel, otid, tup);
331 
332  CatalogIndexInsert(indstate, tup);
333 }
334 
335 /*
336  * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
337  *
338  * Delete the tuple identified by "tid" in the specified catalog.
339  *
340  * With Postgres heaps, there is no index work to do at deletion time;
341  * cleanup will be done later by VACUUM. However, callers of this function
342  * shouldn't have to know that; we'd like a uniform abstraction for all
343  * catalog tuple changes. Hence, provide this currently-trivial wrapper.
344  *
345  * The abstraction is a bit leaky in that we don't provide an optimized
346  * CatalogTupleDeleteWithInfo version, because there is currently nothing to
347  * optimize. If we ever need that, rather than touching a lot of call sites,
348  * it might be better to do something about caching CatalogIndexState.
349  */
350 void
352 {
353  simple_heap_delete(heapRel, tid);
354 }
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2816
int ri_NumIndices
Definition: execnodes.h:418
#define NIL
Definition: pg_list.h:65
Oid tts_tableOid
Definition: tuptable.h:131
Relation ri_RelationDesc
Definition: execnodes.h:415
List * ii_Predicate
Definition: execnodes.h:162
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:177
#define RelationGetDescr(relation)
Definition: rel.h:483
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1208
#define att_isnull(ATT, BITS)
Definition: tupmacs.h:25
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static void CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
Definition: indexing.c:75
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:351
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
Index ri_RangeTableIndex
Definition: execnodes.h:412
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:156
HeapTupleHeader t_data
Definition: htup.h:68
Definition: type.h:89
Form_pg_index rd_index
Definition: rel.h:175
void pfree(void *pointer)
Definition: mcxt.c:1057
int ii_NumIndexKeyAttrs
Definition: execnodes.h:158
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:262
ItemPointerData t_self
Definition: htup.h:65
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:661
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
Oid t_tableOid
Definition: htup.h:66
bool ii_ReadyForInserts
Definition: execnodes.h:172
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:427
void simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2682
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:325
uint8 bits8
Definition: c.h:448
uintptr_t Datum
Definition: postgres.h:367
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:245
int16 attnum
Definition: pg_attribute.h:83
#define makeNode(_type_)
Definition: nodes.h:581
List * ii_Expressions
Definition: execnodes.h:160
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:685
#define Assert(condition)
Definition: c.h:804
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define INDEX_MAX_KEYS
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:3144
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4181
static Datum values[MAXATTR]
Definition: bootstrap.c:165
Oid * ii_ExclusionOps
Definition: execnodes.h:164
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:424
int i
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:84
void heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, int options, BulkInsertState bistate)
Definition: heapam.c:2342
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:761
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: indexam.c:176
#define CatalogTupleCheckConstraints(heapRel, tup)
Definition: indexing.c:205
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4128
#define RelationGetRelid(relation)
Definition: rel.h:457
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:222
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:231
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:421
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1322