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_PRE_DATA_BOUNDARY ,
  PRIO_TABLE_DATA , PRIO_SEQUENCE_SET , PRIO_LARGE_OBJECT , PRIO_LARGE_OBJECT_DATA ,
  PRIO_STATISTICS_DATA_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)==NUM_DUMPABLE_OBJECT_TYPES, "array length mismatch")
 
static int DOTypeNameCompare (const void *p1, const void *p2)
 
static int pgTypeNameCompare (Oid typid1, Oid typid2)
 
static int accessMethodNameCompare (Oid am1, Oid am2)
 
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_PRE_DATA_BOUNDARY 
PRIO_TABLE_DATA 
PRIO_SEQUENCE_SET 
PRIO_LARGE_OBJECT 
PRIO_LARGE_OBJECT_DATA 
PRIO_STATISTICS_DATA_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{
61 PRIO_TYPE, /* used for DO_TYPE and DO_SHELL_TYPE */
67 PRIO_OPFAMILY, /* used for DO_OPFAMILY and DO_OPCLASS */
79 PRIO_PRE_DATA_BOUNDARY, /* boundary! */
85 PRIO_POST_DATA_BOUNDARY, /* boundary! */
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:73
@ 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_STATISTICS_DATA_DATA
Definition: pg_dump_sort.c:84
@ PRIO_TSCONFIG
Definition: pg_dump_sort.c:72
@ 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:75
@ PRIO_DEFAULT_ACL
Definition: pg_dump_sort.c:99
@ 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:82
@ PRIO_CONVERSION
Definition: pg_dump_sort.c:68
@ PRIO_FUNC
Definition: pg_dump_sort.c:63
@ 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: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:90
@ PRIO_NAMESPACE
Definition: pg_dump_sort.c:56
@ PRIO_PUBLICATION_REL
Definition: pg_dump_sort.c:95
@ PRIO_FOREIGN_SERVER
Definition: pg_dump_sort.c:74
@ PRIO_SEQUENCE_SET
Definition: pg_dump_sort.c:81
@ 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:79
@ PRIO_COLLATION
Definition: pg_dump_sort.c:58
@ PRIO_INDEX
Definition: pg_dump_sort.c:87
@ PRIO_TRIGGER
Definition: pg_dump_sort.c:91
@ 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:80
@ PRIO_TABLE_ATTACH
Definition: pg_dump_sort.c:76

Function Documentation

◆ accessMethodNameCompare()

static int accessMethodNameCompare ( Oid  am1,
Oid  am2 
)
static

Definition at line 518 of file pg_dump_sort.c.

519{
520 AccessMethodInfo *amobj1;
521 AccessMethodInfo *amobj2;
522
523 if (am1 == am2)
524 return 0;
525
526 amobj1 = findAccessMethodByOid(am1);
527 amobj2 = findAccessMethodByOid(am2);
528
529 if (!amobj1 || !amobj2)
530 {
531 /* catalog corruption: handle like pgTypeNameCompare() does */
532 Assert(false);
533 return 0;
534 }
535
536 return strcmp(amobj1->dobj.name, amobj2->dobj.name);
537}
AccessMethodInfo * findAccessMethodByOid(Oid oid)
Definition: common.c:954
Assert(PointerIsAligned(start, uint64))
DumpableObject dobj
Definition: pg_dump.h:270
char * name
Definition: pg_dump.h:152

References Assert(), _accessMethodInfo::dobj, findAccessMethodByOid(), and _dumpableObject::name.

Referenced by DOTypeNameCompare().

◆ describeDumpableObject()

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

Definition at line 1503 of file pg_dump_sort.c.

1504{
1505 switch (obj->objType)
1506 {
1507 case DO_NAMESPACE:
1509 "SCHEMA %s (ID %d OID %u)",
1510 obj->name, obj->dumpId, obj->catId.oid);
1511 return;
1512 case DO_EXTENSION:
1514 "EXTENSION %s (ID %d OID %u)",
1515 obj->name, obj->dumpId, obj->catId.oid);
1516 return;
1517 case DO_TYPE:
1519 "TYPE %s (ID %d OID %u)",
1520 obj->name, obj->dumpId, obj->catId.oid);
1521 return;
1522 case DO_SHELL_TYPE:
1524 "SHELL TYPE %s (ID %d OID %u)",
1525 obj->name, obj->dumpId, obj->catId.oid);
1526 return;
1527 case DO_FUNC:
1529 "FUNCTION %s (ID %d OID %u)",
1530 obj->name, obj->dumpId, obj->catId.oid);
1531 return;
1532 case DO_AGG:
1534 "AGGREGATE %s (ID %d OID %u)",
1535 obj->name, obj->dumpId, obj->catId.oid);
1536 return;
1537 case DO_OPERATOR:
1539 "OPERATOR %s (ID %d OID %u)",
1540 obj->name, obj->dumpId, obj->catId.oid);
1541 return;
1542 case DO_ACCESS_METHOD:
1544 "ACCESS METHOD %s (ID %d OID %u)",
1545 obj->name, obj->dumpId, obj->catId.oid);
1546 return;
1547 case DO_OPCLASS:
1549 "OPERATOR CLASS %s (ID %d OID %u)",
1550 obj->name, obj->dumpId, obj->catId.oid);
1551 return;
1552 case DO_OPFAMILY:
1554 "OPERATOR FAMILY %s (ID %d OID %u)",
1555 obj->name, obj->dumpId, obj->catId.oid);
1556 return;
1557 case DO_COLLATION:
1559 "COLLATION %s (ID %d OID %u)",
1560 obj->name, obj->dumpId, obj->catId.oid);
1561 return;
1562 case DO_CONVERSION:
1564 "CONVERSION %s (ID %d OID %u)",
1565 obj->name, obj->dumpId, obj->catId.oid);
1566 return;
1567 case DO_TABLE:
1569 "TABLE %s (ID %d OID %u)",
1570 obj->name, obj->dumpId, obj->catId.oid);
1571 return;
1572 case DO_TABLE_ATTACH:
1574 "TABLE ATTACH %s (ID %d)",
1575 obj->name, obj->dumpId);
1576 return;
1577 case DO_ATTRDEF:
1579 "ATTRDEF %s.%s (ID %d OID %u)",
1580 ((AttrDefInfo *) obj)->adtable->dobj.name,
1581 ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
1582 obj->dumpId, obj->catId.oid);
1583 return;
1584 case DO_INDEX:
1586 "INDEX %s (ID %d OID %u)",
1587 obj->name, obj->dumpId, obj->catId.oid);
1588 return;
1589 case DO_INDEX_ATTACH:
1591 "INDEX ATTACH %s (ID %d)",
1592 obj->name, obj->dumpId);
1593 return;
1594 case DO_STATSEXT:
1596 "STATISTICS %s (ID %d OID %u)",
1597 obj->name, obj->dumpId, obj->catId.oid);
1598 return;
1599 case DO_REFRESH_MATVIEW:
1601 "REFRESH MATERIALIZED VIEW %s (ID %d OID %u)",
1602 obj->name, obj->dumpId, obj->catId.oid);
1603 return;
1604 case DO_RULE:
1606 "RULE %s (ID %d OID %u)",
1607 obj->name, obj->dumpId, obj->catId.oid);
1608 return;
1609 case DO_TRIGGER:
1611 "TRIGGER %s (ID %d OID %u)",
1612 obj->name, obj->dumpId, obj->catId.oid);
1613 return;
1614 case DO_EVENT_TRIGGER:
1616 "EVENT TRIGGER %s (ID %d OID %u)",
1617 obj->name, obj->dumpId, obj->catId.oid);
1618 return;
1619 case DO_CONSTRAINT:
1621 "CONSTRAINT %s (ID %d OID %u)",
1622 obj->name, obj->dumpId, obj->catId.oid);
1623 return;
1624 case DO_FK_CONSTRAINT:
1626 "FK CONSTRAINT %s (ID %d OID %u)",
1627 obj->name, obj->dumpId, obj->catId.oid);
1628 return;
1629 case DO_PROCLANG:
1631 "PROCEDURAL LANGUAGE %s (ID %d OID %u)",
1632 obj->name, obj->dumpId, obj->catId.oid);
1633 return;
1634 case DO_CAST:
1636 "CAST %u to %u (ID %d OID %u)",
1637 ((CastInfo *) obj)->castsource,
1638 ((CastInfo *) obj)->casttarget,
1639 obj->dumpId, obj->catId.oid);
1640 return;
1641 case DO_TRANSFORM:
1643 "TRANSFORM %u lang %u (ID %d OID %u)",
1644 ((TransformInfo *) obj)->trftype,
1645 ((TransformInfo *) obj)->trflang,
1646 obj->dumpId, obj->catId.oid);
1647 return;
1648 case DO_TABLE_DATA:
1650 "TABLE DATA %s (ID %d OID %u)",
1651 obj->name, obj->dumpId, obj->catId.oid);
1652 return;
1653 case DO_SEQUENCE_SET:
1655 "SEQUENCE SET %s (ID %d OID %u)",
1656 obj->name, obj->dumpId, obj->catId.oid);
1657 return;
1658 case DO_DUMMY_TYPE:
1660 "DUMMY TYPE %s (ID %d OID %u)",
1661 obj->name, obj->dumpId, obj->catId.oid);
1662 return;
1663 case DO_TSPARSER:
1665 "TEXT SEARCH PARSER %s (ID %d OID %u)",
1666 obj->name, obj->dumpId, obj->catId.oid);
1667 return;
1668 case DO_TSDICT:
1670 "TEXT SEARCH DICTIONARY %s (ID %d OID %u)",
1671 obj->name, obj->dumpId, obj->catId.oid);
1672 return;
1673 case DO_TSTEMPLATE:
1675 "TEXT SEARCH TEMPLATE %s (ID %d OID %u)",
1676 obj->name, obj->dumpId, obj->catId.oid);
1677 return;
1678 case DO_TSCONFIG:
1680 "TEXT SEARCH CONFIGURATION %s (ID %d OID %u)",
1681 obj->name, obj->dumpId, obj->catId.oid);
1682 return;
1683 case DO_FDW:
1685 "FOREIGN DATA WRAPPER %s (ID %d OID %u)",
1686 obj->name, obj->dumpId, obj->catId.oid);
1687 return;
1688 case DO_FOREIGN_SERVER:
1690 "FOREIGN SERVER %s (ID %d OID %u)",
1691 obj->name, obj->dumpId, obj->catId.oid);
1692 return;
1693 case DO_DEFAULT_ACL:
1695 "DEFAULT ACL %s (ID %d OID %u)",
1696 obj->name, obj->dumpId, obj->catId.oid);
1697 return;
1698 case DO_LARGE_OBJECT:
1700 "LARGE OBJECT (ID %d OID %u)",
1701 obj->dumpId, obj->catId.oid);
1702 return;
1705 "LARGE OBJECT DATA (ID %d)",
1706 obj->dumpId);
1707 return;
1708 case DO_POLICY:
1710 "POLICY (ID %d OID %u)",
1711 obj->dumpId, obj->catId.oid);
1712 return;
1713 case DO_PUBLICATION:
1715 "PUBLICATION (ID %d OID %u)",
1716 obj->dumpId, obj->catId.oid);
1717 return;
1718 case DO_PUBLICATION_REL:
1720 "PUBLICATION TABLE (ID %d OID %u)",
1721 obj->dumpId, obj->catId.oid);
1722 return;
1725 "PUBLICATION TABLES IN SCHEMA (ID %d OID %u)",
1726 obj->dumpId, obj->catId.oid);
1727 return;
1728 case DO_SUBSCRIPTION:
1730 "SUBSCRIPTION (ID %d OID %u)",
1731 obj->dumpId, obj->catId.oid);
1732 return;
1735 "SUBSCRIPTION TABLE (ID %d OID %u)",
1736 obj->dumpId, obj->catId.oid);
1737 return;
1740 "PRE-DATA BOUNDARY (ID %d)",
1741 obj->dumpId);
1742 return;
1745 "POST-DATA BOUNDARY (ID %d)",
1746 obj->dumpId);
1747 return;
1748 case DO_REL_STATS:
1750 "RELATION STATISTICS FOR %s (ID %d OID %u)",
1751 obj->name, obj->dumpId, obj->catId.oid);
1752 return;
1753 }
1754 /* shouldn't get here */
1756 "object type %d (ID %d OID %u)",
1757 (int) obj->objType,
1758 obj->dumpId, obj->catId.oid);
1759}
#define bufsize
Definition: indent_globs.h:36
@ DO_EVENT_TRIGGER
Definition: pg_dump.h:80
@ DO_REFRESH_MATVIEW
Definition: pg_dump.h:81
@ DO_POLICY
Definition: pg_dump.h:82
@ DO_CAST
Definition: pg_dump.h:64
@ DO_FOREIGN_SERVER
Definition: pg_dump.h:73
@ DO_PRE_DATA_BOUNDARY
Definition: pg_dump.h:78
@ DO_PROCLANG
Definition: pg_dump.h:63
@ DO_TYPE
Definition: pg_dump.h:43
@ DO_INDEX
Definition: pg_dump.h:56
@ DO_COLLATION
Definition: pg_dump.h:51
@ DO_LARGE_OBJECT
Definition: pg_dump.h:76
@ DO_TSCONFIG
Definition: pg_dump.h:71
@ DO_OPERATOR
Definition: pg_dump.h:47
@ DO_FK_CONSTRAINT
Definition: pg_dump.h:62
@ DO_CONSTRAINT
Definition: pg_dump.h:61
@ DO_SUBSCRIPTION
Definition: pg_dump.h:87
@ DO_DEFAULT_ACL
Definition: pg_dump.h:74
@ DO_FDW
Definition: pg_dump.h:72
@ DO_SUBSCRIPTION_REL
Definition: pg_dump.h:88
@ DO_REL_STATS
Definition: pg_dump.h:86
@ DO_SEQUENCE_SET
Definition: pg_dump.h:66
@ DO_ATTRDEF
Definition: pg_dump.h:55
@ DO_PUBLICATION_REL
Definition: pg_dump.h:84
@ DO_TABLE_ATTACH
Definition: pg_dump.h:54
@ DO_OPCLASS
Definition: pg_dump.h:49
@ DO_INDEX_ATTACH
Definition: pg_dump.h:57
@ DO_TSTEMPLATE
Definition: pg_dump.h:70
@ DO_STATSEXT
Definition: pg_dump.h:58
@ DO_FUNC
Definition: pg_dump.h:45
@ DO_POST_DATA_BOUNDARY
Definition: pg_dump.h:79
@ DO_LARGE_OBJECT_DATA
Definition: pg_dump.h:77
@ DO_OPFAMILY
Definition: pg_dump.h:50
@ DO_TRANSFORM
Definition: pg_dump.h:75
@ DO_ACCESS_METHOD
Definition: pg_dump.h:48
@ DO_PUBLICATION_TABLE_IN_SCHEMA
Definition: pg_dump.h:85
@ DO_CONVERSION
Definition: pg_dump.h:52
@ DO_TRIGGER
Definition: pg_dump.h:60
@ DO_RULE
Definition: pg_dump.h:59
@ DO_DUMMY_TYPE
Definition: pg_dump.h:67
@ DO_TSDICT
Definition: pg_dump.h:69
@ DO_TSPARSER
Definition: pg_dump.h:68
@ DO_EXTENSION
Definition: pg_dump.h:42
@ DO_TABLE_DATA
Definition: pg_dump.h:65
@ DO_PUBLICATION
Definition: pg_dump.h:83
@ DO_TABLE
Definition: pg_dump.h:53
@ DO_NAMESPACE
Definition: pg_dump.h:41
@ DO_AGG
Definition: pg_dump.h:46
@ DO_SHELL_TYPE
Definition: pg_dump.h:44
static char * buf
Definition: pg_test_fsync.c:72
#define snprintf
Definition: port.h:239
DumpId dumpId
Definition: pg_dump.h:151
DumpableObjectType objType
Definition: pg_dump.h:149
CatalogId catId
Definition: pg_dump.h:150

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_REL_STATS, 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 200 of file pg_dump_sort.c.

