Re: [COMMITTERS] pgsql: Mark JSON error detail messages for translation.

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: [COMMITTERS] pgsql: Mark JSON error detail messages for translation.
Дата
Msg-id 12158.1339604845@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: [COMMITTERS] pgsql: Mark JSON error detail messages for translation.  (Robert Haas <robertmhaas@gmail.com>)
Ответы Re: [COMMITTERS] pgsql: Mark JSON error detail messages for translation.  (Robert Haas <robertmhaas@gmail.com>)
Список pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
> On Wed, Jun 13, 2012 at 11:55 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> In any case, the proposed scheme for providing context requires that
>> you know where the error is before you can identify the context.  I
>> considered schemes that would keep track of the last N characters or
>> line breaks in case one of them proved to be the one we need.  That
>> would add enough cycles to non-error cases to almost certainly not be
>> desirable.  I also considered trying to back up, but that doesn't look
>> promising either for arbitrary multibyte encodings.

> Oh, I see.  :-(

Attached is a complete proposed patch for this, with some further
adjustments to make the output look a bit more like what we use for
SQL error context printouts (in particular, "..." at both ends of the
excerpt when appropriate).

One thing I did not touch, but am less than happy with, is the wording
of this detail message:

        errdetail("Expected string, number, object, array, true, false, or null, but found \"%s\".",
                  token),

This seems uselessly verbose to me.  It could be argued that enumerating
all the options is helpful to rank JSON novices ... but unless you know
exactly what an "object" is and why that's different from the other
options, it's not all that helpful.  I'm inclined to think that
something like this would be better:

        errdetail("Expected JSON value, but found \"%s\".",
                  token),

Thoughts?

            regards, tom lane


diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index e79c294..59335db 100644
*** a/src/backend/utils/adt/json.c
--- b/src/backend/utils/adt/json.c
*************** typedef struct                    /* state of JSON lexe
*** 43,50 ****
      char       *token_start;    /* start of current token within input */
      char       *token_terminator; /* end of previous or current token */
      JsonValueType token_type;    /* type of current token, once it's known */
-     int            line_number;    /* current line number (counting from 1) */
-     char       *line_start;        /* start of current line within input (BROKEN!!) */
  } JsonLexContext;

  typedef enum                    /* states of JSON parser */
--- 43,48 ----
*************** static void json_lex_string(JsonLexConte
*** 78,83 ****
--- 76,82 ----
  static void json_lex_number(JsonLexContext *lex, char *s);
  static void report_parse_error(JsonParseStack *stack, JsonLexContext *lex);
  static void report_invalid_token(JsonLexContext *lex);
+ 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);
*************** json_validate_cstring(char *input)
*** 185,192 ****
      /* Set up lexing context. */
      lex.input = input;
      lex.token_terminator = lex.input;
-     lex.line_number = 1;
-     lex.line_start = input;

      /* Set up parse stack. */
      stacksize = 32;
--- 184,189 ----
*************** json_lex(JsonLexContext *lex)
*** 335,345 ****
      /* Skip leading whitespace. */
      s = lex->token_terminator;
      while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
-     {
-         if (*s == '\n')
-             lex->line_number++;
          s++;
-     }
      lex->token_start = s;

      /* Determine token type. */
--- 332,338 ----
*************** json_lex(JsonLexContext *lex)
*** 350,356 ****
          {
              /* End of string. */
              lex->token_start = NULL;
!             lex->token_terminator = NULL;
          }
          else
          {
--- 343,349 ----
          {
              /* End of string. */
              lex->token_start = NULL;
!             lex->token_terminator = s;
          }
          else
          {
*************** json_lex(JsonLexContext *lex)
*** 397,403 ****
              /*
               * We got some sort of unexpected punctuation or an otherwise
               * unexpected character, so just complain about that one
!              * character.
               */
              lex->token_terminator = s + 1;
              report_invalid_token(lex);
--- 390,397 ----
              /*
               * We got some sort of unexpected punctuation or an otherwise
               * unexpected character, so just complain about that one
!              * character.  (It can't be multibyte because the above loop
!              * will advance over any multibyte characters.)
               */
              lex->token_terminator = s + 1;
              report_invalid_token(lex);
*************** json_lex_string(JsonLexContext *lex)
*** 443,453 ****
                  lex->token_terminator = s;
                  report_invalid_token(lex);
              }
              ereport(ERROR,
                      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                       errmsg("invalid input syntax for type json"),
!                      errdetail("line %d: Character with value \"0x%02x\" must be escaped.",
!                                      lex->line_number, (unsigned char) *s)));
          }
          else if (*s == '\\')
          {
--- 437,449 ----
                  lex->token_terminator = s;
                  report_invalid_token(lex);
              }
