Create a new parsetree node type, TypeCast, so that transformation of
SQL cast constructs can be performed during expression transformation instead of during parsing. This allows constructs like x::numeric(9,2) and x::int2::float8 to behave as one would expect.
This commit is contained in:
parent
e0bd60171a
commit
49528361f5
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.99 2000/01/09 00:26:22 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.100 2000/01/17 00:14:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1385,6 +1385,17 @@ _copyTypeName(TypeName *from)
|
|||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TypeCast *
|
||||||
|
_copyTypeCast(TypeCast *from)
|
||||||
|
{
|
||||||
|
TypeCast *newnode = makeNode(TypeCast);
|
||||||
|
|
||||||
|
Node_Copy(from, newnode, arg);
|
||||||
|
Node_Copy(from, newnode, typename);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
static Query *
|
static Query *
|
||||||
_copyQuery(Query *from)
|
_copyQuery(Query *from)
|
||||||
{
|
{
|
||||||
@ -1658,6 +1669,9 @@ copyObject(void *from)
|
|||||||
case T_TypeName:
|
case T_TypeName:
|
||||||
retval = _copyTypeName(from);
|
retval = _copyTypeName(from);
|
||||||
break;
|
break;
|
||||||
|
case T_TypeCast:
|
||||||
|
retval = _copyTypeCast(from);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VALUE NODES
|
* VALUE NODES
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.30 2000/01/09 00:26:23 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.31 2000/01/17 00:14:47 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1046,6 +1046,15 @@ _freeTypeName(TypeName *node)
|
|||||||
pfree(node);
|
pfree(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_freeTypeCast(TypeCast *node)
|
||||||
|
{
|
||||||
|
freeObject(node->arg);
|
||||||
|
freeObject(node->typename);
|
||||||
|
|
||||||
|
pfree(node);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_freeQuery(Query *node)
|
_freeQuery(Query *node)
|
||||||
{
|
{
|
||||||
@ -1294,6 +1303,9 @@ freeObject(void *node)
|
|||||||
case T_TypeName:
|
case T_TypeName:
|
||||||
_freeTypeName(node);
|
_freeTypeName(node);
|
||||||
break;
|
break;
|
||||||
|
case T_TypeCast:
|
||||||
|
_freeTypeCast(node);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VALUE NODES
|
* VALUE NODES
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.102 2000/01/14 00:53:21 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.103 2000/01/17 00:14:47 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||||
@ -190,6 +190,15 @@ _outTypeName(StringInfo str, TypeName *node)
|
|||||||
_outNode(str, node->arrayBounds);
|
_outNode(str, node->arrayBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outTypeCast(StringInfo str, TypeCast *node)
|
||||||
|
{
|
||||||
|
appendStringInfo(str, " TYPECAST :arg ");
|
||||||
|
_outNode(str, node->arg);
|
||||||
|
appendStringInfo(str, " :typename ");
|
||||||
|
_outNode(str, node->typename);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_outIndexElem(StringInfo str, IndexElem *node)
|
_outIndexElem(StringInfo str, IndexElem *node)
|
||||||
{
|
{
|
||||||
@ -1292,6 +1301,8 @@ _outAConst(StringInfo str, A_Const *node)
|
|||||||
{
|
{
|
||||||
appendStringInfo(str, "CONST ");
|
appendStringInfo(str, "CONST ");
|
||||||
_outValue(str, &(node->val));
|
_outValue(str, &(node->val));
|
||||||
|
appendStringInfo(str, " :typename ");
|
||||||
|
_outNode(str, node->typename);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1400,6 +1411,9 @@ _outNode(StringInfo str, void *obj)
|
|||||||
case T_TypeName:
|
case T_TypeName:
|
||||||
_outTypeName(str, obj);
|
_outTypeName(str, obj);
|
||||||
break;
|
break;
|
||||||
|
case T_TypeCast:
|
||||||
|
_outTypeCast(str, obj);
|
||||||
|
break;
|
||||||
case T_IndexElem:
|
case T_IndexElem:
|
||||||
_outIndexElem(str, obj);
|
_outIndexElem(str, obj);
|
||||||
break;
|
break;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
%{ /* -*-text-*- */
|
%{
|
||||||
|
|
||||||
/*#define YYDEBUG 1*/
|
/*#define YYDEBUG 1*/
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.127 2000/01/16 20:04:55 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.128 2000/01/17 00:14:48 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -71,6 +71,7 @@ static int pfunc_num_args;
|
|||||||
static char *xlateSqlFunc(char *);
|
static char *xlateSqlFunc(char *);
|
||||||
static char *xlateSqlType(char *);
|
static char *xlateSqlType(char *);
|
||||||
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
|
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
|
||||||
|
static Node *makeTypeCast(Node *arg, TypeName *typename);
|
||||||
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
|
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
|
||||||
static void mapTargetColumns(List *source, List *target);
|
static void mapTargetColumns(List *source, List *target);
|
||||||
static void param_type_init(Oid *typev, int nargs);
|
static void param_type_init(Oid *typev, int nargs);
|
||||||
@ -274,6 +275,8 @@ static Node *doNegate(Node *n);
|
|||||||
* This gets annoying when trying to also retain Postgres' nice
|
* This gets annoying when trying to also retain Postgres' nice
|
||||||
* type-extensible features, but we don't really have a choice.
|
* type-extensible features, but we don't really have a choice.
|
||||||
* - thomas 1997-10-11
|
* - thomas 1997-10-11
|
||||||
|
* NOTE: Whenever possible, try to add new keywords to the ColId list,
|
||||||
|
* or failing that, at least to the ColLabel list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Keywords (in SQL92 reserved words) */
|
/* Keywords (in SQL92 reserved words) */
|
||||||
@ -3902,23 +3905,7 @@ MathOp: '+' { $$ = "+"; }
|
|||||||
a_expr: com_expr
|
a_expr: com_expr
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| a_expr TYPECAST Typename
|
| a_expr TYPECAST Typename
|
||||||
{
|
{ $$ = makeTypeCast($1, $3); }
|
||||||
$$ = (Node *)$1;
|
|
||||||
/* AexprConst can be either A_Const or ParamNo */
|
|
||||||
if (nodeTag($1) == T_A_Const) {
|
|
||||||
((A_Const *)$1)->typename = $3;
|
|
||||||
} else if (nodeTag($1) == T_ParamNo) {
|
|
||||||
((ParamNo *)$1)->typename = $3;
|
|
||||||
/* otherwise, try to transform to a function call */
|
|
||||||
} else {
|
|
||||||
FuncCall *n = makeNode(FuncCall);
|
|
||||||
n->funcname = $3->name;
|
|
||||||
n->args = lcons($1,NIL);
|
|
||||||
n->agg_star = false;
|
|
||||||
n->agg_distinct = false;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* Can't collapse this into prior rule by using a_expr_or_null;
|
* Can't collapse this into prior rule by using a_expr_or_null;
|
||||||
* that creates reduce/reduce conflicts. Grumble.
|
* that creates reduce/reduce conflicts. Grumble.
|
||||||
@ -4149,23 +4136,7 @@ a_expr: com_expr
|
|||||||
b_expr: com_expr
|
b_expr: com_expr
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| b_expr TYPECAST Typename
|
| b_expr TYPECAST Typename
|
||||||
{
|
{ $$ = makeTypeCast($1, $3); }
|
||||||
$$ = (Node *)$1;
|
|
||||||
/* AexprConst can be either A_Const or ParamNo */
|
|
||||||
if (nodeTag($1) == T_A_Const) {
|
|
||||||
((A_Const *)$1)->typename = $3;
|
|
||||||
} else if (nodeTag($1) == T_ParamNo) {
|
|
||||||
((ParamNo *)$1)->typename = $3;
|
|
||||||
/* otherwise, try to transform to a function call */
|
|
||||||
} else {
|
|
||||||
FuncCall *n = makeNode(FuncCall);
|
|
||||||
n->funcname = $3->name;
|
|
||||||
n->args = lcons($1,NIL);
|
|
||||||
n->agg_star = false;
|
|
||||||
n->agg_distinct = false;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| NULL_P TYPECAST Typename
|
| NULL_P TYPECAST Typename
|
||||||
{
|
{
|
||||||
A_Const *n = makeNode(A_Const);
|
A_Const *n = makeNode(A_Const);
|
||||||
@ -4243,23 +4214,7 @@ com_expr: attr
|
|||||||
| '(' a_expr_or_null ')'
|
| '(' a_expr_or_null ')'
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| CAST '(' a_expr_or_null AS Typename ')'
|
| CAST '(' a_expr_or_null AS Typename ')'
|
||||||
{
|
{ $$ = makeTypeCast($3, $5); }
|
||||||
$$ = (Node *)$3;
|
|
||||||
/* AexprConst can be either A_Const or ParamNo */
|
|
||||||
if (nodeTag($3) == T_A_Const) {
|
|
||||||
((A_Const *)$3)->typename = $5;
|
|
||||||
} else if (nodeTag($3) == T_ParamNo) {
|
|
||||||
((ParamNo *)$3)->typename = $5;
|
|
||||||
/* otherwise, try to transform to a function call */
|
|
||||||
} else {
|
|
||||||
FuncCall *n = makeNode(FuncCall);
|
|
||||||
n->funcname = $5->name;
|
|
||||||
n->args = lcons($3,NIL);
|
|
||||||
n->agg_star = false;
|
|
||||||
n->agg_distinct = false;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| case_expr
|
| case_expr
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| func_name '(' ')'
|
| func_name '(' ')'
|
||||||
@ -5078,6 +5033,7 @@ ColLabel: ColId { $$ = $1; }
|
|||||||
| CONSTRAINT { $$ = "constraint"; }
|
| CONSTRAINT { $$ = "constraint"; }
|
||||||
| COPY { $$ = "copy"; }
|
| COPY { $$ = "copy"; }
|
||||||
| CURRENT { $$ = "current"; }
|
| CURRENT { $$ = "current"; }
|
||||||
|
| DECIMAL { $$ = "decimal"; }
|
||||||
| DO { $$ = "do"; }
|
| DO { $$ = "do"; }
|
||||||
| ELSE { $$ = "else"; }
|
| ELSE { $$ = "else"; }
|
||||||
| END_TRANS { $$ = "end"; }
|
| END_TRANS { $$ = "end"; }
|
||||||
@ -5095,6 +5051,7 @@ ColLabel: ColId { $$ = $1; }
|
|||||||
| NEW { $$ = "new"; }
|
| NEW { $$ = "new"; }
|
||||||
| NONE { $$ = "none"; }
|
| NONE { $$ = "none"; }
|
||||||
| NULLIF { $$ = "nullif"; }
|
| NULLIF { $$ = "nullif"; }
|
||||||
|
| NUMERIC { $$ = "numeric"; }
|
||||||
| ORDER { $$ = "order"; }
|
| ORDER { $$ = "order"; }
|
||||||
| POSITION { $$ = "position"; }
|
| POSITION { $$ = "position"; }
|
||||||
| PRECISION { $$ = "precision"; }
|
| PRECISION { $$ = "precision"; }
|
||||||
@ -5139,6 +5096,36 @@ makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
|
|||||||
return (Node *)a;
|
return (Node *)a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
makeTypeCast(Node *arg, TypeName *typename)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If arg is an A_Const or ParamNo, just stick the typename into the
|
||||||
|
* field reserved for it --- unless there's something there already!
|
||||||
|
* (We don't want to collapse x::type1::type2 into just x::type2.)
|
||||||
|
* Otherwise, generate a TypeCast node.
|
||||||
|
*/
|
||||||
|
if (IsA(arg, A_Const) &&
|
||||||
|
((A_Const *) arg)->typename == NULL)
|
||||||
|
{
|
||||||
|
((A_Const *) arg)->typename = typename;
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
else if (IsA(arg, ParamNo) &&
|
||||||
|
((ParamNo *) arg)->typename == NULL)
|
||||||
|
{
|
||||||
|
((ParamNo *) arg)->typename = typename;
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TypeCast *n = makeNode(TypeCast);
|
||||||
|
n->arg = arg;
|
||||||
|
n->typename = typename;
|
||||||
|
return (Node *) n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* makeRowExpr()
|
/* makeRowExpr()
|
||||||
* Generate separate operator nodes for a single row descriptor expression.
|
* Generate separate operator nodes for a single row descriptor expression.
|
||||||
* Perhaps this should go deeper in the parser someday...
|
* Perhaps this should go deeper in the parser someday...
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.27 2000/01/10 17:14:36 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.28 2000/01/17 00:14:48 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -32,8 +32,8 @@ static Oid PreferredType(CATEGORY category, Oid type);
|
|||||||
* Convert a function argument to a different type.
|
* Convert a function argument to a different type.
|
||||||
*/
|
*/
|
||||||
Node *
|
Node *
|
||||||
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
|
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||||
int32 atttypmod)
|
Oid targetTypeId, int32 atttypmod)
|
||||||
{
|
{
|
||||||
Node *result = NULL;
|
Node *result = NULL;
|
||||||
|
|
||||||
@ -200,6 +200,70 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* coerce_type_typmod()
|
||||||
|
* Force a value to a particular typmod, if meaningful and possible.
|
||||||
|
*
|
||||||
|
* This is applied to values that are going to be stored in a relation
|
||||||
|
* (where we have an atttypmod for the column) as well as values being
|
||||||
|
* explicitly CASTed (where the typmod comes from the target type spec).
|
||||||
|
*
|
||||||
|
* The caller must have already ensured that the value is of the correct
|
||||||
|
* type, typically by applying coerce_type.
|
||||||
|
*
|
||||||
|
* If the target column type possesses a function named for the type
|
||||||
|
* and having parameter signature (columntype, int4), we assume that
|
||||||
|
* the type requires coercion to its own length and that the said
|
||||||
|
* function should be invoked to do that.
|
||||||
|
*
|
||||||
|
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
|
||||||
|
*/
|
||||||
|
Node *
|
||||||
|
coerce_type_typmod(ParseState *pstate, Node *node,
|
||||||
|
Oid targetTypeId, int32 atttypmod)
|
||||||
|
{
|
||||||
|
char *funcname;
|
||||||
|
Oid oid_array[FUNC_MAX_ARGS];
|
||||||
|
HeapTuple ftup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We assume that only typmod values greater than 0 indicate a forced
|
||||||
|
* conversion is necessary.
|
||||||
|
*/
|
||||||
|
if (atttypmod <= 0 ||
|
||||||
|
atttypmod == exprTypmod(node))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
funcname = typeidTypeName(targetTypeId);
|
||||||
|
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||||
|
oid_array[0] = targetTypeId;
|
||||||
|
oid_array[1] = INT4OID;
|
||||||
|
|
||||||
|
/* attempt to find with arguments exactly as specified... */
|
||||||
|
ftup = SearchSysCacheTuple(PROCNAME,
|
||||||
|
PointerGetDatum(funcname),
|
||||||
|
Int32GetDatum(2),
|
||||||
|
PointerGetDatum(oid_array),
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (HeapTupleIsValid(ftup))
|
||||||
|
{
|
||||||
|
A_Const *cons = makeNode(A_Const);
|
||||||
|
FuncCall *func = makeNode(FuncCall);
|
||||||
|
|
||||||
|
cons->val.type = T_Integer;
|
||||||
|
cons->val.val.ival = atttypmod;
|
||||||
|
|
||||||
|
func->funcname = funcname;
|
||||||
|
func->args = lappend(lcons(node, NIL), cons);
|
||||||
|
func->agg_star = false;
|
||||||
|
func->agg_distinct = false;
|
||||||
|
|
||||||
|
node = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TypeCategory()
|
/* TypeCategory()
|
||||||
* Assign a category to the specified OID.
|
* Assign a category to the specified OID.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.64 2000/01/16 05:18:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.65 2000/01/17 00:14:48 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,7 +29,9 @@
|
|||||||
#include "parser/parse_target.h"
|
#include "parser/parse_target.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
|
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
|
||||||
|
static Node *parser_typecast_expression(ParseState *pstate,
|
||||||
|
Node *expr, TypeName *typename);
|
||||||
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
|
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
|
||||||
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
|
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
|
||||||
static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
||||||
@ -63,7 +65,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
Value *val = &con->val;
|
Value *val = &con->val;
|
||||||
|
|
||||||
if (con->typename != NULL)
|
if (con->typename != NULL)
|
||||||
result = parser_typecast(val, con->typename, con->typename->typmod);
|
result = parser_typecast_constant(val, con->typename);
|
||||||
else
|
else
|
||||||
result = (Node *) make_const(val);
|
result = (Node *) make_const(val);
|
||||||
break;
|
break;
|
||||||
@ -85,6 +87,15 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
param->param_tlist = (List *) NULL;
|
param->param_tlist = (List *) NULL;
|
||||||
result = transformIndirection(pstate, (Node *) param,
|
result = transformIndirection(pstate, (Node *) param,
|
||||||
pno->indirection);
|
pno->indirection);
|
||||||
|
/* XXX what about cast (typename) applied to Param ??? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case T_TypeCast:
|
||||||
|
{
|
||||||
|
TypeCast *tc = (TypeCast *) expr;
|
||||||
|
Node *arg = transformExpr(pstate, tc->arg, precedence);
|
||||||
|
|
||||||
|
result = parser_typecast_expression(pstate, arg, tc->typename);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_A_Expr:
|
case T_A_Expr:
|
||||||
@ -689,7 +700,7 @@ exprTypmod(Node *expr)
|
|||||||
* by the parser and an explicit type name to cast to.
|
* 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_constant(Value *expr, TypeName *typename)
|
||||||
{
|
{
|
||||||
Const *con;
|
Const *con;
|
||||||
Type tp;
|
Type tp;
|
||||||
@ -716,7 +727,7 @@ 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_constant: cannot cast this expression to type '%s'",
|
||||||
typename->name);
|
typename->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +744,7 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
|
|||||||
if (isNull)
|
if (isNull)
|
||||||
datum = (Datum) NULL;
|
datum = (Datum) NULL;
|
||||||
else
|
else
|
||||||
datum = stringTypeDatum(tp, const_string, atttypmod);
|
datum = stringTypeDatum(tp, const_string, typename->typmod);
|
||||||
|
|
||||||
con = makeConst(typeTypeId(tp),
|
con = makeConst(typeTypeId(tp),
|
||||||
typeLen(tp),
|
typeLen(tp),
|
||||||
@ -748,3 +759,52 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
|
|||||||
|
|
||||||
return (Node *) con;
|
return (Node *) con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle an explicit CAST applied to a non-constant expression.
|
||||||
|
* (Actually, this works for constants too, but gram.y won't generate
|
||||||
|
* a TypeCast node if the argument is just a constant.)
|
||||||
|
*
|
||||||
|
* The given expr has already been transformed, but we need to lookup
|
||||||
|
* the type name and then apply any necessary coercion function(s).
|
||||||
|
*/
|
||||||
|
static Node *
|
||||||
|
parser_typecast_expression(ParseState *pstate,
|
||||||
|
Node *expr, TypeName *typename)
|
||||||
|
{
|
||||||
|
Oid inputType = exprType(expr);
|
||||||
|
Type tp;
|
||||||
|
Oid targetType;
|
||||||
|
|
||||||
|
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);
|
||||||
|
targetType = typeTypeId(tp);
|
||||||
|
|
||||||
|
if (inputType == InvalidOid)
|
||||||
|
return expr; /* do nothing if NULL input */
|
||||||
|
|
||||||
|
if (inputType != targetType)
|
||||||
|
{
|
||||||
|
expr = CoerceTargetExpr(pstate, expr,
|
||||||
|
inputType, targetType);
|
||||||
|
if (expr == NULL)
|
||||||
|
elog(ERROR, "Cannot cast type '%s' to '%s'",
|
||||||
|
typeidTypeName(inputType),
|
||||||
|
typeidTypeName(targetType));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If the target is a fixed-length type, it may need a length
|
||||||
|
* coercion as well as a type coercion.
|
||||||
|
*/
|
||||||
|
expr = coerce_type_typmod(pstate, expr,
|
||||||
|
targetType, typename->typmod);
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.51 2000/01/10 17:14:36 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.52 2000/01/17 00:14:48 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -24,8 +24,6 @@
|
|||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
static Node *SizeTargetExpr(ParseState *pstate, Node *expr,
|
|
||||||
Oid attrtype, int32 attrtypmod);
|
|
||||||
static List *ExpandAllTables(ParseState *pstate);
|
static List *ExpandAllTables(ParseState *pstate);
|
||||||
static char *FigureColname(Node *expr, Node *resval);
|
static char *FigureColname(Node *expr, Node *resval);
|
||||||
|
|
||||||
@ -245,9 +243,7 @@ updateTargetListEntry(ParseState *pstate,
|
|||||||
* If the target is a fixed-length type, it may need a length
|
* If the target is a fixed-length type, it may need a length
|
||||||
* coercion as well as a type coercion.
|
* coercion as well as a type coercion.
|
||||||
*/
|
*/
|
||||||
if (attrtypmod > 0 &&
|
tle->expr = coerce_type_typmod(pstate, tle->expr,
|
||||||
attrtypmod != exprTypmod(tle->expr))
|
|
||||||
tle->expr = SizeTargetExpr(pstate, tle->expr,
|
|
||||||
attrtype, attrtypmod);
|
attrtype, attrtypmod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,61 +296,6 @@ CoerceTargetExpr(ParseState *pstate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SizeTargetExpr()
|
|
||||||
*
|
|
||||||
* If the target column type possesses a function named for the type
|
|
||||||
* and having parameter signature (columntype, int4), we assume that
|
|
||||||
* the type requires coercion to its own length and that the said
|
|
||||||
* function should be invoked to do that.
|
|
||||||
*
|
|
||||||
* Currently, "bpchar" (ie, char(N)) is the only such type, but try
|
|
||||||
* to be more general than a hard-wired test...
|
|
||||||
*/
|
|
||||||
static Node *
|
|
||||||
SizeTargetExpr(ParseState *pstate,
|
|
||||||
Node *expr,
|
|
||||||
Oid attrtype,
|
|
||||||
int32 attrtypmod)
|
|
||||||
{
|
|
||||||
char *funcname;
|
|
||||||
Oid oid_array[FUNC_MAX_ARGS];
|
|
||||||
HeapTuple ftup;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
funcname = typeidTypeName(attrtype);
|
|
||||||
oid_array[0] = attrtype;
|
|
||||||
oid_array[1] = INT4OID;
|
|
||||||
for (i = 2; i < FUNC_MAX_ARGS; i++)
|
|
||||||
oid_array[i] = InvalidOid;
|
|
||||||
|
|
||||||
/* attempt to find with arguments exactly as specified... */
|
|
||||||
ftup = SearchSysCacheTuple(PROCNAME,
|
|
||||||
PointerGetDatum(funcname),
|
|
||||||
Int32GetDatum(2),
|
|
||||||
PointerGetDatum(oid_array),
|
|
||||||
0);
|
|
||||||
|
|
||||||
if (HeapTupleIsValid(ftup))
|
|
||||||
{
|
|
||||||
A_Const *cons = makeNode(A_Const);
|
|
||||||
FuncCall *func = makeNode(FuncCall);
|
|
||||||
|
|
||||||
cons->val.type = T_Integer;
|
|
||||||
cons->val.val.ival = attrtypmod;
|
|
||||||
|
|
||||||
func->funcname = funcname;
|
|
||||||
func->args = lappend(lcons(expr, NIL), cons);
|
|
||||||
func->agg_star = false;
|
|
||||||
func->agg_distinct = false;
|
|
||||||
|
|
||||||
expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
|
|
||||||
}
|
|
||||||
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* checkInsertTargets -
|
* checkInsertTargets -
|
||||||
* generate a list of column names if not supplied or
|
* generate a list of column names if not supplied or
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.61 2000/01/16 20:04:58 petere Exp $
|
* $Id: nodes.h,v 1.62 2000/01/17 00:14:48 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -202,7 +202,7 @@ typedef enum NodeTag
|
|||||||
T_FuncCall,
|
T_FuncCall,
|
||||||
T_A_Indices,
|
T_A_Indices,
|
||||||
T_ResTarget,
|
T_ResTarget,
|
||||||
T_ParamString, /* not used anymore */
|
T_TypeCast,
|
||||||
T_RelExpr,
|
T_RelExpr,
|
||||||
T_SortGroupBy,
|
T_SortGroupBy,
|
||||||
T_RangeVar,
|
T_RangeVar,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.94 2000/01/16 20:04:58 petere Exp $
|
* $Id: parsenodes.h,v 1.95 2000/01/17 00:14:48 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -868,6 +868,22 @@ typedef struct A_Const
|
|||||||
TypeName *typename; /* typecast */
|
TypeName *typename; /* typecast */
|
||||||
} A_Const;
|
} A_Const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TypeCast - a CAST expression
|
||||||
|
*
|
||||||
|
* NOTE: for mostly historical reasons, A_Const and ParamNo parsenodes contain
|
||||||
|
* room for a TypeName; we only generate a separate TypeCast node if the
|
||||||
|
* argument to be casted is neither of those kinds of nodes. In theory either
|
||||||
|
* representation would work, but it is convenient (especially for A_Const)
|
||||||
|
* to have the target type immediately available.
|
||||||
|
*/
|
||||||
|
typedef struct TypeCast
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
Node *arg; /* the expression being casted */
|
||||||
|
TypeName *typename; /* the target type */
|
||||||
|
} TypeCast;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CaseExpr - a CASE expression
|
* CaseExpr - a CASE expression
|
||||||
*/
|
*/
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
*
|
*
|
||||||
* parse_coerce.h
|
* parse_coerce.h
|
||||||
*
|
*
|
||||||
*
|
* Routines for type coercion.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parse_coerce.h,v 1.15 1999/07/16 17:07:36 momjian Exp $
|
* $Id: parse_coerce.h,v 1.16 2000/01/17 00:14:49 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -126,5 +126,7 @@ extern CATEGORY TypeCategory(Oid type);
|
|||||||
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids);
|
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids);
|
||||||
extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||||
Oid targetTypeId, int32 atttypmod);
|
Oid targetTypeId, int32 atttypmod);
|
||||||
|
extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
|
||||||
|
Oid targetTypeId, int32 atttypmod);
|
||||||
|
|
||||||
#endif /* PARSE_COERCE_H */
|
#endif /* PARSE_COERCE_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user