201{
202 DumpableObject *obj1 = *(DumpableObject *const *) p1;
203 DumpableObject *obj2 = *(DumpableObject *const *) p2;
204 int cmpval;
205
206 /* Sort by type's priority */
207 cmpval = dbObjectTypePriority[obj1->objType] -
209
210 if (cmpval != 0)
211 return cmpval;
212
213 /*
214 * Sort by namespace. Typically, all objects of the same priority would
215 * either have or not have a namespace link, but there are exceptions.
216 * Sort NULL namespace after non-NULL in such cases.
217 */
218 if (obj1->namespace)
219 {
220 if (obj2->namespace)
221 {
222 cmpval = strcmp(obj1->namespace->dobj.name,
223 obj2->namespace->dobj.name);
224 if (cmpval != 0)
225 return cmpval;
226 }
227 else
228 return -1;
229 }
230 else if (obj2->namespace)
231 return 1;
232
233 /*
234 * Sort by name. With a few exceptions, names here are single catalog
235 * columns. To get a fuller picture, grep pg_dump.c for "dobj.name = ".
236 * Names here don't match "Name:" in plain format output, which is a
237 * _tocEntry.tag. For example, DumpableObject.name of a constraint is
238 * pg_constraint.conname, but _tocEntry.tag of a constraint is relname and
239 * conname joined with a space.
240 */
241 cmpval = strcmp(obj1->name, obj2->name);
242 if (cmpval != 0)
243 return cmpval;
244
245 /*
246 * Sort by type. This helps types that share a type priority without
247 * sharing a unique name constraint, e.g. opclass and opfamily.
248 */
249 cmpval = obj1->objType - obj2->objType;
250 if (cmpval != 0)
251 return cmpval;
252
253 /*
254 * To have a stable sort order, break ties for some object types. Most
255 * catalogs have a natural key, e.g. pg_proc_proname_args_nsp_index. Where
256 * the above "namespace" and "name" comparisons don't cover all natural
257 * key columns, compare the rest here.
258 *
259 * The natural key usually refers to other catalogs by surrogate keys.
260 * Hence, this translates each of those references to the natural key of
261 * the referenced catalog. That may descend through multiple levels of
262 * catalog references. For example, to sort by pg_proc.proargtypes,
263 * descend to each pg_type and then further to its pg_namespace, for an
264 * overall sort by (nspname, typname).
265 */
266 if (obj1->objType == DO_FUNC || obj1->objType == DO_AGG)
267 {
268 FuncInfo *fobj1 = *(FuncInfo *const *) p1;
269 FuncInfo *fobj2 = *(FuncInfo *const *) p2;
270 int i;
271
272 /* Sort by number of arguments, then argument type names */
273 cmpval = fobj1->nargs - fobj2->nargs;
274 if (cmpval != 0)
275 return cmpval;
276 for (i = 0; i < fobj1->nargs; i++)
277 {
278 cmpval = pgTypeNameCompare(fobj1->argtypes[i],
279 fobj2->argtypes[i]);
280 if (cmpval != 0)
281 return cmpval;
282 }
283 }
284 else if (obj1->objType == DO_OPERATOR)
285 {
286 OprInfo *oobj1 = *(OprInfo *const *) p1;
287 OprInfo *oobj2 = *(OprInfo *const *) p2;
288
289 /* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
290 cmpval = (oobj2->oprkind - oobj1->oprkind);
291 if (cmpval != 0)
292 return cmpval;
293 /* Within an oprkind, sort by argument type names */
294 cmpval = pgTypeNameCompare(oobj1->oprleft, oobj2->oprleft);
295 if (cmpval != 0)
296 return cmpval;
297 cmpval = pgTypeNameCompare(oobj1->oprright, oobj2->oprright);
298 if (cmpval != 0)
299 return cmpval;
300 }
301 else if (obj1->objType == DO_OPCLASS)
302 {
303 OpclassInfo *opcobj1 = *(OpclassInfo *const *) p1;
304 OpclassInfo *opcobj2 = *(OpclassInfo *const *) p2;
305
306 /* Sort by access method name, per pg_opclass_am_name_nsp_index */
307 cmpval = accessMethodNameCompare(opcobj1->opcmethod,
308 opcobj2->opcmethod);
309 if (cmpval != 0)
310 return cmpval;
311 }
312 else if (obj1->objType == DO_OPFAMILY)
313 {
314 OpfamilyInfo *opfobj1 = *(OpfamilyInfo *const *) p1;
315 OpfamilyInfo *opfobj2 = *(OpfamilyInfo *const *) p2;
316
317 /* Sort by access method name, per pg_opfamily_am_name_nsp_index */
318 cmpval = accessMethodNameCompare(opfobj1->opfmethod,
319 opfobj2->opfmethod);
320 if (cmpval != 0)
321 return cmpval;
322 }
323 else if (obj1->objType == DO_COLLATION)
324 {
325 CollInfo *cobj1 = *(CollInfo *const *) p1;
326 CollInfo *cobj2 = *(CollInfo *const *) p2;
327
328 /*
329 * Sort by encoding, per pg_collation_name_enc_nsp_index. Technically,
330 * this is not necessary, because wherever this changes dump order,
331 * restoring the dump fails anyway. CREATE COLLATION can't create a
332 * tie for this to break, because it imposes restrictions to make
333 * (nspname, collname) uniquely identify a collation within a given
334 * DatabaseEncoding. While pg_import_system_collations() can create a
335 * tie, pg_dump+restore fails after
336 * pg_import_system_collations('my_schema') does so. However, there's
337 * little to gain by ignoring one natural key column on the basis of
338 * those limitations elsewhere, so respect the full natural key like
339 * we do for other object types.
340 */
341 cmpval = cobj1->collencoding - cobj2->collencoding;
342 if (cmpval != 0)
343 return cmpval;
344 }
345 else if (obj1->objType == DO_ATTRDEF)
346 {
347 AttrDefInfo *adobj1 = *(AttrDefInfo *const *) p1;
348 AttrDefInfo *adobj2 = *(AttrDefInfo *const *) p2;
349
350 /* Sort by attribute number */
351 cmpval = (adobj1->adnum - adobj2->adnum);
352 if (cmpval != 0)
353 return cmpval;
354 }
355 else if (obj1->objType == DO_POLICY)
356 {
357 PolicyInfo *pobj1 = *(PolicyInfo *const *) p1;
358 PolicyInfo *pobj2 = *(PolicyInfo *const *) p2;
359
360 /* Sort by table name (table namespace was considered already) */
361 cmpval = strcmp(pobj1->poltable->dobj.name,
362 pobj2->poltable->dobj.name);
363 if (cmpval != 0)
364 return cmpval;
365 }
366 else if (obj1->objType == DO_RULE)
367 {
368 RuleInfo *robj1 = *(RuleInfo *const *) p1;
369 RuleInfo *robj2 = *(RuleInfo *const *) p2;
370
371 /* Sort by table name (table namespace was considered already) */
372 cmpval = strcmp(robj1->ruletable->dobj.name,
373 robj2->ruletable->dobj.name);
374 if (cmpval != 0)
375 return cmpval;
376 }
377 else if (obj1->objType == DO_TRIGGER)
378 {
379 TriggerInfo *tobj1 = *(TriggerInfo *const *) p1;
380 TriggerInfo *tobj2 = *(TriggerInfo *const *) p2;
381
382 /* Sort by table name (table namespace was considered already) */
383 cmpval = strcmp(tobj1->tgtable->dobj.name,
384 tobj2->tgtable->dobj.name);
385 if (cmpval != 0)
386 return cmpval;
387 }
388 else if (obj1->objType == DO_CONSTRAINT ||
389 obj1->objType == DO_FK_CONSTRAINT)
390 {
391 ConstraintInfo *robj1 = *(ConstraintInfo *const *) p1;
392 ConstraintInfo *robj2 = *(ConstraintInfo *const *) p2;
393
394 /*
395 * Sort domain constraints before table constraints, for consistency
396 * with our decision to sort CREATE DOMAIN before CREATE TABLE.
397 */
398 if (robj1->condomain)
399 {
400 if (robj2->condomain)
401 {
402 /* Sort by domain name (domain namespace was considered) */
403 cmpval = strcmp(robj1->condomain->dobj.name,
404 robj2->condomain->dobj.name);
405 if (cmpval != 0)
406 return cmpval;
407 }
408 else
409 return PRIO_TYPE - PRIO_TABLE;
410 }
411 else if (robj2->condomain)
412 return PRIO_TABLE - PRIO_TYPE;
413 else
414 {
415 /* Sort by table name (table namespace was considered already) */
416 cmpval = strcmp(robj1->contable->dobj.name,
417 robj2->contable->dobj.name);
418 if (cmpval != 0)
419 return cmpval;
420 }
421 }
422 else if (obj1->objType == DO_DEFAULT_ACL)
423 {
424 DefaultACLInfo *daclobj1 = *(DefaultACLInfo *const *) p1;
425 DefaultACLInfo *daclobj2 = *(DefaultACLInfo *const *) p2;
426
427 /*
428 * Sort by defaclrole, per pg_default_acl_role_nsp_obj_index. The
429 * (namespace, name) match (defaclnamespace, defaclobjtype).
430 */
431 cmpval = strcmp(daclobj1->defaclrole, daclobj2->defaclrole);
432 if (cmpval != 0)
433 return cmpval;
434 }
435 else if (obj1->objType == DO_PUBLICATION_REL)
436 {
437 PublicationRelInfo *probj1 = *(PublicationRelInfo *const *) p1;
438 PublicationRelInfo *probj2 = *(PublicationRelInfo *const *) p2;
439
440 /* Sort by publication name, since (namespace, name) match the rel */
441 cmpval = strcmp(probj1->publication->dobj.name,
442 probj2->publication->dobj.name);
443 if (cmpval != 0)
444 return cmpval;
445 }
446 else if (obj1->objType == DO_PUBLICATION_TABLE_IN_SCHEMA)
447 {
448 PublicationSchemaInfo *psobj1 = *(PublicationSchemaInfo *const *) p1;
449 PublicationSchemaInfo *psobj2 = *(PublicationSchemaInfo *const *) p2;
450
451 /* Sort by publication name, since ->name is just nspname */
452 cmpval = strcmp(psobj1->publication->dobj.name,
453 psobj2->publication->dobj.name);
454 if (cmpval != 0)
455 return cmpval;
456 }
457
458 /*
459 * Shouldn't get here except after catalog corruption, but if we do, sort
460 * by OID. This may make logically-identical databases differ in the
461 * order of objects in dump output. Users will get spurious schema diffs.
462 * Expect flaky failures of 002_pg_upgrade.pl test 'dump outputs from
463 * original and restored regression databases match' if the regression
464 * database contains objects allowing that test to reach here. That's a
465 * consequence of the test using "pg_restore -j", which doesn't fully
466 * constrain OID assignment order.
467 */
468 Assert(false);
469 return oidcmp(obj1->catId.oid, obj2->catId.oid);
470}
int i
Definition: isn.c:77
#define oidcmp(x, y)
Definition: pg_dump.h:21
static int pgTypeNameCompare(Oid typid1, Oid typid2)
Definition: pg_dump_sort.c:474
static int accessMethodNameCompare(Oid am1, Oid am2)
Definition: pg_dump_sort.c:518
static const int dbObjectTypePriority[]
Definition: pg_dump_sort.c:105
DumpableObject dobj
Definition: pg_dump.h:669
PublicationInfo * publication
Definition: pg_dump.h:701
int collencoding
Definition: pg_dump.h:293
TypeInfo * condomain
Definition: pg_dump.h:519
TableInfo * contable
Definition: pg_dump.h:518
const char * defaclrole
Definition: pg_dump.h:625
Oid * argtypes
Definition: pg_dump.h:246
int nargs
Definition: pg_dump.h:245
Oid opcmethod
Definition: pg_dump.h:278
Oid opfmethod
Definition: pg_dump.h:285
Oid oprleft
Definition: pg_dump.h:263
char oprkind
Definition: pg_dump.h:262
Oid oprright
Definition: pg_dump.h:264
TableInfo * poltable
Definition: pg_dump.h:655
TableInfo * ruletable
Definition: pg_dump.h:477
DumpableObject dobj
Definition: pg_dump.h:307
TableInfo * tgtable
Definition: pg_dump.h:488
DumpableObject dobj
Definition: pg_dump.h:205

