]> granicus.if.org Git - postgresql/commitdiff
Minor code review for json.c.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Jun 2012 20:23:45 +0000 (16:23 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Jun 2012 20:23:45 +0000 (16:23 -0400)
Improve commenting, conform to project style for use of ++ etc.
No functional changes.

src/backend/utils/adt/json.c

index 3d69e50e8e070408f05c598ccbbda525ea28776d..e79c2946d0c650b854233ec96051462cb1c6a21f 100644 (file)
@@ -25,9 +25,9 @@
 #include "utils/json.h"
 #include "utils/typcache.h"
 
-typedef enum
+typedef enum                                   /* types of JSON values */
 {
-       JSON_VALUE_INVALID,
+       JSON_VALUE_INVALID,                     /* non-value tokens are reported as this */
        JSON_VALUE_STRING,
        JSON_VALUE_NUMBER,
        JSON_VALUE_OBJECT,
@@ -37,17 +37,17 @@ typedef enum
        JSON_VALUE_NULL
 } JsonValueType;
 
-typedef struct
+typedef struct                                 /* state of JSON lexer */
 {
-       char       *input;
-       char       *token_start;
-       char       *token_terminator;
-       JsonValueType token_type;
-       int                     line_number;
-       char       *line_start;
+       char       *input;                      /* whole string being parsed */
+       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
+typedef enum                                   /* states of JSON parser */
 {
        JSON_PARSE_VALUE,                       /* expecting a value */
        JSON_PARSE_ARRAY_START,         /* saw '[', expecting value or ']' */
@@ -58,17 +58,18 @@ typedef enum
        JSON_PARSE_OBJECT_COMMA         /* saw object ',', expecting next label */
 } JsonParseState;
 
-typedef struct JsonParseStack
+typedef struct JsonParseStack  /* the parser state has to be stackable */
 {
        JsonParseState state;
+       /* currently only need the state enum, but maybe someday more stuff */
 } JsonParseStack;
 
-typedef enum
+typedef enum                                   /* required operations on state stack */
 {
-       JSON_STACKOP_NONE,
-       JSON_STACKOP_PUSH,
-       JSON_STACKOP_PUSH_WITH_PUSHBACK,
-       JSON_STACKOP_POP
+       JSON_STACKOP_NONE,                      /* no-op */
+       JSON_STACKOP_PUSH,                      /* push new JSON_PARSE_VALUE stack item */
+       JSON_STACKOP_PUSH_WITH_PUSHBACK, /* push, then rescan current token */
+       JSON_STACKOP_POP                        /* pop, or expect end of input if no stack */
 } JsonStackOp;
 
 static void json_validate_cstring(char *input);
@@ -78,17 +79,28 @@ 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 char *extract_mb_char(char *s);
-static void composite_to_json(Datum composite, StringInfo result, bool use_line_feeds);
+static void composite_to_json(Datum composite, StringInfo result,
+                                                         bool use_line_feeds);
 static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
                                  Datum *vals, bool *nulls, int *valcount,
                                  TYPCATEGORY tcategory, Oid typoutputfunc,
                                  bool use_line_feeds);
-static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds);
+static void array_to_json_internal(Datum array, StringInfo result,
+                                                                  bool use_line_feeds);
 
 /* fake type category for JSON so we can distinguish it in datum_to_json */
 #define TYPCATEGORY_JSON 'j'
 /* letters appearing in numeric output that aren't valid in a JSON number */
 #define NON_NUMERIC_LETTER "NnAaIiFfTtYy"
+/* chars to consider as part of an alphanumeric token */
+#define JSON_ALPHANUMERIC_CHAR(c)  \
+       (((c) >= 'a' && (c) <= 'z') || \
+        ((c) >= 'A' && (c) <= 'Z') || \
+        ((c) >= '0' && (c) <= '9') || \
+        (c) == '_' || \
+        IS_HIGHBIT_SET(c))
+
+
 /*
  * Input.
  */
@@ -99,6 +111,7 @@ json_in(PG_FUNCTION_ARGS)
 
        json_validate_cstring(text);
 
+       /* Internal representation is the same as text, for now */
        PG_RETURN_TEXT_P(cstring_to_text(text));
 }
 
