YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/postgres/src/backend/catalog/indexing.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * indexing.c
4
 *    This file contains routines to support indexes defined on system
5
 *    catalogs.
6
 *
7
 * Portions Copyright (c) 1996-2018, 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/htup_details.h"
19
#include "catalog/index.h"
20
#include "catalog/indexing.h"
21
#include "executor/executor.h"
22
#include "utils/syscache.h"
23
#include "utils/rel.h"
24
25
#include "pg_yb_utils.h"
26
#include "access/yb_scan.h"
27
#include "executor/ybcModifyTable.h"
28
#include "miscadmin.h"
29
30
/*
31
 * CatalogOpenIndexes - open the indexes on a system catalog.
32
 *
33
 * When inserting or updating tuples in a system catalog, call this
34
 * to prepare to update the indexes for the catalog.
35
 *
36
 * In the current implementation, we share code for opening/closing the
37
 * indexes with execUtils.c.  But we do not use ExecInsertIndexTuples,
38
 * because we don't want to create an EState.  This implies that we
39
 * do not support partial or expressional indexes on system catalogs,
40
 * nor can we support generalized exclusion constraints.
41
 * This could be fixed with localized changes here if we wanted to pay
42
 * the extra overhead of building an EState.
43
 */
44
CatalogIndexState
45
CatalogOpenIndexes(Relation heapRel)
46
210k
{
47
210k
  ResultRelInfo *resultRelInfo;
48
49
210k
  resultRelInfo = makeNode(ResultRelInfo);
50
0
  resultRelInfo->ri_RangeTableIndex = 1;  /* dummy */
51
210k
  resultRelInfo->ri_RelationDesc = heapRel;
52
210k
  resultRelInfo->ri_TrigDesc = NULL;  /* we don't fire triggers */
53
54
210k
  ExecOpenIndices(resultRelInfo, false);
55
56
210k
  return resultRelInfo;
57
210k
}
58
59
/*
60
 * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes
61
 */
62
void
63
CatalogCloseIndexes(CatalogIndexState indstate)
64
210k
{
65
210k
  ExecCloseIndices(indstate);
66
210k
  pfree(indstate);
67
210k
}
68
69
/*
70
 * CatalogIndexInsert - insert index entries for one catalog tuple
71
 *
72
 * This should be called for each inserted or updated catalog tuple.
73
 *
74
 * This is effectively a cut-down version of ExecInsertIndexTuples.
75
 *
76
 * if yb_shared_insert is specified, this insert will be done in every
77
 * database (including template0 and template1). This is needed when
78
 * creating shared relations.
79
 * This flag should not be used during initdb bootstrap.
80
 */
81
static void
82
CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple, bool yb_shared_insert)
83
145k
{
84
145k
  int     i;
85
145k
  int     numIndexes;
86
145k
  RelationPtr relationDescs;
87
145k
  Relation  heapRelation;
88
145k
  TupleTableSlot *slot;
89
145k
  IndexInfo **indexInfoArray;
90
145k
  Datum   values[INDEX_MAX_KEYS];
91
145k
  bool    isnull[INDEX_MAX_KEYS];
92
93
  /* HOT update does not require index inserts */
94
145k
  if (HeapTupleIsHeapOnly(heapTuple))
95
0
    return;
96
97
  /*
98
   * Get information from the state structure.  Fall out if nothing to do.
99
   */
100
145k
  numIndexes = indstate->ri_NumIndices;
101
145k
  if (numIndexes == 0)
102
2.75k
    return;
103
142k
  relationDescs = indstate->ri_IndexRelationDescs;
104
142k
  indexInfoArray = indstate->ri_IndexRelationInfo;
105
142k
  heapRelation = indstate->ri_RelationDesc;
106
107
  /* Need a slot to hold the tuple being examined */
108
142k
  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
109
142k
  ExecStoreHeapTuple(heapTuple, slot, false);
110
111
  /*
112
   * for each index, form and insert the index tuple
113
   */
114
444k
  for (i = 0; i < numIndexes; 
i++301k
)
115
301k
  {
116
    /*
117
     * No need to update YugaByte primary key which is intrinic part of
118
     * the base table.
119
     */
120
301k
    if (IsYugaByteEnabled() && 
relationDescs[i]->rd_index->indisprimary301k
)
121
92.7k
      continue;
122
123
209k
    IndexInfo  *indexInfo;
124
125
209k
    indexInfo = indexInfoArray[i];
126
127
    /* If the index is marked as read-only, ignore it */
128
209k
    if (!indexInfo->ii_ReadyForInserts)
129
0
      continue;
130
131
    /*
132
     * Expressional and partial indexes on system catalogs are not
133
     * supported, nor exclusion constraints, nor deferred uniqueness
134
     */
135
209k
    Assert(indexInfo->ii_Expressions == NIL);
136
209k
    Assert(indexInfo->ii_Predicate == NIL);
137
209k
    Assert(indexInfo->ii_ExclusionOps == NULL);
138
209k
    Assert(relationDescs[i]->rd_index->indimmediate);
139
209k
    Assert(indexInfo->ii_NumIndexKeyAttrs != 0);
140
141
    /*
142
     * FormIndexDatum fills in its values and isnull parameters with the
143
     * appropriate values for the column(s) of the index.
144
     */
145
209k
    FormIndexDatum(indexInfo,
146
209k
             slot,
147
209k
             NULL,  /* no expression eval to do */
148
209k
             values,
149
209k
             isnull);
150
151
    /*
152
     * The index AM does the rest.
153
     */
154
209k
    index_insert(relationDescs[i],  /* index relation */
155
209k
           values,  /* array of index Datums */
156
209k
           isnull,  /* is-null flags */
157
209k
           &(heapTuple->t_self),  /* tid of heap tuple */
158
209k
           heapTuple, /* heap tuple */
159
209k
           heapRelation,
160
209k
           relationDescs[i]->rd_index->indisunique ?
161
124k
           
UNIQUE_CHECK_YES84.3k
: UNIQUE_CHECK_NO,
162
209k
           indexInfo,
163
209k
           yb_shared_insert);
164
209k
  }
165
166
142k
  ExecDropSingleTupleTableSlot(slot);
167
142k
}
168
169
/*
170
 * CatalogIndexDelete - delete index entries for one catalog tuple
171
 *
172
 * This should be called for each updated or deleted catalog tuple.
173
 *
174
 * This is effectively a cut-down version of ExecDeleteIndexTuples.
175
 */
