YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/postgres/src/bin/pg_dump/common.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * common.c
4
 *  Catalog routines used by pg_dump; long ago these were shared
5
 *  by another dump tool, but not anymore.
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/bin/pg_dump/common.c
13
 *
14
 *-------------------------------------------------------------------------
15
 */
16
#include "postgres_fe.h"
17
18
#include "pg_backup_archiver.h"
19
#include "pg_backup_utils.h"
20
#include "pg_dump.h"
21
22
#include <ctype.h>
23
24
#include "catalog/pg_class_d.h"
25
#include "fe_utils/string_utils.h"
26
27
28
/*
29
 * Variables for mapping DumpId to DumpableObject
30
 */
31
static DumpableObject **dumpIdMap = NULL;
32
static int  allocedDumpIds = 0;
33
static DumpId lastDumpId = 0;
34
35
/*
36
 * Variables for mapping CatalogId to DumpableObject
37
 */
38
static bool catalogIdMapValid = false;
39
static DumpableObject **catalogIdMap = NULL;
40
static int  numCatalogIds = 0;
41
42
/*
43
 * These variables are static to avoid the notational cruft of having to pass
44
 * them into findTableByOid() and friends.  For each of these arrays, we build
45
 * a sorted-by-OID index array immediately after the objects are fetched,
46
 * and then we use binary search in findTableByOid() and friends.  (qsort'ing
47
 * the object arrays themselves would be simpler, but it doesn't work because
48
 * pg_dump.c may have already established pointers between items.)
49
 */
50
static DumpableObject **tblinfoindex;
51
static DumpableObject **typinfoindex;
52
static DumpableObject **funinfoindex;
53
static DumpableObject **oprinfoindex;
54
static DumpableObject **collinfoindex;
55
static DumpableObject **nspinfoindex;
56
static DumpableObject **extinfoindex;
57
static DumpableObject **tblgrpinfoindex;
58
static int  numTables;
59
static int  numTablegroups;
60
static int  numTypes;
61
static int  numFuncs;
62
static int  numOperators;
63
static int  numCollations;
64
static int  numNamespaces;
65
static int  numExtensions;
66
67
/* This is an array of object identities, not actual DumpableObjects */
68
static ExtensionMemberId *extmembers;
69
static int  numextmembers;
70
71
static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
72
        InhInfo *inhinfo, int numInherits);
73
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
74
static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
75
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
76
        Size objSize);
77
static int  DOCatalogIdCompare(const void *p1, const void *p2);
78
static int  ExtensionMemberIdCompare(const void *p1, const void *p2);
79
static void findParentsByOid(TableInfo *self,
80
         InhInfo *inhinfo, int numInherits);
81
static int  strInArray(const char *pattern, char **arr, int arr_size);
82
static IndxInfo *findIndexByOid(Oid oid, DumpableObject **idxinfoindex,
83
         int numIndexes);
84
85
86
/*
87
 * getSchemaData
88
 *    Collect information about all potentially dumpable objects
89
 */
