PostgreSQL Source Code  git master
pg_dump_sort.c File Reference
#include "postgres_fe.h"
#include "catalog/pg_class_d.h"
#include "common/int.h"
#include "lib/binaryheap.h"
#include "pg_backup_archiver.h"
#include "pg_backup_utils.h"
#include "pg_dump.h"
Include dependency graph for pg_dump_sort.c:

Go to the source code of this file.

Enumerations

enum  dbObjectTypePriorities {
  PRIO_NAMESPACE = 1 , PRIO_PROCLANG , PRIO_COLLATION , PRIO_TRANSFORM ,
  PRIO_EXTENSION , PRIO_TYPE , PRIO_CAST , PRIO_FUNC ,
  PRIO_AGG , PRIO_ACCESS_METHOD , PRIO_OPERATOR , PRIO_OPFAMILY ,
  PRIO_CONVERSION , PRIO_TSPARSER , PRIO_TSTEMPLATE , PRIO_TSDICT ,
  PRIO_TSCONFIG , PRIO_FDW , PRIO_FOREIGN_SERVER , PRIO_TABLE ,
  PRIO_TABLE_ATTACH , PRIO_DUMMY_TYPE , PRIO_ATTRDEF , PRIO_LARGE_OBJECT ,
  PRIO_PRE_DATA_BOUNDARY , PRIO_TABLE_DATA , PRIO_SEQUENCE_SET , PRIO_LARGE_OBJECT_DATA ,
  PRIO_POST_DATA_BOUNDARY , PRIO_CONSTRAINT , PRIO_INDEX , PRIO_INDEX_ATTACH ,
  PRIO_STATSEXT , PRIO_RULE , PRIO_TRIGGER , PRIO_FK_CONSTRAINT ,
  PRIO_POLICY , PRIO_PUBLICATION , PRIO_PUBLICATION_REL , PRIO_PUBLICATION_TABLE_IN_SCHEMA ,
  PRIO_SUBSCRIPTION , PRIO_SUBSCRIPTION_REL , PRIO_DEFAULT_ACL , PRIO_EVENT_TRIGGER ,
  PRIO_REFRESH_MATVIEW
}
 

Functions

 StaticAssertDecl (lengthof(dbObjectTypePriority)==(DO_SUBSCRIPTION_REL+1), "array length mismatch")
 
static int DOTypeNameCompare (const void *p1, const void *p2)
 
static bool TopoSort (DumpableObject **objs, int numObjs, DumpableObject **ordering, int *nOrdering)
 
static void findDependencyLoops (DumpableObject **objs, int nObjs, int totObjs)
 
static int findLoop (DumpableObject *obj, DumpId startPoint, bool *processed, DumpId *searchFailed, DumpableObject **workspace, int depth)
 
static void repairDependencyLoop (DumpableObject **loop, int nLoop)
 
static void describeDumpableObject (DumpableObject *obj, char *buf, int bufsize)
 
static int int_cmp (void *a, void *b, void *arg)
 
void sortDumpableObjectsByTypeName (DumpableObject **objs, int numObjs)
 
void sortDumpableObjects (DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId)
 
static void repairTypeFuncLoop (DumpableObject *typeobj, DumpableObject *funcobj)
 
static void repairViewRuleLoop (DumpableObject *viewobj, DumpableObject *ruleobj)
 
static void repairViewRuleMultiLoop (DumpableObject *viewobj, DumpableObject *ruleobj)
 
static void repairMatViewBoundaryMultiLoop (DumpableObject *boundaryobj, DumpableObject *nextobj)
 
static void repairFunctionBoundaryMultiLoop (DumpableObject *boundaryobj, DumpableObject *nextobj)
 
static void repairTableConstraintLoop (DumpableObject *tableobj, DumpableObject *constraintobj)
 
static void repairTableConstraintMultiLoop (DumpableObject *tableobj, DumpableObject *constraintobj)
 
static void repairTableAttrDefLoop (DumpableObject *tableobj, DumpableObject *attrdefobj)
 
static void repairTableAttrDefMultiLoop (DumpableObject *tableobj, DumpableObject *attrdefobj)
 
static void repairDomainConstraintLoop (DumpableObject *domainobj, DumpableObject *constraintobj)
 
static void repairDomainConstraintMultiLoop (DumpableObject *domainobj, DumpableObject *constraintobj)
 
static void repairIndexLoop (DumpableObject *partedindex, DumpableObject *partindex)
 

Variables

static const int dbObjectTypePriority []
 
static DumpId preDataBoundId
 
static DumpId postDataBoundId
 

Enumeration Type Documentation

◆ dbObjectTypePriorities

Enumerator
PRIO_NAMESPACE 
PRIO_PROCLANG 
PRIO_COLLATION 
PRIO_TRANSFORM 
PRIO_EXTENSION 
PRIO_TYPE 
PRIO_CAST 
PRIO_FUNC 
PRIO_AGG 
PRIO_ACCESS_METHOD 
PRIO_OPERATOR 
PRIO_OPFAMILY 
PRIO_CONVERSION 
PRIO_TSPARSER 
PRIO_TSTEMPLATE 
PRIO_TSDICT 
PRIO_TSCONFIG 
PRIO_FDW 
PRIO_FOREIGN_SERVER 
PRIO_TABLE 
PRIO_TABLE_ATTACH 
PRIO_DUMMY_TYPE 
PRIO_ATTRDEF 
PRIO_LARGE_OBJECT 
PRIO_PRE_DATA_BOUNDARY 
PRIO_TABLE_DATA 
PRIO_SEQUENCE_SET 
PRIO_LARGE_OBJECT_DATA 
PRIO_POST_DATA_BOUNDARY 
PRIO_CONSTRAINT 
PRIO_INDEX 
PRIO_INDEX_ATTACH 
PRIO_STATSEXT 
PRIO_RULE 
PRIO_TRIGGER 
PRIO_FK_CONSTRAINT 
PRIO_POLICY 
PRIO_PUBLICATION 
PRIO_PUBLICATION_REL 
PRIO_PUBLICATION_TABLE_IN_SCHEMA 
PRIO_SUBSCRIPTION 
PRIO_SUBSCRIPTION_REL 
PRIO_DEFAULT_ACL 
PRIO_EVENT_TRIGGER 
PRIO_REFRESH_MATVIEW 

Definition at line 55 of file pg_dump_sort.c.

56 {
57  PRIO_NAMESPACE = 1,
62  PRIO_TYPE, /* used for DO_TYPE and DO_SHELL_TYPE */
63  PRIO_CAST,
64  PRIO_FUNC,
65  PRIO_AGG,
68  PRIO_OPFAMILY, /* used for DO_OPFAMILY and DO_OPCLASS */
74  PRIO_FDW,
76  PRIO_TABLE,
81  PRIO_PRE_DATA_BOUNDARY, /* boundary! */
85  PRIO_POST_DATA_BOUNDARY, /* boundary! */
87  PRIO_INDEX,
90  PRIO_RULE,
99  PRIO_DEFAULT_ACL, /* done in ACL pass */
100  PRIO_EVENT_TRIGGER, /* must be next to last! */
101  PRIO_REFRESH_MATVIEW /* must be last! */
102 };
@ PRIO_EVENT_TRIGGER
Definition: pg_dump_sort.c:100
@ PRIO_SUBSCRIPTION
Definition: pg_dump_sort.c:97
@ PRIO_FDW
Definition: pg_dump_sort.c:74
@ PRIO_SUBSCRIPTION_REL
Definition: pg_dump_sort.c:98
@ PRIO_INDEX_ATTACH
Definition: pg_dump_sort.c:88
@ PRIO_FK_CONSTRAINT
Definition: pg_dump_sort.c:92
@ PRIO_TSCONFIG
Definition: pg_dump_sort.c:73
@ PRIO_POST_DATA_BOUNDARY
Definition: pg_dump_sort.c:85
@ PRIO_PUBLICATION
Definition: pg_dump_sort.c:94
@ PRIO_PUBLICATION_TABLE_IN_SCHEMA
Definition: pg_dump_sort.c:96
@ PRIO_TABLE
Definition: pg_dump_sort.c:76
@ PRIO_DEFAULT_ACL
Definition: pg_dump_sort.c:99
@ PRIO_CAST
Definition: pg_dump_sort.c:63
@ PRIO_AGG
Definition: pg_dump_sort.c:65
@ PRIO_PROCLANG
Definition: pg_dump_sort.c:58
@ PRIO_LARGE_OBJECT
Definition: pg_dump_sort.c:80
@ PRIO_CONVERSION
Definition: pg_dump_sort.c:69
@ PRIO_FUNC
Definition: pg_dump_sort.c:64
@ PRIO_CONSTRAINT
Definition: pg_dump_sort.c:86
@ PRIO_REFRESH_MATVIEW
Definition: pg_dump_sort.c:101
@ PRIO_POLICY
Definition: pg_dump_sort.c:93
@ PRIO_STATSEXT
Definition: pg_dump_sort.c:89
@ PRIO_EXTENSION
Definition: pg_dump_sort.c:61
@ PRIO_TSPARSER
Definition: pg_dump_sort.c:70
@ PRIO_DUMMY_TYPE
Definition: pg_dump_sort.c:78
@ PRIO_OPERATOR
Definition: pg_dump_sort.c:67
@ PRIO_RULE
Definition: pg_dump_sort.c:90
@ PRIO_NAMESPACE
Definition: pg_dump_sort.c:57
@ PRIO_PUBLICATION_REL
Definition: pg_dump_sort.c:95
@ PRIO_FOREIGN_SERVER
Definition: pg_dump_sort.c:75
@ PRIO_SEQUENCE_SET
Definition: pg_dump_sort.c:83
@ PRIO_LARGE_OBJECT_DATA
Definition: pg_dump_sort.c:84
@ PRIO_TSDICT
Definition: pg_dump_sort.c:72
@ PRIO_ACCESS_METHOD
Definition: pg_dump_sort.c:66
@ PRIO_ATTRDEF
Definition: pg_dump_sort.c:79
@ PRIO_PRE_DATA_BOUNDARY
Definition: pg_dump_sort.c:81
@ PRIO_COLLATION
Definition: pg_dump_sort.c:59
@ PRIO_INDEX
Definition: pg_dump_sort.c:87
@ PRIO_TRIGGER
Definition: pg_dump_sort.c:91
@ PRIO_TYPE
Definition: pg_dump_sort.c:62
@ PRIO_OPFAMILY
Definition: pg_dump_sort.c:68
@ PRIO_TSTEMPLATE
Definition: pg_dump_sort.c:71
@ PRIO_TRANSFORM
Definition: pg_dump_sort.c:60
@ PRIO_TABLE_DATA
Definition: pg_dump_sort.c:82
@ PRIO_TABLE_ATTACH
Definition: pg_dump_sort.c:77