References accessMethodNameCompare(), _attrDefInfo::adnum, _funcInfo::argtypes, Assert(), _dumpableObject::catId, _collInfo::collencoding, _constraintInfo::condomain, _constraintInfo::contable, dbObjectTypePriority, _defaultACLInfo::defaclrole, DO_AGG, DO_ATTRDEF, DO_COLLATION, DO_CONSTRAINT, DO_DEFAULT_ACL, DO_FK_CONSTRAINT, DO_FUNC, DO_OPCLASS, DO_OPERATOR, DO_OPFAMILY, DO_POLICY, DO_PUBLICATION_REL, DO_PUBLICATION_TABLE_IN_SCHEMA, DO_RULE, DO_TRIGGER, _typeInfo::dobj, _tableInfo::dobj, _PublicationInfo::dobj, i, _dumpableObject::name, _funcInfo::nargs, _dumpableObject::objType, CatalogId::oid, oidcmp, _opclassInfo::opcmethod, _opfamilyInfo::opfmethod, _oprInfo::oprkind, _oprInfo::oprleft, _oprInfo::oprright, pgTypeNameCompare(), _policyInfo::poltable, PRIO_TABLE, PRIO_TYPE, _PublicationSchemaInfo::publication, _ruleInfo::ruletable, and _triggerInfo::tgtable.

