Commit 00bc96bd authored by Tom Lane's avatar Tom Lane

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.
parent d06e2d20
...@@ -281,7 +281,13 @@ flagInhTables(TableInfo *tblinfo, int numTables, ...@@ -281,7 +281,13 @@ flagInhTables(TableInfo *tblinfo, int numTables,
/* flagInhAttrs - /* flagInhAttrs -
* for each dumpable table in tblinfo, flag its inherited attributes * 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 * modifies tblinfo
*/ */
...@@ -297,7 +303,6 @@ flagInhAttrs(TableInfo *tblinfo, int numTables) ...@@ -297,7 +303,6 @@ flagInhAttrs(TableInfo *tblinfo, int numTables)
TableInfo *tbinfo = &(tblinfo[i]); TableInfo *tbinfo = &(tblinfo[i]);
int numParents; int numParents;
TableInfo **parents; TableInfo **parents;
TableInfo *parent;
/* Sequences and views never have parents */ /* Sequences and views never have parents */
if (tbinfo->relkind == RELKIND_SEQUENCE || if (tbinfo->relkind == RELKIND_SEQUENCE ||
...@@ -314,132 +319,70 @@ flagInhAttrs(TableInfo *tblinfo, int numTables) ...@@ -314,132 +319,70 @@ flagInhAttrs(TableInfo *tblinfo, int numTables)
if (numParents == 0) if (numParents == 0)
continue; /* nothing to see here, move along */ continue; /* nothing to see here, move along */
/*---------------------------------------------------------------- /* For each column, search for matching column names in parent(s) */
* 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 (j = 0; j < tbinfo->numatts; j++) 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 foundNotNull; /* Attr was NOT NULL in a parent */
bool defaultsMatch; /* All non-empty defaults match */ bool foundDefault; /* Found a default in a parent */
bool defaultsFound; /* Found a default in a parent */
AttrDefInfo *attrDef;
foundAttr = false;
foundNotNull = false;
defaultsMatch = true;
defaultsFound = false;
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++) for (k = 0; k < numParents; k++)
{ {
TableInfo *parent = parents[k];
int inhAttrInd; int inhAttrInd;
parent = parents[k];
inhAttrInd = strInArray(tbinfo->attnames[j], inhAttrInd = strInArray(tbinfo->attnames[j],
parent->attnames, parent->attnames,
parent->numatts); parent->numatts);
if (inhAttrInd >= 0)
if (inhAttrInd != -1)
{ {
AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd];
foundAttr = true;
foundNotNull |= parent->notnull[inhAttrInd]; foundNotNull |= parent->notnull[inhAttrInd];
if (inhDef != NULL) foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
{ }
defaultsFound = true; }
/* /* Remember if we found inherited NOT NULL */
* If any parent has a default and the child doesn't, tbinfo->inhNotNull[j] = foundNotNull;
* we have to emit an explicit DEFAULT NULL clause for
* the child, else the parent's default will win. /* Manufacture a DEFAULT NULL clause if necessary */
*/ if (foundDefault && tbinfo->attrdefs[j] == NULL)
if (attrDef == NULL)
{ {
AttrDefInfo *attrDef;
attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo)); attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
attrDef->dobj.objType = DO_ATTRDEF; attrDef->dobj.objType = DO_ATTRDEF;
attrDef->dobj.catId.tableoid = 0; attrDef->dobj.catId.tableoid = 0;
attrDef->dobj.catId.oid = 0; attrDef->dobj.catId.oid = 0;
AssignDumpId(&attrDef->dobj); AssignDumpId(&attrDef->dobj);
attrDef->adtable = tbinfo;
attrDef->adnum = j + 1;
attrDef->adef_expr = pg_strdup("NULL");
attrDef->dobj.name = pg_strdup(tbinfo->dobj.name); attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
attrDef->dobj.namespace = tbinfo->dobj.namespace; attrDef->dobj.namespace = tbinfo->dobj.namespace;
attrDef->dobj.dump = tbinfo->dobj.dump; attrDef->dobj.dump = tbinfo->dobj.dump;
attrDef->separate = false; attrDef->adtable = tbinfo;
addObjectDependency(&tbinfo->dobj, attrDef->adnum = j + 1;
attrDef->dobj.dumpId); attrDef->adef_expr = pg_strdup("NULL");
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);
}
}
}
}
/*
* Based on the scan of the parents, decide if we can rely on the
* inherited attr
*/
if (foundAttr) /* Attr was inherited */
{
/* Set inherited flag by default */
tbinfo->inhAttrs[j] = true;
tbinfo->inhAttrDef[j] = true;
tbinfo->inhNotNull[j] = true;
/* /* Will column be dumped explicitly? */
* Clear it if attr had a default, but parents did not, or if (shouldPrintColumn(tbinfo, j))
* mismatch
*/
if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
{ {
tbinfo->inhAttrs[j] = false; attrDef->separate = false;
tbinfo->inhAttrDef[j] = false; /* No dependency needed: NULL cannot have dependencies */
} }
else
/*
* Clear it if NOT NULL and none of the parents were NOT NULL
*/
if (tbinfo->notnull[j] && !foundNotNull)
{ {
tbinfo->inhAttrs[j] = false; /* column will be suppressed, print default separately */
tbinfo->inhNotNull[j] = false; attrDef->separate = true;
/* ensure it comes out after the table */
addObjectDependency(&attrDef->dobj,
tbinfo->dobj.dumpId);
} }
/* Clear it if attr has local definition */ tbinfo->attrdefs[j] = attrDef;
if (tbinfo->attislocal[j])
tbinfo->inhAttrs[j] = false;
} }
} }
} }
......
This diff is collapsed.
...@@ -277,17 +277,9 @@ typedef struct _tableInfo ...@@ -277,17 +277,9 @@ typedef struct _tableInfo
char **attoptions; /* per-attribute options */ char **attoptions; /* per-attribute options */
Oid *attcollation; /* per-attribute collation selection */ Oid *attcollation; /* per-attribute collation selection */
char **attfdwoptions; /* per-attribute fdw options */ char **attfdwoptions; /* per-attribute fdw options */
bool *notnull; /* NOT NULL constraints on attributes */
/*
* Note: we need to store per-attribute notnull, default, and constraint
* stuff for all interesting tables so that we can tell which constraints
* were inherited.
*/
bool *notnull; /* Not null constraints on attributes */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
bool *inhAttrs; /* true if each attribute is inherited */
bool *inhAttrDef; /* true if attr's default is inherited */
bool *inhNotNull; /* true if NOT NULL is inherited */ bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */ struct _constraintInfo *checkexprs; /* CHECK constraints */
/* /*
...@@ -300,7 +292,7 @@ typedef struct _tableInfo ...@@ -300,7 +292,7 @@ typedef struct _tableInfo
typedef struct _attrDefInfo typedef struct _attrDefInfo
{ {
DumpableObject dobj; DumpableObject dobj; /* note: dobj.name is name of table */
TableInfo *adtable; /* link to table of attribute */ TableInfo *adtable; /* link to table of attribute */
int adnum; int adnum;
char *adef_expr; /* decompiled DEFAULT expression */ char *adef_expr; /* decompiled DEFAULT expression */
...@@ -556,6 +548,7 @@ extern void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables); ...@@ -556,6 +548,7 @@ extern void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables);
extern ProcLangInfo *getProcLangs(Archive *fout, int *numProcLangs); extern ProcLangInfo *getProcLangs(Archive *fout, int *numProcLangs);
extern CastInfo *getCasts(Archive *fout, int *numCasts); extern CastInfo *getCasts(Archive *fout, int *numCasts);
extern void getTableAttrs(Archive *fout, TableInfo *tbinfo, int numTables); extern void getTableAttrs(Archive *fout, TableInfo *tbinfo, int numTables);
extern bool shouldPrintColumn(TableInfo *tbinfo, int colno);
extern TSParserInfo *getTSParsers(Archive *fout, int *numTSParsers); extern TSParserInfo *getTSParsers(Archive *fout, int *numTSParsers);
extern TSDictInfo *getTSDictionaries(Archive *fout, int *numTSDicts); extern TSDictInfo *getTSDictionaries(Archive *fout, int *numTSDicts);
extern TSTemplateInfo *getTSTemplates(Archive *fout, int *numTSTemplates); extern TSTemplateInfo *getTSTemplates(Archive *fout, int *numTSTemplates);
......
...@@ -188,6 +188,15 @@ DOTypeNameCompare(const void *p1, const void *p2) ...@@ -188,6 +188,15 @@ DOTypeNameCompare(const void *p1, const void *p2)
if (cmpval != 0) if (cmpval != 0)
return cmpval; return cmpval;
} }
else if (obj1->objType == DO_ATTRDEF)
{
AttrDefInfo *adobj1 = *(AttrDefInfo * const *) p1;
AttrDefInfo *adobj2 = *(AttrDefInfo * const *) p2;
cmpval = (adobj1->adnum - adobj2->adnum);
if (cmpval != 0)
return cmpval;
}
/* Usually shouldn't get here, but if we do, sort by OID */ /* Usually shouldn't get here, but if we do, sort by OID */
return oidcmp(obj1->catId.oid, obj2->catId.oid); return oidcmp(obj1->catId.oid, obj2->catId.oid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment