~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/bin/pg_dump/common.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * common.c
 
4
 *        common routines between pg_dump and pg4_dump
 
5
 *
 
6
 * Since pg4_dump is long-dead code, there is no longer any useful distinction
 
7
 * between this file and pg_dump.c.
 
8
 *
 
9
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
10
 * Portions Copyright (c) 1994, Regents of the University of California
 
11
 *
 
12
 *
 
13
 * IDENTIFICATION
 
14
 *        $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.85 2004-12-31 22:03:07 pgsql Exp $
 
15
 *
 
16
 *-------------------------------------------------------------------------
 
17
 */
 
18
 
 
19
#include "postgres_fe.h"
 
20
#include "pg_dump.h"
 
21
#include "pg_backup_archiver.h"
 
22
 
 
23
#include "postgres.h"
 
24
#include "catalog/pg_class.h"
 
25
 
 
26
#include <ctype.h>
 
27
 
 
28
#include "libpq-fe.h"
 
29
#ifndef HAVE_STRDUP
 
30
#include "strdup.h"
 
31
#endif
 
32
 
 
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;
 
40
 
 
41
/*
 
42
 * Variables for mapping CatalogId to DumpableObject
 
43
 */
 
44
static bool catalogIdMapValid = false;
 
45
static DumpableObject **catalogIdMap = NULL;
 
46
static int      numCatalogIds = 0;
 
47
 
 
48
/*
 
49
 * These variables are static to avoid the notational cruft of having to pass
 
50
 * them into findTableByOid() and friends.
 
51
 */
 
52
static TableInfo *tblinfo;
 
53
static TypeInfo *typinfo;
 
54
static FuncInfo *funinfo;
 
55
static OprInfo *oprinfo;
 
56
static int      numTables;
 
57
static int      numTypes;
 
58
static int      numFuncs;
 
59
static int      numOperators;
 
60
 
 
61
 
 
62
static void flagInhTables(TableInfo *tbinfo, int numTables,
 
63
                          InhInfo *inhinfo, int numInherits);
 
64
static void flagInhAttrs(TableInfo *tbinfo, int numTables,
 
65
                         InhInfo *inhinfo, int numInherits);
 
66
static int      DOCatalogIdCompare(const void *p1, const void *p2);
 
67
static void findParentsByOid(TableInfo *self,
 
68
                                 InhInfo *inhinfo, int numInherits);
 
69
static int      strInArray(const char *pattern, char **arr, int arr_size);
 
70
 
 
71
 
 
72
/*
 
73
 * getSchemaData
 
74
 *        Collect information about all potentially dumpable objects
 
75
 */
 
76
TableInfo *
 
77
getSchemaData(int *numTablesPtr,
 
78
                          const bool schemaOnly,
 
79
                          const bool dataOnly)
 
