PostgreSQL Source Code git master
Enumerations | Functions | Variables
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

 

Functions

 
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 []
 
 
 

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

518{
519 AccessMethodInfo *amobj1;
520 AccessMethodInfo *amobj2;
521
522 if (am1 == am2)
523 return 0;
524
525 amobj1 = findAccessMethodByOid(am1);
526 amobj2 = findAccessMethodByOid(am2);
527
528 if (!amobj1 || !amobj2)
529 {
530 /* catalog corruption: handle like pgTypeNameCompare() does */
531 Assert(false);
532 return 0;
533 }
534
535 return strcmp(amobj1->dobj.name, amobj2->dobj.name);
536}
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 ( DumpableObjectobj,
char *  buf,
int  bufsize 
)
static

Definition at line 1502 of file pg_dump_sort.c.

1503{
1504 switch (obj->objType)
1505 {
1506 case DO_NAMESPACE:
1508 "SCHEMA %s (ID %d OID %u)",
1509 obj->name, obj->dumpId, obj->catId.oid);
1510 return;
1511 case DO_EXTENSION:
1513 "EXTENSION %s (ID %d OID %u)",
1514 obj->name, obj->dumpId, obj->catId.oid);
1515 return;
1516 case DO_TYPE:
1518 "TYPE %s (ID %d OID %u)",
1519 obj->name, obj->dumpId, obj->catId.oid);
1520 return;
1521 case DO_SHELL_TYPE:
1523 "SHELL TYPE %s (ID %d OID %u)",
1524 obj->name, obj->dumpId, obj->catId.oid);
1525 return;
1526 case DO_FUNC:
1528 "FUNCTION %s (ID %d OID %u)",
1529 obj->name, obj->dumpId, obj->catId.oid);
1530 return;
1531 case DO_AGG:
1533 "AGGREGATE %s (ID %d OID %u)",
1534 obj->name, obj->dumpId, obj->catId.oid);
1535 return;
1536 case DO_OPERATOR:
1538 "OPERATOR %s (ID %d OID %u)",
1539 obj->name, obj->dumpId, obj->catId.oid);
1540 return;
1541 case DO_ACCESS_METHOD:
1543 "ACCESS METHOD %s (ID %d OID %u)",
1544 obj->name, obj->dumpId, obj->catId.oid);
1545 return;
1546 case DO_OPCLASS:
1548 "OPERATOR CLASS %s (ID %d OID %u)",
1549 obj->name, obj->dumpId, obj->catId.oid);
1550 return;
1551 case DO_OPFAMILY:
1553 "OPERATOR FAMILY %s (ID %d OID %u)",
1554 obj->name, obj->dumpId, obj->catId.oid);
1555 return;
1556 case DO_COLLATION:
1558 "COLLATION %s (ID %d OID %u)",
1559 obj->name, obj->dumpId, obj->catId.oid);
1560 return;
1561 case DO_CONVERSION:
1563 "CONVERSION %s (ID %d OID %u)",
1564 obj->name, obj->dumpId, obj->catId.oid);
1565 return;
1566 case DO_TABLE:
1568 "TABLE %s (ID %d OID %u)",
1569 obj->name, obj->dumpId, obj->catId.oid);
1570 return;
1571 case DO_TABLE_ATTACH:
1573 "TABLE ATTACH %s (ID %d)",
1574 obj->name, obj->dumpId);
1575 return;
1576 case DO_ATTRDEF:
1578 "ATTRDEF %s.%s (ID %d OID %u)",
1579 ((AttrDefInfo *) obj)->adtable->dobj.name,
1580 ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
1581 obj->dumpId, obj->catId.oid);
1582 return;
1583 case DO_INDEX:
1585 "INDEX %s (ID %d OID %u)",
1586 obj->name, obj->dumpId, obj->catId.oid);
1587 return;
1588 case DO_INDEX_ATTACH:
1590 "INDEX ATTACH %s (ID %d)",
1591 obj->name, obj->dumpId);
1592 return;
1593 case DO_STATSEXT:
1595 "STATISTICS %s (ID %d OID %u)",
1596 obj->name, obj->dumpId, obj->catId.oid);
1597 return;
1598 case DO_REFRESH_MATVIEW:
1600 "REFRESH MATERIALIZED VIEW %s (ID %d OID %u)",
1601 obj->name, obj->dumpId, obj->catId.oid);
1602 return;
1603 case DO_RULE:
1605 "RULE %s (ID %d OID %u)",
1606 obj->name, obj->dumpId, obj->catId.oid);
1607 return;
1608 case DO_TRIGGER:
1610 "TRIGGER %s (ID %d OID %u)",
1611 obj->name, obj->dumpId, obj->catId.oid);
1612 return;
1613 case DO_EVENT_TRIGGER:
1615 "EVENT TRIGGER %s (ID %d OID %u)",
1616 obj->name, obj->dumpId, obj->catId.oid);
1617 return;
1618 case DO_CONSTRAINT:
1620 "CONSTRAINT %s (ID %d OID %u)",
1621 obj->name, obj->dumpId, obj->catId.oid);
1622 return;
1623 case DO_FK_CONSTRAINT:
1625 "FK CONSTRAINT %s (ID %d OID %u)",
1626 obj->name, obj->dumpId, obj->catId.oid);
1627 return;
1628 case DO_PROCLANG:
1630 "PROCEDURAL LANGUAGE %s (ID %d OID %u)",
1631 obj->name, obj->dumpId, obj->catId.oid);
1632 return;
1633 case DO_CAST:
1635 "CAST %u to %u (ID %d OID %u)",
1636 ((CastInfo *) obj)->castsource,
1637 ((CastInfo *) obj)->casttarget,
1638 obj->dumpId, obj->catId.oid);
1639 return;
1640 case DO_TRANSFORM:
1642 "TRANSFORM %u lang %u (ID %d OID %u)",
1643 ((TransformInfo *) obj)->trftype,
1644 ((TransformInfo *) obj)->trflang,
1645 obj->dumpId, obj->catId.oid);
1646 return;
1647 case DO_TABLE_DATA:
1649 "TABLE DATA %s (ID %d OID %u)",
1650 obj->name, obj->dumpId, obj->catId.oid);
1651 return;
1652 case DO_SEQUENCE_SET:
1654 "SEQUENCE SET %s (ID %d OID %u)",
1655 obj->name, obj->dumpId, obj->catId.oid);
1656 return;
1657 case DO_DUMMY_TYPE:
1659 "DUMMY TYPE %s (ID %d OID %u)",
1660 obj->name, obj->dumpId, obj->catId.oid);
1661 return;
1662 case DO_TSPARSER:
1664 "TEXT SEARCH PARSER %s (ID %d OID %u)",
1665 obj->name, obj->dumpId, obj->catId.oid);
1666 return;
1667 case DO_TSDICT:
1669 "TEXT SEARCH DICTIONARY %s (ID %d OID %u)",
1670 obj->name, obj->dumpId, obj->catId.oid);
1671 return;
1672 case DO_TSTEMPLATE:
1674 "TEXT SEARCH TEMPLATE %s (ID %d OID %u)",
1675 obj->name, obj->dumpId, obj->catId.oid);
1676 return;
1677 case DO_TSCONFIG:
1679 "TEXT SEARCH CONFIGURATION %s (ID %d OID %u)",
1680 obj->name, obj->dumpId, obj->catId.oid);
1681 return;
1682 case DO_FDW:
1684 "FOREIGN DATA WRAPPER %s (ID %d OID %u)",
1685 obj->name, obj->dumpId, obj->catId.oid);
1686 return;
1687 case DO_FOREIGN_SERVER:
1689 "FOREIGN SERVER %s (ID %d OID %u)",
1690 obj->name, obj->dumpId, obj->catId.oid);
1691 return;
1692 case DO_DEFAULT_ACL:
1694 "DEFAULT ACL %s (ID %d OID %u)",
1695 obj->name, obj->dumpId, obj->catId.oid);
1696 return;
1697 case DO_LARGE_OBJECT:
1699 "LARGE OBJECT (ID %d OID %u)",
1700 obj->dumpId, obj->catId.oid);
1701 return;
1704 "LARGE OBJECT DATA (ID %d)",
1705 obj->dumpId);
1706 return;
1707 case DO_POLICY:
1709 "POLICY (ID %d OID %u)",
1710 obj->dumpId, obj->catId.oid);
1711 return;
1712 case DO_PUBLICATION:
1714 "PUBLICATION (ID %d OID %u)",
1715 obj->dumpId, obj->catId.oid);
1716 return;
1717 case DO_PUBLICATION_REL:
1719 "PUBLICATION TABLE (ID %d OID %u)",
1720 obj->dumpId, obj->catId.oid);
1721 return;
1724 "PUBLICATION TABLES IN SCHEMA (ID %d OID %u)",
1725 obj->dumpId, obj->catId.oid);
1726 return;
1727 case DO_SUBSCRIPTION:
1729 "SUBSCRIPTION (ID %d OID %u)",
1730 obj->dumpId, obj->catId.oid);
1731 return;
1734 "SUBSCRIPTION TABLE (ID %d OID %u)",
1735 obj->dumpId, obj->catId.oid);
1736 return;
1739 "PRE-DATA BOUNDARY (ID %d)",
1740 obj->dumpId);
1741 return;
1744 "POST-DATA BOUNDARY (ID %d)",
1745 obj->dumpId);
1746 return;
1747 case DO_REL_STATS:
1749 "RELATION STATISTICS FOR %s (ID %d OID %u)",
1750 obj->name, obj->dumpId, obj->catId.oid);
1751 return;
1752 }
1753 /* shouldn't get here */
1755 "object type %d (ID %d OID %u)",
1756 (int) obj->objType,
1757 obj->dumpId, obj->catId.oid);
1758}
#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
Oid oid
Definition: pg_backup.h:281
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 {
390 ConstraintInfo *robj1 = *(ConstraintInfo *const *) p1;
391 ConstraintInfo *robj2 = *(ConstraintInfo *const *) p2;
392
393 /*
394 * Sort domain constraints before table constraints, for consistency
395 * with our decision to sort CREATE DOMAIN before CREATE TABLE.
396 */
397 if (robj1->condomain)
398 {
399 if (robj2->condomain)
400 {
401 /* Sort by domain name (domain namespace was considered) */
402 cmpval = strcmp(robj1->condomain->dobj.name,
403 robj2->condomain->dobj.name);
404 if (cmpval != 0)
405 return cmpval;
406 }
407 else
408 return PRIO_TYPE - PRIO_TABLE;
409 }
410 else if (robj2->condomain)
411 return PRIO_TABLE - PRIO_TYPE;
412 else
413 {
414 /* Sort by table name (table namespace was considered already) */
415 cmpval = strcmp(robj1->contable->dobj.name,
416 robj2->contable->dobj.name);
417 if (cmpval != 0)
418 return cmpval;
419 }
420 }
421 else if (obj1->objType == DO_DEFAULT_ACL)
422 {
423 DefaultACLInfo *daclobj1 = *(DefaultACLInfo *const *) p1;
424 DefaultACLInfo *daclobj2 = *(DefaultACLInfo *const *) p2;
425
426 /*
427 * Sort by defaclrole, per pg_default_acl_role_nsp_obj_index. The
428 * (namespace, name) match (defaclnamespace, defaclobjtype).
429 */
430 cmpval = strcmp(daclobj1->defaclrole, daclobj2->defaclrole);
431 if (cmpval != 0)
432 return cmpval;
433 }
434 else if (obj1->objType == DO_PUBLICATION_REL)
435 {
436 PublicationRelInfo *probj1 = *(PublicationRelInfo *const *) p1;
437 PublicationRelInfo *probj2 = *(PublicationRelInfo *const *) p2;
438
439 /* Sort by publication name, since (namespace, name) match the rel */
440 cmpval = strcmp(probj1->publication->dobj.name,
441 probj2->publication->dobj.name);
442 if (cmpval != 0)
443 return cmpval;
444 }
445 else if (obj1->objType == DO_PUBLICATION_TABLE_IN_SCHEMA)
446 {
447 PublicationSchemaInfo *psobj1 = *(PublicationSchemaInfo *const *) p1;
448 PublicationSchemaInfo *psobj2 = *(PublicationSchemaInfo *const *) p2;
449
450 /* Sort by publication name, since ->name is just nspname */
451 cmpval = strcmp(psobj1->publication->dobj.name,
452 psobj2->publication->dobj.name);
453 if (cmpval != 0)
454 return cmpval;
455 }
456
457 /*
458 * Shouldn't get here except after catalog corruption, but if we do, sort
459 * by OID. This may make logically-identical databases differ in the
460 * order of objects in dump output. Users will get spurious schema diffs.
461 * Expect flaky failures of 002_pg_upgrade.pl test 'dump outputs from
462 * original and restored regression databases match' if the regression
463 * database contains objects allowing that test to reach here. That's a
464 * consequence of the test using "pg_restore -j", which doesn't fully
465 * constrain OID assignment order.
466 */
467 Assert(false);
468 return oidcmp(obj1->catId.oid, obj2->catId.oid);
469}
i
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:473
static int accessMethodNameCompare(Oid am1, Oid am2)
Definition: pg_dump_sort.c:517
static const int dbObjectTypePriority[]
Definition: pg_dump_sort.c:105
DumpableObject dobj
Definition: pg_dump.h:669
PublicationInfo * publication
Definition: pg_dump.h:700
int adnum
Definition: pg_dump.h:406
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
Definition: pg_dump.h:259
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_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 748 of file pg_dump_sort.c.

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

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