90
TableInfo *
91
getSchemaData(Archive *fout, int *numTablesPtr)
92
0
{
93
0
  TableInfo  *tblinfo;
94
0
  TypeInfo   *typinfo;
95
0
  FuncInfo   *funinfo;
96
0
  OprInfo    *oprinfo;
97
0
  CollInfo   *collinfo;
98
0
  NamespaceInfo *nspinfo;
99
0
  ExtensionInfo *extinfo;
100
0
  InhInfo    *inhinfo;
101
0
  TablegroupInfo *tblgrpinfo;
102
0
  int     numAggregates;
103
0
  int     numInherits;
104
0
  int     numRules;
105
0
  int     numProcLangs;
106
0
  int     numCasts;
107
0
  int     numTransforms;
108
0
  int     numAccessMethods;
109
0
  int     numOpclasses;
110
0
  int     numOpfamilies;
111
0
  int     numConversions;
112
0
  int     numTSParsers;
113
0
  int     numTSTemplates;
114
0
  int     numTSDicts;
115
0
  int     numTSConfigs;
116
0
  int     numForeignDataWrappers;
117
0
  int     numForeignServers;
118
0
  int     numDefaultACLs;
119
0
  int     numEventTriggers;
120
121
  /*
122
   * We must read extensions and extension membership info first, because
123
   * extension membership needs to be consultable during decisions about
124
   * whether other objects are to be dumped.
125
   */
126
0
  if (g_verbose)
127
0
    write_msg(NULL, "reading extensions\n");
128
0
  extinfo = getExtensions(fout, &numExtensions);
129
0
  extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
130
131
0
  if (g_verbose)
132
0
    write_msg(NULL, "identifying extension members\n");
133
0
  getExtensionMembership(fout, extinfo, numExtensions);
134
135
0
  if (g_verbose)
136
0
    write_msg(NULL, "reading schemas\n");
137
0
  nspinfo = getNamespaces(fout, &numNamespaces);
138
0
  nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
139
140
  /*
141
   * getTables should be done as soon as possible, so as to minimize the
142
   * window between starting our transaction and acquiring per-table locks.
143
   * However, we have to do getNamespaces first because the tables get
144
   * linked to their containing namespaces during getTables.
145
   */
146
0
  if (g_verbose)
147
0
    write_msg(NULL, "reading user-defined tables\n");
148
0
  tblinfo = getTables(fout, &numTables);
149
0
  tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
150
151
  /* Do this after we've built tblinfoindex */
152
0
  getOwnedSeqs(fout, tblinfo, numTables);
153
154
0
  if (g_verbose)
155
0
    write_msg(NULL, "reading user-defined functions\n");
156
0
  funinfo = getFuncs(fout, &numFuncs);
157
0
  funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
158
159
  /* this must be after getTables and getFuncs */
160
0
  if (g_verbose)
161
0
    write_msg(NULL, "reading user-defined types\n");
162
0
  typinfo = getTypes(fout, &numTypes);
163
0
  typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
164
165
  /* this must be after getFuncs, too */
166
0
  if (g_verbose)
167
0
    write_msg(NULL, "reading procedural languages\n");
168
0
  getProcLangs(fout, &numProcLangs);
169
170
0
  if (g_verbose)
171
0
    write_msg(NULL, "reading user-defined aggregate functions\n");
172
0
  getAggregates(fout, &numAggregates);
173
174
0
  if (g_verbose)
175
0
    write_msg(NULL, "reading user-defined operators\n");
176
0
  oprinfo = getOperators(fout, &numOperators);
177
0
  oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
178
179
0
  if (g_verbose)
180
0
    write_msg(NULL, "reading user-defined access methods\n");
181
0
  getAccessMethods(fout, &numAccessMethods);
182
183
0
  if (g_verbose)
184
0
    write_msg(NULL, "reading user-defined tablegroups\n");
185
0
  tblgrpinfo = getTablegroups(fout, &numTablegroups);
186
0
  tblgrpinfoindex = buildIndexArray(tblgrpinfo, numTablegroups, sizeof(TablegroupInfo));
187
188
0
  if (g_verbose)
189
0
    write_msg(NULL, "reading user-defined operator classes\n");
190
0
  getOpclasses(fout, &numOpclasses);
191
192
0
  if (g_verbose)
193
0
    write_msg(NULL, "reading user-defined operator families\n");
194
0
  getOpfamilies(fout, &numOpfamilies);
195
196
0
  if (g_verbose)
197
0
    write_msg(NULL, "reading user-defined text search parsers\n");
198
0
  getTSParsers(fout, &numTSParsers);
199
200
0
  if (g_verbose)
201
0
    write_msg(NULL, "reading user-defined text search templates\n");
202
0
  getTSTemplates(fout, &numTSTemplates);
203
204
0
  if (g_verbose)
205
0
    write_msg(NULL, "reading user-defined text search dictionaries\n");
206
0
  getTSDictionaries(fout, &numTSDicts);
207
208
0
  if (g_verbose)
209
0
    write_msg(NULL, "reading user-defined text search configurations\n");
210
0
  getTSConfigurations(fout, &numTSConfigs);
211
212
0
  if (g_verbose)
213
0
    write_msg(NULL, "reading user-defined foreign-data wrappers\n");
214
0
  getForeignDataWrappers(fout, &numForeignDataWrappers);
215
216
0
  if (g_verbose)
217
0
    write_msg(NULL, "reading user-defined foreign servers\n");
218
0
  getForeignServers(fout, &numForeignServers);
219
220
0
  if (g_verbose)
221
0
    write_msg(NULL, "reading default privileges\n");
222
0
  getDefaultACLs(fout, &numDefaultACLs);
223
224
0
  if (g_verbose)
225
0
    write_msg(NULL, "reading user-defined collations\n");
226
0
  collinfo = getCollations(fout, &numCollations);
227
0
  collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
228
229
0
  if (g_verbose)
230
0
    write_msg(NULL, "reading user-defined conversions\n");
231
0
  getConversions(fout, &numConversions);
232
233
0
  if (g_verbose)
234
0
    write_msg(NULL, "reading type casts\n");
235
0
  getCasts(fout, &numCasts);
236
237
0
  if (g_verbose)
238
0
    write_msg(NULL, "reading transforms\n");
239
0
  getTransforms(fout, &numTransforms);
240
241
0
  if (g_verbose)
242
0
    write_msg(NULL, "reading table inheritance information\n");
243
0
  inhinfo = getInherits(fout, &numInherits);
244
245
0
  if (g_verbose)
246
0
    write_msg(NULL, "reading event triggers\n");
247
0
  getEventTriggers(fout, &numEventTriggers);
248
249
  /* Identify extension configuration tables that should be dumped */
250
0
  if (g_verbose)
251
0
    write_msg(NULL, "finding extension tables\n");
252
0
  processExtensionTables(fout, extinfo, numExtensions);
253
254
  /* Link tables to parents, mark parents of target tables interesting */
255
0
  if (g_verbose)
256
0
    write_msg(NULL, "finding inheritance relationships\n");
257
0
  flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
258
259
0
  if (g_verbose)
260
0
    write_msg(NULL, "reading column info for interesting tables\n");
261
0
  getTableAttrs(fout, tblinfo, numTables);
262
263
0
  if (g_verbose)
264
0
    write_msg(NULL, "flagging inherited columns in subtables\n");
265
0
  flagInhAttrs(fout->dopt, tblinfo, numTables);
266
267
0
  if (g_verbose)
268
0
    write_msg(NULL, "reading indexes\n");
269
0
  getIndexes(fout, tblinfo, numTables);
270
271
0
  if (g_verbose)
272
0
    write_msg(NULL, "flagging indexes in partitioned tables\n");
273
0
  flagInhIndexes(fout, tblinfo, numTables);
274
275
0
  if (g_verbose)
276
0
    write_msg(NULL, "reading extended statistics\n");
277
0
  getExtendedStatistics(fout);
278
279
0
  if (g_verbose)
280
0
    write_msg(NULL, "reading constraints\n");
281
0
  getConstraints(fout, tblinfo, numTables);
282
283
0
  if (g_verbose)
284
0
    write_msg(NULL, "reading triggers\n");
285
0
  getTriggers(fout, tblinfo, numTables);
286
287
0
  if (g_verbose)
288
0
    write_msg(NULL, "reading rewrite rules\n");
289
0
  getRules(fout, &numRules);
290
291
0
  if (g_verbose)
292
0
    write_msg(NULL, "reading policies\n");
293
0
  getPolicies(fout, tblinfo, numTables);
294
295
0
  if (g_verbose)
296
0
    write_msg(NULL, "reading publications\n");
297
0
  getPublications(fout);
298
299
0
  if (g_verbose)
300
0
    write_msg(NULL, "reading publication membership\n");
301
0
  getPublicationTables(fout, tblinfo, numTables);
302
303
0
  if (g_verbose)
304
0
    write_msg(NULL, "reading subscriptions\n");
305
0
  getSubscriptions(fout);
306
307
0
  *numTablesPtr = numTables;
308
0
  return tblinfo;
309
0
}
310
311
/* flagInhTables -
312
 *   Fill in parent link fields of tables for which we need that information,
313
 *   and mark parents of target tables as interesting
314
 *
315
 * Note that only direct ancestors of targets are marked interesting.
316
 * This is sufficient; we don't much care whether they inherited their
317
 * attributes or not.
318
 *
319
 * modifies tblinfo
320
 */