Function Documentation

◆ describeDumpableObject()

static void describeDumpableObject ( DumpableObject obj,
char *  buf,
int  bufsize 
)
static

Definition at line 1248 of file pg_dump_sort.c.

1249 {
1250  switch (obj->objType)
1251  {
1252  case DO_NAMESPACE:
1253  snprintf(buf, bufsize,
1254  "SCHEMA %s (ID %d OID %u)",
1255  obj->name, obj->dumpId, obj->catId.oid);
1256  return;
1257  case DO_EXTENSION:
1258  snprintf(buf, bufsize,
1259  "EXTENSION %s (ID %d OID %u)",
1260  obj->name, obj->dumpId, obj->catId.oid);
1261  return;
1262  case DO_TYPE:
1263  snprintf(buf, bufsize,
1264  "TYPE %s (ID %d OID %u)",
1265  obj->name, obj->dumpId, obj->catId.oid);
1266  return;
1267  case DO_SHELL_TYPE:
1268  snprintf(buf, bufsize,
1269  "SHELL TYPE %s (ID %d OID %u)",
1270  obj->name, obj->dumpId, obj->catId.oid);
1271  return;
1272  case DO_FUNC:
1273  snprintf(buf, bufsize,
1274  "FUNCTION %s (ID %d OID %u)",
1275  obj->name, obj->dumpId, obj->catId.oid);
1276  return;
1277  case DO_AGG:
1278  snprintf(buf, bufsize,
1279  "AGGREGATE %s (ID %d OID %u)",
1280  obj->name, obj->dumpId, obj->catId.oid);
1281  return;
1282  case DO_OPERATOR:
1283  snprintf(buf, bufsize,
1284  "OPERATOR %s (ID %d OID %u)",
1285  obj->name, obj->dumpId, obj->catId.oid);
1286  return;
1287  case DO_ACCESS_METHOD:
1288  snprintf(buf, bufsize,
1289  "ACCESS METHOD %s (ID %d OID %u)",
1290  obj->name, obj->dumpId, obj->catId.oid);
1291  return;
1292  case DO_OPCLASS:
1293  snprintf(buf, bufsize,
1294  "OPERATOR CLASS %s (ID %d OID %u)",
1295  obj->name, obj->dumpId, obj->catId.oid);
1296  return;
1297  case DO_OPFAMILY:
1298  snprintf(buf, bufsize,
1299  "OPERATOR FAMILY %s (ID %d OID %u)",
1300  obj->name, obj->dumpId, obj->catId.oid);
1301  return;
1302  case DO_COLLATION:
1303  snprintf(buf, bufsize,
1304  "COLLATION %s (ID %d OID %u)",
1305  obj->name, obj->dumpId, obj->catId.oid);
1306  return;
1307  case DO_CONVERSION:
1308  snprintf(buf, bufsize,
1309  "CONVERSION %s (ID %d OID %u)",
1310  obj->name, obj->dumpId, obj->catId.oid);
1311  return;
1312  case DO_TABLE:
1313  snprintf(buf, bufsize,
1314  "TABLE %s (ID %d OID %u)",
1315  obj->name, obj->dumpId, obj->catId.oid);
1316  return;
1317  case DO_TABLE_ATTACH:
1318  snprintf(buf, bufsize,
1319  "TABLE ATTACH %s (ID %d)",
1320  obj->name, obj->dumpId);
1321  return;
1322  case DO_ATTRDEF:
1323  snprintf(buf, bufsize,
1324  "ATTRDEF %s.%s (ID %d OID %u)",
1325  ((AttrDefInfo *) obj)->adtable->dobj.name,
1326  ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
1327  obj->dumpId, obj->catId.oid);
1328  return;
1329  case DO_INDEX:
1330  snprintf(buf, bufsize,
1331  "INDEX %s (ID %d OID %u)",
1332  obj->name, obj->dumpId, obj->catId.oid);
1333  return;
1334  case DO_INDEX_ATTACH:
1335  snprintf(buf, bufsize,
1336  "INDEX ATTACH %s (ID %d)",
1337  obj->name, obj->dumpId);
1338  return;
1339  case DO_STATSEXT:
1340  snprintf(buf, bufsize,
1341  "STATISTICS %s (ID %d OID %u)",
1342  obj->name, obj->dumpId, obj->catId.oid);
1343  return;
1344  case DO_REFRESH_MATVIEW:
1345  snprintf(buf, bufsize,
1346  "REFRESH MATERIALIZED VIEW %s (ID %d OID %u)",
1347  obj->name, obj->dumpId, obj->catId.oid);
1348  return;
1349  case DO_RULE:
1350  snprintf(buf, bufsize,
1351  "RULE %s (ID %d OID %u)",
1352  obj->name, obj->dumpId, obj->catId.oid);
1353  return;
1354  case DO_TRIGGER:
1355  snprintf(buf, bufsize,
1356  "TRIGGER %s (ID %d OID %u)",
1357  obj->name, obj->dumpId, obj->catId.oid);
1358  return;
1359  case DO_EVENT_TRIGGER:
1360  snprintf(buf, bufsize,
1361  "EVENT TRIGGER %s (ID %d OID %u)",
1362  obj->name, obj->dumpId, obj->catId.oid);
1363  return;
1364  case DO_CONSTRAINT:
1365  snprintf(buf, bufsize,
1366  "CONSTRAINT %s (ID %d OID %u)",
1367  obj->name, obj->dumpId, obj->catId.oid);
1368  return;
1369  case DO_FK_CONSTRAINT:
1370  snprintf(buf, bufsize,
1371  "FK CONSTRAINT %s (ID %d OID %u)",
1372  obj->name, obj->dumpId, obj->catId.oid);
1373  return;
1374  case DO_PROCLANG:
1375  snprintf(buf, bufsize,
1376  "PROCEDURAL LANGUAGE %s (ID %d OID %u)",
1377  obj->name, obj->dumpId, obj->catId.oid);
1378  return;
1379  case DO_CAST:
1380  snprintf(buf, bufsize,
1381  "CAST %u to %u (ID %d OID %u)",
1382  ((CastInfo *) obj)->castsource,
1383  ((CastInfo *) obj)->casttarget,
1384  obj->dumpId, obj->catId.oid);
1385  return;
1386  case DO_TRANSFORM:
1387  snprintf(buf, bufsize,
1388  "TRANSFORM %u lang %u (ID %d OID %u)",
1389  ((TransformInfo *) obj)->trftype,
1390  ((TransformInfo *) obj)->trflang,
1391  obj->dumpId, obj->catId.oid);
1392  return;
1393  case DO_TABLE_DATA:
1394  snprintf(buf, bufsize,
1395  "TABLE DATA %s (ID %d OID %u)",
1396  obj->name, obj->dumpId, obj->catId.oid);
1397  return;
1398  case DO_SEQUENCE_SET:
1399  snprintf(buf, bufsize,
1400  "SEQUENCE SET %s (ID %d OID %u)",
1401  obj->name, obj->dumpId, obj->catId.oid);
1402  return;
1403  case DO_DUMMY_TYPE:
1404  snprintf(buf, bufsize,
1405  "DUMMY TYPE %s (ID %d OID %u)",
1406  obj->name, obj->dumpId, obj->catId.oid);
1407  return;
1408  case DO_TSPARSER:
1409  snprintf(buf, bufsize,
1410  "TEXT SEARCH PARSER %s (ID %d OID %u)",
1411  obj->name, obj->dumpId, obj->catId.oid);
1412  return;
1413  case DO_TSDICT:
1414  snprintf(buf, bufsize,
1415  "TEXT SEARCH DICTIONARY %s (ID %d OID %u)",
1416  obj->name, obj->dumpId, obj->catId.oid);
1417  return;
1418  case DO_TSTEMPLATE:
1419  snprintf(buf, bufsize,
1420  "TEXT SEARCH TEMPLATE %s (ID %d OID %u)",
1421  obj->name, obj->dumpId, obj->catId.oid);
1422  return;
1423  case DO_TSCONFIG:
1424  snprintf(buf, bufsize,
1425  "TEXT SEARCH CONFIGURATION %s (ID %d OID %u)",
1426  obj->name, obj->dumpId, obj->catId.oid);
1427  return;
1428  case DO_FDW:
1429  snprintf(buf, bufsize,
1430  "FOREIGN DATA WRAPPER %s (ID %d OID %u)",
1431  obj->name, obj->dumpId, obj->catId.oid);
1432  return;
1433  case DO_FOREIGN_SERVER:
1434  snprintf(buf, bufsize,
1435  "FOREIGN SERVER %s (ID %d OID %u)",
1436  obj->name, obj->dumpId, obj->catId.oid);
1437  return;
1438  case DO_DEFAULT_ACL:
1439  snprintf(buf, bufsize,
1440  "DEFAULT ACL %s (ID %d OID %u)",
1441  obj->name, obj->dumpId, obj->catId.oid);
1442  return;
1443  case DO_LARGE_OBJECT:
1444  snprintf(buf, bufsize,
1445  "LARGE OBJECT (ID %d OID %u)",
1446  obj->dumpId, obj->catId.oid);
1447  return;
1448  case DO_LARGE_OBJECT_DATA:
1449  snprintf(buf, bufsize,
1450  "LARGE OBJECT DATA (ID %d)",
1451  obj->dumpId);
1452  return;
1453  case DO_POLICY:
1454  snprintf(buf, bufsize,
1455  "POLICY (ID %d OID %u)",
1456  obj->dumpId, obj->catId.oid);
1457  return;
1458  case DO_PUBLICATION:
1459  snprintf(buf, bufsize,
1460  "PUBLICATION (ID %d OID %u)",
1461  obj->dumpId, obj->catId.oid);
1462  return;
1463  case DO_PUBLICATION_REL:
1464  snprintf(buf, bufsize,
1465  "PUBLICATION TABLE (ID %d OID %u)",
1466  obj->dumpId, obj->catId.oid);
1467  return;
1469  snprintf(buf, bufsize,
1470  "PUBLICATION TABLES IN SCHEMA (ID %d OID %u)",
1471  obj->dumpId, obj->catId.oid);
1472  return;
1473  case DO_SUBSCRIPTION:
1474  snprintf(buf, bufsize,
1475  "SUBSCRIPTION (ID %d OID %u)",
1476  obj->dumpId, obj->catId.oid);
1477  return;
1478  case DO_SUBSCRIPTION_REL:
1479  snprintf(buf, bufsize,
1480  "SUBSCRIPTION TABLE (ID %d OID %u)",
1481  obj->dumpId, obj->catId.oid);
1482  return;
1483  case DO_PRE_DATA_BOUNDARY:
1484  snprintf(buf, bufsize,
1485  "PRE-DATA BOUNDARY (ID %d)",
1486  obj->dumpId);
1487  return;
1488  case DO_POST_DATA_BOUNDARY:
1489  snprintf(buf, bufsize,
1490  "POST-DATA BOUNDARY (ID %d)",
1491  obj->dumpId);
1492  return;
1493  }
1494  /* shouldn't get here */
1495  snprintf(buf, bufsize,
1496  "object type %d (ID %d OID %u)",
1497  (int) obj->objType,
1498  obj->dumpId, obj->catId.oid);
1499 }
#define bufsize
Definition: indent_globs.h:36
@ DO_EVENT_TRIGGER
Definition: pg_dump.h:79
@ DO_REFRESH_MATVIEW
Definition: pg_dump.h:80
@ DO_POLICY
Definition: pg_dump.h:81
@ DO_CAST
Definition: pg_dump.h:63
@ DO_FOREIGN_SERVER
Definition: pg_dump.h:72
@ DO_PRE_DATA_BOUNDARY
Definition: pg_dump.h:77
@ DO_PROCLANG
Definition: pg_dump.h:62
@ DO_TYPE
Definition: pg_dump.h:42
@ DO_INDEX
Definition: pg_dump.h:55
@ DO_COLLATION
Definition: pg_dump.h:50
@ DO_LARGE_OBJECT
Definition: pg_dump.h:75
@ DO_TSCONFIG
Definition: pg_dump.h:70
@ DO_OPERATOR
Definition: pg_dump.h:46
@ DO_FK_CONSTRAINT
Definition: pg_dump.h:61
@ DO_CONSTRAINT
Definition: pg_dump.h:60
@ DO_SUBSCRIPTION
Definition: pg_dump.h:85
@ DO_DEFAULT_ACL
Definition: pg_dump.h:73
@ DO_FDW
Definition: pg_dump.h:71
@ DO_SUBSCRIPTION_REL
Definition: pg_dump.h:86
@ DO_SEQUENCE_SET
Definition: pg_dump.h:65
@ DO_ATTRDEF
Definition: pg_dump.h:54
@ DO_PUBLICATION_REL
Definition: pg_dump.h:83
@ DO_TABLE_ATTACH
Definition: pg_dump.h:53
@ DO_OPCLASS
Definition: pg_dump.h:48
@ DO_INDEX_ATTACH
Definition: pg_dump.h:56
@ DO_TSTEMPLATE
Definition: pg_dump.h:69
@ DO_STATSEXT
Definition: pg_dump.h:57
@ DO_FUNC
Definition: pg_dump.h:44
@ DO_POST_DATA_BOUNDARY
Definition: pg_dump.h:78
@ DO_LARGE_OBJECT_DATA
Definition: pg_dump.h:76
@ DO_OPFAMILY
Definition: pg_dump.h:49
@ DO_TRANSFORM
Definition: pg_dump.h:74
@ DO_ACCESS_METHOD
Definition: pg_dump.h:47
@ DO_PUBLICATION_TABLE_IN_SCHEMA
Definition: pg_dump.h:84
@ DO_CONVERSION
Definition: pg_dump.h:51
@ DO_TRIGGER
Definition: pg_dump.h:59
@ DO_RULE
Definition: pg_dump.h:58
@ DO_DUMMY_TYPE
Definition: pg_dump.h:66
@ DO_TSDICT
Definition: pg_dump.h:68
@ DO_TSPARSER
Definition: pg_dump.h:67
@ DO_EXTENSION
Definition: pg_dump.h:41
@ DO_TABLE_DATA
Definition: pg_dump.h:64
@ DO_PUBLICATION
Definition: pg_dump.h:82
@ DO_TABLE
Definition: pg_dump.h:52
@ DO_NAMESPACE
Definition: pg_dump.h:40
@ DO_AGG
Definition: pg_dump.h:45
@ DO_SHELL_TYPE
Definition: pg_dump.h:43
static char * buf
Definition: pg_test_fsync.c:73
#define snprintf
Definition: port.h:238
char * name
Definition: pg_dump.h:138
DumpId dumpId
Definition: pg_dump.h:137
DumpableObjectType objType
Definition: pg_dump.h:135
CatalogId catId
Definition: pg_dump.h:136

References buf, bufsize, _dumpableObject::catId, DO_ACCESS_METHOD, DO_AGG, DO_ATTRDEF, DO_CAST, DO_COLLATION, DO_CONSTRAINT, DO_CONVERSION, DO_DEFAULT_ACL, DO_DUMMY_TYPE, DO_EVENT_TRIGGER, DO_EXTENSION, DO_FDW, DO_FK_CONSTRAINT, DO_FOREIGN_SERVER, DO_FUNC, DO_INDEX, DO_INDEX_ATTACH, DO_LARGE_OBJECT, DO_LARGE_OBJECT_DATA, DO_NAMESPACE, DO_OPCLASS, DO_OPERATOR, DO_OPFAMILY, DO_POLICY, DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, DO_PROCLANG, DO_PUBLICATION, DO_PUBLICATION_REL, DO_PUBLICATION_TABLE_IN_SCHEMA, DO_REFRESH_MATVIEW, DO_RULE, DO_SEQUENCE_SET, DO_SHELL_TYPE, DO_STATSEXT, DO_SUBSCRIPTION, DO_SUBSCRIPTION_REL, DO_TABLE, DO_TABLE_ATTACH, DO_TABLE_DATA, DO_TRANSFORM, DO_TRIGGER, DO_TSCONFIG, DO_TSDICT, DO_TSPARSER, DO_TSTEMPLATE, DO_TYPE, _dumpableObject::dumpId, _dumpableObject::name, _dumpableObject::objType, CatalogId::oid, and snprintf.

