@ -25,6 +25,7 @@
# include "parser/parse_coerce.h"
# include "utils/array.h"
# include "utils/builtins.h"
# include "utils/date.h"
# include "utils/datetime.h"
# include "utils/lsyscache.h"
# include "utils/json.h"
@ -55,8 +56,9 @@ typedef enum /* type categories for datum_to_json */
JSONTYPE_NULL , /* null, so we didn't bother to identify */
JSONTYPE_BOOL , /* boolean (built-in types only) */
JSONTYPE_NUMERIC , /* numeric (ditto) */
JSONTYPE_TIMESTAMP , /* we use special formatting for timestamp */
JSONTYPE_TIMESTAMPTZ , /* ... and timestamptz */
JSONTYPE_DATE , /* we use special formatting for datetimes */
JSONTYPE_TIMESTAMP ,
JSONTYPE_TIMESTAMPTZ ,
JSONTYPE_JSON , /* JSON itself (and JSONB) */
JSONTYPE_ARRAY , /* array */
JSONTYPE_COMPOSITE , /* composite */
@ -1267,6 +1269,10 @@ json_categorize_type(Oid typoid,
* tcategory = JSONTYPE_NUMERIC ;
break ;
case DATEOID :
* tcategory = JSONTYPE_DATE ;
break ;
case TIMESTAMPOID :
* tcategory = JSONTYPE_TIMESTAMP ;
break ;
@ -1348,7 +1354,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
tcategory = = JSONTYPE_CAST ) )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " key value must be scalar, not array, composite, or json " ) ) ) ;
errmsg ( " key value must be scalar, not array, composite, or json " ) ) ) ;
switch ( tcategory )
{
@ -1388,6 +1394,30 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
}
pfree ( outputstr ) ;
break ;
case JSONTYPE_DATE :
{
DateADT date ;
struct pg_tm tm ;
char buf [ MAXDATELEN + 1 ] ;
date = DatumGetDateADT ( val ) ;
/* XSD doesn't support infinite values */
if ( DATE_NOT_FINITE ( date ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ) ,
errmsg ( " date out of range " ) ,
errdetail ( " JSON does not support infinite date values. " ) ) ) ;
else
{
j2date ( date + POSTGRES_EPOCH_JDATE ,
& ( tm . tm_year ) , & ( tm . tm_mon ) , & ( tm . tm_mday ) ) ;
EncodeDateOnly ( & tm , USE_XSD_DATES , buf ) ;
}
appendStringInfo ( result , " \" %s \" " , buf ) ;
}
break ;
case JSONTYPE_TIMESTAMP :
{
Timestamp timestamp ;
@ -1410,7 +1440,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
( errcode ( ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ) ,
errmsg ( " timestamp out of range " ) ) ) ;
appendStringInfo ( result , " \" %s \" " , buf ) ;
appendStringInfo ( result , " \" %s \" " , buf ) ;
}
break ;
case JSONTYPE_TIMESTAMPTZ :
@ -1437,7 +1467,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
( errcode ( ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ) ,
errmsg ( " timestamp out of range " ) ) ) ;
appendStringInfo ( result , " \" %s \" " , buf ) ;
appendStringInfo ( result , " \" %s \" " , buf ) ;
}
break ;
case JSONTYPE_JSON :
@ -2305,20 +2335,21 @@ escape_json(StringInfo buf, const char *str)
appendStringInfoString ( buf , " \\ \" " ) ;
break ;
case ' \\ ' :
/*
* Unicode escapes are passed through as is . There is no
* requirement that they denote a valid character in the
* server encoding - indeed that is a big part of their
* usefulness .
*
* All we require is that they consist of \ uXXXX where
* the Xs are hexadecimal digits . It is the responsibility
* of the caller of , say , to_json ( ) to make sure that the
* unicode escape is valid .
* All we require is that they consist of \ uXXXX where the Xs
* are hexadecimal digits . It is the responsibility of the
* caller of , say , to_json ( ) to make sure that the unicod e
* escape is valid .
*
* In the case of a jsonb string value being escaped , the
* only unicode escape that should be present is \ u0000 ,
* all the other unicode escapes will have been resolved .
* In the case of a jsonb string value being escaped , the only
* unicode escape that should be present is \ u0000 , all the
* other unicode escapes will have been resolved .
*/
if ( p [ 1 ] = = ' u ' & &
isxdigit ( ( unsigned char ) p [ 2 ] ) & &