321
static void
322
flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
323
        InhInfo *inhinfo, int numInherits)
324
0
{
325
0
  DumpOptions *dopt = fout->dopt;
326
0
  int     i,
327
0
        j;
328
329
0
  for (i = 0; i < numTables; i++)
330
0
  {
331
0
    bool    find_parents = true;
332
0
    bool    mark_parents = true;
333
334
    /* Some kinds never have parents */
335
0
    if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
336
0
      tblinfo[i].relkind == RELKIND_VIEW ||
337
0
      tblinfo[i].relkind == RELKIND_MATVIEW)
338
0
      continue;
339
340
    /*
341
     * Normally, we don't bother computing anything for non-target tables,
342
     * but if load-via-partition-root is specified, we gather information
343
     * on every partition in the system so that getRootTableInfo can trace
344
     * from any given to leaf partition all the way up to the root.  (We
345
     * don't need to mark them as interesting for getTableAttrs, though.)
346
     */
347
0
    if (!tblinfo[i].dobj.dump)
348
0
    {
349
0
      mark_parents = false;
350
351
0
      if (!dopt->load_via_partition_root ||
352
0
        !tblinfo[i].ispartition)
353
0
        find_parents = false;
354
0
    }
355
356
    /* If needed, find all the immediate parent tables. */
357
0
    if (find_parents)
358
0
      findParentsByOid(&tblinfo[i], inhinfo, numInherits);
359
360
    /*
361
     * If needed, mark the parents as interesting for getTableAttrs and
362
     * getIndexes.
363
     */
364
0
    if (mark_parents)
365
0
    {
366
0
      int     numParents = tblinfo[i].numParents;
367
0
      TableInfo **parents = tblinfo[i].parents;
368
369
0
      for (j = 0; j < numParents; j++)
370
0
        parents[j]->interesting = true;
371
0
    }
372
0
  }
373
0
}
374
375
/*
376
 * flagInhIndexes -
377
 *   Create AttachIndexInfo objects for partitioned indexes, and add
378
 *   appropriate dependency links.
379
 */
