mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Downgrade implicit casts to text to be assignment-only, except for the ones
from the other string-category types; this eliminates a lot of surprising interpretations that the parser could formerly make when there was no directly applicable operator. Create a general mechanism that supports casts to and from the standard string types (text,varchar,bpchar) for *every* datatype, by invoking the datatype's I/O functions. These new casts are assignment-only in the to-string direction, explicit-only in the other, and therefore should create no surprising behavior. Remove a bunch of thereby-obsoleted datatype-specific casting functions. The "general mechanism" is a new expression node type CoerceViaIO that can actually convert between *any* two datatypes if their external text representations are compatible. This is more general than needed for the immediate feature, but might be useful in plpgsql or other places in future. This commit does nothing about the issue that applying the concatenation operator || to non-text types will now fail, often with strange error messages due to misinterpreting the operator as array concatenation. Since it often (not always) worked before, we should either make it succeed or at least give a more user-friendly error; but details are still under debate. Peter Eisentraut and Tom Lane
This commit is contained in:
@ -54,7 +54,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.183 2007/05/21 17:57:33 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.184 2007/06/05 21:31:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -70,6 +70,7 @@
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/selfuncs.h"
|
||||
#include "utils/tuplesort.h"
|
||||
@ -1951,6 +1952,22 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
context->total.per_tuple += get_func_cost(saop->opfuncid) *
|
||||
cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
|
||||
}
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
|
||||
Oid iofunc;
|
||||
Oid typioparam;
|
||||
bool typisvarlena;
|
||||
|
||||
/* check the result type's input function */
|
||||
getTypeInputInfo(iocoerce->resulttype,
|
||||
&iofunc, &typioparam);
|
||||
context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost;
|
||||
/* check the input type's output function */
|
||||
getTypeOutputInfo(exprType((Node *) iocoerce->arg),
|
||||
&iofunc, &typisvarlena);
|
||||
context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost;
|
||||
}
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
{
|
||||
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.244 2007/05/01 18:53:51 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.245 2007/06/05 21:31:05 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -734,6 +734,25 @@ contain_mutable_functions_walker(Node *node, void *context)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
CoerceViaIO *expr = (CoerceViaIO *) node;
|
||||
Oid iofunc;
|
||||
Oid typioparam;
|
||||
bool typisvarlena;
|
||||
|
||||
/* check the result type's input function */
|
||||
getTypeInputInfo(expr->resulttype,
|
||||
&iofunc, &typioparam);
|
||||
if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE)
|
||||
return true;
|
||||
/* check the input type's output function */
|
||||
getTypeOutputInfo(exprType((Node *) expr->arg),
|
||||
&iofunc, &typisvarlena);
|
||||
if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
{
|
||||
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
|
||||
@ -826,6 +845,25 @@ contain_volatile_functions_walker(Node *node, void *context)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
CoerceViaIO *expr = (CoerceViaIO *) node;
|
||||
Oid iofunc;
|
||||
Oid typioparam;
|
||||
bool typisvarlena;
|
||||
|
||||
/* check the result type's input function */
|
||||
getTypeInputInfo(expr->resulttype,
|
||||
&iofunc, &typioparam);
|
||||
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* check the input type's output function */
|
||||
getTypeOutputInfo(exprType((Node *) expr->arg),
|
||||
&iofunc, &typisvarlena);
|
||||
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
{
|
||||
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
|
||||
@ -1124,6 +1162,13 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
|
||||
|
||||
result = find_nonnullable_rels_walker((Node *) expr->arg, top_level);
|
||||
}
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
/* not clear this is useful, but it can't hurt */
|
||||
CoerceViaIO *expr = (CoerceViaIO *) node;
|
||||
|
||||
result = find_nonnullable_rels_walker((Node *) expr->arg, top_level);
|
||||
}
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
{
|
||||
/* ArrayCoerceExpr is strict at the array level */
|
||||
@ -1486,6 +1531,13 @@ strip_implicit_coercions(Node *node)
|
||||
if (r->relabelformat == COERCE_IMPLICIT_CAST)
|
||||
return strip_implicit_coercions((Node *) r->arg);
|
||||
}
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
CoerceViaIO *c = (CoerceViaIO *) node;
|
||||
|
||||
if (c->coerceformat == COERCE_IMPLICIT_CAST)
|
||||
return strip_implicit_coercions((Node *) c->arg);
|
||||
}
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
{
|
||||
ArrayCoerceExpr *c = (ArrayCoerceExpr *) node;
|
||||
@ -1537,6 +1589,8 @@ set_coercionform_dontcare_walker(Node *node, void *context)
|
||||
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
|
||||
else if (IsA(node, RelabelType))
|
||||
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
((CoerceViaIO *) node)->coerceformat = COERCE_DONTCARE;
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE;
|
||||
else if (IsA(node, ConvertRowtypeExpr))
|
||||
@ -3471,6 +3525,8 @@ expression_tree_walker(Node *node,
|
||||
break;
|
||||
case T_RelabelType:
|
||||
return walker(((RelabelType *) node)->arg, context);
|
||||
case T_CoerceViaIO:
|
||||
return walker(((CoerceViaIO *) node)->arg, context);
|
||||
case T_ArrayCoerceExpr:
|
||||
return walker(((ArrayCoerceExpr *) node)->arg, context);
|
||||
case T_ConvertRowtypeExpr:
|
||||
@ -3959,6 +4015,16 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_CoerceViaIO:
|
||||
{
|
||||
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
|
||||
CoerceViaIO *newnode;
|
||||
|
||||
FLATCOPY(newnode, iocoerce, CoerceViaIO);
|
||||
MUTATE(newnode->arg, iocoerce->arg, Expr *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_ArrayCoerceExpr:
|
||||
{
|
||||
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
|
||||
|
Reference in New Issue
Block a user