+             lex->token_terminator = s + pg_mblen(s);
              ereport(ERROR,
                      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                       errmsg("invalid input syntax for type json"),
!                      errdetail("Character with value 0x%02x must be escaped.",
!                                (unsigned char) *s),
!                      report_json_context(lex)));
          }
          else if (*s == '\\')
          {
*************** json_lex_string(JsonLexContext *lex)
*** 465,502 ****

                  for (i = 1; i <= 4; i++)
                  {
!                     if (s[i] == '\0')
                      {
!                         lex->token_terminator = s + i;
                          report_invalid_token(lex);
                      }
!                     else if (s[i] >= '0' && s[i] <= '9')
!                         ch = (ch * 16) + (s[i] - '0');
!                     else if (s[i] >= 'a' && s[i] <= 'f')
!                         ch = (ch * 16) + (s[i] - 'a') + 10;
!                     else if (s[i] >= 'A' && s[i] <= 'F')
!                         ch = (ch * 16) + (s[i] - 'A') + 10;
                      else
                      {
                          ereport(ERROR,
                                  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                   errmsg("invalid input syntax for type json"),
!                                  errdetail("line %d: \"\\u\" must be followed by four hexadecimal digits.",
!                                                     lex->line_number)));
                      }
                  }
-
-                 /* Account for the four additional bytes we just parsed. */
-                 s += 4;
              }
              else if (strchr("\"\\/bfnrt", *s) == NULL)
              {
                  /* Not a valid string escape, so error out. */
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                           errmsg("invalid input syntax for type json"),
!                          errdetail("line %d: Invalid escape \"\\%s\".",
!                                      lex->line_number, extract_mb_char(s))));
              }
          }
      }
--- 461,499 ----

                  for (i = 1; i <= 4; i++)
                  {
!                     s++;
!                     if (*s == '\0')
                      {
!                         lex->token_terminator = s;
                          report_invalid_token(lex);
                      }
!                     else if (*s >= '0' && *s <= '9')
!                         ch = (ch * 16) + (*s - '0');
!                     else if (*s >= 'a' && *s <= 'f')
!                         ch = (ch * 16) + (*s - 'a') + 10;
!                     else if (*s >= 'A' && *s <= 'F')
!                         ch = (ch * 16) + (*s - 'A') + 10;
                      else
                      {
+                         lex->token_terminator = s + pg_mblen(s);
                          ereport(ERROR,
                                  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                   errmsg("invalid input syntax for type json"),
!                                  errdetail("\"\\u\" must be followed by four hexadecimal digits."),
!                                  report_json_context(lex)));
                      }
                  }
              }
              else if (strchr("\"\\/bfnrt", *s) == NULL)
              {
                  /* Not a valid string escape, so error out. */
+                 lex->token_terminator = s + pg_mblen(s);
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                           errmsg("invalid input syntax for type json"),
!                          errdetail("Invalid string escape \"\\%s\".",
!                                    extract_mb_char(s)),
!                          report_json_context(lex)));
              }
          }
      }
*************** json_lex_number(JsonLexContext *lex, cha
*** 599,666 ****

  /*
   * Report a parse error.
   */
  static void
  report_parse_error(JsonParseStack *stack, JsonLexContext *lex)
  {
!     char       *detail = NULL;
!     char       *token = NULL;
      int            toklen;

      /* Handle case where the input ended prematurely. */
      if (lex->token_start == NULL)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                  errmsg("invalid input syntax for type json: \"%s\"",
!                         lex->input),
!                  errdetail("The input string ended unexpectedly.")));

!     /* Separate out the offending token. */
      toklen = lex->token_terminator - lex->token_start;
      token = palloc(toklen + 1);
      memcpy(token, lex->token_start, toklen);
      token[toklen] = '\0';

