From beaf5ae623f9dd323da095fb65c74768ebc8afc5 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 24 Jan 2005 23:21:57 +0000 Subject: [PATCH] Fix ALTER TABLE ADD COLUMN so that constraints of domain types are enforced properly when there is no explicit default value for the new column. Per report from Craig Perras. --- src/backend/commands/tablecmds.c | 35 ++++++++++++++++++++++++++++++++--- src/backend/commands/typecmds.c | 21 ++++++++++++--------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b788db35cb..89dd8dffae 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.142 2005/01/10 20:02:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.143 2005/01/24 23:21:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include "commands/tablecmds.h" #include "commands/tablespace.h" #include "commands/trigger.h" +#include "commands/typecmds.h" #include "executor/executor.h" #include "lib/stringinfo.h" #include "miscadmin.h" @@ -2853,6 +2854,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, int minattnum, maxatts; HeapTuple typeTuple; + Oid typeOid; Form_pg_type tform; Expr *defval; @@ -2930,9 +2932,10 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, typeTuple = typenameType(colDef->typename); tform = (Form_pg_type) GETSTRUCT(typeTuple); + typeOid = HeapTupleGetOid(typeTuple); /* make sure datatype is legal for a column */ - CheckAttributeType(colDef->colname, HeapTupleGetOid(typeTuple)); + CheckAttributeType(colDef->colname, typeOid); attributeTuple = heap_addheader(Natts_pg_attribute, false, @@ -2943,7 +2946,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, attribute->attrelid = myrelid; namestrcpy(&(attribute->attname), colDef->colname); - attribute->atttypid = HeapTupleGetOid(typeTuple); + attribute->atttypid = typeOid; attribute->attstattarget = -1; attribute->attlen = tform->typlen; attribute->attcacheoff = -1; @@ -3015,11 +3018,37 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, * and return NULL if so, so without any modification of the tuple * data we will get the effect of NULL values in the new column. * + * An exception occurs when the new column is of a domain type: the + * domain might have a NOT NULL constraint, or a check constraint that + * indirectly rejects nulls. If there are any domain constraints then + * we construct an explicit NULL default value that will be passed through + * CoerceToDomain processing. (This is a tad inefficient, since it + * causes rewriting the table which we really don't have to do, but + * the present design of domain processing doesn't offer any simple way + * of checking the constraints more directly.) + * * Note: we use build_column_default, and not just the cooked default * returned by AddRelationRawConstraints, so that the right thing * happens when a datatype's default applies. */ defval = (Expr *) build_column_default(rel, attribute->attnum); + + if (!defval && GetDomainConstraints(typeOid) != NIL) + { + Oid basetype = getBaseType(typeOid); + + defval = (Expr *) makeNullConst(basetype); + defval = (Expr *) coerce_to_target_type(NULL, + (Node *) defval, + basetype, + typeOid, + colDef->typename->typmod, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST); + if (defval == NULL) /* should not happen */ + elog(ERROR, "failed to coerce base type to domain"); + } + if (defval) { NewColumnValue *newval; diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index efeb3f3bab..d9fffbec27 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.65 2004/12/31 21:59:42 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.66 2005/01/24 23:21:57 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -1929,6 +1929,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, * This is called by the executor during plan startup for a CoerceToDomain * expression node. The given constraints will be checked for each value * passed through the node. + * + * We allow this to be called for non-domain types, in which case the result + * is always NIL. */ List * GetDomainConstraints(Oid typeOid) @@ -1954,6 +1957,13 @@ GetDomainConstraints(Oid typeOid) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); + if (typTup->typtype != 'd') + { + /* Not a domain, so done */ + ReleaseSysCache(tup); + break; + } + /* Test for NOT NULL Constraint */ if (typTup->typnotnull) notNull = true; @@ -2010,14 +2020,7 @@ GetDomainConstraints(Oid typeOid) systable_endscan(scan); - if (typTup->typtype != 'd') - { - /* Not a domain, so done */ - ReleaseSysCache(tup); - break; - } - - /* else loop to next domain in stack */ + /* loop to next domain in stack */ typeOid = typTup->typbasetype; ReleaseSysCache(tup); } -- 2.11.0