* json.c
* JSON data type support.
*
- * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
static inline void json_lex(JsonLexContext *lex);
static inline void json_lex_string(JsonLexContext *lex);
static inline void json_lex_number(JsonLexContext *lex, char *s,
- bool *num_err, int *total_len);
+ bool *num_err, int *total_len);
static inline void parse_scalar(JsonLexContext *lex, JsonSemAction *sem);
static void parse_object_field(JsonLexContext *lex, JsonSemAction *sem);
static void parse_object(JsonLexContext *lex, JsonSemAction *sem);
static void parse_array_element(JsonLexContext *lex, JsonSemAction *sem);
static void parse_array(JsonLexContext *lex, JsonSemAction *sem);
-static void report_parse_error(JsonParseContext ctx, JsonLexContext *lex);
-static void report_invalid_token(JsonLexContext *lex);
+static void report_parse_error(JsonParseContext ctx, JsonLexContext *lex) pg_attribute_noreturn();
+static void report_invalid_token(JsonLexContext *lex) pg_attribute_noreturn();
static int report_json_context(JsonLexContext *lex);
static char *extract_mb_char(char *s);
static void composite_to_json(Datum composite, StringInfo result,
- bool use_line_feeds);
+ bool use_line_feeds);
static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
- Datum *vals, bool *nulls, int *valcount,
- JsonTypeCategory tcategory, Oid outfuncoid,
- bool use_line_feeds);
+ Datum *vals, bool *nulls, int *valcount,
+ JsonTypeCategory tcategory, Oid outfuncoid,
+ bool use_line_feeds);
static void array_to_json_internal(Datum array, StringInfo result,
- bool use_line_feeds);
+ bool use_line_feeds);
static void json_categorize_type(Oid typoid,
- JsonTypeCategory *tcategory,
- Oid *outfuncoid);
+ JsonTypeCategory *tcategory,
+ Oid *outfuncoid);
static void datum_to_json(Datum val, bool is_null, StringInfo result,
- JsonTypeCategory tcategory, Oid outfuncoid,
- bool key_scalar);
+ JsonTypeCategory tcategory, Oid outfuncoid,
+ bool key_scalar);
static void add_json(Datum val, bool is_null, StringInfo result,
- Oid val_type, bool key_scalar);
+ Oid val_type, bool key_scalar);
static text *catenate_stringinfo_string(StringInfo buffer, const char *addon);
/* the null action object used for pure validation */
*/
if (*str == '-')
{
- dummy_lex.input = (char *) str + 1;
+ dummy_lex.input = unconstify(char *, str) +1;
dummy_lex.input_length = len - 1;
}
else
{
- dummy_lex.input = (char *) str;
+ dummy_lex.input = unconstify(char *, str);
dummy_lex.input_length = len;
}
{
char buf[MAXDATELEN + 1];
- JsonEncodeDateTime(buf, val, DATEOID);
+ JsonEncodeDateTime(buf, val, DATEOID, NULL);
appendStringInfo(result, "\"%s\"", buf);
}
break;
{
char buf[MAXDATELEN + 1];
- JsonEncodeDateTime(buf, val, TIMESTAMPOID);
+ JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL);
appendStringInfo(result, "\"%s\"", buf);
}
break;
{
char buf[MAXDATELEN + 1];
- JsonEncodeDateTime(buf, val, TIMESTAMPTZOID);
+ JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL);
appendStringInfo(result, "\"%s\"", buf);
}
break;
/*
* Encode 'value' of datetime type 'typid' into JSON string in ISO format using
- * optionally preallocated buffer 'buf'.
+ * optionally preallocated buffer 'buf'. Optional 'tzp' determines time-zone
+ * offset (in seconds) in which we want to show timestamptz.
*/
char *
-JsonEncodeDateTime(char *buf, Datum value, Oid typid)
+JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp)
{
if (!buf)
buf = palloc(MAXDATELEN + 1);
const char *tzn = NULL;
timestamp = DatumGetTimestampTz(value);
+
+ /*
+ * If a time zone is specified, we apply the time-zone shift,
+ * convert timestamptz to pg_tm as if it were without a time
+ * zone, and then use the specified time zone for converting
+ * the timestamp into a string.
+ */
+ if (tzp)
+ {
+ tz = *tzp;
+ timestamp -= (TimestampTz) tz * USECS_PER_SEC;
+ }
+
/* Same as timestamptz_out(), but forcing DateStyle */
if (TIMESTAMP_NOT_FINITE(timestamp))
EncodeSpecialTimestamp(timestamp, buf);
- else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
+ else if (timestamp2tm(timestamp, tzp ? NULL : &tz, &tm, &fsec,
+ tzp ? NULL : &tzn, NULL) == 0)
+ {
+ if (tzp)
+ tm.tm_isdst = 1; /* set time-zone presence flag */
+
EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
+ }
else
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
/*
* SQL function array_to_json(row)
*/
-extern Datum
+Datum
array_to_json(PG_FUNCTION_ARGS)
{
Datum array = PG_GETARG_DATUM(0);
/*
* SQL function array_to_json(row, prettybool)
*/
-extern Datum
+Datum
array_to_json_pretty(PG_FUNCTION_ARGS)
{
Datum array = PG_GETARG_DATUM(0);
/*
* SQL function row_to_json(row)
*/
-extern Datum
+Datum
row_to_json(PG_FUNCTION_ARGS)
{
Datum array = PG_GETARG_DATUM(0);
/*
* SQL function row_to_json(row, prettybool)
*/
-extern Datum
+Datum
row_to_json_pretty(PG_FUNCTION_ARGS)
{
Datum array = PG_GETARG_DATUM(0);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument list must have even number of elements"),
- errhint("The arguments of json_build_object() must consist of alternating keys and values.")));
+ /* translator: %s is a SQL function name */
+ errhint("The arguments of %s must consist of alternating keys and values.",
+ "json_build_object()")));
result = makeStringInfo();