!     /* Select correct detail message. */
      if (stack == NULL)
!         detail = "line %d: Expected end of input, but found \"%s\".";
      else
      {
          switch (stack->state)
          {
              case JSON_PARSE_VALUE:
!                 detail = "line %d: Expected string, number, object, array, true, false, or null, but found \"%s\".";
                  break;
              case JSON_PARSE_ARRAY_START:
!                 detail = "line %d: Expected array element or \"]\", but found \"%s\".";
                  break;
              case JSON_PARSE_ARRAY_NEXT:
!                 detail = "line %d: Expected \",\" or \"]\", but found \"%s\".";
                  break;
              case JSON_PARSE_OBJECT_START:
!                 detail = "line %d: Expected string or \"}\", but found \"%s\".";
                  break;
              case JSON_PARSE_OBJECT_LABEL:
!                 detail = "line %d: Expected \":\", but found \"%s\".";
                  break;
              case JSON_PARSE_OBJECT_NEXT:
!                 detail = "line %d: Expected \",\" or \"}\", but found \"%s\".";
                  break;
              case JSON_PARSE_OBJECT_COMMA:
!                 detail = "line %d: Expected string, but found \"%s\".";
                  break;
          }
      }
-
-     ereport(ERROR,
-             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-              errmsg("invalid input syntax for type json: \"%s\"",
-                     lex->input),
-           detail ? errdetail(detail, lex->line_number, token) : 0));
  }

  /*
   * Report an invalid input token.
   */
  static void
  report_invalid_token(JsonLexContext *lex)
--- 596,703 ----

  /*
   * Report a parse error.
+  *
+  * lex->token_start and lex->token_terminator must identify the current token.
   */
  static void
  report_parse_error(JsonParseStack *stack, JsonLexContext *lex)
  {
!     char       *token;
      int            toklen;

      /* Handle case where the input ended prematurely. */
      if (lex->token_start == NULL)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                  errmsg("invalid input syntax for type json"),
!                  errdetail("The input string ended unexpectedly."),
!                  report_json_context(lex)));

!     /* Separate out the current token. */
      toklen = lex->token_terminator - lex->token_start;
      token = palloc(toklen + 1);
      memcpy(token, lex->token_start, toklen);
      token[toklen] = '\0';

!     /* Complain, with the appropriate detail message. */
      if (stack == NULL)
!         ereport(ERROR,
!                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                  errmsg("invalid input syntax for type json"),
!                  errdetail("Expected end of input, but found \"%s\".",
!                            token),
!                  report_json_context(lex)));
      else
      {
          switch (stack->state)
          {
              case JSON_PARSE_VALUE:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected string, number, object, array, true, false, or null, but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
              case JSON_PARSE_ARRAY_START:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected array element or \"]\", but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
              case JSON_PARSE_ARRAY_NEXT:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected \",\" or \"]\", but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
              case JSON_PARSE_OBJECT_START:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected string or \"}\", but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
              case JSON_PARSE_OBJECT_LABEL:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected \":\", but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
              case JSON_PARSE_OBJECT_NEXT:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected \",\" or \"}\", but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
              case JSON_PARSE_OBJECT_COMMA:
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!                          errmsg("invalid input syntax for type json"),
!                          errdetail("Expected string, but found \"%s\".",
!                                    token),
!                          report_json_context(lex)));
                  break;
+             default:
+                 elog(ERROR, "unexpected json parse state: %d",
+                      (int) stack->state);
          }
      }
  }

  /*
   * Report an invalid input token.
+  *
+  * lex->token_start and lex->token_terminator must identify the token.
   */
  static void
  report_invalid_token(JsonLexContext *lex)
