mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Change the rules for inherited CHECK constraints to be essentially the same
as those for inherited columns; that is, it's no longer allowed for a child table to not have a check constraint matching one that exists on a parent. This satisfies the principle of least surprise (rows selected from the parent will always appear to meet its check constraints) and eliminates some longstanding bogosity in pg_dump, which formerly had to guess about whether check constraints were really inherited or not. The implementation involves adding conislocal and coninhcount columns to pg_constraint (paralleling attislocal and attinhcount in pg_attribute) and refactoring various ALTER TABLE actions to be more like those for columns. Alex Hunsaker, Nikhil Sontakke, Tom Lane
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.489 2008/05/03 23:32:32 adunstan Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.490 2008/05/09 23:32:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -120,6 +120,7 @@ static void expand_table_name_patterns(SimpleStringList *patterns,
|
||||
SimpleOidList *oids);
|
||||
static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
|
||||
static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
|
||||
static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
|
||||
static void dumpComment(Archive *fout, const char *target,
|
||||
const char *namespace, const char *owner,
|
||||
CatalogId catalogId, int subid, DumpId dumpId);
|
||||
@@ -645,6 +646,9 @@ main(int argc, char **argv)
|
||||
*/
|
||||
tblinfo = getSchemaData(&numTables);
|
||||
|
||||
if (g_fout->remoteVersion < 80400)
|
||||
guessConstraintInheritance(tblinfo, numTables);
|
||||
|
||||
if (!schemaOnly)
|
||||
getTableData(tblinfo, numTables, oids);
|
||||
|
||||
@@ -1383,6 +1387,81 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* guessConstraintInheritance:
|
||||
* In pre-8.4 databases, we can't tell for certain which constraints
|
||||
* are inherited. We assume a CHECK constraint is inherited if its name
|
||||
* matches the name of any constraint in the parent. Originally this code
|
||||
* tried to compare the expression texts, but that can fail for various
|
||||
* reasons --- for example, if the parent and child tables are in different
|
||||
* schemas, reverse-listing of function calls may produce different text
|
||||
* (schema-qualified or not) depending on search path.
|
||||
*
|
||||
* In 8.4 and up we can rely on the conislocal field to decide which
|
||||
* constraints must be dumped; much safer.
|
||||
*
|
||||
* This function assumes all conislocal flags were initialized to TRUE.
|
||||
* It clears the flag on anything that seems to be inherited.
|
||||
*/
|
||||
static void
|
||||
guessConstraintInheritance(TableInfo *tblinfo, int numTables)
|
||||
{
|
||||
int i,
|
||||
j,
|
||||
k;
|
||||
|
||||
for (i = 0; i < numTables; i++)
|
||||
{
|
||||
TableInfo *tbinfo = &(tblinfo[i]);
|
||||
int numParents;
|
||||
TableInfo **parents;
|
||||
TableInfo *parent;
|
||||
|
||||
/* Sequences and views never have parents */
|
||||
if (tbinfo->relkind == RELKIND_SEQUENCE ||
|
||||
tbinfo->relkind == RELKIND_VIEW)
|
||||
continue;
|
||||
|
||||
/* Don't bother computing anything for non-target tables, either */
|
||||
if (!tbinfo->dobj.dump)
|
||||
continue;
|
||||
|
||||
numParents = tbinfo->numParents;
|
||||
parents = tbinfo->parents;
|
||||
|
||||
if (numParents == 0)
|
||||
continue; /* nothing to see here, move along */
|
||||
|
||||
/* scan for inherited CHECK constraints */
|
||||
for (j = 0; j < tbinfo->ncheck; j++)
|
||||
{
|
||||
ConstraintInfo *constr;
|
||||
|
||||
constr = &(tbinfo->checkexprs[j]);
|
||||
|
||||
for (k = 0; k < numParents; k++)
|
||||
{
|
||||
int l;
|
||||
|
||||
parent = parents[k];
|
||||
for (l = 0; l < parent->ncheck; l++)
|
||||
{
|
||||
ConstraintInfo *pconstr = &(parent->checkexprs[l]);
|
||||
|
||||
if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
|
||||
{
|
||||
constr->conislocal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!constr->conislocal)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dumpDatabase:
|
||||
* dump the database definition
|
||||
@@ -3522,7 +3601,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
|
||||
constrinfo[j].contype = contype;
|
||||
constrinfo[j].condef = NULL;
|
||||
constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
|
||||
constrinfo[j].coninherited = false;
|
||||
constrinfo[j].conislocal = true;
|
||||
constrinfo[j].separate = true;
|
||||
|
||||
indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
|
||||
@@ -3623,7 +3702,7 @@ getConstraints(TableInfo tblinfo[], int numTables)
|
||||
constrinfo[j].contype = 'f';
|
||||
constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
|
||||
constrinfo[j].conindex = 0;
|
||||
constrinfo[j].coninherited = false;
|
||||
constrinfo[j].conislocal = true;
|
||||
constrinfo[j].separate = true;
|
||||
}
|
||||
|
||||
@@ -3706,7 +3785,7 @@ getDomainConstraints(TypeInfo *tinfo)
|
||||
constrinfo[i].contype = 'c';
|
||||
constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
|
||||
constrinfo[i].conindex = 0;
|
||||
constrinfo[i].coninherited = false;
|
||||
constrinfo[i].conislocal = true;
|
||||
constrinfo[i].separate = false;
|
||||
|
||||
/*
|
||||
@@ -4586,10 +4665,22 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
tbinfo->dobj.name);
|
||||
|
||||
resetPQExpBuffer(q);
|
||||
if (g_fout->remoteVersion >= 70400)
|
||||
if (g_fout->remoteVersion >= 80400)
|
||||
{
|
||||
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
||||
"pg_catalog.pg_get_constraintdef(oid) AS consrc "
|
||||
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
|
||||
"conislocal "
|
||||
"FROM pg_catalog.pg_constraint "
|
||||
"WHERE conrelid = '%u'::pg_catalog.oid "
|
||||
" AND contype = 'c' "
|
||||
"ORDER BY conname",
|
||||
tbinfo->dobj.catId.oid);
|
||||
}
|
||||
else if (g_fout->remoteVersion >= 70400)
|
||||
{
|
||||
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
||||
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
|
||||
"true as conislocal "
|
||||
"FROM pg_catalog.pg_constraint "
|
||||
"WHERE conrelid = '%u'::pg_catalog.oid "
|
||||
" AND contype = 'c' "
|
||||
@@ -4600,7 +4691,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
{
|
||||
/* no pg_get_constraintdef, must use consrc */
|
||||
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
||||
"'CHECK (' || consrc || ')' AS consrc "
|
||||
"'CHECK (' || consrc || ')' AS consrc, "
|
||||
"true as conislocal "
|
||||
"FROM pg_catalog.pg_constraint "
|
||||
"WHERE conrelid = '%u'::pg_catalog.oid "
|
||||
" AND contype = 'c' "
|
||||
@@ -4612,7 +4704,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
/* 7.2 did not have OIDs in pg_relcheck */
|
||||
appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, "
|
||||
"rcname AS conname, "
|
||||
"'CHECK (' || rcsrc || ')' AS consrc "
|
||||
"'CHECK (' || rcsrc || ')' AS consrc, "
|
||||
"true as conislocal "
|
||||
"FROM pg_relcheck "
|
||||
"WHERE rcrelid = '%u'::oid "
|
||||
"ORDER BY rcname",
|
||||
@@ -4622,7 +4715,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
{
|
||||
appendPQExpBuffer(q, "SELECT tableoid, oid, "
|
||||
"rcname AS conname, "
|
||||
"'CHECK (' || rcsrc || ')' AS consrc "
|
||||
"'CHECK (' || rcsrc || ')' AS consrc, "
|
||||
"true as conislocal "
|
||||
"FROM pg_relcheck "
|
||||
"WHERE rcrelid = '%u'::oid "
|
||||
"ORDER BY rcname",
|
||||
@@ -4634,7 +4728,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
appendPQExpBuffer(q, "SELECT "
|
||||
"(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
|
||||
"oid, rcname AS conname, "
|
||||
"'CHECK (' || rcsrc || ')' AS consrc "
|
||||
"'CHECK (' || rcsrc || ')' AS consrc, "
|
||||
"true as conislocal "
|
||||
"FROM pg_relcheck "
|
||||
"WHERE rcrelid = '%u'::oid "
|
||||
"ORDER BY rcname",
|
||||
@@ -4668,7 +4763,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
constrs[j].contype = 'c';
|
||||
constrs[j].condef = strdup(PQgetvalue(res, j, 3));
|
||||
constrs[j].conindex = 0;
|
||||
constrs[j].coninherited = false;
|
||||
constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
|
||||
constrs[j].separate = false;
|
||||
|
||||
constrs[j].dobj.dump = tbinfo->dobj.dump;
|
||||
@@ -4684,8 +4779,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
||||
|
||||
/*
|
||||
* If the constraint is inherited, this will be detected
|
||||
* later. We also detect later if the constraint must be
|
||||
* split out from the table definition.
|
||||
* later (in pre-8.4 databases). We also detect later if the
|
||||
* constraint must be split out from the table definition.
|
||||
*/
|
||||
}
|
||||
PQclear(res);
|
||||
@@ -8840,7 +8935,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
||||
{
|
||||
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
|
||||
|
||||
if (constr->coninherited || constr->separate)
|
||||
if (constr->separate || !constr->conislocal)
|
||||
continue;
|
||||
|
||||
if (actual_atts > 0)
|
||||
@@ -8955,7 +9050,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
||||
{
|
||||
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
|
||||
|
||||
if (constr->coninherited || constr->separate)
|
||||
if (constr->separate || !constr->conislocal)
|
||||
continue;
|
||||
|
||||
dumpTableConstraintComment(fout, constr);
|
||||
|
Reference in New Issue
Block a user