Referenced by sortDumpableObjects().

findLoop()

static int findLoop ( DumpableObjectobj,
DumpId  startPoint,
bool *  processed,
DumpIdsearchFailed,
DumpableObject **  workspace,
int  depth 
)
static

Definition at line 844 of file pg_dump_sort.c.

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

1763{
1764 int ai = (int) (intptr_t) a;
1765 int bi = (int) (intptr_t) b;
1766
1767 return pg_cmp_s32(ai, bi);
1768}
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:646
b
int b
Definition: isn.c:74
a
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 473 of file pg_dump_sort.c.

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

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

Definition at line 1126 of file pg_dump_sort.c.

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

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

repairDomainConstraintMultiLoop()

static void repairDomainConstraintMultiLoop ( DumpableObjectdomainobj,
DumpableObjectconstraintobj 
)
static

Definition at line 1134 of file pg_dump_sort.c.

1136{
1137 /* remove domain's dependency on constraint */
1138 removeObjectDependency(domainobj, constraintobj->dumpId);
1139 /* mark constraint as needing its own dump */
1140 ((ConstraintInfo *) constraintobj)->separate = true;
1141 /* put back constraint's dependency on domain */
1142 addObjectDependency(constraintobj, domainobj->dumpId);
1143 /* now that constraint is separate, it must be post-data */
1144 addObjectDependency(constraintobj, postDataBoundId);
1145}
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 ( DumpableObjectboundaryobj,
DumpableObjectnextobj 
)
static

