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-2024, 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  TU_UpdateIndexes updateIndexes)
77 {
78  int i;
79  int numIndexes;
80  RelationPtr relationDescs;
81  Relation heapRelation;
82  TupleTableSlot *slot;
83  IndexInfo **indexInfoArray;
85  bool isnull[INDEX_MAX_KEYS];
86  bool onlySummarized = (updateIndexes == TU_Summarizing);
87 
88  /*
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
91  * table/index.
92  */
93 #ifndef USE_ASSERT_CHECKING
94  if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
95  return;
96 #endif
97 
98  /* When only updating summarized indexes, the tuple has to be HOT. */
99  Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple));
100 
101  /*
102  * Get information from the state structure. Fall out if nothing to do.
103  */
104  numIndexes = indstate->ri_NumIndices;
105  if (numIndexes == 0)
106  return;
107  relationDescs = indstate->ri_IndexRelationDescs;
108  indexInfoArray = indstate->ri_IndexRelationInfo;
109  heapRelation = indstate->ri_RelationDesc;
110 
111  /* Need a slot to hold the tuple being examined */
112  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation),
113  &TTSOpsHeapTuple);
114  ExecStoreHeapTuple(heapTuple, slot, false);
115 
116  /*
117  * for each index, form and insert the index tuple
118  */
119  for (i = 0; i < numIndexes; i++)
120  {
121  IndexInfo *indexInfo;
122  Relation index;
123 
124  indexInfo = indexInfoArray[i];
125  index = relationDescs[i];
126 
127  /* If the index is marked as read-only, ignore it */
128  if (!indexInfo->ii_ReadyForInserts)
129  continue;
130 
131  /*
132  * Expressional and partial indexes on system catalogs are not
133  * supported, nor exclusion constraints, nor deferred uniqueness
134  */
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);
140 
141  /* see earlier check above */
142 #ifdef USE_ASSERT_CHECKING
143  if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized)
144  {
146  continue;
147  }
148 #endif /* USE_ASSERT_CHECKING */
149 
150  /*
151  * Skip insertions into non-summarizing indexes if we only need to
152  * update summarizing indexes.
153  */
154  if (onlySummarized && !indexInfo->ii_Summarizing)
155  continue;
156 
157  /*
158  * FormIndexDatum fills in its values and isnull parameters with the
159  * appropriate values for the column(s) of the index.
160  */
161  FormIndexDatum(indexInfo,
162  slot,
163  NULL, /* no expression eval to do */
164  values,
165  isnull);
166 
167  /*
168  * The index AM does the rest.
169  */
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 */
174  heapRelation,
175  index->rd_index->indisunique ?
177  false,
178  indexInfo);
179  }
180 
182 }
183 
184 /*
185  * Subroutine to verify that catalog constraints are honored.
186  *
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.
191  */
192 #ifdef USE_ASSERT_CHECKING
193 
194 static void
196 {
197  /*
198  * Currently, the only constraints implemented for system catalogs are
199  * attnotnull constraints.
200  */
201  if (HeapTupleHasNulls(tup))
202  {
203  TupleDesc tupdesc = RelationGetDescr(heapRel);
204  bits8 *bp = tup->t_data->t_bits;
205 
206  for (int attnum = 0; attnum < tupdesc->natts; attnum++)
207  {
208  Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum);
209 
210  Assert(!(thisatt->attnotnull && att_isnull(attnum, bp)));
211  }
212  }
213 }
214 
215 #else /* !USE_ASSERT_CHECKING */
216 
217 #define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0)
218 
219 #endif /* USE_ASSERT_CHECKING */
220 
221 /*
222  * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
223  *
224  * Insert the tuple data in "tup" into the specified catalog relation.
225  *
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.)
231  */
232 void
234 {
235  CatalogIndexState indstate;
236 
237  CatalogTupleCheckConstraints(heapRel, tup);
238 
239  indstate = CatalogOpenIndexes(heapRel);
240 
241  simple_heap_insert(heapRel, tup);
242 
243  CatalogIndexInsert(indstate, tup, TU_All);
244  CatalogCloseIndexes(indstate);
245 }
246 
247 /*
248  * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
249  *
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.
254  */
255 void
257  CatalogIndexState indstate)
258 {
259  CatalogTupleCheckConstraints(heapRel, tup);
260 
261  simple_heap_insert(heapRel, tup);
262 
263  CatalogIndexInsert(indstate, tup, TU_All);
264 }
265 
266 /*
267  * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
268  *
269  * Insert multiple tuples into the given catalog relation at once, with an
270  * amortized cost of CatalogOpenIndexes.
271  */
272 void
274  int ntuples, CatalogIndexState indstate)
275 {
276  /* Nothing to do */
277  if (ntuples <= 0)
278  return;
279 
280  heap_multi_insert(heapRel, slot, ntuples,
281  GetCurrentCommandId(true), 0, NULL);
282 
283  /*
284  * There is no equivalent to heap_multi_insert for the catalog indexes, so
285  * we must loop over and insert individually.
286  */
287  for (int i = 0; i < ntuples; i++)
288  {
289  bool should_free;
290  HeapTuple tuple;
291 
292  tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
293  tuple->t_tableOid = slot[i]->tts_tableOid;
294  CatalogIndexInsert(indstate, tuple, TU_All);
295 
296  if (should_free)
297  heap_freetuple(tuple);
298  }
299 }
300 
301 /*
302  * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
303  *
304  * Update the tuple identified by "otid", replacing it with the data in "tup".
305  *
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.)
311  */
312 void
314 {
315  CatalogIndexState indstate;
316  TU_UpdateIndexes updateIndexes = TU_All;
317 
318  CatalogTupleCheckConstraints(heapRel, tup);
319 
320  indstate = CatalogOpenIndexes(heapRel);
321 
322  simple_heap_update(heapRel, otid, tup, &updateIndexes);
323 
324  CatalogIndexInsert(indstate, tup, updateIndexes);
325  CatalogCloseIndexes(indstate);
326 }
327 
328 /*
329  * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
330  *
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.
335  */
336 void
338  CatalogIndexState indstate)
339 {
340  TU_UpdateIndexes updateIndexes = TU_All;
341 
342  CatalogTupleCheckConstraints(heapRel, tup);
343 
344  simple_heap_update(heapRel, otid, tup, &updateIndexes);
345 
346  CatalogIndexInsert(indstate, tup, updateIndexes);
347 }
348 
349 /*
350  * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
351  *
352  * Delete the tuple identified by "tid" in the specified catalog.
353  *
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.
358  *
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.
363  */
364 void
366 {
367  simple_heap_delete(heapRel, tid);
368 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
uint8 bits8
Definition: c.h:500
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:231
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:156
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1253
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1643
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1351
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:84
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1237
@ UNIQUE_CHECK_NO
Definition: genam.h:117
@ UNIQUE_CHECK_YES
Definition: genam.h:118
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:2934
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup, TU_UpdateIndexes *update_indexes)
Definition: heapam.c:4051
void simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2455
void heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, int options, BulkInsertState bistate)
Definition: heapam.c:2093
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:683
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:659
bool ReindexIsProcessingIndex(Oid indexOid)
Definition: index.c:4069
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2705
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: indexam.c:213
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
static void CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple, TU_UpdateIndexes updateIndexes)
Definition: indexing.c:75
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
#define CatalogTupleCheckConstraints(heapRel, tup)
Definition: indexing.c:217
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:256
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:337
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1508
#define makeNode(_type_)
Definition: nodes.h:155
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define INDEX_MAX_KEYS
#define NIL
Definition: pg_list.h:68
uintptr_t Datum
Definition: postgres.h:64
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:178
Oid * ii_ExclusionOps
Definition: execnodes.h:191
int ii_NumIndexKeyAttrs
Definition: execnodes.h:185
List * ii_Expressions
Definition: execnodes.h:187
bool ii_Summarizing
Definition: execnodes.h:204
bool ii_ReadyForInserts
Definition: execnodes.h:199
List * ii_Predicate
Definition: execnodes.h:189
int ri_NumIndices
Definition: execnodes.h:459
Relation ri_RelationDesc
Definition: execnodes.h:456
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:462
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:486
Index ri_RangeTableIndex
Definition: execnodes.h:453
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:465
Oid tts_tableOid
Definition: tuptable.h:130
Definition: type.h:95
TU_UpdateIndexes
Definition: tableam.h:110
@ TU_Summarizing
Definition: tableam.h:118
@ TU_All
Definition: tableam.h:115
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static bool att_isnull(int ATT, const bits8 *BITS)
Definition: tupmacs.h:26
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:819