mirror of https://github.com/postgres/postgres
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:
parent
5a76a94e41
commit
fd19a350ea
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
Node *result = NULL;
|
||||
Type targetType;
|
||||
Oid infunc;
|
||||
Datum val;
|
||||
|
||||
if (targetTypeId == InvalidOid)
|
||||
result = node;
|
||||
else if (inputTypeId != targetTypeId)
|
||||
if (targetTypeId == InvalidOid ||
|
||||
targetTypeId == inputTypeId)
|
||||
{
|
||||
|
||||
/*
|
||||
* one of the known-good transparent conversions? then drop
|
||||
* through...
|
||||
/* no conversion needed */
|
||||
result = node;
|
||||
}
|
||||
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))
|
||||
result = node;
|
||||
Const *con = (Const *) node;
|
||||
Type targetType = typeidType(targetTypeId);
|
||||
char *val;
|
||||
|
||||
/*
|
||||
* if not unknown input type, try for explicit conversion using
|
||||
* functions...
|
||||
*/
|
||||
else if (inputTypeId != UNKNOWNOID)
|
||||
{
|
||||
/* We know the source constant is really of type 'text' */
|
||||
val = textout((text *) con->constvalue);
|
||||
|
||||
/*
|
||||
* We already know there is a function which will do this, so
|
||||
* let's use it
|
||||
*/
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
/* now make a new const node */
|
||||
con = makeNode(Const);
|
||||
con->consttype = targetTypeId;
|
||||
con->constlen = typeLen(targetType);
|
||||
con->constvalue = stringTypeDatum(targetType, val, atttypmod);
|
||||
con->constisnull = false;
|
||||
con->constbyval = typeByVal(targetType);
|
||||
con->constisset = false;
|
||||
|
||||
n->funcname = typeidTypeName(targetTypeId);
|
||||
n->args = lcons(node, NIL);
|
||||
pfree(val);
|
||||
|
||||
result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
|
||||
}
|
||||
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;
|
||||
}
|
||||
result = (Node *) con;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce an appropriate Const node from a constant value produced
|
||||
* by the parser and an explicit type name to cast to.
|
||||
*/
|
||||
static Node *
|
||||
parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
|
||||
{
|
||||
/* check for passing non-ints */
|
||||
Const *adt;
|
||||
Datum lcp;
|
||||
Type tp;
|
||||
char type_string[NAMEDATALEN];
|
||||
int32 len;
|
||||
char *cp = NULL;
|
||||
char *const_string = NULL;
|
||||
bool string_palloced = false;
|
||||
|
||||
|
@ -659,45 +659,24 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
|
|||
break;
|
||||
default:
|
||||
elog(ERROR,
|
||||
"parser_typecast: cannot cast this expression to type '%s'",
|
||||
"parser_typecast: cannot cast this expression to type '%s'",
|
||||
typename->name);
|
||||
}
|
||||
|
||||
if (typename->arrayBounds != NIL)
|
||||
{
|
||||
char type_string[NAMEDATALEN+2];
|
||||
|
||||
sprintf(type_string, "_%s", typename->name);
|
||||
tp = (Type) typenameType(type_string);
|
||||
}
|
||||
else
|
||||
tp = (Type) typenameType(typename->name);
|
||||
|
||||
len = typeLen(tp);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
lcp = stringTypeDatum(tp, const_string, atttypmod);
|
||||
|
||||
adt = makeConst(typeTypeId(tp),
|
||||
len,
|
||||
typeLen(tp),
|
||||
(Datum) lcp,
|
||||
false,
|
||||
typeByVal(tp),
|
||||
|
@ -709,132 +688,3 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* 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++, 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... */
|
||||
else if (input_typeids[i] != function_typeids[i])
|
||||
if (input_typeids[i] != function_typeids[i])
|
||||
{
|
||||
lfirst(current_fargs) = coerce_type(pstate,
|
||||
lfirst(current_fargs),
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
that string */
|
||||
char *
|
||||
stringTypeString(Type tp, char *string, int32 atttypmod)
|
||||
Datum
|
||||
stringTypeDatum(Type tp, char *string, int32 atttypmod)
|
||||
{
|
||||
Oid op;
|
||||
Oid typelem;
|
||||
|
@ -142,7 +142,7 @@ stringTypeString(Type tp, char *string, int32 atttypmod)
|
|||
op = ((Form_pg_type) GETSTRUCT(tp))->typinput;
|
||||
typelem = ((Form_pg_type) GETSTRUCT(tp))->typelem; /* XXX - used for
|
||||
* 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 */
|
||||
|
@ -242,3 +242,14 @@ typeInfunc(Type typ)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* 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 Oid exprType(Node *expr);
|
||||
extern int32 exprTypmod(Node *expr);
|
||||
extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int32 attypmod);
|
||||
|
||||
#endif /* PARSE_EXPR_H */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* 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 char *typeTypeName(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 typeTypeRelid(Type typ);
|
||||
extern Oid typeTypElem(Type typ);
|
||||
extern Oid GetArrayElementType(Oid typearray);
|
||||
extern Oid typeInfunc(Type typ);
|
||||
extern Oid typeOutfunc(Type typ);
|
||||
|
||||
#endif /* PARSE_TYPE_H */
|
||||
|
|
Loading…
Reference in New Issue