Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
3ace5fd0
Commit
3ace5fd0
authored
May 09, 1998
by
Thomas G. Lockhart
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add capabilities for automatic type conversion.
parent
54b5577c
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
2050 additions
and
394 deletions
+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
No files found.
src/backend/parser/analyze.c
View file @
3ace5fd0
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* 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 @@
...
@@ -30,6 +30,9 @@
#include "parser/parse_target.h"
#include "parser/parse_target.h"
#include "utils/builtins.h"
#include "utils/builtins.h"
#include "utils/mcxt.h"
#include "utils/mcxt.h"
#ifdef PARSEDEBUG
#include "nodes/print.h"
#endif
static
Query
*
transformStmt
(
ParseState
*
pstate
,
Node
*
stmt
);
static
Query
*
transformStmt
(
ParseState
*
pstate
,
Node
*
stmt
);
static
Query
*
transformDeleteStmt
(
ParseState
*
pstate
,
DeleteStmt
*
stmt
);
static
Query
*
transformDeleteStmt
(
ParseState
*
pstate
,
DeleteStmt
*
stmt
);
...
@@ -65,6 +68,10 @@ parse_analyze(List *pl, ParseState *parentParseState)
...
@@ -65,6 +68,10 @@ parse_analyze(List *pl, ParseState *parentParseState)
while
(
pl
!=
NIL
)
while
(
pl
!=
NIL
)
{
{
#ifdef PARSEDEBUG
elog
(
DEBUG
,
"parse tree from yacc:
\n
---
\n
%s
\n
---
\n
"
,
nodeToString
(
lfirst
(
pl
)));
#endif
pstate
=
make_parsestate
(
parentParseState
);
pstate
=
make_parsestate
(
parentParseState
);
result
->
qtrees
[
i
++
]
=
transformStmt
(
pstate
,
lfirst
(
pl
));
result
->
qtrees
[
i
++
]
=
transformStmt
(
pstate
,
lfirst
(
pl
));
if
(
pstate
->
p_target_relation
!=
NULL
)
if
(
pstate
->
p_target_relation
!=
NULL
)
...
...
src/backend/parser/parse_coerce.c
0 → 100644
View file @
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
View file @
3ace5fd0
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* 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)
...
@@ -301,12 +301,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
result
=
(
Node
*
)
expr
;
result
=
(
Node
*
)
expr
;
break
;
break
;
}
}
/* These nodes do _not_ come from the original parse tree.
* They result from parser transformation in this phase.
/* These nodes do _not_ come from the original parse tree,
* but result from parser transformation in this phase.
* At least one construct (BETWEEN/AND) puts the same nodes
* At least one construct (BETWEEN/AND) puts the same nodes
* into two branches of the parse tree. Hence, some nodes
* into two branches of the parse tree; hence, some nodes
* are transformed twice. These nodes come from transforming
* are transformed twice.
* a function call. Let's try just passing them through...
* These cases below come from transforming function calls.
* Let's try just passing them through...
* - thomas 1998-03-14
* - thomas 1998-03-14
*/
*/
case
T_Expr
:
case
T_Expr
:
...
@@ -506,6 +508,10 @@ parser_typecast(Value *expr, TypeName *typename, int16 atttypmod)
...
@@ -506,6 +508,10 @@ parser_typecast(Value *expr, TypeName *typename, int16 atttypmod)
return
(
Node
*
)
adt
;
return
(
Node
*
)
adt
;
}
}
/* parser_typecast2()
* Convert (only) constants to specified type.
*/
Node
*
Node
*
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int16
atttypmod
)
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int16
atttypmod
)
{
{
...
...
src/backend/parser/parse_func.c
View file @
3ace5fd0
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.1
6 1998/04/27 04:06:05 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.1
7 1998/05/09 23:29:53 thomas
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -37,6 +37,7 @@
...
@@ -37,6 +37,7 @@
#include "parser/parse_relation.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "parser/parse_type.h"
#include "parser/parse_coerce.h"
#include "storage/bufmgr.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/acl.h"
...
@@ -50,7 +51,7 @@ ParseComplexProjection(ParseState *pstate,
...
@@ -50,7 +51,7 @@ ParseComplexProjection(ParseState *pstate,
Node
*
first_arg
,
Node
*
first_arg
,
bool
*
attisset
);
bool
*
attisset
);
static
Oid
**
argtype_inherit
(
int
nargs
,
Oid
*
oid_array
);
static
Oid
**
argtype_inherit
(
int
nargs
,
Oid
*
oid_array
);
static
bool
can_coerce
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
);
static
int
find_inheritors
(
Oid
relid
,
Oid
**
supervec
);
static
int
find_inheritors
(
Oid
relid
,
Oid
**
supervec
);
static
CandidateList
func_get_candidates
(
char
*
funcname
,
int
nargs
);
static
CandidateList
func_get_candidates
(
char
*
funcname
,
int
nargs
);
static
bool
static
bool
...
@@ -61,14 +62,15 @@ func_get_detail(char *funcname,
...
@@ -61,14 +62,15 @@ func_get_detail(char *funcname,
Oid
*
rettype
,
/* return value */
Oid
*
rettype
,
/* return value */
bool
*
retset
,
/* return value */
bool
*
retset
,
/* return value */
Oid
**
true_typeids
);
Oid
**
true_typeids
);
static
Oid
*
Oid
*
func_select_candidate
(
int
nargs
,
func_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
input_typeids
,
CandidateList
candidates
);
CandidateList
candidates
);
static
Oid
funcid_get_rettype
(
Oid
funcid
);
static
Oid
funcid_get_rettype
(
Oid
funcid
);
static
Oid
**
gen_cross_product
(
InhPaths
*
arginh
,
int
nargs
);
static
Oid
**
gen_cross_product
(
InhPaths
*
arginh
,
int
nargs
);
static
void
static
void
make_arguments
(
int
nargs
,
make_arguments
(
ParseState
*
pstate
,
int
nargs
,
List
*
fargs
,
List
*
fargs
,
Oid
*
input_typeids
,
Oid
*
input_typeids
,
Oid
*
function_typeids
);
Oid
*
function_typeids
);
...
@@ -255,6 +257,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
...
@@ -255,6 +257,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
/*
/*
* Parsing aggregates.
* Parsing aggregates.
*/
*/
Type
tp
;
Oid
basetype
;
Oid
basetype
;
/*
/*
...
@@ -271,15 +274,27 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
...
@@ -271,15 +274,27 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
0
,
0
))
0
,
0
))
return
(
Node
*
)
ParseAgg
(
pstate
,
funcname
,
basetype
,
return
(
Node
*
)
ParseAgg
(
pstate
,
funcname
,
basetype
,
fargs
,
precedence
);
fargs
,
precedence
);
/*
* See if this is a single argument function with the function name
* also a type name and the input argument and type name binary compatible...
*/
if
((
HeapTupleIsValid
(
tp
=
SearchSysCacheTuple
(
TYPNAME
,
PointerGetDatum
(
funcname
),
0
,
0
,
0
)))
&&
IS_BINARY_COMPATIBLE
(
typeTypeId
(
tp
),
basetype
))
{
return
((
Node
*
)
lfirst
(
fargs
));
}
}
}
}
}
/*
/*
*
*
If we dropped through to here it's really a function (or a set,
* If we dropped through to here it's really a function (or a set,
*
which * is implemented as a function.) * extract arg type info and
*
which is implemented as a function).
*
transform relation name arguments into * varnodes of the
*
Extract arg type info and transform relation name arguments
* appropriate form.
*
into varnodes of the
appropriate form.
*/
*/
MemSet
(
&
oid_array
[
0
],
0
,
8
*
sizeof
(
Oid
));
MemSet
(
&
oid_array
[
0
],
0
,
8
*
sizeof
(
Oid
));
...
@@ -326,9 +341,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
...
@@ -326,9 +341,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
* constants, we don't know what to do with, because we can't
* constants, we don't know what to do with, because we can't
* cast them - jolly
* cast them - jolly
*/
*/
if
(
exprType
(
pair
)
==
UNKNOWNOID
&&
if
(
exprType
(
pair
)
==
UNKNOWNOID
&&
!
IsA
(
pair
,
Const
))
!
IsA
(
pair
,
Const
))
elog
(
ERROR
,
"ParseFuncOrColumn: no function named '%s'"
elog
(
ERROR
,
"ParseFuncOrColumn: no function named '%s'
that takes in an unknown type as argument #%d"
,
funcname
,
nargs
);
"
that takes in an unknown type as argument #%d"
,
funcname
,
nargs
);
else
else
toid
=
exprType
(
pair
);
toid
=
exprType
(
pair
);
}
}
...
@@ -383,7 +398,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
...
@@ -383,7 +398,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
funcnode
->
func_planlist
=
NIL
;
funcnode
->
func_planlist
=
NIL
;
/* perform the necessary typecasting */
/* perform the necessary typecasting */
make_arguments
(
nargs
,
fargs
,
oid_array
,
true_oid_array
);
make_arguments
(
pstate
,
nargs
,
fargs
,
oid_array
,
true_oid_array
);
/*
/*
* for functions returning base types, we want to project out the
* for functions returning base types, we want to project out the
...
@@ -490,7 +505,8 @@ funcid_get_rettype(Oid funcid)
...
@@ -490,7 +505,8 @@ funcid_get_rettype(Oid funcid)
return
(
funcrettype
);
return
(
funcrettype
);
}
}
/*
/* func_get_candidates()
* get a list of all argument type vectors for which a function named
* get a list of all argument type vectors for which a function named
* funcname taking nargs arguments exists
* funcname taking nargs arguments exists
*/
*/
...
@@ -567,44 +583,9 @@ func_get_candidates(char *funcname, int nargs)
...
@@ -567,44 +583,9 @@ func_get_candidates(char *funcname, int nargs)
return
candidates
;
return
candidates
;
}
}
/*
* can input_typeids be coerced to func_typeids?
*/
static
bool
can_coerce
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
)
{
int
i
;
Type
tp
;
/*
* right now, we only coerce "unknown", and we cannot coerce it to a
* relation type
*/
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
if
(
input_typeids
[
i
]
!=
func_typeids
[
i
])
{
if
((
input_typeids
[
i
]
==
BPCHAROID
&&
func_typeids
[
i
]
==
TEXTOID
)
||
(
input_typeids
[
i
]
==
BPCHAROID
&&
func_typeids
[
i
]
==
VARCHAROID
)
||
(
input_typeids
[
i
]
==
VARCHAROID
&&
func_typeids
[
i
]
==
TEXTOID
)
||
(
input_typeids
[
i
]
==
VARCHAROID
&&
func_typeids
[
i
]
==
BPCHAROID
)
||
(
input_typeids
[
i
]
==
CASHOID
&&
func_typeids
[
i
]
==
INT4OID
)
||
(
input_typeids
[
i
]
==
INT4OID
&&
func_typeids
[
i
]
==
CASHOID
))
;
/* these are OK */
else
if
(
input_typeids
[
i
]
!=
UNKNOWNOID
||
func_typeids
[
i
]
==
0
)
return
false
;
tp
=
typeidType
(
input_typeids
[
i
]);
if
(
typeTypeFlag
(
tp
)
==
'c'
)
return
false
;
}
}
return
true
;
/* match_argtypes()
}
* Given a list of possible typeid arrays to a function and an array of
/*
* given a list of possible typeid arrays to a function and an array of
* input typeids, produce a shortlist of those function typeid arrays
* input typeids, produce a shortlist of those function typeid arrays
* that match the input typeids (either exactly or by coercion), and
* that match the input typeids (either exactly or by coercion), and
* return the number of such arrays
* return the number of such arrays
...
@@ -627,7 +608,7 @@ match_argtypes(int nargs,
...
@@ -627,7 +608,7 @@ match_argtypes(int nargs,
current_candidate
=
current_candidate
->
next
)
current_candidate
=
current_candidate
->
next
)
{
{
current_typeids
=
current_candidate
->
args
;
current_typeids
=
current_candidate
->
args
;
if
(
can_coerce
(
nargs
,
input_typeids
,
current_typeids
))
if
(
can_coerce
_type
(
nargs
,
input_typeids
,
current_typeids
))
{
{
matching_candidate
=
(
CandidateList
)
matching_candidate
=
(
CandidateList
)
palloc
(
sizeof
(
struct
_CandidateList
));
palloc
(
sizeof
(
struct
_CandidateList
));
...
@@ -639,23 +620,629 @@ match_argtypes(int nargs,
...
@@ -639,23 +620,629 @@ match_argtypes(int nargs,
}
}
return
ncandidates
;
return
ncandidates
;
}
}
/* match_argtypes() */
/*
* given the input argtype array and more than one candidate
/* func_select_candidate()
* Given the input argtype array and more than one candidate
* for the function argtype array, attempt to resolve the conflict.
* for the function argtype array, attempt to resolve the conflict.
* returns the selected argtype array if the conflict can be resolved,
* returns the selected argtype array if the conflict can be resolved,
* otherwise returns NULL
* otherwise returns NULL.
*
* If all input Oids are UNKNOWNOID, then try matching with TEXTOID.
* Otherwise, could return first function arguments on list of candidates.
* But for now, return NULL and make the user give a better hint.
* - thomas 1998-03-17
*/
*/
static
Oid
*
Oid
*
func_select_candidate
(
int
nargs
,
func_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
input_typeids
,
CandidateList
candidates
)
CandidateList
candidates
)
{
{
/* XXX no conflict resolution implemeneted yet */
CandidateList
current_candidate
;
CandidateList
last_candidate
;
Oid
*
current_typeids
;
int
i
;
int
ncandidates
;
int
nbestMatch
,
nmatch
,
nident
;
CATEGORY
slot_category
,
current_category
;
Oid
slot_type
,
current_type
;
/*
* Run through all candidates and keep those with the most matches
* on explicit types. Keep all candidates if none match.
*/
ncandidates
=
0
;
nbestMatch
=
0
;
last_candidate
=
NULL
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
nmatch
=
0
;
nident
=
0
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
if
((
input_typeids
[
i
]
!=
UNKNOWNOID
)
&&
(
current_typeids
[
i
]
==
input_typeids
[
i
]))
{
nmatch
++
;
}
else
if
(
IS_BINARY_COMPATIBLE
(
current_typeids
[
i
],
input_typeids
[
i
]))
{
nident
++
;
}
}
if
((
nmatch
+
nident
)
==
nargs
)
return
(
current_candidate
->
args
);
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- candidate has %d matches
\n
"
,
nmatch
);
#endif
if
((
nmatch
>
nbestMatch
)
||
(
last_candidate
==
NULL
))
{
nbestMatch
=
nmatch
;
candidates
=
current_candidate
;
last_candidate
=
current_candidate
;
ncandidates
=
1
;
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- choose candidate as best match
\n
"
);
#endif
}
else
if
(
nmatch
==
nbestMatch
)
{
last_candidate
->
next
=
current_candidate
;
last_candidate
=
current_candidate
;
ncandidates
++
;
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- choose candidate as possible match
\n
"
);
#endif
}
else
{
last_candidate
->
next
=
NULL
;
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- reject candidate as possible match
\n
"
);
#endif
}
}
/*
* Still too many candidates?
* Try assigning types for the unknown columns.
*/
if
(
ncandidates
>
1
)
{
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
if
(
input_typeids
[
i
]
==
UNKNOWNOID
)
{
slot_category
=
INVALID_TYPE
;
slot_type
=
InvalidOid
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
current_type
=
current_typeids
[
i
];
current_category
=
TypeCategory
(
current_typeids
[
i
]);
if
(
slot_category
==
InvalidOid
)
{
slot_category
=
current_category
;
slot_type
=
current_type
;
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- assign column #%d first candidate slot type %s
\n
"
,
i
,
typeidTypeName
(
current_type
));
#endif
}
else
if
((
current_category
!=
slot_category
)
&&
IS_BUILTIN_TYPE
(
current_type
))
{
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- multiple possible types for column #%d; unable to choose candidate
\n
"
,
i
);
#endif
return
NULL
;
}
else
if
(
current_type
!=
slot_type
)
{
if
(
IsPreferredType
(
slot_category
,
current_type
))
{
slot_type
=
current_type
;
candidates
=
current_candidate
;
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- column #%d found preferred candidate type %s
\n
"
,
i
,
typeidTypeName
(
slot_type
));
#endif
}
else
{
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- column #%d found possible candidate type %s
\n
"
,
i
,
typeidTypeName
(
current_type
));
#endif
}
}
}
if
(
slot_type
!=
InvalidOid
)
{
input_typeids
[
i
]
=
slot_type
;
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- assign column #%d slot type %s
\n
"
,
i
,
typeidTypeName
(
input_typeids
[
i
]));
#endif
}
}
else
{
#ifdef PARSEDEBUG
printf
(
"func_select_candidate- column #%d input type is %s
\n
"
,
i
,
typeidTypeName
(
input_typeids
[
i
]));
#endif
}
}
ncandidates
=
0
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
ncandidates
++
;
}
}
if
(
ncandidates
==
1
)
return
(
candidates
->
args
);
return
(
NULL
);
return
(
NULL
);
}
}
/* func_select_candidate() */
Oid
*
oper_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
candidates
);
#if FALSE
/* oper_select_candidate()
*/
Oid
*
oper_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
candidates
)
{
CandidateList
current_candidate
;
Oid
*
current_typeids
;
int
unknownOids
,
textOids
;
int
i
;
int
ncandidates
;
int
nbestMatch
;
Oid
bestTypeId
;
unknownOids
=
TRUE
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
unknownOids
&=
(
input_typeids
[
i
]
==
UNKNOWNOID
);
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: argument #%d type is %s
\n
"
,
i
,
typeidTypeName
(
input_typeids
[
i
]));
#endif
}
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
if
(
unknownOids
)
{
textOids
=
TRUE
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
textOids
&=
(
current_typeids
[
i
]
==
TEXTOID
);
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: candidate argument #%d type is %s
\n
"
,
i
,
typeidTypeName
(
current_typeids
[
i
]));
#endif
}
if
(
textOids
)
return
(
current_candidate
->
args
);
}
}
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: no all-text operators found
\n
"
);
#endif
/* OK, there are multiple types here; let's see if we can choose... */
nbestMatch
=
0
;
bestTypeId
=
InvalidOid
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
if
(
IS_HIGHEST_TYPE
(
input_typeids
[
0
])
&&
(
input_typeids
[
0
]
==
current_typeids
[
0
])
&&
IS_HIGHEST_TYPE
(
current_typeids
[
1
])
&&
can_coerce_type
(
1
,
&
input_typeids
[
1
],
&
current_typeids
[
1
]))
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: (1) choose (%s,%s) -> (%s,%s)...
\n
"
,
typeidTypeName
(
input_typeids
[
0
]),
typeidTypeName
(
input_typeids
[
1
]),
typeidTypeName
(
current_typeids
[
0
]),
typeidTypeName
(
current_typeids
[
1
]));
#endif
return
(
current_candidate
->
args
);
}
else
if
(
IS_HIGHEST_TYPE
(
input_typeids
[
1
])
&&
(
input_typeids
[
1
]
==
current_typeids
[
1
])
&&
IS_HIGHEST_TYPE
(
current_typeids
[
0
])
&&
can_coerce_type
(
1
,
&
input_typeids
[
0
],
&
current_typeids
[
0
]))
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: (2) choose (%s,%s) -> (%s,%s)...
\n
"
,
typeidTypeName
(
input_typeids
[
0
]),
typeidTypeName
(
input_typeids
[
1
]),
typeidTypeName
(
current_typeids
[
0
]),
typeidTypeName
(
current_typeids
[
1
]));
#endif
return
(
current_candidate
->
args
);
}
else
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: (3) skip (%s,%s) -> (%s,%s)...
\n
"
,
typeidTypeName
(
input_typeids
[
0
]),
typeidTypeName
(
input_typeids
[
1
]),
typeidTypeName
(
current_typeids
[
0
]),
typeidTypeName
(
current_typeids
[
1
]));
#endif
}
}
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
if
((
input_typeids
[
0
]
==
current_typeids
[
0
])
&&
can_coerce_type
(
1
,
&
input_typeids
[
1
],
&
current_typeids
[
1
]))
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: (4) choose (%s,%s) -> (%s,%s)...
\n
"
,
typeidTypeName
(
input_typeids
[
0
]),
typeidTypeName
(
input_typeids
[
1
]),
typeidTypeName
(
current_typeids
[
0
]),
typeidTypeName
(
current_typeids
[
1
]));
#endif
return
(
current_candidate
->
args
);
}
else
if
((
input_typeids
[
1
]
==
current_typeids
[
1
])
&&
can_coerce_type
(
1
,
&
input_typeids
[
0
],
&
current_typeids
[
0
]))
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: (5) choose (%s,%s) -> (%s,%s)...
\n
"
,
typeidTypeName
(
input_typeids
[
0
]),
typeidTypeName
(
input_typeids
[
1
]),
typeidTypeName
(
current_typeids
[
0
]),
typeidTypeName
(
current_typeids
[
1
]));
#endif
return
(
current_candidate
->
args
);
}
else
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate: (3) skip (%s,%s) -> (%s,%s)...
\n
"
,
typeidTypeName
(
input_typeids
[
0
]),
typeidTypeName
(
input_typeids
[
1
]),
typeidTypeName
(
current_typeids
[
0
]),
typeidTypeName
(
current_typeids
[
1
]));
#endif
}
}
return
(
NULL
);
#if FALSE
return
(
candidates
->
args
);
#endif
}
/* oper_select_candidate() */
#endif
/* oper_select_candidate()
* Given the input argtype array and more than one candidate
* for the function argtype array, attempt to resolve the conflict.
* returns the selected argtype array if the conflict can be resolved,
* otherwise returns NULL.
*
* If all input Oids are UNKNOWNOID, then try matching with TEXTOID.
* Otherwise, could return first function arguments on list of candidates.
* But for now, return NULL and make the user give a better hint.
* - thomas 1998-03-17
*/
Oid
*
oper_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
candidates
)
{
CandidateList
current_candidate
;
CandidateList
last_candidate
;
Oid
*
current_typeids
;
int
unknownOids
;
int
i
;
int
ncandidates
;
int
nbestMatch
,
nmatch
;
CATEGORY
slot_category
,
current_category
;
Oid
slot_type
,
current_type
;
/*
* Run through all candidates and keep those with the most matches
* on explicit types. Keep all candidates if none match.
*/
ncandidates
=
0
;
nbestMatch
=
0
;
last_candidate
=
NULL
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
nmatch
=
0
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
if
((
input_typeids
[
i
]
!=
UNKNOWNOID
)
&&
(
current_typeids
[
i
]
==
input_typeids
[
i
]))
{
nmatch
++
;
}
}
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- candidate has %d matches
\n
"
,
nmatch
);
#endif
if
((
nmatch
>
nbestMatch
)
||
(
last_candidate
==
NULL
))
{
nbestMatch
=
nmatch
;
candidates
=
current_candidate
;
last_candidate
=
current_candidate
;
ncandidates
=
1
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- choose candidate as best match
\n
"
);
#endif
}
else
if
(
nmatch
==
nbestMatch
)
{
last_candidate
->
next
=
current_candidate
;
last_candidate
=
current_candidate
;
ncandidates
++
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- choose candidate as possible match
\n
"
);
#endif
}
else
{
last_candidate
->
next
=
NULL
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- reject candidate as possible match
\n
"
);
#endif
}
}
if
(
ncandidates
<=
1
)
return
((
ncandidates
==
1
)
?
candidates
->
args
:
NULL
);
/*
* Now look for candidates which allow coersion and are preferred types.
* Keep all candidates if none match.
*/
ncandidates
=
0
;
nbestMatch
=
0
;
last_candidate
=
NULL
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
nmatch
=
0
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
current_category
=
TypeCategory
(
current_typeids
[
i
]);
if
(
input_typeids
[
i
]
!=
UNKNOWNOID
)
{
if
(
current_typeids
[
i
]
==
input_typeids
[
i
])
{
nmatch
++
;
}
else
if
(
IsPreferredType
(
current_category
,
current_typeids
[
i
])
&&
can_coerce_type
(
1
,
&
input_typeids
[
i
],
&
current_typeids
[
i
]))
{
nmatch
++
;
}
}
}
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- candidate has %d matches
\n
"
,
nmatch
);
#endif
if
((
nmatch
>
nbestMatch
)
||
(
last_candidate
==
NULL
))
{
nbestMatch
=
nmatch
;
candidates
=
current_candidate
;
last_candidate
=
current_candidate
;
ncandidates
=
1
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- choose candidate as best match
\n
"
);
#endif
}
else
if
(
nmatch
==
nbestMatch
)
{
last_candidate
->
next
=
current_candidate
;
last_candidate
=
current_candidate
;
ncandidates
++
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- choose candidate as possible match
\n
"
);
#endif
}
else
{
last_candidate
->
next
=
NULL
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- reject candidate as possible match
\n
"
);
#endif
}
}
if
(
ncandidates
<=
1
)
return
((
ncandidates
==
1
)
?
candidates
->
args
:
NULL
);
/*
* Still too many candidates?
* Try assigning types for the unknown columns.
*/
if
(
ncandidates
>
1
)
{
unknownOids
=
FALSE
;
current_type
=
UNKNOWNOID
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
if
(
input_typeids
[
i
]
!=
UNKNOWNOID
)
{
current_type
=
input_typeids
[
i
];
}
else
{
unknownOids
=
TRUE
;
}
}
if
(
unknownOids
&&
(
current_type
!=
UNKNOWNOID
))
{
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
nmatch
=
0
;
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
current_typeids
=
current_candidate
->
args
;
if
((
current_type
==
current_typeids
[
i
])
||
IS_BINARY_COMPATIBLE
(
current_type
,
current_typeids
[
i
]))
nmatch
++
;
}
if
(
nmatch
==
nargs
)
return
(
candidates
->
args
);
}
}
for
(
i
=
0
;
i
<
nargs
;
i
++
)
{
if
(
input_typeids
[
i
]
==
UNKNOWNOID
)
{
slot_category
=
INVALID_TYPE
;
slot_type
=
InvalidOid
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
current_typeids
=
current_candidate
->
args
;
current_type
=
current_typeids
[
i
];
current_category
=
TypeCategory
(
current_typeids
[
i
]);
if
(
slot_category
==
InvalidOid
)
{
slot_category
=
current_category
;
slot_type
=
current_type
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- assign column #%d first candidate slot type %s
\n
"
,
i
,
typeidTypeName
(
current_type
));
#endif
}
else
if
(
current_category
!=
slot_category
)
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- multiple possible types for column #%d; unable to choose candidate
\n
"
,
i
);
#endif
return
NULL
;
}
else
if
(
current_type
!=
slot_type
)
{
if
(
IsPreferredType
(
slot_category
,
current_type
))
{
slot_type
=
current_type
;
candidates
=
current_candidate
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- column #%d found preferred candidate type %s
\n
"
,
i
,
typeidTypeName
(
slot_type
));
#endif
}
else
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- column #%d found possible candidate type %s
\n
"
,
i
,
typeidTypeName
(
current_type
));
#endif
}
}
}
if
(
slot_type
!=
InvalidOid
)
{
input_typeids
[
i
]
=
slot_type
;
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- assign column #%d slot type %s
\n
"
,
i
,
typeidTypeName
(
input_typeids
[
i
]));
#endif
}
}
else
{
#ifdef PARSEDEBUG
printf
(
"oper_select_candidate- column #%d input type is %s
\n
"
,
i
,
typeidTypeName
(
input_typeids
[
i
]));
#endif
}
}
ncandidates
=
0
;
for
(
current_candidate
=
candidates
;
current_candidate
!=
NULL
;
current_candidate
=
current_candidate
->
next
)
{
ncandidates
++
;
}
}
if
(
ncandidates
==
1
)
return
(
candidates
->
args
);
return
(
NULL
);
}
/* oper_select_candidate() */
/* func_get_detail()
* Find the named function in the system catalogs.
*
* Attempt to find the named function in the system catalogs with
* arguments exactly as specified, so that the normal case
* (exact match) is as quick as possible.
*
* If an exact match isn't found:
* 1) get a vector of all possible input arg type arrays constructed
* from the superclasses of the original input arg types
* 2) get a list of all possible argument type arrays to the function
* with given name and number of arguments
* 3) for each input arg type array from vector #1:
* a) find how many of the function arg type arrays from list #2
* it can be coerced to
* b) if the answer is one, we have our function
* c) if the answer is more than one, attempt to resolve the conflict
* d) if the answer is zero, try the next array from vector #1
*/
static
bool
static
bool
func_get_detail
(
char
*
funcname
,
func_get_detail
(
char
*
funcname
,
int
nargs
,
int
nargs
,
...
@@ -672,11 +1259,7 @@ func_get_detail(char *funcname,
...
@@ -672,11 +1259,7 @@ func_get_detail(char *funcname,
HeapTuple
ftup
;
HeapTuple
ftup
;
Form_pg_proc
pform
;
Form_pg_proc
pform
;
/*
/* attempt to find with arguments exactly as specified... */
* attempt to find named function in the system catalogs with
* arguments exactly as specified - so that the normal case is just as
* quick as before
*/
ftup
=
SearchSysCacheTuple
(
PRONAME
,
ftup
=
SearchSysCacheTuple
(
PRONAME
,
PointerGetDatum
(
funcname
),
PointerGetDatum
(
funcname
),
Int32GetDatum
(
nargs
),
Int32GetDatum
(
nargs
),
...
@@ -684,24 +1267,15 @@ func_get_detail(char *funcname,
...
@@ -684,24 +1267,15 @@ func_get_detail(char *funcname,
0
);
0
);
*
true_typeids
=
oid_array
;
*
true_typeids
=
oid_array
;
/*
/* didn't find an exact match, so now try to match up candidates... */
* If an exact match isn't found : 1) get a vector of all possible
* input arg type arrays constructed from the superclasses of the
* original input arg types 2) get a list of all possible argument
* type arrays to the function with given name and number of arguments
* 3) for each input arg type array from vector #1 : a) find how many
* of the function arg type arrays from list #2 it can be coerced to
* b) - if the answer is one, we have our function - if the answer is
* more than one, attempt to resolve the conflict - if the answer is
* zero, try the next array from vector #1
*/
if
(
!
HeapTupleIsValid
(
ftup
))
if
(
!
HeapTupleIsValid
(
ftup
))
{
{
function_typeids
=
func_get_candidates
(
funcname
,
nargs
);
function_typeids
=
func_get_candidates
(
funcname
,
nargs
);
/* found something, so let's look through them... */
if
(
function_typeids
!=
NULL
)
if
(
function_typeids
!=
NULL
)
{
{
int
ncandidates
=
0
;
int
ncandidates
;
input_typeid_vector
=
argtype_inherit
(
nargs
,
oid_array
);
input_typeid_vector
=
argtype_inherit
(
nargs
,
oid_array
);
current_input_typeids
=
oid_array
;
current_input_typeids
=
oid_array
;
...
@@ -711,6 +1285,8 @@ func_get_detail(char *funcname,
...
@@ -711,6 +1285,8 @@ func_get_detail(char *funcname,
ncandidates
=
match_argtypes
(
nargs
,
current_input_typeids
,
ncandidates
=
match_argtypes
(
nargs
,
current_input_typeids
,
function_typeids
,
function_typeids
,
&
current_function_typeids
);
&
current_function_typeids
);
/* one match only? then run with it... */
if
(
ncandidates
==
1
)
if
(
ncandidates
==
1
)
{
{
*
true_typeids
=
current_function_typeids
->
args
;
*
true_typeids
=
current_function_typeids
->
args
;
...
@@ -721,20 +1297,23 @@ func_get_detail(char *funcname,
...
@@ -721,20 +1297,23 @@ func_get_detail(char *funcname,
0
);
0
);
Assert
(
HeapTupleIsValid
(
ftup
));
Assert
(
HeapTupleIsValid
(
ftup
));
}
}
/* multiple candidates? then better decide or throw an error... */
else
if
(
ncandidates
>
1
)
else
if
(
ncandidates
>
1
)
{
{
*
true_typeids
=
*
true_typeids
=
func_select_candidate
(
nargs
,
func_select_candidate
(
nargs
,
current_input_typeids
,
current_input_typeids
,
current_function_typeids
);
current_function_typeids
);
/* couldn't decide, so quit */
if
(
*
true_typeids
==
NULL
)
if
(
*
true_typeids
==
NULL
)
{
{
elog
(
NOTICE
,
"there is more than one function named
\"
%s
\"
"
,
func_error
(
NULL
,
funcname
,
nargs
,
oid_array
,
funcname
);
"There is more than one function that satisfies the given argument types"
elog
(
NOTICE
,
"that satisfies the given argument types. you will have to"
);
"
\n\t
You will have to retype your query using explicit typecasts"
);
elog
(
NOTICE
,
"retype your query using explicit typecasts."
);
func_error
(
NULL
,
funcname
,
nargs
,
oid_array
);
}
}
/* found something, so use the first one... */
else
else
{
{
ftup
=
SearchSysCacheTuple
(
PRONAME
,
ftup
=
SearchSysCacheTuple
(
PRONAME
,
...
@@ -752,6 +1331,22 @@ func_get_detail(char *funcname,
...
@@ -752,6 +1331,22 @@ func_get_detail(char *funcname,
}
}
}
}
#if FALSE
/* Last-ditch attempt
* See if this is a single argument function with the function name
* also a type name and the input argument and type name binary compatible...
*/
if
(
!
HeapTupleIsValid
(
ftup
)
&&
(
nargs
==
1
))
{
Type
ttup
;
if
((
HeapTupleIsValid
(
ttup
=
SearchSysCacheTuple
(
TYPNAME
,
PointerGetDatum
(
funcname
),
0
,
0
,
0
)))
&&
IS_BINARY_COMPATIBLE
(
typeTypeId
(
ttup
),
oid_array
[
0
]))
{
}
}
#endif
if
(
!
HeapTupleIsValid
(
ftup
))
if
(
!
HeapTupleIsValid
(
ftup
))
{
{
Type
tp
;
Type
tp
;
...
@@ -760,10 +1355,11 @@ func_get_detail(char *funcname,
...
@@ -760,10 +1355,11 @@ func_get_detail(char *funcname,
{
{
tp
=
typeidType
(
oid_array
[
0
]);
tp
=
typeidType
(
oid_array
[
0
]);
if
(
typeTypeFlag
(
tp
)
==
'c'
)
if
(
typeTypeFlag
(
tp
)
==
'c'
)
elog
(
ERROR
,
"no such attribute or function
\"
%s
\"
"
,
elog
(
ERROR
,
"no such attribute or function '%s'"
,
funcname
);
funcname
);
}
}
func_error
(
NULL
,
funcname
,
nargs
,
oid_array
);
#if FALSE
func_error
(
NULL
,
funcname
,
nargs
,
oid_array
,
NULL
);
#endif
}
}
else
else
{
{
...
@@ -774,10 +1370,10 @@ func_get_detail(char *funcname,
...
@@ -774,10 +1370,10 @@ func_get_detail(char *funcname,
return
(
true
);
return
(
true
);
}
}
/* shouldn't reach here */
return
(
false
);
}
/* shouldn't reach here */
return
(
false
);
}
/* func_get_detail() */
/*
/*
* argtype_inherit() -- Construct an argtype vector reflecting the
* argtype_inherit() -- Construct an argtype vector reflecting the
...
@@ -1012,26 +1608,27 @@ gen_cross_product(InhPaths *arginh, int nargs)
...
@@ -1012,26 +1608,27 @@ gen_cross_product(InhPaths *arginh, int nargs)
}
}
/*
/* make_arguments()
** make_arguments --
* Given the number and types of arguments to a function, and the
** Given the number and types of arguments to a function, and the
* actual arguments and argument types, do the necessary typecasting.
** actual arguments and argument types, do the necessary typecasting.
*
* There are two ways an input typeid can differ from a function typeid:
* 1) the input type inherits the function type, so no typecasting required
* 2) the input type can be typecast into the function type
* Right now, we only typecast unknowns, and that is all we check for.
*
* func_get_detail() now can find coersions for function arguments which
* will make this function executable. So, we need to recover these
* results here too.
* - thomas 1998-03-25
*/
*/
static
void
static
void
make_arguments
(
int
nargs
,
make_arguments
(
ParseState
*
pstate
,
int
nargs
,
List
*
fargs
,
List
*
fargs
,
Oid
*
input_typeids
,
Oid
*
input_typeids
,
Oid
*
function_typeids
)
Oid
*
function_typeids
)
{
{
/*
* there are two ways an input typeid can differ from a function
* typeid : either the input type inherits the function type, so no
* typecasting is necessary, or the input type can be typecast into
* the function type. right now, we only typecast unknowns, and that
* is all we check for.
*/
List
*
current_fargs
;
List
*
current_fargs
;
int
i
;
int
i
;
...
@@ -1039,7 +1636,7 @@ make_arguments(int nargs,
...
@@ -1039,7 +1636,7 @@ make_arguments(int nargs,
i
<
nargs
;
i
<
nargs
;
i
++
,
current_fargs
=
lnext
(
current_fargs
))
i
++
,
current_fargs
=
lnext
(
current_fargs
))
{
{
/* unspecified type for string constant? then use heuristics for conversion... */
if
(
input_typeids
[
i
]
==
UNKNOWNOID
&&
function_typeids
[
i
]
!=
InvalidOid
)
if
(
input_typeids
[
i
]
==
UNKNOWNOID
&&
function_typeids
[
i
]
!=
InvalidOid
)
{
{
lfirst
(
current_fargs
)
=
lfirst
(
current_fargs
)
=
...
@@ -1048,6 +1645,15 @@ make_arguments(int nargs,
...
@@ -1048,6 +1645,15 @@ make_arguments(int nargs,
typeidType
(
function_typeids
[
i
]),
typeidType
(
function_typeids
[
i
]),
-
1
);
-
1
);
}
}
/* types don't match? then force coersion using a function call... */
else
if
(
input_typeids
[
i
]
!=
function_typeids
[
i
])
{
lfirst
(
current_fargs
)
=
coerce_type
(
pstate
,
lfirst
(
current_fargs
),
input_typeids
[
i
],
function_typeids
[
i
]);
}
}
}
}
}
...
@@ -1070,7 +1676,8 @@ setup_tlist(char *attname, Oid relid)
...
@@ -1070,7 +1676,8 @@ setup_tlist(char *attname, Oid relid)
attno
=
get_attnum
(
relid
,
attname
);
attno
=
get_attnum
(
relid
,
attname
);
if
(
attno
<
0
)
if
(
attno
<
0
)
elog
(
ERROR
,
"cannot reference attribute '%s' of tuple params/return values for functions"
,
attname
);
elog
(
ERROR
,
"cannot reference attribute '%s'"
" of tuple params/return values for functions"
,
attname
);
typeid
=
get_atttype
(
relid
,
attno
);
typeid
=
get_atttype
(
relid
,
attno
);
type_mod
=
get_atttypmod
(
relid
,
attno
);
type_mod
=
get_atttypmod
(
relid
,
attno
);
...
@@ -1173,8 +1780,7 @@ ParseComplexProjection(ParseState *pstate,
...
@@ -1173,8 +1780,7 @@ ParseComplexProjection(ParseState *pstate,
}
}
else
else
{
{
elog
(
ERROR
,
elog
(
ERROR
,
"Function '%s' has bad returntype %d"
,
"Function '%s' has bad returntype %d"
,
funcname
,
argtype
);
funcname
,
argtype
);
}
}
}
}
...
@@ -1285,7 +1891,7 @@ ParseComplexProjection(ParseState *pstate,
...
@@ -1285,7 +1891,7 @@ ParseComplexProjection(ParseState *pstate,
* argument types
* argument types
*/
*/
void
void
func_error
(
char
*
caller
,
char
*
funcname
,
int
nargs
,
Oid
*
argtypes
)
func_error
(
char
*
caller
,
char
*
funcname
,
int
nargs
,
Oid
*
argtypes
,
char
*
msg
)
{
{
char
p
[(
NAMEDATALEN
+
2
)
*
MAXFMGRARGS
],
char
p
[(
NAMEDATALEN
+
2
)
*
MAXFMGRARGS
],
*
ptr
;
*
ptr
;
...
@@ -1312,10 +1918,12 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
...
@@ -1312,10 +1918,12 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
if
(
caller
==
NULL
)
if
(
caller
==
NULL
)
{
{
elog
(
ERROR
,
"function %s(%s) does not exist"
,
funcname
,
p
);
elog
(
ERROR
,
"function '%s(%s)' does not exist%s%s"
,
funcname
,
p
,
((
msg
!=
NULL
)
?
"
\n\t
"
:
""
),
((
msg
!=
NULL
)
?
msg
:
""
));
}
}
else
else
{
{
elog
(
ERROR
,
"%s: function %s(%s) does not exist"
,
caller
,
funcname
,
p
);
elog
(
ERROR
,
"%s: function '%s(%s)' does not exist%s%s"
,
caller
,
funcname
,
p
,
((
msg
!=
NULL
)
?
"
\n\t
"
:
""
),
((
msg
!=
NULL
)
?
msg
:
""
));
}
}
}
}
src/backend/parser/parse_node.c
View file @
3ace5fd0
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* 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,
...
@@ -39,7 +39,7 @@ make_operand(char *opname,
/*
/*
* make_parsestate() --
* make_parsestate() --
* allocate and initialize a new ParseState.
* allocate and initialize a new ParseState.
* the 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)
...
@@ -57,6 +57,15 @@ make_parsestate(ParseState *parentParseState)
return
(
pstate
);
return
(
pstate
);
}
}
extern
Node
*
coerce_type
(
ParseState
*
pstate
,
Node
*
node
,
Oid
inputTypeId
,
Oid
targetTypeId
);
/* make_operand()
* Ensure argument type match by forcing conversion of constants.
*/
static
Node
*
static
Node
*
make_operand
(
char
*
opname
,
make_operand
(
char
*
opname
,
Node
*
tree
,
Node
*
tree
,
...
@@ -65,35 +74,33 @@ make_operand(char *opname,
...
@@ -65,35 +74,33 @@ make_operand(char *opname,
{
{
Node
*
result
;
Node
*
result
;
Type
true_type
;
Type
true_type
;
#if FALSE
Datum
val
;
Datum
val
;
Oid
infunc
;
Oid
infunc
;
#endif
#ifdef PARSEDEBUG
printf
(
"make_operand: constructing operand for '%s' %s->%s
\n
"
,
opname
,
typeidTypeName
(
orig_typeId
),
typeidTypeName
(
true_typeId
));
#endif
if
(
tree
!=
NULL
)
if
(
tree
!=
NULL
)
{
{
result
=
tree
;
result
=
tree
;
true_type
=
typeidType
(
true_typeId
);
true_type
=
typeidType
(
true_typeId
);
disallow_setop
(
opname
,
true_type
,
result
);
disallow_setop
(
opname
,
true_type
,
result
);
/* must coerce? */
if
(
true_typeId
!=
orig_typeId
)
if
(
true_typeId
!=
orig_typeId
)
{
/* must coerce */
{
Const
*
con
=
(
Const
*
)
result
;
#ifdef PARSEDEBUG
printf
(
"make_operand: try to convert node from %s to %s
\n
"
,
Assert
(
nodeTag
(
result
)
==
T_Const
);
typeidTypeName
(
orig_typeId
),
typeidTypeName
(
true_typeId
));
val
=
(
Datum
)
textout
((
struct
varlena
*
)
#endif
con
->
constvalue
);
result
=
coerce_type
(
NULL
,
tree
,
orig_typeId
,
true_typeId
);
infunc
=
typeidInfunc
(
true_typeId
);
con
=
makeNode
(
Const
);
con
->
consttype
=
true_typeId
;
con
->
constlen
=
typeLen
(
true_type
);
con
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
val
,
typeidTypElem
(
true_typeId
),
-
1
/* for varchar() type */
);
con
->
constisnull
=
false
;
con
->
constbyval
=
true
;
con
->
constisset
=
false
;
result
=
(
Node
*
)
con
;
}
}
}
}
/* otherwise, this is a NULL value */
else
else
{
{
Const
*
con
=
makeNode
(
Const
);
Const
*
con
=
makeNode
(
Const
);
...
@@ -108,7 +115,7 @@ make_operand(char *opname,
...
@@ -108,7 +115,7 @@ make_operand(char *opname,
}
}
return
result
;
return
result
;
}
}
/* make_operand() */
static
void
static
void
...
@@ -119,13 +126,49 @@ disallow_setop(char *op, Type optype, Node *operand)
...
@@ -119,13 +126,49 @@ disallow_setop(char *op, Type optype, Node *operand)
if
(
nodeTag
(
operand
)
==
T_Iter
)
if
(
nodeTag
(
operand
)
==
T_Iter
)
{
{
elog
(
NOTICE
,
"An operand to the '%s' operator returns a set of %s,"
,
elog
(
ERROR
,
"An operand to the '%s' operator returns a set of %s,"
op
,
typeTypeName
(
optype
));
"
\n\t
but '%s' takes single values, not sets."
,
elog
(
ERROR
,
"but '%s' takes single values, not sets."
,
op
,
typeTypeName
(
optype
),
op
);
op
);
}
}
}
}
/* CoerceType()
* Try to force type of node.
*/
Oid
CoerceType
(
Oid
typeId
,
Node
*
node
);
Oid
CoerceType
(
Oid
typeId
,
Node
*
node
)
{
switch
(
nodeTag
(
node
))
{
case
T_Const
:
{
Const
*
con
=
(
Const
*
)
node
;
#ifdef PARSEDEBUG
printf
(
"Convert node %d to text
\n
"
,
nodeTag
(
node
));
#endif
typeId
=
TEXTOID
;
con
->
consttype
=
typeId
;
}
break
;
default:
break
;
}
return
typeId
;
}
/* CoerceType() */
/* make_op()
* Operator construction.
*
* Transform operator expression ensuring type compatibility.
* This is where some type conversion happens.
*/
Expr
*
Expr
*
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
)
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
)
{
{
...
@@ -138,10 +181,9 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -138,10 +181,9 @@ make_op(char *opname, Node *ltree, Node *rtree)
*
right
;
*
right
;
Expr
*
result
;
Expr
*
result
;
/* right operator? */
if
(
rtree
==
NULL
)
if
(
rtree
==
NULL
)
{
{
/* right operator */
ltypeId
=
(
ltree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
ltree
);
ltypeId
=
(
ltree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
ltree
);
temp
=
right_oper
(
opname
,
ltypeId
);
temp
=
right_oper
(
opname
,
ltypeId
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
...
@@ -149,25 +191,29 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -149,25 +191,29 @@ make_op(char *opname, Node *ltree, Node *rtree)
right
=
NULL
;
right
=
NULL
;
}
}
/* left operator? */
else
if
(
ltree
==
NULL
)
else
if
(
ltree
==
NULL
)
{
{
/* left operator */
rtypeId
=
(
rtree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
rtree
);
rtypeId
=
(
rtree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
rtree
);
temp
=
left_oper
(
opname
,
rtypeId
);
temp
=
left_oper
(
opname
,
rtypeId
);
#ifdef PARSEDEBUG
printf
(
"make_op: returned from left_oper() with structure at %p
\n
"
,
(
void
*
)
temp
);
#endif
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
#ifdef PARSEDEBUG
printf
(
"make_op: calling make_operand()
\n
"
);
#endif
right
=
make_operand
(
opname
,
rtree
,
rtypeId
,
opform
->
oprright
);
right
=
make_operand
(
opname
,
rtree
,
rtypeId
,
opform
->
oprright
);
left
=
NULL
;
left
=
NULL
;
}
}
/* otherwise, binary operator */
else
else
{
{
char
*
outstr
;
Oid
infunc
,
outfunc
;
Type
newtype
;
#define CONVERT
A
BLE_TYPE(t) ( (t) == INT2OID || \
#define CONVERT
I
BLE_TYPE(t) ( (t) == INT2OID || \
(t) == INT4OID || \
(t) == INT4OID || \
(t) == OIDOID || \
(t) == OIDOID || \
(t) == FLOAT4OID || \
(t) == FLOAT4OID || \
...
@@ -178,12 +224,32 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -178,12 +224,32 @@ make_op(char *opname, Node *ltree, Node *rtree)
ltypeId
=
(
ltree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
ltree
);
ltypeId
=
(
ltree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
ltree
);
rtypeId
=
(
rtree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
rtree
);
rtypeId
=
(
rtree
==
NULL
)
?
UNKNOWNOID
:
exprType
(
rtree
);
#if FALSE
/* Both operands of unknown type?
* Then they are strings and we should force at least one to text
* - thomas 1998-03-16
*/
ltypeId
=
exprType
(
ltree
);
rtypeId
=
exprType
(
rtree
);
if
((
ltypeId
==
UNKNOWNOID
)
&&
(
rtypeId
==
UNKNOWNOID
))
{
#ifdef PARSEDEBUG
printf
(
"Convert left-hand constant to text for node %d
\n
"
,
nodeTag
(
ltree
));
#endif
ltypeId
=
CoerceType
(
TEXTOID
,
ltree
);
}
#endif
#if FALSE
/*
/*
* convert constant when using a const of a numeric type and a
* convert constant when using a const of a numeric type and a
* non-const of another numeric type
* non-const of another numeric type
*/
*/
if
(
CONVERT
A
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
!=
T_Const
&&
if
(
CONVERT
I
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
!=
T_Const
&&
CONVERT
A
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
==
T_Const
&&
CONVERT
I
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
==
T_Const
&&
!
((
Const
*
)
rtree
)
->
constiscast
)
!
((
Const
*
)
rtree
)
->
constiscast
)
{
{
outfunc
=
typeidOutfunc
(
rtypeId
);
outfunc
=
typeidOutfunc
(
rtypeId
);
...
@@ -197,8 +263,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -197,8 +263,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
((
Const
*
)
rtree
)
->
constbyval
=
typeByVal
(
newtype
);
((
Const
*
)
rtree
)
->
constbyval
=
typeByVal
(
newtype
);
}
}
if
(
CONVERT
A
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
!=
T_Const
&&
if
(
CONVERT
I
BLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
!=
T_Const
&&
CONVERT
A
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
==
T_Const
&&
CONVERT
I
BLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
==
T_Const
&&
!
((
Const
*
)
ltree
)
->
constiscast
)
!
((
Const
*
)
ltree
)
->
constiscast
)
{
{
outfunc
=
typeidOutfunc
(
ltypeId
);
outfunc
=
typeidOutfunc
(
ltypeId
);
...
@@ -211,6 +277,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -211,6 +277,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
((
Const
*
)
ltree
)
->
constlen
=
typeLen
(
newtype
);
((
Const
*
)
ltree
)
->
constlen
=
typeLen
(
newtype
);
((
Const
*
)
ltree
)
->
constbyval
=
typeByVal
(
newtype
);
((
Const
*
)
ltree
)
->
constbyval
=
typeByVal
(
newtype
);
}
}
#endif
temp
=
oper
(
opname
,
ltypeId
,
rtypeId
,
false
);
temp
=
oper
(
opname
,
ltypeId
,
rtypeId
,
false
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
opform
=
(
OperatorTupleForm
)
GETSTRUCT
(
temp
);
...
@@ -219,7 +286,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -219,7 +286,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
}
}
newop
=
makeOper
(
oprid
(
temp
),
/* opno */
newop
=
makeOper
(
oprid
(
temp
),
/* opno */
InvalidOid
,
/* opid */
InvalidOid
,
/* opid */
opform
->
oprresult
,
/* operator result type */
opform
->
oprresult
,
/* operator result type */
0
,
0
,
NULL
);
NULL
);
...
@@ -239,6 +306,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -239,6 +306,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
return
result
;
return
result
;
}
}
Var
*
Var
*
make_var
(
ParseState
*
pstate
,
Oid
relid
,
char
*
refname
,
make_var
(
ParseState
*
pstate
,
Oid
relid
,
char
*
refname
,
char
*
attrname
)
char
*
attrname
)
...
@@ -356,6 +424,9 @@ make_array_ref(Node *expr,
...
@@ -356,6 +424,9 @@ make_array_ref(Node *expr,
return
aref
;
return
aref
;
}
}
/* make_array_set()
*/
ArrayRef
*
ArrayRef
*
make_array_set
(
Expr
*
target_expr
,
make_array_set
(
Expr
*
target_expr
,
List
*
upperIndexpr
,
List
*
upperIndexpr
,
...
@@ -406,10 +477,12 @@ make_array_set(Expr *target_expr,
...
@@ -406,10 +477,12 @@ make_array_set(Expr *target_expr,
aref
->
refexpr
=
(
Node
*
)
target_expr
;
aref
->
refexpr
=
(
Node
*
)
target_expr
;
aref
->
refassgnexpr
=
(
Node
*
)
expr
;
aref
->
refassgnexpr
=
(
Node
*
)
expr
;
if
(
lowerIndexpr
==
NIL
)
/* accessing a single array element */
/* accessing a single array element? */
if
(
lowerIndexpr
==
NIL
)
reftype
=
aref
->
refelemtype
;
reftype
=
aref
->
refelemtype
;
/* otherwise, request to set a part of the array, by another array */
else
else
/* request to set a part of the array, by another array */
reftype
=
typearray
;
reftype
=
typearray
;
aref
->
refelemtype
=
reftype
;
aref
->
refelemtype
=
reftype
;
...
...
src/backend/parser/parse_oper.c
View file @
3ace5fd0
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* 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 @@
...
@@ -23,9 +23,18 @@
#include "fmgr.h"
#include "fmgr.h"
#include "parser/parse_oper.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "parser/parse_type.h"
#include "parser/parse_coerce.h"
#include "storage/bufmgr.h"
#include "storage/bufmgr.h"
#include "utils/syscache.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
static
int
binary_oper_get_candidates
(
char
*
opname
,
binary_oper_get_candidates
(
char
*
opname
,
Oid
leftTypeId
,
Oid
leftTypeId
,
...
@@ -63,7 +72,8 @@ oprid(Operator op)
...
@@ -63,7 +72,8 @@ oprid(Operator op)
return
(
op
->
t_oid
);
return
(
op
->
t_oid
);
}
}
/*
/* binary_oper_get_candidates()
* given opname, leftTypeId and rightTypeId,
* given opname, leftTypeId and rightTypeId,
* find all possible (arg1, arg2) pairs for which an operator named
* find all possible (arg1, arg2) pairs for which an operator named
* opname exists, such that leftTypeId can be coerced to arg1 and
* opname exists, such that leftTypeId can be coerced to arg1 and
...
@@ -97,7 +107,145 @@ binary_oper_get_candidates(char *opname,
...
@@ -97,7 +107,145 @@ binary_oper_get_candidates(char *opname,
F_CHAREQ
,
F_CHAREQ
,
CharGetDatum
(
'b'
));
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
(
leftTypeId
==
UNKNOWNOID
)
{
{
if
(
rightTypeId
==
UNKNOWNOID
)
if
(
rightTypeId
==
UNKNOWNOID
)
...
@@ -124,8 +272,12 @@ binary_oper_get_candidates(char *opname,
...
@@ -124,8 +272,12 @@ binary_oper_get_candidates(char *opname,
ObjectIdGetDatum
(
leftTypeId
));
ObjectIdGetDatum
(
leftTypeId
));
}
}
else
else
{
/* currently only "unknown" can be coerced */
/* currently only "unknown" can be coerced */
return
0
;
return
0
;
#endif
nkeys
=
2
;
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
...
@@ -156,7 +308,9 @@ binary_oper_get_candidates(char *opname,
...
@@ -156,7 +308,9 @@ binary_oper_get_candidates(char *opname,
heap_close
(
pg_operator_desc
);
heap_close
(
pg_operator_desc
);
return
ncandidates
;
return
ncandidates
;
}
}
/* BinaryOperCandidates() */
#endif
/*
/*
* equivalentOpersAfterPromotion -
* equivalentOpersAfterPromotion -
...
@@ -164,7 +318,7 @@ binary_oper_get_candidates(char *opname,
...
@@ -164,7 +318,7 @@ binary_oper_get_candidates(char *opname,
* binary_oper_get_candidates() contain equivalent operators. If
* binary_oper_get_candidates() contain equivalent operators. If
* this routine is called, we have more than 1 candidate and need to
* 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
* 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).
* promotion (int2, int4, float4 -> float8).
*/
*/
static
bool
static
bool
...
@@ -237,33 +391,18 @@ equivalentOpersAfterPromotion(CandidateList candidates)
...
@@ -237,33 +391,18 @@ equivalentOpersAfterPromotion(CandidateList candidates)
}
}
/*
/* binary_oper_select_candidate()
* given a choice of argument type pairs for a binary operator,
* Given a choice of argument type pairs for a binary operator,
* try to choose a default pair
* try to choose a default pair.
*/
static
CandidateList
binary_oper_select_candidate
(
Oid
arg1
,
Oid
arg2
,
CandidateList
candidates
)
{
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
* current wisdom holds that the default operator should be one in which
* both operands have the same type (there will only be one such
* both operands have the same type (there will only be one such
* operator)
* operator)
*
*
* 7.27.93 - I have decided not to do this; it's too hard to justify, and
* 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
* it's easy enough to typecast explicitly - avi
* routine were commented out since then -ay]
* [the rest of this routine was commented out since then - ay]
*/
*
if
(
arg1
==
UNKNOWNOID
&&
arg2
==
UNKNOWNOID
)
return
(
NULL
);
/*
* 6/23/95 - I don't complete agree with avi. In particular, casting
* 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
* floats is a pain for users. Whatever the rationale behind not doing
* this is, I need the following special case to work.
* this is, I need the following special case to work.
...
@@ -277,9 +416,22 @@ binary_oper_select_candidate(Oid arg1,
...
@@ -277,9 +416,22 @@ binary_oper_select_candidate(Oid arg1,
* the solution. In addition to requiring the operator operates on the
* the solution. In addition to requiring the operator operates on the
* same type for both operands [as in the code Avi originally
* same type for both operands [as in the code Avi originally
* commented out], we also require that the operators be equivalent in
* commented out], we also require that the operators be equivalent in
* some sense. (see equivalentOpersAfterPromotion for details.) - ay
* some sense. (see equivalentOpersAfterPromotion for details.)
*
6/95
* - ay
6/95
*/
*/
static
CandidateList
binary_oper_select_candidate
(
Oid
arg1
,
Oid
arg2
,
CandidateList
candidates
)
{
CandidateList
result
;
/*
* If both are "unknown", there is no way to select a candidate
*/
if
(
arg1
==
UNKNOWNOID
&&
arg2
==
UNKNOWNOID
)
return
(
NULL
);
if
(
!
equivalentOpersAfterPromotion
(
candidates
))
if
(
!
equivalentOpersAfterPromotion
(
candidates
))
return
NULL
;
return
NULL
;
...
@@ -296,43 +448,48 @@ binary_oper_select_candidate(Oid arg1,
...
@@ -296,43 +448,48 @@ binary_oper_select_candidate(Oid arg1,
return
(
NULL
);
return
(
NULL
);
}
}
/* Given operator, types of arg1, and arg2, return oper struct */
/* oper()
/* arg1, arg2 --typeids */
* Given operator, types of arg1, and arg2, return oper struct.
* Inputs:
* arg1, arg2: Type IDs
*/
Operator
Operator
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
)
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
)
{
{
HeapTuple
tup
;
HeapTuple
tup
;
CandidateList
candidates
;
CandidateList
candidates
;
int
ncandidates
;
int
ncandidates
;
Oid
*
targetOids
;
Oid
inputOids
[
2
];
if
(
!
arg2
)
/* Unspecified type for one of the arguments? then use the other */
if
(
arg2
==
InvalidOid
)
arg2
=
arg1
;
arg2
=
arg1
;
if
(
!
arg1
)
if
(
arg1
==
InvalidOid
)
arg1
=
arg2
;
arg1
=
arg2
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg1
),
ObjectIdGetDatum
(
arg1
),
ObjectIdGetDatum
(
arg2
),
ObjectIdGetDatum
(
arg2
),
Int8GetDatum
(
'b'
))))
Int8GetDatum
(
'b'
));
/* Did not find anything? then look more carefully... */
if
(
!
HeapTupleIsValid
(
tup
))
{
{
ncandidates
=
binary_oper_get_candidates
(
op
,
arg1
,
arg2
,
&
candidates
);
ncandidates
=
binary_oper_get_candidates
(
op
,
arg1
,
arg2
,
&
candidates
);
/* No operators found? Then throw error or return null... */
if
(
ncandidates
==
0
)
if
(
ncandidates
==
0
)
{
{
/*
* no operators of the desired types found
*/
if
(
!
noWarnings
)
if
(
!
noWarnings
)
op_error
(
op
,
arg1
,
arg2
);
op_error
(
op
,
arg1
,
arg2
);
return
(
NULL
);
return
(
NULL
);
}
}
/* Or found exactly one? Then proceed... */
else
if
(
ncandidates
==
1
)
else
if
(
ncandidates
==
1
)
{
{
/*
* exactly one operator of the desired types found
*/
tup
=
SearchSysCacheTuple
(
OPRNAME
,
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
...
@@ -340,46 +497,53 @@ oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
...
@@ -340,46 +497,53 @@ oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
Int8GetDatum
(
'b'
));
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
Assert
(
HeapTupleIsValid
(
tup
));
}
}
/* Otherwise, multiple operators of the desired types found... */
else
else
{
{
#if FALSE
/*
* multiple operators of the desired types found
*/
candidates
=
binary_oper_select_candidate
(
arg1
,
arg2
,
candidates
);
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
,
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
arg
s
[
0
]),
ObjectIdGetDatum
(
targetOid
s
[
0
]),
ObjectIdGetDatum
(
candidates
->
arg
s
[
1
]),
ObjectIdGetDatum
(
targetOid
s
[
1
]),
Int8GetDatum
(
'b'
));
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
}
else
else
{
{
Type
tp1
,
tup
=
NULL
;
tp2
;
}
/* we chose none of them
*/
/* Could not choose one, for whatever reason...
*/
tp1
=
typeidType
(
arg1
);
if
(
!
HeapTupleIsValid
(
tup
))
tp2
=
typeidType
(
arg2
);
{
if
(
!
noWarnings
)
if
(
!
noWarnings
)
{
{
elog
(
NOTICE
,
"there is more than one operator %s for types"
,
op
);
elog
(
ERROR
,
"There is more than one operator '%s' for types '%s' and '%s'"
elog
(
NOTICE
,
"%s and %s. You will have to retype this query"
,
"
\n\t
You will have to retype this query using an explicit cast"
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
op
,
typeTypeName
(
typeidType
(
arg1
)),
typeTypeName
(
typeidType
(
arg2
)));
elog
(
ERROR
,
"using an explicit cast"
);
}
}
return
(
NULL
);
return
(
NULL
);
}
}
}
}
}
}
return
((
Operator
)
tup
);
return
((
Operator
)
tup
);
}
}
/* oper() */
/*
/* unary_oper_get_candidates()
* given opname and typeId, find all possible types for which
* given opname and typeId, find all possible types for which
* a right/left unary operator named opname exists,
* a right/left unary operator named opname exists,
* such that typeId can be coerced to it
* such that typeId can be coerced to it
...
@@ -409,6 +573,7 @@ unary_oper_get_candidates(char *op,
...
@@ -409,6 +573,7 @@ unary_oper_get_candidates(char *op,
fmgr_info
(
F_CHAREQ
,
(
FmgrInfo
*
)
&
opKey
[
1
].
sk_func
);
fmgr_info
(
F_CHAREQ
,
(
FmgrInfo
*
)
&
opKey
[
1
].
sk_func
);
opKey
[
1
].
sk_argument
=
CharGetDatum
(
rightleft
);
opKey
[
1
].
sk_argument
=
CharGetDatum
(
rightleft
);
#if FALSE
/* currently, only "unknown" can be coerced */
/* currently, only "unknown" can be coerced */
/*
/*
...
@@ -419,7 +584,11 @@ unary_oper_get_candidates(char *op,
...
@@ -419,7 +584,11 @@ unary_oper_get_candidates(char *op,
{
{
return
0
;
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_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
0
,
...
@@ -442,6 +611,10 @@ unary_oper_get_candidates(char *op,
...
@@ -442,6 +611,10 @@ unary_oper_get_candidates(char *op,
current_candidate
->
args
[
0
]
=
oper
->
oprright
;
current_candidate
->
args
[
0
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
*
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
++
;
ncandidates
++
;
ReleaseBuffer
(
buffer
);
ReleaseBuffer
(
buffer
);
}
}
...
@@ -450,8 +623,12 @@ unary_oper_get_candidates(char *op,
...
@@ -450,8 +623,12 @@ unary_oper_get_candidates(char *op,
heap_endscan
(
pg_operator_scan
);
heap_endscan
(
pg_operator_scan
);
heap_close
(
pg_operator_desc
);
heap_close
(
pg_operator_desc
);
#ifdef PARSEDEBUG
printf
(
"unary_oper_get_candidates: found %d candidates
\n
"
,
ncandidates
);
#endif
return
ncandidates
;
return
ncandidates
;
}
}
/* unary_oper_get_candidates() */
/* Given unary right-side operator (operator on right), return oper struct */
/* Given unary right-side operator (operator on right), return oper struct */
/* arg-- type id */
/* arg-- type id */
...
@@ -461,21 +638,20 @@ right_oper(char *op, Oid arg)
...
@@ -461,21 +638,20 @@ right_oper(char *op, Oid arg)
HeapTuple
tup
;
HeapTuple
tup
;
CandidateList
candidates
;
CandidateList
candidates
;
int
ncandidates
;
int
ncandidates
;
Oid
*
targetOid
;
/*
tup
=
SearchSysCacheTuple
(
OPRNAME
,
* if (!OpCache) { init_op_cache(); }
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg
),
ObjectIdGetDatum
(
arg
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
))))
Int8GetDatum
(
'r'
));
if
(
!
HeapTupleIsValid
(
tup
))
{
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'r'
);
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'r'
);
if
(
ncandidates
==
0
)
if
(
ncandidates
==
0
)
{
{
elog
(
ERROR
,
elog
(
ERROR
,
"Can't find right op '%s' for type %d"
,
op
,
arg
);
"Can't find right op: %s for type %d"
,
op
,
arg
);
return
(
NULL
);
return
(
NULL
);
}
}
else
if
(
ncandidates
==
1
)
else
if
(
ncandidates
==
1
)
...
@@ -489,14 +665,36 @@ right_oper(char *op, Oid arg)
...
@@ -489,14 +665,36 @@ right_oper(char *op, Oid arg)
}
}
else
else
{
{
elog
(
NOTICE
,
"there is more than one right operator %s"
,
op
);
#if FALSE
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
ERROR
,
"There is more than one right operator %s"
elog
(
ERROR
,
"using an explicit cast"
);
"
\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
(
NULL
);
}
}
}
}
}
return
((
Operator
)
tup
);
return
((
Operator
)
tup
);
}
}
/* right_oper() */
/* Given unary left-side operator (operator on left), return oper struct */
/* Given unary left-side operator (operator on left), return oper struct */
/* arg--type id */
/* arg--type id */
...
@@ -506,21 +704,20 @@ left_oper(char *op, Oid arg)
...
@@ -506,21 +704,20 @@ left_oper(char *op, Oid arg)
HeapTuple
tup
;
HeapTuple
tup
;
CandidateList
candidates
;
CandidateList
candidates
;
int
ncandidates
;
int
ncandidates
;
Oid
*
targetOid
;
/*
tup
=
SearchSysCacheTuple
(
OPRNAME
,
* if (!OpCache) { init_op_cache(); }
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
arg
),
ObjectIdGetDatum
(
arg
),
Int8GetDatum
(
'l'
))))
Int8GetDatum
(
'l'
));
if
(
!
HeapTupleIsValid
(
tup
))
{
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'l'
);
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'l'
);
if
(
ncandidates
==
0
)
if
(
ncandidates
==
0
)
{
{
elog
(
ERROR
,
elog
(
ERROR
,
"Can't find left op '%s' for type %d"
,
op
,
arg
);
"Can't find left op: %s for type %d"
,
op
,
arg
);
return
(
NULL
);
return
(
NULL
);
}
}
else
if
(
ncandidates
==
1
)
else
if
(
ncandidates
==
1
)
...
@@ -531,19 +728,41 @@ left_oper(char *op, Oid arg)
...
@@ -531,19 +728,41 @@ left_oper(char *op, Oid arg)
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
Int8GetDatum
(
'l'
));
Int8GetDatum
(
'l'
));
Assert
(
HeapTupleIsValid
(
tup
));
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
else
{
{
elog
(
NOTICE
,
"there is more than one left operator %s"
,
op
);
#if FALSE
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
ERROR
,
"There is more than one left operator %s"
elog
(
ERROR
,
"using an explicit cast"
);
"
\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
);
return
(
NULL
);
}
}
#ifdef PARSEDEBUG
printf
(
"left_oper: searched cache for best left oper candidate '%s %s'
\n
"
,
op
,
typeidTypeName
(
*
targetOid
));
#endif
}
}
}
return
((
Operator
)
tup
);
return
((
Operator
)
tup
);
}
}
/* left_oper() */
/*
/* op_error()
* Give a somewhat useful error message when the operator for two types
* Give a somewhat useful error message when the operator for two types
* is not found.
* is not found.
*/
*/
...
@@ -559,7 +778,8 @@ op_error(char *op, Oid arg1, Oid arg2)
...
@@ -559,7 +778,8 @@ op_error(char *op, Oid arg1, Oid arg2)
}
}
else
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
))
if
(
typeidIsValid
(
arg2
))
...
@@ -568,17 +788,10 @@ op_error(char *op, Oid arg1, Oid arg2)
...
@@ -568,17 +788,10 @@ op_error(char *op, Oid arg1, Oid arg2)
}
}
else
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'"
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
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"
,
"
\n\t
or you will have to define the operator using CREATE OPERATOR"
,
...
...
src/backend/parser/parse_target.c
View file @
3ace5fd0
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* 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 @@
...
@@ -26,6 +26,13 @@
#include "parser/parse_target.h"
#include "parser/parse_target.h"
#include "utils/builtins.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
extern
bool
can_coerce_type
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
);
extern
Node
*
coerce_type
(
ParseState
*
pstate
,
Node
*
node
,
Oid
inputTypeId
,
Oid
targetTypeId
);
static
List
*
expandAllTables
(
ParseState
*
pstate
);
static
List
*
expandAllTables
(
ParseState
*
pstate
);
static
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
);
static
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
);
...
@@ -34,6 +41,16 @@ make_targetlist_expr(ParseState *pstate,
...
@@ -34,6 +41,16 @@ make_targetlist_expr(ParseState *pstate,
char
*
colname
,
char
*
colname
,
Node
*
expr
,
Node
*
expr
,
List
*
arrayRef
);
List
*
arrayRef
);
Node
*
size_target_expr
(
ParseState
*
pstate
,
Node
*
expr
,
Oid
attrtype
,
int16
attrtypmod
);
Node
*
coerce_target_expr
(
ParseState
*
pstate
,
Node
*
expr
,
Oid
type_id
,
Oid
attrtype
);
/*
/*
* transformTargetList -
* transformTargetList -
...
@@ -110,8 +127,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
...
@@ -110,8 +127,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
Relation
rd
;
Relation
rd
;
Value
*
constval
;
Value
*
constval
;
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
!
IsA
(
expr
,
Const
))
!
IsA
(
expr
,
Const
))
elog
(
ERROR
,
"yyparse: string constant expected"
);
elog
(
ERROR
,
"yyparse: string constant expected"
);
val
=
(
char
*
)
textout
((
struct
varlena
*
)
val
=
(
char
*
)
textout
((
struct
varlena
*
)
...
@@ -123,15 +139,15 @@ transformTargetList(ParseState *pstate, List *targetlist)
...
@@ -123,15 +139,15 @@ transformTargetList(ParseState *pstate, List *targetlist)
aind
->
uidx
=
transformExpr
(
pstate
,
aind
->
uidx
,
EXPR_COLUMN_FIRST
);
aind
->
uidx
=
transformExpr
(
pstate
,
aind
->
uidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
uidx
,
Const
))
if
(
!
IsA
(
aind
->
uidx
,
Const
))
elog
(
ERROR
,
elog
(
ERROR
,
"Array Index for Append should be a constant"
);
"Array Index for Append should be a constant"
);
uindx
[
i
]
=
((
Const
*
)
aind
->
uidx
)
->
constvalue
;
uindx
[
i
]
=
((
Const
*
)
aind
->
uidx
)
->
constvalue
;
if
(
aind
->
lidx
!=
NULL
)
if
(
aind
->
lidx
!=
NULL
)
{
{
aind
->
lidx
=
transformExpr
(
pstate
,
aind
->
lidx
,
EXPR_COLUMN_FIRST
);
aind
->
lidx
=
transformExpr
(
pstate
,
aind
->
lidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
lidx
,
Const
))
if
(
!
IsA
(
aind
->
lidx
,
Const
))
elog
(
ERROR
,
elog
(
ERROR
,
"Array Index for Append should be a constant"
);
"Array Index for Append should be a constant"
);
lindx
[
i
]
=
((
Const
*
)
aind
->
lidx
)
->
constvalue
;
lindx
[
i
]
=
((
Const
*
)
aind
->
lidx
)
->
constvalue
;
}
}
else
else
...
@@ -140,6 +156,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
...
@@ -140,6 +156,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
}
if
(
lindx
[
i
]
>
uindx
[
i
])
if
(
lindx
[
i
]
>
uindx
[
i
])
elog
(
ERROR
,
"yyparse: lower index cannot be greater than upper index"
);
elog
(
ERROR
,
"yyparse: lower index cannot be greater than upper index"
);
sprintf
(
str
,
"[%d:%d]"
,
lindx
[
i
],
uindx
[
i
]);
sprintf
(
str
,
"[%d:%d]"
,
lindx
[
i
],
uindx
[
i
]);
str
+=
strlen
(
str
);
str
+=
strlen
(
str
);
i
++
;
i
++
;
...
@@ -151,6 +168,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
...
@@ -151,6 +168,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
ndims
=
attnumAttNelems
(
rd
,
resdomno
);
ndims
=
attnumAttNelems
(
rd
,
resdomno
);
if
(
i
!=
ndims
)
if
(
i
!=
ndims
)
elog
(
ERROR
,
"yyparse: array dimensions do not match"
);
elog
(
ERROR
,
"yyparse: array dimensions do not match"
);
constval
=
makeNode
(
Value
);
constval
=
makeNode
(
Value
);
constval
->
type
=
T_String
;
constval
->
type
=
T_String
;
constval
->
val
.
str
=
save_str
;
constval
->
val
.
str
=
save_str
;
...
@@ -300,8 +318,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
...
@@ -300,8 +318,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
}
default:
default:
/* internal error */
/* internal error */
elog
(
ERROR
,
elog
(
ERROR
,
"internal error: do not know how to transform targetlist"
);
"internal error: do not know how to transform targetlist"
);
break
;
break
;
}
}
...
@@ -321,11 +338,125 @@ transformTargetList(ParseState *pstate, List *targetlist)
...
@@ -321,11 +338,125 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
}
/*
Node
*
* make_targetlist_expr -
coerce_target_expr
(
ParseState
*
pstate
,
* make a TargetEntry from an expression
Node
*
expr
,
Oid
type_id
,
Oid
attrtype
)
{
if
(
can_coerce_type
(
1
,
&
type_id
,
&
attrtype
))
{
#ifdef PARSEDEBUG
printf
(
"parse_target: coerce type from %s to %s
\n
"
,
typeidTypeName
(
type_id
),
typeidTypeName
(
attrtype
));
#endif
expr
=
coerce_type
(
pstate
,
expr
,
type_id
,
attrtype
);
}
#ifndef DISABLE_STRING_HACKS
/* string hacks to get transparent conversions w/o explicit conversions */
else
if
((
attrtype
==
BPCHAROID
)
||
(
attrtype
==
VARCHAROID
))
{
Oid
text_id
=
TEXTOID
;
#ifdef PARSEDEBUG
printf
(
"parse_target: try coercing from %s to %s via text
\n
"
,
typeidTypeName
(
type_id
),
typeidTypeName
(
attrtype
));
#endif
if
(
type_id
==
TEXTOID
)
{
}
else
if
(
can_coerce_type
(
1
,
&
type_id
,
&
text_id
))
{
expr
=
coerce_type
(
pstate
,
expr
,
type_id
,
text_id
);
}
else
{
expr
=
NULL
;
}
}
#endif
else
{
expr
=
NULL
;
}
return
expr
;
}
/* coerce_target_expr() */
/* size_target_expr()
* Apparently going to a fixed-length string?
* Then explicitly size for storage...
*/
Node
*
size_target_expr
(
ParseState
*
pstate
,
Node
*
expr
,
Oid
attrtype
,
int16
attrtypmod
)
{
int
i
;
HeapTuple
ftup
;
char
*
funcname
;
Oid
oid_array
[
8
];
FuncCall
*
func
;
A_Const
*
cons
;
#ifdef PARSEDEBUG
printf
(
"parse_target: ensure target fits storage
\n
"
);
#endif
funcname
=
typeidTypeName
(
attrtype
);
oid_array
[
0
]
=
attrtype
;
oid_array
[
1
]
=
INT4OID
;
for
(
i
=
2
;
i
<
8
;
i
++
)
oid_array
[
i
]
=
InvalidOid
;
#ifdef PARSEDEBUG
printf
(
"parse_target: look for conversion function %s(%s,%s)
\n
"
,
funcname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
INT4OID
));
#endif
/* attempt to find with arguments exactly as specified... */
ftup
=
SearchSysCacheTuple
(
PRONAME
,
PointerGetDatum
(
funcname
),
Int32GetDatum
(
2
),
PointerGetDatum
(
oid_array
),
0
);
if
(
HeapTupleIsValid
(
ftup
))
{
#ifdef PARSEDEBUG
printf
(
"parse_target: found conversion function for sizing
\n
"
);
#endif
func
=
makeNode
(
FuncCall
);
func
->
funcname
=
funcname
;
cons
=
makeNode
(
A_Const
);
cons
->
val
.
type
=
T_Integer
;
cons
->
val
.
val
.
ival
=
attrtypmod
;
func
->
args
=
lappend
(
lcons
(
expr
,
NIL
),
cons
);
expr
=
transformExpr
(
pstate
,
(
Node
*
)
func
,
EXPR_COLUMN_FIRST
);
}
#ifdef PARSEDEBUG
else
{
printf
(
"parse_target: no conversion function for sizing
\n
"
);
}
#endif
return
expr
;
}
/* size_target_expr() */
/* make_targetlist_expr()
* Make a TargetEntry from an expression
*
*
* arrayRef is a list of transformed A_Indices
* arrayRef is a list of transformed A_Indices
*
* For type mismatches between expressions and targets, use the same
* techniques as for function and operator type coersion.
* - thomas 1998-05-08
*/
*/
static
TargetEntry
*
static
TargetEntry
*
make_targetlist_expr
(
ParseState
*
pstate
,
make_targetlist_expr
(
ParseState
*
pstate
,
...
@@ -355,7 +486,6 @@ make_targetlist_expr(ParseState *pstate,
...
@@ -355,7 +486,6 @@ make_targetlist_expr(ParseState *pstate,
/* Processes target columns that will be receiving results */
/* Processes target columns that will be receiving results */
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
{
{
/*
/*
* insert or update query -- insert, update work only on one
* insert or update query -- insert, update work only on one
* relation, so multiple occurence of same resdomno is bogus
* relation, so multiple occurence of same resdomno is bogus
...
@@ -368,91 +498,47 @@ make_targetlist_expr(ParseState *pstate,
...
@@ -368,91 +498,47 @@ make_targetlist_expr(ParseState *pstate,
if
((
arrayRef
!=
NIL
)
&&
(
lfirst
(
arrayRef
)
==
NIL
))
if
((
arrayRef
!=
NIL
)
&&
(
lfirst
(
arrayRef
)
==
NIL
))
attrtype
=
GetArrayElementType
(
attrtype
);
attrtype
=
GetArrayElementType
(
attrtype
);
attrtypmod
=
rd
->
rd_att
->
attrs
[
resdomno
-
1
]
->
atttypmod
;
attrtypmod
=
rd
->
rd_att
->
attrs
[
resdomno
-
1
]
->
atttypmod
;
#if 0
if (Input_is_string && Typecast_ok)
{
Datum val;
if (type_id == typeTypeId(type("unknown")))
/* Check for InvalidOid since that seems to indicate a NULL constant... */
if
(
type_id
!=
InvalidOid
)
{
{
val = (Datum) textout((struct varlena *)
/* Mismatch on types? then try to coerce to target... */
((Const) lnext(expr))->constvalue);
if
(
attrtype
!=
type_id
)
}
else
{
{
val = ((Const) lnext(expr))->constvalue
;
Oid
typelem
;
}
if (attrisset
)
if
(
arrayRef
&&
!
(((
A_Indices
*
)
lfirst
(
arrayRef
))
->
lidx
)
)
{
{
lnext(expr) = makeConst(attrtype,
typelem
=
typeidTypElem
(
attrtype
);
attrlen,
val,
false,
true,
true, /* is set */
false);
}
}
else
else
{
{
lnext(expr) =
typelem
=
attrtype
;
makeConst(attrtype,
attrlen,
(Datum) fmgr(typeidInfunc(attrtype),
val, typeidTypElem(attrtype), -1),
false,
true /* Maybe correct-- 80% chance */ ,
false, /* is not a set */
false);
}
}
}
else if ((Typecast_ok) && (attrtype != type_id))
expr
=
coerce_target_expr
(
pstate
,
expr
,
type_id
,
typelem
);
if
(
!
HeapTupleIsValid
(
expr
))
{
{
lnext(expr) =
elog
(
ERROR
,
"parser: attribute '%s' is of type '%s'"
parser_typecast2(expr, typeidType(attrtype));
" but expression is of type '%s'"
"
\n\t
You will need to rewrite or cast the expression"
,
colname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
type_id
));
}
}
else if (attrtype != type_id)
{
if ((attrtype == INT2OID) && (type_id == INT4OID))
lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
lfirst(expr) = lispInteger(FLOAT4OID);
else
elog(ERROR, "unequal type in tlist : %s \n", colname);
}
}
Input_is_string = false;
#ifdef PARSEDEBUG
Input_is_integer = false;
printf
(
"parse_target: attrtypmod is %d
\n
"
,
(
int4
)
attrtypmod
);
Typecast_ok = true;
#endif
#endif
if
(
attrtype
!=
type_id
)
/* Apparently going to a fixed-length string?
{
* Then explicitly size for storage...
if
(
IsA
(
expr
,
Const
))
*/
{
if
(
attrtypmod
>
0
)
/* try to cast the constant */
if
(
arrayRef
&&
!
(((
A_Indices
*
)
lfirst
(
arrayRef
))
->
lidx
))
{
/* updating a single item */
Oid
typelem
=
typeidTypElem
(
attrtype
);
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
typeidType
(
typelem
),
attrtypmod
);
}
else
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
typeidType
(
attrtype
),
attrtypmod
);
}
else
{
{
/* currently, we can't handle casting of expressions */
expr
=
size_target_expr
(
pstate
,
expr
,
attrtype
,
attrtypmod
);
elog
(
ERROR
,
"parser: attribute '%s' is of type '%s' but expression is of type '%s'"
,
colname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
type_id
));
}
}
}
}
...
@@ -514,7 +600,8 @@ make_targetlist_expr(ParseState *pstate,
...
@@ -514,7 +600,8 @@ make_targetlist_expr(ParseState *pstate,
tent
->
expr
=
expr
;
tent
->
expr
=
expr
;
return
tent
;
return
tent
;
}
}
/* make_targetlist_expr() */
/*
/*
* makeTargetNames -
* makeTargetNames -
...
...
src/backend/parser/parse_type.c
View file @
3ace5fd0
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
*
* parse_type.
h
* parse_type.
c
* handle type operations for parser
* handle type operations for parser
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.
8 1998/02/27 19:44:51 scrappy
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.
9 1998/05/09 23:29:54 thomas
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -15,11 +15,17 @@
...
@@ -15,11 +15,17 @@
#include "postgres.h"
#include "postgres.h"
#include "fmgr.h"
#include "fmgr.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "nodes/primnodes.h"
#include "parser/parse_node.h"
#include "catalog/pg_type.h"
#include "catalog/pg_type.h"
#include "parser/parse_target.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "parser/parse_type.h"
#include "utils/syscache.h"
#include "utils/syscache.h"
/* check to see if a type id is valid,
/* check to see if a type id is valid,
* returns true if it is. By using this call before calling
* returns true if it is. By using this call before calling
* typeidType or typeidTypeName, more meaningful error messages
* typeidType or typeidTypeName, more meaningful error messages
...
...
src/include/parser/parse_coerce.h
0 → 100644
View file @
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
View file @
3ace5fd0
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
* $Id: parse_func.h,v 1.
8 1998/02/26 04:42:45 momjian
Exp $
* $Id: parse_func.h,v 1.
9 1998/05/09 23:31:34 thomas
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -49,6 +49,6 @@ extern Node *
...
@@ -49,6 +49,6 @@ extern Node *
ParseFuncOrColumn
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
ParseFuncOrColumn
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
int
*
curr_resno
,
int
precedence
);
int
*
curr_resno
,
int
precedence
);
extern
void
func_error
(
char
*
caller
,
char
*
funcname
,
int
nargs
,
Oid
*
argtypes
);
extern
void
func_error
(
char
*
caller
,
char
*
funcname
,
int
nargs
,
Oid
*
argtypes
,
char
*
msg
);
#endif
/* PARSE_FUNC_H */
#endif
/* PARSE_FUNC_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment