Revise parse_coerce() to handle coercion of int and float

constants, not only string constants, at parse time.  Get rid of
parser_typecast2(), which is bogus and redundant...
This commit is contained in:
Tom Lane 1999-08-05 02:33:54 +00:00
parent 5a76a94e41
commit fd19a350ea
6 changed files with 118 additions and 243 deletions

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.21 1999/07/17 20:17:23 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.22 1999/08/05 02:33:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -35,74 +35,101 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
int32 atttypmod) int32 atttypmod)
{ {
Node *result = NULL; Node *result = NULL;
Type targetType;
Oid infunc;
Datum val;
if (targetTypeId == InvalidOid) if (targetTypeId == InvalidOid ||
result = node; targetTypeId == inputTypeId)
else if (inputTypeId != targetTypeId)
{ {
/* no conversion needed */
/* result = node;
* one of the known-good transparent conversions? then drop }
* through... else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
{
/* no work if one of the known-good transparent conversions */
result = node;
}
else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
{
/* Input is a string constant with previously undetermined type.
* Apply the target type's typinput function to it to produce
* a constant of the target type.
*
* NOTE: this case cannot be folded together with the other
* constant-input case, since the typinput function does not
* necessarily behave the same as a type conversion function.
* For example, int4's typinput function will reject "1.2",
* whereas float-to-int type conversion will round to integer.
*/ */
if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId)) Const *con = (Const *) node;
result = node; Type targetType = typeidType(targetTypeId);
char *val;
/* /* We know the source constant is really of type 'text' */
* if not unknown input type, try for explicit conversion using val = textout((text *) con->constvalue);
* functions...
*/
else if (inputTypeId != UNKNOWNOID)
{
/* /* now make a new const node */
* We already know there is a function which will do this, so con = makeNode(Const);
* let's use it con->consttype = targetTypeId;
*/ con->constlen = typeLen(targetType);
FuncCall *n = makeNode(FuncCall); con->constvalue = stringTypeDatum(targetType, val, atttypmod);
con->constisnull = false;
con->constbyval = typeByVal(targetType);
con->constisset = false;
n->funcname = typeidTypeName(targetTypeId); pfree(val);
n->args = lcons(node, NIL);
result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST); result = (Node *) con;
}
else
{
if (nodeTag(node) == T_Const)
{
Const *con = (Const *) node;
val = (Datum) textout((struct varlena *) con->constvalue);
targetType = typeidType(targetTypeId);
infunc = typeInfunc(targetType);
con = makeNode(Const);
con->consttype = targetTypeId;
con->constlen = typeLen(targetType);
/*
* Use "-1" for varchar() type. For char(), we need to pad
* out the type with the proper number of spaces. This
* was a major problem for DEFAULT string constants to
* char() types.
*/
con->constvalue = (Datum) fmgr(infunc,
val,
typeTypElem(targetType),
(targetTypeId != BPCHAROID) ? -1 : atttypmod);
con->constisnull = false;
con->constbyval = typeByVal(targetType);
con->constisset = false;
result = (Node *) con;
}
else
result = node;
}
} }
else else
result = node; {
/*
* Otherwise, find the appropriate type conversion function
* (caller should have determined that there is one), and
* generate an expression tree representing run-time
* application of the conversion function.
*/
FuncCall *n = makeNode(FuncCall);
Type targetType = typeidType(targetTypeId);
n->funcname = typeTypeName(targetType);
n->args = lcons(node, NIL);
result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
/*
* If the input is a constant, apply the type conversion function
* now instead of delaying to runtime. (This could someday be
* done in a downstream constant-expression-simplifier, but we
* can save cycles in the rewriter if we do it here.)
*
* XXX there are cases where we probably shouldn't do this,
* such as coercing text 'now' to datetime? Need a way to
* know whether type conversion function is cacheable...
*/
if (IsA(node, Const))
{
Const *con = (Const *) node;
Oid convertFuncid;
Datum val;
Assert(IsA(result, Expr) &&
((Expr *) result)->opType == FUNC_EXPR);
/* Convert the given constant */
convertFuncid = ((Func *) (((Expr *) result)->oper))->funcid;
val = (Datum) fmgr(convertFuncid, con->constvalue);
/* now make a new const node */
con = makeNode(Const);
con->consttype = targetTypeId;
con->constlen = typeLen(targetType);
con->constvalue = val;
con->constisnull = false;
con->constbyval = typeByVal(targetType);
con->constisset = false;
result = (Node *) con;
}
}
return result; return result;
} }

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.55 1999/07/19 00:26:19 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.56 1999/08/05 02:33:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -631,16 +631,16 @@ exprTypmod(Node *expr)
return -1; return -1;
} }
/*
* Produce an appropriate Const node from a constant value produced
* by the parser and an explicit type name to cast to.
*/
static Node * static Node *
parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
{ {
/* check for passing non-ints */
Const *adt; Const *adt;
Datum lcp; Datum lcp;
Type tp; Type tp;
char type_string[NAMEDATALEN];
int32 len;
char *cp = NULL;
char *const_string = NULL; char *const_string = NULL;
bool string_palloced = false; bool string_palloced = false;
@ -659,45 +659,24 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
break; break;
default: default:
elog(ERROR, elog(ERROR,
"parser_typecast: cannot cast this expression to type '%s'", "parser_typecast: cannot cast this expression to type '%s'",
typename->name); typename->name);
} }
if (typename->arrayBounds != NIL) if (typename->arrayBounds != NIL)
{ {
char type_string[NAMEDATALEN+2];
sprintf(type_string, "_%s", typename->name); sprintf(type_string, "_%s", typename->name);
tp = (Type) typenameType(type_string); tp = (Type) typenameType(type_string);
} }
else else
tp = (Type) typenameType(typename->name); tp = (Type) typenameType(typename->name);
len = typeLen(tp); lcp = stringTypeDatum(tp, const_string, atttypmod);
cp = stringTypeString(tp, const_string, atttypmod);
if (!typeByVal(tp))
lcp = PointerGetDatum(cp);
else
{
switch (len)
{
case 1:
lcp = Int8GetDatum(cp);
break;
case 2:
lcp = Int16GetDatum(cp);
break;
case 4:
lcp = Int32GetDatum(cp);
break;
default:
lcp = PointerGetDatum(cp);
break;
}
}
adt = makeConst(typeTypeId(tp), adt = makeConst(typeTypeId(tp),
len, typeLen(tp),
(Datum) lcp, (Datum) lcp,
false, false,
typeByVal(tp), typeByVal(tp),
@ -709,132 +688,3 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
return (Node *) adt; return (Node *) adt;
} }
/* parser_typecast2()
* Convert (only) constants to specified type.
*/
Node *
parser_typecast2(Node *expr, Oid exprType, Type tp, int32 atttypmod)
{
/* check for passing non-ints */
Const *adt;
Datum lcp;
int32 len = typeLen(tp);
char *cp = NULL;
char *const_string = NULL;
bool string_palloced = false;
Assert(IsA(expr, Const));
switch (exprType)
{
case 0: /* NULL */
break;
case INT4OID: /* int4 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%d",
(int) ((Const *) expr)->constvalue);
break;
case NAMEOID: /* name */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%s",
(char *) ((Const *) expr)->constvalue);
break;
case CHAROID: /* char */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%c",
(char) ((Const *) expr)->constvalue);
break;
case FLOAT4OID: /* float4 */
{
float32 floatVal = DatumGetFloat32(((Const *) expr)->constvalue);
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%f", *floatVal);
break;
}
case FLOAT8OID: /* float8 */
{
float64 floatVal = DatumGetFloat64(((Const *) expr)->constvalue);
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%f", *floatVal);
break;
}
case CASHOID: /* money */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%ld",
(long) ((Const *) expr)->constvalue);
break;
case TEXTOID: /* text */
const_string = DatumGetPointer(((Const *) expr)->constvalue);
const_string = (char *) textout((struct varlena *) const_string);
break;
case UNKNOWNOID: /* unknown */
const_string = DatumGetPointer(((Const *) expr)->constvalue);
const_string = (char *) textout((struct varlena *) const_string);
break;
default:
elog(ERROR, "unknown type %u", exprType);
}
if (!exprType)
{
adt = makeConst(typeTypeId(tp),
(Size) 0,
(Datum) NULL,
true, /* isnull */
false, /* was omitted */
false, /* not a set */
true /* is cast */ );
return (Node *) adt;
}
cp = stringTypeString(tp, const_string, atttypmod);
if (!typeByVal(tp))
lcp = PointerGetDatum(cp);
else
{
switch (len)
{
case 1:
lcp = Int8GetDatum(cp);
break;
case 2:
lcp = Int16GetDatum(cp);
break;
case 4:
lcp = Int32GetDatum(cp);
break;
default:
lcp = PointerGetDatum(cp);
break;
}
}
adt = makeConst(typeTypeId(tp),
(Size) len,
(Datum) lcp,
false,
typeByVal(tp),
false, /* not a set */
true /* is cast */ );
/*
* printf("adt %s : %u %d %d\n",CString(expr),typeTypeId(tp) ,
* len,cp);
*/
if (string_palloced)
pfree(const_string);
return (Node *) adt;
}

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.50 1999/07/17 20:17:24 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.51 1999/08/05 02:33:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1278,21 +1278,8 @@ make_arguments(ParseState *pstate,
i < nargs; i < nargs;
i++, current_fargs = lnext(current_fargs)) i++, current_fargs = lnext(current_fargs))
{ {
/*
* unspecified type for string constant? then use heuristics for
* conversion...
*/
if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)
{
lfirst(current_fargs) = parser_typecast2(lfirst(current_fargs),
input_typeids[i],
typeidType(function_typeids[i]),
-1);
}
/* types don't match? then force coersion using a function call... */ /* types don't match? then force coersion using a function call... */
else if (input_typeids[i] != function_typeids[i]) if (input_typeids[i] != function_typeids[i])
{ {
lfirst(current_fargs) = coerce_type(pstate, lfirst(current_fargs) = coerce_type(pstate,
lfirst(current_fargs), lfirst(current_fargs),

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.24 1999/07/17 20:17:26 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.25 1999/08/05 02:33:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -133,8 +133,8 @@ typeTypeFlag(Type t)
/* Given a type structure and a string, returns the internal form of /* Given a type structure and a string, returns the internal form of
that string */ that string */
char * Datum
stringTypeString(Type tp, char *string, int32 atttypmod) stringTypeDatum(Type tp, char *string, int32 atttypmod)
{ {
Oid op; Oid op;
Oid typelem; Oid typelem;
@ -142,7 +142,7 @@ stringTypeString(Type tp, char *string, int32 atttypmod)
op = ((Form_pg_type) GETSTRUCT(tp))->typinput; op = ((Form_pg_type) GETSTRUCT(tp))->typinput;
typelem = ((Form_pg_type) GETSTRUCT(tp))->typelem; /* XXX - used for typelem = ((Form_pg_type) GETSTRUCT(tp))->typelem; /* XXX - used for
* array_in */ * array_in */
return (char *) fmgr(op, string, typelem, atttypmod); return (Datum) fmgr(op, string, typelem, atttypmod);
} }
/* Given a type id, returns the out-conversion function of the type */ /* Given a type id, returns the out-conversion function of the type */
@ -242,3 +242,14 @@ typeInfunc(Type typ)
return typtup->typinput; return typtup->typinput;
} }
/* Given a type structure, return the out-conversion function of the type */
Oid
typeOutfunc(Type typ)
{
Form_pg_type typtup;
typtup = (Form_pg_type) GETSTRUCT(typ);
return typtup->typoutput;
}

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_expr.h,v 1.14 1999/07/19 00:26:16 tgl Exp $ * $Id: parse_expr.h,v 1.15 1999/08/05 02:33:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -22,6 +22,5 @@
extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence); extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
extern Oid exprType(Node *expr); extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr); extern int32 exprTypmod(Node *expr);
extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int32 attypmod);
#endif /* PARSE_EXPR_H */ #endif /* PARSE_EXPR_H */

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_type.h,v 1.10 1999/05/29 03:17:19 tgl Exp $ * $Id: parse_type.h,v 1.11 1999/08/05 02:33:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -26,11 +26,12 @@ extern int16 typeLen(Type t);
extern bool typeByVal(Type t); extern bool typeByVal(Type t);
extern char *typeTypeName(Type t); extern char *typeTypeName(Type t);
extern char typeTypeFlag(Type t); extern char typeTypeFlag(Type t);
extern char *stringTypeString(Type tp, char *string, int32 atttypmod); extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
extern Oid typeidTypeRelid(Oid type_id); extern Oid typeidTypeRelid(Oid type_id);
extern Oid typeTypeRelid(Type typ); extern Oid typeTypeRelid(Type typ);
extern Oid typeTypElem(Type typ); extern Oid typeTypElem(Type typ);
extern Oid GetArrayElementType(Oid typearray); extern Oid GetArrayElementType(Oid typearray);
extern Oid typeInfunc(Type typ); extern Oid typeInfunc(Type typ);
extern Oid typeOutfunc(Type typ);
#endif /* PARSE_TYPE_H */ #endif /* PARSE_TYPE_H */