176
static void
177
CatalogIndexDelete(CatalogIndexState indstate, HeapTuple heapTuple)
178
113k
{
179
113k
  int     i;
180
113k
  int     numIndexes;
181
113k
  RelationPtr relationDescs;
182
113k
  Relation  heapRelation;
183
113k
  TupleTableSlot *slot;
184
113k
  IndexInfo **indexInfoArray;
185
113k
  Datum   values[INDEX_MAX_KEYS];
186
113k
  bool    isnull[INDEX_MAX_KEYS];
187
188
  /*
189
   * Get information from the state structure.  Fall out if nothing to do.
190
   */
191
113k
  numIndexes = indstate->ri_NumIndices;
192
113k
  if (numIndexes == 0)
193
0
    return;
194
113k
  relationDescs = indstate->ri_IndexRelationDescs;
195
113k
  indexInfoArray = indstate->ri_IndexRelationInfo;
196
113k
  heapRelation = indstate->ri_RelationDesc;
197
198
  /* Need a slot to hold the tuple being examined */
199
113k
  slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
200
113k
  ExecStoreHeapTuple(heapTuple, slot, false);
201
202
  /*
203
   * for each index, form and delete the index tuple
204
   */
205
357k
  for (i = 0; i < numIndexes; 
i++243k
)
206
243k
  {
207
    /*
208
     * No need to update YugaByte primary key which is intrinic part of
209
     * the base table.
210
     */
211
243k
    if (IsYugaByteEnabled() && relationDescs[i]->rd_index->indisprimary)
212
72.6k
      continue;
213
214
170k
    IndexInfo  *indexInfo;
215
216
170k
    indexInfo = indexInfoArray[i];
217
218
    /* If the index is marked as read-only, ignore it */
219
170k
    if (!indexInfo->ii_ReadyForInserts)
220
0
      continue;
221
222
    /*
223
     * Expressional and partial indexes on system catalogs are not
224
     * supported, nor exclusion constraints, nor deferred uniqueness
225
     */
226
170k
    Assert(indexInfo->ii_Expressions == NIL);
227
170k
    Assert(indexInfo->ii_Predicate == NIL);
228
170k
    Assert(indexInfo->ii_ExclusionOps == NULL);
229
170k
    Assert(relationDescs[i]->rd_index->indimmediate);
230
231
    /*
232
     * FormIndexDatum fills in its values and isnull parameters with the
233
     * appropriate values for the column(s) of the index.
234
     */
235
170k
    FormIndexDatum(indexInfo,
236
170k
             slot,
237
170k
             NULL,  /* no expression eval to do */
238
170k
             values,
239
170k
             isnull);
240
241
    /*
242
     * The index AM does the rest.
243
     */
244
170k
    index_delete(relationDescs[i],  /* index relation */
245
170k
           values,  /* array of index Datums */
246
170k
           isnull,  /* is-null flags */
247
170k
           heapTuple->t_ybctid, /* heap tuple */
248
170k
           heapRelation,
249
170k
           indexInfo);
250
170k
  }
251
252
113k
  ExecDropSingleTupleTableSlot(slot);
253
113k
}
254
255
/*
256
 * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
257
 *
258
 * Insert the tuple data in "tup" into the specified catalog relation.
259
 * The Oid of the inserted tuple is returned.
260
 *
261
 * This is a convenience routine for the common case of inserting a single
262
 * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
263
 * current.  Avoid using it for multiple tuples, since opening the indexes
264
 * and building the index info structures is moderately expensive.
265
 * (Use CatalogTupleInsertWithInfo in such cases.)
266
 */
267
Oid
268
CatalogTupleInsert(Relation heapRel, HeapTuple tup)
269
26.7k
{
270
26.7k
  return YBCatalogTupleInsert(heapRel, tup, false);
271
26.7k
}
272
273
/*
274
 * Enhanced version of CatalogTupleInsert.
275
 *
276
 * if yb_shared_insert is specified, this insert will be done in every
277
 * database (including template0 and template1). This is needed when
278
 * creating shared relations.
279
 * This flag should not be used during initdb bootstrap.
280
 */
281
Oid
282
YBCatalogTupleInsert(Relation heapRel, HeapTuple tup, bool yb_shared_insert)
283
48.6k
{
284
48.6k
  CatalogIndexState indstate;
285
48.6k
  Oid     oid;
286
287
48.6k
  if (IsYugaByteEnabled())
288
48.6k
  {
289
48.6k
    if (yb_shared_insert)
290
41
    {
291
41
      if (!IsYsqlUpgrade)
292
0
        elog(ERROR, "shared insert cannot be done outside of YSQL upgrade");
293
294
246
      
YB_FOR_EACH_DB41
(pg_db_tuple)
295
246
      {
296
246
        Oid dboid = HeapTupleGetOid(pg_db_tuple);
297
        /*
298
         * Since this is a catalog table, we assume it exists in all databases.
299
         * YB doesn't use PG locks so it's okay not to take them.
300
         */
301
246
        if (dboid == YBCGetDatabaseOid(heapRel))
302
41
          continue; /* Will be done after the loop. */
303
205
        YBCExecuteInsertForDb(dboid, heapRel, RelationGetDescr(heapRel), tup);
304
205
      }
305
205
      YB_FOR_EACH_DB_END;
306
82
    }
307
48.6k
    oid = YBCExecuteInsertForDb(YBCGetDatabaseOid(heapRel),
308
48.6k
                  heapRel,
309
48.6k
                  RelationGetDescr(heapRel),
310
48.6k
                  tup);
311
    /* Update the local cache automatically */
312
48.6k
    YBSetSysCacheTuple(heapRel, tup);
313
48.6k
  }
314
0
  else
315
0
  {
316
0
    oid = simple_heap_insert(heapRel, tup);
317
0
  }
318
319
48.6k
  indstate = CatalogOpenIndexes(heapRel);
320
321
48.6k
  CatalogIndexInsert(indstate, tup, yb_shared_insert);
322
48.6k
  CatalogCloseIndexes(indstate);
323
324
48.6k
  return oid;
325
48.6k
}
326
327
/*
328
 * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
329
 *
330
 * This should be used when it's important to amortize CatalogOpenIndexes/
331
 * CatalogCloseIndexes work across multiple insertions.  At some point we
332
 * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
333
 * so that callers needn't trouble over this ... but we don't do so today.
334
 *
335
 * if yb_shared_insert is specified, this insert will be done in every
336
 * database (including template0 and template1). This is needed when
337
 * creating shared relations.
338
 * This flag should not be used during initdb bootstrap.
339
 */
