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-2020, 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  indexInfo);
166  }
167 
169 }
170 
171 /*
172  * Subroutine to verify that catalog constraints are honored.
173  *
174  * Tuples inserted via CatalogTupleInsert/CatalogTupleUpdate are generally
175  * "hand made", so that it's possible that they fail to satisfy constraints
176  * that would be checked if they were being inserted by the executor. That's
177  * a coding error, so we only bother to check for it in assert-enabled builds.
178  */
179 #ifdef USE_ASSERT_CHECKING
180 
181 static void
183 {
184  /*
185  * Currently, the only constraints implemented for system catalogs are
186  * attnotnull constraints.
187  */
188  if (HeapTupleHasNulls(tup))
189  {
190  TupleDesc tupdesc = RelationGetDescr(heapRel);
191  bits8 *bp = tup->t_data->t_bits;
192 
193  for (int attnum = 0; attnum < tupdesc->natts; attnum++)
194  {
195  Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
196 
197  Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
198  }
199  }
200 }
201 
202 #else /* !USE_ASSERT_CHECKING */
203 
204 #define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0)
205 
206 #endif /* USE_ASSERT_CHECKING */
207 
208 /*
209  * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
210  *
211  * Insert the tuple data in "tup" into the specified catalog relation.
212  * The Oid of the inserted tuple is returned.
213  *
214  * This is a convenience routine for the common case of inserting a single
215  * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
216  * current. Avoid using it for multiple tuples, since opening the indexes
217  * and building the index info structures is moderately expensive.
218  * (Use CatalogTupleInsertWithInfo in such cases.)
219  */
220 void
222 {
223  CatalogIndexState indstate;
224 
225  CatalogTupleCheckConstraints(heapRel, tup);
226 
227  indstate = CatalogOpenIndexes(heapRel);
228 
229  simple_heap_insert(heapRel, tup);
230 
231  CatalogIndexInsert(indstate, tup);
232  CatalogCloseIndexes(indstate);
233 }
234 
235 /*
236  * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
237  *
238  * This should be used when it's important to amortize CatalogOpenIndexes/
239  * CatalogCloseIndexes work across multiple insertions. At some point we
240  * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
241  * so that callers needn't trouble over this ... but we don't do so today.
242  */
243 void
245  CatalogIndexState indstate)
246 {
247  CatalogTupleCheckConstraints(heapRel, tup);
248 
249  simple_heap_insert(heapRel, tup);
250 
251  CatalogIndexInsert(indstate, tup);
252 }
253 
254 /*
255  * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
256  *
257  * Insert multiple tuples into the given catalog relation at once, with an
258  * amortized cost of CatalogOpenIndexes.
259  */
260 void
262  int ntuples, CatalogIndexState indstate)
263 {
264  /* Nothing to do */
265  if (ntuples <= 0)
266  return;
267 
268  heap_multi_insert(heapRel, slot, ntuples,
269  GetCurrentCommandId(true), 0, NULL);
270 
271  /*
272  * There is no equivalent to heap_multi_insert for the catalog indexes, so
273  * we must loop over and insert individually.
274  */
275  for (int i = 0; i < ntuples; i++)
276  {
277  bool should_free;
278  HeapTuple tuple;
279 
280  tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
281  tuple->t_tableOid = slot[i]->tts_tableOid;
282  CatalogIndexInsert(indstate, tuple);
283 
284  if (should_free)
285  heap_freetuple(tuple);
286  }
287 }
288 
289 /*
290  * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
291  *
292  * Update the tuple identified by "otid", replacing it with the data in "tup".
293  *
294  * This is a convenience routine for the common case of updating a single
295  * tuple in a system catalog; it updates one heap tuple, keeping indexes
296  * current. Avoid using it for multiple tuples, since opening the indexes
297  * and building the index info structures is moderately expensive.
298  * (Use CatalogTupleUpdateWithInfo in such cases.)
299  */
300 void
302 {
303  CatalogIndexState indstate;
304 
305  CatalogTupleCheckConstraints(heapRel, tup);
306 
307  indstate = CatalogOpenIndexes(heapRel);
308 
309  simple_heap_update(heapRel, otid, tup);
310 
311  CatalogIndexInsert(indstate, tup);
312  CatalogCloseIndexes(indstate);
313 }
314 
315 /*
316  * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
317  *
318  * This should be used when it's important to amortize CatalogOpenIndexes/
319  * CatalogCloseIndexes work across multiple updates. At some point we
320  * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
321  * so that callers needn't trouble over this ... but we don't do so today.
322  */
323 void
325  CatalogIndexState indstate)
326 {
327  CatalogTupleCheckConstraints(heapRel, tup);
328 
329  simple_heap_update(heapRel, otid, tup);
330 
331  CatalogIndexInsert(indstate, tup);
332 }
333 
334 /*
335  * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
336  *
337  * Delete the tuple identified by "tid" in the specified catalog.
338  *
339  * With Postgres heaps, there is no index work to do at deletion time;
340  * cleanup will be done later by VACUUM. However, callers of this function
341  * shouldn't have to know that; we'd like a uniform abstraction for all
342  * catalog tuple changes. Hence, provide this currently-trivial wrapper.
343  *
344  * The abstraction is a bit leaky in that we don't provide an optimized
345  * CatalogTupleDeleteWithInfo version, because there is currently nothing to
346  * optimize. If we ever need that, rather than touching a lot of call sites,
347  * it might be better to do something about caching CatalogIndexState.
348  */
349 void
351 {
352  simple_heap_delete(heapRel, tid);
353 }
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2585
int ri_NumIndices
Definition: execnodes.h:416
#define NIL
Definition: pg_list.h:65
Oid tts_tableOid
Definition: tuptable.h:131
Relation ri_RelationDesc
Definition: execnodes.h:413
List * ii_Predicate
Definition: execnodes.h:163
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:177
#define RelationGetDescr(relation)
Definition: rel.h:482
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:350
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
Index ri_RangeTableIndex
Definition: execnodes.h:410
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:151
HeapTupleHeader t_data
Definition: htup.h:68
Definition: type.h:89
Form_pg_index rd_index
Definition: rel.h:174
void pfree(void *pointer)
Definition: mcxt.c:1057
int ii_NumIndexKeyAttrs
Definition: execnodes.h:159
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:261
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:193
Oid t_tableOid
Definition: htup.h:66
bool ii_ReadyForInserts
Definition: execnodes.h:173
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
void simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2384
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:324
uint8 bits8
Definition: c.h:381
uintptr_t Datum
Definition: postgres.h:367
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:244
int16 attnum
Definition: pg_attribute.h:79
#define makeNode(_type_)
Definition: nodes.h:577
List * ii_Expressions
Definition: execnodes.h:161
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:685
#define Assert(condition)
Definition: c.h:745
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define INDEX_MAX_KEYS
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:2847
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:3885
static Datum values[MAXATTR]
Definition: bootstrap.c:165
Oid * ii_ExclusionOps
Definition: execnodes.h:165
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:422
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:2097
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:761
#define CatalogTupleCheckConstraints(heapRel, tup)
Definition: indexing.c:204
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:3845
#define RelationGetRelid(relation)
Definition: rel.h:456
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:226
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:419
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1322
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: indexam.c:176