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