PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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_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 54 of file pg_dump_sort.c.

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

Function Documentation

◆ describeDumpableObject()

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

Definition at line 1258 of file pg_dump_sort.c.

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

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

Referenced by sortDumpableObjectsByTypeName().

◆ findDependencyLoops()

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

Definition at line 533 of file pg_dump_sort.c.

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

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 629 of file pg_dump_sort.c.

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

1514 {
1515  int ai = (int) (intptr_t) a;
1516  int bi = (int) (intptr_t) b;
1517 
1518  return pg_cmp_s32(ai, bi);
1519 }
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:598
int b
Definition: isn.c:69
int a
Definition: isn.c:68

References a, b, and pg_cmp_s32().

Referenced by TopoSort().

◆ repairDependencyLoop()

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

Definition at line 936 of file pg_dump_sort.c.

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

902 {
903  /* remove constraint's dependency on domain */
904  removeObjectDependency(constraintobj, domainobj->dumpId);
905 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairDomainConstraintMultiLoop()

static void repairDomainConstraintMultiLoop ( DumpableObject domainobj,
DumpableObject constraintobj 
)
static

Definition at line 908 of file pg_dump_sort.c.

910 {
911  /* remove domain's dependency on constraint */
912  removeObjectDependency(domainobj, constraintobj->dumpId);
913  /* mark constraint as needing its own dump */
914  ((ConstraintInfo *) constraintobj)->separate = true;
915  /* put back constraint's dependency on domain */
916  addObjectDependency(constraintobj, domainobj->dumpId);
917  /* now that constraint is separate, it must be post-data */
918  addObjectDependency(constraintobj, postDataBoundId);
919 }
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:795
static DumpId postDataBoundId
Definition: pg_dump_sort.c:159

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

Referenced by repairDependencyLoop().

◆ repairFunctionBoundaryMultiLoop()

static void repairFunctionBoundaryMultiLoop ( DumpableObject boundaryobj,
DumpableObject nextobj 
)
static

Definition at line 822 of file pg_dump_sort.c.

824 {
825  /* remove boundary's dependency on object after it in loop */
826  removeObjectDependency(boundaryobj, nextobj->dumpId);
827  /* if that object is a function, mark it as postponed into post-data */
828  if (nextobj->objType == DO_FUNC)
829  {
830  FuncInfo *nextinfo = (FuncInfo *) nextobj;
831 
832  nextinfo->postponed_def = true;
833  }
834 }
bool postponed_def
Definition: pg_dump.h:232

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 922 of file pg_dump_sort.c.

924 {
925  removeObjectDependency(partedindex, partindex->dumpId);
926 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairMatViewBoundaryMultiLoop()

static void repairMatViewBoundaryMultiLoop ( DumpableObject boundaryobj,
DumpableObject nextobj 
)
static

Definition at line 799 of file pg_dump_sort.c.

801 {
802  /* remove boundary's dependency on object after it in loop */
803  removeObjectDependency(boundaryobj, nextobj->dumpId);
804  /* if that object is a matview, mark it as postponed into post-data */
805  if (nextobj->objType == DO_TABLE)
806  {
807  TableInfo *nextinfo = (TableInfo *) nextobj;
808 
809  if (nextinfo->relkind == RELKIND_MATVIEW)
810  nextinfo->postponed_def = true;
811  }
812 }
char relkind
Definition: pg_dump.h:289
bool postponed_def
Definition: pg_dump.h:322

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 877 of file pg_dump_sort.c.

879 {
880  /* remove attrdef's dependency on table */
881  removeObjectDependency(attrdefobj, tableobj->dumpId);
882 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableAttrDefMultiLoop()

static void repairTableAttrDefMultiLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
)
static

Definition at line 885 of file pg_dump_sort.c.

887 {
888  /* remove table's dependency on attrdef */
889  removeObjectDependency(tableobj, attrdefobj->dumpId);
890  /* mark attrdef as needing its own dump */
891  ((AttrDefInfo *) attrdefobj)->separate = true;
892  /* put back attrdef's dependency on table */
893  addObjectDependency(attrdefobj, tableobj->dumpId);
894 }

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

Referenced by repairDependencyLoop().

◆ repairTableConstraintLoop()

static void repairTableConstraintLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
)
static

Definition at line 843 of file pg_dump_sort.c.

845 {
846  /* remove constraint's dependency on table */
847  removeObjectDependency(constraintobj, tableobj->dumpId);
848 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableConstraintMultiLoop()

static void repairTableConstraintMultiLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
)
static

Definition at line 860 of file pg_dump_sort.c.

862 {
863  /* remove table's dependency on constraint */
864  removeObjectDependency(tableobj, constraintobj->dumpId);
865  /* mark constraint as needing its own dump */
866  ((ConstraintInfo *) constraintobj)->separate = true;
867  /* put back constraint's dependency on table */
868  addObjectDependency(constraintobj, tableobj->dumpId);
869  /* now that constraint is separate, it must be post-data */
870  addObjectDependency(constraintobj, postDataBoundId);
871 }

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

Referenced by repairDependencyLoop().

◆ repairTypeFuncLoop()

static void repairTypeFuncLoop ( DumpableObject typeobj,
DumpableObject funcobj 
)
static

Definition at line 714 of file pg_dump_sort.c.

715 {
716  TypeInfo *typeInfo = (TypeInfo *) typeobj;
717 
718  /* remove function's dependency on type */
719  removeObjectDependency(funcobj, typeobj->dumpId);
720 
721  /* add function's dependency on shell type, instead */
722  if (typeInfo->shellType)
723  {
724  addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
725 
726  /*
727  * Mark shell type (always including the definition, as we need the
728  * shell type defined to identify the function fully) as to be dumped
729  * if any such function is
730  */
731  if (funcobj->dump)
732  typeInfo->shellType->dobj.dump = funcobj->dump |
734  }
735 }
#define DUMP_COMPONENT_DEFINITION
Definition: pg_dump.h:97
DumpComponents dump
Definition: pg_dump.h:139
DumpableObject dobj
Definition: pg_dump.h:218
struct _shellTypeInfo * shellType
Definition: pg_dump.h:210

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 745 of file pg_dump_sort.c.

747 {
748  /* remove rule's dependency on view */
749  removeObjectDependency(ruleobj, viewobj->dumpId);
750  /* flags on the two objects are already set correctly for this case */
751 }

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairViewRuleMultiLoop()

static void repairViewRuleMultiLoop ( DumpableObject viewobj,
DumpableObject ruleobj 
)
static

Definition at line 765 of file pg_dump_sort.c.

767 {
768  TableInfo *viewinfo = (TableInfo *) viewobj;
769  RuleInfo *ruleinfo = (RuleInfo *) ruleobj;
770 
771  /* remove view's dependency on rule */
772  removeObjectDependency(viewobj, ruleobj->dumpId);
773  /* mark view to be printed with a dummy definition */
774  viewinfo->dummy_view = true;
775  /* mark rule as needing its own dump */
776  ruleinfo->separate = true;
777  /* put back rule's dependency on view */
778  addObjectDependency(ruleobj, viewobj->dumpId);
779  /* now that rule is separate, it must be post-data */
781 }
bool separate
Definition: pg_dump.h:439
bool dummy_view
Definition: pg_dump.h:321

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 332 of file pg_dump_sort.c.

334 {
335  DumpableObject **ordering;
336  int nOrdering;
337 
338  if (numObjs <= 0) /* can't happen anymore ... */
339  return;
340 
341  /*
342  * Saving the boundary IDs in static variables is a bit grotty, but seems
343  * better than adding them to parameter lists of subsidiary functions.
344  */
345  preDataBoundId = preBoundaryId;
346  postDataBoundId = postBoundaryId;
347 
348  ordering = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
349  while (!TopoSort(objs, numObjs, ordering, &nOrdering))
350  findDependencyLoops(ordering, nOrdering, numObjs);
351 
352  memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
353 
354  free(ordering);
355 }
static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
Definition: pg_dump_sort.c:533
static DumpId preDataBoundId
Definition: pg_dump_sort.c:158
static bool TopoSort(DumpableObject **objs, int numObjs, DumpableObject **ordering, int *nOrdering)
Definition: pg_dump_sort.c:384

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

Referenced by main().

◆ sortDumpableObjectsByTypeName()

void sortDumpableObjectsByTypeName ( DumpableObject **  objs,
int  numObjs 
)

Definition at line 188 of file pg_dump_sort.c.

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

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 384 of file pg_dump_sort.c.

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

Referenced by DOTypeNameCompare().

◆ postDataBoundId

◆ preDataBoundId

DumpId preDataBoundId
static

Definition at line 158 of file pg_dump_sort.c.

Referenced by sortDumpableObjects().