340
Oid
341
CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
342
               CatalogIndexState indstate, bool yb_shared_insert)
343
89.6k
{
344
89.6k
  Oid     oid;
345
346
89.6k
  if (IsYugaByteEnabled())
347
89.6k
  {
348
89.6k
    if (yb_shared_insert)
349
106
    {
350
106
      if (!IsYsqlUpgrade)
351
0
        elog(ERROR, "shared insert cannot be done outside of YSQL upgrade");
352
353
636
      
YB_FOR_EACH_DB106
(pg_db_tuple)
354
636
      {
355
636
        Oid dboid = HeapTupleGetOid(pg_db_tuple);
356
        /*
357
         * Since this is a catalog table, we assume it exists in all databases.
358
         * YB doesn't use PG locks so it's okay not to take them.
359
         */
360
636
        if (dboid == YBCGetDatabaseOid(heapRel))
361
106
          continue; /* Will be done after the loop. */
362
530
        YBCExecuteInsertForDb(dboid, heapRel, RelationGetDescr(heapRel), tup);
363
530
      }
364
530
      YB_FOR_EACH_DB_END;
365
212
    }
366
89.6k
    oid = YBCExecuteInsertForDb(YBCGetDatabaseOid(heapRel),
367
89.6k
                  heapRel,
368
89.6k
                  RelationGetDescr(heapRel),
369
89.6k
                  tup);
370
    /* Update the local cache automatically */
371
89.6k
    YBSetSysCacheTuple(heapRel, tup);
372
89.6k
  }
373
0
  else
374
0
  {
375
0
    oid = simple_heap_insert(heapRel, tup);
376
0
  }
377
378
89.6k
  CatalogIndexInsert(indstate, tup, yb_shared_insert);
379
380
89.6k
  return oid;
381
89.6k
}
382
383
/*
384
 * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
385
 *
386
 * Update the tuple identified by "otid", replacing it with the data in "tup".
387
 *
388
 * This is a convenience routine for the common case of updating a single
389
 * tuple in a system catalog; it updates one heap tuple, keeping indexes
390
 * current.  Avoid using it for multiple tuples, since opening the indexes
391
 * and building the index info structures is moderately expensive.
392
 * (Use CatalogTupleUpdateWithInfo in such cases.)
393
 */
