Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9309d5f

Browse files
committed
In ALTER COLUMN TYPE, strip any implicit coercion operations appearing
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.
1 parent 4733dcc commit 9309d5f

File tree

4 files changed

+65
-5
lines changed

4 files changed

+65
-5
lines changed

doc/src/sgml/ref/alter_table.sgml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.73 2004/07/11 23:13:51 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.74 2004/10/22 17:20:04 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -459,6 +459,22 @@ ALTER TABLE table ALTER COLUMN anycol TYPE anytype;
459459
data.
460460
</para>
461461

462+
<para>
463+
The <literal>USING</literal> option of <literal>ALTER TYPE</> can actually
464+
specify any expression involving the old values of the row; that is, it
465+
can refer to other columns as well as the one being converted. This allows
466+
very general conversions to be done with the <literal>ALTER TYPE</>
467+
syntax. Because of this flexibility, the <literal>USING</literal>
468+
expression is not applied to the column's default value (if any); the
469+
result might not be a constant expression as required for a default.
470+
This means that when there is no implicit or assignment cast from old to
471+
new type, <literal>ALTER TYPE</> may fail to convert the default even
472+
though a <literal>USING</literal> clause is supplied. In such cases,
473+
drop the default with <literal>DROP DEFAULT</>, perform the <literal>ALTER
474+
TYPE</>, and then use <literal>SET DEFAULT</> to add a suitable new
475+
default.
476+
</para>
477+
462478
<para>
463479
If a table has any descendant tables, it is not permitted to add,
464480
rename, or change the type of a column in the parent table without doing

src/backend/commands/tablecmds.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.136 2004/10/21 21:33:59 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.137 2004/10/22 17:20:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -4738,13 +4738,20 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
47384738
* changing the column type, because build_column_default itself will
47394739
* try to coerce, and will not issue the error message we want if it
47404740
* fails.)
4741+
*
4742+
* We remove any implicit coercion steps at the top level of the old
4743+
* default expression; this has been agreed to satisfy the principle
4744+
* of least surprise. (The conversion to the new column type should
4745+
* act like it started from what the user sees as the stored expression,
4746+
* and the implicit coercions aren't going to be shown.)
47414747
*/
47424748
if (attTup->atthasdef)
47434749
{
47444750
defaultexpr = build_column_default(rel, attnum);
47454751
Assert(defaultexpr);
4752+
defaultexpr = strip_implicit_coercions(defaultexpr);
47464753
defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
4747-
defaultexpr, exprType(defaultexpr),
4754+
defaultexpr, exprType(defaultexpr),
47484755
targettype, typename->typmod,
47494756
COERCION_ASSIGNMENT,
47504757
COERCE_IMPLICIT_CAST);

src/backend/optimizer/util/clauses.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.182 2004/10/07 18:38:49 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.183 2004/10/22 17:20:05 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -1021,6 +1021,41 @@ CommuteClause(OpExpr *clause)
10211021
lsecond(clause->args) = temp;
10221022
}
10231023

1024+
/*
1025+
* strip_implicit_coercions: remove implicit coercions at top level of tree
1026+
*
1027+
* Note: there isn't any useful thing we can do with a RowExpr here, so
1028+
* just return it unchanged, even if it's marked as an implicit coercion.
1029+
*/
1030+
Node *
1031+
strip_implicit_coercions(Node *node)
1032+
{
1033+
if (node == NULL)
1034+
return NULL;
1035+
if (IsA(node, FuncExpr))
1036+
{
1037+
FuncExpr *f = (FuncExpr *) node;
1038+
1039+
if (f->funcformat == COERCE_IMPLICIT_CAST)
1040+
return strip_implicit_coercions(linitial(f->args));
1041+
}
1042+
else if (IsA(node, RelabelType))
1043+
{
1044+
RelabelType *r = (RelabelType *) node;
1045+
1046+
if (r->relabelformat == COERCE_IMPLICIT_CAST)
1047+
return strip_implicit_coercions((Node *) r->arg);
1048+
}
1049+
else if (IsA(node, CoerceToDomain))
1050+
{
1051+
CoerceToDomain *c = (CoerceToDomain *) node;
1052+
1053+
if (c->coercionformat == COERCE_IMPLICIT_CAST)
1054+
return strip_implicit_coercions((Node *) c->arg);
1055+
}
1056+
return node;
1057+
}
1058+
10241059
/*
10251060
* set_coercionform_dontcare: set all CoercionForm fields to COERCE_DONTCARE
10261061
*

src/include/optimizer/clauses.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.75 2004/08/29 04:13:07 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.76 2004/10/22 17:20:05 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -63,6 +63,8 @@ extern bool has_distinct_on_clause(Query *query);
6363
extern int NumRelids(Node *clause);
6464
extern void CommuteClause(OpExpr *clause);
6565

66+
extern Node *strip_implicit_coercions(Node *node);
67+
6668
extern void set_coercionform_dontcare(Node *node);
6769

6870
extern Node *eval_const_expressions(Node *node);

0 commit comments

Comments
 (0)