*************** report_invalid_token(JsonLexContext *lex
*** 668,673 ****
--- 705,711 ----
      char       *token;
      int            toklen;

+     /* Separate out the offending token. */
      toklen = lex->token_terminator - lex->token_start;
      token = palloc(toklen + 1);
      memcpy(token, lex->token_start, toklen);
*************** report_invalid_token(JsonLexContext *lex
*** 676,683 ****
      ereport(ERROR,
              (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
               errmsg("invalid input syntax for type json"),
!              errdetail("line %d: Token \"%s\" is invalid.",
!                                 lex->line_number, token)));
  }

  /*
--- 714,793 ----
      ereport(ERROR,
              (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
               errmsg("invalid input syntax for type json"),
!              errdetail("Token \"%s\" is invalid.", token),
!              report_json_context(lex)));
! }
!
! /*
!  * Report a CONTEXT line for bogus JSON input.
!  *
!  * lex->token_terminator must be set to identify the spot where we detected
!  * the error.  Note that lex->token_start might be NULL, in case we recognized
!  * error at EOF.
!  *
!  * The return value isn't meaningful, but we make it non-void so that this
!  * can be invoked inside ereport().
!  */
! static int
! report_json_context(JsonLexContext *lex)
! {
!     const char *context_start;
!     const char *context_end;
!     const char *line_start;
!     int            line_number;
!     char       *ctxt;
!     int            ctxtlen;
!     const char *prefix;
!     const char *suffix;
!
!     /* Choose boundaries for the part of the input we will display */
!     context_start = lex->input;
!     context_end = lex->token_terminator;
!     line_start = context_start;
!     line_number = 1;
!     for (;;)
!     {
!         /* Always advance over newlines (context_end test is just paranoia) */
!         if (*context_start == '\n' && context_start < context_end)
!         {
!             context_start++;
!             line_start = context_start;
!             line_number++;
!             continue;
!         }
!         /* Otherwise, done as soon as we are close enough to context_end */
!         if (context_end - context_start < 50)
!             break;
!         /* Advance to next multibyte character */
!         if (IS_HIGHBIT_SET(*context_start))
!             context_start += pg_mblen(context_start);
!         else
!             context_start++;
!     }
!
!     /*
!      * We add "..." to indicate that the excerpt doesn't start at the
!      * beginning of the line ... but if we're within 3 characters of the
!      * beginning of the line, we might as well just show the whole line.
!      */
!     if (context_start - line_start <= 3)
!         context_start = line_start;
!
!     /* Get a null-terminated copy of the data to present */
!     ctxtlen = context_end - context_start;
!     ctxt = palloc(ctxtlen + 1);
!     memcpy(ctxt, context_start, ctxtlen);
!     ctxt[ctxtlen] = '\0';
!
!     /*
!      * Show the context, prefixing "..." if not starting at start of line, and
!      * suffixing "..." if not ending at end of line.
!      */
!     prefix = (context_start > line_start) ? "..." : "";
!     suffix = (*context_end != '\0' && *context_end != '\n' && *context_end != '\r') ? "..." : "";
!
!     return errcontext("JSON data, line %d: %s%s%s",
!                       line_number, prefix, ctxt, suffix);
  }

  /*
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 4b1ad89..1f79e05 100644
*** a/src/test/regress/expected/json.out
--- b/src/test/regress/expected/json.out
*************** SELECT $$''$$::json;            -- ERROR, single
*** 9,15 ****
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT $$''$$::json;
                 ^
! DETAIL:  line 1: Token "'" is invalid.
  SELECT '"abc"'::json;            -- OK
   json
  -------
--- 9,16 ----
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT $$''$$::json;
                 ^
! DETAIL:  Token "'" is invalid.
! CONTEXT:  JSON data, line 1: '...
  SELECT '"abc"'::json;            -- OK
   json
  -------
*************** SELECT '"abc'::json;            -- ERROR, quotes
*** 20,32 ****
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"abc'::json;
                 ^
! DETAIL:  line 1: Token ""abc" is invalid.
  SELECT '"abc
  def"'::json;                    -- ERROR, unescaped newline in string constant
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"abc
                 ^
! DETAIL:  line 1: Character with value "0x0a" must be escaped.
  SELECT '"\n\"\\"'::json;        -- OK, legal escapes
     json
  ----------
--- 21,36 ----
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"abc'::json;
                 ^
! DETAIL:  Token ""abc" is invalid.
! CONTEXT:  JSON data, line 1: "abc
  SELECT '"abc
  def"'::json;                    -- ERROR, unescaped newline in string constant
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"abc
                 ^
! DETAIL:  Character with value 0x0a must be escaped.
! CONTEXT:  JSON data, line 1: "abc
! ...
  SELECT '"\n\"\\"'::json;        -- OK, legal escapes
     json
  ----------
*************** SELECT '"\v"'::json;            -- ERROR, not a v
*** 37,58 ****
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\v"'::json;
                 ^
! DETAIL:  line 1: Invalid escape "\v".
  SELECT '"\u"'::json;            -- ERROR, incomplete escape
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\u"'::json;
                 ^
! DETAIL:  line 1: "\u" must be followed by four hexadecimal digits.
  SELECT '"\u00"'::json;            -- ERROR, incomplete escape
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\u00"'::json;
                 ^
! DETAIL:  line 1: "\u" must be followed by four hexadecimal digits.
  SELECT '"\u000g"'::json;        -- ERROR, g is not a hex digit
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\u000g"'::json;
                 ^
! DETAIL:  line 1: "\u" must be followed by four hexadecimal digits.
  SELECT '"\u0000"'::json;        -- OK, legal escape
     json
  ----------
--- 41,66 ----
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\v"'::json;
                 ^
! DETAIL:  Invalid string escape "\v".
! CONTEXT:  JSON data, line 1: "\v...
  SELECT '"\u"'::json;            -- ERROR, incomplete escape
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\u"'::json;
                 ^
! DETAIL:  "\u" must be followed by four hexadecimal digits.
! CONTEXT:  JSON data, line 1: "\u"
  SELECT '"\u00"'::json;            -- ERROR, incomplete escape
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\u00"'::json;
                 ^
! DETAIL:  "\u" must be followed by four hexadecimal digits.
! CONTEXT:  JSON data, line 1: "\u00"
  SELECT '"\u000g"'::json;        -- ERROR, g is not a hex digit
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '"\u000g"'::json;
                 ^
! DETAIL:  "\u" must be followed by four hexadecimal digits.
! CONTEXT:  JSON data, line 1: "\u000g...
  SELECT '"\u0000"'::json;        -- OK, legal escape
     json
  ----------
*************** SELECT '01'::json;                -- ERROR, not vali
*** 82,88 ****
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '01'::json;
                 ^
! DETAIL:  line 1: Token "01" is invalid.
  SELECT '0.1'::json;                -- OK
   json
  ------
--- 90,97 ----
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '01'::json;
                 ^
! DETAIL:  Token "01" is invalid.
! CONTEXT:  JSON data, line 1: 01
  SELECT '0.1'::json;                -- OK
   json
  ------
*************** SELECT '1f2'::json;                -- ERROR
*** 111,127 ****
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '1f2'::json;
                 ^
! DETAIL:  line 1: Token "1f2" is invalid.
  SELECT '0.x1'::json;            -- ERROR
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '0.x1'::json;
                 ^
! DETAIL:  line 1: Token "0.x1" is invalid.
  SELECT '1.3ex100'::json;        -- ERROR
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '1.3ex100'::json;
                 ^
! DETAIL:  line 1: Token "1.3ex100" is invalid.
  -- Arrays.
  SELECT '[]'::json;                -- OK
   json
--- 120,139 ----
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '1f2'::json;
                 ^
! DETAIL:  Token "1f2" is invalid.
! CONTEXT:  JSON data, line 1: 1f2
  SELECT '0.x1'::json;            -- ERROR
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '0.x1'::json;
                 ^
! DETAIL:  Token "0.x1" is invalid.
! CONTEXT:  JSON data, line 1: 0.x1
  SELECT '1.3ex100'::json;        -- ERROR
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '1.3ex100'::json;
                 ^
! DETAIL:  Token "1.3ex100" is invalid.
! CONTEXT:  JSON data, line 1: 1.3ex100
  -- Arrays.
  SELECT '[]'::json;                -- OK
   json
*************** SELECT '[1,2]'::json;            -- OK
*** 142,161 ****
  (1 row)

  SELECT '[1,2,]'::json;            -- ERROR, trailing comma
! ERROR:  invalid input syntax for type json: "[1,2,]"
  LINE 1: SELECT '[1,2,]'::json;
                 ^
! DETAIL:  line 1: Expected string, number, object, array, true, false, or null, but found "]".
  SELECT '[1,2'::json;            -- ERROR, no closing bracket
! ERROR:  invalid input syntax for type json: "[1,2"
  LINE 1: SELECT '[1,2'::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
  SELECT '[1,[2]'::json;            -- ERROR, no closing bracket
! ERROR:  invalid input syntax for type json: "[1,[2]"
  LINE 1: SELECT '[1,[2]'::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
  -- Objects.
  SELECT '{}'::json;                -- OK
   json
--- 154,176 ----
  (1 row)

  SELECT '[1,2,]'::json;            -- ERROR, trailing comma
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '[1,2,]'::json;
                 ^
! DETAIL:  Expected string, number, object, array, true, false, or null, but found "]".
! CONTEXT:  JSON data, line 1: [1,2,]
  SELECT '[1,2'::json;            -- ERROR, no closing bracket
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '[1,2'::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
+ CONTEXT:  JSON data, line 1: [1,2
  SELECT '[1,[2]'::json;            -- ERROR, no closing bracket
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '[1,[2]'::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
+ CONTEXT:  JSON data, line 1: [1,[2]
  -- Objects.
  SELECT '{}'::json;                -- OK
   json
*************** SELECT '{}'::json;                -- OK
*** 164,173 ****
  (1 row)

  SELECT '{"abc"}'::json;            -- ERROR, no value
! ERROR:  invalid input syntax for type json: "{"abc"}"
  LINE 1: SELECT '{"abc"}'::json;
                 ^
! DETAIL:  line 1: Expected ":", but found "}".
  SELECT '{"abc":1}'::json;        -- OK
     json
  -----------
--- 179,189 ----
  (1 row)

  SELECT '{"abc"}'::json;            -- ERROR, no value
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc"}'::json;
                 ^
! DETAIL:  Expected ":", but found "}".
! CONTEXT:  JSON data, line 1: {"abc"}
  SELECT '{"abc":1}'::json;        -- OK
     json
  -----------
*************** SELECT '{"abc":1}'::json;        -- OK
*** 175,199 ****
  (1 row)

  SELECT '{1:"abc"}'::json;        -- ERROR, keys must be strings
! ERROR:  invalid input syntax for type json: "{1:"abc"}"
  LINE 1: SELECT '{1:"abc"}'::json;
                 ^
! DETAIL:  line 1: Expected string or "}", but found "1".
  SELECT '{"abc",1}'::json;        -- ERROR, wrong separator
! ERROR:  invalid input syntax for type json: "{"abc",1}"
  LINE 1: SELECT '{"abc",1}'::json;
                 ^
! DETAIL:  line 1: Expected ":", but found ",".
  SELECT '{"abc"=1}'::json;        -- ERROR, totally wrong separator
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc"=1}'::json;
                 ^
! DETAIL:  line 1: Token "=" is invalid.
  SELECT '{"abc"::1}'::json;        -- ERROR, another wrong separator
! ERROR:  invalid input syntax for type json: "{"abc"::1}"
  LINE 1: SELECT '{"abc"::1}'::json;
                 ^
! DETAIL:  line 1: Expected string, number, object, array, true, false, or null, but found ":".
  SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::json; -- OK
                            json
  ---------------------------------------------------------
--- 191,219 ----
  (1 row)

  SELECT '{1:"abc"}'::json;        -- ERROR, keys must be strings
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{1:"abc"}'::json;
                 ^
! DETAIL:  Expected string or "}", but found "1".
! CONTEXT:  JSON data, line 1: {1...
  SELECT '{"abc",1}'::json;        -- ERROR, wrong separator
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc",1}'::json;
                 ^
! DETAIL:  Expected ":", but found ",".
! CONTEXT:  JSON data, line 1: {"abc",...
  SELECT '{"abc"=1}'::json;        -- ERROR, totally wrong separator
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc"=1}'::json;
                 ^
! DETAIL:  Token "=" is invalid.
! CONTEXT:  JSON data, line 1: {"abc"=...
  SELECT '{"abc"::1}'::json;        -- ERROR, another wrong separator
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc"::1}'::json;
                 ^
! DETAIL:  Expected string, number, object, array, true, false, or null, but found ":".
! CONTEXT:  JSON data, line 1: {"abc"::...
  SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::json; -- OK
                            json
  ---------------------------------------------------------
*************** SELECT '{"abc":1,"def":2,"ghi":[3,4],"hi
*** 201,215 ****
  (1 row)

  SELECT '{"abc":1:2}'::json;        -- ERROR, colon in wrong spot
! ERROR:  invalid input syntax for type json: "{"abc":1:2}"
  LINE 1: SELECT '{"abc":1:2}'::json;
                 ^
! DETAIL:  line 1: Expected "," or "}", but found ":".
  SELECT '{"abc":1,3}'::json;        -- ERROR, no value
! ERROR:  invalid input syntax for type json: "{"abc":1,3}"
  LINE 1: SELECT '{"abc":1,3}'::json;
                 ^
! DETAIL:  line 1: Expected string, but found "3".
  -- Miscellaneous stuff.
  SELECT 'true'::json;            -- OK
   json
--- 221,237 ----
  (1 row)

  SELECT '{"abc":1:2}'::json;        -- ERROR, colon in wrong spot
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc":1:2}'::json;
                 ^
! DETAIL:  Expected "," or "}", but found ":".
! CONTEXT:  JSON data, line 1: {"abc":1:...
  SELECT '{"abc":1,3}'::json;        -- ERROR, no value
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '{"abc":1,3}'::json;
                 ^
! DETAIL:  Expected string, but found "3".
! CONTEXT:  JSON data, line 1: {"abc":1,3...
  -- Miscellaneous stuff.
  SELECT 'true'::json;            -- OK
   json
*************** SELECT ' true '::json;            -- OK, even wit
*** 236,270 ****
  (1 row)

  SELECT 'true false'::json;        -- ERROR, too many values
! ERROR:  invalid input syntax for type json: "true false"
  LINE 1: SELECT 'true false'::json;
                 ^
! DETAIL:  line 1: Expected end of input, but found "false".
  SELECT 'true, false'::json;        -- ERROR, too many values
! ERROR:  invalid input syntax for type json: "true, false"
  LINE 1: SELECT 'true, false'::json;
                 ^
! DETAIL:  line 1: Expected end of input, but found ",".
  SELECT 'truf'::json;            -- ERROR, not a keyword
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT 'truf'::json;
                 ^
! DETAIL:  line 1: Token "truf" is invalid.
  SELECT 'trues'::json;            -- ERROR, not a keyword
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT 'trues'::json;
                 ^
! DETAIL:  line 1: Token "trues" is invalid.
  SELECT ''::json;                -- ERROR, no value
! ERROR:  invalid input syntax for type json: ""
  LINE 1: SELECT ''::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
  SELECT '    '::json;            -- ERROR, no value
! ERROR:  invalid input syntax for type json: "    "
  LINE 1: SELECT '    '::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
  --constructors
  -- array_to_json
  SELECT array_to_json(array(select 1 as a));
--- 258,298 ----
  (1 row)

  SELECT 'true false'::json;        -- ERROR, too many values
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT 'true false'::json;
                 ^
! DETAIL:  Expected end of input, but found "false".
! CONTEXT:  JSON data, line 1: true false
  SELECT 'true, false'::json;        -- ERROR, too many values
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT 'true, false'::json;
                 ^
! DETAIL:  Expected end of input, but found ",".
! CONTEXT:  JSON data, line 1: true,...
  SELECT 'truf'::json;            -- ERROR, not a keyword
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT 'truf'::json;
                 ^
! DETAIL:  Token "truf" is invalid.
! CONTEXT:  JSON data, line 1: truf
  SELECT 'trues'::json;            -- ERROR, not a keyword
  ERROR:  invalid input syntax for type json
  LINE 1: SELECT 'trues'::json;
                 ^
! DETAIL:  Token "trues" is invalid.
! CONTEXT:  JSON data, line 1: trues
  SELECT ''::json;                -- ERROR, no value
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT ''::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
+ CONTEXT:  JSON data, line 1:
  SELECT '    '::json;            -- ERROR, no value
! ERROR:  invalid input syntax for type json
  LINE 1: SELECT '    '::json;
                 ^
  DETAIL:  The input string ended unexpectedly.
+ CONTEXT:  JSON data, line 1:
  --constructors
  -- array_to_json
  SELECT array_to_json(array(select 1 as a));

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Bruce Momjian
Дата:
Сообщение: Re: Re: [GENERAL] pg_upgrade from 9.0.7 to 9.1.3: duplicate key pg_authid_oid_index
Следующее
От: Robert Haas
Дата:
Сообщение: uncataloged tables are a vestigial husk