Commit beaf5ae6 authored by Tom Lane's avatar Tom Lane

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.
parent ad538d8b
......@@ -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;
......
......@@ -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);
}
......
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