Definition at line 1048 of file pg_dump_sort.c.

1050{
1051 /* remove boundary's dependency on object after it in loop */
1052 removeObjectDependency(boundaryobj, nextobj->dumpId);
1053 /* if that object is a function, mark it as postponed into post-data */
1054 if (nextobj->objType == DO_FUNC)
1055 {
1056 FuncInfo *nextinfo = (FuncInfo *) nextobj;
1057
1058 nextinfo->postponed_def = true;
1059 }
1060}
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 ( DumpableObjectpartedindex,
DumpableObjectpartindex 
)
static

Definition at line 1148 of file pg_dump_sort.c.

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

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

repairMatViewBoundaryMultiLoop()

static void repairMatViewBoundaryMultiLoop ( DumpableObjectboundaryobj,
DumpableObjectnextobj 
)
static

Definition at line 1014 of file pg_dump_sort.c.

1016{
1017 /* remove boundary's dependency on object after it in loop */
1018 removeObjectDependency(boundaryobj, nextobj->dumpId);
1019
1020 /*
1021 * If that object is a matview or matview stats, mark it as postponed into
1022 * post-data.
1023 */
1024 if (nextobj->objType == DO_TABLE)
1025 {
1026 TableInfo *nextinfo = (TableInfo *) nextobj;
1027
1028 if (nextinfo->relkind == RELKIND_MATVIEW)
1029 nextinfo->postponed_def = true;
1030 }
1031 else if (nextobj->objType == DO_REL_STATS)
1032 {
1033 RelStatsInfo *nextinfo = (RelStatsInfo *) nextobj;
1034
1035 if (nextinfo->relkind == RELKIND_MATVIEW)
1036 nextinfo->section = SECTION_POST_DATA;
1037 }
1038}
@ 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 ( DumpableObjecttableobj,
DumpableObjectattrdefobj 
)
static

