Skip to content

Commit 4952836

Browse files
committed
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.
1 parent e0bd601 commit 4952836

File tree

10 files changed

+242
-132
lines changed

10 files changed

+242
-132
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.99 2000/01/09 00:26:22 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.100 2000/01/17 00:14:46 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1385,6 +1385,17 @@ _copyTypeName(TypeName *from)
13851385
return newnode;
13861386
}
13871387

1388+
static TypeCast *
1389+
_copyTypeCast(TypeCast *from)
1390+
{
1391+
TypeCast *newnode = makeNode(TypeCast);
1392+
1393+
Node_Copy(from, newnode, arg);
1394+
Node_Copy(from, newnode, typename);
1395+
1396+
return newnode;
1397+
}
1398+
13881399
static Query *
13891400
_copyQuery(Query *from)
13901401
{
@@ -1658,6 +1669,9 @@ copyObject(void *from)
16581669
case T_TypeName:
16591670
retval = _copyTypeName(from);
16601671
break;
1672+
case T_TypeCast:
1673+
retval = _copyTypeCast(from);
1674+
break;
16611675

16621676
/*
16631677
* VALUE NODES

src/backend/nodes/freefuncs.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.30 2000/01/09 00:26:23 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.31 2000/01/17 00:14:47 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1046,6 +1046,15 @@ _freeTypeName(TypeName *node)
10461046
pfree(node);
10471047
}
10481048

1049+
static void
1050+
_freeTypeCast(TypeCast *node)
1051+
{
1052+
freeObject(node->arg);
1053+
freeObject(node->typename);
1054+
1055+
pfree(node);
1056+
}
1057+
10491058
static void
10501059
_freeQuery(Query *node)
10511060
{
@@ -1294,6 +1303,9 @@ freeObject(void *node)
12941303
case T_TypeName:
12951304
_freeTypeName(node);
12961305
break;
1306+
case T_TypeCast:
1307+
_freeTypeCast(node);
1308+
break;
12971309

12981310
/*
12991311
* VALUE NODES

src/backend/nodes/outfuncs.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Copyright (c) 1994, Regents of the University of California
77
*
8-
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.102 2000/01/14 00:53:21 tgl Exp $
8+
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.103 2000/01/17 00:14:47 tgl Exp $
99
*
1010
* NOTES
1111
* Every (plan) node in POSTGRES has an associated "out" routine which
@@ -190,6 +190,15 @@ _outTypeName(StringInfo str, TypeName *node)
190190
_outNode(str, node->arrayBounds);
191191
}
192192

193+
static void
194+
_outTypeCast(StringInfo str, TypeCast *node)
195+
{
196+
appendStringInfo(str, " TYPECAST :arg ");
197+
_outNode(str, node->arg);
198+
appendStringInfo(str, " :typename ");
199+
_outNode(str, node->typename);
200+
}
201+
193202
static void
194203
_outIndexElem(StringInfo str, IndexElem *node)
195204
{
@@ -1292,6 +1301,8 @@ _outAConst(StringInfo str, A_Const *node)
12921301
{
12931302
appendStringInfo(str, "CONST ");
12941303
_outValue(str, &(node->val));
1304+
appendStringInfo(str, " :typename ");
1305+
_outNode(str, node->typename);
12951306
}
12961307

12971308
static void
@@ -1400,6 +1411,9 @@ _outNode(StringInfo str, void *obj)
14001411
case T_TypeName:
14011412
_outTypeName(str, obj);
14021413
break;
1414+
case T_TypeCast:
1415+
_outTypeCast(str, obj);
1416+
break;
14031417
case T_IndexElem:
14041418
_outIndexElem(str, obj);
14051419
break;

src/backend/parser/gram.y

Lines changed: 40 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
%{ /* -*-text-*- */
1+
%{
22

33
/*#define YYDEBUG 1*/
44
/*-------------------------------------------------------------------------
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.127 2000/01/16 20:04:55 petere Exp $
13+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.128 2000/01/17 00:14:48 tgl Exp $
1414
*
1515
* HISTORY
1616
* AUTHOR DATE MAJOR EVENT
@@ -71,6 +71,7 @@ static int pfunc_num_args;
7171
static char *xlateSqlFunc(char *);
7272
static char *xlateSqlType(char *);
7373
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
74+
static Node *makeTypeCast(Node *arg, TypeName *typename);
7475
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
7576
static void mapTargetColumns(List *source, List *target);
7677
static void param_type_init(Oid *typev, int nargs);
@@ -274,6 +275,8 @@ static Node *doNegate(Node *n);
274275
* This gets annoying when trying to also retain Postgres' nice
275276
* type-extensible features, but we don't really have a choice.
276277
* - thomas 1997-10-11
278+
* NOTE: Whenever possible, try to add new keywords to the ColId list,
279+
* or failing that, at least to the ColLabel list.
277280
*/
278281

279282
/* Keywords (in SQL92 reserved words) */
@@ -3902,23 +3905,7 @@ MathOp: '+' { $$ = "+"; }
39023905
a_expr: com_expr
39033906
{ $$ = $1; }
39043907
| a_expr TYPECAST Typename
3905-
{
3906-
$$ = (Node *)$1;
3907-
/* AexprConst can be either A_Const or ParamNo */
3908-
if (nodeTag($1) == T_A_Const) {
3909-
((A_Const *)$1)->typename = $3;
3910-
} else if (nodeTag($1) == T_ParamNo) {
3911-
((ParamNo *)$1)->typename = $3;
3912-
/* otherwise, try to transform to a function call */
3913-
} else {
3914-
FuncCall *n = makeNode(FuncCall);
3915-
n->funcname = $3->name;
3916-
n->args = lcons($1,NIL);
3917-
n->agg_star = false;
3918-
n->agg_distinct = false;
3919-
$$ = (Node *)n;
3920-
}
3921-
}
3908+
{ $$ = makeTypeCast($1, $3); }
39223909
/*
39233910
* Can't collapse this into prior rule by using a_expr_or_null;
39243911
* that creates reduce/reduce conflicts. Grumble.
@@ -4149,23 +4136,7 @@ a_expr: com_expr
41494136
b_expr: com_expr
41504137
{ $$ = $1; }
41514138
| b_expr TYPECAST Typename
4152-
{
4153-
$$ = (Node *)$1;
4154-
/* AexprConst can be either A_Const or ParamNo */
4155-
if (nodeTag($1) == T_A_Const) {
4156-
((A_Const *)$1)->typename = $3;
4157-
} else if (nodeTag($1) == T_ParamNo) {
4158-
((ParamNo *)$1)->typename = $3;
4159-
/* otherwise, try to transform to a function call */
4160-
} else {
4161-
FuncCall *n = makeNode(FuncCall);
4162-
n->funcname = $3->name;
4163-
n->args = lcons($1,NIL);
4164-
n->agg_star = false;
4165-
n->agg_distinct = false;
4166-
$$ = (Node *)n;
4167-
}
4168-
}
4139+
{ $$ = makeTypeCast($1, $3); }
41694140
| NULL_P TYPECAST Typename
41704141
{
41714142
A_Const *n = makeNode(A_Const);
@@ -4243,23 +4214,7 @@ com_expr: attr
42434214
| '(' a_expr_or_null ')'
42444215
{ $$ = $2; }
42454216
| CAST '(' a_expr_or_null AS Typename ')'
4246-
{
4247-
$$ = (Node *)$3;
4248-
/* AexprConst can be either A_Const or ParamNo */
4249-
if (nodeTag($3) == T_A_Const) {
4250-
((A_Const *)$3)->typename = $5;
4251-
} else if (nodeTag($3) == T_ParamNo) {
4252-
((ParamNo *)$3)->typename = $5;
4253-
/* otherwise, try to transform to a function call */
4254-
} else {
4255-
FuncCall *n = makeNode(FuncCall);
4256-
n->funcname = $5->name;
4257-
n->args = lcons($3,NIL);
4258-
n->agg_star = false;
4259-
n->agg_distinct = false;
4260-
$$ = (Node *)n;
4261-
}
4262-
}
4217+
{ $$ = makeTypeCast($3, $5); }
42634218
| case_expr
42644219
{ $$ = $1; }
42654220
| func_name '(' ')'
@@ -5078,6 +5033,7 @@ ColLabel: ColId { $$ = $1; }
50785033
| CONSTRAINT { $$ = "constraint"; }
50795034
| COPY { $$ = "copy"; }
50805035
| CURRENT { $$ = "current"; }
5036+
| DECIMAL { $$ = "decimal"; }
50815037
| DO { $$ = "do"; }
50825038
| ELSE { $$ = "else"; }
50835039
| END_TRANS { $$ = "end"; }
@@ -5095,6 +5051,7 @@ ColLabel: ColId { $$ = $1; }
50955051
| NEW { $$ = "new"; }
50965052
| NONE { $$ = "none"; }
50975053
| NULLIF { $$ = "nullif"; }
5054+
| NUMERIC { $$ = "numeric"; }
50985055
| ORDER { $$ = "order"; }
50995056
| POSITION { $$ = "position"; }
51005057
| PRECISION { $$ = "precision"; }
@@ -5139,6 +5096,36 @@ makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
51395096
return (Node *)a;
51405097
}
51415098

5099+
static Node *
5100+
makeTypeCast(Node *arg, TypeName *typename)
5101+
{
5102+
/*
5103+
* If arg is an A_Const or ParamNo, just stick the typename into the
5104+
* field reserved for it --- unless there's something there already!
5105+
* (We don't want to collapse x::type1::type2 into just x::type2.)
5106+
* Otherwise, generate a TypeCast node.
5107+
*/
5108+
if (IsA(arg, A_Const) &&
5109+
((A_Const *) arg)->typename == NULL)
5110+
{
5111+
((A_Const *) arg)->typename = typename;
5112+
return arg;
5113+
}
5114+
else if (IsA(arg, ParamNo) &&
5115+
((ParamNo *) arg)->typename == NULL)
5116+
{
5117+
((ParamNo *) arg)->typename = typename;
5118+
return arg;
5119+
}
5120+
else
5121+
{
5122+
TypeCast *n = makeNode(TypeCast);
5123+
n->arg = arg;
5124+
n->typename = typename;
5125+
return (Node *) n;
5126+
}
5127+
}
5128+
51425129
/* makeRowExpr()
51435130
* Generate separate operator nodes for a single row descriptor expression.
51445131
* Perhaps this should go deeper in the parser someday...

src/backend/parser/parse_coerce.c

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.27 2000/01/10 17:14:36 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.28 2000/01/17 00:14:48 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -32,8 +32,8 @@ static Oid PreferredType(CATEGORY category, Oid type);
3232
* Convert a function argument to a different type.
3333
*/
3434
Node *
35-
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
36-
int32 atttypmod)
35+
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
36+
Oid targetTypeId, int32 atttypmod)
3737
{
3838
Node *result = NULL;
3939

@@ -200,6 +200,70 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
200200
return true;
201201
}
202202

