Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 73ce2a0

Browse files
committed
Move some code from jsonapi.c to jsonfuncs.c.
Specifically, move those functions that depend on ereport() from jsonapi.c to jsonfuncs.c, in preparation for allowing jsonapi.c to be used from frontend code. A few cases where elog(ERROR, ...) is used for can't-happen conditions are left alone; we can handle those in some other way in frontend code. Reviewed by Mark Dilger and Andrew Dunstan. Discussion: http://postgr.es/m/CA+TgmoYfOXhd27MUDGioVh6QtpD0C1K-f6ObSA10AWiHBAL5bA@mail.gmail.com
1 parent 1f3a021 commit 73ce2a0

File tree

6 files changed

+140
-141
lines changed

6 files changed

+140
-141
lines changed

src/backend/utils/adt/json.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include "utils/date.h"
2424
#include "utils/datetime.h"
2525
#include "utils/json.h"
26-
#include "utils/jsonapi.h"
26+
#include "utils/jsonfuncs.h"
2727
#include "utils/lsyscache.h"
2828
#include "utils/typcache.h"
2929

src/backend/utils/adt/jsonapi.c

+2-125
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ static JsonParseErrorType parse_object(JsonLexContext *lex, JsonSemAction *sem);
4444
static JsonParseErrorType parse_array_element(JsonLexContext *lex, JsonSemAction *sem);
4545
static JsonParseErrorType parse_array(JsonLexContext *lex, JsonSemAction *sem);
4646
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex);
47-
static int report_json_context(JsonLexContext *lex);
4847
static char *extract_token(JsonLexContext *lex);
4948

5049
/* the null action object used for pure validation */
@@ -128,25 +127,13 @@ IsValidJsonNumber(const char *str, int len)
128127
}
129128

130129
/*
131-
* makeJsonLexContext
130+
* makeJsonLexContextCstringLen
132131
*
133-
* lex constructor, with or without StringInfo object
134-
* for de-escaped lexemes.
132+
* lex constructor, with or without StringInfo object for de-escaped lexemes.
135133
*
136134
* Without is better as it makes the processing faster, so only make one
137135
* if really required.
138-
*
139-
* If you already have the json as a text* value, use the first of these
140-
* functions, otherwise use makeJsonLexContextCstringLen().
141136
*/
142-
JsonLexContext *
143-
makeJsonLexContext(text *json, bool need_escapes)
144-
{
145-
return makeJsonLexContextCstringLen(VARDATA_ANY(json),
146-
VARSIZE_ANY_EXHDR(json),
147-
need_escapes);
148-
}
149-
150137
JsonLexContext *
151138
makeJsonLexContextCstringLen(char *json, int len, bool need_escapes)
152139
{
@@ -202,23 +189,6 @@ pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
202189
return result;
203190
}
204191

205-
/*
206-
* pg_parse_json_or_ereport
207-
*
208-
* This fuction is like pg_parse_json, except that it does not return a
209-
* JsonParseErrorType. Instead, in case of any failure, this function will
210-
* ereport(ERROR).
211-
*/
212-
void
213-
pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem)
214-
{
215-
JsonParseErrorType result;
216-
217-
result = pg_parse_json(lex, sem);
218-
if (result != JSON_SUCCESS)
219-
json_ereport_error(result, lex);
220-
}
221-
222192
/*
223193
* json_count_array_elements
224194
*
@@ -1038,27 +1008,6 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
10381008
}
10391009
}
10401010

1041-
/*
1042-
* Report a JSON error.
1043-
*/
1044-
void
1045-
json_ereport_error(JsonParseErrorType error, JsonLexContext *lex)
1046-
{
1047-
if (error == JSON_UNICODE_HIGH_ESCAPE ||
1048-
error == JSON_UNICODE_CODE_POINT_ZERO)
1049-
ereport(ERROR,
1050-
(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
1051-
errmsg("unsupported Unicode escape sequence"),
1052-
errdetail("%s", json_errdetail(error, lex)),
1053-
report_json_context(lex)));
1054-
else
1055-
ereport(ERROR,
1056-
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1057-
errmsg("invalid input syntax for type %s", "json"),
1058-
errdetail("%s", json_errdetail(error, lex)),
1059-
report_json_context(lex)));
1060-
}
1061-
10621011
/*
10631012
* Construct a detail message for a JSON error.
10641013
*/
@@ -1118,78 +1067,6 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
11181067
}
11191068
}
11201069

1121-
/*
1122-
* Report a CONTEXT line for bogus JSON input.
1123-
*
1124-
* lex->token_terminator must be set to identify the spot where we detected
1125-
* the error. Note that lex->token_start might be NULL, in case we recognized
1126-
* error at EOF.
1127-
*
1128-
* The return value isn't meaningful, but we make it non-void so that this
1129-
* can be invoked inside ereport().
1130-
*/
1131-
static int
1132-
report_json_context(JsonLexContext *lex)
1133-
{
1134-
const char *context_start;
1135-
const char *context_end;
1136-
const char *line_start;
1137-
int line_number;
1138-
char *ctxt;
1139-
int ctxtlen;
1140-
const char *prefix;
1141-
const char *suffix;
1142-
1143-
/* Choose boundaries for the part of the input we will display */
1144-
context_start = lex->input;
1145-
context_end = lex->token_terminator;
1146-
line_start = context_start;
1147-
line_number = 1;
1148-
for (;;)
1149-
{
1150-
/* Always advance over newlines */
1151-
if (context_start < context_end && *context_start == '\n')
1152-
{
1153-
context_start++;
1154-
line_start = context_start;
1155-
line_number++;
1156-
continue;
1157-
}
1158-
/* Otherwise, done as soon as we are close enough to context_end */
1159-
if (context_end - context_start < 50)
1160-
break;
1161-
/* Advance to next multibyte character */
1162-
if (IS_HIGHBIT_SET(*context_start))
1163-
context_start += pg_mblen(context_start);
1164-
else
1165-
context_start++;
1166-
}
1167-
1168-
/*
1169-
* We add "..." to indicate that the excerpt doesn't start at the
1170-
* beginning of the line ... but if we're within 3 characters of the
1171-
* beginning of the line, we might as well just show the whole line.
1172-
*/
1173-
if (context_start - line_start <= 3)
1174-
context_start = line_start;
1175-
1176-
/* Get a null-terminated copy of the data to present */
1177-
ctxtlen = context_end - context_start;
1178-
ctxt = palloc(ctxtlen + 1);
1179-
memcpy(ctxt, context_start, ctxtlen);
1180-
ctxt[ctxtlen] = '\0';
1181-
1182-
/*
1183-
* Show the context, prefixing "..." if not starting at start of line, and
1184-
* suffixing "..." if not ending at end of line.
1185-
*/
1186-
prefix = (context_start > line_start) ? "..." : "";
1187-
suffix = (lex->token_type != JSON_TOKEN_END && context_end - lex->input < lex->input_length && *context_end != '\n' && *context_end != '\r') ? "..." : "";
1188-
1189-
return errcontext("JSON data, line %d: %s%s%s",
1190-
line_number, prefix, ctxt, suffix);
1191-
}
1192-
11931070
/*
11941071
* Extract the current token from a lexing context, for error reporting.
11951072
*/

src/backend/utils/adt/jsonb.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
#include "utils/date.h"
2424
#include "utils/datetime.h"
2525
#include "utils/json.h"
26-
#include "utils/jsonapi.h"
2726
#include "utils/jsonb.h"
27+
#include "utils/jsonfuncs.h"
2828
#include "utils/lsyscache.h"
2929
#include "utils/syscache.h"
3030
#include "utils/typcache.h"

src/backend/utils/adt/jsonfuncs.c

+126
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ typedef struct JsObject
329329
hash_destroy((jso)->val.json_hash); \
330330
} while (0)
331331

332+
static int report_json_context(JsonLexContext *lex);
333+
332334
/* semantic action functions for json_object_keys */
333335
static void okeys_object_field_start(void *state, char *fname, bool isnull);
334336
static void okeys_array_start(void *state);
@@ -484,6 +486,37 @@ static void transform_string_values_object_field_start(void *state, char *fname,
484486
static void transform_string_values_array_element_start(void *state, bool isnull);
485487
static void transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype);
486488

