@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $ Header : / cvsroot / pgsql / src / backend / parser / parse_oper . c , v 1.11 1998 / 05 / 09 23 : 29 : 53 thomas Exp $
* $ Header : / cvsroot / pgsql / src / backend / parser / parse_oper . c , v 1.12 1998 / 05 / 29 14 : 00 : 22 thomas Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -21,37 +21,27 @@
# include "catalog/pg_operator.h"
# include "catalog/pg_type.h"
# include "fmgr.h"
# include "parser/parse_func.h"
# include "parser/parse_oper.h"
# include "parser/parse_type.h"
# include "parser/parse_coerce.h"
# include "storage/bufmgr.h"
# include "utils/syscache.h"
extern
Oid *
func_select_candidate ( int nargs , Oid * input_typeids , CandidateList candidates ) ;
extern
Oid *
oper_select_candidate ( int nargs , Oid * input_typeids , CandidateList candidates ) ;
static int
binary_oper_get_candidates ( char * opname ,
Oid leftTypeId ,
Oid rightTypeId ,
CandidateList * candidates ) ;
static CandidateList
binary_oper_select_candidate ( Oid arg1 ,
Oid arg2 ,
CandidateList candidates ) ;
static bool equivalentOpersAfterPromotion ( CandidateList candidates ) ;
static void op_error ( char * op , Oid arg1 , Oid arg2 ) ;
static int
unary_oper_get_candidates ( char * op ,
Oid typeId ,
CandidateList * candidates ,
char rightleft ) ;
static void
op_error ( char * op , Oid arg1 , Oid arg2 ) ;
Oid
any_ordering_op ( int restype )
@ -59,7 +49,13 @@ any_ordering_op(int restype)
Operator order_op ;
Oid order_opid ;
order_op = oper ( " < " , restype , restype , false ) ;
order_op = oper ( " < " , restype , restype , TRUE ) ;
if ( ! HeapTupleIsValid ( order_op ) )
{
elog ( ERROR , " Unable to find an ordering operator '%s' for type %s. "
" \n \t Use an explicit ordering operator or modify the query. " ,
" < " , typeidTypeName ( restype ) ) ;
}
order_opid = oprid ( order_op ) ;
return order_opid ;
@ -107,44 +103,12 @@ binary_oper_get_candidates(char *opname,
F_CHAREQ ,
CharGetDatum ( ' b ' ) ) ;
# if FALSE
if ( leftTypeId = = UNKNOWNOID )
{
if ( rightTypeId = = UNKNOWNOID )
{
nkeys = 2 ;
}
else
{
nkeys = 3 ;
ScanKeyEntryInitialize ( & opKey [ 2 ] , 0 ,
Anum_pg_operator_oprright ,
ObjectIdEqualRegProcedure ,
ObjectIdGetDatum ( rightTypeId ) ) ;
}
}
else if ( rightTypeId = = UNKNOWNOID )
{
nkeys = 3 ;
ScanKeyEntryInitialize ( & opKey [ 2 ] , 0 ,
Anum_pg_operator_oprleft ,
ObjectIdEqualRegProcedure ,
ObjectIdGetDatum ( leftTypeId ) ) ;
}
else
{
/* currently only "unknown" can be coerced */
return 0 ;
# endif
nkeys = 2 ;
pg_operator_desc = heap_openr ( OperatorRelationName ) ;
pg_operator_scan = heap_beginscan ( pg_operator_desc ,
0 ,
true ,
TRUE ,
nkeys ,
opKey ) ;
@ -173,288 +137,400 @@ binary_oper_get_candidates(char *opname,
} /* 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 .
/* 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 .
*
* This routine is new code , replacing binary_oper_select_candidate ( )
* which dates from v4 .2 / v1 .0 . x days . It tries very hard to match up
* operators with types , including allowing type coersions if necessary .
* The important thing is that the code do as much as possible ,
* while _never_ doing the wrong thing , where " the wrong thing " would
* be returning an operator when other better choices are available ,
* or returning an operator which is a non - intuitive possibility .
* - thomas 1998 - 05 - 21
*
* The comments below came from binary_oper_select_candidate ( ) , and
* illustrate the issues and choices which are possible :
* - thomas 1998 - 05 - 20
*
* current wisdom holds that the default operator should be one in which
* both operands have the same type ( there will only be one such
* operator )
*
* 7.27 .93 - I have decided not to do this ; it ' s too hard to justify , and
* it ' s easy enough to typecast explicitly - avi
* [ the rest of this routine was commented out since then - ay ]
*
* 6 / 23 / 95 - I don ' t complete agree with avi . In particular , casting
* floats is a pain for users . Whatever the rationale behind not doing
* this is , I need the following special case to work .
*
* In the WHERE clause of a query , if a float is specified without
* quotes , we treat it as float8 . I added the float48 * operators so
* that we can operate on float4 and float8 . But now we have more than
* one matching operator if the right arg is unknown ( eg . float
* specified with quotes ) . This break some stuff in the regression
* test where there are floats in quotes not properly casted . Below is
* the solution . In addition to requiring the operator operates on the
* same type for both operands [ as in the code Avi originally
* commented out ] , we also require that the operators be equivalent in
* some sense . ( see equivalentOpersAfterPromotion for details . )
* - ay 6 / 95
*/
static int
BinaryOperCandidates ( char * opname ,
Oid lTypeId ,
Oid rTypeId ,
CandidateList * candidates )
Oid *
oper_select_candidate ( int nargs ,
Oid * input_typeids ,
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 ] ;
CandidateList current_candidate ;
CandidateList last_candidate ;
Oid * current_typeids ;
int unknownOids ;
int i ;
/* 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 ) ;
int ncandidates ;
int nbestMatch ,
nmatch ;
PromoteLowerType ( & lCandidateTypeId , & rCandidateTypeId ) ;
}
CATEGORY slot_category ,
current_category ;
Oid slot_type ,
current_type ;
/* Can we promote the lesser type directly to the other? */
if ( can_coerce_type ( lowerTypeId , higherTypeId ) )
/*
* 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 )
{
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 ' ) ) ;
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 + + ;
}
}
# if FALSE
if ( leftTypeId = = UNKNOWNOID )
{
if ( rightTypeId = = UNKNOWNOID )
# 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 )
{
nkeys = 2 ;
last_candidate - > next = current_candidate ;
last_candidate = current_candidate ;
ncandidates + + ;
# ifdef PARSEDEBUG
printf ( " oper_select_candidate- choose candidate as possible match \n " ) ;
# endif
}
else
{
nkeys = 3 ;
ScanKeyEntryInitialize ( & opKey [ 2 ] , 0 ,
Anum_pg_operator_oprright ,
F_OIDEQ ,
ObjectIdGetDatum ( rightTypeId ) ) ;
last_candidate - > next = NULL ;
# ifdef PARSEDEBUG
printf ( " oper_select_candidate- reject candidate as possible match \n " ) ;
# endif
}
}
else if ( rightTypeId = = UNKNOWNOID )
{
nkeys = 3 ;
ScanKeyEntryInitialize ( & opKey [ 2 ] , 0 ,
Anum_pg_operator_oprleft ,
F_OIDEQ ,
ObjectIdGetDatum ( leftTypeId ) ) ;
}
else
if ( ncandidates < = 1 )
{
/* 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 ) ;
if ( ! can_coerce_type ( 1 , & input_typeids [ 0 ] , & candidates - > args [ 0 ] )
| | ! can_coerce_type ( 1 , & input_typeids [ 1 ] , & candidates - > args [ 1 ] ) )
{
ncandidates = 0 ;
}
return ( ( ncandidates = = 1 ) ? candidates - > args : NULL ) ;
}
do
/*
* Still too many candidates ?
* 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 )
{
tup = heap_getnext ( pg_operator_scan , 0 , & buffer ) ;
if ( HeapTupleIsValid ( tup ) )
current_typeids = current_candidate - > args ;
nmatch = 0 ;
for ( i = 0 ; i < nargs ; i + + )
{
current_candidate = ( CandidateList ) palloc ( sizeof ( struct _CandidateList ) ) ;
current_candidate - > args = ( Oid * ) palloc ( 2 * sizeof ( Oid ) ) ;
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 + + ;
}
}
}
oper = ( OperatorTupleForm ) GETSTRUCT ( tup ) ;
current_candidate - > args [ 0 ] = oper - > oprleft ;
current_candidate - > args [ 1 ] = oper - > oprright ;
current_candidate - > next = * candidates ;
* candidates = current_candidate ;
# 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 + + ;
ReleaseBuffer ( buffer ) ;
# ifdef PARSEDEBUG
printf ( " oper_select_candidate- choose candidate as possible match \n " ) ;
# endif
}
} while ( HeapTupleIsValid ( tup ) ) ;
heap_endscan ( pg_operator_scan ) ;
heap_close ( pg_operator_desc ) ;
return ncandidates ;
} /* BinaryOperCandidates() */
else
{
last_candidate - > next = NULL ;
# ifdef PARSEDEBUG
printf ( " oper_select_candidate- reject candidate as possible match \n " ) ;
# endif
}
}
if ( ncandidates < = 1 )
{
if ( ! can_coerce_type ( 1 , & input_typeids [ 0 ] , & candidates - > args [ 0 ] )
| | ! can_coerce_type ( 1 , & input_typeids [ 1 ] , & candidates - > args [ 1 ] ) )
{
ncandidates = 0 ;
# ifdef PARSEDEBUG
printf ( " oper_select_candidate- unable to coerce preferred candidate \n " ) ;
# endif
}
return ( ( ncandidates = = 1 ) ? candidates - > args : NULL ) ;
}
/*
* equivalentOpersAfterPromotion -
* checks if a list of candidate operators obtained from
* binary_oper_get_candidates ( ) contain equivalent operators . If
* this routine is called , we have more than 1 candidate and need to
* decided whether to pick one of them . This routine returns true if
* all the candidates operate on the same data types after
* promotion ( int2 , int4 , float4 - > float8 ) .
* Still too many candidates ?
* Try assigning types for the unknown columns .
*/
static bool
equivalentOpersAfterPromotion ( CandidateList candidates )
{
CandidateList result ;
CandidateList promotedCandidates = NULL ;
Oid leftarg ,
rightarg ;
unknownOids = FALSE ;
current_type = UNKNOWNOID ;
for ( i = 0 ; i < nargs ; i + + )
{
if ( ( input_typeids [ i ] ! = UNKNOWNOID )
& & ( input_typeids [ i ] ! = InvalidOid ) )
{
current_type = input_typeids [ i ] ;
}
else
{
unknownOids = TRUE ;
}
}
for ( result = candidates ; result ! = NULL ; result = result - > next )
if ( unknownOids & & ( current_type ! = UNKNOWNOID ) )
{
CandidateList c ;
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 ) ;
}
}
c = ( CandidateList ) palloc ( sizeof ( * c ) ) ;
c - > args = ( Oid * ) palloc ( 2 * sizeof ( Oid ) ) ;
switch ( result - > args [ 0 ] )
for ( i = 0 ; i < nargs ; i + + )
{
if ( input_typeids [ i ] = = UNKNOWNOID )
{
case FLOAT4OID :
case INT4OID :
case INT2OID :
case CASHOID :
c - > args [ 0 ] = FLOAT8OID ;
break ;
default :
c - > args [ 0 ] = result - > args [ 0 ] ;
break ;
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
}
}
switch ( result - > args [ 1 ] )
else
{
case FLOAT4OID :
case INT4OID :
case INT2OID :
case CASHOID :
c - > args [ 1 ] = FLOAT8OID ;
break ;
default :
c - > args [ 1 ] = result - > args [ 1 ] ;
break ;
# ifdef PARSEDEBUG
printf ( " oper_select_candidate- column #%d input type is %s \n " ,
i , typeidTypeName ( input_typeids [ i ] ) ) ;
# endif
}
c - > next = promotedCandidates ;
promotedCandidates = c ;
}
/*
* if we get called , we have more than 1 candidates so we can do the
* following safely
*/
leftarg = promotedCandidates - > args [ 0 ] ;
rightarg = promotedCandidates - > args [ 1 ] ;
for ( result = promotedCandidates - > next ; result ! = NULL ; result = result - > next )
ncandidates = 0 ;
for ( current_candidate = candidates ;
current_candidate ! = NULL ;
current_candidate = current_candidate - > next )
{
if ( result - > args [ 0 ] ! = leftarg | | result - > args [ 1 ] ! = rightarg )
/*
* this list contains operators that operate on different data
* types even after promotion . Hence we can ' t decide on which
* one to pick . The user must do explicit type casting .
*/
return FALSE ;
if ( can_coerce_type ( 1 , & input_typeids [ 0 ] , & current_candidate - > args [ 0 ] )
& & can_coerce_type ( 1 , & input_typeids [ 1 ] , & current_candidate - > args [ 1 ] ) )
ncandidates + + ;
}
/*
* all the candidates are equivalent in the following sense : they
* operate on equivalent data types and picking any one of them is as
* good .
*/
return TRUE ;
}
return ( ( ncandidates = = 1 ) ? candidates - > args : NULL ) ;
} /* oper_select_candidate() */
/* binary_oper_select_candidate()
* Given a choice of argument type pairs for a binary operator ,
* try to choose a default pair .
*
* current wisdom holds that the default operator should be one in which
* both operands have the same type ( there will only be one such
* operator )
*
* 7.27 .93 - I have decided not to do this ; it ' s too hard to justify , and
* it ' s easy enough to typecast explicitly - avi
* [ the rest of this routine was commented out since then - ay ]
*
* 6 / 23 / 95 - I don ' t complete agree with avi . In particular , casting
* floats is a pain for users . Whatever the rationale behind not doing
* this is , I need the following special case to work .
*
* In the WHERE clause of a query , if a float is specified without
* quotes , we treat it as float8 . I added the float48 * operators so
* that we can operate on float4 and float8 . But now we have more than
* one matching operator if the right arg is unknown ( eg . float
* specified with quotes ) . This break some stuff in the regression
* test where there are floats in quotes not properly casted . Below is
* the solution . In addition to requiring the operator operates on the
* same type for both operands [ as in the code Avi originally
* commented out ] , we also require that the operators be equivalent in
* some sense . ( see equivalentOpersAfterPromotion for details . )
* - ay 6 / 95
/* oper_exact()
* Given operator , and arguments , return oper struct .
* Inputs :
* arg1 , arg2 : Type IDs
*/
static CandidateList
binary_oper_select_candidate ( Oid arg1 ,
Oid arg2 ,
CandidateList candidates )
Operator
oper_exact ( char * op , Oid arg1 , Oid arg2 , Node * * ltree , Node * * rtree , bool noWarnings )
{
CandidateList result ;
HeapTuple tup ;
Node * tree ;
/*
* If both are " unknown " , there is no way to select a candidate
*/
if ( arg1 = = UNKNOWNOID & & arg2 = = UNKNOWNOID )
return ( NULL ) ;
/* Unspecified type for one of the arguments? then use the other */
if ( ( arg1 = = UNKNOWNOID ) & & ( arg2 ! = InvalidOid ) ) arg1 = arg2 ;
else if ( ( arg2 = = UNKNOWNOID ) & & ( arg1 ! = InvalidOid ) ) arg2 = arg1 ;
if ( ! equivalentOpersAfterPromotion ( candidates ) )
return NULL ;
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( arg1 ) ,
ObjectIdGetDatum ( arg2 ) ,
Int8GetDatum ( ' b ' ) ) ;
/*
* if we get here , any one will do but we ' re more picky and require
* both operands be the same .
*/
for ( result = candidates ; result ! = NULL ; result = result - > next )
/* Did not find anything? then try flipping arguments on a commutative operator... */
if ( ! HeapTupleIsValid ( tup ) & & ( arg1 ! = arg2 ) )
{
if ( result - > args [ 0 ] = = result - > args [ 1 ] )
return result ;
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( arg2 ) ,
ObjectIdGetDatum ( arg1 ) ,
Int8GetDatum ( ' b ' ) ) ;
if ( HeapTupleIsValid ( tup ) )
{
OperatorTupleForm opform ;
# if PARSEDEBUG
printf ( " oper_exact: found possible commutative operator candidate \n " ) ;
# endif
opform = ( OperatorTupleForm ) GETSTRUCT ( tup ) ;
if ( opform - > oprcom = = tup - > t_oid )
{
# if PARSEDEBUG
printf ( " oper_exact: commutative operator found \n " ) ;
# endif
if ( ( ltree ! = NULL ) & & ( rtree ! = NULL ) )
{
tree = * ltree ;
* ltree = * rtree ;
* rtree = tree ;
}
}
/* disable for now... - thomas 1998-05-14 */
else
{
tup = NULL ;
}
}
if ( ! HeapTupleIsValid ( tup ) & & ( ! noWarnings ) )
{
op_error ( op , arg1 , arg2 ) ;
}
}
return ( NULL ) ;
}
return tup ;
} /* oper_exact() */
/* oper()
/* oper_inexact()
* Given operator , types of arg1 , and arg2 , return oper struct .
* Inputs :
* arg1 , arg2 : Type IDs
*/
Operator
oper ( char * op , Oid arg1 , Oid arg2 , bool noWarnings )
oper_inexact ( char * op , Oid arg1 , Oid arg2 , Node * * ltree , Node * * rtree , bool noWarnings )
{
HeapTuple tup ;
CandidateList candidates ;
@ -468,77 +544,95 @@ oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
if ( arg1 = = InvalidOid )
arg1 = arg2 ;
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( arg1 ) ,
ObjectIdGetDatum ( arg2 ) ,
Int8GetDatum ( ' b ' ) ) ;
ncandidates = binary_oper_get_candidates ( op , arg1 , arg2 , & candidates ) ;
/* Did not find anything? then look more carefully ... */
if ( ! HeapTupleIsValid ( tup ) )
/* No operators found? Then throw error or return null... */
if ( ncandidates = = 0 )
{
ncandidates = binary_oper_get_candidates ( op , arg1 , arg2 , & candidates ) ;
if ( ! noWarnings )
op_error ( op , arg1 , arg2 ) ;
return ( NULL ) ;
}
/* No operators found? Then throw error or return null... */
if ( ncandidates = = 0 )
{
if ( ! noWarnings )
op_error ( op , arg1 , arg2 ) ;
return ( NULL ) ;
}
/* Or found exactly one? Then proceed... */
else if ( ncandidates = = 1 )
{
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( candidates - > args [ 0 ] ) ,
ObjectIdGetDatum ( candidates - > args [ 1 ] ) ,
Int8GetDatum ( ' b ' ) ) ;
Assert ( HeapTupleIsValid ( tup ) ) ;
/* Or found exactly one? Then proceed... */
else if ( ncandidates = = 1 )
# if PARSEDEBUG
printf ( " oper_inexact: found single candidate \n " ) ;
# endif
}
/* Otherwise, multiple operators of the desired types found... */
else
{
inputOids [ 0 ] = arg1 ;
inputOids [ 1 ] = arg2 ;
targetOids = oper_select_candidate ( 2 , inputOids , candidates ) ;
if ( targetOids ! = NULL )
{
# if PARSEDEBUG
printf ( " oper_inexact: found candidate \n " ) ;
# endif
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( candidates - > args [ 0 ] ) ,
ObjectIdGetDatum ( candidates - > args [ 1 ] ) ,
ObjectIdGetDatum ( targetOid s [ 0 ] ) ,
ObjectIdGetDatum ( targetOid s [ 1 ] ) ,
Int8GetDatum ( ' b ' ) ) ;
Assert ( HeapTupleIsValid ( tup ) ) ;
}
/* Otherwise, multiple operators of the desired types found... */
}
else
{
# if FALSE
candidates = binary_oper_select_candidate ( arg1 , arg2 , candidates ) ;
# 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 )
{
# if PARSEDEBUG
printf ( " oper: found candidate \n " ) ;
# endif
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( targetOids [ 0 ] ) ,
ObjectIdGetDatum ( targetOids [ 1 ] ) ,
Int8GetDatum ( ' b ' ) ) ;
}
else
{
tup = NULL ;
}
tup = NULL ;
}
/* Could not choose one, for whatever reason... */
if ( ! HeapTupleIsValid ( tup ) )
/* Could not choose one, for whatever reason... */
if ( ! HeapTupleIsValid ( tup ) )
{
if ( ! noWarnings )
{
if ( ! noWarnings )
{
elog ( ERROR , " There is more than one operator '%s' for types '%s' and '%s' "
" \n \t You will have to retype this query using an explicit cast " ,
op , typeTypeName ( typeidType ( arg1 ) ) , typeTypeName ( typeidType ( arg2 ) ) ) ;
}
return ( NULL ) ;
elog ( ERROR , " There is more than one possible operator '%s' for types '%s' and '%s' "
" \n \t You will have to retype this query using an explicit cast " ,
op , typeTypeName ( typeidType ( arg1 ) ) , typeTypeName ( typeidType ( arg2 ) ) ) ;
}
return ( NULL ) ;
}
}
return ( ( Operator ) tup ) ;
} /* oper_inexact() */
/* oper()
* Given operator , types of arg1 , and arg2 , return oper struct .
* Inputs :
* arg1 , arg2 : Type IDs
*/
Operator
oper ( char * opname , Oid ltypeId , Oid rtypeId , bool noWarnings )
{
HeapTuple tup ;
/* check for exact match on this operator... */
if ( HeapTupleIsValid ( tup = oper_exact ( opname , ltypeId , rtypeId , NULL , NULL , TRUE ) ) )
{
}
/* try to find a match on likely candidates... */
else if ( HeapTupleIsValid ( tup = oper_inexact ( opname , ltypeId , rtypeId , NULL , NULL , TRUE ) ) )
{
}
else if ( ! noWarnings )
{
elog ( ERROR , " Unable to find binary operator '%s' for types %s and %s " ,
opname , typeTypeName ( typeidType ( ltypeId ) ) , typeTypeName ( typeidType ( rtypeId ) ) ) ;
}
return ( ( Operator ) tup ) ;
} /* oper() */
@ -573,26 +667,13 @@ unary_oper_get_candidates(char *op,
fmgr_info ( F_CHAREQ , ( FmgrInfo * ) & opKey [ 1 ] . sk_func ) ;
opKey [ 1 ] . sk_argument = CharGetDatum ( rightleft ) ;
# if FALSE
/* currently, only "unknown" can be coerced */
/*
* but we should allow types that are internally the same to be
* " coerced "
*/
if ( typeId ! = UNKNOWNOID )
{
return 0 ;
}
# endif
# ifdef PARSEDEBUG
printf ( " unary_oper_get_candidates: start scan for '%s' \n " , op ) ;
# endif
pg_operator_desc = heap_openr ( OperatorRelationName ) ;
pg_operator_scan = heap_beginscan ( pg_operator_desc ,
0 ,
true ,
TRUE ,
2 ,
opKey ) ;
@ -658,17 +739,13 @@ right_oper(char *op, Oid arg)
{
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
ObjectIdGetDatum ( candidates - > args [ 0 ] ) ,
ObjectIdGetDatum ( candidates - > args [ 0 ] ) ,
ObjectIdGetDatum ( InvalidOid ) ,
Int8GetDatum ( ' r ' ) ) ;
Assert ( HeapTupleIsValid ( tup ) ) ;
}
else
{
# if FALSE
elog ( ERROR , " There is more than one right operator %s "
" \n \t You will have to retype this query using an explicit cast " , op ) ;
# endif
targetOid = func_select_candidate ( 1 , & arg , candidates ) ;
if ( targetOid ! = NULL )
@ -735,10 +812,6 @@ printf("left_oper: searched cache for single left oper candidate '%s %s'\n",
}
else
{
# if FALSE
elog ( ERROR , " There is more than one left operator %s "
" \n \t You will have to retype this query using an explicit cast " , op ) ;
# endif
targetOid = func_select_candidate ( 1 , & arg , candidates ) ;
tup = SearchSysCacheTuple ( OPRNAME ,
PointerGetDatum ( op ) ,
@ -779,7 +852,7 @@ op_error(char *op, Oid arg1, Oid arg2)
else
{
elog ( ERROR , " Left hand side of operator '%s' has an unknown type "
" \n \t Probably a bad attribute name " , op ) ;
" \n \t Probably a bad attribute name " , op ) ;
}
if ( typeidIsValid ( arg2 ) )
@ -789,11 +862,11 @@ op_error(char *op, Oid arg1, Oid arg2)
else
{
elog ( ERROR , " Right hand side of operator %s has an unknown type "
" \n \t Probably a bad attribute name " , op ) ;
" \n \t Probably a bad attribute name " , op ) ;
}
elog ( ERROR , " There is no operator '%s' for types '%s' and '%s' "
" \n \t You will either have to retype this query using an explicit cast, "
" \n \t or you will have to define the operator using CREATE OPERATOR " ,
" \n \t or you will have to define the operator using CREATE OPERATOR " ,
op , typeTypeName ( tp1 ) , typeTypeName ( tp2 ) ) ;
}