203+
/* coerce_type_typmod()
204+
* Force a value to a particular typmod, if meaningful and possible.
205+
*
206+
* This is applied to values that are going to be stored in a relation
207+
* (where we have an atttypmod for the column) as well as values being
208+
* explicitly CASTed (where the typmod comes from the target type spec).
209+
*
210+
* The caller must have already ensured that the value is of the correct
211+
* type, typically by applying coerce_type.
212+
*
213+
* If the target column type possesses a function named for the type
214+
* and having parameter signature (columntype, int4), we assume that
215+
* the type requires coercion to its own length and that the said
216+
* function should be invoked to do that.
217+
*
218+
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
219+
*/
220+
Node *
221+
coerce_type_typmod(ParseState *pstate, Node *node,
222+
Oid targetTypeId, int32 atttypmod)
223+
{
224+
char *funcname;
225+
Oid oid_array[FUNC_MAX_ARGS];
226+
HeapTuple ftup;
227+
228+
/*
229+
* We assume that only typmod values greater than 0 indicate a forced
230+
* conversion is necessary.
231+
*/
232+
if (atttypmod <= 0 ||
233+
atttypmod == exprTypmod(node))
234+
return node;
235+
236+
funcname = typeidTypeName(targetTypeId);
237+
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
238+
oid_array[0] = targetTypeId;
239+
oid_array[1] = INT4OID;
240+
241+
/* attempt to find with arguments exactly as specified... */
242+
ftup = SearchSysCacheTuple(PROCNAME,
243+
PointerGetDatum(funcname),
244+
Int32GetDatum(2),
245+
PointerGetDatum(oid_array),
246+
0);
247+
248+
if (HeapTupleIsValid(ftup))
249+
{
250+
A_Const *cons = makeNode(A_Const);
251+
FuncCall *func = makeNode(FuncCall);
252+
253+
cons->val.type = T_Integer;
254+
cons->val.val.ival = atttypmod;
255+
256+
func->funcname = funcname;
257+
func->args = lappend(lcons(node, NIL), cons);
258+
func->agg_star = false;
259+
func->agg_distinct = false;
260+
261+
node = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
262+
}
263+
264+
return node;
265+
}
266+
203267

204268
/* TypeCategory()
205269
* Assign a category to the specified OID.

0 commit comments

Comments
 (0)