@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / parser / parse_expr . c , v 1.230 2008 / 08 / 22 00 : 16 : 04 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / parser / parse_expr . c , v 1.231 2008 / 08 / 25 22 : 42 : 33 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -17,13 +17,10 @@
# include "catalog/pg_type.h"
# include "commands/dbcommands.h"
# include "mb/pg_wchar.h"
# include "miscadmin.h"
# include "nodes/makefuncs.h"
# include "nodes/plannodes.h"
# include "optimizer/clauses.h"
# include "nodes/nodeFuncs.h"
# include "parser/analyze.h"
# include "parser/gramparse.h"
# include "parser/parse_coerce.h"
# include "parser/parse_expr.h"
# include "parser/parse_func.h"
@ -1863,484 +1860,6 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
return result ;
}
/*
* exprType -
* returns the Oid of the type of the expression . ( Used for typechecking . )
*/
Oid
exprType ( Node * expr )
{
Oid type ;
if ( ! expr )
return InvalidOid ;
switch ( nodeTag ( expr ) )
{
case T_Var :
type = ( ( Var * ) expr ) - > vartype ;
break ;
case T_Const :
type = ( ( Const * ) expr ) - > consttype ;
break ;
case T_Param :
type = ( ( Param * ) expr ) - > paramtype ;
break ;
case T_Aggref :
type = ( ( Aggref * ) expr ) - > aggtype ;
break ;
case T_ArrayRef :
{
ArrayRef * arrayref = ( ArrayRef * ) expr ;
/* slice and/or store operations yield the array type */
if ( arrayref - > reflowerindexpr | | arrayref - > refassgnexpr )
type = arrayref - > refarraytype ;
else
type = arrayref - > refelemtype ;
}
break ;
case T_FuncExpr :
type = ( ( FuncExpr * ) expr ) - > funcresulttype ;
break ;
case T_OpExpr :
type = ( ( OpExpr * ) expr ) - > opresulttype ;
break ;
case T_DistinctExpr :
type = ( ( DistinctExpr * ) expr ) - > opresulttype ;
break ;
case T_ScalarArrayOpExpr :
type = BOOLOID ;
break ;
case T_BoolExpr :
type = BOOLOID ;
break ;
case T_SubLink :
{
SubLink * sublink = ( SubLink * ) expr ;
if ( sublink - > subLinkType = = EXPR_SUBLINK | |
sublink - > subLinkType = = ARRAY_SUBLINK )
{
/* get the type of the subselect's first target column */
Query * qtree = ( Query * ) sublink - > subselect ;
TargetEntry * tent ;
if ( ! qtree | | ! IsA ( qtree , Query ) )
elog ( ERROR , " cannot get type for untransformed sublink " ) ;
tent = ( TargetEntry * ) linitial ( qtree - > targetList ) ;
Assert ( IsA ( tent , TargetEntry ) ) ;
Assert ( ! tent - > resjunk ) ;
type = exprType ( ( Node * ) tent - > expr ) ;
if ( sublink - > subLinkType = = ARRAY_SUBLINK )
{
type = get_array_type ( type ) ;
if ( ! OidIsValid ( type ) )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " could not find array type for data type %s " ,
format_type_be ( exprType ( ( Node * ) tent - > expr ) ) ) ) ) ;
}
}
else
{
/* for all other sublink types, result is boolean */
type = BOOLOID ;
}
}
break ;
case T_SubPlan :
{
/*
* Although the parser does not ever deal with already - planned
* expression trees , we support SubPlan nodes in this routine
* for the convenience of ruleutils . c .
*/
SubPlan * subplan = ( SubPlan * ) expr ;
if ( subplan - > subLinkType = = EXPR_SUBLINK | |
subplan - > subLinkType = = ARRAY_SUBLINK )
{
/* get the type of the subselect's first target column */
type = subplan - > firstColType ;
if ( subplan - > subLinkType = = ARRAY_SUBLINK )
{
type = get_array_type ( type ) ;
if ( ! OidIsValid ( type ) )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " could not find array type for data type %s " ,
format_type_be ( subplan - > firstColType ) ) ) ) ;
}
}
else
{
/* for all other subplan types, result is boolean */
type = BOOLOID ;
}
}
break ;
case T_AlternativeSubPlan :
{
/* As above, supported for the convenience of ruleutils.c */
AlternativeSubPlan * asplan = ( AlternativeSubPlan * ) expr ;
/* subplans should all return the same thing */
type = exprType ( ( Node * ) linitial ( asplan - > subplans ) ) ;
}
break ;
case T_FieldSelect :
type = ( ( FieldSelect * ) expr ) - > resulttype ;
break ;
case T_FieldStore :
type = ( ( FieldStore * ) expr ) - > resulttype ;
break ;
case T_RelabelType :
type = ( ( RelabelType * ) expr ) - > resulttype ;
break ;
case T_CoerceViaIO :
type = ( ( CoerceViaIO * ) expr ) - > resulttype ;
break ;
case T_ArrayCoerceExpr :
type = ( ( ArrayCoerceExpr * ) expr ) - > resulttype ;
break ;
case T_ConvertRowtypeExpr :
type = ( ( ConvertRowtypeExpr * ) expr ) - > resulttype ;
break ;
case T_CaseExpr :
type = ( ( CaseExpr * ) expr ) - > casetype ;
break ;
case T_CaseTestExpr :
type = ( ( CaseTestExpr * ) expr ) - > typeId ;
break ;
case T_ArrayExpr :
type = ( ( ArrayExpr * ) expr ) - > array_typeid ;
break ;
case T_RowExpr :
type = ( ( RowExpr * ) expr ) - > row_typeid ;
break ;
case T_RowCompareExpr :
type = BOOLOID ;
break ;
case T_CoalesceExpr :
type = ( ( CoalesceExpr * ) expr ) - > coalescetype ;
break ;
case T_MinMaxExpr :
type = ( ( MinMaxExpr * ) expr ) - > minmaxtype ;
break ;
case T_XmlExpr :
if ( ( ( XmlExpr * ) expr ) - > op = = IS_DOCUMENT )
type = BOOLOID ;
else if ( ( ( XmlExpr * ) expr ) - > op = = IS_XMLSERIALIZE )
type = TEXTOID ;
else
type = XMLOID ;
break ;
case T_NullIfExpr :
type = exprType ( ( Node * ) linitial ( ( ( NullIfExpr * ) expr ) - > args ) ) ;
break ;
case T_NullTest :
type = BOOLOID ;
break ;
case T_BooleanTest :
type = BOOLOID ;
break ;
case T_CoerceToDomain :
type = ( ( CoerceToDomain * ) expr ) - > resulttype ;
break ;
case T_CoerceToDomainValue :
type = ( ( CoerceToDomainValue * ) expr ) - > typeId ;
break ;
case T_SetToDefault :
type = ( ( SetToDefault * ) expr ) - > typeId ;
break ;
case T_CurrentOfExpr :
type = BOOLOID ;
break ;
default :
elog ( ERROR , " unrecognized node type: %d " , ( int ) nodeTag ( expr ) ) ;
type = InvalidOid ; /* keep compiler quiet */
break ;
}
return type ;
}
/*
* exprTypmod -
* returns the type - specific attrmod of the expression , if it can be
* determined . In most cases , it can ' t and we return - 1.
*/
int32
exprTypmod ( Node * expr )
{
if ( ! expr )
return - 1 ;
switch ( nodeTag ( expr ) )
{
case T_Var :
return ( ( Var * ) expr ) - > vartypmod ;
case T_Const :
return ( ( Const * ) expr ) - > consttypmod ;
case T_Param :
return ( ( Param * ) expr ) - > paramtypmod ;
case T_ArrayRef :
/* typmod is the same for array or element */
return ( ( ArrayRef * ) expr ) - > reftypmod ;
case T_FuncExpr :
{
int32 coercedTypmod ;
/* Be smart about length-coercion functions... */
if ( exprIsLengthCoercion ( expr , & coercedTypmod ) )
return coercedTypmod ;
}
break ;
case T_SubLink :
{
SubLink * sublink = ( SubLink * ) expr ;
if ( sublink - > subLinkType = = EXPR_SUBLINK | |
sublink - > subLinkType = = ARRAY_SUBLINK )
{
/* get the typmod of the subselect's first target column */
Query * qtree = ( Query * ) sublink - > subselect ;
TargetEntry * tent ;
if ( ! qtree | | ! IsA ( qtree , Query ) )
elog ( ERROR , " cannot get type for untransformed sublink " ) ;
tent = ( TargetEntry * ) linitial ( qtree - > targetList ) ;
Assert ( IsA ( tent , TargetEntry ) ) ;
Assert ( ! tent - > resjunk ) ;
return exprTypmod ( ( Node * ) tent - > expr ) ;
/* note we don't need to care if it's an array */
}
}
break ;
case T_FieldSelect :
return ( ( FieldSelect * ) expr ) - > resulttypmod ;
case T_RelabelType :
return ( ( RelabelType * ) expr ) - > resulttypmod ;
case T_ArrayCoerceExpr :
return ( ( ArrayCoerceExpr * ) expr ) - > resulttypmod ;
case T_CaseExpr :
{
/*
* If all the alternatives agree on type / typmod , return that
* typmod , else use - 1
*/
CaseExpr * cexpr = ( CaseExpr * ) expr ;
Oid casetype = cexpr - > casetype ;
int32 typmod ;
ListCell * arg ;
if ( ! cexpr - > defresult )
return - 1 ;
if ( exprType ( ( Node * ) cexpr - > defresult ) ! = casetype )
return - 1 ;
typmod = exprTypmod ( ( Node * ) cexpr - > defresult ) ;
if ( typmod < 0 )
return - 1 ; /* no point in trying harder */
foreach ( arg , cexpr - > args )
{
CaseWhen * w = ( CaseWhen * ) lfirst ( arg ) ;
Assert ( IsA ( w , CaseWhen ) ) ;
if ( exprType ( ( Node * ) w - > result ) ! = casetype )
return - 1 ;
if ( exprTypmod ( ( Node * ) w - > result ) ! = typmod )
return - 1 ;
}
return typmod ;
}
break ;
case T_CaseTestExpr :
return ( ( CaseTestExpr * ) expr ) - > typeMod ;
case T_ArrayExpr :
{
/*
* If all the elements agree on type / typmod , return that
* typmod , else use - 1
*/
ArrayExpr * arrayexpr = ( ArrayExpr * ) expr ;
Oid commontype ;
int32 typmod ;
ListCell * elem ;
if ( arrayexpr - > elements = = NIL )
return - 1 ;
typmod = exprTypmod ( ( Node * ) linitial ( arrayexpr - > elements ) ) ;
if ( typmod < 0 )
return - 1 ; /* no point in trying harder */
if ( arrayexpr - > multidims )
commontype = arrayexpr - > array_typeid ;
else
commontype = arrayexpr - > element_typeid ;
foreach ( elem , arrayexpr - > elements )
{
Node * e = ( Node * ) lfirst ( elem ) ;
if ( exprType ( e ) ! = commontype )
return - 1 ;
if ( exprTypmod ( e ) ! = typmod )
return - 1 ;
}
return typmod ;
}
break ;
case T_CoalesceExpr :
{
/*
* If all the alternatives agree on type / typmod , return that
* typmod , else use - 1
*/
CoalesceExpr * cexpr = ( CoalesceExpr * ) expr ;
Oid coalescetype = cexpr - > coalescetype ;
int32 typmod ;
ListCell * arg ;
if ( exprType ( ( Node * ) linitial ( cexpr - > args ) ) ! = coalescetype )
return - 1 ;
typmod = exprTypmod ( ( Node * ) linitial ( cexpr - > args ) ) ;
if ( typmod < 0 )
return - 1 ; /* no point in trying harder */
for_each_cell ( arg , lnext ( list_head ( cexpr - > args ) ) )
{
Node * e = ( Node * ) lfirst ( arg ) ;
if ( exprType ( e ) ! = coalescetype )
return - 1 ;
if ( exprTypmod ( e ) ! = typmod )
return - 1 ;
}
return typmod ;
}
break ;
case T_MinMaxExpr :
{
/*
* If all the alternatives agree on type / typmod , return that
* typmod , else use - 1
*/
MinMaxExpr * mexpr = ( MinMaxExpr * ) expr ;
Oid minmaxtype = mexpr - > minmaxtype ;
int32 typmod ;
ListCell * arg ;
if ( exprType ( ( Node * ) linitial ( mexpr - > args ) ) ! = minmaxtype )
return - 1 ;
typmod = exprTypmod ( ( Node * ) linitial ( mexpr - > args ) ) ;
if ( typmod < 0 )
return - 1 ; /* no point in trying harder */
for_each_cell ( arg , lnext ( list_head ( mexpr - > args ) ) )
{
Node * e = ( Node * ) lfirst ( arg ) ;
if ( exprType ( e ) ! = minmaxtype )
return - 1 ;
if ( exprTypmod ( e ) ! = typmod )
return - 1 ;
}
return typmod ;
}
break ;
case T_NullIfExpr :
{
NullIfExpr * nexpr = ( NullIfExpr * ) expr ;
return exprTypmod ( ( Node * ) linitial ( nexpr - > args ) ) ;
}
break ;
case T_CoerceToDomain :
return ( ( CoerceToDomain * ) expr ) - > resulttypmod ;
case T_CoerceToDomainValue :
return ( ( CoerceToDomainValue * ) expr ) - > typeMod ;
case T_SetToDefault :
return ( ( SetToDefault * ) expr ) - > typeMod ;
default :
break ;
}
return - 1 ;
}
/*
* exprIsLengthCoercion
* Detect whether an expression tree is an application of a datatype ' s
* typmod - coercion function . Optionally extract the result ' s typmod .
*
* If coercedTypmod is not NULL , the typmod is stored there if the expression
* is a length - coercion function , else - 1 is stored there .
*
* Note that a combined type - and - length coercion will be treated as a
* length coercion by this routine .
*/
bool
exprIsLengthCoercion ( Node * expr , int32 * coercedTypmod )
{
if ( coercedTypmod ! = NULL )
* coercedTypmod = - 1 ; /* default result on failure */
/*
* Scalar - type length coercions are FuncExprs , array - type length coercions
* are ArrayCoerceExprs
*/
if ( expr & & IsA ( expr , FuncExpr ) )
{
FuncExpr * func = ( FuncExpr * ) expr ;
int nargs ;
Const * second_arg ;
/*
* If it didn ' t come from a coercion context , reject .
*/
if ( func - > funcformat ! = COERCE_EXPLICIT_CAST & &
func - > funcformat ! = COERCE_IMPLICIT_CAST )
return false ;
/*
* If it ' s not a two - argument or three - argument function with the
* second argument being an int4 constant , it can ' t have been created
* from a length coercion ( it must be a type coercion , instead ) .
*/
nargs = list_length ( func - > args ) ;
if ( nargs < 2 | | nargs > 3 )
return false ;
second_arg = ( Const * ) lsecond ( func - > args ) ;
if ( ! IsA ( second_arg , Const ) | |
second_arg - > consttype ! = INT4OID | |
second_arg - > constisnull )
return false ;
/*
* OK , it is indeed a length - coercion function .
*/
if ( coercedTypmod ! = NULL )
* coercedTypmod = DatumGetInt32 ( second_arg - > constvalue ) ;
return true ;
}
if ( expr & & IsA ( expr , ArrayCoerceExpr ) )
{
ArrayCoerceExpr * acoerce = ( ArrayCoerceExpr * ) expr ;
/* It's not a length coercion unless there's a nondefault typmod */
if ( acoerce - > resulttypmod < 0 )
return false ;
/*
* OK , it is indeed a length - coercion expression .
*/
if ( coercedTypmod ! = NULL )
* coercedTypmod = acoerce - > resulttypmod ;
return true ;
}
return false ;
}
/*
* Handle an explicit CAST construct .
*