00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "pg_backup_archiver.h"
00017 #include "pg_backup_utils.h"
00018
00019 #include <ctype.h>
00020
00021 #include "catalog/pg_class.h"
00022
00023
00024
00025
00026
00027 static DumpableObject **dumpIdMap = NULL;
00028 static int allocedDumpIds = 0;
00029 static DumpId lastDumpId = 0;
00030
00031
00032
00033
00034 static bool catalogIdMapValid = false;
00035 static DumpableObject **catalogIdMap = NULL;
00036 static int numCatalogIds = 0;
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 static TableInfo *tblinfo;
00047 static TypeInfo *typinfo;
00048 static FuncInfo *funinfo;
00049 static OprInfo *oprinfo;
00050 static NamespaceInfo *nspinfo;
00051 static int numTables;
00052 static int numTypes;
00053 static int numFuncs;
00054 static int numOperators;
00055 static int numCollations;
00056 static int numNamespaces;
00057 static DumpableObject **tblinfoindex;
00058 static DumpableObject **typinfoindex;
00059 static DumpableObject **funinfoindex;
00060 static DumpableObject **oprinfoindex;
00061 static DumpableObject **collinfoindex;
00062 static DumpableObject **nspinfoindex;
00063
00064
00065 static void flagInhTables(TableInfo *tbinfo, int numTables,
00066 InhInfo *inhinfo, int numInherits);
00067 static void flagInhAttrs(TableInfo *tblinfo, int numTables);
00068 static DumpableObject **buildIndexArray(void *objArray, int numObjs,
00069 Size objSize);
00070 static int DOCatalogIdCompare(const void *p1, const void *p2);
00071 static void findParentsByOid(TableInfo *self,
00072 InhInfo *inhinfo, int numInherits);
00073 static int strInArray(const char *pattern, char **arr, int arr_size);
00074
00075
00076
00077
00078
00079
00080 TableInfo *
00081 getSchemaData(Archive *fout, int *numTablesPtr)
00082 {
00083 ExtensionInfo *extinfo;
00084 InhInfo *inhinfo;
00085 CollInfo *collinfo;
00086 int numExtensions;
00087 int numAggregates;
00088 int numInherits;
00089 int numRules;
00090 int numProcLangs;
00091 int numCasts;
00092 int numOpclasses;
00093 int numOpfamilies;
00094 int numConversions;
00095 int numTSParsers;
00096 int numTSTemplates;
00097 int numTSDicts;
00098 int numTSConfigs;
00099 int numForeignDataWrappers;
00100 int numForeignServers;
00101 int numDefaultACLs;
00102 int numEventTriggers;
00103
00104 if (g_verbose)
00105 write_msg(NULL, "reading schemas\n");
00106 nspinfo = getNamespaces(fout, &numNamespaces);
00107 nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
00108
00109
00110
00111
00112
00113
00114
00115 if (g_verbose)
00116 write_msg(NULL, "reading user-defined tables\n");
00117 tblinfo = getTables(fout, &numTables);
00118 tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
00119
00120
00121 getOwnedSeqs(fout, tblinfo, numTables);
00122
00123 if (g_verbose)
00124 write_msg(NULL, "reading extensions\n");
00125 extinfo = getExtensions(fout, &numExtensions);
00126
00127 if (g_verbose)
00128 write_msg(NULL, "reading user-defined functions\n");
00129 funinfo = getFuncs(fout, &numFuncs);
00130 funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
00131
00132
00133 if (g_verbose)
00134 write_msg(NULL, "reading user-defined types\n");
00135 typinfo = getTypes(fout, &numTypes);
00136 typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
00137
00138
00139 if (g_verbose)
00140 write_msg(NULL, "reading procedural languages\n");
00141 getProcLangs(fout, &numProcLangs);
00142
00143 if (g_verbose)
00144 write_msg(NULL, "reading user-defined aggregate functions\n");
00145 getAggregates(fout, &numAggregates);
00146
00147 if (g_verbose)
00148 write_msg(NULL, "reading user-defined operators\n");
00149 oprinfo = getOperators(fout, &numOperators);
00150 oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
00151
00152 if (g_verbose)
00153 write_msg(NULL, "reading user-defined operator classes\n");
00154 getOpclasses(fout, &numOpclasses);
00155
00156 if (g_verbose)
00157 write_msg(NULL, "reading user-defined operator families\n");
00158 getOpfamilies(fout, &numOpfamilies);
00159
00160 if (g_verbose)
00161 write_msg(NULL, "reading user-defined text search parsers\n");
00162 getTSParsers(fout, &numTSParsers);
00163
00164 if (g_verbose)
00165 write_msg(NULL, "reading user-defined text search templates\n");
00166 getTSTemplates(fout, &numTSTemplates);
00167
00168 if (g_verbose)
00169 write_msg(NULL, "reading user-defined text search dictionaries\n");
00170 getTSDictionaries(fout, &numTSDicts);
00171
00172 if (g_verbose)
00173 write_msg(NULL, "reading user-defined text search configurations\n");
00174 getTSConfigurations(fout, &numTSConfigs);
00175
00176 if (g_verbose)
00177 write_msg(NULL, "reading user-defined foreign-data wrappers\n");
00178 getForeignDataWrappers(fout, &numForeignDataWrappers);
00179
00180 if (g_verbose)
00181 write_msg(NULL, "reading user-defined foreign servers\n");
00182 getForeignServers(fout, &numForeignServers);
00183
00184 if (g_verbose)
00185 write_msg(NULL, "reading default privileges\n");
00186 getDefaultACLs(fout, &numDefaultACLs);
00187
00188 if (g_verbose)
00189 write_msg(NULL, "reading user-defined collations\n");
00190 collinfo = getCollations(fout, &numCollations);
00191 collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
00192
00193 if (g_verbose)
00194 write_msg(NULL, "reading user-defined conversions\n");
00195 getConversions(fout, &numConversions);
00196
00197 if (g_verbose)
00198 write_msg(NULL, "reading type casts\n");
00199 getCasts(fout, &numCasts);
00200
00201 if (g_verbose)
00202 write_msg(NULL, "reading table inheritance information\n");
00203 inhinfo = getInherits(fout, &numInherits);
00204
00205 if (g_verbose)
00206 write_msg(NULL, "reading rewrite rules\n");
00207 getRules(fout, &numRules);
00208
00209
00210
00211
00212
00213
00214 if (g_verbose)
00215 write_msg(NULL, "finding extension members\n");
00216 getExtensionMembership(fout, extinfo, numExtensions);
00217
00218
00219 if (g_verbose)
00220 write_msg(NULL, "finding inheritance relationships\n");
00221 flagInhTables(tblinfo, numTables, inhinfo, numInherits);
00222
00223 if (g_verbose)
00224 write_msg(NULL, "reading column info for interesting tables\n");
00225 getTableAttrs(fout, tblinfo, numTables);
00226
00227 if (g_verbose)
00228 write_msg(NULL, "flagging inherited columns in subtables\n");
00229 flagInhAttrs(tblinfo, numTables);
00230
00231 if (g_verbose)
00232 write_msg(NULL, "reading indexes\n");
00233 getIndexes(fout, tblinfo, numTables);
00234
00235 if (g_verbose)
00236 write_msg(NULL, "reading constraints\n");
00237 getConstraints(fout, tblinfo, numTables);
00238
00239 if (g_verbose)
00240 write_msg(NULL, "reading triggers\n");
00241 getTriggers(fout, tblinfo, numTables);
00242
00243 if (g_verbose)
00244 write_msg(NULL, "reading event triggers\n");
00245 getEventTriggers(fout, &numEventTriggers);
00246
00247 *numTablesPtr = numTables;
00248 return tblinfo;
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 static void
00262 flagInhTables(TableInfo *tblinfo, int numTables,
00263 InhInfo *inhinfo, int numInherits)
00264 {
00265 int i,
00266 j;
00267 int numParents;
00268 TableInfo **parents;
00269
00270 for (i = 0; i < numTables; i++)
00271 {
00272
00273 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
00274 tblinfo[i].relkind == RELKIND_VIEW ||
00275 tblinfo[i].relkind == RELKIND_MATVIEW)
00276 continue;
00277
00278
00279 if (!tblinfo[i].dobj.dump)
00280 continue;
00281
00282
00283 findParentsByOid(&tblinfo[i], inhinfo, numInherits);
00284
00285
00286 numParents = tblinfo[i].numParents;
00287 parents = tblinfo[i].parents;
00288 for (j = 0; j < numParents; j++)
00289 parents[j]->interesting = true;
00290 }
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 static void
00306 flagInhAttrs(TableInfo *tblinfo, int numTables)
00307 {
00308 int i,
00309 j,
00310 k;
00311
00312 for (i = 0; i < numTables; i++)
00313 {
00314 TableInfo *tbinfo = &(tblinfo[i]);
00315 int numParents;
00316 TableInfo **parents;
00317
00318
00319 if (tbinfo->relkind == RELKIND_SEQUENCE ||
00320 tbinfo->relkind == RELKIND_VIEW ||
00321 tbinfo->relkind == RELKIND_MATVIEW)
00322 continue;
00323
00324
00325 if (!tbinfo->dobj.dump)
00326 continue;
00327
00328 numParents = tbinfo->numParents;
00329 parents = tbinfo->parents;
00330
00331 if (numParents == 0)
00332 continue;
00333
00334
00335 for (j = 0; j < tbinfo->numatts; j++)
00336 {
00337 bool foundNotNull;
00338 bool foundDefault;
00339
00340
00341 if (tbinfo->attisdropped[j])
00342 continue;
00343
00344 foundNotNull = false;
00345 foundDefault = false;
00346 for (k = 0; k < numParents; k++)
00347 {
00348 TableInfo *parent = parents[k];
00349 int inhAttrInd;
00350
00351 inhAttrInd = strInArray(tbinfo->attnames[j],
00352 parent->attnames,
00353 parent->numatts);
00354 if (inhAttrInd >= 0)
00355 {
00356 foundNotNull |= parent->notnull[inhAttrInd];
00357 foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
00358 }
00359 }
00360
00361
00362 tbinfo->inhNotNull[j] = foundNotNull;
00363
00364
00365 if (foundDefault && tbinfo->attrdefs[j] == NULL)
00366 {
00367 AttrDefInfo *attrDef;
00368
00369 attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
00370 attrDef->dobj.objType = DO_ATTRDEF;
00371 attrDef->dobj.catId.tableoid = 0;
00372 attrDef->dobj.catId.oid = 0;
00373 AssignDumpId(&attrDef->dobj);
00374 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
00375 attrDef->dobj.namespace = tbinfo->dobj.namespace;
00376 attrDef->dobj.dump = tbinfo->dobj.dump;
00377
00378 attrDef->adtable = tbinfo;
00379 attrDef->adnum = j + 1;
00380 attrDef->adef_expr = pg_strdup("NULL");
00381
00382
00383 if (shouldPrintColumn(tbinfo, j))
00384 {
00385 attrDef->separate = false;
00386
00387 }
00388 else
00389 {
00390
00391 attrDef->separate = true;
00392
00393 addObjectDependency(&attrDef->dobj,
00394 tbinfo->dobj.dumpId);
00395 }
00396
00397 tbinfo->attrdefs[j] = attrDef;
00398 }
00399 }
00400 }
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 void
00412 AssignDumpId(DumpableObject *dobj)
00413 {
00414 dobj->dumpId = ++lastDumpId;
00415 dobj->name = NULL;
00416 dobj->namespace = NULL;
00417 dobj->dump = true;
00418 dobj->ext_member = false;
00419 dobj->dependencies = NULL;
00420 dobj->nDeps = 0;
00421 dobj->allocDeps = 0;
00422
00423 while (dobj->dumpId >= allocedDumpIds)
00424 {
00425 int newAlloc;
00426
00427 if (allocedDumpIds <= 0)
00428 {
00429 newAlloc = 256;
00430 dumpIdMap = (DumpableObject **)
00431 pg_malloc(newAlloc * sizeof(DumpableObject *));
00432 }
00433 else
00434 {
00435 newAlloc = allocedDumpIds * 2;
00436 dumpIdMap = (DumpableObject **)
00437 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
00438 }
00439 memset(dumpIdMap + allocedDumpIds, 0,
00440 (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
00441 allocedDumpIds = newAlloc;
00442 }
00443 dumpIdMap[dobj->dumpId] = dobj;
00444
00445
00446 catalogIdMapValid = false;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455 DumpId
00456 createDumpId(void)
00457 {
00458 return ++lastDumpId;
00459 }
00460
00461
00462
00463
00464 DumpId
00465 getMaxDumpId(void)
00466 {
00467 return lastDumpId;
00468 }
00469
00470
00471
00472
00473
00474
00475 DumpableObject *
00476 findObjectByDumpId(DumpId dumpId)
00477 {
00478 if (dumpId <= 0 || dumpId >= allocedDumpIds)
00479 return NULL;
00480 return dumpIdMap[dumpId];
00481 }
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 DumpableObject *
00494 findObjectByCatalogId(CatalogId catalogId)
00495 {
00496 DumpableObject **low;
00497 DumpableObject **high;
00498
00499 if (!catalogIdMapValid)
00500 {
00501 if (catalogIdMap)
00502 free(catalogIdMap);
00503 getDumpableObjects(&catalogIdMap, &numCatalogIds);
00504 if (numCatalogIds > 1)
00505 qsort((void *) catalogIdMap, numCatalogIds,
00506 sizeof(DumpableObject *), DOCatalogIdCompare);
00507 catalogIdMapValid = true;
00508 }
00509
00510
00511
00512
00513
00514
00515 if (numCatalogIds <= 0)
00516 return NULL;
00517 low = catalogIdMap;
00518 high = catalogIdMap + (numCatalogIds - 1);
00519 while (low <= high)
00520 {
00521 DumpableObject **middle;
00522 int difference;
00523
00524 middle = low + (high - low) / 2;
00525
00526 difference = oidcmp((*middle)->catId.oid, catalogId.oid);
00527 if (difference == 0)
00528 difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
00529 if (difference == 0)
00530 return *middle;
00531 else if (difference < 0)
00532 low = middle + 1;
00533 else
00534 high = middle - 1;
00535 }
00536 return NULL;
00537 }
00538
00539
00540
00541
00542
00543
00544 static DumpableObject *
00545 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
00546 {
00547 DumpableObject **low;
00548 DumpableObject **high;
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 if (numObjs <= 0)
00559 return NULL;
00560 low = indexArray;
00561 high = indexArray + (numObjs - 1);
00562 while (low <= high)
00563 {
00564 DumpableObject **middle;
00565 int difference;
00566
00567 middle = low + (high - low) / 2;
00568 difference = oidcmp((*middle)->catId.oid, oid);
00569 if (difference == 0)
00570 return *middle;
00571 else if (difference < 0)
00572 low = middle + 1;
00573 else
00574 high = middle - 1;
00575 }
00576 return NULL;
00577 }
00578
00579
00580
00581
00582 static DumpableObject **
00583 buildIndexArray(void *objArray, int numObjs, Size objSize)
00584 {
00585 DumpableObject **ptrs;
00586 int i;
00587
00588 ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
00589 for (i = 0; i < numObjs; i++)
00590 ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
00591
00592
00593 if (numObjs > 1)
00594 qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
00595 DOCatalogIdCompare);
00596
00597 return ptrs;
00598 }
00599
00600
00601
00602
00603 static int
00604 DOCatalogIdCompare(const void *p1, const void *p2)
00605 {
00606 const DumpableObject *obj1 = *(DumpableObject *const *) p1;
00607 const DumpableObject *obj2 = *(DumpableObject *const *) p2;
00608 int cmpval;
00609
00610
00611
00612
00613
00614 cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
00615 if (cmpval == 0)
00616 cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
00617 return cmpval;
00618 }
00619
00620
00621
00622
00623
00624
00625 void
00626 getDumpableObjects(DumpableObject ***objs, int *numObjs)
00627 {
00628 int i,
00629 j;
00630
00631 *objs = (DumpableObject **)
00632 pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
00633 j = 0;
00634 for (i = 1; i < allocedDumpIds; i++)
00635 {
00636 if (dumpIdMap[i])
00637 (*objs)[j++] = dumpIdMap[i];
00638 }
00639 *numObjs = j;
00640 }
00641
00642
00643
00644
00645
00646
00647 void
00648 addObjectDependency(DumpableObject *dobj, DumpId refId)
00649 {
00650 if (dobj->nDeps >= dobj->allocDeps)
00651 {
00652 if (dobj->allocDeps <= 0)
00653 {
00654 dobj->allocDeps = 16;
00655 dobj->dependencies = (DumpId *)
00656 pg_malloc(dobj->allocDeps * sizeof(DumpId));
00657 }
00658 else
00659 {
00660 dobj->allocDeps *= 2;
00661 dobj->dependencies = (DumpId *)
00662 pg_realloc(dobj->dependencies,
00663 dobj->allocDeps * sizeof(DumpId));
00664 }
00665 }
00666 dobj->dependencies[dobj->nDeps++] = refId;
00667 }
00668
00669
00670
00671
00672
00673
00674 void
00675 removeObjectDependency(DumpableObject *dobj, DumpId refId)
00676 {
00677 int i;
00678 int j = 0;
00679
00680 for (i = 0; i < dobj->nDeps; i++)
00681 {
00682 if (dobj->dependencies[i] != refId)
00683 dobj->dependencies[j++] = dobj->dependencies[i];
00684 }
00685 dobj->nDeps = j;
00686 }
00687
00688
00689
00690
00691
00692
00693
00694 TableInfo *
00695 findTableByOid(Oid oid)
00696 {
00697 return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
00698 }
00699
00700
00701
00702
00703
00704
00705 TypeInfo *
00706 findTypeByOid(Oid oid)
00707 {
00708 return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
00709 }
00710
00711
00712
00713
00714
00715
00716 FuncInfo *
00717 findFuncByOid(Oid oid)
00718 {
00719 return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
00720 }
00721
00722
00723
00724
00725
00726
00727 OprInfo *
00728 findOprByOid(Oid oid)
00729 {
00730 return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
00731 }
00732
00733
00734
00735
00736
00737
00738 CollInfo *
00739 findCollationByOid(Oid oid)
00740 {
00741 return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
00742 }
00743
00744
00745
00746
00747
00748
00749 NamespaceInfo *
00750 findNamespaceByOid(Oid oid)
00751 {
00752 return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
00753 }
00754
00755
00756
00757
00758
00759
00760 static void
00761 findParentsByOid(TableInfo *self,
00762 InhInfo *inhinfo, int numInherits)
00763 {
00764 Oid oid = self->dobj.catId.oid;
00765 int i,
00766 j;
00767 int numParents;
00768
00769 numParents = 0;
00770 for (i = 0; i < numInherits; i++)
00771 {
00772 if (inhinfo[i].inhrelid == oid)
00773 numParents++;
00774 }
00775
00776 self->numParents = numParents;
00777
00778 if (numParents > 0)
00779 {
00780 self->parents = (TableInfo **)
00781 pg_malloc(sizeof(TableInfo *) * numParents);
00782 j = 0;
00783 for (i = 0; i < numInherits; i++)
00784 {
00785 if (inhinfo[i].inhrelid == oid)
00786 {
00787 TableInfo *parent;
00788
00789 parent = findTableByOid(inhinfo[i].inhparent);
00790 if (parent == NULL)
00791 {
00792 write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
00793 inhinfo[i].inhparent,
00794 self->dobj.name,
00795 oid);
00796 exit_nicely(1);
00797 }
00798 self->parents[j++] = parent;
00799 }
00800 }
00801 }
00802 else
00803 self->parents = NULL;
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815 void
00816 parseOidArray(const char *str, Oid *array, int arraysize)
00817 {
00818 int j,
00819 argNum;
00820 char temp[100];
00821 char s;
00822
00823 argNum = 0;
00824 j = 0;
00825 for (;;)
00826 {
00827 s = *str++;
00828 if (s == ' ' || s == '\0')
00829 {
00830 if (j > 0)
00831 {
00832 if (argNum >= arraysize)
00833 {
00834 write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
00835 exit_nicely(1);
00836 }
00837 temp[j] = '\0';
00838 array[argNum++] = atooid(temp);
00839 j = 0;
00840 }
00841 if (s == '\0')
00842 break;
00843 }
00844 else
00845 {
00846 if (!(isdigit((unsigned char) s) || s == '-') ||
00847 j >= sizeof(temp) - 1)
00848 {
00849 write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
00850 exit_nicely(1);
00851 }
00852 temp[j++] = s;
00853 }
00854 }
00855
00856 while (argNum < arraysize)
00857 array[argNum++] = InvalidOid;
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868 static int
00869 strInArray(const char *pattern, char **arr, int arr_size)
00870 {
00871 int i;
00872
00873 for (i = 0; i < arr_size; i++)
00874 {
00875 if (strcmp(pattern, arr[i]) == 0)
00876 return i;
00877 }
00878 return -1;
00879 }
00880
00881
00882
00883
00884
00885
00886 void
00887 simple_oid_list_append(SimpleOidList *list, Oid val)
00888 {
00889 SimpleOidListCell *cell;
00890
00891 cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
00892 cell->next = NULL;
00893 cell->val = val;
00894
00895 if (list->tail)
00896 list->tail->next = cell;
00897 else
00898 list->head = cell;
00899 list->tail = cell;
00900 }
00901
00902 bool
00903 simple_oid_list_member(SimpleOidList *list, Oid val)
00904 {
00905 SimpleOidListCell *cell;
00906
00907 for (cell = list->head; cell; cell = cell->next)
00908 {
00909 if (cell->val == val)
00910 return true;
00911 }
00912 return false;
00913 }