Referenced by sortDumpableObjectsByTypeName().

◆ findDependencyLoops()

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

Definition at line 749 of file pg_dump_sort.c.

750{
751 /*
752 * We use three data structures here:
753 *
754 * processed[] is a bool array indexed by dump ID, marking the objects
755 * already processed during this invocation of findDependencyLoops().
756 *
757 * searchFailed[] is another array indexed by dump ID. searchFailed[j] is
758 * set to dump ID k if we have proven that there is no dependency path
759 * leading from object j back to start point k. This allows us to skip
760 * useless searching when there are multiple dependency paths from k to j,
761 * which is a common situation. We could use a simple bool array for
762 * this, but then we'd need to re-zero it for each start point, resulting
763 * in O(N^2) zeroing work. Using the start point's dump ID as the "true"
764 * value lets us skip clearing the array before we consider the next start
765 * point.
766 *
767 * workspace[] is an array of DumpableObject pointers, in which we try to
768 * build lists of objects constituting loops. We make workspace[] large
769 * enough to hold all the objects in TopoSort's output, which is huge
770 * overkill in most cases but could theoretically be necessary if there is
771 * a single dependency chain linking all the objects.
772 */
773 bool *processed;
774 DumpId *searchFailed;
775 DumpableObject **workspace;
776 bool fixedloop;
777 int i;
778
779 processed = (bool *) pg_malloc0((getMaxDumpId() + 1) * sizeof(bool));
780 searchFailed = (DumpId *) pg_malloc0((getMaxDumpId() + 1) * sizeof(DumpId));
781 workspace = (DumpableObject **) pg_malloc(totObjs * sizeof(DumpableObject *));
782 fixedloop = false;
783
784 for (i = 0; i < nObjs; i++)
785 {
786 DumpableObject *obj = objs[i];
787 int looplen;
788 int j;
789
790 looplen = findLoop(obj,
791 obj->dumpId,
792 processed,
793 searchFailed,
794 workspace,
795 0);
796
797 if (looplen > 0)
798 {
799 /* Found a loop, repair it */
800 repairDependencyLoop(workspace, looplen);
801 fixedloop = true;
802 /* Mark loop members as processed */
803 for (j = 0; j < looplen; j++)
804 processed[workspace[j]->dumpId] = true;
805 }
806 else
807 {
808 /*
809 * There's no loop starting at this object, but mark it processed
810 * anyway. This is not necessary for correctness, but saves later
811 * invocations of findLoop() from uselessly chasing references to
812 * such an object.
813 */
814 processed[obj->dumpId] = true;
815 }
816 }
817
818 /* We'd better have fixed at least one loop */
819 if (!fixedloop)
820 pg_fatal("could not identify dependency loop");
821
822 free(workspace);
823 free(searchFailed);
824 free(processed);
825}
DumpId getMaxDumpId(void)
Definition: common.c:754
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
#define free(a)
Definition: header.h:65
int j
Definition: isn.c:78
int DumpId
Definition: pg_backup.h:284
#define pg_fatal(...)
static int findLoop(DumpableObject *obj, DumpId startPoint, bool *processed, DumpId *searchFailed, DumpableObject **workspace, int depth)
Definition: pg_dump_sort.c:845
static void repairDependencyLoop(DumpableObject **loop, int nLoop)

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