380
static void
381
flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
382
0
{
383
0
  int     i,
384
0
        j,
385
0
        k;
386
0
  DumpableObject ***parentIndexArray;
387
388
0
  parentIndexArray = (DumpableObject ***)
389
0
    pg_malloc0(getMaxDumpId() * sizeof(DumpableObject **));
390
391
0
  for (i = 0; i < numTables; i++)
392
0
  {
393
0
    TableInfo  *parenttbl;
394
0
    IndexAttachInfo *attachinfo;
395
396
0
    if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
397
0
      continue;
398
399
0
    Assert(tblinfo[i].numParents == 1);
400
0
    parenttbl = tblinfo[i].parents[0];
401
402
    /*
403
     * We need access to each parent table's index list, but there is no
404
     * index to cover them outside of this function.  To avoid having to
405
     * sort every parent table's indexes each time we come across each of
406
     * its partitions, create an indexed array for each parent the first
407
     * time it is required.
408
     */
409
0
    if (parentIndexArray[parenttbl->dobj.dumpId] == NULL)
410
0
      parentIndexArray[parenttbl->dobj.dumpId] =
411
0
        buildIndexArray(parenttbl->indexes,
412
0
                parenttbl->numIndexes,
413
0
                sizeof(IndxInfo));
414
415
0
    attachinfo = (IndexAttachInfo *)
416
0
      pg_malloc0(tblinfo[i].numIndexes * sizeof(IndexAttachInfo));
417
0
    for (j = 0, k = 0; j < tblinfo[i].numIndexes; j++)
418
0
    {
419
0
      IndxInfo   *index = &(tblinfo[i].indexes[j]);
420
0
      IndxInfo   *parentidx;
421
422
0
      if (index->parentidx == 0)
423
0
        continue;
424
425
0
      parentidx = findIndexByOid(index->parentidx,
426
0
                     parentIndexArray[parenttbl->dobj.dumpId],
427
0
                     parenttbl->numIndexes);
428
0
      if (parentidx == NULL)
429
0
        continue;
430
431
0
      attachinfo[k].dobj.objType = DO_INDEX_ATTACH;
432
0
      attachinfo[k].dobj.catId.tableoid = 0;
433
0
      attachinfo[k].dobj.catId.oid = 0;
434
0
      AssignDumpId(&attachinfo[k].dobj);
435
0
      attachinfo[k].dobj.name = pg_strdup(index->dobj.name);
436
0
      attachinfo[k].dobj.namespace = index->indextable->dobj.namespace;
437
0
      attachinfo[k].parentIdx = parentidx;
438
0
      attachinfo[k].partitionIdx = index;
439
440
      /*
441
       * We must state the DO_INDEX_ATTACH object's dependencies
442
       * explicitly, since it will not match anything in pg_depend.
443
       *
444
       * Give it dependencies on both the partition index and the parent
445
       * index, so that it will not be executed till both of those
446
       * exist.  (There's no need to care what order those are created
447
       * in.)
448
       *
449
       * In addition, give it dependencies on the indexes' underlying
450
       * tables.  This does nothing of great value so far as serial
451
       * restore ordering goes, but it ensures that a parallel restore
452
       * will not try to run the ATTACH concurrently with other
453
       * operations on those tables.
454
       */
455
0
      addObjectDependency(&attachinfo[k].dobj, index->dobj.dumpId);
456
0
      addObjectDependency(&attachinfo[k].dobj, parentidx->dobj.dumpId);
457
0
      addObjectDependency(&attachinfo[k].dobj,
458
0
                index->indextable->dobj.dumpId);
459
0
      addObjectDependency(&attachinfo[k].dobj,
460
0
                parentidx->indextable->dobj.dumpId);
461
462
0
      k++;
463
0
    }
464
0
  }
465
466
0
  for (i = 0; i < numTables; i++)
467
0
    if (parentIndexArray[i])
468
0
      pg_free(parentIndexArray[i]);
469
0
  pg_free(parentIndexArray);
470
0
}
471
472
/* flagInhAttrs -
473
 *   for each dumpable table in tblinfo, flag its inherited attributes
474
 *
475
 * What we need to do here is detect child columns that inherit NOT NULL
476
 * bits from their parents (so that we needn't specify that again for the
477
 * child) and child columns that have DEFAULT NULL when their parents had
478
 * some non-null default.  In the latter case, we make up a dummy AttrDefInfo
479
 * object so that we'll correctly emit the necessary DEFAULT NULL clause;
480
 * otherwise the backend will apply an inherited default to the column.
481
 *
482
 * modifies tblinfo
483
 */