@@ -108,6 +121,7 @@ json_in(PG_FUNCTION_ARGS)
 Datum
 json_out(PG_FUNCTION_ARGS)
 {
+       /* we needn't detoast because text_to_cstring will handle that */
        Datum           txt = PG_GETARG_DATUM(0);
 
        PG_RETURN_CSTRING(TextDatumGetCString(txt));
@@ -119,8 +133,8 @@ json_out(PG_FUNCTION_ARGS)
 Datum
 json_send(PG_FUNCTION_ARGS)
 {
-       StringInfoData buf;
        text       *t = PG_GETARG_TEXT_PP(0);
+       StringInfoData buf;
 
        pq_begintypsend(&buf);
        pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
@@ -176,7 +190,7 @@ json_validate_cstring(char *input)
 
        /* Set up parse stack. */
        stacksize = 32;
-       stacktop = palloc(sizeof(JsonParseStack) * stacksize);
+       stacktop = (JsonParseStack *) palloc(sizeof(JsonParseStack) * stacksize);
        stack = stacktop;
        stack->state = JSON_PARSE_VALUE;
 
@@ -212,8 +226,8 @@ redo:
                                        stack->state = JSON_PARSE_ARRAY_NEXT;
                                else if (lex.token_start[0] == ']')
                                        op = JSON_STACKOP_POP;
-                               else if (lex.token_start[0] == '['
-                                                || lex.token_start[0] == '{')
+                               else if (lex.token_start[0] == '[' ||
+                                                lex.token_start[0] == '{')
                                {
                                        stack->state = JSON_PARSE_ARRAY_NEXT;
                                        op = JSON_STACKOP_PUSH_WITH_PUSHBACK;
@@ -234,15 +248,15 @@ redo:
                        case JSON_PARSE_OBJECT_START:
                                if (lex.token_type == JSON_VALUE_STRING)
                                        stack->state = JSON_PARSE_OBJECT_LABEL;
-                               else if (lex.token_type == JSON_VALUE_INVALID
-                                                && lex.token_start[0] == '}')
+                               else if (lex.token_type == JSON_VALUE_INVALID &&
+                                                lex.token_start[0] == '}')
                                        op = JSON_STACKOP_POP;
                                else
                                        report_parse_error(stack, &lex);
                                break;
                        case JSON_PARSE_OBJECT_LABEL:
-                               if (lex.token_type == JSON_VALUE_INVALID
-                                       && lex.token_start[0] == ':')
+                               if (lex.token_type == JSON_VALUE_INVALID &&
+                                       lex.token_start[0] == ':')
                                {
                                        stack->state = JSON_PARSE_OBJECT_NEXT;
                                        op = JSON_STACKOP_PUSH;
@@ -271,19 +285,21 @@ redo:
                                         (int) stack->state);
                }
 
-               /* Push or pop the stack, if needed. */
+               /* Push or pop the state stack, if needed. */
                switch (op)
                {
                        case JSON_STACKOP_PUSH:
                        case JSON_STACKOP_PUSH_WITH_PUSHBACK:
-                               ++stack;
+                               stack++;
                                if (stack >= &stacktop[stacksize])
                                {
+                                       /* Need to enlarge the stack. */
                                        int                     stackoffset = stack - stacktop;
 
-                                       stacksize = stacksize + 32;
-                                       stacktop = repalloc(stacktop,
-                                                                               sizeof(JsonParseStack) * stacksize);
+                                       stacksize += 32;
+                                       stacktop = (JsonParseStack *)
+                                               repalloc(stacktop,
+                                                                sizeof(JsonParseStack) * stacksize);
                                        stack = stacktop + stackoffset;
                                }
                                stack->state = JSON_PARSE_VALUE;
@@ -299,7 +315,7 @@ redo:
                                                report_parse_error(NULL, &lex);
                                        return;
                                }
-                               --stack;
+                               stack--;
                                break;
                        case JSON_STACKOP_NONE:
                                /* nothing to do */
@@ -321,15 +337,15 @@ json_lex(JsonLexContext *lex)
        while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
        {
                if (*s == '\n')
-                       ++lex->line_number;
-               ++s;
+                       lex->line_number++;
+               s++;
        }
        lex->token_start = s;
 
        /* Determine token type. */
-       if (strchr("{}[],:", s[0]))
+       if (strchr("{}[],:", s[0]) != NULL)
        {
-               /* strchr() doesn't return false on a NUL input. */
+               /* strchr() is willing to match a zero byte, so test for that. */
                if (s[0] == '\0')
                {
                        /* End of string. */
@@ -373,17 +389,16 @@ json_lex(JsonLexContext *lex)
                 * whole word as an unexpected token, rather than just some
                 * unintuitive prefix thereof.
                 */
-               for (p = s; (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')
-                        || (*p >= '0' && *p <= '9') || *p == '_' || IS_HIGHBIT_SET(*p);
-                        ++p)
-                       ;
+               for (p = s; JSON_ALPHANUMERIC_CHAR(*p); p++)
+                       /* skip */ ;
 
-               /*
-                * We got some sort of unexpected punctuation or an otherwise
-                * unexpected character, so just complain about that one character.
-                */
                if (p == s)
                {
+                       /*
+                        * 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);
                }
@@ -415,9 +430,9 @@ json_lex(JsonLexContext *lex)
 static void
 json_lex_string(JsonLexContext *lex)
 {
-       char       *s = lex->token_start + 1;
+       char       *s;
 
-       for (s = lex->token_start + 1; *s != '"'; ++s)
+       for (s = lex->token_start + 1; *s != '"'; s++)
        {
                /* Per RFC4627, these characters MUST be escaped. */
                if ((unsigned char) *s < 32)
@@ -437,7 +452,7 @@ json_lex_string(JsonLexContext *lex)
                else if (*s == '\\')
                {
                        /* OK, we have an escape character. */
-                       ++s;
+                       s++;
                        if (*s == '\0')
                        {
                                lex->token_terminator = s;
@@ -448,7 +463,7 @@ json_lex_string(JsonLexContext *lex)
                                int                     i;
                                int                     ch = 0;
 
-                               for (i = 1; i <= 4; ++i)
+                               for (i = 1; i <= 4; i++)
                                {
                                        if (s[i] == '\0')
                                        {
@@ -474,9 +489,9 @@ json_lex_string(JsonLexContext *lex)
                                /* Account for the four additional bytes we just parsed. */
                                s += 4;
                        }
-                       else if (!strchr("\"\\/bfnrt", *s))
+                       else if (strchr("\"\\/bfnrt", *s) == NULL)
                        {
-                               /* Error out. */
+                               /* Not a valid string escape, so error out. */
                                ereport(ERROR,
                                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                                 errmsg("invalid input syntax for type json"),
@@ -527,12 +542,12 @@ json_lex_number(JsonLexContext *lex, char *s)
 
        /* Part (2): parse main digit string. */
        if (*s == '0')
-               ++s;
+               s++;
        else if (*s >= '1' && *s <= '9')
        {
                do
                {
-                       ++s;
+                       s++;
                } while (*s >= '0' && *s <= '9');
        }
        else
@@ -541,14 +556,14 @@ json_lex_number(JsonLexContext *lex, char *s)
        /* Part (3): parse optional decimal portion. */
        if (*s == '.')
        {
-               ++s;
+               s++;
                if (*s < '0' || *s > '9')
                        error = true;
                else
                {
                        do
                        {
-                               ++s;
+                               s++;
                        } while (*s >= '0' && *s <= '9');
                }
        }
@@ -556,26 +571,29 @@ json_lex_number(JsonLexContext *lex, char *s)
        /* Part (4): parse optional exponent. */
        if (*s == 'e' || *s == 'E')
        {
-               ++s;
+               s++;
                if (*s == '+' || *s == '-')
-                       ++s;
+                       s++;
                if (*s < '0' || *s > '9')
                        error = true;
                else
                {
                        do
                        {
-                               ++s;
+                               s++;
                        } while (*s >= '0' && *s <= '9');
                }
        }
 
-       /* Check for trailing garbage. */
-       for (p = s; (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')
-                || (*p >= '0' && *p <= '9') || *p == '_' || IS_HIGHBIT_SET(*p); ++p)
-               ;
+       /*
+        * Check for trailing garbage.  As in json_lex(), any alphanumeric stuff
+        * here should be considered part of the token for error-reporting
+        * purposes.
+        */
+       for (p = s; JSON_ALPHANUMERIC_CHAR(*p); p++)
+               error = true;
        lex->token_terminator = p;
-       if (p > s || error)
+       if (error)
                report_invalid_token(lex);
 }
 
@@ -597,7 +615,7 @@ report_parse_error(JsonParseStack *stack, JsonLexContext *lex)
                                                lex->input),
                                 errdetail("The input string ended unexpectedly.")));
 
-       /* Work out the offending token. */
+       /* Separate out the offending token. */
        toklen = lex->token_terminator - lex->token_start;
        token = palloc(toklen + 1);
        memcpy(token, lex->token_start, toklen);
@@ -680,14 +698,15 @@ extract_mb_char(char *s)
 }
 
 /*
- * Turn a scalar Datum into JSON. Hand off a non-scalar datum to
- * composite_to_json or array_to_json_internal as appropriate.
+ * Turn a scalar Datum into JSON, appending the string to "result".
+ *
+ * Hand off a non-scalar datum to composite_to_json or array_to_json_internal
+ * as appropriate.
  */
-static inline void
-datum_to_json(Datum val, bool is_null, StringInfo result, TYPCATEGORY tcategory,
-                         Oid typoutputfunc)
+static void
+datum_to_json(Datum val, bool is_null, StringInfo result,
+                         TYPCATEGORY tcategory, Oid typoutputfunc)
 {
-
        char       *outputstr;
 
        if (is_null)
@@ -735,6 +754,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result, TYPCATEGORY tcategory,
                        outputstr = OidOutputFunctionCall(typoutputfunc, val);
                        escape_json(result, outputstr);
                        pfree(outputstr);
+                       break;
        }
 }
 
@@ -748,9 +768,8 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
                                  bool *nulls, int *valcount, TYPCATEGORY tcategory,
                                  Oid typoutputfunc, bool use_line_feeds)
 {
-
        int                     i;
-       char       *sep;
+       const char *sep;
 
        Assert(dim < ndims);
 
@@ -797,7 +816,6 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
        int                     count = 0;
        Datum      *elements;
        bool       *nulls;
-
        int16           typlen;
        bool            typbyval;
        char            typalign,
@@ -852,7 +870,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
                           *tuple;
        int                     i;
        bool            needsep = false;
-       char       *sep;
+       const char *sep;
 
        sep = use_line_feeds ? ",\n " : ",";