Move jsonapi.c and jsonapi.h to src/common.

To make this work, (1) makeJsonLexContextCstringLen now takes the
encoding to be used as an argument; (2) check_stack_depth() is made to
do nothing in frontend code, and (3) elog(ERROR, ...) is changed to
pg_log_fatal + exit in frontend code.

Mark Dilger, reviewed and slightly revised by me.

Discussion: http://postgr.es/m/CA+TgmoYfOXhd27MUDGioVh6QtpD0C1K-f6ObSA10AWiHBAL5bA@mail.gmail.com
This commit is contained in:
Robert Haas 2020-01-29 10:19:24 -05:00
parent dc788668bb
commit beb4699091
12 changed files with 41 additions and 20 deletions

View File

@ -7,13 +7,13 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/jsonapi.h"
#include "funcapi.h" #include "funcapi.h"
#include "hstore.h" #include "hstore.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/json.h" #include "utils/json.h"
#include "utils/jsonapi.h"
#include "utils/jsonb.h" #include "utils/jsonb.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h" #include "utils/memutils.h"

View File

@ -13,10 +13,10 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "common/jsonapi.h"
#include "tsearch/ts_cache.h" #include "tsearch/ts_cache.h"
#include "tsearch/ts_utils.h" #include "tsearch/ts_utils.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/jsonapi.h"
#include "utils/jsonfuncs.h" #include "utils/jsonfuncs.h"

View File

@ -16,11 +16,11 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "common/jsonapi.h"
#include "funcapi.h" #include "funcapi.h"
#include "tsearch/ts_cache.h" #include "tsearch/ts_cache.h"
#include "tsearch/ts_utils.h" #include "tsearch/ts_utils.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/jsonapi.h"
#include "utils/jsonfuncs.h" #include "utils/jsonfuncs.h"
#include "utils/varlena.h" #include "utils/varlena.h"

View File

@ -44,7 +44,6 @@ OBJS = \
int.o \ int.o \
int8.o \ int8.o \
json.o \ json.o \
jsonapi.o \
jsonb.o \ jsonb.o \
jsonb_gin.o \ jsonb_gin.o \
jsonb_op.o \ jsonb_op.o \

View File

@ -127,7 +127,7 @@ json_recv(PG_FUNCTION_ARGS)
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
/* Validate it. */ /* Validate it. */
lex = makeJsonLexContextCstringLen(str, nbytes, false); lex = makeJsonLexContextCstringLen(str, nbytes, GetDatabaseEncoding(), false);
pg_parse_json_or_ereport(lex, &nullSemAction); pg_parse_json_or_ereport(lex, &nullSemAction);
PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes)); PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));

View File

@ -261,7 +261,7 @@ jsonb_from_cstring(char *json, int len)
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
memset(&sem, 0, sizeof(sem)); memset(&sem, 0, sizeof(sem));
lex = makeJsonLexContextCstringLen(json, len, true); lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
sem.semstate = (void *) &state; sem.semstate = (void *) &state;

View File

@ -15,12 +15,12 @@
#include "catalog/pg_collation.h" #include "catalog/pg_collation.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/jsonapi.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/datetime.h" #include "utils/datetime.h"
#include "utils/hashutils.h" #include "utils/hashutils.h"
#include "utils/json.h" #include "utils/json.h"
#include "utils/jsonapi.h"
#include "utils/jsonb.h" #include "utils/jsonb.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/varlena.h" #include "utils/varlena.h"

View File

@ -18,6 +18,7 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/jsonapi.h"
#include "fmgr.h" #include "fmgr.h"
#include "funcapi.h" #include "funcapi.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
@ -27,7 +28,6 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/json.h" #include "utils/json.h"
#include "utils/jsonapi.h"
#include "utils/jsonb.h" #include "utils/jsonb.h"
#include "utils/jsonfuncs.h" #include "utils/jsonfuncs.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
@ -514,6 +514,7 @@ makeJsonLexContext(text *json, bool need_escapes)
{ {
return makeJsonLexContextCstringLen(VARDATA_ANY(json), return makeJsonLexContextCstringLen(VARDATA_ANY(json),
VARSIZE_ANY_EXHDR(json), VARSIZE_ANY_EXHDR(json),
GetDatabaseEncoding(),
need_escapes); need_escapes);
} }
@ -2605,7 +2606,7 @@ populate_array_json(PopulateArrayContext *ctx, char *json, int len)
PopulateArrayState state; PopulateArrayState state;
JsonSemAction sem; JsonSemAction sem;
state.lex = makeJsonLexContextCstringLen(json, len, true); state.lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
state.ctx = ctx; state.ctx = ctx;
memset(&sem, 0, sizeof(sem)); memset(&sem, 0, sizeof(sem));
@ -3448,7 +3449,7 @@ get_json_object_as_hash(char *json, int len, const char *funcname)
HASHCTL ctl; HASHCTL ctl;
HTAB *tab; HTAB *tab;
JHashState *state; JHashState *state;
JsonLexContext *lex = makeJsonLexContextCstringLen(json, len, true); JsonLexContext *lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
JsonSemAction *sem; JsonSemAction *sem;
memset(&ctl, 0, sizeof(ctl)); memset(&ctl, 0, sizeof(ctl));

View File

@ -56,6 +56,7 @@ OBJS_COMMON = \
f2s.o \ f2s.o \
file_perm.o \ file_perm.o \
ip.o \ ip.o \
jsonapi.o \
keywords.o \ keywords.o \
kwlookup.o \ kwlookup.o \
link-canary.o \ link-canary.o \

