diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-02-10 13:28:25 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-02-10 13:28:25 -0500 |
commit | 0951f4d1f5849ff3d868452debf4ced1a736efd0 (patch) | |
tree | c60fe928d99a6fc7907942a0b5b265df74256256 /src/bin/pg_dump/common.c | |
parent | 7b4fcabb2f7df4480fefd487c004369a98ac110c (diff) |
Fix pg_dump for better handling of inherited columns.
Revise pg_dump's handling of inherited columns, which was last looked at
seriously in 2001, to eliminate several misbehaviors associated with
inherited default expressions and NOT NULL flags. In particular make sure
that a column is printed in a child table's CREATE TABLE command if and
only if it has attislocal = true; the former behavior would sometimes cause
a column to become marked attislocal when it was not so marked in the
source database. Also, stop relying on textual comparison of default
expressions to decide if they're inherited; instead, don't use
default-expression inheritance at all, but just install the default
explicitly at each level of the hierarchy. This fixes the
search-path-related misbehavior recently exhibited by Chester Young, and
also removes some dubious assumptions about the order in which ALTER TABLE
SET DEFAULT commands would be executed.
Back-patch to all supported branches.
Diffstat (limited to 'src/bin/pg_dump/common.c')
-rw-r--r-- | src/bin/pg_dump/common.c | 153 |
1 files changed, 48 insertions, 105 deletions
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index fd7ce1d8f7d..fd8709f1d59 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -269,7 +269,13 @@ flagInhTables(TableInfo *tblinfo, int numTables, /* flagInhAttrs - * for each dumpable table in tblinfo, flag its inherited attributes - * so when we dump the table out, we don't dump out the inherited attributes + * + * What we need to do here is detect child columns that inherit NOT NULL + * bits from their parents (so that we needn't specify that again for the + * child) and child columns that have DEFAULT NULL when their parents had + * some non-null default. In the latter case, we make up a dummy AttrDefInfo + * object so that we'll correctly emit the necessary DEFAULT NULL clause; + * otherwise the backend will apply an inherited default to the column. * * modifies tblinfo */ @@ -285,7 +291,6 @@ flagInhAttrs(TableInfo *tblinfo, int numTables) TableInfo *tbinfo = &(tblinfo[i]); int numParents; TableInfo **parents; - TableInfo *parent; /* Sequences and views never have parents */ if (tbinfo->relkind == RELKIND_SEQUENCE || @@ -302,132 +307,70 @@ flagInhAttrs(TableInfo *tblinfo, int numTables) if (numParents == 0) continue; /* nothing to see here, move along */ - /*---------------------------------------------------------------- - * For each attr, check the parent info: if no parent has an attr - * with the same name, then it's not inherited. If there *is* an - * attr with the same name, then only dump it if: - * - * - it is NOT NULL and zero parents are NOT NULL - * OR - * - it has a default value AND the default value does not match - * all parent default values, or no parents specify a default. - * - * See discussion on -hackers around 2-Apr-2001. - *---------------------------------------------------------------- - */ + /* For each column, search for matching column names in parent(s) */ for (j = 0; j < tbinfo->numatts; j++) { - bool foundAttr; /* Attr was found in a parent */ bool foundNotNull; /* Attr was NOT NULL in a parent */ - bool defaultsMatch; /* All non-empty defaults match */ - bool defaultsFound; /* Found a default in a parent */ - AttrDefInfo *attrDef; - - foundAttr = false; - foundNotNull = false; - defaultsMatch = true; - defaultsFound = false; + bool foundDefault; /* Found a default in a parent */ - attrDef = tbinfo->attrdefs[j]; + /* no point in examining dropped columns */ + if (tbinfo->attisdropped[j]) + continue; + foundNotNull = false; + foundDefault = false; for (k = 0; k < numParents; k++) { + TableInfo *parent = parents[k]; int inhAttrInd; - parent = parents[k]; inhAttrInd = strInArray(tbinfo->attnames[j], parent->attnames, parent->numatts); - - if (inhAttrInd != -1) + if (inhAttrInd >= 0) { - AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd]; - - foundAttr = true; foundNotNull |= parent->notnull[inhAttrInd]; - if (inhDef != NULL) - { - defaultsFound = true; - - /* - * If any parent has a default and the child doesn't, - * we have to emit an explicit DEFAULT NULL clause for - * the child, else the parent's default will win. - */ - if (attrDef == NULL) - { - attrDef = (AttrDefInfo *) malloc(sizeof(AttrDefInfo)); - attrDef->dobj.objType = DO_ATTRDEF; - attrDef->dobj.catId.tableoid = 0; - attrDef->dobj.catId.oid = 0; - AssignDumpId(&attrDef->dobj); - attrDef->adtable = tbinfo; - attrDef->adnum = j + 1; - attrDef->adef_expr = strdup("NULL"); - - attrDef->dobj.name = strdup(tbinfo->dobj.name); - attrDef->dobj.namespace = tbinfo->dobj.namespace; - - attrDef->dobj.dump = tbinfo->dobj.dump; - - attrDef->separate = false; - addObjectDependency(&tbinfo->dobj, - attrDef->dobj.dumpId); - - tbinfo->attrdefs[j] = attrDef; - } - if (strcmp(attrDef->adef_expr, inhDef->adef_expr) != 0) - { - defaultsMatch = false; - - /* - * Whenever there is a non-matching parent - * default, add a dependency to force the parent - * default to be dumped first, in case the - * defaults end up being dumped as separate - * commands. Otherwise the parent default will - * override the child's when it is applied. - */ - addObjectDependency(&attrDef->dobj, - inhDef->dobj.dumpId); - } - } + foundDefault |= (parent->attrdefs[inhAttrInd] != NULL); } } - /* - * Based on the scan of the parents, decide if we can rely on the - * inherited attr - */ - if (foundAttr) /* Attr was inherited */ + /* Remember if we found inherited NOT NULL */ + tbinfo->inhNotNull[j] = foundNotNull; + + /* Manufacture a DEFAULT NULL clause if necessary */ + if (foundDefault && tbinfo->attrdefs[j] == NULL) { - /* Set inherited flag by default */ - tbinfo->inhAttrs[j] = true; - tbinfo->inhAttrDef[j] = true; - tbinfo->inhNotNull[j] = true; - - /* - * Clear it if attr had a default, but parents did not, or - * mismatch - */ - if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch)) + AttrDefInfo *attrDef; + + attrDef = (AttrDefInfo *) malloc(sizeof(AttrDefInfo)); + attrDef->dobj.objType = DO_ATTRDEF; + attrDef->dobj.catId.tableoid = 0; + attrDef->dobj.catId.oid = 0; + AssignDumpId(&attrDef->dobj); + attrDef->dobj.name = strdup(tbinfo->dobj.name); + attrDef->dobj.namespace = tbinfo->dobj.namespace; + attrDef->dobj.dump = tbinfo->dobj.dump; + + attrDef->adtable = tbinfo; + attrDef->adnum = j + 1; + attrDef->adef_expr = strdup("NULL"); + + /* Will column be dumped explicitly? */ + if (shouldPrintColumn(tbinfo, j)) { - tbinfo->inhAttrs[j] = false; - tbinfo->inhAttrDef[j] = false; + attrDef->separate = false; + /* No dependency needed: NULL cannot have dependencies */ } - - /* - * Clear it if NOT NULL and none of the parents were NOT NULL - */ - if (tbinfo->notnull[j] && !foundNotNull) + else { - tbinfo->inhAttrs[j] = false; - tbinfo->inhNotNull[j] = false; + /* column will be suppressed, print default separately */ + attrDef->separate = true; + /* ensure it comes out after the table */ + addObjectDependency(&attrDef->dobj, + tbinfo->dobj.dumpId); } - /* Clear it if attr has local definition */ - if (tbinfo->attislocal[j]) - tbinfo->inhAttrs[j] = false; + tbinfo->attrdefs[j] = attrDef; } } } |