484
static void
485
flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
486
0
{
487
0
  int     i,
488
0
        j,
489
0
        k;
490
491
0
  for (i = 0; i < numTables; i++)
492
0
  {
493
0
    TableInfo  *tbinfo = &(tblinfo[i]);
494
0
    int     numParents;
495
0
    TableInfo **parents;
496
497
    /* Some kinds never have parents */
498
0
    if (tbinfo->relkind == RELKIND_SEQUENCE ||
499
0
      tbinfo->relkind == RELKIND_VIEW ||
500
0
      tbinfo->relkind == RELKIND_MATVIEW)
501
0
      continue;
502
503
    /* Don't bother computing anything for non-target tables, either */
504
0
    if (!tbinfo->dobj.dump)
505
0
      continue;
506
507
0
    numParents = tbinfo->numParents;
508
0
    parents = tbinfo->parents;
509
510
0
    if (numParents == 0)
511
0
      continue;     /* nothing to see here, move along */
512
513
    /* For each column, search for matching column names in parent(s) */
514
0
    for (j = 0; j < tbinfo->numatts; j++)
515
0
    {
516
0
      bool    foundNotNull; /* Attr was NOT NULL in a parent */
517
0
      bool    foundDefault; /* Found a default in a parent */
518
519
      /* no point in examining dropped columns */
520
0
      if (tbinfo->attisdropped[j])
521
0
        continue;
522
523
0
      foundNotNull = false;
524
0
      foundDefault = false;
525
0
      for (k = 0; k < numParents; k++)
526
0
      {
527
0
        TableInfo  *parent = parents[k];
528
0
        int     inhAttrInd;
529
530
0
        inhAttrInd = strInArray(tbinfo->attnames[j],
531
0
                    parent->attnames,
532
0
                    parent->numatts);
533
0
        if (inhAttrInd >= 0)
534
0
        {
535
0
          foundNotNull |= parent->notnull[inhAttrInd];
536
0
          foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
537
0
        }
538
0
      }
539
540
      /* Remember if we found inherited NOT NULL */
541
0
      tbinfo->inhNotNull[j] = foundNotNull;
542
543
      /* Manufacture a DEFAULT NULL clause if necessary */
544
0
      if (foundDefault && tbinfo->attrdefs[j] == NULL)
545
0
      {
546
0
        AttrDefInfo *attrDef;
547
548
0
        attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
549
0
        attrDef->dobj.objType = DO_ATTRDEF;
550
0
        attrDef->dobj.catId.tableoid = 0;
551
0
        attrDef->dobj.catId.oid = 0;
552
0
        AssignDumpId(&attrDef->dobj);
553
0
        attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
554
0
        attrDef->dobj.namespace = tbinfo->dobj.namespace;
555
0
        attrDef->dobj.dump = tbinfo->dobj.dump;
556
557
0
        attrDef->adtable = tbinfo;
558
0
        attrDef->adnum = j + 1;
559
0
        attrDef->adef_expr = pg_strdup("NULL");
560
561
        /* Will column be dumped explicitly? */
562
0
        if (shouldPrintColumn(dopt, tbinfo, j))
563
0
        {
564
0
          attrDef->separate = false;
565
          /* No dependency needed: NULL cannot have dependencies */
566
0
        }
567
0
        else
568
0
        {
569
          /* column will be suppressed, print default separately */
570
0
          attrDef->separate = true;
571
          /* ensure it comes out after the table */
572
0
          addObjectDependency(&attrDef->dobj,
573
0
                    tbinfo->dobj.dumpId);
574
0
        }
575
576
0
        tbinfo->attrdefs[j] = attrDef;
577
0
      }
578
0
    }
579
0
  }
580
0
}
581
582
/*
583
 * AssignDumpId
584
 *    Given a newly-created dumpable object, assign a dump ID,
585
 *    and enter the object into the lookup table.
586
 *
587
 * The caller is expected to have filled in objType and catId,
588
 * but not any of the other standard fields of a DumpableObject.
589
 */