View File

@ -7,15 +7,32 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* src/backend/utils/adt/jsonapi.c * src/common/jsonapi.c
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef FRONTEND
#include "postgres.h" #include "postgres.h"
#else
#include "postgres_fe.h"
#endif
#include "common/jsonapi.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#ifdef FRONTEND
#include "common/logging.h"
#else
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/jsonapi.h" #endif
#ifdef FRONTEND
#define check_stack_depth()
#define json_log_and_abort(...) \
do { pg_log_fatal(__VA_ARGS__); exit(1); } while(0)
#else
#define json_log_and_abort(...) elog(ERROR, __VA_ARGS__)
#endif
/* /*
* The context of the parser is maintained by the recursive descent * The context of the parser is maintained by the recursive descent
@ -135,13 +152,14 @@ IsValidJsonNumber(const char *str, int len)
* if really required. * if really required.
*/ */
JsonLexContext * JsonLexContext *
makeJsonLexContextCstringLen(char *json, int len, bool need_escapes) makeJsonLexContextCstringLen(char *json, int len, int encoding, bool need_escapes)
{ {
JsonLexContext *lex = palloc0(sizeof(JsonLexContext)); JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
lex->input = lex->token_terminator = lex->line_start = json; lex->input = lex->token_terminator = lex->line_start = json;
lex->line_number = 1; lex->line_number = 1;
lex->input_length = len; lex->input_length = len;
lex->input_encoding = encoding;
if (need_escapes) if (need_escapes)
lex->strval = makeStringInfo(); lex->strval = makeStringInfo();
return lex; return lex;
@ -720,7 +738,7 @@ json_lex_string(JsonLexContext *lex)
ch = (ch * 16) + (*s - 'A') + 10; ch = (ch * 16) + (*s - 'A') + 10;
else else
{ {
lex->token_terminator = s + pg_mblen(s); lex->token_terminator = s + pg_encoding_mblen(lex->input_encoding, s);
return JSON_UNICODE_ESCAPE_FORMAT; return JSON_UNICODE_ESCAPE_FORMAT;
} }
} }
@ -759,7 +777,7 @@ json_lex_string(JsonLexContext *lex)
/* We can't allow this, since our TEXT type doesn't */ /* We can't allow this, since our TEXT type doesn't */
return JSON_UNICODE_CODE_POINT_ZERO; return JSON_UNICODE_CODE_POINT_ZERO;
} }
else if (GetDatabaseEncoding() == PG_UTF8) else if (lex->input_encoding == PG_UTF8)
{ {
unicode_to_utf8(ch, (unsigned char *) utf8str); unicode_to_utf8(ch, (unsigned char *) utf8str);
utf8len = pg_utf_mblen((unsigned char *) utf8str); utf8len = pg_utf_mblen((unsigned char *) utf8str);
@ -809,7 +827,7 @@ json_lex_string(JsonLexContext *lex)
default: default:
/* Not a valid string escape, so signal error. */ /* Not a valid string escape, so signal error. */
lex->token_start = s; lex->token_start = s;
lex->token_terminator = s + pg_mblen(s); lex->token_terminator = s + pg_encoding_mblen(lex->input_encoding, s);
return JSON_ESCAPING_INVALID; return JSON_ESCAPING_INVALID;
} }
} }
@ -823,7 +841,7 @@ json_lex_string(JsonLexContext *lex)
* shown it's not a performance win. * shown it's not a performance win.
*/ */
lex->token_start = s; lex->token_start = s;
lex->token_terminator = s + pg_mblen(s); lex->token_terminator = s + pg_encoding_mblen(lex->input_encoding, s);
return JSON_ESCAPING_INVALID; return JSON_ESCAPING_INVALID;
} }
@ -1010,7 +1028,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
* unhandled enum values. But this needs to be here anyway to cover the * unhandled enum values. But this needs to be here anyway to cover the
* possibility of an incorrect input. * possibility of an incorrect input.
*/ */
elog(ERROR, "unexpected json parse state: %d", (int) ctx); json_log_and_abort("unexpected json parse state: %d", (int) ctx);
return JSON_SUCCESS; /* silence stupider compilers */ return JSON_SUCCESS; /* silence stupider compilers */
} }
@ -1077,7 +1095,7 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
* unhandled enum values. But this needs to be here anyway to cover the * unhandled enum values. But this needs to be here anyway to cover the
* possibility of an incorrect input. * possibility of an incorrect input.
*/ */
elog(ERROR, "unexpected json parse error type: %d", (int) error); json_log_and_abort("unexpected json parse error type: %d", (int) error);
return NULL; /* silence stupider compilers */ return NULL; /* silence stupider compilers */
} }

View File

@ -73,6 +73,7 @@ typedef struct JsonLexContext
{ {
char *input; char *input;
int input_length; int input_length;
int input_encoding;
char *token_start; char *token_start;
char *token_terminator; char *token_terminator;
char *prev_token_terminator; char *prev_token_terminator;
@ -149,6 +150,7 @@ extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex,
*/ */
extern JsonLexContext *makeJsonLexContextCstringLen(char *json, extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
int len, int len,
int encoding,
bool need_escapes); bool need_escapes);
/* lex one token */ /* lex one token */

View File

@ -14,7 +14,7 @@
#ifndef JSONFUNCS_H #ifndef JSONFUNCS_H
#define JSONFUNCS_H #define JSONFUNCS_H
#include "utils/jsonapi.h" #include "common/jsonapi.h"
#include "utils/jsonb.h" #include "utils/jsonb.h"
/* /*