]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/json.c
Fix initialization of fake LSN for unlogged relations
[postgresql] / src / backend / utils / adt / json.c
index 97a5b85516fa8d4be0e4a351263f52d3538ef76c..d4ba3bd87db344305738250db64733f13593ce22 100644 (file)
@@ -3,7 +3,7 @@
  * 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
@@ -78,32 +78,32 @@ typedef struct JsonAggState
 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 */
@@ -207,12 +207,12 @@ IsValidJsonNumber(const char *str, int len)
         */
        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;
        }
 
@@ -1506,7 +1506,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
                        {
                                char            buf[MAXDATELEN + 1];
 
-                               JsonEncodeDateTime(buf, val, DATEOID);
+                               JsonEncodeDateTime(buf, val, DATEOID, NULL);
                                appendStringInfo(result, "\"%s\"", buf);
                        }
                        break;
@@ -1514,7 +1514,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
                        {
                                char            buf[MAXDATELEN + 1];
 
-                               JsonEncodeDateTime(buf, val, TIMESTAMPOID);
+                               JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL);
                                appendStringInfo(result, "\"%s\"", buf);
                        }
                        break;
@@ -1522,7 +1522,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
                        {
                                char            buf[MAXDATELEN + 1];
 
-                               JsonEncodeDateTime(buf, val, TIMESTAMPTZOID);
+                               JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL);
                                appendStringInfo(result, "\"%s\"", buf);
                        }
                        break;
@@ -1550,10 +1550,11 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
 /*
  * 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);
@@ -1630,11 +1631,30 @@ JsonEncodeDateTime(char *buf, Datum value, Oid typid)
                                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),
@@ -1843,7 +1863,7 @@ add_json(Datum val, bool is_null, StringInfo result,
 /*
  * SQL function array_to_json(row)
  */
-extern Datum
+Datum
 array_to_json(PG_FUNCTION_ARGS)
 {
        Datum           array = PG_GETARG_DATUM(0);
@@ -1859,7 +1879,7 @@ array_to_json(PG_FUNCTION_ARGS)
 /*
  * SQL function array_to_json(row, prettybool)
  */
-extern Datum
+Datum
 array_to_json_pretty(PG_FUNCTION_ARGS)
 {
        Datum           array = PG_GETARG_DATUM(0);
@@ -1876,7 +1896,7 @@ array_to_json_pretty(PG_FUNCTION_ARGS)
 /*
  * SQL function row_to_json(row)
  */
-extern Datum
+Datum
 row_to_json(PG_FUNCTION_ARGS)
 {
        Datum           array = PG_GETARG_DATUM(0);
@@ -1892,7 +1912,7 @@ row_to_json(PG_FUNCTION_ARGS)
 /*
  * SQL function row_to_json(row, prettybool)
  */
-extern Datum
+Datum
 row_to_json_pretty(PG_FUNCTION_ARGS)
 {
        Datum           array = PG_GETARG_DATUM(0);
@@ -2192,7 +2212,9 @@ json_build_object(PG_FUNCTION_ARGS)
                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();