mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Fix handling of inherited check constraints in ALTER COLUMN TYPE (again).
The previous way of reconstructing check constraints was to do a separate "ALTER TABLE ONLY tab ADD CONSTRAINT" for each table in an inheritance hierarchy. However, that way has no hope of reconstructing the check constraints' own inheritance properties correctly, as pointed out in bug #13779 from Jan Dirk Zijlstra. What we should do instead is to do a regular "ALTER TABLE", allowing recursion, at the topmost table that has a particular constraint, and then suppress the work queue entries for inherited instances of the constraint. Annoyingly, we'd tried to fix this behavior before, in commit5ed6546cf
, but we failed to notice that it wasn't reconstructing the pg_constraint field values correctly. As long as I'm touching pg_get_constraintdef_worker anyway, tweak it to always schema-qualify the target table name; this seems like useful backup to the protections installed by commit5f173040
. In HEAD/9.5, get rid of get_constraint_relation_oids, which is now unused. (I could alternatively have modified it to also return conislocal, but that seemed like a pretty single-purpose API, so let's not pretend it has some other use.) It's unused in the back branches as well, but I left it in place just in case some third-party code has decided to use it. In HEAD/9.5, also rename pg_get_constraintdef_string to pg_get_constraintdef_command, as the previous name did nothing to explain what that entry point did differently from others (and its comment was equally useless). Again, that change doesn't seem like material for back-patching. I did a bit of re-pgindenting in tablecmds.c in HEAD/9.5, as well. Otherwise, back-patch to all supported branches.
This commit is contained in:
@ -420,6 +420,7 @@ static Node *processIndirection(Node *node, deparse_context *context,
|
||||
static void printSubscripts(ArrayRef *aref, deparse_context *context);
|
||||
static char *get_relation_name(Oid relid);
|
||||
static char *generate_relation_name(Oid relid, List *namespaces);
|
||||
static char *generate_qualified_relation_name(Oid relid);
|
||||
static char *generate_function_name(Oid funcid, int nargs,
|
||||
List *argnames, Oid *argtypes,
|
||||
bool has_variadic, bool *use_variadic_p);
|
||||
@ -1298,7 +1299,9 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
|
||||
prettyFlags)));
|
||||
}
|
||||
|
||||
/* Internal version that returns a palloc'd C string; no pretty-printing */
|
||||
/*
|
||||
* Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
|
||||
*/
|
||||
char *
|
||||
pg_get_constraintdef_string(Oid constraintId)
|
||||
{
|
||||
@ -1347,10 +1350,16 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
if (fullCommand && OidIsValid(conForm->conrelid))
|
||||
if (fullCommand)
|
||||
{
|
||||
appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
|
||||
generate_relation_name(conForm->conrelid, NIL),
|
||||
/*
|
||||
* Currently, callers want ALTER TABLE (without ONLY) for CHECK
|
||||
* constraints, and other types of constraints don't inherit anyway so
|
||||
* it doesn't matter whether we say ONLY or not. Someday we might
|
||||
* need to let callers specify whether to put ONLY in the command.
|
||||
*/
|
||||
appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
|
||||
generate_qualified_relation_name(conForm->conrelid),
|
||||
quote_identifier(NameStr(conForm->conname)));
|
||||
}
|
||||
|
||||
@ -1874,28 +1883,9 @@ pg_get_serial_sequence(PG_FUNCTION_ARGS)
|
||||
|
||||
if (OidIsValid(sequenceId))
|
||||
{
|
||||
HeapTuple classtup;
|
||||
Form_pg_class classtuple;
|
||||
char *nspname;
|
||||
char *result;
|
||||
|
||||
/* Get the sequence's pg_class entry */
|
||||
classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(sequenceId));
|
||||
if (!HeapTupleIsValid(classtup))
|
||||
elog(ERROR, "cache lookup failed for relation %u", sequenceId);
|
||||
classtuple = (Form_pg_class) GETSTRUCT(classtup);
|
||||
|
||||
/* Get the namespace */
|
||||
nspname = get_namespace_name(classtuple->relnamespace);
|
||||
if (!nspname)
|
||||
elog(ERROR, "cache lookup failed for namespace %u",
|
||||
classtuple->relnamespace);
|
||||
|
||||
/* And construct the result string */
|
||||
result = quote_qualified_identifier(nspname,
|
||||
NameStr(classtuple->relname));
|
||||
|
||||
ReleaseSysCache(classtup);
|
||||
result = generate_qualified_relation_name(sequenceId);
|
||||
|
||||
PG_RETURN_TEXT_P(string_to_text(result));
|
||||
}
|
||||
@ -9138,6 +9128,39 @@ generate_relation_name(Oid relid, List *namespaces)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate_qualified_relation_name
|
||||
* Compute the name to display for a relation specified by OID
|
||||
*
|
||||
* As above, but unconditionally schema-qualify the name.
|
||||
*/
|
||||
static char *
|
||||
generate_qualified_relation_name(Oid relid)
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_class reltup;
|
||||
char *relname;
|
||||
char *nspname;
|
||||
char *result;
|
||||
|
||||
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "cache lookup failed for relation %u", relid);
|
||||
reltup = (Form_pg_class) GETSTRUCT(tp);
|
||||
relname = NameStr(reltup->relname);
|
||||
|
||||
nspname = get_namespace_name(reltup->relnamespace);
|
||||
if (!nspname)
|
||||
elog(ERROR, "cache lookup failed for namespace %u",
|
||||
reltup->relnamespace);
|
||||
|
||||
result = quote_qualified_identifier(nspname, relname);
|
||||
|
||||
ReleaseSysCache(tp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate_function_name
|
||||
* Compute the name to display for a function specified by OID,
|
||||
|
Reference in New Issue
Block a user