Referenced by repairDependencyLoop().

◆ DOTypeNameCompare()

static int DOTypeNameCompare ( const void *  p1,
const void *  p2 
)
static

Definition at line 197 of file pg_dump_sort.c.

198 {
199  DumpableObject *obj1 = *(DumpableObject *const *) p1;
200  DumpableObject *obj2 = *(DumpableObject *const *) p2;
201  int cmpval;
202 
203  /* Sort by type's priority */
204  cmpval = dbObjectTypePriority[obj1->objType] -
206 
207  if (cmpval != 0)
208  return cmpval;
209 
210  /*
211  * Sort by namespace. Typically, all objects of the same priority would
212  * either have or not have a namespace link, but there are exceptions.
213  * Sort NULL namespace after non-NULL in such cases.
214  */
215  if (obj1->namespace)
216  {
217  if (obj2->namespace)
218  {
219  cmpval = strcmp(obj1->namespace->dobj.name,
220  obj2->namespace->dobj.name);
221  if (cmpval != 0)
222  return cmpval;
223  }
224  else
225  return -1;
226  }
227  else if (obj2->namespace)
228  return 1;
229 
230  /* Sort by name */
231  cmpval = strcmp(obj1->name, obj2->name);
232  if (cmpval != 0)
233  return cmpval;
234 
235  /* To have a stable sort order, break ties for some object types */
236  if (obj1->objType == DO_FUNC || obj1->objType == DO_AGG)
237  {
238  FuncInfo *fobj1 = *(FuncInfo *const *) p1;
239  FuncInfo *fobj2 = *(FuncInfo *const *) p2;
240  int i;
241 
242  /* Sort by number of arguments, then argument type names */
243  cmpval = fobj1->nargs - fobj2->nargs;
244  if (cmpval != 0)
245  return cmpval;
246  for (i = 0; i < fobj1->nargs; i++)
247  {
248  TypeInfo *argtype1 = findTypeByOid(fobj1->argtypes[i]);
249  TypeInfo *argtype2 = findTypeByOid(fobj2->argtypes[i]);
250 
251  if (argtype1 && argtype2)
252  {
253  if (argtype1->dobj.namespace && argtype2->dobj.namespace)
254  {
255  cmpval = strcmp(argtype1->dobj.namespace->dobj.name,
256  argtype2->dobj.namespace->dobj.name);
257  if (cmpval != 0)
258  return cmpval;
259  }
260  cmpval = strcmp(argtype1->dobj.name, argtype2->dobj.name);
261  if (cmpval != 0)
262  return cmpval;
263  }
264  }
265  }
266  else if (obj1->objType == DO_OPERATOR)
267  {
268  OprInfo *oobj1 = *(OprInfo *const *) p1;
269  OprInfo *oobj2 = *(OprInfo *const *) p2;
270 
271  /* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
272  cmpval = (oobj2->oprkind - oobj1->oprkind);
273  if (cmpval != 0)
274  return cmpval;
275  }
276  else if (obj1->objType == DO_ATTRDEF)
277  {
278  AttrDefInfo *adobj1 = *(AttrDefInfo *const *) p1;
279  AttrDefInfo *adobj2 = *(AttrDefInfo *const *) p2;
280 
281  /* Sort by attribute number */
282  cmpval = (adobj1->adnum - adobj2->adnum);
283  if (cmpval != 0)
284  return cmpval;
285  }
286  else if (obj1->objType == DO_POLICY)
287  {
288  PolicyInfo *pobj1 = *(PolicyInfo *const *) p1;
289  PolicyInfo *pobj2 = *(PolicyInfo *const *) p2;
290 
291  /* Sort by table name (table namespace was considered already) */
292  cmpval = strcmp(pobj1->poltable->dobj.name,
293  pobj2->poltable->dobj.name);
294  if (cmpval != 0)
295  return cmpval;
296  }
297  else if (obj1->objType == DO_TRIGGER)
298  {
299  TriggerInfo *tobj1 = *(TriggerInfo *const *) p1;
300  TriggerInfo *tobj2 = *(TriggerInfo *const *) p2;
301 
302  /* Sort by table name (table namespace was considered already) */
303  cmpval = strcmp(tobj1->tgtable->dobj.name,
304  tobj2->tgtable->dobj.name);
305  if (cmpval != 0)
306  return cmpval;
307  }
308 
309  /* Usually shouldn't get here, but if we do, sort by OID */
310  return oidcmp(obj1->catId.oid, obj2->catId.oid);
311 }
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:864
int i
Definition: isn.c:73
#define oidcmp(x, y)
Definition: pg_dump.h:20
static const int dbObjectTypePriority[]
Definition: pg_dump_sort.c:105
Oid * argtypes
Definition: pg_dump.h:229
int nargs
Definition: pg_dump.h:228
char oprkind
Definition: pg_dump.h:245
TableInfo * poltable
Definition: pg_dump.h:602
DumpableObject dobj
Definition: pg_dump.h:285
TableInfo * tgtable
Definition: pg_dump.h:446
DumpableObject dobj
Definition: pg_dump.h:191

References _attrDefInfo::adnum, _funcInfo::argtypes, _dumpableObject::catId, dbObjectTypePriority, DO_AGG, DO_ATTRDEF, DO_FUNC, DO_OPERATOR, DO_POLICY, DO_TRIGGER, _typeInfo::dobj, _tableInfo::dobj, findTypeByOid(), i, _dumpableObject::name, _funcInfo::nargs, _dumpableObject::objType, CatalogId::oid, oidcmp, _oprInfo::oprkind, p2, _policyInfo::poltable, and _triggerInfo::tgtable.

Referenced by sortDumpableObjectsByTypeName().

◆ findDependencyLoops()

static void findDependencyLoops ( DumpableObject **  objs,
int  nObjs,
int  totObjs 
)
static

Definition at line 523 of file pg_dump_sort.c.

