@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / parser / parse_type . c , v 1.91 2007 / 06 / 15 20 : 56 : 50 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / parser / parse_type . c , v 1.92 2007 / 11 / 11 19 : 22 : 49 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -26,26 +26,46 @@
# include "utils/syscache.h"
static int32 typenameTypeMod ( ParseState * pstate , const TypeName * typename ,
Type typ ) ;
/*
* LookupTypeName
* Given a TypeName object , get the OID of the referenced type .
* Returns InvalidOid if no such type can be found .
* Given a TypeName object , lookup the pg_type syscache entry of the type .
* Returns NULL if no such type can be found . If the type is found ,
* the typmod value represented in the TypeName struct is computed and
* stored into * typmod_p .
*
* NB : on success , the caller must ReleaseSysCache the type tuple when done
* with it .
*
* NB : direct callers of this function MUST check typisdefined before assuming
* that the type is fully valid . Most code should go through typenameType
* or typenameTypeId instead .
*
* NB : even if the returned OID is not InvalidOid , the type might be
* just a shell . Caller should check typisdefined before using the type .
* typmod_p can be passed as NULL if the caller does not care to know the
* typmod value , but the typmod decoration ( if any ) will be validated anyway ,
* except in the case where the type is not found . Note that if the type is
* found but is a shell , and there is typmod decoration , an error will be
* thrown - - - this is intentional .
*
* pstate is only used for error location info , and may be NULL .
*/
Oid
LookupTypeName ( ParseState * pstate , const TypeName * typename )
Type
LookupTypeName ( ParseState * pstate , const TypeName * typename ,
int32 * typmod_p )
{
Oid restype ;
Oid typoid ;
HeapTuple tup ;
int32 typmod ;
/* Easy if it's an internally generated TypeName */
if ( typename - > names = = NIL )
return typename - > typeid ;
if ( typename - > pct_type )
{
/* We have the OID already if it's an internally generated TypeName */
typoid = typename - > typeid ;
}
else if ( typename - > pct_type )
{
/* Handle %TYPE reference to type of an existing field */
RangeVar * rel = makeRangeVar ( NULL , NULL ) ;
@ -96,7 +116,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
errmsg ( " column \" %s \" of relation \" %s \" does not exist " ,
field , rel - > relname ) ,
parser_errposition ( pstate , typename - > location ) ) ) ;
restype = get_atttype ( relid , attnum ) ;
typoid = get_atttype ( relid , attnum ) ;
/* this construct should never have an array indicator */
Assert ( typename - > arrayBounds = = NIL ) ;
@ -105,7 +125,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
ereport ( NOTICE ,
( errmsg ( " type reference %s converted to %s " ,
TypeNameToString ( typename ) ,
format_type_be ( restype ) ) ) ) ;
format_type_be ( typoid ) ) ) ) ;
}
else
{
@ -122,130 +142,86 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
Oid namespaceId ;
namespaceId = LookupExplicitNamespace ( schemaname ) ;
restype = GetSysCacheOid ( TYPENAMENSP ,
PointerGetDatum ( typname ) ,
ObjectIdGetDatum ( namespaceId ) ,
0 , 0 ) ;
typoid = GetSysCacheOid ( TYPENAMENSP ,
PointerGetDatum ( typname ) ,
ObjectIdGetDatum ( namespaceId ) ,
0 , 0 ) ;
}
else
{
/* Unqualified type name, so search the search path */
restype = TypenameGetTypid ( typname ) ;
typoid = TypenameGetTypid ( typname ) ;
}
/* If an array reference, return the array type instead */
if ( typename - > arrayBounds ! = NIL )
restype = get_array_type ( restype ) ;
typoid = get_array_type ( typoid ) ;
}
return restype ;
}
/*
* appendTypeNameToBuffer
* Append a string representing the name of a TypeName to a StringInfo .
* This is the shared guts of TypeNameToString and TypeNameListToString .
*
* NB : this must work on TypeNames that do not describe any actual type ;
* it is mostly used for reporting lookup errors .
*/
static void
appendTypeNameToBuffer ( const TypeName * typename , StringInfo string )
{
if ( typename - > names ! = NIL )
{
/* Emit possibly-qualified name as-is */
ListCell * l ;
foreach ( l , typename - > names )
{
if ( l ! = list_head ( typename - > names ) )
appendStringInfoChar ( string , ' . ' ) ;
appendStringInfoString ( string , strVal ( lfirst ( l ) ) ) ;
}
}
else
if ( ! OidIsValid ( typoid ) )
{
/* Look up internally-specified type */
appendStringInfoString ( string , format_type_be ( typename - > typeid ) ) ;
if ( typmod_p )
* typmod_p = - 1 ;
return NULL ;
}
/*
* Add decoration as needed , but only for fields considered by
* LookupTypeName
*/
if ( typename - > pct_type )
appendStringInfoString ( string , " %TYPE " ) ;
if ( typename - > arrayBounds ! = NIL )
appendStringInfoString ( string , " [] " ) ;
}
/*
* TypeNameToString
* Produce a string representing the name of a TypeName .
*
* NB : this must work on TypeNames that do not describe any actual type ;
* it is mostly used for reporting lookup errors .
*/
char *
TypeNameToString ( const TypeName * typename )
{
StringInfoData string ;
initStringInfo ( & string ) ;
appendTypeNameToBuffer ( typename , & string ) ;
return string . data ;
}
tup = SearchSysCache ( TYPEOID ,
ObjectIdGetDatum ( typoid ) ,
0 , 0 , 0 ) ;
if ( ! HeapTupleIsValid ( tup ) ) /* should not happen */
elog ( ERROR , " cache lookup failed for type %u " , typoid ) ;
/*
* TypeNameListToString
* Produce a string representing the name ( s ) of a List of TypeNames
*/
char *
TypeNameListToString ( List * typenames )
{
StringInfoData string ;
ListCell * l ;
typmod = typenameTypeMod ( pstate , typename , ( Type ) tup ) ;
initStringInfo ( & string ) ;
foreach ( l , typenames )
{
TypeName * typename = ( TypeName * ) lfirst ( l ) ;
if ( typmod_p )
* typmod_p = typmod ;
Assert ( IsA ( typename , TypeName ) ) ;
if ( l ! = list_head ( typenames ) )
appendStringInfoChar ( & string , ' , ' ) ;
appendTypeNameToBuffer ( typename , & string ) ;
}
return string . data ;
return ( Type ) tup ;
}
/*
* typenameTypeId - given a TypeName , return the type ' s OID
* typenameType - given a TypeName , return a Type structure and typmod
*
* This is equivalent to LookupTypeName , except that this will report
* a suitable error message if the type cannot be found or is not defined .
* Callers of this can therefore assume the result is a fully valid type .
*/
Oid
typenameTypeId ( ParseState * pstate , const TypeName * typename )
Type
typenameType ( ParseState * pstate , const TypeName * typename , int32 * typmod_p )
{
Oid typoid ;
Type tup ;
typoid = LookupTypeName ( pstate , typename ) ;
if ( ! OidIsValid ( typoid ) )
tup = LookupTypeName ( pstate , typename , typmod_p ) ;
if ( tup = = NULL )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " type \" %s \" does not exist " ,
TypeNameToString ( typename ) ) ,
parser_errposition ( pstate , typename - > location ) ) ) ;
if ( ! get_typisdefined ( typoid ) )
if ( ! ( ( Form_pg_type ) GETSTRUCT ( tup ) ) - > typisdefined )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " type \" %s \" is only a shell " ,
TypeNameToString ( typename ) ) ,
parser_errposition ( pstate , typename - > location ) ) ) ;
return tup ;
}
/*
* typenameTypeId - given a TypeName , return the type ' s OID and typmod
*
* This is equivalent to typenameType , but we only hand back the type OID
* not the syscache entry .
*/
Oid
typenameTypeId ( ParseState * pstate , const TypeName * typename , int32 * typmod_p )
{
Oid typoid ;
Type tup ;
tup = typenameType ( pstate , typename , typmod_p ) ;
typoid = HeapTupleGetOid ( tup ) ;
ReleaseSysCache ( tup ) ;
return typoid ;
}
@ -257,13 +233,12 @@ typenameTypeId(ParseState *pstate, const TypeName *typename)
* illegal for the data type .
*
* The actual type OID represented by the TypeName must already have been
* determined ( usually by typenameTypeId ( ) ) , and is passed as typeId .
* looked up , and is passed as " typ " .
*
* pstate is only used for error location info , and may be NULL .
*/
int32
typenameTypeMod ( ParseState * pstate , const TypeName * typename ,
Oid typeId )
static int32
typenameTypeMod ( ParseState * pstate , const TypeName * typename , Type typ )
{
int32 result ;
Oid typmodin ;
@ -272,14 +247,23 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename,
ListCell * l ;
ArrayType * arrtypmod ;
Assert ( OidIsValid ( typeId ) ) ;
/* Return prespecified typmod if no typmod expressions */
if ( typename - > typmods = = NIL )
return typename - > typemod ;
/* Else, type had better accept typmods */
typmodin = get_typmodin ( typeId ) ;
/*
* Else , type had better accept typmods . We give a special error
* message for the shell - type case , since a shell couldn ' t possibly
* have a typmodin function .
*/
if ( ! ( ( Form_pg_type ) GETSTRUCT ( typ ) ) - > typisdefined )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " type modifier cannot be specified for shell type \" %s \" " ,
TypeNameToString ( typename ) ) ,
parser_errposition ( pstate , typename - > location ) ) ) ;
typmodin = ( ( Form_pg_type ) GETSTRUCT ( typ ) ) - > typmodin ;
if ( typmodin = = InvalidOid )
ereport ( ERROR ,
@ -349,36 +333,83 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename,
}
/*
* typenameType - given a TypeName , return a Type structure
* appendTypeNameToBuffer
* Append a string representing the name of a TypeName to a StringInfo .
* This is the shared guts of TypeNameToString and TypeNameListToString .
*
* This is equivalent to typenameTypeId + syscache fetch of Type tuple .
* NB : caller must ReleaseSysCache the type tuple when done with it .
* NB : this must work on TypeNames that do not describe any actual type ;
* it is mostly used for reporting lookup errors .
*/
Type
typenameType ( ParseState * pstate , const TypeName * typename )
static void
appendTypeNameToBuffer ( const TypeName * typename , StringInfo string )
{
Oid typoid ;
HeapTuple tup ;
if ( typename - > names ! = NIL )
{
/* Emit possibly-qualified name as-is */
ListCell * l ;
typoid = LookupTypeName ( pstate , typename ) ;
if ( ! OidIsValid ( typoid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " type \" %s \" does not exist " ,
TypeNameToString ( typename ) ) ,
parser_errposition ( pstate , typename - > location ) ) ) ;
tup = SearchSysCache ( TYPEOID ,
ObjectIdGetDatum ( typoid ) ,
0 , 0 , 0 ) ;
if ( ! HeapTupleIsValid ( tup ) ) /* should not happen */
elog ( ERROR , " cache lookup failed for type %u " , typoid ) ;
if ( ! ( ( Form_pg_type ) GETSTRUCT ( tup ) ) - > typisdefined )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " type \" %s \" is only a shell " ,
TypeNameToString ( typename ) ) ,
parser_errposition ( pstate , typename - > location ) ) ) ;
return ( Type ) tup ;
foreach ( l , typename - > names )
{
if ( l ! = list_head ( typename - > names ) )
appendStringInfoChar ( string , ' . ' ) ;
appendStringInfoString ( string , strVal ( lfirst ( l ) ) ) ;
}
}
else
{
/* Look up internally-specified type */
appendStringInfoString ( string , format_type_be ( typename - > typeid ) ) ;
}
/*
* Add decoration as needed , but only for fields considered by
* LookupTypeName
*/
if ( typename - > pct_type )
appendStringInfoString ( string , " %TYPE " ) ;
if ( typename - > arrayBounds ! = NIL )
appendStringInfoString ( string , " [] " ) ;
}
/*
* TypeNameToString
* Produce a string representing the name of a TypeName .
*
* NB : this must work on TypeNames that do not describe any actual type ;
* it is mostly used for reporting lookup errors .
*/
char *
TypeNameToString ( const TypeName * typename )
{
StringInfoData string ;
initStringInfo ( & string ) ;
appendTypeNameToBuffer ( typename , & string ) ;
return string . data ;
}
/*
* TypeNameListToString
* Produce a string representing the name ( s ) of a List of TypeNames
*/
char *
TypeNameListToString ( List * typenames )
{
StringInfoData string ;
ListCell * l ;
initStringInfo ( & string ) ;
foreach ( l , typenames )
{
TypeName * typename = ( TypeName * ) lfirst ( l ) ;
Assert ( IsA ( typename , TypeName ) ) ;
if ( l ! = list_head ( typenames ) )
appendStringInfoChar ( & string , ' , ' ) ;
appendTypeNameToBuffer ( typename , & string ) ;
}
return string . data ;
}
/* return a Type structure, given a type id */
@ -507,7 +538,7 @@ pts_error_callback(void *arg)
* the string and convert it to a type OID and type modifier .
*/
void
parseTypeString ( const char * str , Oid * type_id , int32 * typmod )
parseTypeString ( const char * str , Oid * type_id , int32 * typmod_p )
{
StringInfoData buf ;
List * raw_parsetree_list ;
@ -579,8 +610,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
if ( typename - > setof )
goto fail ;
* type_id = typenameTypeId ( NULL , typename ) ;
* typmod = typenameTypeMod ( NULL , typename , * type_id ) ;
* type_id = typenameTypeId ( NULL , typename , typmod_p ) ;
pfree ( buf . data ) ;