851{
852 int i;
853
854 /*
855 * Reject if obj is already processed. This test prevents us from finding
856 * loops that overlap previously-processed loops.
857 */
858 if (processed[obj->dumpId])
859 return 0;
860
861 /*
862 * If we've already proven there is no path from this object back to the
863 * startPoint, forget it.
864 */
865 if (searchFailed[obj->dumpId] == startPoint)
866 return 0;
867
868 /*
869 * Reject if obj is already present in workspace. This test prevents us
870 * from going into infinite recursion if we are given a startPoint object
871 * that links to a cycle it's not a member of, and it guarantees that we
872 * can't overflow the allocated size of workspace[].
873 */
874 for (i = 0; i < depth; i++)
875 {
876 if (workspace[i] == obj)
877 return 0;
878 }
879
880 /*
881 * Okay, tentatively add obj to workspace
882 */
883 workspace[depth++] = obj;
884
885 /*
886 * See if we've found a loop back to the desired startPoint; if so, done
887 */
888 for (i = 0; i < obj->nDeps; i++)
889 {
890 if (obj->dependencies[i] == startPoint)
891 return depth;
892 }
893
894 /*
895 * Recurse down each outgoing branch
896 */
897 for (i = 0; i < obj->nDeps; i++)
898 {
900 int newDepth;
901
902 if (!nextobj)
903 continue; /* ignore dependencies on undumped objects */
904 newDepth = findLoop(nextobj,
905 startPoint,
906 processed,
907 searchFailed,
908 workspace,
909 depth);
910 if (newDepth > 0)
911 return newDepth;
912 }
913
914 /*
915 * Remember there is no path from here back to startPoint
916 */
917 searchFailed[obj->dumpId] = startPoint;
918
919 return 0;
920}
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:765
DumpId * dependencies
Definition: pg_dump.h:159

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

Referenced by findDependencyLoops(), and findLoop().

◆ int_cmp()

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

Definition at line 1763 of file pg_dump_sort.c.

1764{
1765 int ai = (int) (intptr_t) a;
1766 int bi = (int) (intptr_t) b;
1767
1768 return pg_cmp_s32(ai, bi);
1769}
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:646
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, b, and pg_cmp_s32().

Referenced by TopoSort().

◆ pgTypeNameCompare()

static int pgTypeNameCompare ( Oid  typid1,
Oid  typid2 
)
static

Definition at line 474 of file pg_dump_sort.c.

475{
476 TypeInfo *typobj1;
477 TypeInfo *typobj2;
478 int cmpval;
479
480 if (typid1 == typid2)
481 return 0;
482
483 typobj1 = findTypeByOid(typid1);
484 typobj2 = findTypeByOid(typid2);
485
486 if (!typobj1 || !typobj2)
487 {
488 /*
489 * getTypes() didn't find some OID. Assume catalog corruption, e.g.
490 * an oprright value without the corresponding OID in a pg_type row.
491 * Report as "equal", so the caller uses the next available basis for
492 * comparison, e.g. the next function argument.
493 *
494 * Unary operators have InvalidOid in oprleft (if oprkind='r') or in
495 * oprright (if oprkind='l'). Caller already sorted by oprkind,
496 * calling us only for like-kind operators. Hence, "typid1 == typid2"
497 * took care of InvalidOid. (v14 removed postfix operator support.
498 * Hence, when dumping from v14+, only oprleft can be InvalidOid.)
499 */
500 Assert(false);
501 return 0;
502 }
503
504 if (!typobj1->dobj.namespace || !typobj2->dobj.namespace)
505 Assert(false); /* catalog corruption */
506 else
507 {
508 cmpval = strcmp(typobj1->dobj.namespace->dobj.name,
509 typobj2->dobj.namespace->dobj.name);
510 if (cmpval != 0)
511 return cmpval;
512 }
513 return strcmp(typobj1->dobj.name, typobj2->dobj.name);
514}
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:899

References Assert(), _typeInfo::dobj, findTypeByOid(), and _dumpableObject::name.

Referenced by DOTypeNameCompare().

◆ repairDependencyLoop()

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

Definition at line 1163 of file pg_dump_sort.c.