80
{
 
81
        NamespaceInfo *nsinfo;
 
82
        AggInfo    *agginfo;
 
83
        InhInfo    *inhinfo;
 
84
        RuleInfo   *ruleinfo;
 
85
        ProcLangInfo *proclanginfo;
 
86
        CastInfo   *castinfo;
 
87
        OpclassInfo *opcinfo;
 
88
        ConvInfo   *convinfo;
 
89
        int                     numNamespaces;
 
90
        int                     numAggregates;
 
91
        int                     numInherits;
 
92
        int                     numRules;
 
93
        int                     numProcLangs;
 
94
        int                     numCasts;
 
95
        int                     numOpclasses;
 
96
        int                     numConversions;
 
97
 
 
98
        if (g_verbose)
 
99
                write_msg(NULL, "reading schemas\n");
 
100
        nsinfo = getNamespaces(&numNamespaces);
 
101
 
 
102
        if (g_verbose)
 
103
                write_msg(NULL, "reading user-defined functions\n");
 
104
        funinfo = getFuncs(&numFuncs);
 
105
 
 
106
        /* this must be after getFuncs */
 
107
        if (g_verbose)
 
108
                write_msg(NULL, "reading user-defined types\n");
 
109
        typinfo = getTypes(&numTypes);
 
110
 
 
111
        /* this must be after getFuncs, too */
 
112
        if (g_verbose)
 
113
                write_msg(NULL, "reading procedural languages\n");
 
114
        proclanginfo = getProcLangs(&numProcLangs);
 
115
 
 
116
        if (g_verbose)
 
117
                write_msg(NULL, "reading user-defined aggregate functions\n");
 
118
        agginfo = getAggregates(&numAggregates);
 
119
 
 
120
        if (g_verbose)
 
121
                write_msg(NULL, "reading user-defined operators\n");
 
122
        oprinfo = getOperators(&numOperators);
 
123
 
 
124
        if (g_verbose)
 
125
                write_msg(NULL, "reading user-defined operator classes\n");
 
126
        opcinfo = getOpclasses(&numOpclasses);
 
127
 
 
128
        if (g_verbose)
 
129
                write_msg(NULL, "reading user-defined conversions\n");
 
130
        convinfo = getConversions(&numConversions);
 
131
 
 
132
        if (g_verbose)
 
133
                write_msg(NULL, "reading user-defined tables\n");
 
134
        tblinfo = getTables(&numTables);
 
135
 
 
136
        if (g_verbose)
 
137
                write_msg(NULL, "reading table inheritance information\n");
 
138
        inhinfo = getInherits(&numInherits);
 
139
 
 
140
        if (g_verbose)
 
141
                write_msg(NULL, "reading rewrite rules\n");
 
142
        ruleinfo = getRules(&numRules);
 
143
 
 
144
        if (g_verbose)
 
145
                write_msg(NULL, "reading type casts\n");
 
146
        castinfo = getCasts(&numCasts);
 
147
 
 
148
        /* Link tables to parents, mark parents of target tables interesting */
 
149
        if (g_verbose)
 
150
                write_msg(NULL, "finding inheritance relationships\n");
 
151
        flagInhTables(tblinfo, numTables, inhinfo, numInherits);
 
152
 
 
153
        if (g_verbose)
 
154
                write_msg(NULL, "reading column info for interesting tables\n");
 
155
        getTableAttrs(tblinfo, numTables);
 
156
 
 
157
        if (g_verbose)
 
158
                write_msg(NULL, "flagging inherited columns in subtables\n");
 
159
        flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
 
160
 
 
161
        if (g_verbose)
 
162
                write_msg(NULL, "reading indexes\n");
 
163
        getIndexes(tblinfo, numTables);
 
164
 
 
165
        if (g_verbose)
 
166
                write_msg(NULL, "reading constraints\n");
 
167
        getConstraints(tblinfo, numTables);
 
168
 
 
169
        if (g_verbose)
 
170
                write_msg(NULL, "reading triggers\n");
 
171
        getTriggers(tblinfo, numTables);
 
172
 
 
173
        *numTablesPtr = numTables;
 
174
        return tblinfo;
 
175
}
 
176
 
 
177
/* flagInhTables -
 
178
 *       Fill in parent link fields of every target table, and mark
 
179
 *       parents of target tables as interesting
 
180
 *
 
181
 * Note that only direct ancestors of targets are marked interesting.
 
182
 * This is sufficient; we don't much care whether they inherited their
 
183
 * attributes or not.
 
184
 *
 
185
 * modifies tblinfo
 
186
 */
 
187
static void
 
188
flagInhTables(TableInfo *tblinfo, int numTables,
 
189
                          InhInfo *inhinfo, int numInherits)
 
190
{
 
191
        int                     i,
 
192
                                j;
 
193
        int                     numParents;
 
194
        TableInfo **parents;
 
195
 
 
196
        for (i = 0; i < numTables; i++)
 
197
        {
 
198
                /* Sequences and views never have parents */
 
199
                if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
 
200
                        tblinfo[i].relkind == RELKIND_VIEW)
 
201
                        continue;
 
202
 
 
203
                /* Don't bother computing anything for non-target tables, either */
 
204
                if (!tblinfo[i].dump)
 
205
                        continue;
 
206
 
 
207
                /* Find all the immediate parent tables */
 
208
                findParentsByOid(&tblinfo[i], inhinfo, numInherits);
 
209
 
 
210
                /* Mark the parents as interesting for getTableAttrs */
 
211
                numParents = tblinfo[i].numParents;
 
212
                parents = tblinfo[i].parents;
 
213
                for (j = 0; j < numParents; j++)
 
214
                        parents[j]->interesting = true;
 
215
        }
 
216
}
 
217
 
 
218
/* flagInhAttrs -
 
219
 *       for each dumpable table in tblinfo, flag its inherited attributes
 
220
 * so when we dump the table out, we don't dump out the inherited attributes
 
221
 *
 
222
 * modifies tblinfo
 
223
 */
 
224
static void
 
