Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
3ace5fd0
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3ace5fd0
编写于
5月 09, 1998
作者:
T
Thomas G. Lockhart
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add capabilities for automatic type conversion.
上级
54b5577c
变更
10
展开全部
隐藏空白更改
内联
并排
Showing
10 changed file
with
2050 addition
and
394 deletion
+2050
-394
src/backend/parser/analyze.c
src/backend/parser/analyze.c
+8
-1
src/backend/parser/parse_coerce.c
src/backend/parser/parse_coerce.c
+560
-0
src/backend/parser/parse_expr.c
src/backend/parser/parse_expr.c
+12
-6
src/backend/parser/parse_func.c
src/backend/parser/parse_func.c
+727
-119
src/backend/parser/parse_node.c
src/backend/parser/parse_node.c
+115
-42
src/backend/parser/parse_oper.c
src/backend/parser/parse_oper.c
+341
-128
src/backend/parser/parse_target.c
src/backend/parser/parse_target.c
+181
-94
src/backend/parser/parse_type.c
src/backend/parser/parse_type.c
+8
-2
src/include/parser/parse_coerce.h
src/include/parser/parse_coerce.h
+96
-0
src/include/parser/parse_func.h
src/include/parser/parse_func.h
+2
-2
未找到文件。
src/backend/parser/analyze.c
浏览文件 @
3ace5fd0
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.7
4 1998/03/31 23:31:10 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.7
5 1998/05/09 23:29:52 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -30,6 +30,9 @@
#include "parser/parse_target.h"
#include "utils/builtins.h"
#include "utils/mcxt.h"
#ifdef PARSEDEBUG
#include "nodes/print.h"
#endif
static
Query
*
transformStmt
(
ParseState
*
pstate
,
Node
*
stmt
);
static
Query
*
transformDeleteStmt
(
ParseState
*
pstate
,
DeleteStmt
*
stmt
);
...
...
@@ -65,6 +68,10 @@ parse_analyze(List *pl, ParseState *parentParseState)
while
(
pl
!=
NIL
)
{
#ifdef PARSEDEBUG
elog
(
DEBUG
,
"parse tree from yacc:
\n
---
\n
%s
\n
---
\n
"
,
nodeToString
(
lfirst
(
pl
)));
#endif
pstate
=
make_parsestate
(
parentParseState
);
result
->
qtrees
[
i
++
]
=
transformStmt
(
pstate
,
lfirst
(
pl
));
if
(
pstate
->
p_target_relation
!=
NULL
)
...
...
src/backend/parser/parse_coerce.c
0 → 100644
浏览文件 @
3ace5fd0
/*-------------------------------------------------------------------------
*
* parse_coerce.c
* handle type coersions/conversions for parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.1 1998/05/09 23:29:53 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "utils/builtins.h"
#include "fmgr.h"
#include "nodes/makefuncs.h"
#include "parser/parse_expr.h"
#include "catalog/pg_type.h"
#include "parser/parse_type.h"
#include "parser/parse_target.h"
#include "parser/parse_coerce.h"
#include "utils/syscache.h"
Oid
DemoteType
(
Oid
inType
);
Oid
PromoteTypeToNext
(
Oid
inType
);
/* coerce_type()
* Convert a function argument to a different type.
*/
Node
*
coerce_type
(
ParseState
*
pstate
,
Node
*
node
,
Oid
inputTypeId
,
Oid
targetTypeId
)
{
Node
*
result
=
NULL
;
Oid
infunc
;
Datum
val
;
#ifdef PARSEDEBUG
printf
(
"coerce_type: argument types are %d -> %d
\n
"
,
inputTypeId
,
targetTypeId
);
#endif
if
(
targetTypeId
==
InvalidOid
)
{
#ifdef PARSEDEBUG
printf
(
"coerce_type: apparent NULL target argument; suppress type conversion
\n
"
);
#endif
result
=
node
;
}
else
if
(
inputTypeId
!=
targetTypeId
)
{
/* one of the known-good transparent conversions? then drop through... */
if
(
IS_BINARY_COMPATIBLE
(
inputTypeId
,
targetTypeId
))
{
#ifdef PARSEDEBUG
printf
(
"coerce_type: argument type %s is known to be convertible to type %s
\n
"
,
typeidTypeName
(
inputTypeId
),
typeidTypeName
(
targetTypeId
));
#endif
result
=
node
;
}
/* if not unknown input type, try for explicit conversion using functions... */
else
if
(
inputTypeId
!=
UNKNOWNOID
)
{
/* We already know there is a function which will do this, so let's use it */
FuncCall
*
n
=
makeNode
(
FuncCall
);
n
->
funcname
=
typeidTypeName
(
targetTypeId
);
n
->
args
=
lcons
(
node
,
NIL
);
#ifdef PARSEDEBUG
printf
(
"coerce_type: construct function %s(%s)
\n
"
,
typeidTypeName
(
targetTypeId
),
typeidTypeName
(
inputTypeId
));
#endif
result
=
transformExpr
(
pstate
,
(
Node
*
)
n
,
EXPR_COLUMN_FIRST
);
}
else
{
#ifdef PARSEDEBUG
printf
(
"coerce_type: node is UNKNOWN type
\n
"
);
#endif
if
(
nodeTag
(
node
)
==
T_Const
)
{
Const
*
con
=
(
Const
*
)
node
;
val
=
(
Datum
)
textout
((
struct
varlena
*
)
con
->
constvalue
);
infunc
=
typeidInfunc
(
targetTypeId
);
con
=
makeNode
(
Const
);
con
->
consttype
=
targetTypeId
;
con
->
constlen
=
typeLen
(
typeidType
(
targetTypeId
));
/* use "-1" for varchar() type */
con
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
val
,
typeidTypElem
(
targetTypeId
),
-
1
);
con
->
constisnull
=
false
;
con
->
constbyval
=
true
;
con
->
constisset
=
false
;
result
=
(
Node
*
)
con
;
}
else
{
#ifdef PARSEDEBUG
printf
(
"coerce_type: should never get here!
\n
"
);
#endif
result
=
node
;
}
}
}
else
{
#ifdef PARSEDEBUG
printf
(
"coerce_type: argument type IDs %d match
\n
"
,
inputTypeId
);
#endif
result
=
node
;
}
return
result
;
}
/* coerce_type() */
/* can_coerce_type()
* Can input_typeids be coerced to func_typeids?
*
* There are a few types which are known apriori to be convertible.
* We will check for those cases first, and then look for possible
* conversion functions.
*
* Notes:
* This uses the same mechanism as the CAST() SQL construct in gram.y.
* We should also check the function return type on candidate conversion
* routines just to be safe but we do not do that yet...
* We need to have a zero-filled OID array here, otherwise the cache lookup fails.
* - thomas 1998-03-31
*/
bool
can_coerce_type
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
)
{
HeapTuple
ftup
;
int
i
;
Type
tp
;
Oid
oid_array
[
8
];
/* run through argument list... */
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: argument #%d types are %d -> %d
\n
"
,
i
,
input_typeids
[
i
],
func_typeids
[
i
]);
#endif
if
(
input_typeids
[
i
]
!=
func_typeids
[
i
])
{
/* one of the known-good transparent conversions? then drop through... */
if
(
IS_BINARY_COMPATIBLE
(
input_typeids
[
i
],
func_typeids
[
i
]))
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: argument #%d type %s is known to be convertible to type %s
\n
"
,
i
,
typeidTypeName
(
input_typeids
[
i
]),
typeidTypeName
(
func_typeids
[
i
]));
#endif
}
/* don't know what to do for the output type? then quit... */
else
if
(
func_typeids
[
i
]
==
InvalidOid
)
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: output OID func_typeids[%d] is zero
\n
"
,
i
);
#endif
return
false
;
}
/* don't know what to do for the input type? then quit... */
else
if
(
input_typeids
[
i
]
==
InvalidOid
)
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: input OID input_typeids[%d] is zero
\n
"
,
i
);
#endif
return
false
;
}
/* if not unknown input type, try for explicit conversion using functions... */
else
if
(
input_typeids
[
i
]
!=
UNKNOWNOID
)
{
MemSet
(
&
oid_array
[
0
],
0
,
8
*
sizeof
(
Oid
));
oid_array
[
0
]
=
input_typeids
[
i
];
/* look for a single-argument function named with the target type name */
ftup
=
SearchSysCacheTuple
(
PRONAME
,
PointerGetDatum
(
typeidTypeName
(
func_typeids
[
i
])),
Int32GetDatum
(
1
),
PointerGetDatum
(
oid_array
),
0
);
/* should also check the function return type just to be safe... */
if
(
HeapTupleIsValid
(
ftup
))
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: found function %s(%s) to convert argument #%d
\n
"
,
typeidTypeName
(
func_typeids
[
i
]),
typeidTypeName
(
input_typeids
[
i
]),
i
);
#endif
}
else
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: did not find function %s(%s) to convert argument #%d
\n
"
,
typeidTypeName
(
func_typeids
[
i
]),
typeidTypeName
(
input_typeids
[
i
]),
i
);
#endif
return
false
;
}
}
else
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: argument #%d type is %d (UNKNOWN)
\n
"
,
i
,
input_typeids
[
i
]);
#endif
}
tp
=
typeidType
(
input_typeids
[
i
]);
if
(
typeTypeFlag
(
tp
)
==
'c'
)
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: typeTypeFlag for %s is 'c'
\n
"
,
typeidTypeName
(
input_typeids
[
i
]));
#endif
return
false
;
}
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: conversion from %s to %s is possible
\n
"
,
typeidTypeName
(
input_typeids
[
i
]),
typeidTypeName
(
func_typeids
[
i
]));
#endif
}
else
{
#ifdef PARSEDEBUG
printf
(
"can_coerce_type: argument #%d type IDs %d match
\n
"
,
i
,
input_typeids
[
i
]);
#endif
}
}
return
true
;
}
/* can_coerce_type() */
/* TypeCategory()
* Assign a category to the specified OID.
*/
CATEGORY
TypeCategory
(
Oid
inType
)
{
CATEGORY
result
;
switch
(
inType
)
{
case
(
BOOLOID
):
result
=
BOOLEAN_TYPE
;
break
;
case
(
CHAROID
):
case
(
BPCHAROID
):
case
(
VARCHAROID
):
case
(
TEXTOID
):
result
=
STRING_TYPE
;
break
;
case
(
INT2OID
):
case
(
INT4OID
):
case
(
FLOAT4OID
):
case
(
FLOAT8OID
):
case
(
CASHOID
):
result
=
NUMERIC_TYPE
;
break
;
case
(
ABSTIMEOID
):
case
(
TIMESTAMPOID
):
case
(
DATETIMEOID
):
result
=
DATETIME_TYPE
;
break
;
case
(
RELTIMEOID
):
case
(
TIMESPANOID
):
result
=
TIMESPAN_TYPE
;
break
;
case
(
POINTOID
):
case
(
LSEGOID
):
case
(
LINEOID
):
case
(
BOXOID
):
case
(
PATHOID
):
case
(
CIRCLEOID
):
case
(
POLYGONOID
):
result
=
GEOMETRIC_TYPE
;
break
;
default:
result
=
USER_TYPE
;
break
;
}
return
(
result
);
}
/* TypeCategory() */
/* IsPreferredType()
* Assign a category to the specified OID.
*/
bool
IsPreferredType
(
CATEGORY
category
,
Oid
type
)
{
return
(
type
==
PreferredType
(
category
,
type
));
}
/* IsPreferredType() */
/* PreferredType()
* Assign a category to the specified OID.
*/
Oid
PreferredType
(
CATEGORY
category
,
Oid
type
)
{
Oid
result
;
switch
(
category
)
{
case
(
BOOLEAN_TYPE
):
result
=
BOOLOID
;
break
;
case
(
STRING_TYPE
):
result
=
TEXTOID
;
break
;
case
(
NUMERIC_TYPE
):
result
=
FLOAT8OID
;
break
;
case
(
DATETIME_TYPE
):
result
=
DATETIMEOID
;
break
;
case
(
TIMESPAN_TYPE
):
result
=
TIMESPANOID
;
break
;
case
(
GEOMETRIC_TYPE
):
case
(
USER_TYPE
):
result
=
type
;
break
;
default:
result
=
UNKNOWNOID
;
break
;
}
#ifdef PARSEDEBUG
printf
(
"PreferredType- (%d) preferred type is %s
\n
"
,
category
,
typeidTypeName
(
result
));
#endif
return
(
result
);
}
/* PreferredType() */
#if FALSE
Oid
PromoteTypeToNext
(
Oid
inType
)
{
Oid
result
;
switch
(
inType
)
{
case
(
CHAROID
):
case
(
BPCHAROID
):
result
=
VARCHAROID
;
break
;
case
(
VARCHAROID
):
result
=
TEXTOID
;
break
;
case
(
INT2OID
):
case
(
CASHOID
):
result
=
INT4OID
;
break
;
case
(
INT4OID
):
case
(
FLOAT4OID
):
result
=
FLOAT8OID
;
break
;
case
(
DATEOID
):
case
(
ABSTIMEOID
):
case
(
TIMESTAMPOID
):
result
=
DATETIMEOID
;
break
;
case
(
TIMEOID
):
case
(
RELTIMEOID
):
result
=
TIMESPANOID
;
break
;
case
(
BOOLOID
):
case
(
TEXTOID
):
case
(
FLOAT8OID
):
case
(
DATETIMEOID
):
case
(
TIMESPANOID
):
default:
result
=
inType
;
break
;
}
return
(
result
);
}
/* PromoteTypeToNext() */
Oid
DemoteType
(
Oid
inType
)
{
Oid
result
;
switch
(
inType
)
{
case
(
FLOAT4OID
):
case
(
FLOAT8OID
):
result
=
INT4OID
;
break
;
default:
result
=
inType
;
break
;
}
return
(
result
);
}
/* DemoteType() */
Oid
PromoteLesserType
(
Oid
inType1
,
Oid
inType2
,
Oid
*
newType1
,
Oid
*
newType2
)
{
Oid
result
;
if
(
inType1
==
inType2
)
{
result
=
PromoteTypeToNext
(
inType1
);
inType1
=
result
;
*
arg2
=
result
;
return
(
result
);
}
kind1
=
ClassifyType
(
inType1
);
kind2
=
ClassifyType
(
*
arg2
);
if
(
kind1
!=
kind2
)
{
*
newType1
=
inType1
;
*
newType2
=
inType2
;
result
=
InvalidOid
;
}
isBuiltIn1
=
IS_BUILTIN_TYPE
(
inType1
);
isBuiltIn2
=
IS_BUILTIN_TYPE
(
*
arg2
);
if
(
isBuiltIn1
&&
isBuiltIn2
)
{
switch
(
*
arg1
)
{
case
(
CHAROID
):
switch
(
*
arg2
)
{
case
(
BPCHAROID
):
case
(
VARCHAROID
):
case
(
TEXTOID
):
case
(
INT2OID
):
case
(
INT4OID
):
case
(
FLOAT4OID
):
case
(
FLOAT8OID
):
case
(
CASHOID
):
case
(
POINTOID
):
case
(
LSEGOID
):
case
(
LINEOID
):
case
(
BOXOID
):
case
(
PATHOID
):
case
(
CIRCLEOID
):
case
(
POLYGONOID
):
case
(
InvalidOid
):
case
(
UNKNOWNOID
):
case
(
BOOLOID
):
default:
*
arg1
=
InvalidOid
;
*
arg2
=
InvalidOid
;
result
=
InvalidOid
;
}
}
else
if
(
isBuiltIn1
&&
!
isBuiltIn2
)
{
if
((
promotedType
=
PromoteBuiltInType
(
*
arg1
))
!=
*
arg1
)
{
*
arg1
=
promotedType
;
return
(
promotedType
);
}
else
if
(
CanCoerceType
(
*
arg1
,
*
arg2
))
{
*
arg1
=
*
arg2
;
return
(
*
arg2
);
}
}
else
if
(
!
isBuiltIn1
&&
isBuiltIn2
)
{
if
((
promotedType
=
PromoteBuiltInType
(
*
arg2
))
!=
*
arg2
)
{
*
arg2
=
promotedType
;
return
(
promotedType
);
}
else
if
(
CanCoerceType
(
*
arg2
,
*
arg1
))
{
*
arg2
=
*
arg1
;
return
(
*
arg1
);
}
}
if
(
*
arg2
==
InvalidOid
)
return
InvalidOid
;
switch
(
*
arg1
)
{
case
(
CHAROID
):
switch
(
*
arg2
)
{
case
(
BPCHAROID
):
case
(
VARCHAROID
):
case
(
TEXTOID
):
case
(
INT2OID
):
case
(
INT4OID
):
case
(
FLOAT4OID
):
case
(
FLOAT8OID
):
case
(
CASHOID
):
case
(
POINTOID
):
case
(
LSEGOID
):
case
(
LINEOID
):
case
(
BOXOID
):
case
(
PATHOID
):
case
(
CIRCLEOID
):
case
(
POLYGONOID
):
case
(
InvalidOid
):
case
(
UNKNOWNOID
):
case
(
BOOLOID
):
default:
*
arg1
=
InvalidOid
;
*
arg2
=
InvalidOid
;
result
=
InvalidOid
;
}
}
#endif
src/backend/parser/parse_expr.c
浏览文件 @
3ace5fd0
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.2
7 1998/04/26 04:06:45 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.2
8 1998/05/09 23:29:53 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -301,12 +301,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
result
=
(
Node
*
)
expr
;
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
* into two branches of the parse tree. Hence, some nodes
* are transformed twice. These nodes come from transforming
* a function call. Let's try just passing them through...
* into two branches of the parse tree; hence, some nodes
* are transformed twice.
* These cases below come from transforming function calls.
* Let's try just passing them through...
* - thomas 1998-03-14
*/
case
T_Expr
:
...
...
@@ -506,6 +508,10 @@ parser_typecast(Value *expr, TypeName *typename, int16 atttypmod)
return
(
Node
*
)
adt
;
}
/* parser_typecast2()
* Convert (only) constants to specified type.
*/
Node
*
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int16
atttypmod
)
{
...
...
src/backend/parser/parse_func.c
浏览文件 @
3ace5fd0
此差异已折叠。
点击以展开。
src/backend/parser/parse_node.c
浏览文件 @
3ace5fd0
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.1
4 1998/02/26 04:33:32 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.1
5 1998/05/09 23:29:53 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -39,7 +39,7 @@ make_operand(char *opname,
/*
* make_parsestate() --
* allocate and initialize a new ParseState.
* the CALLER
S
is responsible for freeing the ParseState* returned
* the CALLER is responsible for freeing the ParseState* returned
*
*/
...
...
@@ -57,6 +57,15 @@ make_parsestate(ParseState *parentParseState)
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
*
make_operand
(
char
*
opname
,
Node
*
tree
,
...
...
@@ -65,35 +74,33 @@ make_operand(char *opname,
{
Node
*
result
;
Type
true_type
;
#if FALSE
Datum
val
;
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
)
{
result
=
tree
;
true_type
=
typeidType
(
true_typeId
);
disallow_setop
(
opname
,
true_type
,
result
);
/* must coerce? */
if
(
true_typeId
!=
orig_typeId
)
{
/* must coerce */
Const
*
con
=
(
Const
*
)
result
;
Assert
(
nodeTag
(
result
)
==
T_Const
);
val
=
(
Datum
)
textout
((
struct
varlena
*
)
con
->
constvalue
);
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
;
{
#ifdef PARSEDEBUG
printf
(
"make_operand: try to convert node from %s to %s
\n
"
,
typeidTypeName
(
orig_typeId
),
typeidTypeName
(
true_typeId
));
#endif
result
=
coerce_type
(
NULL
,
tree
,
orig_typeId
,
true_typeId
);
}
}
/* otherwise, this is a NULL value */
else
{
Const
*
con
=
makeNode
(
Const
);
...
...
@@ -108,7 +115,7 @@ make_operand(char *opname,
}
return
result
;
}
}
/* make_operand() */
static
void
...
...
@@ -119,13 +126,49 @@ disallow_setop(char *op, Type optype, Node *operand)
if
(
nodeTag
(
operand
)
==
T_Iter
)
{
elog
(
NOTICE
,
"An operand to the '%s' operator returns a set of %s,"
,
op
,
typeTypeName
(
optype
));
elog
(
ERROR
,
"but '%s' takes single values, not sets."
,
op
);
elog
(
ERROR
,
"An operand to the '%s' operator returns a set of %s,"
"
\n\t
but '%s' takes single values, not sets."
,
op
,
typeTypeName
(
optype
),
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
*
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
)
{
...
...
@@ -138,10 +181,9 @@ make_op(char *opname, Node *ltree, Node *rtree)
*
right
;
Expr
*
result
;
/* right operator? */
if
(
rtree
==
NULL
)
{
/* right operator */
ltypeId
=
(
ltree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
ltree
);
temp
=
right_oper
(
opname
,
ltypeId
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
...
...
@@ -149,25 +191,29 @@ make_op(char *opname, Node *ltree, Node *rtree)
right
=
NULL
;
}
/* left operator? */
else
if
(
ltree
==
NULL
)
{
/* left operator */
rtypeId
=
(
rtree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
rtree
);
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
);
#ifdef PARSEDEBUG
printf
(
"make_op: calling make_operand()
\n
"
);
#endif
right
=
make_operand
(
opname
,
rtree
,
rtypeId
,
opform
->
oprright
);
left
=
NULL
;
}
/* otherwise, binary operator */
else
{
char
*
outstr
;
Oid
infunc
,
outfunc
;
Type
newtype
;
#define CONVERT
A
BLE_TYPE(t) ( (t) == INT2OID || \
#define CONVERT
I
BLE_TYPE(t) ( (t) == INT2OID || \
(t) == INT4OID || \
(t) == OIDOID || \
(t) == FLOAT4OID || \
...
...
@@ -178,12 +224,32 @@ make_op(char *opname, Node *ltree, Node *rtree)
ltypeId
=
(
ltree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
ltree
);
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
* non-const of another numeric type
*/
if
(
CONVERT
A
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
!=
T_Const
&&
CONVERT
A
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
==
T_Const
&&
if
(
CONVERT
I
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
!=
T_Const
&&
CONVERT
I
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
==
T_Const
&&
!
((
Const
*
)
rtree
)
->
constiscast
)
{
outfunc
=
typeidOutfunc
(
rtypeId
);
...
...
@@ -197,8 +263,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
((
Const
*
)
rtree
)
->
constbyval
=
typeByVal
(
newtype
);
}
if
(
CONVERT
A
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
!=
T_Const
&&
CONVERT
A
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
==
T_Const
&&
if
(
CONVERT
I
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
!=
T_Const
&&
CONVERT
I
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
==
T_Const
&&
!
((
Const
*
)
ltree
)
->
constiscast
)
{
outfunc
=
typeidOutfunc
(
ltypeId
);
...
...
@@ -211,6 +277,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
((
Const
*
)
ltree
)
->
constlen
=
typeLen
(
newtype
);
((
Const
*
)
ltree
)
->
constbyval
=
typeByVal
(
newtype
);
}
#endif
temp
=
oper
(
opname
,
ltypeId
,
rtypeId
,
false
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
...
...
@@ -219,8 +286,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
}
newop
=
makeOper
(
oprid
(
temp
),
/* opno */
InvalidOid
,
/* opid */
opform
->
oprresult
,
/* operator result type */
InvalidOid
,
/* opid */
opform
->
oprresult
,
/* operator result type */
0
,
NULL
);
...
...
@@ -239,6 +306,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
return
result
;
}
Var
*
make_var
(
ParseState
*
pstate
,
Oid
relid
,
char
*
refname
,
char
*
attrname
)
...
...
@@ -356,6 +424,9 @@ make_array_ref(Node *expr,
return
aref
;
}
/* make_array_set()
*/
ArrayRef
*
make_array_set
(
Expr
*
target_expr
,
List
*
upperIndexpr
,
...
...
@@ -406,10 +477,12 @@ make_array_set(Expr *target_expr,
aref
->
refexpr
=
(
Node
*
)
target_expr
;
aref
->
refassgnexpr
=
(
Node
*
)
expr
;
if
(
lowerIndexpr
==
NIL
)
/* accessing a single array element */
/* accessing a single array element? */
if
(
lowerIndexpr
==
NIL
)
reftype
=
aref
->
refelemtype
;
/* otherwise, request to set a part of the array, by another array */
else
/* request to set a part of the array, by another array */
reftype
=
typearray
;
aref
->
refelemtype
=
reftype
;
...
...
src/backend/parser/parse_oper.c
浏览文件 @
3ace5fd0
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.1
0 1998/04/27 04:06:09 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.1
1 1998/05/09 23:29:53 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -23,9 +23,18 @@
#include "fmgr.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "parser/parse_coerce.h"
#include "storage/bufmgr.h"
#include "utils/syscache.h"
extern
Oid
*
func_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
candidates
);
extern
Oid
*
oper_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
candidates
);
static
int
binary_oper_get_candidates
(
char
*
opname
,
Oid
leftTypeId
,
...
...
@@ -63,7 +72,8 @@ oprid(Operator op)
return
(
op
->
t_oid
);
}
/*
/* binary_oper_get_candidates()
* given opname, leftTypeId and rightTypeId,
* find all possible (arg1, arg2) pairs for which an operator named
* opname exists, such that leftTypeId can be coerced to arg1 and
...
...
@@ -97,7 +107,145 @@ binary_oper_get_candidates(char *opname,
F_CHAREQ
,
CharGetDatum
(
'b'
));
#if FALSE
if
(
leftTypeId
==
UNKNOWNOID
)
{
if
(
rightTypeId
==
UNKNOWNOID
)
{
nkeys
=
2
;
}
else
{
nkeys
=
3
;
ScanKeyEntryInitialize
(
&
opKey
[
2
],
0
,
Anum_pg_operator_oprright
,
ObjectIdEqualRegProcedure
,
ObjectIdGetDatum
(
rightTypeId
));
}
}
else
if
(
rightTypeId
==
UNKNOWNOID
)
{
nkeys
=
3
;
ScanKeyEntryInitialize
(
&
opKey
[
2
],
0
,
Anum_pg_operator_oprleft
,
ObjectIdEqualRegProcedure
,
ObjectIdGetDatum
(
leftTypeId
));
}
else
{
/* currently only "unknown" can be coerced */
return
0
;
#endif
nkeys
=
2
;
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
true
,
nkeys
,
opKey
);
do
{
tup
=
heap_getnext
(
pg_operator_scan
,
0
,
&
buffer
);
if
(
HeapTupleIsValid
(
tup
))
{
current_candidate
=
(
CandidateList
)
palloc
(
sizeof
(
struct
_CandidateList
));
current_candidate
->
args
=
(
Oid
*
)
palloc
(
2
*
sizeof
(
Oid
));
oper
=
(
OperatorTupleForm
)
GETSTRUCT
(
tup
);
current_candidate
->
args
[
0
]
=
oper
->
oprleft
;
current_candidate
->
args
[
1
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
ncandidates
++
;
ReleaseBuffer
(
buffer
);
}
}
while
(
HeapTupleIsValid
(
tup
));
heap_endscan
(
pg_operator_scan
);
heap_close
(
pg_operator_desc
);
return
ncandidates
;
}
/* binary_oper_get_candidates() */
#if FALSE
/* BinaryOperCandidates()
* Given opname, leftTypeId and rightTypeId,
* find all possible (arg1, arg2) pairs for which an operator named
* opname exists, such that leftTypeId can be coerced to arg1 and
* rightTypeId can be coerced to arg2.
*/
static
int
BinaryOperCandidates
(
char
*
opname
,
Oid
lTypeId
,
Oid
rTypeId
,
CandidateList
*
candidates
)
{
CandidateList
current_candidate
;
Relation
pg_operator_desc
;
HeapScanDesc
pg_operator_scan
;
HeapTuple
tup
;
OperatorTupleForm
oper
;
Buffer
buffer
;
int
nkeys
;
int
ncandidates
=
0
;
ScanKeyData
opKey
[
3
];
/* Can we promote the lesser type and find a match? */
lCandidateTypeId
=
lTypeId
;
rCandidateTypeId
=
rTypeId
;
higherTypeId
=
PromoteLowerType
(
&
lCandidateTypeId
,
&
rCandidateTypeId
);
if
(
lTypeId
!=
higherTypeId
)
lowerTypeId
=
lTypeId
;
else
lowerTypeId
=
rTypeId
;
while
(
lCandidateTypeId
!=
rCandidateTypeId
)
if
((
lCandidateTypeId
==
InvalidOid
)
||
(
rCandidateTypeId
==
InvalidOid
))
break
;
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
lCandidateTypeId
),
ObjectIdGetDatum
(
rCandidateTypeId
),
Int8GetDatum
(
'b'
));
if
(
HeapTupleIsValid
(
tup
))
return
((
Operator
)
tup
);
PromoteLowerType
(
&
lCandidateTypeId
,
&
rCandidateTypeId
);
}
/* Can we promote the lesser type directly to the other? */
if
(
can_coerce_type
(
lowerTypeId
,
higherTypeId
))
{
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
higherTypeId
),
ObjectIdGetDatum
(
higherTypeId
),
Int8GetDatum
(
'b'
));
if
(
HeapTupleIsValid
(
tup
))
return
((
Operator
)
tup
);
}
*
candidates
=
NULL
;
ScanKeyEntryInitialize
(
&
opKey
[
0
],
0
,
Anum_pg_operator_oprname
,
NameEqualRegProcedure
,
NameGetDatum
(
opname
));
ScanKeyEntryInitialize
(
&
opKey
[
1
],
0
,
Anum_pg_operator_oprkind
,
CharacterEqualRegProcedure
,
CharGetDatum
(
'b'
));
#if FALSE
if
(
leftTypeId
==
UNKNOWNOID
)
{
if
(
rightTypeId
==
UNKNOWNOID
)
...
...
@@ -124,8 +272,12 @@ binary_oper_get_candidates(char *opname,
ObjectIdGetDatum
(
leftTypeId
));
}
else
{
/* currently only "unknown" can be coerced */
return
0
;
#endif
nkeys
=
2
;
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
...
...
@@ -156,7 +308,9 @@ binary_oper_get_candidates(char *opname,
heap_close
(
pg_operator_desc
);
return
ncandidates
;
}
}
/* BinaryOperCandidates() */
#endif
/*
* equivalentOpersAfterPromotion -
...
...
@@ -164,7 +318,7 @@ binary_oper_get_candidates(char *opname,
* binary_oper_get_candidates() contain equivalent operators. If
* this routine is called, we have more than 1 candidate and need to
* decided whether to pick one of them. This routine returns true if
*
the
all the candidates operate on the same data types after
* all the candidates operate on the same data types after
* promotion (int2, int4, float4 -> float8).
*/
static
bool
...
...
@@ -237,9 +391,33 @@ equivalentOpersAfterPromotion(CandidateList candidates)
}
/*
* given a choice of argument type pairs for a binary operator,
* try to choose a default pair
/* binary_oper_select_candidate()
* Given a choice of argument type pairs for a binary operator,
* try to choose a default pair.
*
* current wisdom holds that the default operator should be one in which
* both operands have the same type (there will only be one such
* operator)
*
* 7.27.93 - I have decided not to do this; it's too hard to justify, and
* it's easy enough to typecast explicitly - avi
* [the rest of this routine was commented out since then - ay]
*
* 6/23/95 - I don't complete agree with avi. In particular, casting
* floats is a pain for users. Whatever the rationale behind not doing
* this is, I need the following special case to work.
*
* In the WHERE clause of a query, if a float is specified without
* quotes, we treat it as float8. I added the float48* operators so
* that we can operate on float4 and float8. But now we have more than
* one matching operator if the right arg is unknown (eg. float
* specified with quotes). This break some stuff in the regression
* test where there are floats in quotes not properly casted. Below is
* the solution. In addition to requiring the operator operates on the
* same type for both operands [as in the code Avi originally
* commented out], we also require that the operators be equivalent in
* some sense. (see equivalentOpersAfterPromotion for details.)
* - ay 6/95
*/
static
CandidateList
binary_oper_select_candidate
(
Oid
arg1
,
...
...
@@ -249,37 +427,11 @@ binary_oper_select_candidate(Oid arg1,
CandidateList
result
;
/*
* if both are "unknown", there is no way to select a candidate
*
* current wisdom holds that the default operator should be one in which
* both operands have the same type (there will only be one such
* operator)
*
* 7.27.93 - I have decided not to do this; it's too hard to justify, and
* it's easy enough to typecast explicitly -avi [the rest of this
* routine were commented out since then -ay]
* If both are "unknown", there is no way to select a candidate
*/
if
(
arg1
==
UNKNOWNOID
&&
arg2
==
UNKNOWNOID
)
return
(
NULL
);
/*
* 6/23/95 - I don't complete agree with avi. In particular, casting
* floats is a pain for users. Whatever the rationale behind not doing
* this is, I need the following special case to work.
*
* In the WHERE clause of a query, if a float is specified without
* quotes, we treat it as float8. I added the float48* operators so
* that we can operate on float4 and float8. But now we have more than
* one matching operator if the right arg is unknown (eg. float
* specified with quotes). This break some stuff in the regression
* test where there are floats in quotes not properly casted. Below is
* the solution. In addition to requiring the operator operates on the
* same type for both operands [as in the code Avi originally
* commented out], we also require that the operators be equivalent in
* some sense. (see equivalentOpersAfterPromotion for details.) - ay
* 6/95
*/
if
(
!
equivalentOpersAfterPromotion
(
candidates
))
return
NULL
;
...
...
@@ -296,90 +448,102 @@ binary_oper_select_candidate(Oid arg1,
return
(
NULL
);
}
/* Given operator, types of arg1, and arg2, return oper struct */
/* arg1, arg2 --typeids */
/* oper()
* Given operator, types of arg1, and arg2, return oper struct.
* Inputs:
* arg1, arg2: Type IDs
*/
Operator
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
if
(
!
arg2
)
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
Oid
*
targetOids
;
Oid
inputOids
[
2
];
/* Unspecified type for one of the arguments? then use the other */
if
(
arg2
==
InvalidOid
)
arg2
=
arg1
;
if
(
!
arg1
)
if
(
arg1
==
InvalidOid
)
arg1
=
arg2
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg1
),
ObjectIdGetDatum
(
arg2
),
Int8GetDatum
(
'b'
))))
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg1
),
ObjectIdGetDatum
(
arg2
),
Int8GetDatum
(
'b'
));
/* Did not find anything? then look more carefully... */
if
(
!
HeapTupleIsValid
(
tup
))
{
ncandidates
=
binary_oper_get_candidates
(
op
,
arg1
,
arg2
,
&
candidates
);
/* No operators found? Then throw error or return null... */
if
(
ncandidates
==
0
)
{
/*
* no operators of the desired types found
*/
if
(
!
noWarnings
)
op_error
(
op
,
arg1
,
arg2
);
return
(
NULL
);
}
/* Or found exactly one? Then proceed... */
else
if
(
ncandidates
==
1
)
{
/*
* exactly one operator of the desired types found
*/
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
1
]),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
1
]),
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
/* Otherwise, multiple operators of the desired types found... */
else
{
/*
* multiple operators of the desired types found
*/
#if FALSE
candidates
=
binary_oper_select_candidate
(
arg1
,
arg2
,
candidates
);
if
(
candidates
!=
NULL
)
#endif
inputOids
[
0
]
=
arg1
;
inputOids
[
1
]
=
arg2
;
targetOids
=
oper_select_candidate
(
2
,
inputOids
,
candidates
);
#if FALSE
targetOids
=
func_select_candidate
(
2
,
inputOids
,
candidates
);
#endif
if
(
targetOids
!=
NULL
)
{
/* we chose one of them */
#if PARSEDEBUG
printf
(
"oper: found candidate
\n
"
);
#endif
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
arg
s
[
0
]),
ObjectIdGetDatum
(
candidates
->
arg
s
[
1
]),
ObjectIdGetDatum
(
targetOid
s
[
0
]),
ObjectIdGetDatum
(
targetOid
s
[
1
]),
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
else
{
Type
tp1
,
tp2
;
tup
=
NULL
;
}
/* we chose none of them
*/
tp1
=
typeidType
(
arg1
);
tp2
=
typeidType
(
arg2
);
/* Could not choose one, for whatever reason...
*/
if
(
!
HeapTupleIsValid
(
tup
))
{
if
(
!
noWarnings
)
{
elog
(
NOTICE
,
"there is more than one operator %s for types"
,
op
);
elog
(
NOTICE
,
"%s and %s. You will have to retype this query"
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
elog
(
ERROR
,
"using an explicit cast"
);
elog
(
ERROR
,
"There is more than one operator '%s' for types '%s' and '%s'"
"
\n\t
You will have to retype this query using an explicit cast"
,
op
,
typeTypeName
(
typeidType
(
arg1
)),
typeTypeName
(
typeidType
(
arg2
)));
}
return
(
NULL
);
}
}
}
return
((
Operator
)
tup
);
}
}
/* oper() */
/*
/* unary_oper_get_candidates()
* given opname and typeId, find all possible types for which
* a right/left unary operator named opname exists,
* such that typeId can be coerced to it
...
...
@@ -409,6 +573,7 @@ unary_oper_get_candidates(char *op,
fmgr_info
(
F_CHAREQ
,
(
FmgrInfo
*
)
&
opKey
[
1
].
sk_func
);
opKey
[
1
].
sk_argument
=
CharGetDatum
(
rightleft
);
#if FALSE
/* currently, only "unknown" can be coerced */
/*
...
...
@@ -419,7 +584,11 @@ unary_oper_get_candidates(char *op,
{
return
0
;
}
#endif
#ifdef PARSEDEBUG
printf
(
"unary_oper_get_candidates: start scan for '%s'
\n
"
,
op
);
#endif
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
...
...
@@ -442,6 +611,10 @@ unary_oper_get_candidates(char *op,
current_candidate
->
args
[
0
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
#ifdef PARSEDEBUG
printf
(
"unary_oper_get_candidates: found candidate '%s' for type %s
\n
"
,
op
,
typeidTypeName
(
current_candidate
->
args
[
0
]));
#endif
ncandidates
++
;
ReleaseBuffer
(
buffer
);
}
...
...
@@ -450,32 +623,35 @@ unary_oper_get_candidates(char *op,
heap_endscan
(
pg_operator_scan
);
heap_close
(
pg_operator_desc
);
#ifdef PARSEDEBUG
printf
(
"unary_oper_get_candidates: found %d candidates
\n
"
,
ncandidates
);
#endif
return
ncandidates
;
}
}
/* unary_oper_get_candidates() */
/* Given unary right-side operator (operator on right), return oper struct */
/* arg-- type id */
Operator
right_oper
(
char
*
op
,
Oid
arg
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
/*
* if (!OpCache) { init_op_cache(); }
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg
),
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
))
))
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
Oid
*
targetOid
;
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg
)
,
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
));
if
(
!
HeapTupleIsValid
(
tup
))
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'r'
);
if
(
ncandidates
==
0
)
{
elog
(
ERROR
,
"Can't find right op: %s for type %d"
,
op
,
arg
);
elog
(
ERROR
,
"Can't find right op '%s' for type %d"
,
op
,
arg
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
...
...
@@ -489,38 +665,59 @@ right_oper(char *op, Oid arg)
}
else
{
elog
(
NOTICE
,
"there is more than one right operator %s"
,
op
);
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
ERROR
,
"using an explicit cast"
);
return
(
NULL
);
#if FALSE
elog
(
ERROR
,
"There is more than one right operator %s"
"
\n\t
You will have to retype this query using an explicit cast"
,
op
);
#endif
targetOid
=
func_select_candidate
(
1
,
&
arg
,
candidates
);
if
(
targetOid
!=
NULL
)
{
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
*
targetOid
),
Int8GetDatum
(
'r'
));
}
else
{
tup
=
NULL
;
}
if
(
!
HeapTupleIsValid
(
tup
))
{
elog
(
ERROR
,
"Unable to convert right operator '%s' from type %s to %s"
,
op
,
typeidTypeName
(
arg
),
typeidTypeName
(
*
targetOid
));
return
(
NULL
);
}
}
}
return
((
Operator
)
tup
);
}
}
/* right_oper() */
/* Given unary left-side operator (operator on left), return oper struct */
/* arg--type id */
Operator
left_oper
(
char
*
op
,
Oid
arg
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
/*
* if (!OpCache) { init_op_cache(); }
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
arg
),
Int8GetDatum
(
'l'
))
))
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
Oid
*
targetOid
;
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
)
,
ObjectIdGetDatum
(
arg
),
Int8GetDatum
(
'l'
));
if
(
!
HeapTupleIsValid
(
tup
))
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'l'
);
if
(
ncandidates
==
0
)
{
elog
(
ERROR
,
"Can't find left op: %s for type %d"
,
op
,
arg
);
elog
(
ERROR
,
"Can't find left op '%s' for type %d"
,
op
,
arg
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
...
...
@@ -528,22 +725,44 @@ left_oper(char *op, Oid arg)
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
Int8GetDatum
(
'l'
));
Assert
(
HeapTupleIsValid
(
tup
));
#ifdef PARSEDEBUG
printf
(
"left_oper: searched cache for single left oper candidate '%s %s'
\n
"
,
op
,
typeidTypeName
((
Oid
)
candidates
->
args
[
0
]));
#endif
}
else
{
elog
(
NOTICE
,
"there is more than one left operator %s"
,
op
);
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
ERROR
,
"using an explicit cast"
);
return
(
NULL
);
#if FALSE
elog
(
ERROR
,
"There is more than one left operator %s"
"
\n\t
You will have to retype this query using an explicit cast"
,
op
);
#endif
targetOid
=
func_select_candidate
(
1
,
&
arg
,
candidates
);
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
*
targetOid
),
Int8GetDatum
(
'l'
));
if
(
!
HeapTupleIsValid
(
tup
))
{
elog
(
ERROR
,
"Unable to convert left operator '%s' from type %s to %s"
,
op
,
typeidTypeName
(
arg
),
typeidTypeName
(
*
targetOid
));
return
(
NULL
);
}
#ifdef PARSEDEBUG
printf
(
"left_oper: searched cache for best left oper candidate '%s %s'
\n
"
,
op
,
typeidTypeName
(
*
targetOid
));
#endif
}
}
return
((
Operator
)
tup
);
}
}
/* left_oper() */
/*
/* op_error()
* Give a somewhat useful error message when the operator for two types
* is not found.
*/
...
...
@@ -559,7 +778,8 @@ op_error(char *op, Oid arg1, Oid arg2)
}
else
{
elog
(
ERROR
,
"left hand side of operator %s has an unknown type, probably a bad attribute name"
,
op
);
elog
(
ERROR
,
"Left hand side of operator '%s' has an unknown type"
"
\n\t
Probably a bad attribute name"
,
op
);
}
if
(
typeidIsValid
(
arg2
))
...
...
@@ -568,17 +788,10 @@ op_error(char *op, Oid arg1, Oid arg2)
}
else
{
elog
(
ERROR
,
"right hand side of operator %s has an unknown type, probably a bad attribute name"
,
op
);
elog
(
ERROR
,
"Right hand side of operator %s has an unknown type"
"
\n\t
Probably a bad attribute name"
,
op
);
}
#if FALSE
elog
(
NOTICE
,
"there is no operator %s for types %s and %s"
,
op
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
elog
(
NOTICE
,
"You will either have to retype this query using an"
);
elog
(
NOTICE
,
"explicit cast, or you will have to define the operator"
);
elog
(
ERROR
,
"%s for %s and %s using CREATE OPERATOR"
,
op
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
#endif
elog
(
ERROR
,
"There is no operator '%s' for types '%s' and '%s'"
"
\n\t
You will either have to retype this query using an explicit cast,"
"
\n\t
or you will have to define the operator using CREATE OPERATOR"
,
...
...
src/backend/parser/parse_target.c
浏览文件 @
3ace5fd0
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.1
1 1998/02/26 04:33:35 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.1
2 1998/05/09 23:29:54 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -26,6 +26,13 @@
#include "parser/parse_target.h"
#include "utils/builtins.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
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
);
...
...
@@ -34,6 +41,16 @@ make_targetlist_expr(ParseState *pstate,
char
*
colname
,
Node
*
expr
,
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 -
...
...
@@ -110,8 +127,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
Relation
rd
;
Value
*
constval
;
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
!
IsA
(
expr
,
Const
))
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
!
IsA
(
expr
,
Const
))
elog
(
ERROR
,
"yyparse: string constant expected"
);
val
=
(
char
*
)
textout
((
struct
varlena
*
)
...
...
@@ -123,15 +139,15 @@ transformTargetList(ParseState *pstate, List *targetlist)
aind
->
uidx
=
transformExpr
(
pstate
,
aind
->
uidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
uidx
,
Const
))
elog
(
ERROR
,
"Array Index for Append should be a constant"
);
elog
(
ERROR
,
"Array Index for Append should be a constant"
);
uindx
[
i
]
=
((
Const
*
)
aind
->
uidx
)
->
constvalue
;
if
(
aind
->
lidx
!=
NULL
)
{
aind
->
lidx
=
transformExpr
(
pstate
,
aind
->
lidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
lidx
,
Const
))
elog
(
ERROR
,
"Array Index for Append should be a constant"
);
elog
(
ERROR
,
"Array Index for Append should be a constant"
);
lindx
[
i
]
=
((
Const
*
)
aind
->
lidx
)
->
constvalue
;
}
else
...
...
@@ -140,6 +156,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
if
(
lindx
[
i
]
>
uindx
[
i
])
elog
(
ERROR
,
"yyparse: lower index cannot be greater than upper index"
);
sprintf
(
str
,
"[%d:%d]"
,
lindx
[
i
],
uindx
[
i
]);
str
+=
strlen
(
str
);
i
++
;
...
...
@@ -151,11 +168,12 @@ transformTargetList(ParseState *pstate, List *targetlist)
ndims
=
attnumAttNelems
(
rd
,
resdomno
);
if
(
i
!=
ndims
)
elog
(
ERROR
,
"yyparse: array dimensions do not match"
);
constval
=
makeNode
(
Value
);
constval
->
type
=
T_String
;
constval
->
val
.
str
=
save_str
;
tent
=
make_targetlist_expr
(
pstate
,
res
->
name
,
(
Node
*
)
make_const
(
constval
),
(
Node
*
)
make_const
(
constval
),
NULL
);
pfree
(
save_str
);
}
...
...
@@ -300,8 +318,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
default:
/* internal error */
elog
(
ERROR
,
"internal error: do not know how to transform targetlist"
);
elog
(
ERROR
,
"internal error: do not know how to transform targetlist"
);
break
;
}
...
...
@@ -321,11 +338,125 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
/*
* make_targetlist_expr -
* make a TargetEntry from an expression
Node
*
coerce_target_expr
(
ParseState
*
pstate
,
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
*
* For type mismatches between expressions and targets, use the same
* techniques as for function and operator type coersion.
* - thomas 1998-05-08
*/
static
TargetEntry
*
make_targetlist_expr
(
ParseState
*
pstate
,
...
...
@@ -355,7 +486,6 @@ make_targetlist_expr(ParseState *pstate,
/* Processes target columns that will be receiving results */
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
{
/*
* insert or update query -- insert, update work only on one
* relation, so multiple occurence of same resdomno is bogus
...
...
@@ -368,91 +498,47 @@ make_targetlist_expr(ParseState *pstate,
if
((
arrayRef
!=
NIL
)
&&
(
lfirst
(
arrayRef
)
==
NIL
))
attrtype
=
GetArrayElementType
(
attrtype
);
attrtypmod
=
rd
->
rd_att
->
attrs
[
resdomno
-
1
]
->
atttypmod
;
#if 0
if (Input_is_string && Typecast_ok)
{
Datum val;
if (type_id == typeTypeId(type("unknown")))
{
val = (Datum) textout((struct varlena *)
((Const) lnext(expr))->constvalue);
}
else
{
val = ((Const) lnext(expr))->constvalue;
}
if (attrisset)
{
lnext(expr) = makeConst(attrtype,
attrlen,
val,
false,
true,
true, /* is set */
false);
}
else
{
lnext(expr) =
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))
{
lnext(expr) =
parser_typecast2(expr, typeidType(attrtype));
}
else if (attrtype != type_id)
/* Check for InvalidOid since that seems to indicate a NULL constant... */
if
(
type_id
!=
InvalidOid
)
{
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;
Input_is_integer = false;
Typecast_ok = true;
#endif
if
(
attrtype
!=
type_id
)
{
if
(
IsA
(
expr
,
Const
))
/* Mismatch on types? then try to coerce to target... */
if
(
attrtype
!=
type_id
)
{
/* try to cast the constant */
Oid
typelem
;
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
);
typelem
=
typeidTypElem
(
attrtype
);
}
else
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
typeidType
(
attrtype
),
attrtypmod
);
{
typelem
=
attrtype
;
}
expr
=
coerce_target_expr
(
pstate
,
expr
,
type_id
,
typelem
);
if
(
!
HeapTupleIsValid
(
expr
))
{
elog
(
ERROR
,
"parser: attribute '%s' is of type '%s'"
" but expression is of type '%s'"
"
\n\t
You will need to rewrite or cast the expression"
,
colname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
type_id
));
}
}
else
#ifdef PARSEDEBUG
printf
(
"parse_target: attrtypmod is %d
\n
"
,
(
int4
)
attrtypmod
);
#endif
/* Apparently going to a fixed-length string?
* Then explicitly size for storage...
*/
if
(
attrtypmod
>
0
)
{
/* currently, we can't handle casting of expressions */
elog
(
ERROR
,
"parser: attribute '%s' is of type '%s' but expression is of type '%s'"
,
colname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
type_id
));
expr
=
size_target_expr
(
pstate
,
expr
,
attrtype
,
attrtypmod
);
}
}
...
...
@@ -467,8 +553,8 @@ make_targetlist_expr(ParseState *pstate,
att
->
relname
=
pstrdup
(
RelationGetRelationName
(
rd
)
->
data
);
att
->
attrs
=
lcons
(
makeString
(
colname
),
NIL
);
target_expr
=
(
Expr
*
)
ParseNestedFuncOrColumn
(
pstate
,
att
,
&
pstate
->
p_last_resno
,
EXPR_COLUMN_FIRST
);
&
pstate
->
p_last_resno
,
EXPR_COLUMN_FIRST
);
while
(
ar
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ar
);
...
...
@@ -514,7 +600,8 @@ make_targetlist_expr(ParseState *pstate,
tent
->
expr
=
expr
;
return
tent
;
}
}
/* make_targetlist_expr() */
/*
* makeTargetNames -
...
...
@@ -564,7 +651,7 @@ makeTargetNames(ParseState *pstate, List *cols)
attnameAttNum
(
pstate
->
p_target_relation
,
name
);
foreach
(
nxt
,
lnext
(
tl
))
if
(
!
strcmp
(
name
,
((
Ident
*
)
lfirst
(
nxt
))
->
name
))
elog
(
ERROR
,
"Attribute '%s' should be specified only once"
,
name
);
elog
(
ERROR
,
"Attribute '%s' should be specified only once"
,
name
);
}
}
...
...
src/backend/parser/parse_type.c
浏览文件 @
3ace5fd0
/*-------------------------------------------------------------------------
*
* parse_type.
h
* parse_type.
c
* handle type operations for parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* 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 @@
#include "postgres.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 "parser/parse_target.h"
#include "parser/parse_type.h"
#include "utils/syscache.h"
/* check to see if a type id is valid,
* returns true if it is. By using this call before calling
* typeidType or typeidTypeName, more meaningful error messages
...
...
src/include/parser/parse_coerce.h
0 → 100644
浏览文件 @
3ace5fd0
/*-------------------------------------------------------------------------
*
* 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 */
src/include/parser/parse_func.h
浏览文件 @
3ace5fd0
...
...
@@ -6,7 +6,7 @@
*
* 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 *
ParseFuncOrColumn
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
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 */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录