590
void
591
AssignDumpId(DumpableObject *dobj)
592
0
{
593
0
  dobj->dumpId = ++lastDumpId;
594
0
  dobj->name = NULL;      /* must be set later */
595
0
  dobj->namespace = NULL;   /* may be set later */
596
0
  dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
597
0
  dobj->ext_member = false; /* default assumption */
598
0
  dobj->dependencies = NULL;
599
0
  dobj->nDeps = 0;
600
0
  dobj->allocDeps = 0;
601
602
0
  while (dobj->dumpId >= allocedDumpIds)
603
0
  {
604
0
    int     newAlloc;
605
606
0
    if (allocedDumpIds <= 0)
607
0
    {
608
0
      newAlloc = 256;
609
0
      dumpIdMap = (DumpableObject **)
610
0
        pg_malloc(newAlloc * sizeof(DumpableObject *));
611
0
    }
612
0
    else
613
0
    {
614
0
      newAlloc = allocedDumpIds * 2;
615
0
      dumpIdMap = (DumpableObject **)
616
0
        pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
617
0
    }
618
0
    memset(dumpIdMap + allocedDumpIds, 0,
619
0
         (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
620
0
    allocedDumpIds = newAlloc;
621
0
  }
622
0
  dumpIdMap[dobj->dumpId] = dobj;
623
624
  /* mark catalogIdMap invalid, but don't rebuild it yet */
625
0
  catalogIdMapValid = false;
626
0
}
627
628
/*
629
 * Assign a DumpId that's not tied to a DumpableObject.
630
 *
631
 * This is used when creating a "fixed" ArchiveEntry that doesn't need to
632
 * participate in the sorting logic.
633
 */
634
DumpId
635
createDumpId(void)
636
0
{
637
0
  return ++lastDumpId;
638
0
}
639
640
/*
641
 * Return the largest DumpId so far assigned
642
 */
643
DumpId
644
getMaxDumpId(void)
645
0
{
646
0
  return lastDumpId;
647
0
}
648
649
/*
650
 * Find a DumpableObject by dump ID
651
 *
652
 * Returns NULL for invalid ID
653
 */
654
DumpableObject *
655
findObjectByDumpId(DumpId dumpId)
656
0
{
657
0
  if (dumpId <= 0 || dumpId >= allocedDumpIds)
658
0
    return NULL;     /* out of range? */
659
0
  return dumpIdMap[dumpId];
660
0
}
661
662
/*
663
 * Find a DumpableObject by catalog ID
664
 *
665
 * Returns NULL for unknown ID
666
 *
667
 * We use binary search in a sorted list that is built on first call.
668
 * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
669
 * the code would work, but possibly be very slow.  In the current usage
670
 * pattern that does not happen, indeed we build the list at most twice.
671
 */
672
DumpableObject *
673
findObjectByCatalogId(CatalogId catalogId)
674
0
{
675
0
  DumpableObject **low;
676
0
  DumpableObject **high;
677
678
0
  if (!catalogIdMapValid)
679
0
  {
680
0
    if (catalogIdMap)
681
0
      free(catalogIdMap);
682
0
    getDumpableObjects(&catalogIdMap, &numCatalogIds);
683
0
    if (numCatalogIds > 1)
684
0
      qsort((void *) catalogIdMap, numCatalogIds,
685
0
          sizeof(DumpableObject *), DOCatalogIdCompare);
686
0
    catalogIdMapValid = true;
687
0
  }
688
689
  /*
690
   * We could use bsearch() here, but the notational cruft of calling
691
   * bsearch is nearly as bad as doing it ourselves; and the generalized
692
   * bsearch function is noticeably slower as well.
693
   */
694
0
  if (numCatalogIds <= 0)
695
0
    return NULL;
696
0
  low = catalogIdMap;
697
0
  high = catalogIdMap + (numCatalogIds - 1);
698
0
  while (low <= high)
699
0
  {
700
0
    DumpableObject **middle;
701
0
    int     difference;
702
703
0
    middle = low + (high - low) / 2;
704
    /* comparison must match DOCatalogIdCompare, below */
705
0
    difference = oidcmp((*middle)->catId.oid, catalogId.oid);
706
0
    if (difference == 0)
707
0
      difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
708
0
    if (difference == 0)
709
0
      return *middle;
710
0
    else if (difference < 0)
711
0
      low = middle + 1;
712
0
    else
713
0
      high = middle - 1;
714
0
  }
715
0
  return NULL;
716
0
}
717
718
/*
719
 * Find a DumpableObject by OID, in a pre-sorted array of one type of object
720
 *
721
 * Returns NULL for unknown OID
722
 */
723
static DumpableObject *
724
findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
725
0
{
726
0
  DumpableObject **low;
727
0
  DumpableObject **high;
728
729
  /*
730
   * This is the same as findObjectByCatalogId except we assume we need not
731
   * look at table OID because the objects are all the same type.
732
   *
733
   * We could use bsearch() here, but the notational cruft of calling
734
   * bsearch is nearly as bad as doing it ourselves; and the generalized
735
   * bsearch function is noticeably slower as well.
736
   */
737
0
  if (numObjs <= 0)
738
0
    return NULL;
739
0
  low = indexArray;
740
0
  high = indexArray + (numObjs - 1);
741
0
  while (low <= high)
742
0
  {
743
0
    DumpableObject **middle;
744
0
    int     difference;
745
746
0
    middle = low + (high - low) / 2;
747
0
    difference = oidcmp((*middle)->catId.oid, oid);
748
0
    if (difference == 0)
749
0
      return *middle;
750
0
    else if (difference < 0)
751
0
      low = middle + 1;
752
0
    else
753
0
      high = middle - 1;
754
0
  }
755
0
  return NULL;
756
0
}
757
758
/*
759
 * Build an index array of DumpableObject pointers, sorted by OID
760
 */
761
static DumpableObject **
762
buildIndexArray(void *objArray, int numObjs, Size objSize)
763
0
{
764
0
  DumpableObject **ptrs;
765
0
  int     i;
766
767
0
  ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
768
0
  for (i = 0; i < numObjs; i++)
769
0
    ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
770
771
  /* We can use DOCatalogIdCompare to sort since its first key is OID */
772
0
  if (numObjs > 1)
773
0
    qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
774
0
        DOCatalogIdCompare);
775
776
0
  return ptrs;
777
0
}
778
779
/*
780
 * qsort comparator for pointers to DumpableObjects
781
 */
782
static int
783
DOCatalogIdCompare(const void *p1, const void *p2)
784
0
{
785
0
  const DumpableObject *obj1 = *(DumpableObject *const *) p1;
786
0
  const DumpableObject *obj2 = *(DumpableObject *const *) p2;
787
0
  int     cmpval;
788
789
  /*
790
   * Compare OID first since it's usually unique, whereas there will only be
791
   * a few distinct values of tableoid.
792
   */
793
0
  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
794
0
  if (cmpval == 0)
795
0
    cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
796
0
  return cmpval;
797
0
}
798
799
/*
800
 * Build an array of pointers to all known dumpable objects
801
 *
802
 * This simply creates a modifiable copy of the internal map.
803
 */
804
void
805
getDumpableObjects(DumpableObject ***objs, int *numObjs)
806
0
{
807
0
  int     i,
808
0
        j;
809
810
0
  *objs = (DumpableObject **)
811
0
    pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
812
0
  j = 0;
813
0
  for (i = 1; i < allocedDumpIds; i++)
814
0
  {
815
0
    if (dumpIdMap[i])
816
0
      (*objs)[j++] = dumpIdMap[i];
817
0
  }
818
0
  *numObjs = j;
819
0
}
820
821
/*
822
 * Add a dependency link to a DumpableObject
823
 *
824
 * Note: duplicate dependencies are currently not eliminated
825
 */
826
void
827
addObjectDependency(DumpableObject *dobj, DumpId refId)
828
0
{
829
0
  if (dobj->nDeps >= dobj->allocDeps)
830
0
  {
831
0
    if (dobj->allocDeps <= 0)
832
0
    {
833
0
      dobj->allocDeps = 16;
834
0
      dobj->dependencies = (DumpId *)
835
0
        pg_malloc(dobj->allocDeps * sizeof(DumpId));
836
0
    }
837
0
    else
838
0
    {
839
0
      dobj->allocDeps *= 2;
840
0
      dobj->dependencies = (DumpId *)
841
0
        pg_realloc(dobj->dependencies,
842
0
               dobj->allocDeps * sizeof(DumpId));
843
0
    }
844
0
  }
845
0
  dobj->dependencies[dobj->nDeps++] = refId;
846
0
}
847
848
/*
849
 * Remove a dependency link from a DumpableObject
850
 *
851
 * If there are multiple links, all are removed
852
 */
853
void
854
removeObjectDependency(DumpableObject *dobj, DumpId refId)
855
0
{
856
0
  int     i;
857
0
  int     j = 0;
858
859
0
  for (i = 0; i < dobj->nDeps; i++)
860
0
  {
861
0
    if (dobj->dependencies[i] != refId)
862
0
      dobj->dependencies[j++] = dobj->dependencies[i];
863
0
  }
864
0
  dobj->nDeps = j;
865
0
}
866
867
868
/*
869
 * findTableByOid
870
 *    finds the entry (in tblinfo) of the table with the given oid
871
 *    returns NULL if not found
872
 */
873
TableInfo *
874
findTableByOid(Oid oid)
875
0
{
876
0
  return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
877
0
}
878
879
/*
880
 * findTypeByOid
881
 *    finds the entry (in typinfo) of the type with the given oid
882
 *    returns NULL if not found
883
 */
884
TypeInfo *
885
findTypeByOid(Oid oid)
886
0
{
887
0
  return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
888
0
}
889
890
/*
891
 * findFuncByOid
892
 *    finds the entry (in funinfo) of the function with the given oid
893
 *    returns NULL if not found
894
 */
895
FuncInfo *
896
findFuncByOid(Oid oid)
897
0
{
898
0
  return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
899
0
}
900
901
/*
902
 * findOprByOid
903
 *    finds the entry (in oprinfo) of the operator with the given oid
904
 *    returns NULL if not found
905
 */
906
OprInfo *
907
findOprByOid(Oid oid)
908
0
{
909
0
  return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
910
0
}
911
912
/*
913
 * findCollationByOid
914
 *    finds the entry (in collinfo) of the collation with the given oid
915
 *    returns NULL if not found
916
 */
917
CollInfo *
918
findCollationByOid(Oid oid)
919
0
{
920
0
  return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
921
0
}
922
923
/*
924
 * findNamespaceByOid
925
 *    finds the entry (in nspinfo) of the namespace with the given oid
926
 *    returns NULL if not found
927
 */
928
NamespaceInfo *
929
findNamespaceByOid(Oid oid)
930
0
{
931
0
  return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
932
0
}
933
934
/*
935
 * findExtensionByOid
936
 *    finds the entry (in extinfo) of the extension with the given oid
937
 *    returns NULL if not found
938
 */
939
ExtensionInfo *
940
findExtensionByOid(Oid oid)
941
0
{
942
0
  return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
943
0
}
944
945
/*
946
 * findTablegroupByOid
947
 *    finds the entry (in tblgrpinfo) of the tablegroup with the given oid
948
 *    returns NULL if not found
949
 */
950
TablegroupInfo *
951
findTablegroupByOid(Oid oid)
952
0
{
953
0
  return (TablegroupInfo *) findObjectByOid(oid, tblgrpinfoindex, numTablegroups);
954
0
}
955
956
/*
957
 * findIndexByOid
958
 *    find the entry of the index with the given oid
959
 *
960
 * This one's signature is different from the previous ones because we lack a
961
 * global array of all indexes, so caller must pass their array as argument.
962
 */
963
static IndxInfo *
964
findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
965
0
{
966
0
  return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
967
0
}
968
969
/*
970
 * setExtensionMembership
971
 *    accept and save data about which objects belong to extensions
972
 */
973
void
974
setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
975
0
{
976
  /* Sort array in preparation for binary searches */
977
0
  if (nextmems > 1)
978
0
    qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
979
0
        ExtensionMemberIdCompare);
980
  /* And save */
981
0
  extmembers = extmems;
982
0
  numextmembers = nextmems;
983
0
}
984
985
/*
986
 * findOwningExtension
987
 *    return owning extension for specified catalog ID, or NULL if none
988
 */