524 {
525  /*
526  * We use three data structures here:
527  *
528  * processed[] is a bool array indexed by dump ID, marking the objects
529  * already processed during this invocation of findDependencyLoops().
530  *
531  * searchFailed[] is another array indexed by dump ID. searchFailed[j] is
532  * set to dump ID k if we have proven that there is no dependency path
533  * leading from object j back to start point k. This allows us to skip
534  * useless searching when there are multiple dependency paths from k to j,
535  * which is a common situation. We could use a simple bool array for
536  * this, but then we'd need to re-zero it for each start point, resulting
537  * in O(N^2) zeroing work. Using the start point's dump ID as the "true"
538  * value lets us skip clearing the array before we consider the next start
539  * point.
540  *
541  * workspace[] is an array of DumpableObject pointers, in which we try to
542  * build lists of objects constituting loops. We make workspace[] large
543  * enough to hold all the objects in TopoSort's output, which is huge
544  * overkill in most cases but could theoretically be necessary if there is
545  * a single dependency chain linking all the objects.
546  */
547  bool *processed;
548  DumpId *searchFailed;
549  DumpableObject **workspace;
550  bool fixedloop;
551  int i;
552 
553  processed = (bool *) pg_malloc0((getMaxDumpId() + 1) * sizeof(bool));
554  searchFailed = (DumpId *) pg_malloc0((getMaxDumpId() + 1) * sizeof(DumpId));
555  workspace = (DumpableObject **) pg_malloc(totObjs * sizeof(DumpableObject *));
556  fixedloop = false;
557 
558  for (i = 0; i < nObjs; i++)
559  {
560  DumpableObject *obj = objs[i];
561  int looplen;
562  int j;
563 
564  looplen = findLoop(obj,
565  obj->dumpId,
566  processed,
567  searchFailed,
568  workspace,
569  0);
570 
571  if (looplen > 0)
572  {
573  /* Found a loop, repair it */
574  repairDependencyLoop(workspace, looplen);
575  fixedloop = true;
576  /* Mark loop members as processed */
577  for (j = 0; j < looplen; j++)
578  processed[workspace[j]->dumpId] = true;
579  }
580  else
581  {
582  /*
583  * There's no loop starting at this object, but mark it processed
584  * anyway. This is not necessary for correctness, but saves later
585  * invocations of findLoop() from uselessly chasing references to
586  * such an object.
587  */
588  processed[obj->dumpId] = true;
589  }
590  }
591 
592  /* We'd better have fixed at least one loop */
593  if (!fixedloop)
594  pg_fatal("could not identify dependency loop");
595 
596  free(workspace);
597  free(searchFailed);
598  free(processed);
599 }
DumpId getMaxDumpId(void)
Definition: common.c:719
unsigned char bool
Definition: c.h:443
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define free(a)
Definition: header.h:65
int j
Definition: isn.c:74
int DumpId
Definition: pg_backup.h:268
#define pg_fatal(...)
static int findLoop(DumpableObject *obj, DumpId startPoint, bool *processed, DumpId *searchFailed, DumpableObject **workspace, int depth)
Definition: pg_dump_sort.c:619
static void repairDependencyLoop(DumpableObject **loop, int nLoop)
Definition: pg_dump_sort.c:926

References _dumpableObject::dumpId, findLoop(), free, getMaxDumpId(), i, j, pg_fatal, pg_malloc(), pg_malloc0(), and repairDependencyLoop().

Referenced by sortDumpableObjects().

◆ findLoop()

static int findLoop ( DumpableObject obj,
DumpId  startPoint,
bool processed,
DumpId searchFailed,
DumpableObject **  workspace,
int  depth 
)
static

Definition at line 619 of file pg_dump_sort.c.

625 {
626  int i;
627 
628  /*
629  * Reject if obj is already processed. This test prevents us from finding
630  * loops that overlap previously-processed loops.
631  */
632  if (processed[obj->dumpId])
633  return 0;
634 
635  /*
636  * If we've already proven there is no path from this object back to the
637  * startPoint, forget it.
638  */
639  if (searchFailed[obj->dumpId] == startPoint)
640  return 0;
641 
642  /*
643  * Reject if obj is already present in workspace. This test prevents us
644  * from going into infinite recursion if we are given a startPoint object
645  * that links to a cycle it's not a member of, and it guarantees that we
646  * can't overflow the allocated size of workspace[].
647  */
648  for (i = 0; i < depth; i++)
649  {
650  if (workspace[i] == obj)
651  return 0;
652  }
653 
654  /*
655  * Okay, tentatively add obj to workspace
656  */
657  workspace[depth++] = obj;
658 
659  /*
660  * See if we've found a loop back to the desired startPoint; if so, done
661  */
662  for (i = 0; i < obj->nDeps; i++)
663  {
664  if (obj->dependencies[i] == startPoint)
665  return depth;
666  }
667 
668  /*
669  * Recurse down each outgoing branch
670  */
671  for (i = 0; i < obj->nDeps; i++)
672  {
674  int newDepth;
675 
676  if (!nextobj)
677  continue; /* ignore dependencies on undumped objects */
678  newDepth = findLoop(nextobj,
679  startPoint,
680  processed,
681  searchFailed,
682  workspace,
683  depth);
684  if (newDepth > 0)
685  return newDepth;
686  }
687 
688  /*
689  * Remember there is no path from here back to startPoint
690  */
691  searchFailed[obj->dumpId] = startPoint;
692 
693  return 0;
694 }
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:730
DumpId * dependencies
Definition: pg_dump.h:145

References _dumpableObject::dependencies, _dumpableObject::dumpId, findObjectByDumpId(), i, and _dumpableObject::nDeps.

Referenced by findDependencyLoops().

◆ int_cmp()

static int int_cmp ( void *  a,
void *  b,
void *  arg 
)
static

Definition at line 1503 of file pg_dump_sort.c.

1504 {
1505  int ai = (int) (intptr_t) a;
1506  int bi = (int) (intptr_t) b;
1507 
1508  return pg_cmp_s32(ai, bi);
1509 }
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:483
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, b, and pg_cmp_s32().

Referenced by TopoSort().

◆ repairDependencyLoop()

static void repairDependencyLoop ( DumpableObject **  loop,
int  nLoop 
)
static

Definition at line 926 of file pg_dump_sort.c.

