@ -34,15 +34,16 @@
static Node * coerce_type_typmod ( Node * node ,
static Node * coerce_type_typmod ( Node * node ,
Oid targetTypeId , int32 targetTypMod ,
Oid targetTypeId , int32 targetTypMod ,
CoercionForm cformat , int location ,
CoercionContext ccontext , CoercionForm cformat ,
bool isExplicit , bool hideInputCoercion ) ;
int location ,
bool hideInputCoercion ) ;
static void hide_coercion_node ( Node * node ) ;
static void hide_coercion_node ( Node * node ) ;
static Node * build_coercion_expression ( Node * node ,
static Node * build_coercion_expression ( Node * node ,
CoercionPathType pathtype ,
CoercionPathType pathtype ,
Oid funcId ,
Oid funcId ,
Oid targetTypeId , int32 targetTypMod ,
Oid targetTypeId , int32 targetTypMod ,
CoercionForm cformat , int location ,
CoercionContext ccontext , CoercionForm cformat ,
bool isExplicit ) ;
int location ) ;
static Node * coerce_record_to_complex ( ParseState * pstate , Node * node ,
static Node * coerce_record_to_complex ( ParseState * pstate , Node * node ,
Oid targetTypeId ,
Oid targetTypeId ,
CoercionContext ccontext ,
CoercionContext ccontext ,
@ -110,8 +111,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
*/
*/
result = coerce_type_typmod ( result ,
result = coerce_type_typmod ( result ,
targettype , targettypmod ,
targettype , targettypmod ,
cformat , location ,
ccontext , cformat , location ,
( cformat ! = COERCE_IMPLICIT_CAST ) ,
( result ! = expr & & ! IsA ( result , Const ) ) ) ;
( result ! = expr & & ! IsA ( result , Const ) ) ) ;
if ( expr ! = origexpr )
if ( expr ! = origexpr )
@ -355,7 +355,8 @@ coerce_type(ParseState *pstate, Node *node,
result = coerce_to_domain ( result ,
result = coerce_to_domain ( result ,
baseTypeId , baseTypeMod ,
baseTypeId , baseTypeMod ,
targetTypeId ,
targetTypeId ,
cformat , location , false , false ) ;
ccontext , cformat , location ,
false ) ;
ReleaseSysCache ( baseType ) ;
ReleaseSysCache ( baseType ) ;
@ -370,10 +371,10 @@ coerce_type(ParseState *pstate, Node *node,
* NULL to indicate we should proceed with normal coercion .
* NULL to indicate we should proceed with normal coercion .
*/
*/
result = pstate - > p_coerce_param_hook ( pstate ,
result = pstate - > p_coerce_param_hook ( pstate ,
( Param * ) node ,
( Param * ) node ,
targetTypeId ,
targetTypeId ,
targetTypeMod ,
targetTypeMod ,
location ) ;
location ) ;
if ( result )
if ( result )
return result ;
return result ;
}
}
@ -417,20 +418,17 @@ coerce_type(ParseState *pstate, Node *node,
result = build_coercion_expression ( node , pathtype , funcId ,
result = build_coercion_expression ( node , pathtype , funcId ,
baseTypeId , baseTypeMod ,
baseTypeId , baseTypeMod ,
cformat , location ,
ccontext , cformat , location ) ;
( cformat ! = COERCE_IMPLICIT_CAST ) ) ;
/*
/*
* If domain , coerce to the domain type and relabel with domain
* If domain , coerce to the domain type and relabel with domain
* type ID . We can skip the internal length - coercion step if the
* type ID , hiding the previous coercion node .
* selected coercion function was a type - and - length coercion .
*/
*/
if ( targetTypeId ! = baseTypeId )
if ( targetTypeId ! = baseTypeId )
result = coerce_to_domain ( result , baseTypeId , baseTypeMod ,
result = coerce_to_domain ( result , baseTypeId , baseTypeMod ,
targetTypeId ,
targetTypeId ,
cformat , location , true ,
ccontext , cformat , location ,
exprIsLengthCoercion ( result ,
true ) ;
NULL ) ) ;
}
}
else
else
{
{
@ -444,7 +442,8 @@ coerce_type(ParseState *pstate, Node *node,
* then we won ' t need a RelabelType node .
* then we won ' t need a RelabelType node .
*/
*/
result = coerce_to_domain ( node , InvalidOid , - 1 , targetTypeId ,
result = coerce_to_domain ( node , InvalidOid , - 1 , targetTypeId ,
cformat , location , false , false ) ;
ccontext , cformat , location ,
false ) ;
if ( result = = node )
if ( result = = node )
{
{
/*
/*
@ -636,19 +635,17 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
* ' baseTypeMod ' : base type typmod of domain , if known ( pass - 1 if caller
* ' baseTypeMod ' : base type typmod of domain , if known ( pass - 1 if caller
* has not bothered to look this up )
* has not bothered to look this up )
* ' typeId ' : target type to coerce to
* ' typeId ' : target type to coerce to
* ' cformat ' : coercion format
* ' ccontext ' : context indicator to control coercions
* ' cformat ' : coercion display format
* ' location ' : coercion request location
* ' location ' : coercion request location
* ' hideInputCoercion ' : if true , hide the input coercion under this one .
* ' hideInputCoercion ' : if true , hide the input coercion under this one .
* ' lengthCoercionDone ' : if true , caller already accounted for length ,
* ie the input is already of baseTypMod as well as baseTypeId .
*
*
* If the target type isn ' t a domain , the given ' arg ' is returned as - is .
* If the target type isn ' t a domain , the given ' arg ' is returned as - is .
*/
*/
Node *
Node *
coerce_to_domain ( Node * arg , Oid baseTypeId , int32 baseTypeMod , Oid typeId ,
coerce_to_domain ( Node * arg , Oid baseTypeId , int32 baseTypeMod , Oid typeId ,
CoercionForm cformat , int location ,
CoercionContext ccontext , CoercionForm cformat , int location ,
bool hideInputCoercion ,
bool hideInputCoercion )
bool lengthCoercionDone )
{
{
CoerceToDomain * result ;
CoerceToDomain * result ;
@ -677,14 +674,9 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
* would be safe to do anyway , without lots of knowledge about what the
* would be safe to do anyway , without lots of knowledge about what the
* base type thinks the typmod means .
* base type thinks the typmod means .
*/
*/
if ( ! lengthCoercionDone )
arg = coerce_type_typmod ( arg , baseTypeId , baseTypeMod ,
{
ccontext , COERCE_IMPLICIT_CAST , location ,
if ( baseTypeMod > = 0 )
false ) ;
arg = coerce_type_typmod ( arg , baseTypeId , baseTypeMod ,
COERCE_IMPLICIT_CAST , location ,
( cformat ! = COERCE_IMPLICIT_CAST ) ,
false ) ;
}
/*
/*
* Now build the domain coercion node . This represents run - time checking
* Now build the domain coercion node . This represents run - time checking
@ -714,11 +706,14 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
* The caller must have already ensured that the value is of the correct
* The caller must have already ensured that the value is of the correct
* type , typically by applying coerce_type .
* type , typically by applying coerce_type .
*
*
* cformat determines the display properties of the generated node ( if any ) ,
* ccontext may affect semantics , depending on whether the length coercion
* while isExplicit may affect semantics . If hideInputCoercion is true
* function pays attention to the isExplicit flag it ' s passed .
* * and * we generate a node , the input node is forced to IMPLICIT display
*
* form , so that only the typmod coercion node will be visible when
* cformat determines the display properties of the generated node ( if any ) .
* displaying the expression .
*
* If hideInputCoercion is true * and * we generate a node , the input node is
* forced to IMPLICIT display form , so that only the typmod coercion node will
* be visible when displaying the expression .
*
*
* NOTE : this does not need to work on domain types , because any typmod
* NOTE : this does not need to work on domain types , because any typmod
* coercion for a domain is considered to be part of the type coercion
* coercion for a domain is considered to be part of the type coercion
@ -726,8 +721,9 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
*/
*/
static Node *
static Node *
coerce_type_typmod ( Node * node , Oid targetTypeId , int32 targetTypMod ,
coerce_type_typmod ( Node * node , Oid targetTypeId , int32 targetTypMod ,
CoercionForm cformat , int location ,
CoercionContext ccontext , CoercionForm cformat ,
bool isExplicit , bool hideInputCoercion )
int location ,
bool hideInputCoercion )
{
{
CoercionPathType pathtype ;
CoercionPathType pathtype ;
Oid funcId ;
Oid funcId ;
@ -749,8 +745,7 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
node = build_coercion_expression ( node , pathtype , funcId ,
node = build_coercion_expression ( node , pathtype , funcId ,
targetTypeId , targetTypMod ,
targetTypeId , targetTypMod ,
cformat , location ,
ccontext , cformat , location ) ;
isExplicit ) ;
}
}
return node ;
return node ;
@ -799,8 +794,8 @@ build_coercion_expression(Node *node,
CoercionPathType pathtype ,
CoercionPathType pathtype ,
Oid funcId ,
Oid funcId ,
Oid targetTypeId , int32 targetTypMod ,
Oid targetTypeId , int32 targetTypMod ,
CoercionForm cformat , int location ,
CoercionContext ccontext , CoercionForm cformat ,
bool isExplicit )
int location )
{
{
int nargs = 0 ;
int nargs = 0 ;
@ -865,7 +860,7 @@ build_coercion_expression(Node *node,
- 1 ,
- 1 ,
InvalidOid ,
InvalidOid ,
sizeof ( bool ) ,
sizeof ( bool ) ,
BoolGetDatum ( isExplicit ) ,
BoolGetDatum ( ccontext = = COERCION_EXPLICIT ) ,
false ,
false ,
true ) ;
true ) ;
@ -881,19 +876,52 @@ build_coercion_expression(Node *node,
{
{
/* We need to build an ArrayCoerceExpr */
/* We need to build an ArrayCoerceExpr */
ArrayCoerceExpr * acoerce = makeNode ( ArrayCoerceExpr ) ;
ArrayCoerceExpr * acoerce = makeNode ( ArrayCoerceExpr ) ;
CaseTestExpr * ctest = makeNode ( CaseTestExpr ) ;
Oid sourceBaseTypeId ;
int32 sourceBaseTypeMod ;
Oid targetElementType ;
Node * elemexpr ;
/*
* Look through any domain over the source array type . Note we don ' t
* expect that the target type is a domain ; it must be a plain array .
* ( To get to a domain target type , we ' ll do coerce_to_domain later . )
*/
sourceBaseTypeMod = exprTypmod ( node ) ;
sourceBaseTypeId = getBaseTypeAndTypmod ( exprType ( node ) ,
& sourceBaseTypeMod ) ;
/* Set up CaseTestExpr representing one element of source array */
ctest - > typeId = get_element_type ( sourceBaseTypeId ) ;
Assert ( OidIsValid ( ctest - > typeId ) ) ;
ctest - > typeMod = sourceBaseTypeMod ;
ctest - > collation = InvalidOid ; /* Assume coercions don't care */
/* And coerce it to the target element type */
targetElementType = get_element_type ( targetTypeId ) ;
Assert ( OidIsValid ( targetElementType ) ) ;
elemexpr = coerce_to_target_type ( NULL ,
( Node * ) ctest ,
ctest - > typeId ,
targetElementType ,
targetTypMod ,
ccontext ,
cformat ,
location ) ;
if ( elemexpr = = NULL ) /* shouldn't happen */
elog ( ERROR , " failed to coerce array element type as expected " ) ;
acoerce - > arg = ( Expr * ) node ;
acoerce - > arg = ( Expr * ) node ;
acoerce - > elemfuncid = funcId ;
acoerce - > elemexpr = ( Expr * ) elemexpr ;
acoerce - > resulttype = targetTypeId ;
acoerce - > resulttype = targetTypeId ;
/*
/*
* Label the output as having a particular typmod only if we are
* Label the output as having a particular element typmod only if we
* really invoking a length - coercion function , ie one with more than
* ended up with a per - element expression that is labeled that way .
* one argument .
*/
*/
acoerce - > resulttypmod = ( nargs > = 2 ) ? targetTypMod : - 1 ;
acoerce - > resulttypmod = exprTypmod ( elemexpr ) ;
/* resultcollid will be set by parse_collate.c */
/* resultcollid will be set by parse_collate.c */
acoerce - > isExplicit = isExplicit ;
acoerce - > coerceformat = cformat ;
acoerce - > coerceformat = cformat ;
acoerce - > location = location ;
acoerce - > location = location ;
@ -2148,8 +2176,7 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
* COERCION_PATH_RELABELTYPE : binary - compatible cast , no function needed
* COERCION_PATH_RELABELTYPE : binary - compatible cast , no function needed
* * funcid is set to InvalidOid
* * funcid is set to InvalidOid
* COERCION_PATH_ARRAYCOERCE : need an ArrayCoerceExpr node
* COERCION_PATH_ARRAYCOERCE : need an ArrayCoerceExpr node
* * funcid is set to the element cast function , or InvalidOid
* * funcid is set to InvalidOid
* if the array elements are binary - compatible
* COERCION_PATH_COERCEVIAIO : need a CoerceViaIO node
* COERCION_PATH_COERCEVIAIO : need a CoerceViaIO node
* * funcid is set to InvalidOid
* * funcid is set to InvalidOid
*
*
@ -2235,11 +2262,8 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
{
{
/*
/*
* If there ' s no pg_cast entry , perhaps we are dealing with a pair of
* If there ' s no pg_cast entry , perhaps we are dealing with a pair of
* array types . If so , and if the element types have a suitable cast ,
* array types . If so , and if their element types have a conversion
* report that we can coerce with an ArrayCoerceExpr .
* pathway , report that we can coerce with an ArrayCoerceExpr .
*
* Note that the source type can be a domain over array , but not the
* target , because ArrayCoerceExpr won ' t check domain constraints .
*
*
* Hack : disallow coercions to oidvector and int2vector , which
* Hack : disallow coercions to oidvector and int2vector , which
* otherwise tend to capture coercions that should go to " real " array
* otherwise tend to capture coercions that should go to " real " array
@ -2254,7 +2278,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
Oid sourceElem ;
Oid sourceElem ;
if ( ( targetElem = get_element_type ( targetTypeId ) ) ! = InvalidOid & &
if ( ( targetElem = get_element_type ( targetTypeId ) ) ! = InvalidOid & &
( sourceElem = get_base_ element_type ( sourceTypeId ) ) ! = InvalidOid )
( sourceElem = get_element_type ( sourceTypeId ) ) ! = InvalidOid )
{
{
CoercionPathType elempathtype ;
CoercionPathType elempathtype ;
Oid elemfuncid ;
Oid elemfuncid ;
@ -2263,14 +2287,9 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
sourceElem ,
sourceElem ,
ccontext ,
ccontext ,
& elemfuncid ) ;
& elemfuncid ) ;
if ( elempathtype ! = COERCION_PATH_NONE & &
if ( elempathtype ! = COERCION_PATH_NONE )
elempathtype ! = COERCION_PATH_ARRAYCOERCE )
{
{
* funcid = elemfuncid ;
result = COERCION_PATH_ARRAYCOERCE ;
if ( elempathtype = = COERCION_PATH_COERCEVIAIO )
result = COERCION_PATH_COERCEVIAIO ;
else
result = COERCION_PATH_ARRAYCOERCE ;
}
}
}
}
}
}
@ -2311,7 +2330,9 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
* If the given type is a varlena array type , we do not look for a coercion
* If the given type is a varlena array type , we do not look for a coercion
* function associated directly with the array type , but instead look for
* function associated directly with the array type , but instead look for
* one associated with the element type . An ArrayCoerceExpr node must be
* one associated with the element type . An ArrayCoerceExpr node must be
* used to apply such a function .
* used to apply such a function . ( Note : currently , it ' s pointless to
* return the funcid in this case , because it ' ll just get looked up again
* in the recursive construction of the ArrayCoerceExpr ' s elemexpr . )
*
*
* We use the same result enum as find_coercion_pathway , but the only possible
* We use the same result enum as find_coercion_pathway , but the only possible
* result codes are :
* result codes are :