989
ExtensionInfo *
990
findOwningExtension(CatalogId catalogId)
991
0
{
992
0
  ExtensionMemberId *low;
993
0
  ExtensionMemberId *high;
994
995
  /*
996
   * We could use bsearch() here, but the notational cruft of calling
997
   * bsearch is nearly as bad as doing it ourselves; and the generalized
998
   * bsearch function is noticeably slower as well.
999
   */
1000
0
  if (numextmembers <= 0)
1001
0
    return NULL;
1002
0
  low = extmembers;
1003
0
  high = extmembers + (numextmembers - 1);
1004
0
  while (low <= high)
1005
0
  {
1006
0
    ExtensionMemberId *middle;
1007
0
    int     difference;
1008
1009
0
    middle = low + (high - low) / 2;
1010
    /* comparison must match ExtensionMemberIdCompare, below */
1011
0
    difference = oidcmp(middle->catId.oid, catalogId.oid);
1012
0
    if (difference == 0)
1013
0
      difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
1014
0
    if (difference == 0)
1015
0
      return middle->ext;
1016
0
    else if (difference < 0)
1017
0
      low = middle + 1;
1018
0
    else
1019
0
      high = middle - 1;
1020
0
  }
1021
0
  return NULL;
1022
0
}
1023
1024
/*
1025
 * qsort comparator for ExtensionMemberIds
1026
 */
