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