Commit 3ace5fd0 authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

Add capabilities for automatic type conversion.

parent 54b5577c
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.74 1998/03/31 23:31:10 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.75 1998/05/09 23:29:52 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include "parser/parse_target.h" #include "parser/parse_target.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/mcxt.h" #include "utils/mcxt.h"
#ifdef PARSEDEBUG
#include "nodes/print.h"
#endif
static Query *transformStmt(ParseState *pstate, Node *stmt); static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt); static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
...@@ -65,6 +68,10 @@ parse_analyze(List *pl, ParseState *parentParseState) ...@@ -65,6 +68,10 @@ parse_analyze(List *pl, ParseState *parentParseState)
while (pl != NIL) while (pl != NIL)
{ {
#ifdef PARSEDEBUG
elog(DEBUG,"parse tree from yacc:\n---\n%s\n---\n", nodeToString(lfirst(pl)));
#endif
pstate = make_parsestate(parentParseState); pstate = make_parsestate(parentParseState);
result->qtrees[i++] = transformStmt(pstate, lfirst(pl)); result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
if (pstate->p_target_relation != NULL) if (pstate->p_target_relation != NULL)
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.27 1998/04/26 04:06:45 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.28 1998/05/09 23:29:53 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -301,12 +301,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -301,12 +301,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
result = (Node *) expr; result = (Node *) expr;
break; break;
} }
/* These nodes do _not_ come from the original parse tree.
* They result from parser transformation in this phase. /* These nodes do _not_ come from the original parse tree,
* but result from parser transformation in this phase.
* At least one construct (BETWEEN/AND) puts the same nodes * At least one construct (BETWEEN/AND) puts the same nodes
* into two branches of the parse tree. Hence, some nodes * into two branches of the parse tree; hence, some nodes
* are transformed twice. These nodes come from transforming * are transformed twice.
* a function call. Let's try just passing them through... * These cases below come from transforming function calls.
* Let's try just passing them through...
* - thomas 1998-03-14 * - thomas 1998-03-14
*/ */
case T_Expr: case T_Expr:
...@@ -506,6 +508,10 @@ parser_typecast(Value *expr, TypeName *typename, int16 atttypmod) ...@@ -506,6 +508,10 @@ parser_typecast(Value *expr, TypeName *typename, int16 atttypmod)
return (Node *) adt; return (Node *) adt;
} }
/* parser_typecast2()
* Convert (only) constants to specified type.
*/
Node * Node *
parser_typecast2(Node *expr, Oid exprType, Type tp, int16 atttypmod) parser_typecast2(Node *expr, Oid exprType, Type tp, int16 atttypmod)
{ {
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.14 1998/02/26 04:33:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.15 1998/05/09 23:29:53 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,7 +39,7 @@ make_operand(char *opname, ...@@ -39,7 +39,7 @@ make_operand(char *opname,
/* /*
* make_parsestate() -- * make_parsestate() --
* allocate and initialize a new ParseState. * allocate and initialize a new ParseState.
* the CALLERS is responsible for freeing the ParseState* returned * the CALLER is responsible for freeing the ParseState* returned
* *
*/ */
...@@ -57,6 +57,15 @@ make_parsestate(ParseState *parentParseState) ...@@ -57,6 +57,15 @@ make_parsestate(ParseState *parentParseState)
return (pstate); return (pstate);
} }
extern
Node *
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId);
/* make_operand()
* Ensure argument type match by forcing conversion of constants.
*/
static Node * static Node *
make_operand(char *opname, make_operand(char *opname,
Node *tree, Node *tree,
...@@ -65,35 +74,33 @@ make_operand(char *opname, ...@@ -65,35 +74,33 @@ make_operand(char *opname,
{ {
Node *result; Node *result;
Type true_type; Type true_type;
#if FALSE
Datum val; Datum val;
Oid infunc; Oid infunc;
#endif
#ifdef PARSEDEBUG
printf("make_operand: constructing operand for '%s' %s->%s\n",
opname, typeidTypeName(orig_typeId), typeidTypeName(true_typeId));
#endif
if (tree != NULL) if (tree != NULL)
{ {
result = tree; result = tree;
true_type = typeidType(true_typeId); true_type = typeidType(true_typeId);
disallow_setop(opname, true_type, result); disallow_setop(opname, true_type, result);
/* must coerce? */
if (true_typeId != orig_typeId) if (true_typeId != orig_typeId)
{ /* must coerce */ {
Const *con = (Const *) result; #ifdef PARSEDEBUG
printf("make_operand: try to convert node from %s to %s\n",
Assert(nodeTag(result) == T_Const); typeidTypeName(orig_typeId), typeidTypeName(true_typeId));
val = (Datum) textout((struct varlena *) #endif
con->constvalue); result = coerce_type(NULL, tree, orig_typeId, true_typeId);
infunc = typeidInfunc(true_typeId);
con = makeNode(Const);
con->consttype = true_typeId;
con->constlen = typeLen(true_type);
con->constvalue = (Datum) fmgr(infunc,
val,
typeidTypElem(true_typeId),
-1 /* for varchar() type */ );
con->constisnull = false;
con->constbyval = true;
con->constisset = false;
result = (Node *) con;
} }
} }
/* otherwise, this is a NULL value */
else else
{ {
Const *con = makeNode(Const); Const *con = makeNode(Const);
...@@ -108,7 +115,7 @@ make_operand(char *opname, ...@@ -108,7 +115,7 @@ make_operand(char *opname,
} }
return result; return result;
} } /* make_operand() */
static void static void
...@@ -119,13 +126,49 @@ disallow_setop(char *op, Type optype, Node *operand) ...@@ -119,13 +126,49 @@ disallow_setop(char *op, Type optype, Node *operand)
if (nodeTag(operand) == T_Iter) if (nodeTag(operand) == T_Iter)
{ {
elog(NOTICE, "An operand to the '%s' operator returns a set of %s,", elog(ERROR, "An operand to the '%s' operator returns a set of %s,"
op, typeTypeName(optype)); "\n\tbut '%s' takes single values, not sets.",
elog(ERROR, "but '%s' takes single values, not sets.", op, typeTypeName(optype), op);
op);
} }
} }
/* CoerceType()
* Try to force type of node.
*/
Oid CoerceType(Oid typeId, Node *node);
Oid
CoerceType(Oid typeId, Node *node)
{
switch (nodeTag(node))
{
case T_Const:
{
Const *con = (Const *) node;
#ifdef PARSEDEBUG
printf( "Convert node %d to text\n", nodeTag(node));
#endif
typeId = TEXTOID;
con->consttype = typeId;
}
break;
default:
break;
}
return typeId;
} /* CoerceType() */
/* make_op()
* Operator construction.
*
* Transform operator expression ensuring type compatibility.
* This is where some type conversion happens.
*/
Expr * Expr *
make_op(char *opname, Node *ltree, Node *rtree) make_op(char *opname, Node *ltree, Node *rtree)
{ {
...@@ -138,10 +181,9 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -138,10 +181,9 @@ make_op(char *opname, Node *ltree, Node *rtree)
*right; *right;
Expr *result; Expr *result;
/* right operator? */
if (rtree == NULL) if (rtree == NULL)
{ {
/* right operator */
ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree); ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
temp = right_oper(opname, ltypeId); temp = right_oper(opname, ltypeId);
opform = (OperatorTupleForm) GETSTRUCT(temp); opform = (OperatorTupleForm) GETSTRUCT(temp);
...@@ -149,25 +191,29 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -149,25 +191,29 @@ make_op(char *opname, Node *ltree, Node *rtree)
right = NULL; right = NULL;
} }
/* left operator? */
else if (ltree == NULL) else if (ltree == NULL)
{ {
/* left operator */
rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree); rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
temp = left_oper(opname, rtypeId); temp = left_oper(opname, rtypeId);
#ifdef PARSEDEBUG
printf("make_op: returned from left_oper() with structure at %p\n", (void *)temp);
#endif
opform = (OperatorTupleForm) GETSTRUCT(temp); opform = (OperatorTupleForm) GETSTRUCT(temp);
#ifdef PARSEDEBUG
printf("make_op: calling make_operand()\n");
#endif
right = make_operand(opname, rtree, rtypeId, opform->oprright); right = make_operand(opname, rtree, rtypeId, opform->oprright);
left = NULL; left = NULL;
} }
/* otherwise, binary operator */
else else
{ {
char *outstr;
Oid infunc,
outfunc;
Type newtype;
#define CONVERTABLE_TYPE(t) ( (t) == INT2OID || \ #define CONVERTIBLE_TYPE(t) ( (t) == INT2OID || \
(t) == INT4OID || \ (t) == INT4OID || \
(t) == OIDOID || \ (t) == OIDOID || \
(t) == FLOAT4OID || \ (t) == FLOAT4OID || \
...@@ -178,12 +224,32 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -178,12 +224,32 @@ make_op(char *opname, Node *ltree, Node *rtree)
ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree); ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree); rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
#if FALSE
/* Both operands of unknown type?
* Then they are strings and we should force at least one to text
* - thomas 1998-03-16
*/
ltypeId = exprType(ltree);
rtypeId = exprType(rtree);
if ((ltypeId == UNKNOWNOID)
&& (rtypeId == UNKNOWNOID))
{
#ifdef PARSEDEBUG
printf( "Convert left-hand constant to text for node %d\n", nodeTag(ltree));
#endif
ltypeId = CoerceType(TEXTOID, ltree);
}
#endif
#if FALSE
/* /*
* convert constant when using a const of a numeric type and a * convert constant when using a const of a numeric type and a
* non-const of another numeric type * non-const of another numeric type
*/ */
if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const && if (CONVERTIBLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const && CONVERTIBLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
!((Const *) rtree)->constiscast) !((Const *) rtree)->constiscast)
{ {
outfunc = typeidOutfunc(rtypeId); outfunc = typeidOutfunc(rtypeId);
...@@ -197,8 +263,8 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -197,8 +263,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
((Const *) rtree)->constbyval = typeByVal(newtype); ((Const *) rtree)->constbyval = typeByVal(newtype);
} }
if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const && if (CONVERTIBLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const && CONVERTIBLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
!((Const *) ltree)->constiscast) !((Const *) ltree)->constiscast)
{ {
outfunc = typeidOutfunc(ltypeId); outfunc = typeidOutfunc(ltypeId);
...@@ -211,6 +277,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -211,6 +277,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
((Const *) ltree)->constlen = typeLen(newtype); ((Const *) ltree)->constlen = typeLen(newtype);
((Const *) ltree)->constbyval = typeByVal(newtype); ((Const *) ltree)->constbyval = typeByVal(newtype);
} }
#endif
temp = oper(opname, ltypeId, rtypeId, false); temp = oper(opname, ltypeId, rtypeId, false);
opform = (OperatorTupleForm) GETSTRUCT(temp); opform = (OperatorTupleForm) GETSTRUCT(temp);
...@@ -219,7 +286,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -219,7 +286,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
} }
newop = makeOper(oprid(temp), /* opno */ newop = makeOper(oprid(temp), /* opno */
InvalidOid,/* opid */ InvalidOid, /* opid */
opform->oprresult, /* operator result type */ opform->oprresult, /* operator result type */
0, 0,
NULL); NULL);
...@@ -239,6 +306,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -239,6 +306,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
return result; return result;
} }
Var * Var *
make_var(ParseState *pstate, Oid relid, char *refname, make_var(ParseState *pstate, Oid relid, char *refname,
char *attrname) char *attrname)
...@@ -356,6 +424,9 @@ make_array_ref(Node *expr, ...@@ -356,6 +424,9 @@ make_array_ref(Node *expr,
return aref; return aref;
} }
/* make_array_set()
*/
ArrayRef * ArrayRef *
make_array_set(Expr *target_expr, make_array_set(Expr *target_expr,
List *upperIndexpr, List *upperIndexpr,
...@@ -406,10 +477,12 @@ make_array_set(Expr *target_expr, ...@@ -406,10 +477,12 @@ make_array_set(Expr *target_expr,
aref->refexpr = (Node *) target_expr; aref->refexpr = (Node *) target_expr;
aref->refassgnexpr = (Node *) expr; aref->refassgnexpr = (Node *) expr;
if (lowerIndexpr == NIL) /* accessing a single array element */ /* accessing a single array element? */
if (lowerIndexpr == NIL)
reftype = aref->refelemtype; reftype = aref->refelemtype;
/* otherwise, request to set a part of the array, by another array */
else else
/* request to set a part of the array, by another array */
reftype = typearray; reftype = typearray;
aref->refelemtype = reftype; aref->refelemtype = reftype;
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.11 1998/02/26 04:33:35 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.12 1998/05/09 23:29:54 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,13 @@ ...@@ -26,6 +26,13 @@
#include "parser/parse_target.h" #include "parser/parse_target.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h"
extern
bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids);
extern
Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId);
static List *expandAllTables(ParseState *pstate); static List *expandAllTables(ParseState *pstate);
static char *figureColname(Node *expr, Node *resval); static char *figureColname(Node *expr, Node *resval);
...@@ -34,6 +41,16 @@ make_targetlist_expr(ParseState *pstate, ...@@ -34,6 +41,16 @@ make_targetlist_expr(ParseState *pstate,
char *colname, char *colname,
Node *expr, Node *expr,
List *arrayRef); List *arrayRef);
Node *
size_target_expr(ParseState *pstate,
Node *expr,
Oid attrtype,
int16 attrtypmod);
Node *
coerce_target_expr(ParseState *pstate,
Node *expr,
Oid type_id,
Oid attrtype);
/* /*
* transformTargetList - * transformTargetList -
...@@ -110,8 +127,7 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -110,8 +127,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
Relation rd; Relation rd;
Value *constval; Value *constval;
if (exprType(expr) != UNKNOWNOID || if (exprType(expr) != UNKNOWNOID || !IsA(expr, Const))
!IsA(expr, Const))
elog(ERROR, "yyparse: string constant expected"); elog(ERROR, "yyparse: string constant expected");
val = (char *) textout((struct varlena *) val = (char *) textout((struct varlena *)
...@@ -123,15 +139,15 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -123,15 +139,15 @@ transformTargetList(ParseState *pstate, List *targetlist)
aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST); aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
if (!IsA(aind->uidx, Const)) if (!IsA(aind->uidx, Const))
elog(ERROR, elog(ERROR, "Array Index for Append should be a constant");
"Array Index for Append should be a constant");
uindx[i] = ((Const *) aind->uidx)->constvalue; uindx[i] = ((Const *) aind->uidx)->constvalue;
if (aind->lidx != NULL) if (aind->lidx != NULL)
{ {
aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST); aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
if (!IsA(aind->lidx, Const)) if (!IsA(aind->lidx, Const))
elog(ERROR, elog(ERROR, "Array Index for Append should be a constant");
"Array Index for Append should be a constant");
lindx[i] = ((Const *) aind->lidx)->constvalue; lindx[i] = ((Const *) aind->lidx)->constvalue;
} }
else else
...@@ -140,6 +156,7 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -140,6 +156,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
} }
if (lindx[i] > uindx[i]) if (lindx[i] > uindx[i])
elog(ERROR, "yyparse: lower index cannot be greater than upper index"); elog(ERROR, "yyparse: lower index cannot be greater than upper index");
sprintf(str, "[%d:%d]", lindx[i], uindx[i]); sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
str += strlen(str); str += strlen(str);
i++; i++;
...@@ -151,6 +168,7 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -151,6 +168,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
ndims = attnumAttNelems(rd, resdomno); ndims = attnumAttNelems(rd, resdomno);
if (i != ndims) if (i != ndims)
elog(ERROR, "yyparse: array dimensions do not match"); elog(ERROR, "yyparse: array dimensions do not match");
constval = makeNode(Value); constval = makeNode(Value);
constval->type = T_String; constval->type = T_String;
constval->val.str = save_str; constval->val.str = save_str;
...@@ -300,8 +318,7 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -300,8 +318,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
} }
default: default:
/* internal error */ /* internal error */
elog(ERROR, elog(ERROR, "internal error: do not know how to transform targetlist");
"internal error: do not know how to transform targetlist");
break; break;
} }
...@@ -321,11 +338,125 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -321,11 +338,125 @@ transformTargetList(ParseState *pstate, List *targetlist)
} }
/* Node *
* make_targetlist_expr - coerce_target_expr(ParseState *pstate,
* make a TargetEntry from an expression Node *expr,
Oid type_id,
Oid attrtype)
{
if (can_coerce_type(1, &type_id, &attrtype))
{
#ifdef PARSEDEBUG
printf("parse_target: coerce type from %s to %s\n",
typeidTypeName(type_id), typeidTypeName(attrtype));
#endif
expr = coerce_type(pstate, expr, type_id, attrtype);
}
#ifndef DISABLE_STRING_HACKS
/* string hacks to get transparent conversions w/o explicit conversions */
else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
{
Oid text_id = TEXTOID;
#ifdef PARSEDEBUG
printf("parse_target: try coercing from %s to %s via text\n",
typeidTypeName(type_id), typeidTypeName(attrtype));
#endif
if (type_id == TEXTOID)
{
}
else if (can_coerce_type(1, &type_id, &text_id))
{
expr = coerce_type(pstate, expr, type_id, text_id);
}
else
{
expr = NULL;
}
}
#endif
else
{
expr = NULL;
}
return expr;
} /* coerce_target_expr() */
/* size_target_expr()
* Apparently going to a fixed-length string?
* Then explicitly size for storage...
*/
Node *
size_target_expr(ParseState *pstate,
Node *expr,
Oid attrtype,
int16 attrtypmod)
{
int i;
HeapTuple ftup;
char *funcname;
Oid oid_array[8];
FuncCall *func;
A_Const *cons;
#ifdef PARSEDEBUG
printf("parse_target: ensure target fits storage\n");
#endif
funcname = typeidTypeName(attrtype);
oid_array[0] = attrtype;
oid_array[1] = INT4OID;
for (i = 2; i < 8; i++) oid_array[i] = InvalidOid;
#ifdef PARSEDEBUG
printf("parse_target: look for conversion function %s(%s,%s)\n",
funcname, typeidTypeName(attrtype), typeidTypeName(INT4OID));
#endif
/* attempt to find with arguments exactly as specified... */
ftup = SearchSysCacheTuple(PRONAME,
PointerGetDatum(funcname),
Int32GetDatum(2),
PointerGetDatum(oid_array),
0);
if (HeapTupleIsValid(ftup))
{
#ifdef PARSEDEBUG
printf("parse_target: found conversion function for sizing\n");
#endif
func = makeNode(FuncCall);
func->funcname = funcname;
cons = makeNode(A_Const);
cons->val.type = T_Integer;
cons->val.val.ival = attrtypmod;
func->args = lappend( lcons(expr,NIL), cons);
expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
}
#ifdef PARSEDEBUG
else
{
printf("parse_target: no conversion function for sizing\n");
}
#endif
return expr;
} /* size_target_expr() */
/* make_targetlist_expr()
* Make a TargetEntry from an expression
* *
* arrayRef is a list of transformed A_Indices * arrayRef is a list of transformed A_Indices
*
* For type mismatches between expressions and targets, use the same
* techniques as for function and operator type coersion.
* - thomas 1998-05-08
*/ */
static TargetEntry * static TargetEntry *
make_targetlist_expr(ParseState *pstate, make_targetlist_expr(ParseState *pstate,
...@@ -355,7 +486,6 @@ make_targetlist_expr(ParseState *pstate, ...@@ -355,7 +486,6 @@ make_targetlist_expr(ParseState *pstate,
/* Processes target columns that will be receiving results */ /* Processes target columns that will be receiving results */
if (pstate->p_is_insert || pstate->p_is_update) if (pstate->p_is_insert || pstate->p_is_update)
{ {
/* /*
* insert or update query -- insert, update work only on one * insert or update query -- insert, update work only on one
* relation, so multiple occurence of same resdomno is bogus * relation, so multiple occurence of same resdomno is bogus
...@@ -368,91 +498,47 @@ make_targetlist_expr(ParseState *pstate, ...@@ -368,91 +498,47 @@ make_targetlist_expr(ParseState *pstate,
if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL)) if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
attrtype = GetArrayElementType(attrtype); attrtype = GetArrayElementType(attrtype);
attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod; attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;
#if 0
if (Input_is_string && Typecast_ok)
{
Datum val;
if (type_id == typeTypeId(type("unknown"))) /* Check for InvalidOid since that seems to indicate a NULL constant... */
if (type_id != InvalidOid)
{ {
val = (Datum) textout((struct varlena *) /* Mismatch on types? then try to coerce to target... */
((Const) lnext(expr))->constvalue); if (attrtype != type_id)
}
else
{ {
val = ((Const) lnext(expr))->constvalue; Oid typelem;
}
if (attrisset) if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
{ {
lnext(expr) = makeConst(attrtype, typelem = typeidTypElem(attrtype);
attrlen,
val,
false,
true,
true, /* is set */
false);
} }
else else
{ {
lnext(expr) = typelem = attrtype;
makeConst(attrtype,
attrlen,
(Datum) fmgr(typeidInfunc(attrtype),
val, typeidTypElem(attrtype), -1),
false,
true /* Maybe correct-- 80% chance */ ,
false, /* is not a set */
false);
} }
}
else if ((Typecast_ok) && (attrtype != type_id)) expr = coerce_target_expr(pstate, expr, type_id, typelem);
if (!HeapTupleIsValid(expr))
{ {
lnext(expr) = elog(ERROR, "parser: attribute '%s' is of type '%s'"
parser_typecast2(expr, typeidType(attrtype)); " but expression is of type '%s'"
"\n\tYou will need to rewrite or cast the expression",
colname,
typeidTypeName(attrtype),
typeidTypeName(type_id));
} }
else if (attrtype != type_id)
{
if ((attrtype == INT2OID) && (type_id == INT4OID))
lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
lfirst(expr) = lispInteger(FLOAT4OID);
else
elog(ERROR, "unequal type in tlist : %s \n", colname);
} }
Input_is_string = false; #ifdef PARSEDEBUG
Input_is_integer = false; printf("parse_target: attrtypmod is %d\n", (int4) attrtypmod);
Typecast_ok = true;
#endif #endif
if (attrtype != type_id) /* Apparently going to a fixed-length string?
{ * Then explicitly size for storage...
if (IsA(expr, Const)) */
{ if (attrtypmod > 0)
/* try to cast the constant */
if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
{
/* updating a single item */
Oid typelem = typeidTypElem(attrtype);
expr = (Node *) parser_typecast2(expr,
type_id,
typeidType(typelem),
attrtypmod);
}
else
expr = (Node *) parser_typecast2(expr,
type_id,
typeidType(attrtype),
attrtypmod);
}
else
{ {
/* currently, we can't handle casting of expressions */ expr = size_target_expr(pstate, expr, attrtype, attrtypmod);
elog(ERROR, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
colname,
typeidTypeName(attrtype),
typeidTypeName(type_id));
} }
} }
...@@ -514,7 +600,8 @@ make_targetlist_expr(ParseState *pstate, ...@@ -514,7 +600,8 @@ make_targetlist_expr(ParseState *pstate,
tent->expr = expr; tent->expr = expr;
return tent; return tent;
} } /* make_targetlist_expr() */
/* /*
* makeTargetNames - * makeTargetNames -
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* parse_type.h * parse_type.c
* handle type operations for parser * handle type operations for parser
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.8 1998/02/27 19:44:51 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.9 1998/05/09 23:29:54 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,11 +15,17 @@ ...@@ -15,11 +15,17 @@
#include "postgres.h" #include "postgres.h"
#include "fmgr.h" #include "fmgr.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "nodes/primnodes.h"
#include "parser/parse_node.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "parser/parse_target.h" #include "parser/parse_target.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/syscache.h" #include "utils/syscache.h"
/* check to see if a type id is valid, /* check to see if a type id is valid,
* returns true if it is. By using this call before calling * returns true if it is. By using this call before calling
* typeidType or typeidTypeName, more meaningful error messages * typeidType or typeidTypeName, more meaningful error messages
......
/*-------------------------------------------------------------------------
*
* parse_coerce.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_coerce.h,v 1.1 1998/05/09 23:31:34 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_COERCE_H
#define PARSE_COERCE_H
typedef enum CATEGORY {
INVALID_TYPE,
UNKNOWN_TYPE,
BOOLEAN_TYPE,
STRING_TYPE,
NUMERIC_TYPE,
DATETIME_TYPE,
TIMESPAN_TYPE,
GEOMETRIC_TYPE,
USER_TYPE,
MIXED_TYPE
} CATEGORY;
#define IS_BUILTIN_TYPE(t) \
(((t) == BOOLOID) \
|| ((t) == BPCHAROID) \
|| ((t) == VARCHAROID) \
|| ((t) == TEXTOID) \
|| ((t) == CASHOID) \
|| ((t) == INT4OID) \
|| ((t) == DATETIMEOID) \
|| ((t) == FLOAT8OID) \
|| ((t) == ABSTIMEOID) \
|| ((t) == TIMESTAMPOID) \
|| ((t) == RELTIMEOID))
/* IS_BINARY_COMPATIBLE()
* Check for types with the same underlying binary representation.
* This allows us to cheat and directly exchange values without
* going through the trouble of calling a conversion function.
*/
#define IS_BINARY_COMPATIBLE(a,b) \
(((a) == BPCHAROID && (b) == TEXTOID) \
|| ((a) == BPCHAROID && (b) == VARCHAROID) \
|| ((a) == VARCHAROID && (b) == TEXTOID) \
|| ((a) == VARCHAROID && (b) == BPCHAROID) \
|| ((a) == TEXTOID && (b) == BPCHAROID) \
|| ((a) == TEXTOID && (b) == VARCHAROID) \
|| ((a) == CASHOID && (b) == INT4OID) \
|| ((a) == INT4OID && (b) == CASHOID) \
|| ((a) == DATETIMEOID && (b) == FLOAT8OID) \
|| ((a) == FLOAT8OID && (b) == DATETIMEOID) \
|| ((a) == ABSTIMEOID && (b) == TIMESTAMPOID) \
|| ((a) == TIMESTAMPOID && (b) == ABSTIMEOID) \
|| ((a) == ABSTIMEOID && (b) == INT4OID) \
|| ((a) == INT4OID && (b) == ABSTIMEOID) \
|| ((a) == RELTIMEOID && (b) == INT4OID) \
|| ((a) == INT4OID && (b) == RELTIMEOID))
/* IS_HIGHER_TYPE()
* These types are the most general in each of the type categories.
*/
#define IS_HIGHER_TYPE(t) \
(((t) == TEXTOID) \
|| ((t) == FLOAT8OID) \
|| ((t) == TIMESPANOID) \
|| ((t) == DATETIMEOID) \
|| ((t) == POLYGONOID))
/* IS_HIGHEST_TYPE()
* These types are the most general in each of the type categories.
* Since timespan and datetime overload so many functions, let's
* give datetime the preference.
* Since text is a generic string type let's leave it out too.
*/
#define IS_HIGHEST_TYPE(t) \
(((t) == FLOAT8OID) \
|| ((t) == DATETIMEOID) \
|| ((t) == TIMESPANOID))
extern bool IsPreferredType(CATEGORY category, Oid type);
extern Oid PreferredType(CATEGORY category, Oid type);
extern CATEGORY TypeCategory(Oid type);
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids);
extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId);
#endif /* PARSE_COERCE_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_func.h,v 1.8 1998/02/26 04:42:45 momjian Exp $ * $Id: parse_func.h,v 1.9 1998/05/09 23:31:34 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -49,6 +49,6 @@ extern Node * ...@@ -49,6 +49,6 @@ extern Node *
ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
int *curr_resno, int precedence); int *curr_resno, int precedence);
extern void func_error(char *caller, char *funcname, int nargs, Oid *argtypes); extern void func_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg);
#endif /* PARSE_FUNC_H */ #endif /* PARSE_FUNC_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment