Age Owner Branch data TLA Line data Source code
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-2025, 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 <ctype.h>
19 : :
20 : : #include "catalog/pg_am_d.h"
21 : : #include "catalog/pg_class_d.h"
22 : : #include "catalog/pg_collation_d.h"
23 : : #include "catalog/pg_extension_d.h"
24 : : #include "catalog/pg_namespace_d.h"
25 : : #include "catalog/pg_operator_d.h"
26 : : #include "catalog/pg_proc_d.h"
27 : : #include "catalog/pg_publication_d.h"
28 : : #include "catalog/pg_subscription_d.h"
29 : : #include "catalog/pg_type_d.h"
30 : : #include "common/hashfn.h"
31 : : #include "pg_backup_utils.h"
32 : : #include "pg_dump.h"
33 : :
34 : : /*
35 : : * Variables for mapping DumpId to DumpableObject
36 : : */
37 : : static DumpableObject **dumpIdMap = NULL;
38 : : static int allocedDumpIds = 0;
39 : : static DumpId lastDumpId = 0; /* Note: 0 is InvalidDumpId */
40 : :
41 : : /*
42 : : * Infrastructure for mapping CatalogId to DumpableObject
43 : : *
44 : : * We use a hash table generated by simplehash.h. That infrastructure
45 : : * requires all the hash table entries to be the same size, and it also
46 : : * expects that it can move them around when resizing the table. So we
47 : : * cannot make the DumpableObjects be elements of the hash table directly;
48 : : * instead, the hash table elements contain pointers to DumpableObjects.
49 : : * This does have the advantage of letting us map multiple CatalogIds
50 : : * to one DumpableObject, which is useful for blobs.
51 : : *
52 : : * It turns out to be convenient to also use this data structure to map
53 : : * CatalogIds to owning extensions, if any. Since extension membership
54 : : * data is read before creating most DumpableObjects, either one of dobj
55 : : * and ext could be NULL.
56 : : */
57 : : typedef struct _catalogIdMapEntry
58 : : {
59 : : CatalogId catId; /* the indexed CatalogId */
60 : : uint32 status; /* hash status */
61 : : uint32 hashval; /* hash code for the CatalogId */
62 : : DumpableObject *dobj; /* the associated DumpableObject, if any */
63 : : ExtensionInfo *ext; /* owning extension, if any */
64 : : } CatalogIdMapEntry;
65 : :
66 : : #define SH_PREFIX catalogid
67 : : #define SH_ELEMENT_TYPE CatalogIdMapEntry
68 : : #define SH_KEY_TYPE CatalogId
69 : : #define SH_KEY catId
70 : : #define SH_HASH_KEY(tb, key) hash_bytes((const unsigned char *) &(key), sizeof(CatalogId))
71 : : #define SH_EQUAL(tb, a, b) ((a).oid == (b).oid && (a).tableoid == (b).tableoid)
72 : : #define SH_STORE_HASH
73 : : #define SH_GET_HASH(tb, a) (a)->hashval
74 : : #define SH_SCOPE static inline
75 : : #define SH_RAW_ALLOCATOR pg_malloc0
76 : : #define SH_DECLARE
77 : : #define SH_DEFINE
78 : : #include "lib/simplehash.h"
79 : :
80 : : #define CATALOGIDHASH_INITIAL_SIZE 10000
81 : :
82 : : static catalogid_hash *catalogIdHash = NULL;
83 : :
84 : : static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
85 : : InhInfo *inhinfo, int numInherits);
86 : : static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
87 : : static void flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo,
88 : : int numTables);
89 : : static int strInArray(const char *pattern, char **arr, int arr_size);
90 : : static IndxInfo *findIndexByOid(Oid oid);
91 : :
92 : :
93 : : /*
94 : : * getSchemaData
95 : : * Collect information about all potentially dumpable objects
96 : : */
97 : : TableInfo *
3524 tgl@sss.pgh.pa.us 98 :GIC 186 : getSchemaData(Archive *fout, int *numTablesPtr)
99 : : {
100 : : TableInfo *tblinfo;
101 : : ExtensionInfo *extinfo;
102 : : InhInfo *inhinfo;
103 : : int numTables;
104 : : int numExtensions;
105 : : int numInherits;
106 : :
107 : : /*
108 : : * We must read extensions and extension membership info first, because
109 : : * extension membership needs to be consultable during decisions about
110 : : * whether other objects are to be dumped.
111 : : */
2350 peter@eisentraut.org 112 : 186 : pg_log_info("reading extensions");
3524 tgl@sss.pgh.pa.us 113 : 186 : extinfo = getExtensions(fout, &numExtensions);
114 : :
2350 peter@eisentraut.org 115 : 186 : pg_log_info("identifying extension members");
3524 tgl@sss.pgh.pa.us 116 : 186 : getExtensionMembership(fout, extinfo, numExtensions);
117 : :
2350 peter@eisentraut.org 118 : 186 : pg_log_info("reading schemas");
431 nathan@postgresql.or 119 : 186 : getNamespaces(fout);
120 : :
121 : : /*
122 : : * getTables should be done as soon as possible, so as to minimize the
123 : : * window between starting our transaction and acquiring per-table locks.
124 : : * However, we have to do getNamespaces first because the tables get
125 : : * linked to their containing namespaces during getTables.
126 : : */
2350 peter@eisentraut.org 127 : 186 : pg_log_info("reading user-defined tables");
3524 tgl@sss.pgh.pa.us 128 : 186 : tblinfo = getTables(fout, &numTables);
129 : :
4907 130 : 185 : getOwnedSeqs(fout, tblinfo, numTables);
131 : :
2350 peter@eisentraut.org 132 : 185 : pg_log_info("reading user-defined functions");
431 nathan@postgresql.or 133 : 185 : getFuncs(fout);
134 : :
135 : : /* this must be after getTables and getFuncs */
2350 peter@eisentraut.org 136 : 185 : pg_log_info("reading user-defined types");
431 nathan@postgresql.or 137 : 185 : getTypes(fout);
138 : :
139 : : /* this must be after getFuncs, too */
2350 peter@eisentraut.org 140 : 185 : pg_log_info("reading procedural languages");
431 nathan@postgresql.or 141 : 185 : getProcLangs(fout);
142 : :
2350 peter@eisentraut.org 143 : 185 : pg_log_info("reading user-defined aggregate functions");
431 nathan@postgresql.or 144 : 185 : getAggregates(fout);
145 : :
2350 peter@eisentraut.org 146 : 185 : pg_log_info("reading user-defined operators");
431 nathan@postgresql.or 147 : 185 : getOperators(fout);
148 : :
2350 peter@eisentraut.org 149 : 185 : pg_log_info("reading user-defined access methods");
431 nathan@postgresql.or 150 : 185 : getAccessMethods(fout);
151 : :
2350 peter@eisentraut.org 152 : 185 : pg_log_info("reading user-defined operator classes");
431 nathan@postgresql.or 153 : 185 : getOpclasses(fout);
154 : :
2350 peter@eisentraut.org 155 : 185 : pg_log_info("reading user-defined operator families");
431 nathan@postgresql.or 156 : 185 : getOpfamilies(fout);
157 : :
2350 peter@eisentraut.org 158 : 185 : pg_log_info("reading user-defined text search parsers");
431 nathan@postgresql.or 159 : 185 : getTSParsers(fout);
160 : :
2350 peter@eisentraut.org 161 : 185 : pg_log_info("reading user-defined text search templates");
431 nathan@postgresql.or 162 : 185 : getTSTemplates(fout);
163 : :
2350 peter@eisentraut.org 164 : 185 : pg_log_info("reading user-defined text search dictionaries");
431 nathan@postgresql.or 165 : 185 : getTSDictionaries(fout);
166 : :
2350 peter@eisentraut.org 167 : 185 : pg_log_info("reading user-defined text search configurations");
431 nathan@postgresql.or 168 : 185 : getTSConfigurations(fout);
169 : :
2350 peter@eisentraut.org 170 : 185 : pg_log_info("reading user-defined foreign-data wrappers");
431 nathan@postgresql.or 171 : 185 : getForeignDataWrappers(fout);
172 : :
2350 peter@eisentraut.org 173 : 185 : pg_log_info("reading user-defined foreign servers");
431 nathan@postgresql.or 174 : 185 : getForeignServers(fout);
175 : :
2350 peter@eisentraut.org 176 : 185 : pg_log_info("reading default privileges");
431 nathan@postgresql.or 177 : 185 : getDefaultACLs(fout);
178 : :
2350 peter@eisentraut.org 179 : 185 : pg_log_info("reading user-defined collations");
431 nathan@postgresql.or 180 : 185 : getCollations(fout);
181 : :
2350 peter@eisentraut.org 182 : 185 : pg_log_info("reading user-defined conversions");
431 nathan@postgresql.or 183 : 185 : getConversions(fout);
184 : :
2350 peter@eisentraut.org 185 : 185 : pg_log_info("reading type casts");
431 nathan@postgresql.or 186 : 185 : getCasts(fout);
187 : :
2350 peter@eisentraut.org 188 : 185 : pg_log_info("reading transforms");
431 nathan@postgresql.or 189 : 185 : getTransforms(fout);
190 : :
2350 peter@eisentraut.org 191 : 185 : pg_log_info("reading table inheritance information");
4961 rhaas@postgresql.org 192 : 185 : inhinfo = getInherits(fout, &numInherits);
193 : :
2350 peter@eisentraut.org 194 : 185 : pg_log_info("reading event triggers");
431 nathan@postgresql.or 195 : 185 : getEventTriggers(fout);
196 : :
197 : : /* Identify extension configuration tables that should be dumped */
2350 peter@eisentraut.org 198 : 185 : pg_log_info("finding extension tables");
3524 tgl@sss.pgh.pa.us 199 : 185 : processExtensionTables(fout, extinfo, numExtensions);
200 : :
201 : : /* Link tables to parents, mark parents of target tables interesting */
2350 peter@eisentraut.org 202 : 185 : pg_log_info("finding inheritance relationships");
2945 rhaas@postgresql.org 203 : 185 : flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
204 : :
2350 peter@eisentraut.org 205 : 185 : pg_log_info("reading column info for interesting tables");
3524 tgl@sss.pgh.pa.us 206 : 185 : getTableAttrs(fout, tblinfo, numTables);
207 : :
2350 peter@eisentraut.org 208 : 185 : pg_log_info("flagging inherited columns in subtables");
302 alvherre@alvh.no-ip. 209 : 185 : flagInhAttrs(fout, fout->dopt, tblinfo, numTables);
210 : :
904 tgl@sss.pgh.pa.us 211 : 185 : pg_log_info("reading partitioning data");
212 : 185 : getPartitioningInfo(fout);
213 : :
2350 peter@eisentraut.org 214 : 185 : pg_log_info("reading indexes");
4961 rhaas@postgresql.org 215 : 185 : getIndexes(fout, tblinfo, numTables);
216 : :
2350 peter@eisentraut.org 217 : 185 : pg_log_info("flagging indexes in partitioned tables");
2787 alvherre@alvh.no-ip. 218 : 185 : flagInhIndexes(fout, tblinfo, numTables);
219 : :
2350 peter@eisentraut.org 220 : 185 : pg_log_info("reading extended statistics");
2764 tgl@sss.pgh.pa.us 221 : 185 : getExtendedStatistics(fout);
222 : :
2350 peter@eisentraut.org 223 : 185 : pg_log_info("reading constraints");
4961 rhaas@postgresql.org 224 : 185 : getConstraints(fout, tblinfo, numTables);
225 : :
2350 peter@eisentraut.org 226 : 185 : pg_log_info("reading triggers");
4961 rhaas@postgresql.org 227 : 185 : getTriggers(fout, tblinfo, numTables);
228 : :
2350 peter@eisentraut.org 229 : 185 : pg_log_info("reading rewrite rules");
431 nathan@postgresql.or 230 : 185 : getRules(fout);
231 : :
2350 peter@eisentraut.org 232 : 185 : pg_log_info("reading policies");
3936 sfrost@snowman.net 233 : 185 : getPolicies(fout, tblinfo, numTables);
234 : :
2350 peter@eisentraut.org 235 : 185 : pg_log_info("reading publications");
431 nathan@postgresql.or 236 : 185 : getPublications(fout);
237 : :
1410 akapila@postgresql.o 238 : 185 : pg_log_info("reading publication membership of tables");
3152 peter_e@gmx.net 239 : 185 : getPublicationTables(fout, tblinfo, numTables);
240 : :
1410 akapila@postgresql.o 241 : 185 : pg_log_info("reading publication membership of schemas");
242 : 185 : getPublicationNamespaces(fout);
243 : :
2350 peter@eisentraut.org 244 : 185 : pg_log_info("reading subscriptions");
3152 peter_e@gmx.net 245 : 185 : getSubscriptions(fout);
246 : :
613 akapila@postgresql.o 247 : 185 : pg_log_info("reading subscription membership of tables");
248 : 185 : getSubscriptionTables(fout);
249 : :
1413 tgl@sss.pgh.pa.us 250 : 185 : free(inhinfo); /* not needed any longer */
251 : :
5033 bruce@momjian.us 252 : 185 : *numTablesPtr = numTables;
253 : 185 : return tblinfo;
254 : : }
255 : :
256 : : /* flagInhTables -
257 : : * Fill in parent link fields of tables for which we need that information,
258 : : * mark parents of target tables as interesting, and create
259 : : * TableAttachInfo objects for partitioned tables with appropriate
260 : : * dependency links.
261 : : *
262 : : * Note that only direct ancestors of targets are marked interesting.
263 : : * This is sufficient; we don't much care whether they inherited their
264 : : * attributes or not.
265 : : *
266 : : * modifies tblinfo
267 : : */
268 : : static void
2945 rhaas@postgresql.org 269 : 185 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
270 : : InhInfo *inhinfo, int numInherits)
271 : : {
904 tgl@sss.pgh.pa.us 272 : 185 : TableInfo *child = NULL;
273 : 185 : TableInfo *parent = NULL;
274 : : int i,
275 : : j;
276 : :
277 : : /*
278 : : * Set up links from child tables to their parents.
279 : : *
280 : : * We used to attempt to skip this work for tables that are not to be
281 : : * dumped; but the optimizable cases are rare in practice, and setting up
282 : : * these links in bulk is cheaper than the old way. (Note in particular
283 : : * that it's very rare for a child to have more than one parent.)
284 : : */
285 [ + + ]: 3690 : for (i = 0; i < numInherits; i++)
286 : : {
287 : : /*
288 : : * Skip a hashtable lookup if it's same table as last time. This is
289 : : * unlikely for the child, but less so for the parent. (Maybe we
290 : : * should ask the backend for a sorted array to make it more likely?
291 : : * Not clear the sorting effort would be repaid, though.)
292 : : */
293 [ + + ]: 3505 : if (child == NULL ||
294 [ + + ]: 2677 : child->dobj.catId.oid != inhinfo[i].inhrelid)
295 : : {
296 : 3388 : child = findTableByOid(inhinfo[i].inhrelid);
297 : :
298 : : /*
299 : : * If we find no TableInfo, assume the pg_inherits entry is for a
300 : : * partitioned index, which we don't need to track.
301 : : */
302 [ + + ]: 3388 : if (child == NULL)
303 : 756 : continue;
304 : : }
305 [ + + ]: 2749 : if (parent == NULL ||
306 [ + + ]: 2672 : parent->dobj.catId.oid != inhinfo[i].inhparent)
307 : : {
308 : 1646 : parent = findTableByOid(inhinfo[i].inhparent);
309 [ - + ]: 1646 : if (parent == NULL)
904 tgl@sss.pgh.pa.us 310 :UIC 0 : pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
311 : : inhinfo[i].inhparent,
312 : : child->dobj.name,
313 : : child->dobj.catId.oid);
314 : : }
315 : : /* Add this parent to the child's list of parents. */
904 tgl@sss.pgh.pa.us 316 [ + + ]:GIC 2749 : if (child->numParents > 0)
317 : 121 : child->parents = pg_realloc_array(child->parents,
318 : : TableInfo *,
319 : : child->numParents + 1);
320 : : else
321 : 2628 : child->parents = pg_malloc_array(TableInfo *, 1);
322 : 2749 : child->parents[child->numParents++] = parent;
323 : : }
324 : :
325 : : /*
326 : : * Now consider all child tables and mark parents interesting as needed.
327 : : */
328 [ + + ]: 49228 : for (i = 0; i < numTables; i++)
329 : : {
330 : : /*
331 : : * If needed, mark the parents as interesting for getTableAttrs and
332 : : * getIndexes. We only need this for direct parents of dumpable
333 : : * tables.
334 : : */
335 [ + + ]: 49043 : if (tblinfo[i].dobj.dump)
336 : : {
2945 rhaas@postgresql.org 337 : 31135 : int numParents = tblinfo[i].numParents;
338 : 31135 : TableInfo **parents = tblinfo[i].parents;
339 : :
340 [ + + ]: 33220 : for (j = 0; j < numParents; j++)
341 : 2085 : parents[j]->interesting = true;
342 : : }
343 : :
344 : : /* Create TableAttachInfo object if needed */
904 tgl@sss.pgh.pa.us 345 [ + + ]: 49043 : if ((tblinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
346 [ + + ]: 7338 : tblinfo[i].ispartition)
347 : : {
348 : : TableAttachInfo *attachinfo;
349 : :
350 : : /* With partitions there can only be one parent */
1699 351 [ - + ]: 1435 : if (tblinfo[i].numParents != 1)
1247 tgl@sss.pgh.pa.us 352 :UIC 0 : pg_fatal("invalid number of parents %d for table \"%s\"",
353 : : tblinfo[i].numParents,
354 : : tblinfo[i].dobj.name);
355 : :
1699 tgl@sss.pgh.pa.us 356 :GIC 1435 : attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
357 : 1435 : attachinfo->dobj.objType = DO_TABLE_ATTACH;
358 : 1435 : attachinfo->dobj.catId.tableoid = 0;
359 : 1435 : attachinfo->dobj.catId.oid = 0;
360 : 1435 : AssignDumpId(&attachinfo->dobj);
361 : 1435 : attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
362 : 1435 : attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
363 : 1435 : attachinfo->parentTbl = tblinfo[i].parents[0];
364 : 1435 : attachinfo->partitionTbl = &tblinfo[i];
365 : :
366 : : /*
367 : : * We must state the DO_TABLE_ATTACH object's dependencies
368 : : * explicitly, since it will not match anything in pg_depend.
369 : : *
370 : : * Give it dependencies on both the partition table and the parent
371 : : * table, so that it will not be executed till both of those
372 : : * exist. (There's no need to care what order those are created
373 : : * in.)
374 : : */
375 : 1435 : addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
376 : 1435 : addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
377 : : }
378 : : }
6907 379 : 185 : }
380 : :
381 : : /*
382 : : * flagInhIndexes -
383 : : * Create IndexAttachInfo objects for partitioned indexes, and add
384 : : * appropriate dependency links.
385 : : */
386 : : static void
2787 alvherre@alvh.no-ip. 387 : 185 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
388 : : {
389 : : int i,
390 : : j;
391 : :
392 [ + + ]: 49228 : for (i = 0; i < numTables; i++)
393 : : {
394 [ + + - + ]: 49043 : if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
395 : 47137 : continue;
396 : :
397 [ - + ]: 1906 : Assert(tblinfo[i].numParents == 1);
398 : :
1413 tgl@sss.pgh.pa.us 399 [ + + ]: 2573 : for (j = 0; j < tblinfo[i].numIndexes; j++)
400 : : {
2787 alvherre@alvh.no-ip. 401 : 667 : IndxInfo *index = &(tblinfo[i].indexes[j]);
402 : : IndxInfo *parentidx;
403 : : IndexAttachInfo *attachinfo;
404 : :
405 [ + + ]: 667 : if (index->parentidx == 0)
406 : 55 : continue;
407 : :
1415 tgl@sss.pgh.pa.us 408 : 612 : parentidx = findIndexByOid(index->parentidx);
2787 alvherre@alvh.no-ip. 409 [ - + ]: 612 : if (parentidx == NULL)
2787 alvherre@alvh.no-ip. 410 :UIC 0 : continue;
411 : :
1090 peter@eisentraut.org 412 :GIC 612 : attachinfo = pg_malloc_object(IndexAttachInfo);
413 : :
1413 tgl@sss.pgh.pa.us 414 : 612 : attachinfo->dobj.objType = DO_INDEX_ATTACH;
415 : 612 : attachinfo->dobj.catId.tableoid = 0;
416 : 612 : attachinfo->dobj.catId.oid = 0;
417 : 612 : AssignDumpId(&attachinfo->dobj);
418 : 612 : attachinfo->dobj.name = pg_strdup(index->dobj.name);
419 : 612 : attachinfo->dobj.namespace = index->indextable->dobj.namespace;
420 : 612 : attachinfo->parentIdx = parentidx;
421 : 612 : attachinfo->partitionIdx = index;
422 : :
423 : : /*
424 : : * We must state the DO_INDEX_ATTACH object's dependencies
425 : : * explicitly, since it will not match anything in pg_depend.
426 : : *
427 : : * Give it dependencies on both the partition index and the parent
428 : : * index, so that it will not be executed till both of those
429 : : * exist. (There's no need to care what order those are created
430 : : * in.)
431 : : *
432 : : * In addition, give it dependencies on the indexes' underlying
433 : : * tables. This does nothing of great value so far as serial
434 : : * restore ordering goes, but it ensures that a parallel restore
435 : : * will not try to run the ATTACH concurrently with other
436 : : * operations on those tables.
437 : : */
438 : 612 : addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
439 : 612 : addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
440 : 612 : addObjectDependency(&attachinfo->dobj,
2566 441 : 612 : index->indextable->dobj.dumpId);
1413 442 : 612 : addObjectDependency(&attachinfo->dobj,
2566 443 : 612 : parentidx->indextable->dobj.dumpId);
444 : :
445 : : /* keep track of the list of partitions in the parent index */
1413 446 : 612 : simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
447 : : }
448 : : }
2787 alvherre@alvh.no-ip. 449 : 185 : }
450 : :
451 : : /* flagInhAttrs -
452 : : * for each dumpable table in tblinfo, flag its inherited attributes
453 : : *
454 : : * What we need to do here is:
455 : : *
456 : : * - Detect child columns that inherit NOT NULL bits from their parents, so
457 : : * that we needn't specify that again for the child. For versions 18 and
458 : : * up, this is needed when the parent is NOT VALID and the child isn't.
459 : : *
460 : : * - Detect child columns that have DEFAULT NULL when their parents had some
461 : : * non-null default. In this case, we make up a dummy AttrDefInfo object so
462 : : * that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
463 : : * the backend will apply an inherited default to the column.
464 : : *
465 : : * - Detect child columns that have a generation expression and all their
466 : : * parents also have the same generation expression, and if so suppress the
467 : : * child's expression. The child will inherit the generation expression
468 : : * automatically, so there's no need to dump it. This improves the dump's
469 : : * compatibility with pre-v16 servers, which didn't allow the child's
470 : : * expression to be given explicitly. Exceptions: If it's a partition or
471 : : * we are in binary upgrade mode, we dump such expressions anyway because
472 : : * in those cases inherited tables are recreated standalone first and then
473 : : * reattached to the parent. (See also the logic in dumpTableSchema().)
474 : : *
475 : : * modifies tblinfo
476 : : */
477 : : static void
302 478 : 185 : flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
479 : : {
480 : : int i,
481 : : j,
482 : : k;
483 : :
484 : : /*
485 : : * We scan the tables in OID order, since that's how tblinfo[] is sorted.
486 : : * Hence we will typically visit parents before their children --- but
487 : : * that is *not* guaranteed. Thus this loop must be careful that it does
488 : : * not alter table properties in a way that could change decisions made at
489 : : * child tables during other iterations.
490 : : */
5033 bruce@momjian.us 491 [ + + ]: 49228 : for (i = 0; i < numTables; i++)
492 : : {
493 : 49043 : TableInfo *tbinfo = &(tblinfo[i]);
494 : : int numParents;
495 : : TableInfo **parents;
496 : :
497 : : /* Some kinds never have parents */
498 [ + + ]: 49043 : if (tbinfo->relkind == RELKIND_SEQUENCE ||
4570 kgrittn@postgresql.o 499 [ + + ]: 48387 : tbinfo->relkind == RELKIND_VIEW ||
500 [ + + ]: 20969 : tbinfo->relkind == RELKIND_MATVIEW)
5033 bruce@momjian.us 501 : 28640 : continue;
502 : :
503 : : /* Don't bother computing anything for non-target tables, either */
504 [ + + ]: 20403 : if (!tbinfo->dobj.dump)
505 : 3995 : continue;
506 : :
507 : 16408 : numParents = tbinfo->numParents;
508 : 16408 : parents = tbinfo->parents;
509 : :
510 [ + + ]: 16408 : if (numParents == 0)
511 : 14417 : continue; /* nothing to see here, move along */
512 : :
513 : : /* For each column, search for matching column names in parent(s) */
514 [ + + ]: 6879 : for (j = 0; j < tbinfo->numatts; j++)
515 : : {
516 : : bool foundNotNull; /* Attr was NOT NULL in a parent */
517 : : bool foundDefault; /* Found a default in a parent */
518 : : bool foundSameGenerated; /* Found matching GENERATED */
519 : : bool foundDiffGenerated; /* Found non-matching GENERATED */
131 alvherre@kurilemu.de 520 : 4888 : bool allNotNullsInvalid = true; /* is NOT NULL NOT VALID
521 : : * on all parents? */
522 : :
523 : : /* no point in examining dropped columns */
4957 tgl@sss.pgh.pa.us 524 [ + + ]: 4888 : if (tbinfo->attisdropped[j])
525 : 305 : continue;
526 : :
527 : 4583 : foundNotNull = false;
528 : 4583 : foundDefault = false;
969 529 : 4583 : foundSameGenerated = false;
530 : 4583 : foundDiffGenerated = false;
5033 bruce@momjian.us 531 [ + + ]: 9385 : for (k = 0; k < numParents; k++)
532 : : {
4957 tgl@sss.pgh.pa.us 533 : 4802 : TableInfo *parent = parents[k];
534 : : int inhAttrInd;
535 : :
5033 bruce@momjian.us 536 : 4802 : inhAttrInd = strInArray(tbinfo->attnames[j],
537 : : parent->attnames,
538 : : parent->numatts);
4957 tgl@sss.pgh.pa.us 539 [ + + ]: 4802 : if (inhAttrInd >= 0)
540 : : {
921 541 : 4562 : AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
542 : :
543 : : /*
544 : : * Account for each parent having a not-null constraint.
545 : : * In versions 18 and later, we don't need this (and those
546 : : * didn't have NO INHERIT.)
547 : : */
302 alvherre@alvh.no-ip. 548 [ - + ]: 4562 : if (fout->remoteVersion < 180000 &&
302 alvherre@alvh.no-ip. 549 [ # # ]:UIC 0 : parent->notnull_constrs[inhAttrInd] != NULL)
550 : 0 : foundNotNull = true;
551 : :
552 : : /*
553 : : * Keep track of whether all the parents that have a
554 : : * not-null constraint on this column have it as NOT
555 : : * VALID; if they all are, arrange to have it printed for
556 : : * this column. If at least one parent has it as valid,
557 : : * there's no need.
558 : : */
131 alvherre@kurilemu.de 559 [ + - ]:GIC 4562 : if (fout->remoteVersion >= 180000 &&
560 [ + + ]: 4562 : parent->notnull_constrs[inhAttrInd] &&
561 [ + - ]: 936 : !parent->notnull_invalid[inhAttrInd])
562 : 936 : allNotNullsInvalid = false;
563 : :
921 tgl@sss.pgh.pa.us 564 : 9662 : foundDefault |= (parentDef != NULL &&
565 [ + + + + ]: 5050 : strcmp(parentDef->adef_expr, "NULL") != 0 &&
969 566 [ + + ]: 488 : !parent->attgenerated[inhAttrInd]);
567 [ + + ]: 4562 : if (parent->attgenerated[inhAttrInd])
568 : : {
569 : : /* these pointer nullness checks are just paranoia */
921 570 [ + + ]: 296 : if (parentDef != NULL &&
969 571 [ + - ]: 272 : tbinfo->attrdefs[j] != NULL &&
921 572 : 272 : strcmp(parentDef->adef_expr,
969 573 [ + + ]: 272 : tbinfo->attrdefs[j]->adef_expr) == 0)
574 : 242 : foundSameGenerated = true;
575 : : else
576 : 54 : foundDiffGenerated = true;
577 : : }
578 : : }
579 : : }
580 : :
581 : : /*
582 : : * In versions < 18, for lack of a better system, we arbitrarily
583 : : * decide that a not-null constraint is not locally defined if at
584 : : * least one of the parents has it.
585 : : */
302 alvherre@alvh.no-ip. 586 [ - + - - ]: 4583 : if (fout->remoteVersion < 180000 && foundNotNull)
302 alvherre@alvh.no-ip. 587 :UIC 0 : tbinfo->notnull_islocal[j] = false;
588 : :
589 : : /*
590 : : * For versions >18, we must print the not-null constraint locally
591 : : * for this table even if it isn't really locally defined, but is
592 : : * valid for the child and no parent has it as valid.
593 : : */
131 alvherre@kurilemu.de 594 [ + - + + ]:GIC 4583 : if (fout->remoteVersion >= 180000 && allNotNullsInvalid)
595 : 3652 : tbinfo->notnull_islocal[j] = true;
596 : :
597 : : /*
598 : : * Manufacture a DEFAULT NULL clause if necessary. This breaks
599 : : * the advice given above to avoid changing state that might get
600 : : * inspected in other loop iterations. We prevent trouble by
601 : : * having the foundDefault test above check whether adef_expr is
602 : : * "NULL", so that it will reach the same conclusion before or
603 : : * after this is done.
604 : : */
4957 tgl@sss.pgh.pa.us 605 [ + + + + ]: 4583 : if (foundDefault && tbinfo->attrdefs[j] == NULL)
606 : : {
607 : : AttrDefInfo *attrDef;
608 : :
1090 peter@eisentraut.org 609 : 40 : attrDef = pg_malloc_object(AttrDefInfo);
4957 tgl@sss.pgh.pa.us 610 : 40 : attrDef->dobj.objType = DO_ATTRDEF;
611 : 40 : attrDef->dobj.catId.tableoid = 0;
612 : 40 : attrDef->dobj.catId.oid = 0;
613 : 40 : AssignDumpId(&attrDef->dobj);
614 : 40 : attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
615 : 40 : attrDef->dobj.namespace = tbinfo->dobj.namespace;
616 : 40 : attrDef->dobj.dump = tbinfo->dobj.dump;
617 : :
618 : 40 : attrDef->adtable = tbinfo;
619 : 40 : attrDef->adnum = j + 1;
620 : 40 : attrDef->adef_expr = pg_strdup("NULL");
621 : :
622 : : /* Will column be dumped explicitly? */
3980 alvherre@alvh.no-ip. 623 [ + - ]: 40 : if (shouldPrintColumn(dopt, tbinfo, j))
624 : : {
4957 tgl@sss.pgh.pa.us 625 : 40 : attrDef->separate = false;
626 : : /* No dependency needed: NULL cannot have dependencies */
627 : : }
628 : : else
629 : : {
630 : : /* column will be suppressed, print default separately */
4957 tgl@sss.pgh.pa.us 631 :UIC 0 : attrDef->separate = true;
632 : : /* ensure it comes out after the table */
633 : 0 : addObjectDependency(&attrDef->dobj,
634 : : tbinfo->dobj.dumpId);
635 : : }
636 : :
4957 tgl@sss.pgh.pa.us 637 :GIC 40 : tbinfo->attrdefs[j] = attrDef;
638 : : }
639 : :
640 : : /* No need to dump generation expression if it's inheritable */
969 641 [ + + + - ]: 4583 : if (foundSameGenerated && !foundDiffGenerated &&
642 [ + + + + ]: 242 : !tbinfo->ispartition && !dopt->binary_upgrade)
921 643 : 180 : tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
644 : : }
645 : : }
5033 bruce@momjian.us 646 : 185 : }
647 : :
648 : : /*
649 : : * AssignDumpId
650 : : * Given a newly-created dumpable object, assign a dump ID,
651 : : * and enter the object into the lookup tables.
652 : : *
653 : : * The caller is expected to have filled in objType and catId,
654 : : * but not any of the other standard fields of a DumpableObject.
655 : : */
656 : : void
657 : 819474 : AssignDumpId(DumpableObject *dobj)
658 : : {
659 : 819474 : dobj->dumpId = ++lastDumpId;
660 : 819474 : dobj->name = NULL; /* must be set later */
661 : 819474 : dobj->namespace = NULL; /* may be set later */
3440 sfrost@snowman.net 662 : 819474 : dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
1699 tgl@sss.pgh.pa.us 663 : 819474 : dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
664 : : /* All objects have definitions; we may set more components bits later */
1370 665 : 819474 : dobj->components = DUMP_COMPONENT_DEFINITION;
5033 bruce@momjian.us 666 : 819474 : dobj->ext_member = false; /* default assumption */
2005 alvherre@alvh.no-ip. 667 : 819474 : dobj->depends_on_ext = false; /* default assumption */
5033 bruce@momjian.us 668 : 819474 : dobj->dependencies = NULL;
669 : 819474 : dobj->nDeps = 0;
670 : 819474 : dobj->allocDeps = 0;
671 : :
672 : : /* Add object to dumpIdMap[], enlarging that array if need be */
673 [ + + ]: 820519 : while (dobj->dumpId >= allocedDumpIds)
674 : : {
675 : : int newAlloc;
676 : :
677 [ + + ]: 1045 : if (allocedDumpIds <= 0)
678 : : {
679 : 186 : newAlloc = 256;
1090 peter@eisentraut.org 680 : 186 : dumpIdMap = pg_malloc_array(DumpableObject *, newAlloc);
681 : : }
682 : : else
683 : : {
5033 bruce@momjian.us 684 : 859 : newAlloc = allocedDumpIds * 2;
1090 peter@eisentraut.org 685 : 859 : dumpIdMap = pg_realloc_array(dumpIdMap, DumpableObject *, newAlloc);
686 : : }
5033 bruce@momjian.us 687 : 1045 : memset(dumpIdMap + allocedDumpIds, 0,
688 : 1045 : (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
689 : 1045 : allocedDumpIds = newAlloc;
690 : : }
691 : 819474 : dumpIdMap[dobj->dumpId] = dobj;
692 : :
693 : : /* If it has a valid CatalogId, enter it into the hash table */
1415 tgl@sss.pgh.pa.us 694 [ + + ]: 819474 : if (OidIsValid(dobj->catId.tableoid))
695 : : {
696 : : CatalogIdMapEntry *entry;
697 : : bool found;
698 : :
699 : : /* Initialize CatalogId hash table if not done yet */
700 [ + + ]: 799450 : if (catalogIdHash == NULL)
701 : 186 : catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
702 : :
703 : 799450 : entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
704 [ + + ]: 799450 : if (!found)
705 : : {
706 : 798557 : entry->dobj = NULL;
707 : 798557 : entry->ext = NULL;
708 : : }
709 [ - + ]: 799450 : Assert(entry->dobj == NULL);
710 : 799450 : entry->dobj = dobj;
711 : : }
5033 bruce@momjian.us 712 : 819474 : }
713 : :
714 : : /*
715 : : * recordAdditionalCatalogID
716 : : * Record an additional catalog ID for the given DumpableObject
717 : : */
718 : : void
523 tgl@sss.pgh.pa.us 719 : 10 : recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
720 : : {
721 : : CatalogIdMapEntry *entry;
722 : : bool found;
723 : :
724 : : /* CatalogId hash table must exist, if we have a DumpableObject */
725 [ - + ]: 10 : Assert(catalogIdHash != NULL);
726 : :
727 : : /* Add reference to CatalogId hash */
728 : 10 : entry = catalogid_insert(catalogIdHash, catId, &found);
729 [ + - ]: 10 : if (!found)
730 : : {
731 : 10 : entry->dobj = NULL;
732 : 10 : entry->ext = NULL;
733 : : }
734 [ - + ]: 10 : Assert(entry->dobj == NULL);
735 : 10 : entry->dobj = dobj;
736 : 10 : }
737 : :
738 : : /*
739 : : * Assign a DumpId that's not tied to a DumpableObject.
740 : : *
741 : : * This is used when creating a "fixed" ArchiveEntry that doesn't need to
742 : : * participate in the sorting logic.
743 : : */
744 : : DumpId
5033 bruce@momjian.us 745 : 13988 : createDumpId(void)
746 : : {
747 : 13988 : return ++lastDumpId;
748 : : }
749 : :
750 : : /*
751 : : * Return the largest DumpId so far assigned
752 : : */
753 : : DumpId
754 : 1310 : getMaxDumpId(void)
755 : : {
756 : 1310 : return lastDumpId;
757 : : }
758 : :
759 : : /*
760 : : * Find a DumpableObject by dump ID
761 : : *
762 : : * Returns NULL for invalid ID
763 : : */
764 : : DumpableObject *
765 : 24046100 : findObjectByDumpId(DumpId dumpId)
766 : : {
767 [ + - + + ]: 24046100 : if (dumpId <= 0 || dumpId >= allocedDumpIds)
768 : 64 : return NULL; /* out of range? */
769 : 24046036 : return dumpIdMap[dumpId];
770 : : }
771 : :
772 : : /*
773 : : * Find a DumpableObject by catalog ID
774 : : *
775 : : * Returns NULL for unknown ID
776 : : */
777 : : DumpableObject *
778 : 3856205 : findObjectByCatalogId(CatalogId catalogId)
779 : : {
780 : : CatalogIdMapEntry *entry;
781 : :
1415 tgl@sss.pgh.pa.us 782 [ - + ]: 3856205 : if (catalogIdHash == NULL)
1415 tgl@sss.pgh.pa.us 783 :UIC 0 : return NULL; /* no objects exist yet */
784 : :
1415 tgl@sss.pgh.pa.us 785 :GIC 3856205 : entry = catalogid_lookup(catalogIdHash, catalogId);
786 [ + + ]: 3856205 : if (entry == NULL)
5033 bruce@momjian.us 787 : 669032 : return NULL;
1415 tgl@sss.pgh.pa.us 788 : 3187173 : return entry->dobj;
789 : : }
790 : :
791 : : /*
792 : : * Build an array of pointers to all known dumpable objects
793 : : *
794 : : * This simply creates a modifiable copy of the internal map.
795 : : */
796 : : void
5033 bruce@momjian.us 797 : 192 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
798 : : {
799 : : int i,
800 : : j;
801 : :
1090 peter@eisentraut.org 802 : 192 : *objs = pg_malloc_array(DumpableObject *, allocedDumpIds);
5033 bruce@momjian.us 803 : 192 : j = 0;
804 [ + + ]: 1314816 : for (i = 1; i < allocedDumpIds; i++)
805 : : {
806 [ + + ]: 1314624 : if (dumpIdMap[i])
807 : 849909 : (*objs)[j++] = dumpIdMap[i];
808 : : }
809 : 192 : *numObjs = j;
810 : 192 : }
811 : :
812 : : /*
813 : : * Add a dependency link to a DumpableObject
814 : : *
815 : : * Note: duplicate dependencies are currently not eliminated
816 : : */
817 : : void
818 : 1217500 : addObjectDependency(DumpableObject *dobj, DumpId refId)
819 : : {
820 [ + + ]: 1217500 : if (dobj->nDeps >= dobj->allocDeps)
821 : : {
822 [ + + ]: 185588 : if (dobj->allocDeps <= 0)
823 : : {
824 : 176084 : dobj->allocDeps = 16;
1090 peter@eisentraut.org 825 : 176084 : dobj->dependencies = pg_malloc_array(DumpId, dobj->allocDeps);
826 : : }
827 : : else
828 : : {
5033 bruce@momjian.us 829 : 9504 : dobj->allocDeps *= 2;
1090 peter@eisentraut.org 830 : 9504 : dobj->dependencies = pg_realloc_array(dobj->dependencies,
831 : : DumpId, dobj->allocDeps);
832 : : }
833 : : }
5033 bruce@momjian.us 834 : 1217500 : dobj->dependencies[dobj->nDeps++] = refId;
835 : 1217500 : }
836 : :
837 : : /*
838 : : * Remove a dependency link from a DumpableObject
839 : : *
840 : : * If there are multiple links, all are removed
841 : : */
842 : : void
843 : 31208 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
844 : : {
845 : : int i;
846 : 31208 : int j = 0;
847 : :
848 [ + + ]: 891069 : for (i = 0; i < dobj->nDeps; i++)
849 : : {
850 [ + + ]: 859861 : if (dobj->dependencies[i] != refId)
851 : 827152 : dobj->dependencies[j++] = dobj->dependencies[i];
852 : : }
853 : 31208 : dobj->nDeps = j;
854 : 31208 : }
855 : :
856 : :
857 : : /*
858 : : * findTableByOid
859 : : * finds the DumpableObject for the table with the given oid
860 : : * returns NULL if not found
861 : : */
862 : : TableInfo *
863 : 84190 : findTableByOid(Oid oid)
864 : : {
865 : : CatalogId catId;
866 : : DumpableObject *dobj;
867 : :
1415 tgl@sss.pgh.pa.us 868 : 84190 : catId.tableoid = RelationRelationId;
869 : 84190 : catId.oid = oid;
870 : 84190 : dobj = findObjectByCatalogId(catId);
871 [ + + - + ]: 84190 : Assert(dobj == NULL || dobj->objType == DO_TABLE);
872 : 84190 : return (TableInfo *) dobj;
873 : : }
874 : :
875 : : /*
876 : : * findIndexByOid
877 : : * finds the DumpableObject for the index with the given oid
878 : : * returns NULL if not found
879 : : */
880 : : static IndxInfo *
881 : 612 : findIndexByOid(Oid oid)
882 : : {
883 : : CatalogId catId;
884 : : DumpableObject *dobj;
885 : :
886 : 612 : catId.tableoid = RelationRelationId;
887 : 612 : catId.oid = oid;
888 : 612 : dobj = findObjectByCatalogId(catId);
889 [ + - - + ]: 612 : Assert(dobj == NULL || dobj->objType == DO_INDEX);
890 : 612 : return (IndxInfo *) dobj;
891 : : }
892 : :
893 : : /*
894 : : * findTypeByOid
895 : : * finds the DumpableObject for the type with the given oid
896 : : * returns NULL if not found
897 : : */
898 : : TypeInfo *
5033 bruce@momjian.us 899 : 1409840 : findTypeByOid(Oid oid)
900 : : {
901 : : CatalogId catId;
902 : : DumpableObject *dobj;
903 : :
1415 tgl@sss.pgh.pa.us 904 : 1409840 : catId.tableoid = TypeRelationId;
905 : 1409840 : catId.oid = oid;
906 : 1409840 : dobj = findObjectByCatalogId(catId);
907 [ + - + + : 1409840 : Assert(dobj == NULL ||
- + ]
908 : : dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
909 : 1409840 : return (TypeInfo *) dobj;
910 : : }
911 : :
912 : : /*
913 : : * findFuncByOid
914 : : * finds the DumpableObject for the function with the given oid
915 : : * returns NULL if not found
916 : : */
917 : : FuncInfo *
5033 bruce@momjian.us 918 : 295 : findFuncByOid(Oid oid)
919 : : {
920 : : CatalogId catId;
921 : : DumpableObject *dobj;
922 : :
1415 tgl@sss.pgh.pa.us 923 : 295 : catId.tableoid = ProcedureRelationId;
924 : 295 : catId.oid = oid;
925 : 295 : dobj = findObjectByCatalogId(catId);
926 [ + + - + ]: 295 : Assert(dobj == NULL || dobj->objType == DO_FUNC);
927 : 295 : return (FuncInfo *) dobj;
928 : : }
929 : :
930 : : /*
931 : : * findOprByOid
932 : : * finds the DumpableObject for the operator with the given oid
933 : : * returns NULL if not found
934 : : */
935 : : OprInfo *
5033 bruce@momjian.us 936 : 2824 : findOprByOid(Oid oid)
937 : : {
938 : : CatalogId catId;
939 : : DumpableObject *dobj;
940 : :
1415 tgl@sss.pgh.pa.us 941 : 2824 : catId.tableoid = OperatorRelationId;
942 : 2824 : catId.oid = oid;
943 : 2824 : dobj = findObjectByCatalogId(catId);
944 [ + - - + ]: 2824 : Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
945 : 2824 : return (OprInfo *) dobj;
946 : : }
947 : :
948 : : /*
949 : : * findAccessMethodByOid
950 : : * finds the DumpableObject for the access method with the given oid
951 : : * returns NULL if not found
952 : : */
953 : : AccessMethodInfo *
37 noah@leadboat.com 954 : 51222 : findAccessMethodByOid(Oid oid)
955 : : {
956 : : CatalogId catId;
957 : : DumpableObject *dobj;
958 : :
959 : 51222 : catId.tableoid = AccessMethodRelationId;
960 : 51222 : catId.oid = oid;
961 : 51222 : dobj = findObjectByCatalogId(catId);
962 [ + - - + ]: 51222 : Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
963 : 51222 : return (AccessMethodInfo *) dobj;
964 : : }
965 : :
966 : : /*
967 : : * findCollationByOid
968 : : * finds the DumpableObject for the collation with the given oid
969 : : * returns NULL if not found
970 : : */
971 : : CollInfo *
5033 bruce@momjian.us 972 : 278 : findCollationByOid(Oid oid)
973 : : {
974 : : CatalogId catId;
975 : : DumpableObject *dobj;
976 : :
1415 tgl@sss.pgh.pa.us 977 : 278 : catId.tableoid = CollationRelationId;
978 : 278 : catId.oid = oid;
979 : 278 : dobj = findObjectByCatalogId(catId);
980 [ + - - + ]: 278 : Assert(dobj == NULL || dobj->objType == DO_COLLATION);
981 : 278 : return (CollInfo *) dobj;
982 : : }
983 : :
984 : : /*
985 : : * findNamespaceByOid
986 : : * finds the DumpableObject for the namespace with the given oid
987 : : * returns NULL if not found
988 : : */
989 : : NamespaceInfo *
4852 990 : 714937 : findNamespaceByOid(Oid oid)
991 : : {
992 : : CatalogId catId;
993 : : DumpableObject *dobj;
994 : :
1415 995 : 714937 : catId.tableoid = NamespaceRelationId;
996 : 714937 : catId.oid = oid;
997 : 714937 : dobj = findObjectByCatalogId(catId);
998 [ + - - + ]: 714937 : Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
999 : 714937 : return (NamespaceInfo *) dobj;
1000 : : }
1001 : :
1002 : : /*
1003 : : * findExtensionByOid
1004 : : * finds the DumpableObject for the extension with the given oid
1005 : : * returns NULL if not found
1006 : : */
1007 : : ExtensionInfo *
3524 1008 : 211 : findExtensionByOid(Oid oid)
1009 : : {
1010 : : CatalogId catId;
1011 : : DumpableObject *dobj;
1012 : :
1415 1013 : 211 : catId.tableoid = ExtensionRelationId;
1014 : 211 : catId.oid = oid;
1015 : 211 : dobj = findObjectByCatalogId(catId);
1016 [ + - - + ]: 211 : Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
1017 : 211 : return (ExtensionInfo *) dobj;
1018 : : }
1019 : :
1020 : : /*
1021 : : * findPublicationByOid
1022 : : * finds the DumpableObject for the publication with the given oid
1023 : : * returns NULL if not found
1024 : : */
1025 : : PublicationInfo *
1696 1026 : 529 : findPublicationByOid(Oid oid)
1027 : : {
1028 : : CatalogId catId;
1029 : : DumpableObject *dobj;
1030 : :
1415 1031 : 529 : catId.tableoid = PublicationRelationId;
1032 : 529 : catId.oid = oid;
1033 : 529 : dobj = findObjectByCatalogId(catId);
1034 [ + - - + ]: 529 : Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
1035 : 529 : return (PublicationInfo *) dobj;
1036 : : }
1037 : :
1038 : : /*
1039 : : * findSubscriptionByOid
1040 : : * finds the DumpableObject for the subscription with the given oid
1041 : : * returns NULL if not found
1042 : : */
1043 : : SubscriptionInfo *
613 akapila@postgresql.o 1044 : 2 : findSubscriptionByOid(Oid oid)
1045 : : {
1046 : : CatalogId catId;
1047 : : DumpableObject *dobj;
1048 : :
1049 : 2 : catId.tableoid = SubscriptionRelationId;
1050 : 2 : catId.oid = oid;
1051 : 2 : dobj = findObjectByCatalogId(catId);
1052 [ + - - + ]: 2 : Assert(dobj == NULL || dobj->objType == DO_SUBSCRIPTION);
1053 : 2 : return (SubscriptionInfo *) dobj;
1054 : : }
1055 : :
1056 : :
1057 : : /*
1058 : : * recordExtensionMembership
1059 : : * Record that the object identified by the given catalog ID
1060 : : * belongs to the given extension
1061 : : */
1062 : : void
1415 tgl@sss.pgh.pa.us 1063 : 1344 : recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
1064 : : {
1065 : : CatalogIdMapEntry *entry;
1066 : : bool found;
1067 : :
1068 : : /* CatalogId hash table must exist, if we have an ExtensionInfo */
1069 [ - + ]: 1344 : Assert(catalogIdHash != NULL);
1070 : :
1071 : : /* Add reference to CatalogId hash */
1072 : 1344 : entry = catalogid_insert(catalogIdHash, catId, &found);
1073 [ + - ]: 1344 : if (!found)
1074 : : {
1075 : 1344 : entry->dobj = NULL;
1076 : 1344 : entry->ext = NULL;
1077 : : }
1078 [ - + ]: 1344 : Assert(entry->ext == NULL);
1079 : 1344 : entry->ext = ext;
3524 1080 : 1344 : }
1081 : :
1082 : : /*
1083 : : * findOwningExtension
1084 : : * return owning extension for specified catalog ID, or NULL if none
1085 : : */
1086 : : ExtensionInfo *
1087 : 714407 : findOwningExtension(CatalogId catalogId)
1088 : : {
1089 : : CatalogIdMapEntry *entry;
1090 : :
1415 1091 [ - + ]: 714407 : if (catalogIdHash == NULL)
1415 tgl@sss.pgh.pa.us 1092 :UIC 0 : return NULL; /* no objects exist yet */
1093 : :
1415 tgl@sss.pgh.pa.us 1094 :GIC 714407 : entry = catalogid_lookup(catalogIdHash, catalogId);
1095 [ - + ]: 714407 : if (entry == NULL)
1415 tgl@sss.pgh.pa.us 1096 :UIC 0 : return NULL;
1415 tgl@sss.pgh.pa.us 1097 :GIC 714407 : return entry->ext;
1098 : : }
1099 : :
1100 : :
1101 : : /*
1102 : : * parseOidArray
1103 : : * parse a string of numbers delimited by spaces into a character array
1104 : : *
1105 : : * Note: actually this is used for both Oids and potentially-signed
1106 : : * attribute numbers. This should cause no trouble, but we could split
1107 : : * the function into two functions with different argument types if it does.
1108 : : */
1109 : :
1110 : : void
5033 bruce@momjian.us 1111 : 6762 : parseOidArray(const char *str, Oid *array, int arraysize)
1112 : : {
1113 : : int j,
1114 : : argNum;
1115 : : char temp[100];
1116 : : char s;
1117 : :
1118 : 6762 : argNum = 0;
1119 : 6762 : j = 0;
1120 : : for (;;)
1121 : : {
1122 : 31815 : s = *str++;
1123 [ + + + + ]: 31815 : if (s == ' ' || s == '\0')
1124 : : {
1125 [ + - ]: 10856 : if (j > 0)
1126 : : {
1127 [ - + ]: 10856 : if (argNum >= arraysize)
1247 tgl@sss.pgh.pa.us 1128 :UIC 0 : pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
5033 bruce@momjian.us 1129 :GIC 10856 : temp[j] = '\0';
1130 : 10856 : array[argNum++] = atooid(temp);
1131 : 10856 : j = 0;
1132 : : }
1133 [ + + ]: 10856 : if (s == '\0')
1134 : 6762 : break;
1135 : : }
1136 : : else
1137 : : {
1138 [ - + - - ]: 20959 : if (!(isdigit((unsigned char) s) || s == '-') ||
1139 [ - + ]: 20959 : j >= sizeof(temp) - 1)
1247 tgl@sss.pgh.pa.us 1140 :UIC 0 : pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
5033 bruce@momjian.us 1141 :GIC 20959 : temp[j++] = s;
1142 : : }
1143 : : }
1144 : :
1145 [ - + ]: 6762 : while (argNum < arraysize)
5033 bruce@momjian.us 1146 :UIC 0 : array[argNum++] = InvalidOid;
5033 bruce@momjian.us 1147 :GIC 6762 : }
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 : 4802 : strInArray(const char *pattern, char **arr, int arr_size)
1159 : : {
1160 : : int i;
1161 : :
1162 [ + + ]: 9427 : for (i = 0; i < arr_size; i++)
1163 : : {
1164 [ + + ]: 9187 : if (strcmp(pattern, arr[i]) == 0)
1165 : 4562 : return i;
1166 : : }
1167 : 240 : return -1;
1168 : : }
|