489+
/*
490+
* pg_parse_json_or_ereport
491+
*
492+
* This fuction is like pg_parse_json, except that it does not return a
493+
* JsonParseErrorType. Instead, in case of any failure, this function will
494+
* ereport(ERROR).
495+
*/
496+
void
497+
pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem)
498+
{
499+
JsonParseErrorType result;
500+
501+
result = pg_parse_json(lex, sem);
502+
if (result != JSON_SUCCESS)
503+
json_ereport_error(result, lex);
504+
}
505+
506+
/*
507+
* makeJsonLexContext
508+
*
509+
* This is like makeJsonLexContextCstringLen, but it accepts a text value
510+
* directly.
511+
*/
512+
JsonLexContext *
513+
makeJsonLexContext(text *json, bool need_escapes)
514+
{
515+
return makeJsonLexContextCstringLen(VARDATA_ANY(json),
516+
VARSIZE_ANY_EXHDR(json),
517+
need_escapes);
518+
}
519+
487520
/*
488521
* SQL function json_object_keys
489522
*
@@ -573,6 +606,99 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
573606
SRF_RETURN_DONE(funcctx);
574607
}
575608

609+
/*
610+
* Report a JSON error.
611+
*/
612+
void
613+
json_ereport_error(JsonParseErrorType error, JsonLexContext *lex)
614+
{
615+
if (error == JSON_UNICODE_HIGH_ESCAPE ||
616+
error == JSON_UNICODE_CODE_POINT_ZERO)
617+
ereport(ERROR,
618+
(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
619+
errmsg("unsupported Unicode escape sequence"),
620+
errdetail("%s", json_errdetail(error, lex)),
621+
report_json_context(lex)));
622+
else
623+
ereport(ERROR,
624+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
625+
errmsg("invalid input syntax for type %s", "json"),
626+
errdetail("%s", json_errdetail(error, lex)),
627+
report_json_context(lex)));
628+
}
629+
630+
/*
631+
* Report a CONTEXT line for bogus JSON input.
632+
*
633+
* lex->token_terminator must be set to identify the spot where we detected
634+
* the error. Note that lex->token_start might be NULL, in case we recognized
635+
* error at EOF.
636+
*
637+
* The return value isn't meaningful, but we make it non-void so that this
638+
* can be invoked inside ereport().
639+
*/
640+
static int
641+
report_json_context(JsonLexContext *lex)
642+
{
643+
const char *context_start;
644+
const char *context_end;
645+
const char *line_start;
646+
int line_number;
647+
char *ctxt;
648+
int ctxtlen;
649+
const char *prefix;
650+
const char *suffix;
651+
652+
/* Choose boundaries for the part of the input we will display */
653+
context_start = lex->input;
654+
context_end = lex->token_terminator;
655+
line_start = context_start;
656+
line_number = 1;
657+
for (;;)
658+
{
659+
/* Always advance over newlines */
660+
if (context_start < context_end && *context_start == '\n')
661+
{
662+
context_start++;
663+
line_start = context_start;
664+
line_number++;
665+
continue;
666+
}
667+
/* Otherwise, done as soon as we are close enough to context_end */
668+
if (context_end - context_start < 50)
669+
break;
670+
/* Advance to next multibyte character */
671+
if (IS_HIGHBIT_SET(*context_start))
672+
context_start += pg_mblen(context_start);
673+
else
674+
context_start++;
675+
}
676+
677+
/*
678+
* We add "..." to indicate that the excerpt doesn't start at the
679+
* beginning of the line ... but if we're within 3 characters of the
680+
* beginning of the line, we might as well just show the whole line.
681+
*/
682+
if (context_start - line_start <= 3)
683+
context_start = line_start;
684+
685+
/* Get a null-terminated copy of the data to present */
686+
ctxtlen = context_end - context_start;
687+
ctxt = palloc(ctxtlen + 1);
688+
memcpy(ctxt, context_start, ctxtlen);
689+
ctxt[ctxtlen] = '\0';
690+
691+
/*
692+
* Show the context, prefixing "..." if not starting at start of line, and
693+
* suffixing "..." if not ending at end of line.
694+
*/
695+
prefix = (context_start > line_start) ? "..." : "";
696+
suffix = (lex->token_type != JSON_TOKEN_END && context_end - lex->input < lex->input_length && *context_end != '\n' && *context_end != '\r') ? "..." : "";
697+
698+
return errcontext("JSON data, line %d: %s%s%s",
699+
line_number, prefix, ctxt, suffix);
700+
}
701+
576702

577703
Datum
578704
json_object_keys(PG_FUNCTION_ARGS)

src/include/utils/jsonapi.h

+1-14
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,6 @@ typedef struct JsonSemAction
126126
extern JsonParseErrorType pg_parse_json(JsonLexContext *lex,
127127
JsonSemAction *sem);
128128

129-
/*
130-
* Same thing, but signal errors via ereport(ERROR) instead of returning
131-
* a result code.
132-
*/
133-
extern void pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem);
134-
135129
/* the null action object used for pure validation */
136130
extern JsonSemAction nullSemAction;
137131

@@ -148,25 +142,18 @@ extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex,
148142
int *elements);
149143

150144
/*
151-
* constructors for JsonLexContext, with or without strval element.
145+
* constructor for JsonLexContext, with or without strval element.
152146
* If supplied, the strval element will contain a de-escaped version of
153147
* the lexeme. However, doing this imposes a performance penalty, so
154148
* it should be avoided if the de-escaped lexeme is not required.
155-
*
156-
* If you already have the json as a text* value, use the first of these
157-
* functions, otherwise use makeJsonLexContextCstringLen().
158149
*/
159-
extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes);
160150
extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
161151
int len,
162152
bool need_escapes);
163153

164154
/* lex one token */
165155
extern JsonParseErrorType json_lex(JsonLexContext *lex);
166156

167-
/* report an error during json lexing or parsing */
168-
extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex);
169-
170157
/* construct an error detail string for a json error */
171158
extern char *json_errdetail(JsonParseErrorType error, JsonLexContext *lex);
172159

src/include/utils/jsonfuncs.h

+9
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ typedef void (*JsonIterateStringValuesAction) (void *state, char *elem_value, in
3636
/* an action that will be applied to each value in transform_json(b)_values functions */
3737
typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value, int elem_len);
3838

39+
/* build a JsonLexContext from a text datum */
40+
extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes);
41+
42+
/* try to parse json, and ereport(ERROR) on failure */
43+
extern void pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem);
44+
45+
/* report an error during json lexing or parsing */
46+
extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex);
47+
3948
extern uint32 parse_jsonb_index_flags(Jsonb *jb);
4049
extern void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state,
4150
JsonIterateStringValuesAction action);

0 commit comments

Comments
 (0)