Definition at line 1103 of file pg_dump_sort.c.

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

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

repairTableAttrDefMultiLoop()

static void repairTableAttrDefMultiLoop ( DumpableObjecttableobj,
DumpableObjectattrdefobj 
)
static

Definition at line 1111 of file pg_dump_sort.c.

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

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

Referenced by repairDependencyLoop().

repairTableConstraintLoop()

static void repairTableConstraintLoop ( DumpableObjecttableobj,
DumpableObjectconstraintobj 
)
static

Definition at line 1069 of file pg_dump_sort.c.

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

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

repairTableConstraintMultiLoop()

static void repairTableConstraintMultiLoop ( DumpableObjecttableobj,
DumpableObjectconstraintobj 
)
static

Definition at line 1086 of file pg_dump_sort.c.

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

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

Referenced by repairDependencyLoop().

repairTypeFuncLoop()

static void repairTypeFuncLoop ( DumpableObjecttypeobj,
DumpableObjectfuncobj 
)
static

Definition at line 929 of file pg_dump_sort.c.

930{
931 TypeInfo *typeInfo = (TypeInfo *) typeobj;
932
933 /* remove function's dependency on type */
934 removeObjectDependency(funcobj, typeobj->dumpId);
935
936 /* add function's dependency on shell type, instead */
937 if (typeInfo->shellType)
938 {
939 addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
940
941 /*
942 * Mark shell type (always including the definition, as we need the
943 * shell type defined to identify the function fully) as to be dumped
944 * if any such function is
945 */
946 if (funcobj->dump)
947 typeInfo->shellType->dobj.dump = funcobj->dump |
949 }
950}
#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 ( DumpableObjectviewobj,
DumpableObjectruleobj 
)
static

Definition at line 960 of file pg_dump_sort.c.

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

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

repairViewRuleMultiLoop()

static void repairViewRuleMultiLoop ( DumpableObjectviewobj,
DumpableObjectruleobj 
)
static

Definition at line 980 of file pg_dump_sort.c.

982{
983 TableInfo *viewinfo = (TableInfo *) viewobj;
984 RuleInfo *ruleinfo = (RuleInfo *) ruleobj;
985
986 /* remove view's dependency on rule */
987 removeObjectDependency(viewobj, ruleobj->dumpId);
988 /* mark view to be printed with a dummy definition */
989 viewinfo->dummy_view = true;
990 /* mark rule as needing its own dump */
991 ruleinfo->separate = true;
992 /* put back rule's dependency on view */
993 addObjectDependency(ruleobj, viewobj->dumpId);
994 /* now that rule is separate, it must be post-data */
996}
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 547 of file pg_dump_sort.c.

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

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()

"array length mismatch"   
)

TopoSort()

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

Definition at line 599 of file pg_dump_sort.c.

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

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().

AltStyle によって変換されたページ (->オリジナル) /