225
flagInhAttrs(TableInfo *tblinfo, int numTables,
 
226
                         InhInfo *inhinfo, int numInherits)
 
227
{
 
228
        int                     i,
 
229
                                j,
 
230
                                k;
 
231
 
 
232
        for (i = 0; i < numTables; i++)
 
233
        {
 
234
                TableInfo  *tbinfo = &(tblinfo[i]);
 
235
                int                     numParents;
 
236
                TableInfo **parents;
 
237
                TableInfo  *parent;
 
238
 
 
239
                /* Sequences and views never have parents */
 
240
                if (tbinfo->relkind == RELKIND_SEQUENCE ||
 
241
                        tbinfo->relkind == RELKIND_VIEW)
 
242
                        continue;
 
243
 
 
244
                /* Don't bother computing anything for non-target tables, either */
 
245
                if (!tbinfo->dump)
 
246
                        continue;
 
247
 
 
248
                numParents = tbinfo->numParents;
 
249
                parents = tbinfo->parents;
 
250
 
 
251
                if (numParents == 0)
 
252
                        continue;                       /* nothing to see here, move along */
 
253
 
 
254
                /*----------------------------------------------------------------
 
255
                 * For each attr, check the parent info: if no parent has an attr
 
256
                 * with the same name, then it's not inherited. If there *is* an
 
257
                 * attr with the same name, then only dump it if:
 
258
                 *
 
259
                 * - it is NOT NULL and zero parents are NOT NULL
 
260
                 *       OR
 
261
                 * - it has a default value AND the default value does not match
 
262
                 *       all parent default values, or no parents specify a default.
 
263
                 *
 
264
                 * See discussion on -hackers around 2-Apr-2001.
 
265
                 *----------------------------------------------------------------
 
266
                 */
 
267
                for (j = 0; j < tbinfo->numatts; j++)
 
268
                {
 
269
                        bool            foundAttr;              /* Attr was found in a parent */
 
270
                        bool            foundNotNull;   /* Attr was NOT NULL in a parent */
 
271
                        bool            defaultsMatch;  /* All non-empty defaults match */
 
272
                        bool            defaultsFound;  /* Found a default in a parent */
 
273
                        AttrDefInfo *attrDef;
 
274
 
 
275
                        foundAttr = false;
 
276
                        foundNotNull = false;
 
277
                        defaultsMatch = true;
 
278
                        defaultsFound = false;
 
279
 
 
280
                        attrDef = tbinfo->attrdefs[j];
 
281
 
 
282
                        for (k = 0; k < numParents; k++)
 
283
                        {
 
284
                                int                     inhAttrInd;
 
285
 
 
286
                                parent = parents[k];
 
287
                                inhAttrInd = strInArray(tbinfo->attnames[j],
 
288
                                                                                parent->attnames,
 
289
                                                                                parent->numatts);
 
290
 
 
291
                                if (inhAttrInd != -1)
 
292
                                {
 
293
                                        foundAttr = true;
 
294
                                        foundNotNull |= parent->notnull[inhAttrInd];
 
295
                                        if (attrDef != NULL)            /* If we have a default,
 
296
                                                                                                 * check parent */
 
297
                                        {
 
298
                                                AttrDefInfo *inhDef;
 
299
 
 
300
                                                inhDef = parent->attrdefs[inhAttrInd];
 
301
                                                if (inhDef != NULL)
 
302
                                                {
 
303
                                                        defaultsFound = true;
 
304
                                                        defaultsMatch &= (strcmp(attrDef->adef_expr,
 
305
                                                                                                inhDef->adef_expr) == 0);
 
306
                                                }
 
307
                                        }
 
308
                                }
 
309
                        }
 
310
 
 
311
                        /*
 
312
                         * Based on the scan of the parents, decide if we can rely on
 
313
                         * the inherited attr
 
314
                         */
 
315
                        if (foundAttr)          /* Attr was inherited */
 
316
                        {
 
317
                                /* Set inherited flag by default */
 
318
                                tbinfo->inhAttrs[j] = true;
 
319
                                tbinfo->inhAttrDef[j] = true;
 
320
                                tbinfo->inhNotNull[j] = true;
 
321
 
 
322
                                /*
 
323
                                 * Clear it if attr had a default, but parents did not, or
 
324
                                 * mismatch
 
325
                                 */
 
326
                                if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
 
327
                                {
 
328
                                        tbinfo->inhAttrs[j] = false;
 
329
                                        tbinfo->inhAttrDef[j] = false;
 
330
                                }
 
331
 
 
332
                                /*
 
333
                                 * Clear it if NOT NULL and none of the parents were NOT
 
334
                                 * NULL
 
335
                                 */
 
336
                                if (tbinfo->notnull[j] && !foundNotNull)
 
337
                                {
 
338
                                        tbinfo->inhAttrs[j] = false;
 
339
                                        tbinfo->inhNotNull[j] = false;
 
340
                                }
 
341
 
 
342
                                /* Clear it if attr has local definition */
 
343
                                if (tbinfo->attislocal[j])
 
344
                                        tbinfo->inhAttrs[j] = false;
 
345
                        }
 
346
                }
 
347
 
 
348
                /*
 
349
                 * Check for inherited CHECK constraints.  We assume a constraint
 
350
                 * is inherited if its expression matches the parent and the name
 
351
                 * is the same, *or* both names start with '$'.
 
352
                 */
 
353
                for (j = 0; j < tbinfo->ncheck; j++)
 
354
                {
 
355
                        ConstraintInfo *constr;
 
356
 
 
357
                        constr = &(tbinfo->checkexprs[j]);
 
358
 
 
359
                        for (k = 0; k < numParents; k++)
 
360
                        {
 
361
                                int                     l;
 
362
 
 
363
                                parent = parents[k];
 
364
                                for (l = 0; l < parent->ncheck; l++)
 
365
                                {
 
366
                                        ConstraintInfo *pconstr;
 
367
 
 
368
                                        pconstr = &(parent->checkexprs[l]);
 
369
                                        if (strcmp(pconstr->condef, constr->condef) != 0)
 
370
                                                continue;
 
371
                                        if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0 ||
 
372
                                                (pconstr->dobj.name[0] == '$' &&
 
373
                                                 constr->dobj.name[0] == '$'))
 
374
                                        {
 
375
                                                constr->coninherited = true;
 
376
                                                break;
 
377
                                        }
 
378
                                }
 
379
                                if (constr->coninherited)
 
380
                                        break;
 
381
                        }
 
382
                }
 
383
        }
 
