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