1027
static int
1028
ExtensionMemberIdCompare(const void *p1, const void *p2)
1029
0
{
1030
0
  const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
1031
0
  const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
1032
0
  int     cmpval;
1033
1034
  /*
1035
   * Compare OID first since it's usually unique, whereas there will only be
1036
   * a few distinct values of tableoid.
1037
   */
1038
0
  cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
1039
0
  if (cmpval == 0)
1040
0
    cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
1041
0
  return cmpval;
1042
0
}
1043
1044
1045
/*
1046
 * findParentsByOid
1047
 *    find a table's parents in tblinfo[]
1048
 */
1049
static void
1050
findParentsByOid(TableInfo *self,
1051
         InhInfo *inhinfo, int numInherits)
1052
0
{
1053
0
  Oid     oid = self->dobj.catId.oid;
1054
0
  int     i,
1055
0
        j;
1056
0
  int     numParents;
1057
1058
0
  numParents = 0;
1059
0
  for (i = 0; i < numInherits; i++)
1060
0
  {
1061
0
    if (inhinfo[i].inhrelid == oid)
1062
0
      numParents++;
1063
0
  }
1064
1065
0
  self->numParents = numParents;
1066
1067
0
  if (numParents > 0)
1068
0
  {
1069
0
    self->parents = (TableInfo **)
1070
0
      pg_malloc(sizeof(TableInfo *) * numParents);
1071
0
    j = 0;
1072
0
    for (i = 0; i < numInherits; i++)
1073
0
    {
1074
0
      if (inhinfo[i].inhrelid == oid)
1075
0
      {
1076
0
        TableInfo  *parent;
1077
1078
0
        parent = findTableByOid(inhinfo[i].inhparent);
1079
0
        if (parent == NULL)
1080
0
        {
1081
0
          write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
1082
0
                inhinfo[i].inhparent,
1083
0
                self->dobj.name,
1084
0
                oid);
1085
0
          exit_nicely(1);
1086
0
        }
1087
0
        self->parents[j++] = parent;
1088
0
      }
1089
0
    }
1090
0
  }
1091
0
  else
1092
0
    self->parents = NULL;
1093
0
}
1094
1095
/*
1096
 * parseOidArray
1097
 *    parse a string of numbers delimited by spaces into a character array
1098
 *
1099
 * Note: actually this is used for both Oids and potentially-signed
1100
 * attribute numbers.  This should cause no trouble, but we could split
1101
 * the function into two functions with different argument types if it does.
1102
 */
1103
1104
void
1105
parseOidArray(const char *str, Oid *array, int arraysize)
1106
0
{
1107
0
  int     j,
1108
0
        argNum;
1109
0
  char    temp[100];
1110
0
  char    s;
1111
1112
0
  argNum = 0;
1113
0
  j = 0;
1114
0
  for (;;)
1115
0
  {
1116
0
    s = *str++;
1117
0
    if (s == ' ' || s == '\0')
1118
0
    {
1119
0
      if (j > 0)
1120
0
      {
1121
0
        if (argNum >= arraysize)
1122
0
        {
1123
0
          write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
1124
0
          exit_nicely(1);
1125
0
        }
1126
0
        temp[j] = '\0';
1127
0
        array[argNum++] = atooid(temp);
1128
0
        j = 0;
1129
0
      }
1130
0
      if (s == '\0')
1131
0
        break;
1132
0
    }
1133
0
    else
1134
0
    {
1135
0
      if (!(isdigit((unsigned char) s) || s == '-') ||
1136
0
        j >= sizeof(temp) - 1)
1137
0
      {
1138
0
        write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
1139
0
        exit_nicely(1);
1140
0
      }
1141
0
      temp[j++] = s;
1142
0
    }
1143
0
  }
1144
1145
0
  while (argNum < arraysize)
1146
0
    array[argNum++] = InvalidOid;
1147
0
}
1148
1149
1150
/*
1151
 * strInArray:
1152
 *    takes in a string and a string array and the number of elements in the
1153
 * string array.
1154
 *    returns the index if the string is somewhere in the array, -1 otherwise
1155
 */
1156
1157
static int
1158
strInArray(const char *pattern, char **arr, int arr_size)
1159
0
{
1160
0
  int     i;
1161
1162
0
  for (i = 0; i < arr_size; i++)
1163
0
  {
1164
0
    if (strcmp(pattern, arr[i]) == 0)
1165
0
      return i;
1166
0
  }
1167
0
  return -1;
1168
0
}