928 {
929  int i,
930  j;
931 
932  /* Datatype and one of its I/O or canonicalize functions */
933  if (nLoop == 2 &&
934  loop[0]->objType == DO_TYPE &&
935  loop[1]->objType == DO_FUNC)
936  {
937  repairTypeFuncLoop(loop[0], loop[1]);
938  return;
939  }
940  if (nLoop == 2 &&
941  loop[1]->objType == DO_TYPE &&
942  loop[0]->objType == DO_FUNC)
943  {
944  repairTypeFuncLoop(loop[1], loop[0]);
945  return;
946  }
947 
948  /* View (including matview) and its ON SELECT rule */
949  if (nLoop == 2 &&
950  loop[0]->objType == DO_TABLE &&
951  loop[1]->objType == DO_RULE &&
952  (((TableInfo *) loop[0])->relkind == RELKIND_VIEW ||
953  ((TableInfo *) loop[0])->relkind == RELKIND_MATVIEW) &&
954  ((RuleInfo *) loop[1])->ev_type == '1' &&
955  ((RuleInfo *) loop[1])->is_instead &&
956  ((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
957  {
958  repairViewRuleLoop(loop[0], loop[1]);
959  return;
960  }
961  if (nLoop == 2 &&
962  loop[1]->objType == DO_TABLE &&
963  loop[0]->objType == DO_RULE &&
964  (((TableInfo *) loop[1])->relkind == RELKIND_VIEW ||
965  ((TableInfo *) loop[1])->relkind == RELKIND_MATVIEW) &&
966  ((RuleInfo *) loop[0])->ev_type == '1' &&
967  ((RuleInfo *) loop[0])->is_instead &&
968  ((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
969  {
970  repairViewRuleLoop(loop[1], loop[0]);
971  return;
972  }
973 
974  /* Indirect loop involving view (but not matview) and ON SELECT rule */
975  if (nLoop > 2)
976  {
977  for (i = 0; i < nLoop; i++)
978  {
979  if (loop[i]->objType == DO_TABLE &&
980  ((TableInfo *) loop[i])->relkind == RELKIND_VIEW)
981  {
982  for (j = 0; j < nLoop; j++)
983  {
984  if (loop[j]->objType == DO_RULE &&
985  ((RuleInfo *) loop[j])->ev_type == '1' &&
986  ((RuleInfo *) loop[j])->is_instead &&
987  ((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
988  {
989  repairViewRuleMultiLoop(loop[i], loop[j]);
990  return;
991  }
992  }
993  }
994  }
995  }
996 
997  /* Indirect loop involving matview and data boundary */
998  if (nLoop > 2)
999  {
1000  for (i = 0; i < nLoop; i++)
1001  {
1002  if (loop[i]->objType == DO_TABLE &&
1003  ((TableInfo *) loop[i])->relkind == RELKIND_MATVIEW)
1004  {
1005  for (j = 0; j < nLoop; j++)
1006  {
1007  if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1008  {
1009  DumpableObject *nextobj;
1010 
1011  nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1012  repairMatViewBoundaryMultiLoop(loop[j], nextobj);
1013  return;
1014  }
1015  }
1016  }
1017  }
1018  }
1019 
1020  /* Indirect loop involving function and data boundary */
1021  if (nLoop > 2)
1022  {
1023  for (i = 0; i < nLoop; i++)
1024  {
1025  if (loop[i]->objType == DO_FUNC)
1026  {
1027  for (j = 0; j < nLoop; j++)
1028  {
1029  if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1030  {
1031  DumpableObject *nextobj;
1032 
1033  nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1034  repairFunctionBoundaryMultiLoop(loop[j], nextobj);
1035  return;
1036  }
1037  }
1038  }
1039  }
1040  }
1041 
1042  /* Table and CHECK constraint */
1043  if (nLoop == 2 &&
1044  loop[0]->objType == DO_TABLE &&
1045  loop[1]->objType == DO_CONSTRAINT &&
1046  ((ConstraintInfo *) loop[1])->contype == 'c' &&
1047  ((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
1048  {
1049  repairTableConstraintLoop(loop[0], loop[1]);
1050  return;
1051  }
1052  if (nLoop == 2 &&
1053  loop[1]->objType == DO_TABLE &&
1054  loop[0]->objType == DO_CONSTRAINT &&
1055  ((ConstraintInfo *) loop[0])->contype == 'c' &&
1056  ((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
1057  {
1058  repairTableConstraintLoop(loop[1], loop[0]);
1059  return;
1060  }
1061 
1062  /* Indirect loop involving table and CHECK constraint */
1063  if (nLoop > 2)
1064  {
1065  for (i = 0; i < nLoop; i++)
1066  {
1067  if (loop[i]->objType == DO_TABLE)
1068  {
1069  for (j = 0; j < nLoop; j++)
1070  {
1071  if (loop[j]->objType == DO_CONSTRAINT &&
1072  ((ConstraintInfo *) loop[j])->contype == 'c' &&
1073  ((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
1074  {
1075  repairTableConstraintMultiLoop(loop[i], loop[j]);
1076  return;
1077  }
1078  }
1079  }
1080  }
1081  }
1082 
1083  /* Table and attribute default */
1084  if (nLoop == 2 &&
1085  loop[0]->objType == DO_TABLE &&
1086  loop[1]->objType == DO_ATTRDEF &&
1087  ((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
1088  {
1089  repairTableAttrDefLoop(loop[0], loop[1]);
1090  return;
1091  }
1092  if (nLoop == 2 &&
1093  loop[1]->objType == DO_TABLE &&
1094  loop[0]->objType == DO_ATTRDEF &&
1095  ((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
1096  {
1097  repairTableAttrDefLoop(loop[1], loop[0]);
1098  return;
1099  }
1100 
1101  /* index on partitioned table and corresponding index on partition */
1102  if (nLoop == 2 &&
1103  loop[0]->objType == DO_INDEX &&
1104  loop[1]->objType == DO_INDEX)
1105  {
1106  if (((IndxInfo *) loop[0])->parentidx == loop[1]->catId.oid)
1107  {
1108  repairIndexLoop(loop[0], loop[1]);
1109  return;
1110  }
1111  else if (((IndxInfo *) loop[1])->parentidx == loop[0]->catId.oid)
1112  {
1113  repairIndexLoop(loop[1], loop[0]);
1114  return;
1115  }
1116  }
1117 
1118  /* Indirect loop involving table and attribute default */
1119  if (nLoop > 2)
1120  {
1121  for (i = 0; i < nLoop; i++)
1122  {
1123  if (loop[i]->objType == DO_TABLE)
1124  {
1125  for (j = 0; j < nLoop; j++)
1126  {
1127  if (loop[j]->objType == DO_ATTRDEF &&
1128  ((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
1129  {
1130  repairTableAttrDefMultiLoop(loop[i], loop[j]);
1131  return;
1132  }
1133  }
1134  }
1135  }
1136  }
1137 
1138  /* Domain and CHECK constraint */
1139  if (nLoop == 2 &&
1140  loop[0]->objType == DO_TYPE &&
1141  loop[1]->objType == DO_CONSTRAINT &&
1142  ((ConstraintInfo *) loop[1])->contype == 'c' &&
1143  ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
1144  {
1145  repairDomainConstraintLoop(loop[0], loop[1]);
1146  return;
1147  }
1148  if (nLoop == 2 &&
1149  loop[1]->objType == DO_TYPE &&
1150  loop[0]->objType == DO_CONSTRAINT &&
1151  ((ConstraintInfo *) loop[0])->contype == 'c' &&
1152  ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
1153  {
1154  repairDomainConstraintLoop(loop[1], loop[0]);
1155  return;
1156  }
1157 
1158  /* Indirect loop involving domain and CHECK constraint */
1159  if (nLoop > 2)
1160  {
1161  for (i = 0; i < nLoop; i++)
1162  {
1163  if (loop[i]->objType == DO_TYPE)
1164  {
1165  for (j = 0; j < nLoop; j++)
1166  {
1167  if (loop[j]->objType == DO_CONSTRAINT &&
1168  ((ConstraintInfo *) loop[j])->contype == 'c' &&
1169  ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
1170  {
1171  repairDomainConstraintMultiLoop(loop[i], loop[j]);
1172  return;
1173  }
1174  }
1175  }
1176  }
1177  }
1178 
1179  /*
1180  * Loop of table with itself --- just ignore it.
1181  *
1182  * (Actually, what this arises from is a dependency of a table column on
1183  * another column, which happened with generated columns before v15; or a
1184  * dependency of a table column on the whole table, which happens with
1185  * partitioning. But we didn't pay attention to sub-object IDs while
1186  * collecting the dependency data, so we can't see that here.)
1187  */
1188  if (nLoop == 1)
1189  {
1190  if (loop[0]->objType == DO_TABLE)
1191  {
1192  removeObjectDependency(loop[0], loop[0]->dumpId);
1193  return;
1194  }
1195  }
1196 
1197  /*
1198  * If all the objects are TABLE_DATA items, what we must have is a
1199  * circular set of foreign key constraints (or a single self-referential
1200  * table). Print an appropriate complaint and break the loop arbitrarily.
1201  */
1202  for (i = 0; i < nLoop; i++)
1203  {
1204  if (loop[i]->objType != DO_TABLE_DATA)
1205  break;
1206  }
1207  if (i >= nLoop)
1208  {
1209  pg_log_warning(ngettext("there are circular foreign-key constraints on this table:",
1210  "there are circular foreign-key constraints among these tables:",
1211  nLoop));
1212  for (i = 0; i < nLoop; i++)
1213  pg_log_warning_detail("%s", loop[i]->name);
1214  pg_log_warning_hint("You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.");
1215  pg_log_warning_hint("Consider using a full dump instead of a --data-only dump to avoid this problem.");
1216  if (nLoop > 1)
1217  removeObjectDependency(loop[0], loop[1]->dumpId);
1218  else /* must be a self-dependency */
1219  removeObjectDependency(loop[0], loop[0]->dumpId);
1220  return;
1221  }
1222 
1223  /*
1224  * If we can't find a principled way to break the loop, complain and break
1225  * it in an arbitrary fashion.
1226  */
1227  pg_log_warning("could not resolve dependency loop among these items:");
1228  for (i = 0; i < nLoop; i++)
1229  {
1230  char buf[1024];
1231 
1232  describeDumpableObject(loop[i], buf, sizeof(buf));
1233  pg_log_warning_detail("%s", buf);
1234  }
1235 
1236  if (nLoop > 1)
1237  removeObjectDependency(loop[0], loop[1]->dumpId);
1238  else /* must be a self-dependency */
1239  removeObjectDependency(loop[0], loop[0]->dumpId);
1240 }
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:808
#define ngettext(s, p, n)
Definition: c.h:1168
#define pg_log_warning_hint(...)
Definition: logging.h:121
#define pg_log_warning_detail(...)
Definition: logging.h:118
static void repairMatViewBoundaryMultiLoop(DumpableObject *boundaryobj, DumpableObject *nextobj)
Definition: pg_dump_sort.c:789
static void repairTableAttrDefLoop(DumpableObject *tableobj, DumpableObject *attrdefobj)
Definition: pg_dump_sort.c:867
static void repairTableConstraintLoop(DumpableObject *tableobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:833
static void repairTableAttrDefMultiLoop(DumpableObject *tableobj, DumpableObject *attrdefobj)
Definition: pg_dump_sort.c:875
static void repairViewRuleMultiLoop(DumpableObject *viewobj, DumpableObject *ruleobj)
Definition: pg_dump_sort.c:755
static void repairDomainConstraintLoop(DumpableObject *domainobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:890
static void repairTableConstraintMultiLoop(DumpableObject *tableobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:850
static void describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
static void repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
Definition: pg_dump_sort.c:704
static void repairDomainConstraintMultiLoop(DumpableObject *domainobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:898
static void repairIndexLoop(DumpableObject *partedindex, DumpableObject *partindex)
Definition: pg_dump_sort.c:912
static void repairViewRuleLoop(DumpableObject *viewobj, DumpableObject *ruleobj)
Definition: pg_dump_sort.c:735
static void repairFunctionBoundaryMultiLoop(DumpableObject *boundaryobj, DumpableObject *nextobj)
Definition: pg_dump_sort.c:812
#define pg_log_warning(...)
Definition: pgfnames.c:24
const char * name

References buf, describeDumpableObject(), DO_ATTRDEF, DO_CONSTRAINT, DO_FUNC, DO_INDEX, DO_PRE_DATA_BOUNDARY, DO_RULE, DO_TABLE, DO_TABLE_DATA, DO_TYPE, i, j, name, ngettext, pg_log_warning, pg_log_warning_detail, pg_log_warning_hint, removeObjectDependency(), repairDomainConstraintLoop(), repairDomainConstraintMultiLoop(), repairFunctionBoundaryMultiLoop(), repairIndexLoop(), repairMatViewBoundaryMultiLoop(), repairTableAttrDefLoop(), repairTableAttrDefMultiLoop(), repairTableConstraintLoop(), repairTableConstraintMultiLoop(), repairTypeFuncLoop(), repairViewRuleLoop(), and repairViewRuleMultiLoop().

Referenced by findDependencyLoops().

◆ repairDomainConstraintLoop()

static void repairDomainConstraintLoop ( DumpableObject domainobj,
DumpableObject constraintobj 
)
static

Definition at line 890 of file pg_dump_sort.c.

892 {
893  /* remove constraint's dependency on domain */
894  removeObjectDependency(constraintobj, domainobj->dumpId);
895 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairDomainConstraintMultiLoop()

static void repairDomainConstraintMultiLoop ( DumpableObject domainobj,
DumpableObject constraintobj 
)
static

Definition at line 898 of file pg_dump_sort.c.

900 {
901  /* remove domain's dependency on constraint */
902  removeObjectDependency(domainobj, constraintobj->dumpId);
903  /* mark constraint as needing its own dump */
904  ((ConstraintInfo *) constraintobj)->separate = true;
905  /* put back constraint's dependency on domain */
906  addObjectDependency(constraintobj, domainobj->dumpId);
907  /* now that constraint is separate, it must be post-data */
908  addObjectDependency(constraintobj, postDataBoundId);
909 }
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:783
static DumpId postDataBoundId
Definition: pg_dump_sort.c:160

References addObjectDependency(), _dumpableObject::dumpId, postDataBoundId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairFunctionBoundaryMultiLoop()

static void repairFunctionBoundaryMultiLoop ( DumpableObject boundaryobj,
DumpableObject nextobj 
)
static

Definition at line 812 of file pg_dump_sort.c.

814 {
815  /* remove boundary's dependency on object after it in loop */
816  removeObjectDependency(boundaryobj, nextobj->dumpId);
817  /* if that object is a function, mark it as postponed into post-data */
818  if (nextobj->objType == DO_FUNC)
819  {
820  FuncInfo *nextinfo = (FuncInfo *) nextobj;
821 
822  nextinfo->postponed_def = true;
823  }
824 }
bool postponed_def
Definition: pg_dump.h:231

References DO_FUNC, _dumpableObject::dumpId, _dumpableObject::objType, _funcInfo::postponed_def, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairIndexLoop()

static void repairIndexLoop ( DumpableObject partedindex,
DumpableObject partindex 
)
static

Definition at line 912 of file pg_dump_sort.c.

914 {
915  removeObjectDependency(partedindex, partindex->dumpId);
916 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairMatViewBoundaryMultiLoop()

static void repairMatViewBoundaryMultiLoop ( DumpableObject boundaryobj,
DumpableObject nextobj 
)
static

Definition at line 789 of file pg_dump_sort.c.

791 {
792  /* remove boundary's dependency on object after it in loop */
793  removeObjectDependency(boundaryobj, nextobj->dumpId);
794  /* if that object is a matview, mark it as postponed into post-data */
795  if (nextobj->objType == DO_TABLE)
796  {
797  TableInfo *nextinfo = (TableInfo *) nextobj;
798 
799  if (nextinfo->relkind == RELKIND_MATVIEW)
800  nextinfo->postponed_def = true;
801  }
802 }
char relkind
Definition: pg_dump.h:288
bool postponed_def
Definition: pg_dump.h:321

References DO_TABLE, _dumpableObject::dumpId, _dumpableObject::objType, _tableInfo::postponed_def, _tableInfo::relkind, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableAttrDefLoop()

static void repairTableAttrDefLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
)
static

Definition at line 867 of file pg_dump_sort.c.

869 {
870  /* remove attrdef's dependency on table */
871  removeObjectDependency(attrdefobj, tableobj->dumpId);
872 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableAttrDefMultiLoop()

static void repairTableAttrDefMultiLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
)
static

Definition at line 875 of file pg_dump_sort.c.

877 {
878  /* remove table's dependency on attrdef */
879  removeObjectDependency(tableobj, attrdefobj->dumpId);
880  /* mark attrdef as needing its own dump */
881  ((AttrDefInfo *) attrdefobj)->separate = true;
882  /* put back attrdef's dependency on table */
883  addObjectDependency(attrdefobj, tableobj->dumpId);
884 }

References addObjectDependency(), _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableConstraintLoop()

static void repairTableConstraintLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
)
static

Definition at line 833 of file pg_dump_sort.c.

835 {
836  /* remove constraint's dependency on table */
837  removeObjectDependency(constraintobj, tableobj->dumpId);
838 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableConstraintMultiLoop()

static void repairTableConstraintMultiLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
)
static

Definition at line 850 of file pg_dump_sort.c.

852 {
853  /* remove table's dependency on constraint */
854  removeObjectDependency(tableobj, constraintobj->dumpId);
855  /* mark constraint as needing its own dump */
856  ((ConstraintInfo *) constraintobj)->separate = true;
857  /* put back constraint's dependency on table */
858  addObjectDependency(constraintobj, tableobj->dumpId);
859  /* now that constraint is separate, it must be post-data */
860  addObjectDependency(constraintobj, postDataBoundId);
861 }

References addObjectDependency(), _dumpableObject::dumpId, postDataBoundId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTypeFuncLoop()

static void repairTypeFuncLoop ( DumpableObject typeobj,
DumpableObject funcobj 
)
static

Definition at line 704 of file pg_dump_sort.c.

705 {
706  TypeInfo *typeInfo = (TypeInfo *) typeobj;
707 
708  /* remove function's dependency on type */
709  removeObjectDependency(funcobj, typeobj->dumpId);
710 
711  /* add function's dependency on shell type, instead */
712  if (typeInfo->shellType)
713  {
714  addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
715 
716  /*
717  * Mark shell type (always including the definition, as we need the
718  * shell type defined to identify the function fully) as to be dumped
719  * if any such function is
720  */
721  if (funcobj->dump)
722  typeInfo->shellType->dobj.dump = funcobj->dump |
724  }
725 }
#define DUMP_COMPONENT_DEFINITION
Definition: pg_dump.h:97
DumpComponents dump
Definition: pg_dump.h:139
DumpableObject dobj
Definition: pg_dump.h:217
struct _shellTypeInfo * shellType
Definition: pg_dump.h:209

References addObjectDependency(), _shellTypeInfo::dobj, _dumpableObject::dump, DUMP_COMPONENT_DEFINITION, _dumpableObject::dumpId, removeObjectDependency(), and _typeInfo::shellType.

Referenced by repairDependencyLoop().

◆ repairViewRuleLoop()

static void repairViewRuleLoop ( DumpableObject viewobj,
DumpableObject ruleobj 
)
static

Definition at line 735 of file pg_dump_sort.c.

737 {
738  /* remove rule's dependency on view */
739  removeObjectDependency(ruleobj, viewobj->dumpId);
740  /* flags on the two objects are already set correctly for this case */
741 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairViewRuleMultiLoop()

static void repairViewRuleMultiLoop ( DumpableObject viewobj,
DumpableObject ruleobj 
)
static

Definition at line 755 of file pg_dump_sort.c.

757 {
758  TableInfo *viewinfo = (TableInfo *) viewobj;
759  RuleInfo *ruleinfo = (RuleInfo *) ruleobj;
760 
761  /* remove view's dependency on rule */
762  removeObjectDependency(viewobj, ruleobj->dumpId);
763  /* mark view to be printed with a dummy definition */
764  viewinfo->dummy_view = true;
765  /* mark rule as needing its own dump */
766  ruleinfo->separate = true;
767  /* put back rule's dependency on view */
768  addObjectDependency(ruleobj, viewobj->dumpId);
769  /* now that rule is separate, it must be post-data */
771 }
bool separate
Definition: pg_dump.h:439
bool dummy_view
Definition: pg_dump.h:320

References addObjectDependency(), _tableInfo::dummy_view, _dumpableObject::dumpId, postDataBoundId, removeObjectDependency(), and _ruleInfo::separate.

Referenced by repairDependencyLoop().

◆ sortDumpableObjects()

void sortDumpableObjects ( DumpableObject **  objs,
int  numObjs,
DumpId  preBoundaryId,
DumpId  postBoundaryId 
)

Definition at line 322 of file pg_dump_sort.c.

324 {
325  DumpableObject **ordering;
326  int nOrdering;
327 
328  if (numObjs <= 0) /* can't happen anymore ... */
329  return;
330 
331  /*
332  * Saving the boundary IDs in static variables is a bit grotty, but seems
333  * better than adding them to parameter lists of subsidiary functions.
334  */
335  preDataBoundId = preBoundaryId;
336  postDataBoundId = postBoundaryId;
337 
338  ordering = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
339  while (!TopoSort(objs, numObjs, ordering, &nOrdering))
340  findDependencyLoops(ordering, nOrdering, numObjs);
341 
342  memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
343 
344  free(ordering);
345 }
static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
Definition: pg_dump_sort.c:523
static DumpId preDataBoundId
Definition: pg_dump_sort.c:159
static bool TopoSort(DumpableObject **objs, int numObjs, DumpableObject **ordering, int *nOrdering)
Definition: pg_dump_sort.c:374

References findDependencyLoops(), free, pg_malloc(), postDataBoundId, preDataBoundId, and TopoSort().

Referenced by main().

◆ sortDumpableObjectsByTypeName()

void sortDumpableObjectsByTypeName ( DumpableObject **  objs,
int  numObjs 
)

Definition at line 189 of file pg_dump_sort.c.

190 {
191  if (numObjs > 1)
192  qsort(objs, numObjs, sizeof(DumpableObject *),
194 }
static int DOTypeNameCompare(const void *p1, const void *p2)
Definition: pg_dump_sort.c:197
#define qsort(a, b, c, d)
Definition: port.h:449

References DOTypeNameCompare(), and qsort.

Referenced by main().

◆ StaticAssertDecl()

StaticAssertDecl ( lengthof(dbObjectTypePriority = =(DO_SUBSCRIPTION_REL+1),
"array length mismatch"   
)

◆ TopoSort()

static bool TopoSort ( DumpableObject **  objs,
int  numObjs,
DumpableObject **  ordering,
int *  nOrdering 
)
static

Definition at line 374 of file pg_dump_sort.c.

378 {
379  DumpId maxDumpId = getMaxDumpId();
380  binaryheap *pendingHeap;
381  int *beforeConstraints;
382  int *idMap;
383  DumpableObject *obj;
384  int i,
385  j,
386  k;
387 
388  /*
389  * This is basically the same algorithm shown for topological sorting in
390  * Knuth's Volume 1. However, we would like to minimize unnecessary
391  * rearrangement of the input ordering; that is, when we have a choice of
392  * which item to output next, we always want to take the one highest in
393  * the original list. Therefore, instead of maintaining an unordered
394  * linked list of items-ready-to-output as Knuth does, we maintain a heap
395  * of their item numbers, which we can use as a priority queue. This
396  * turns the algorithm from O(N) to O(N log N) because each insertion or
397  * removal of a heap item takes O(log N) time. However, that's still
398  * plenty fast enough for this application.
399  */
400 
401  *nOrdering = numObjs; /* for success return */
402 
403  /* Eliminate the null case */
404  if (numObjs <= 0)
405  return true;
406 
407  /* Create workspace for the above-described heap */
408  pendingHeap = binaryheap_allocate(numObjs, int_cmp, NULL);
409 
410  /*
411  * Scan the constraints, and for each item in the input, generate a count
412  * of the number of constraints that say it must be before something else.
413  * The count for the item with dumpId j is stored in beforeConstraints[j].
414  * We also make a map showing the input-order index of the item with
415  * dumpId j.
416  */
417  beforeConstraints = (int *) pg_malloc0((maxDumpId + 1) * sizeof(int));
418  idMap = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
419  for (i = 0; i < numObjs; i++)
420  {
421  obj = objs[i];
422  j = obj->dumpId;
423  if (j <= 0 || j > maxDumpId)
424  pg_fatal("invalid dumpId %d", j);
425  idMap[j] = i;
426  for (j = 0; j < obj->nDeps; j++)
427  {
428  k = obj->dependencies[j];
429  if (k <= 0 || k > maxDumpId)
430  pg_fatal("invalid dependency %d", k);
431  beforeConstraints[k]++;
432  }
433  }
434 
435  /*
436  * Now initialize the heap of items-ready-to-output by filling it with the
437  * indexes of items that already have beforeConstraints[id] == 0.
438  *
439  * We enter the indexes into pendingHeap in decreasing order so that the
440  * heap invariant is satisfied at the completion of this loop. This
441  * reduces the amount of work that binaryheap_build() must do.
442  */
443  for (i = numObjs; --i >= 0;)
444  {
445  if (beforeConstraints[objs[i]->dumpId] == 0)
446  binaryheap_add_unordered(pendingHeap, (void *) (intptr_t) i);
447  }
448  binaryheap_build(pendingHeap);
449 
450  /*--------------------
451  * Now emit objects, working backwards in the output list. At each step,
452  * we use the priority heap to select the last item that has no remaining
453  * before-constraints. We remove that item from the heap, output it to
454  * ordering[], and decrease the beforeConstraints count of each of the
455  * items it was constrained against. Whenever an item's beforeConstraints
456  * count is thereby decreased to zero, we insert it into the priority heap
457  * to show that it is a candidate to output. We are done when the heap
458  * becomes empty; if we have output every element then we succeeded,
459  * otherwise we failed.
460  * i = number of ordering[] entries left to output
461  * j = objs[] index of item we are outputting
462  * k = temp for scanning constraint list for item j
463  *--------------------
464  */
465  i = numObjs;
466  while (!binaryheap_empty(pendingHeap))
467  {
468  /* Select object to output by removing largest heap member */
469  j = (int) (intptr_t) binaryheap_remove_first(pendingHeap);
470  obj = objs[j];
471  /* Output candidate to ordering[] */
472  ordering[--i] = obj;
473  /* Update beforeConstraints counts of its predecessors */
474  for (k = 0; k < obj->nDeps; k++)
475  {
476  int id = obj->dependencies[k];
477 
478  if ((--beforeConstraints[id]) == 0)
479  binaryheap_add(pendingHeap, (void *) (intptr_t) idMap[id]);
480  }
481  }
482 
483  /*
484  * If we failed, report the objects that couldn't be output; these are the
485  * ones with beforeConstraints[] still nonzero.
486  */
487  if (i != 0)
488  {
489  k = 0;
490  for (j = 1; j <= maxDumpId; j++)
491  {
492  if (beforeConstraints[j] != 0)
493  ordering[k++] = objs[idMap[j]];
494  }
495  *nOrdering = k;
496  }
497 
498  /* Done */
499  binaryheap_free(pendingHeap);
501  free(idMap);
502 
503  return (i == 0);
504 }
void binaryheap_build(binaryheap *heap)
Definition: binaryheap.c:138
void binaryheap_add(binaryheap *heap, bh_node_type d)
Definition: binaryheap.c:154
bh_node_type binaryheap_remove_first(binaryheap *heap)
Definition: binaryheap.c:192
binaryheap * binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
Definition: binaryheap.c:39
void binaryheap_free(binaryheap *heap)
Definition: binaryheap.c:75
void binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
Definition: binaryheap.c:116
#define binaryheap_empty(h)
Definition: binaryheap.h:65
static int * beforeConstraints
Definition: deadlock.c:107
static int int_cmp(void *a, void *b, void *arg)

References beforeConstraints, binaryheap_add(), binaryheap_add_unordered(), binaryheap_allocate(), binaryheap_build(), binaryheap_empty, binaryheap_free(), binaryheap_remove_first(), _dumpableObject::dependencies, _dumpableObject::dumpId, free, getMaxDumpId(), i, int_cmp(), j, _dumpableObject::nDeps, pg_fatal, pg_malloc(), and pg_malloc0().

Referenced by sortDumpableObjects().

Variable Documentation

◆ dbObjectTypePriority

const int dbObjectTypePriority[]
static

Definition at line 105 of file pg_dump_sort.c.

Referenced by DOTypeNameCompare().

◆ postDataBoundId

◆ preDataBoundId

DumpId preDataBoundId
static

Definition at line 159 of file pg_dump_sort.c.

Referenced by sortDumpableObjects().