394
void
395
CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
396
7.83k
{
397
7.83k
  CatalogIndexState indstate;
398
399
7.83k
  indstate = CatalogOpenIndexes(heapRel);
400
401
7.83k
  if (IsYugaByteEnabled())
402
7.83k
  {
403
7.83k
    HeapTuple oldtup = NULL;
404
7.83k
    bool    has_indices = YBRelHasSecondaryIndices(heapRel);
405
406
7.83k
    if (has_indices)
407
7.43k
    {
408
7.43k
      if (tup->t_ybctid)
409
7.43k
      {
410
7.43k
        oldtup = YBCFetchTuple(heapRel, tup->t_ybctid);
411
7.43k
        CatalogIndexDelete(indstate, oldtup);
412
7.43k
      }
413
0
      else
414
0
        YBC_LOG_WARNING("ybctid missing in %s's tuple",
415
7.43k
                RelationGetRelationName(heapRel));
416
7.43k
    }
417
418
7.83k
    YBCUpdateSysCatalogTuple(heapRel, oldtup, tup);
419
    /* Update the local cache automatically */
420
7.83k
    YBSetSysCacheTuple(heapRel, tup);
421
422
7.83k
    if (has_indices)
423
7.43k
      CatalogIndexInsert(indstate, tup, false /* yb_shared_insert */);
424
7.83k
  }
425
0
  else
426
0
  {
427
0
    simple_heap_update(heapRel, otid, tup);
428
429
0
    CatalogIndexInsert(indstate, tup, false /* yb_shared_insert */);
430
0
  }
431
432
7.83k
  CatalogCloseIndexes(indstate);
433
7.83k
}
434
435
/*
436
 * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
437
 *
438
 * This should be used when it's important to amortize CatalogOpenIndexes/
439
 * CatalogCloseIndexes work across multiple updates.  At some point we
440
 * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
441
 * so that callers needn't trouble over this ... but we don't do so today.
442
 */
443
void
444
CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
445
               CatalogIndexState indstate)
446
47
{
447
47
  if (IsYugaByteEnabled())
448
47
  {
449
47
    HeapTuple oldtup = NULL;
450
47
    bool    has_indices = YBRelHasSecondaryIndices(heapRel);
451
452
47
    if (has_indices)
453
46
    {
454
46
      if (tup->t_ybctid)
455
46
      {
456
46
        oldtup = YBCFetchTuple(heapRel, tup->t_ybctid);
457
46
        CatalogIndexDelete(indstate, oldtup);
458
46
      }
459
0
      else
460
0
        YBC_LOG_WARNING("ybctid missing in %s's tuple",
461
46
                RelationGetRelationName(heapRel));
462
46
    }
463
464
47
    YBCUpdateSysCatalogTuple(heapRel, oldtup, tup);
465
    /* Update the local cache automatically */
466
47
    YBSetSysCacheTuple(heapRel, tup);
467
468
47
    if (has_indices)
469
46
      CatalogIndexInsert(indstate, tup, false /* yb_shared_insert */);
470
47
  }
471
0
  else
472
0
  {
473
0
    simple_heap_update(heapRel, otid, tup);
474
475
0
    CatalogIndexInsert(indstate, tup, false /* yb_shared_insert */);
476
0
  }
477
47
}
478
479
/*
480
 * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
481
 *
482
 * Delete the tuple identified by "tid" in the specified catalog.
483
 *
484
 * With Postgres heaps, there is no index work to do at deletion time;
485
 * cleanup will be done later by VACUUM.  However, callers of this function
486
 * shouldn't have to know that; we'd like a uniform abstraction for all
487
 * catalog tuple changes.  Hence, provide this currently-trivial wrapper.
488
 *
489
 * The abstraction is a bit leaky in that we don't provide an optimized
490
 * CatalogTupleDeleteWithInfo version, because there is currently nothing to
491
 * optimize.  If we ever need that, rather than touching a lot of call sites,
492
 * it might be better to do something about caching CatalogIndexState.
493
 */
494
void
495
CatalogTupleDelete(Relation heapRel, HeapTuple tup)
496
106k
{
497
106k
  if (IsYugaByteEnabled())
498
106k
  {
499
106k
    YBCDeleteSysCatalogTuple(heapRel, tup);
500
501
106k
    CatalogIndexState indstate = CatalogOpenIndexes(heapRel);
502
503
106k
    CatalogIndexDelete(indstate, tup);
504
106k
    CatalogCloseIndexes(indstate);
505
106k
  }
506
0
  else
507
0
  {
508
0
    simple_heap_delete(heapRel, &tup->t_self);
509
0
  }
510
106k
}