1165{
1166 int i,
1167 j;
1168
1169 /* Datatype and one of its I/O or canonicalize functions */
1170 if (nLoop == 2 &&
1171 loop[0]->objType == DO_TYPE &&
1172 loop[1]->objType == DO_FUNC)
1173 {
1174 repairTypeFuncLoop(loop[0], loop[1]);
1175 return;
1176 }
1177 if (nLoop == 2 &&
1178 loop[1]->objType == DO_TYPE &&
1179 loop[0]->objType == DO_FUNC)
1180 {
1181 repairTypeFuncLoop(loop[1], loop[0]);
1182 return;
1183 }
1184
1185 /* View (including matview) and its ON SELECT rule */
1186 if (nLoop == 2 &&
1187 loop[0]->objType == DO_TABLE &&
1188 loop[1]->objType == DO_RULE &&
1189 (((TableInfo *) loop[0])->relkind == RELKIND_VIEW ||
1190 ((TableInfo *) loop[0])->relkind == RELKIND_MATVIEW) &&
1191 ((RuleInfo *) loop[1])->ev_type == '1' &&
1192 ((RuleInfo *) loop[1])->is_instead &&
1193 ((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
1194 {
1195 repairViewRuleLoop(loop[0], loop[1]);
1196 return;
1197 }
1198 if (nLoop == 2 &&
1199 loop[1]->objType == DO_TABLE &&
1200 loop[0]->objType == DO_RULE &&
1201 (((TableInfo *) loop[1])->relkind == RELKIND_VIEW ||
1202 ((TableInfo *) loop[1])->relkind == RELKIND_MATVIEW) &&
1203 ((RuleInfo *) loop[0])->ev_type == '1' &&
1204 ((RuleInfo *) loop[0])->is_instead &&
1205 ((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
1206 {
1207 repairViewRuleLoop(loop[1], loop[0]);
1208 return;
1209 }
1210
1211 /* Indirect loop involving view (but not matview) and ON SELECT rule */
1212 if (nLoop > 2)
1213 {
1214 for (i = 0; i < nLoop; i++)
1215 {
1216 if (loop[i]->objType == DO_TABLE &&
1217 ((TableInfo *) loop[i])->relkind == RELKIND_VIEW)
1218 {
1219 for (j = 0; j < nLoop; j++)
1220 {
1221 if (loop[j]->objType == DO_RULE &&
1222 ((RuleInfo *) loop[j])->ev_type == '1' &&
1223 ((RuleInfo *) loop[j])->is_instead &&
1224 ((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
1225 {
1226 repairViewRuleMultiLoop(loop[i], loop[j]);
1227 return;
1228 }
1229 }
1230 }
1231 }
1232 }
1233
1234 /* Indirect loop involving matview and data boundary */
1235 if (nLoop > 2)
1236 {
1237 for (i = 0; i < nLoop; i++)
1238 {
1239 if (loop[i]->objType == DO_TABLE &&
1240 ((TableInfo *) loop[i])->relkind == RELKIND_MATVIEW)
1241 {
1242 for (j = 0; j < nLoop; j++)
1243 {
1244 if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1245 {
1246 DumpableObject *nextobj;
1247
1248 nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1249 repairMatViewBoundaryMultiLoop(loop[j], nextobj);
1250 return;
1251 }
1252 }
1253 }
1254 else if (loop[i]->objType == DO_REL_STATS &&
1255 ((RelStatsInfo *) loop[i])->relkind == RELKIND_MATVIEW)
1256 {
1257 for (j = 0; j < nLoop; j++)
1258 {
1259 if (loop[j]->objType == DO_POST_DATA_BOUNDARY)
1260 {
1261 DumpableObject *nextobj;
1262
1263 nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1264 repairMatViewBoundaryMultiLoop(loop[j], nextobj);
1265 return;
1266 }
1267 }
1268 }
1269 }
1270 }
1271
1272 /* Indirect loop involving function and data boundary */
1273 if (nLoop > 2)
1274 {
1275 for (i = 0; i < nLoop; i++)
1276 {
1277 if (loop[i]->objType == DO_FUNC)
1278 {
1279 for (j = 0; j < nLoop; j++)
1280 {
1281 if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1282 {
1283 DumpableObject *nextobj;
1284
1285 nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1286 repairFunctionBoundaryMultiLoop(loop[j], nextobj);
1287 return;
1288 }
1289 }
1290 }
1291 }
1292 }
1293
1294 /* Table and CHECK constraint */
1295 if (nLoop == 2 &&
1296 loop[0]->objType == DO_TABLE &&
1297 loop[1]->objType == DO_CONSTRAINT &&
1298 ((ConstraintInfo *) loop[1])->contype == 'c' &&
1299 ((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
1300 {
1301 repairTableConstraintLoop(loop[0], loop[1]);
1302 return;
1303 }
1304 if (nLoop == 2 &&
1305 loop[1]->objType == DO_TABLE &&
1306 loop[0]->objType == DO_CONSTRAINT &&
1307 ((ConstraintInfo *) loop[0])->contype == 'c' &&
1308 ((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
1309 {
1310 repairTableConstraintLoop(loop[1], loop[0]);
1311 return;
1312 }
1313
1314 /* Indirect loop involving table and CHECK constraint */
1315 if (nLoop > 2)
1316 {
1317 for (i = 0; i < nLoop; i++)
1318 {
1319 if (loop[i]->objType == DO_TABLE)
1320 {
1321 for (j = 0; j < nLoop; j++)
1322 {
1323 if (loop[j]->objType == DO_CONSTRAINT &&
1324 ((ConstraintInfo *) loop[j])->contype == 'c' &&
1325 ((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
1326 {
1327 repairTableConstraintMultiLoop(loop[i], loop[j]);
1328 return;
1329 }
1330 }
1331 }
1332 }
1333 }
1334
1335 /* Table and attribute default */
1336 if (nLoop == 2 &&
1337 loop[0]->objType == DO_TABLE &&
1338 loop[1]->objType == DO_ATTRDEF &&
1339 ((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
1340 {
1341 repairTableAttrDefLoop(loop[0], loop[1]);
1342 return;
1343 }
1344 if (nLoop == 2 &&
1345 loop[1]->objType == DO_TABLE &&
1346 loop[0]->objType == DO_ATTRDEF &&
1347 ((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
1348 {
1349 repairTableAttrDefLoop(loop[1], loop[0]);
1350 return;
1351 }
1352
1353 /* index on partitioned table and corresponding index on partition */
1354 if (nLoop == 2 &&
1355 loop[0]->objType == DO_INDEX &&
1356 loop[1]->objType == DO_INDEX)
1357 {
1358 if (((IndxInfo *) loop[0])->parentidx == loop[1]->catId.oid)
1359 {
1360 repairIndexLoop(loop[0], loop[1]);
1361 return;
1362 }
1363 else if (((IndxInfo *) loop[1])->parentidx == loop[0]->catId.oid)
1364 {
1365 repairIndexLoop(loop[1], loop[0]);
1366 return;
1367 }
1368 }
1369
1370 /* Indirect loop involving table and attribute default */
1371 if (nLoop > 2)
1372 {
1373 for (i = 0; i < nLoop; i++)
1374 {
1375 if (loop[i]->objType == DO_TABLE)
1376 {
1377 for (j = 0; j < nLoop; j++)
1378 {
1379 if (loop[j]->objType == DO_ATTRDEF &&
1380 ((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
1381 {
1382 repairTableAttrDefMultiLoop(loop[i], loop[j]);
1383 return;
1384 }
1385 }
1386 }
1387 }
1388 }
1389
1390 /* Domain and CHECK or NOT NULL constraint */
1391 if (nLoop == 2 &&
1392 loop[0]->objType == DO_TYPE &&
1393 loop[1]->objType == DO_CONSTRAINT &&
1394 (((ConstraintInfo *) loop[1])->contype == 'c' ||
1395 ((ConstraintInfo *) loop[1])->contype == 'n') &&
1396 ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
1397 {
1398 repairDomainConstraintLoop(loop[0], loop[1]);
1399 return;
1400 }
1401 if (nLoop == 2 &&
1402 loop[1]->objType == DO_TYPE &&
1403 loop[0]->objType == DO_CONSTRAINT &&
1404 (((ConstraintInfo *) loop[0])->contype == 'c' ||
1405 ((ConstraintInfo *) loop[0])->contype == 'n') &&
1406 ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
1407 {
1408 repairDomainConstraintLoop(loop[1], loop[0]);
1409 return;
1410 }
1411
1412 /* Indirect loop involving domain and CHECK or NOT NULL constraint */
1413 if (nLoop > 2)
1414 {
1415 for (i = 0; i < nLoop; i++)
1416 {
1417 if (loop[i]->objType == DO_TYPE)
1418 {
1419 for (j = 0; j < nLoop; j++)
1420 {
1421 if (loop[j]->objType == DO_CONSTRAINT &&
1422 (((ConstraintInfo *) loop[j])->contype == 'c' ||
1423 ((ConstraintInfo *) loop[j])->contype == 'n') &&
1424 ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
1425 {
1426 repairDomainConstraintMultiLoop(loop[i], loop[j]);
1427 return;
1428 }
1429 }
1430 }
1431 }
1432 }
1433
1434 /*
1435 * Loop of table with itself --- just ignore it.
1436 *
1437 * (Actually, what this arises from is a dependency of a table column on
1438 * another column, which happened with generated columns before v15; or a
1439 * dependency of a table column on the whole table, which happens with
1440 * partitioning. But we didn't pay attention to sub-object IDs while
1441 * collecting the dependency data, so we can't see that here.)
1442 */
1443 if (nLoop == 1)
1444 {
1445 if (loop[0]->objType == DO_TABLE)
1446 {
1447 removeObjectDependency(loop[0], loop[0]->dumpId);
1448 return;
1449 }
1450 }
1451
1452 /*
1453 * If all the objects are TABLE_DATA items, what we must have is a
1454 * circular set of foreign key constraints (or a single self-referential
1455 * table). Print an appropriate complaint and break the loop arbitrarily.
1456 */
1457 for (i = 0; i < nLoop; i++)
1458 {
1459 if (loop[i]->objType != DO_TABLE_DATA)
1460 break;
1461 }
1462 if (i >= nLoop)
1463 {
1464 pg_log_warning(ngettext("there are circular foreign-key constraints on this table:",
1465 "there are circular foreign-key constraints among these tables:",
1466 nLoop));
1467 for (i = 0; i < nLoop; i++)
1468 pg_log_warning_detail("%s", loop[i]->name);
1469 pg_log_warning_hint("You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.");
1470 pg_log_warning_hint("Consider using a full dump instead of a --data-only dump to avoid this problem.");
1471 if (nLoop > 1)
1472 removeObjectDependency(loop[0], loop[1]->dumpId);
1473 else /* must be a self-dependency */
1474 removeObjectDependency(loop[0], loop[0]->dumpId);
1475 return;
1476 }
1477
1478 /*
1479 * If we can't find a principled way to break the loop, complain and break
1480 * it in an arbitrary fashion.
1481 */
1482 pg_log_warning("could not resolve dependency loop among these items:");
1483 for (i = 0; i < nLoop; i++)
1484 {
1485 char buf[1024];
1486
1487 describeDumpableObject(loop[i], buf, sizeof(buf));
1489 }
1490
1491 if (nLoop > 1)
1492 removeObjectDependency(loop[0], loop[1]->dumpId);
1493 else /* must be a self-dependency */
1494 removeObjectDependency(loop[0], loop[0]->dumpId);
1495}
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:843
#define ngettext(s, p, n)
Definition: c.h:1184
#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)
static void repairTableAttrDefLoop(DumpableObject *tableobj, DumpableObject *attrdefobj)
static void repairTableConstraintLoop(DumpableObject *tableobj, DumpableObject *constraintobj)
static void repairTableAttrDefMultiLoop(DumpableObject *tableobj, DumpableObject *attrdefobj)
static void repairViewRuleMultiLoop(DumpableObject *viewobj, DumpableObject *ruleobj)
Definition: pg_dump_sort.c:981
static void repairDomainConstraintLoop(DumpableObject *domainobj, DumpableObject *constraintobj)
static void repairTableConstraintMultiLoop(DumpableObject *tableobj, DumpableObject *constraintobj)
static void describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
static void repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
Definition: pg_dump_sort.c:930
static void repairDomainConstraintMultiLoop(DumpableObject *domainobj, DumpableObject *constraintobj)
static void repairIndexLoop(DumpableObject *partedindex, DumpableObject *partindex)
static void repairViewRuleLoop(DumpableObject *viewobj, DumpableObject *ruleobj)
Definition: pg_dump_sort.c:961
static void repairFunctionBoundaryMultiLoop(DumpableObject *boundaryobj, DumpableObject *nextobj)
#define pg_log_warning(...)
Definition: pgfnames.c:24
const char * name

References buf, describeDumpableObject(), DO_ATTRDEF, DO_CONSTRAINT, DO_FUNC, DO_INDEX, DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, DO_REL_STATS, 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 1127 of file pg_dump_sort.c.

1129{
1130 /* remove constraint's dependency on domain */
1131 removeObjectDependency(constraintobj, domainobj->dumpId);
1132}

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairDomainConstraintMultiLoop()

static void repairDomainConstraintMultiLoop ( DumpableObject domainobj,
DumpableObject constraintobj 
)
static

Definition at line 1135 of file pg_dump_sort.c.

1137{
1138 /* remove domain's dependency on constraint */
1139 removeObjectDependency(domainobj, constraintobj->dumpId);
1140 /* mark constraint as needing its own dump */
1141 ((ConstraintInfo *) constraintobj)->separate = true;
1142 /* put back constraint's dependency on domain */
1143 addObjectDependency(constraintobj, domainobj->dumpId);
1144 /* now that constraint is separate, it must be post-data */
1145 addObjectDependency(constraintobj, postDataBoundId);
1146}
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:818
static DumpId postDataBoundId
Definition: pg_dump_sort.c:161

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

Referenced by repairDependencyLoop().

◆ repairFunctionBoundaryMultiLoop()

static void repairFunctionBoundaryMultiLoop ( DumpableObject boundaryobj,
DumpableObject nextobj 
)
static

Definition at line 1049 of file pg_dump_sort.c.

1051{
1052 /* remove boundary's dependency on object after it in loop */
1053 removeObjectDependency(boundaryobj, nextobj->dumpId);
1054 /* if that object is a function, mark it as postponed into post-data */
1055 if (nextobj->objType == DO_FUNC)
1056 {
1057 FuncInfo *nextinfo = (FuncInfo *) nextobj;
1058
1059 nextinfo->postponed_def = true;
1060 }
1061}
bool postponed_def
Definition: pg_dump.h:248

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

1151{
1152 removeObjectDependency(partedindex, partindex->dumpId);
1153}

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairMatViewBoundaryMultiLoop()

static void repairMatViewBoundaryMultiLoop ( DumpableObject boundaryobj,
DumpableObject nextobj 
)
static

Definition at line 1015 of file pg_dump_sort.c.

1017{
1018 /* remove boundary's dependency on object after it in loop */
1019 removeObjectDependency(boundaryobj, nextobj->dumpId);
1020
1021 /*
1022 * If that object is a matview or matview stats, mark it as postponed into
1023 * post-data.
1024 */
1025 if (nextobj->objType == DO_TABLE)
1026 {
1027 TableInfo *nextinfo = (TableInfo *) nextobj;
1028
1029 if (nextinfo->relkind == RELKIND_MATVIEW)
1030 nextinfo->postponed_def = true;
1031 }
1032 else if (nextobj->objType == DO_REL_STATS)
1033 {
1034 RelStatsInfo *nextinfo = (RelStatsInfo *) nextobj;
1035
1036 if (nextinfo->relkind == RELKIND_MATVIEW)
1037 nextinfo->section = SECTION_POST_DATA;
1038 }
1039}
@ SECTION_POST_DATA
Definition: pg_backup.h:60
char relkind
Definition: pg_dump.h:455
teSection section
Definition: pg_dump.h:463
char relkind
Definition: pg_dump.h:310
bool postponed_def
Definition: pg_dump.h:343

References DO_REL_STATS, DO_TABLE, _dumpableObject::dumpId, _dumpableObject::objType, _tableInfo::postponed_def, _tableInfo::relkind, _relStatsInfo::relkind, removeObjectDependency(), _relStatsInfo::section, and SECTION_POST_DATA.

Referenced by repairDependencyLoop().

◆ repairTableAttrDefLoop()

static void repairTableAttrDefLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
)
static

Definition at line 1104 of file pg_dump_sort.c.

1106{
1107 /* remove attrdef's dependency on table */
1108 removeObjectDependency(attrdefobj, tableobj->dumpId);
1109}

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableAttrDefMultiLoop()

static void repairTableAttrDefMultiLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
)
static

Definition at line 1112 of file pg_dump_sort.c.

1114{
1115 /* remove table's dependency on attrdef */
1116 removeObjectDependency(tableobj, attrdefobj->dumpId);
1117 /* mark attrdef as needing its own dump */
1118 ((AttrDefInfo *) attrdefobj)->separate = true;
1119 /* put back attrdef's dependency on table */
1120 addObjectDependency(attrdefobj, tableobj->dumpId);
1121}

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

Referenced by repairDependencyLoop().

◆ repairTableConstraintLoop()

static void repairTableConstraintLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
)
static

Definition at line 1070 of file pg_dump_sort.c.

1072{
1073 /* remove constraint's dependency on table */
1074 removeObjectDependency(constraintobj, tableobj->dumpId);
1075}

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairTableConstraintMultiLoop()

static void repairTableConstraintMultiLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
)
static

Definition at line 1087 of file pg_dump_sort.c.

1089{
1090 /* remove table's dependency on constraint */
1091 removeObjectDependency(tableobj, constraintobj->dumpId);
1092 /* mark constraint as needing its own dump */
1093 ((ConstraintInfo *) constraintobj)->separate = true;
1094 /* put back constraint's dependency on table */
1095 addObjectDependency(constraintobj, tableobj->dumpId);
1096 /* now that constraint is separate, it must be post-data */
1097 addObjectDependency(constraintobj, postDataBoundId);
1098}

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

Referenced by repairDependencyLoop().

◆ repairTypeFuncLoop()

static void repairTypeFuncLoop ( DumpableObject typeobj,
DumpableObject funcobj 
)
static

Definition at line 930 of file pg_dump_sort.c.

931{
932 TypeInfo *typeInfo = (TypeInfo *) typeobj;
933
934 /* remove function's dependency on type */
935 removeObjectDependency(funcobj, typeobj->dumpId);
936
937 /* add function's dependency on shell type, instead */
938 if (typeInfo->shellType)
939 {
940 addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
941
942 /*
943 * Mark shell type (always including the definition, as we need the
944 * shell type defined to identify the function fully) as to be dumped
945 * if any such function is
946 */
947 if (funcobj->dump)
948 typeInfo->shellType->dobj.dump = funcobj->dump |
950 }
951}
#define DUMP_COMPONENT_DEFINITION
Definition: pg_dump.h:109
DumpComponents dump
Definition: pg_dump.h:153
DumpableObject dobj
Definition: pg_dump.h:234
struct _shellTypeInfo * shellType
Definition: pg_dump.h:224

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

963{
964 /* remove rule's dependency on view */
965 removeObjectDependency(ruleobj, viewobj->dumpId);
966 /* flags on the two objects are already set correctly for this case */
967}

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

◆ repairViewRuleMultiLoop()

static void repairViewRuleMultiLoop ( DumpableObject viewobj,
DumpableObject ruleobj 
)
static

Definition at line 981 of file pg_dump_sort.c.

983{
984 TableInfo *viewinfo = (TableInfo *) viewobj;
985 RuleInfo *ruleinfo = (RuleInfo *) ruleobj;
986
987 /* remove view's dependency on rule */
988 removeObjectDependency(viewobj, ruleobj->dumpId);
989 /* mark view to be printed with a dummy definition */
990 viewinfo->dummy_view = true;
991 /* mark rule as needing its own dump */
992 ruleinfo->separate = true;
993 /* put back rule's dependency on view */
994 addObjectDependency(ruleobj, viewobj->dumpId);
995 /* now that rule is separate, it must be post-data */
997}
bool separate
Definition: pg_dump.h:481
bool dummy_view
Definition: pg_dump.h:342

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

550{
551 DumpableObject **ordering;
552 int nOrdering;
553
554 if (numObjs <= 0) /* can't happen anymore ... */
555 return;
556
557 /*
558 * Saving the boundary IDs in static variables is a bit grotty, but seems
559 * better than adding them to parameter lists of subsidiary functions.
560 */
561 preDataBoundId = preBoundaryId;
562 postDataBoundId = postBoundaryId;
563
564 ordering = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
565 while (!TopoSort(objs, numObjs, ordering, &nOrdering))
566 findDependencyLoops(ordering, nOrdering, numObjs);
567
568 memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
569
570 free(ordering);
571}
static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
Definition: pg_dump_sort.c:749
static DumpId preDataBoundId
Definition: pg_dump_sort.c:160
static bool TopoSort(DumpableObject **objs, int numObjs, DumpableObject **ordering, int *nOrdering)
Definition: pg_dump_sort.c:600

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

Referenced by main().

◆ sortDumpableObjectsByTypeName()

void sortDumpableObjectsByTypeName ( DumpableObject **  objs,
int  numObjs 
)

Definition at line 192 of file pg_dump_sort.c.

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

References DOTypeNameCompare(), and qsort.

Referenced by main().

◆ StaticAssertDecl()

StaticAssertDecl ( lengthof(dbObjectTypePriority = =NUM_DUMPABLE_OBJECT_TYPES,
"array length mismatch"   
)

◆ TopoSort()

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

Definition at line 600 of file pg_dump_sort.c.

604{
605 DumpId maxDumpId = getMaxDumpId();
606 binaryheap *pendingHeap;
608 int *idMap;
609 DumpableObject *obj;
610 int i,
611 j,
612 k;
613
614 /*
615 * This is basically the same algorithm shown for topological sorting in
616 * Knuth's Volume 1. However, we would like to minimize unnecessary
617 * rearrangement of the input ordering; that is, when we have a choice of
618 * which item to output next, we always want to take the one highest in
619 * the original list. Therefore, instead of maintaining an unordered
620 * linked list of items-ready-to-output as Knuth does, we maintain a heap
621 * of their item numbers, which we can use as a priority queue. This
622 * turns the algorithm from O(N) to O(N log N) because each insertion or
623 * removal of a heap item takes O(log N) time. However, that's still
624 * plenty fast enough for this application.
625 */
626
627 *nOrdering = numObjs; /* for success return */
628
629 /* Eliminate the null case */
630 if (numObjs <= 0)
631 return true;
632
633 /* Create workspace for the above-described heap */
634 pendingHeap = binaryheap_allocate(numObjs, int_cmp, NULL);
635
636 /*
637 * Scan the constraints, and for each item in the input, generate a count
638 * of the number of constraints that say it must be before something else.
639 * The count for the item with dumpId j is stored in beforeConstraints[j].
640 * We also make a map showing the input-order index of the item with
641 * dumpId j.
642 */
643 beforeConstraints = (int *) pg_malloc0((maxDumpId + 1) * sizeof(int));
644 idMap = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
645 for (i = 0; i < numObjs; i++)
646 {
647 obj = objs[i];
648 j = obj->dumpId;
649 if (j <= 0 || j > maxDumpId)
650 pg_fatal("invalid dumpId %d", j);
651 idMap[j] = i;
652 for (j = 0; j < obj->nDeps; j++)
653 {
654 k = obj->dependencies[j];
655 if (k <= 0 || k > maxDumpId)
656 pg_fatal("invalid dependency %d", k);
658 }
659 }
660
661 /*
662 * Now initialize the heap of items-ready-to-output by filling it with the
663 * indexes of items that already have beforeConstraints[id] == 0.
664 *
665 * We enter the indexes into pendingHeap in decreasing order so that the
666 * heap invariant is satisfied at the completion of this loop. This
667 * reduces the amount of work that binaryheap_build() must do.
668 */
669 for (i = numObjs; --i >= 0;)
670 {
671 if (beforeConstraints[objs[i]->dumpId] == 0)
672 binaryheap_add_unordered(pendingHeap, (void *) (intptr_t) i);
673 }
674 binaryheap_build(pendingHeap);
675
676 /*--------------------
677 * Now emit objects, working backwards in the output list. At each step,
678 * we use the priority heap to select the last item that has no remaining
679 * before-constraints. We remove that item from the heap, output it to
680 * ordering[], and decrease the beforeConstraints count of each of the
681 * items it was constrained against. Whenever an item's beforeConstraints
682 * count is thereby decreased to zero, we insert it into the priority heap
683 * to show that it is a candidate to output. We are done when the heap
684 * becomes empty; if we have output every element then we succeeded,
685 * otherwise we failed.
686 * i = number of ordering[] entries left to output
687 * j = objs[] index of item we are outputting
688 * k = temp for scanning constraint list for item j
689 *--------------------
690 */
691 i = numObjs;
692 while (!binaryheap_empty(pendingHeap))
693 {
694 /* Select object to output by removing largest heap member */
695 j = (int) (intptr_t) binaryheap_remove_first(pendingHeap);
696 obj = objs[j];
697 /* Output candidate to ordering[] */
698 ordering[--i] = obj;
699 /* Update beforeConstraints counts of its predecessors */
700 for (k = 0; k < obj->nDeps; k++)
701 {
702 int id = obj->dependencies[k];
703
704 if ((--beforeConstraints[id]) == 0)
705 binaryheap_add(pendingHeap, (void *) (intptr_t) idMap[id]);
706 }
707 }
708
709 /*
710 * If we failed, report the objects that couldn't be output; these are the
711 * ones with beforeConstraints[] still nonzero.
712 */
713 if (i != 0)
714 {
715 k = 0;
716 for (j = 1; j <= maxDumpId; j++)
717 {
718 if (beforeConstraints[j] != 0)
719 ordering[k++] = objs[idMap[j]];
720 }
721 *nOrdering = k;
722 }
723
724 /* Done */
725 binaryheap_free(pendingHeap);
727 free(idMap);
728
729 return (i == 0);
730}
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
void binaryheap_free(binaryheap *heap)
Definition: binaryheap.c:75
void binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
Definition: binaryheap.c:116
binaryheap * binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
Definition: binaryheap.c:39
#define binaryheap_empty(h)
Definition: binaryheap.h:65
static int * beforeConstraints
Definition: deadlock.c:108
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 160 of file pg_dump_sort.c.

Referenced by sortDumpableObjects().