In ALTER COLUMN TYPE, strip any implicit coercion operations appearing
authorTom Lane
Fri, 22 Oct 2004 17:20:05 +0000 (17:20 +0000)
committerTom Lane
Fri, 22 Oct 2004 17:20:05 +0000 (17:20 +0000)
at the top level of the column's old default expression before adding
an implicit coercion to the new column type.  This seems to satisfy the
principle of least surprise, as per discussion of bug #1290.

doc/src/sgml/ref/alter_table.sgml
src/backend/commands/tablecmds.c
src/backend/optimizer/util/clauses.c
src/include/optimizer/clauses.h

index 263e5024b62148863c139a523222af253871288a..e5856d9bfb4cea718b2e886313267f96f6cf7b92 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -459,6 +459,22 @@ ALTER TABLE table ALTER COLUMN anycol TYPE anytype;
     data.
    
 
+   
+    The USING option of ALTER TYPE can actually
+    specify any expression involving the old values of the row; that is, it
+    can refer to other columns as well as the one being converted.  This allows
+    very general conversions to be done with the ALTER TYPE
+    syntax.  Because of this flexibility, the USING
+    expression is not applied to the column's default value (if any); the
+    result might not be a constant expression as required for a default.
+    This means that when there is no implicit or assignment cast from old to
+    new type, ALTER TYPE may fail to convert the default even
+    though a USING clause is supplied.  In such cases,
+    drop the default with DROP DEFAULT, perform the ALTER
+    TYPE, and then use SET DEFAULT to add a suitable new
+    default.
+   
+
    
     If a table has any descendant tables, it is not permitted to add,
     rename, or change the type of a column in the parent table without doing
index 463d2506c2e39554a8d8fb7ab600cfdb2905f9f2..3616275858392c370bdc5457557b48f701d08101 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.136 2004/10/21 21:33:59 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.137 2004/10/22 17:20:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4738,13 +4738,20 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
     * changing the column type, because build_column_default itself will
     * try to coerce, and will not issue the error message we want if it
     * fails.)
+    *
+    * We remove any implicit coercion steps at the top level of the old
+    * default expression; this has been agreed to satisfy the principle
+    * of least surprise.  (The conversion to the new column type should
+    * act like it started from what the user sees as the stored expression,
+    * and the implicit coercions aren't going to be shown.)
     */
    if (attTup->atthasdef)
    {
        defaultexpr = build_column_default(rel, attnum);
        Assert(defaultexpr);
+       defaultexpr = strip_implicit_coercions(defaultexpr);
        defaultexpr = coerce_to_target_type(NULL,       /* no UNKNOWN params */
-                                     defaultexpr, exprType(defaultexpr),
+                                           defaultexpr, exprType(defaultexpr),
                                            targettype, typename->typmod,
                                            COERCION_ASSIGNMENT,
                                            COERCE_IMPLICIT_CAST);
index b6ac7786aa7a96d7a95912271cf1cbd9418a7094..0f7d8dc31fcae1c2640cb4e2d91c5059bc36f17d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.182 2004/10/07 18:38:49 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.183 2004/10/22 17:20:05 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -1021,6 +1021,41 @@ CommuteClause(OpExpr *clause)
    lsecond(clause->args) = temp;
 }
 
+/*
+ * strip_implicit_coercions: remove implicit coercions at top level of tree
+ *
+ * Note: there isn't any useful thing we can do with a RowExpr here, so
+ * just return it unchanged, even if it's marked as an implicit coercion.
+ */
+Node *
+strip_implicit_coercions(Node *node)
+{
+   if (node == NULL)
+       return NULL;
+   if (IsA(node, FuncExpr))
+   {
+       FuncExpr   *f = (FuncExpr *) node;
+
+       if (f->funcformat == COERCE_IMPLICIT_CAST)
+           return strip_implicit_coercions(linitial(f->args));
+   }
+   else if (IsA(node, RelabelType))
+   {
+       RelabelType *r = (RelabelType *) node;
+
+       if (r->relabelformat == COERCE_IMPLICIT_CAST)
+           return strip_implicit_coercions((Node *) r->arg);
+   }
+   else if (IsA(node, CoerceToDomain))
+   {
+       CoerceToDomain *c = (CoerceToDomain *) node;
+
+       if (c->coercionformat == COERCE_IMPLICIT_CAST)
+           return strip_implicit_coercions((Node *) c->arg);
+   }
+   return node;
+}
+
 /*
  * set_coercionform_dontcare: set all CoercionForm fields to COERCE_DONTCARE
  *
index d3fec6c444c02ab7c4f8db923937f461c894dbbc..0f452755e5ae51f77144a6d993b92a702ce35c21 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.75 2004/08/29 04:13:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.76 2004/10/22 17:20:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,8 @@ extern bool has_distinct_on_clause(Query *query);
 extern int NumRelids(Node *clause);
 extern void CommuteClause(OpExpr *clause);
 
+extern Node *strip_implicit_coercions(Node *node);
+
 extern void set_coercionform_dontcare(Node *node);
 
 extern Node *eval_const_expressions(Node *node);