384
}
 
385
 
 
386
/*
 
387
 * AssignDumpId
 
388
 *              Given a newly-created dumpable object, assign a dump ID,
 
389
 *              and enter the object into the lookup table.
 
390
 *
 
391
 * The caller is expected to have filled in objType and catalogId,
 
392
 * but not any of the other standard fields of a DumpableObject.
 
393
 */
 
394
void
 
395
AssignDumpId(DumpableObject *dobj)
 
396
{
 
397
        dobj->dumpId = ++lastDumpId;
 
398
        dobj->name = NULL;                      /* must be set later */
 
399
        dobj->namespace = NULL;         /* may be set later */
 
400
        dobj->dependencies = NULL;
 
401
        dobj->nDeps = 0;
 
402
        dobj->allocDeps = 0;
 
403
 
 
404
        while (dobj->dumpId >= allocedDumpIds)
 
405
        {
 
406
                int                     newAlloc;
 
407
 
 
408
                if (allocedDumpIds <= 0)
 
409
                {
 
410
                        newAlloc = 256;
 
411
                        dumpIdMap = (DumpableObject **)
 
412
                                malloc(newAlloc * sizeof(DumpableObject *));
 
413
                }
 
414
                else
 
415
                {
 
416
                        newAlloc = allocedDumpIds * 2;
 
417
                        dumpIdMap = (DumpableObject **)
 
418
                                realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
 
419
                }
 
420
                if (dumpIdMap == NULL)
 
421
                        exit_horribly(NULL, NULL, "out of memory\n");
 
422
                memset(dumpIdMap + allocedDumpIds, 0,
 
423
                           (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
 
424
                allocedDumpIds = newAlloc;
 
425
        }
 
426
        dumpIdMap[dobj->dumpId] = dobj;
 
427
 
 
428
        /* mark catalogIdMap invalid, but don't rebuild it yet */
 
429
        catalogIdMapValid = false;
 
430
}
 
431
 
 
432
/*
 
433
 * Assign a DumpId that's not tied to a DumpableObject.
 
434
 *
 
435
 * This is used when creating a "fixed" ArchiveEntry that doesn't need to
 
436
 * participate in the sorting logic.
 
437
 */
 
438
DumpId
 
439
createDumpId(void)
 
440
{
 
441
        return ++lastDumpId;
 
442
}
 
443
 
 
444
/*
 
445
 * Return the largest DumpId so far assigned
 
446
 */
 
447
DumpId
 
448
getMaxDumpId(void)
 
449
{
 
450
        return lastDumpId;
 
451
}
 
452
 
 
453
/*
 
454
 * Find a DumpableObject by dump ID
 
455
 *
 
456
 * Returns NULL for invalid ID
 
457
 */
 
458
DumpableObject *
 
459
findObjectByDumpId(DumpId dumpId)
 
460
{
 
461
        if (dumpId <= 0 || dumpId >= allocedDumpIds)
 
462
                return NULL;                    /* out of range? */
 
463
        return dumpIdMap[dumpId];
 
464
}
 
465
 
 
466
/*
 
467
 * Find a DumpableObject by catalog ID
 
468
 *
 
469
 * Returns NULL for unknown ID
 
470
 *
 
471
 * We use binary search in a sorted list that is built on first call.
 
472
 * If AssignDumpId() and findObjectByCatalogId() calls were intermixed,
 
473
 * the code would work, but possibly be very slow.      In the current usage
 
474
 * pattern that does not happen, indeed we only need to build the list once.
 
475
 */
 
476
DumpableObject *
 
477
findObjectByCatalogId(CatalogId catalogId)
 
478
{
 
479
        DumpableObject **low;
 
480
        DumpableObject **high;
 
481
 
 
482
        if (!catalogIdMapValid)
 
483
        {
 
484
                if (catalogIdMap)
 
485
                        free(catalogIdMap);
 
486
                getDumpableObjects(&catalogIdMap, &numCatalogIds);
 
487
                if (numCatalogIds > 1)
 
488
                        qsort((void *) catalogIdMap, numCatalogIds,
 
489
                                  sizeof(DumpableObject *), DOCatalogIdCompare);
 
490
                catalogIdMapValid = true;
 
491
        }
 
492
 
 
493
        /*
 
494
         * We could use bsearch() here, but the notational cruft of calling
 
495
         * bsearch is nearly as bad as doing it ourselves; and the generalized
 
496
         * bsearch function is noticeably slower as well.
 
497
         */
 
498
        if (numCatalogIds <= 0)
 
499
                return NULL;
 
500
        low = catalogIdMap;
 
501
        high = catalogIdMap + (numCatalogIds - 1);
 
502
        while (low <= high)
 
503
        {
 
504
                DumpableObject **middle;
 
505
                int                     difference;
 
506
 
 
507
                middle = low + (high - low) / 2;
 
508
                /* comparison must match DOCatalogIdCompare, below */
 
509
                difference = oidcmp((*middle)->catId.oid, catalogId.oid);
 
510
                if (difference == 0)
 
511
                        difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
 
512
                if (difference == 0)
 
513
                        return *middle;
 
514
                else if (difference < 0)
 
515
                        low = middle + 1;
 
516
                else
 
517
                        high = middle - 1;
 
518
        }
 
519
        return NULL;
 
520
}
 
521
 
 
522
static int
 
523
DOCatalogIdCompare(const void *p1, const void *p2)
 
524
{
 
525
        DumpableObject *obj1 = *(DumpableObject **) p1;
 
526
        DumpableObject *obj2 = *(DumpableObject **) p2;
 
527
        int                     cmpval;
 
528
 
 
529
        /*
 
530
         * Compare OID first since it's usually unique, whereas there will
 
531
         * only be a few distinct values of tableoid.
 
532
         */
 
533
        cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
 
534
        if (cmpval == 0)
 
535
                cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
 
536
        return cmpval;
 
537
}
 
538
 
 
539
/*
 
540
 * Build an array of pointers to all known dumpable objects
 
541
 *
 
542
 * This simply creates a modifiable copy of the internal map.
 
543
 */
 
544
void
 
545
getDumpableObjects(DumpableObject ***objs, int *numObjs)
 
546
{
 
547
        int                     i,
 
548
                                j;
 
549
 
 
550
        *objs = (DumpableObject **)
 
551
                malloc(allocedDumpIds * sizeof(DumpableObject *));
 
552
        if (*objs == NULL)
 
553
                exit_horribly(NULL, NULL, "out of memory\n");
 
554
        j = 0;
 
555
        for (i = 1; i < allocedDumpIds; i++)
 
556
        {
 
557
                if (dumpIdMap[i])
 
558
                        (*objs)[j++] = dumpIdMap[i];
 
559
        }
 
560
        *numObjs = j;
 
561
}
 
562
 
 
563
/*
 
564
 * Add a dependency link to a DumpableObject
 
565
 *
 
566
 * Note: duplicate dependencies are currently not eliminated
 
567
 */
 
568
void
 
569
addObjectDependency(DumpableObject *dobj, DumpId refId)
 
570
{
 
571
        if (dobj->nDeps >= dobj->allocDeps)
 
572
        {
 
573
                if (dobj->allocDeps <= 0)
 
574
                {
 
575
                        dobj->allocDeps = 16;
 
576
                        dobj->dependencies = (DumpId *)
 
577
                                malloc(dobj->allocDeps * sizeof(DumpId));
 
578
                }
 
579
                else
 
580
                {
 
581
                        dobj->allocDeps *= 2;
 
582
                        dobj->dependencies = (DumpId *)
 
583
                                realloc(dobj->dependencies,
 
584
                                                dobj->allocDeps * sizeof(DumpId));
 
585
                }
 
586
                if (dobj->dependencies == NULL)
 
587
                        exit_horribly(NULL, NULL, "out of memory\n");
 
588
        }
 
589
        dobj->dependencies[dobj->nDeps++] = refId;
 
590
}
 
591
 
 
592
/*
 
593
 * Remove a dependency link from a DumpableObject
 
594
 *
 
595
 * If there are multiple links, all are removed
 
596
 */
 
597
void
 
598
removeObjectDependency(DumpableObject *dobj, DumpId refId)
 
599
{
 
600
        int                     i;
 
601
        int                     j = 0;
 
602
 
 
603
        for (i = 0; i < dobj->nDeps; i++)
 
604
        {
 
605
                if (dobj->dependencies[i] != refId)
 
606
                        dobj->dependencies[j++] = dobj->dependencies[i];
 
607
        }
 
608
        dobj->nDeps = j;
 
609
}
 
610
 
 
611
 
 
612
/*
 
613
 * findTableByOid
 
614
 *        finds the entry (in tblinfo) of the table with the given oid
 
615
 *        returns NULL if not found
 
616
 *
 
617
 * NOTE:  should hash this, but just do linear search for now
 
618
 */
 
619
TableInfo *
 
620
findTableByOid(Oid oid)
 
621
{
 
622
        int                     i;
 
623
 
 
624
        for (i = 0; i < numTables; i++)
 
625
        {
 
626
                if (tblinfo[i].dobj.catId.oid == oid)
 
627
                        return &tblinfo[i];
 
628
        }
 
629
        return NULL;
 
630
}
 
631
 
 
632
/*
 
633
 * findTypeByOid
 
634
 *        finds the entry (in typinfo) of the type with the given oid
 
635
 *        returns NULL if not found
 
636
 *
 
637
 * NOTE:  should hash this, but just do linear search for now
 
638
 */
 
639
TypeInfo *
 
640
findTypeByOid(Oid oid)
 
641
{
 
642
        int                     i;
 
643
 
 
644
        for (i = 0; i < numTypes; i++)
 
645
        {
 
646
                if (typinfo[i].dobj.catId.oid == oid)
 
647
                        return &typinfo[i];
 
648
        }
 
649
        return NULL;
 
650
}
 
651
 
 
652
/*
 
653
 * findFuncByOid
 
654
 *        finds the entry (in funinfo) of the function with the given oid
 
655
 *        returns NULL if not found
 
656
 *
 
657
 * NOTE:  should hash this, but just do linear search for now
 
658
 */
 
659
FuncInfo *
 
660
findFuncByOid(Oid oid)
 
661
{
 
662
        int                     i;
 
663
 
 
664
        for (i = 0; i < numFuncs; i++)
 
665
        {
 
666
                if (funinfo[i].dobj.catId.oid == oid)
 
667
                        return &funinfo[i];
 
668
        }
 
669
        return NULL;
 
670
}
 
671
 
 
672
/*
 
673
 * findOprByOid
 
674
 *        finds the entry (in oprinfo) of the operator with the given oid
 
675
 *        returns NULL if not found
 
676
 *
 
677
 * NOTE:  should hash this, but just do linear search for now
 
678
 */
 
679
OprInfo *
 
680
findOprByOid(Oid oid)
 
681
{
 
682
        int                     i;
 
683
 
 
684
        for (i = 0; i < numOperators; i++)
 
685
        {
 
686
                if (oprinfo[i].dobj.catId.oid == oid)
 
687
                        return &oprinfo[i];
 
688
        }
 
689
        return NULL;
 
690
}
 
691
 
 
692
 
 
693
/*
 
694
 * findParentsByOid
 
695
 *        find a table's parents in tblinfo[]
 
696
 */
 
697
static void
 
698
findParentsByOid(TableInfo *self,
 
699
                                 InhInfo *inhinfo, int numInherits)
 
700
{
 
701
        Oid                     oid = self->dobj.catId.oid;
 
702
        int                     i,
 
703
                                j;
 
704
        int                     numParents;
 
705
 
 
706
        numParents = 0;
 
707
        for (i = 0; i < numInherits; i++)
 
708
        {
 
709
                if (inhinfo[i].inhrelid == oid)
 
710
                        numParents++;
 
711
        }
 
712
 
 
713
        self->numParents = numParents;
 
714
 
 
715
        if (numParents > 0)
 
716
        {
 
717
                self->parents = (TableInfo **) malloc(sizeof(TableInfo *) * numParents);
 
718
                j = 0;
 
719
                for (i = 0; i < numInherits; i++)
 
720
                {
 
721
                        if (inhinfo[i].inhrelid == oid)
 
722
                        {
 
723
                                TableInfo  *parent;
 
724
 
 
725
                                parent = findTableByOid(inhinfo[i].inhparent);
 
726
                                if (parent == NULL)
 
727
                                {
 
728
                                        write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
 
729
                                                          inhinfo[i].inhparent,
 
730
                                                          self->dobj.name,
 
731
                                                          oid);
 
732
                                        exit_nicely();
 
733
                                }
 
734
                                self->parents[j++] = parent;
 
735
                        }
 
736
                }
 
737
        }
 
738
        else
 
739
                self->parents = NULL;
 
740
}
 
741
 
 
742
/*
 
743
 * parseOidArray
 
744
 *        parse a string of numbers delimited by spaces into a character array
 
745
 *
 
746
 * Note: actually this is used for both Oids and potentially-signed
 
747
 * attribute numbers.  This should cause no trouble, but we could split
 
748
 * the function into two functions with different argument types if it does.
 
749
 */
 
750
 
 
751
void
 
752
parseOidArray(const char *str, Oid *array, int arraysize)
 
753
{
 
754
        int                     j,
 
755
                                argNum;
 
756
        char            temp[100];
 
757
        char            s;
 
758
 
 
759
        argNum = 0;
 
760
        j = 0;
 
761
        for (;;)
 
762
        {
 
763
                s = *str++;
 
764
                if (s == ' ' || s == '\0')
 
765
                {
 
766
                        if (j > 0)
 
767
                        {
 
768
                                if (argNum >= arraysize)
 
769
                                {
 
770
                                        write_msg(NULL, "could not parse numeric array: too many numbers\n");
 
771
                                        exit_nicely();
 
772
                                }
 
773
                                temp[j] = '\0';
 
774
                                array[argNum++] = atooid(temp);
 
775
                                j = 0;
 
776
                        }
 
777
                        if (s == '\0')
 
778
                                break;
 
779
                }
 
780
                else
 
781
                {
 
782
                        if (!(isdigit((unsigned char) s) || s == '-') ||
 
783
                                j >= sizeof(temp) - 1)
 
784
                        {
 
785
                                write_msg(NULL, "could not parse numeric array: invalid character in number\n");
 
786
                                exit_nicely();
 
787
                        }
 
788
                        temp[j++] = s;
 
789
                }
 
790
        }
 
791
 
 
792
        while (argNum < arraysize)
 
793
                array[argNum++] = InvalidOid;
 
794
}
 
795
 
 
796
 
 
797
/*
 
798
 * strInArray:
 
799
 *        takes in a string and a string array and the number of elements in the
 
800
 * string array.
 
801
 *        returns the index if the string is somewhere in the array, -1 otherwise
 
802
 */
 
803
 
 
804
static int
 
805
strInArray(const char *pattern, char **arr, int arr_size)
 
806
{
 
807
        int                     i;
 
808
 
 
809
        for (i = 0; i < arr_size; i++)
 
810
        {
 
811
                if (strcmp(pattern, arr[i]) == 0)
 
812
                        return i;
 
813
        }
 
814
        return -1;
 
815
}