PostgreSQL Source Code git master
test_json_parser_incremental.c File Reference
#include "postgres_fe.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "common/jsonapi.h"
#include "common/logging.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "pg_getopt.h"
Include dependency graph for test_json_parser_incremental.c:

Go to the source code of this file.

Data Structures

struct  DoState
 

Macros

#define BUFSIZE   6000
 
#define DEFAULT_CHUNK_SIZE   60
 

Typedefs

typedef struct DoState DoState
 

Functions

static void usage (const char *progname)
 
static void escape_json (StringInfo buf, const char *str)
 
static JsonParseErrorType do_object_start (void *state)
 
static JsonParseErrorType do_object_end (void *state)
 
static JsonParseErrorType do_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType do_object_field_end (void *state, char *fname, bool isnull)
 
static JsonParseErrorType do_array_start (void *state)
 
static JsonParseErrorType do_array_end (void *state)
 
static JsonParseErrorType do_array_element_start (void *state, bool isnull)
 
static JsonParseErrorType do_array_element_end (void *state, bool isnull)
 
static JsonParseErrorType do_scalar (void *state, char *token, JsonTokenType tokentype)
 
int main (int argc, char **argv)
 

Variables

static JsonSemAction sem
 
static bool lex_owns_tokens = false
 

Macro Definition Documentation

◆ BUFSIZE

#define BUFSIZE   6000

Definition at line 43 of file test_json_parser_incremental.c.

◆ DEFAULT_CHUNK_SIZE

#define DEFAULT_CHUNK_SIZE   60

Definition at line 44 of file test_json_parser_incremental.c.

Typedef Documentation

◆ DoState

typedef struct DoState DoState

Function Documentation

◆ do_array_element_end()

static JsonParseErrorType do_array_element_end ( void *  state,
bool  isnull 
)
static

Definition at line 292 of file test_json_parser_incremental.c.

293{
294 /* nothing to do */
295
296 return JSON_SUCCESS;
297}
@ JSON_SUCCESS
Definition: jsonapi.h:36

References JSON_SUCCESS.

◆ do_array_element_start()

static JsonParseErrorType do_array_element_start ( void *  state,
bool  isnull 
)
static

Definition at line 280 of file test_json_parser_incremental.c.

281{
282 DoState *_state = (DoState *) state;
283
284 if (!_state->elem_is_first)
285 printf(",\n");
286 _state->elem_is_first = false;
287
288 return JSON_SUCCESS;
289}
#define printf(...)
Definition: port.h:244
Definition: regguts.h:323

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_array_end()

static JsonParseErrorType do_array_end ( void *  state)
static

Definition at line 269 of file test_json_parser_incremental.c.

270{
271 DoState *_state = (DoState *) state;
272
273 printf("\n]\n");
274 _state->elem_is_first = false;
275
276 return JSON_SUCCESS;
277}

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_array_start()

static JsonParseErrorType do_array_start ( void *  state)
static

Definition at line 258 of file test_json_parser_incremental.c.

259{
260 DoState *_state = (DoState *) state;
261
262 printf("[\n");
263 _state->elem_is_first = true;
264
265 return JSON_SUCCESS;
266}

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_object_end()

static JsonParseErrorType do_object_end ( void *  state)
static

Definition at line 223 of file test_json_parser_incremental.c.

224{
225 DoState *_state = (DoState *) state;
226
227 printf("\n}\n");
228 _state->elem_is_first = false;
229
230 return JSON_SUCCESS;
231}

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_object_field_end()

static JsonParseErrorType do_object_field_end ( void *  state,
char *  fname,
bool  isnull 
)
static

Definition at line 249 of file test_json_parser_incremental.c.

250{
251 if (!lex_owns_tokens)
252 free(fname);
253
254 return JSON_SUCCESS;
255}
#define free(a)
Definition: header.h:65
static bool lex_owns_tokens

References free, JSON_SUCCESS, and lex_owns_tokens.

◆ do_object_field_start()

static JsonParseErrorType do_object_field_start ( void *  state,
char *  fname,
bool  isnull 
)
static

Definition at line 234 of file test_json_parser_incremental.c.

235{
236 DoState *_state = (DoState *) state;
237
238 if (!_state->elem_is_first)
239 printf(",\n");
240 resetStringInfo(_state->buf);
241 escape_json(_state->buf, fname);
242 printf("%s: ", _state->buf->data);
243 _state->elem_is_first = false;
244
245 return JSON_SUCCESS;
246}
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
static void escape_json(StringInfo buf, const char *str)

References DoState::buf, StringInfoData::data, DoState::elem_is_first, escape_json(), JSON_SUCCESS, printf, and resetStringInfo().

◆ do_object_start()

static JsonParseErrorType do_object_start ( void *  state)
static

Definition at line 212 of file test_json_parser_incremental.c.

213{
214 DoState *_state = (DoState *) state;
215
216 printf("{\n");
217 _state->elem_is_first = true;
218
219 return JSON_SUCCESS;
220}

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_scalar()

static JsonParseErrorType do_scalar ( void *  state,
char *  token,
JsonTokenType  tokentype 
)
static

Definition at line 300 of file test_json_parser_incremental.c.

301{
302 DoState *_state = (DoState *) state;
303
304 if (tokentype == JSON_TOKEN_STRING)
305 {
306 resetStringInfo(_state->buf);
307 escape_json(_state->buf, token);
308 printf("%s", _state->buf->data);
309 }
310 else
311 printf("%s", token);
312
313 if (!lex_owns_tokens)
314 free(token);
315
316 return JSON_SUCCESS;
317}
#define token
Definition: indent_globs.h:126
@ JSON_TOKEN_STRING
Definition: jsonapi.h:20

References DoState::buf, StringInfoData::data, escape_json(), free, JSON_SUCCESS, JSON_TOKEN_STRING, lex_owns_tokens, printf, resetStringInfo(), and token.

◆ escape_json()

static void escape_json ( StringInfo  buf,
const char *  str 
)
static

Definition at line 322 of file test_json_parser_incremental.c.

323{
324 const char *p;
325
327 for (p = str; *p; p++)
328 {
329 switch (*p)
330 {
331 case '\b':
333 break;
334 case '\f':
336 break;
337 case '\n':
339 break;
340 case '\r':
342 break;
343 case '\t':
345 break;
346 case '"':
348 break;
349 case '\\':
351 break;
352 default:
353 if ((unsigned char) *p < ' ')
354 appendStringInfo(buf, "\\u%04x", (int) *p);
355 else
357 break;
358 }
359 }
361}
const char * str
static char * buf
Definition: pg_test_fsync.c:72
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:231

References appendStringInfo(), appendStringInfoCharMacro, appendStringInfoString(), buf, and str.

Referenced by do_object_field_start(), and do_scalar().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 82 of file test_json_parser_incremental.c.

83{
84 char buff[BUFSIZE];
85 FILE *json_file;
86 JsonParseErrorType result;
88 StringInfoData json;
89 int n_read;
90 size_t chunk_size = DEFAULT_CHUNK_SIZE;
91 struct stat statbuf;
92 off_t bytes_left;
93 const JsonSemAction *testsem = &nullSemAction;
94 char *testfile;
95 int c;
96 bool need_strings = false;
97 int ret = 0;
98
99 pg_logging_init(argv[0]);
100
101 while ((c = getopt(argc, argv, "c:os")) != -1)
102 {
103 switch (c)
104 {
105 case 'c': /* chunksize */
106 chunk_size = strtou64(optarg, NULL, 10);
107 if (chunk_size > BUFSIZE)
108 pg_fatal("chunk size cannot exceed %d", BUFSIZE);
109 break;
110 case 'o': /* switch token ownership */
111 lex_owns_tokens = true;
112 break;
113 case 's': /* do semantic processing */
114 testsem = &sem;
115 sem.semstate = palloc(sizeof(struct DoState));
116 ((struct DoState *) sem.semstate)->lex = &lex;
117 ((struct DoState *) sem.semstate)->buf = makeStringInfo();
118 need_strings = true;
119 break;
120 }
121 }
122
123 if (optind < argc)
124 {
125 testfile = argv[optind];
126 optind++;
127 }
128 else
129 {
130 usage(argv[0]);
131 exit(1);
132 }
133
136 initStringInfo(&json);
137
138 if ((json_file = fopen(testfile, PG_BINARY_R)) == NULL)
139 pg_fatal("error opening input: %m");
140
141 if (fstat(fileno(json_file), &statbuf) != 0)
142 pg_fatal("error statting input: %m");
143
144 bytes_left = statbuf.st_size;
145
146 for (;;)
147 {
148 /* We will break when there's nothing left to read */
149
150 if (bytes_left < chunk_size)
151 chunk_size = bytes_left;
152
153 n_read = fread(buff, 1, chunk_size, json_file);
154 if (n_read < chunk_size)
155 pg_fatal("error reading input file: %d", ferror(json_file));
156
157 appendBinaryStringInfo(&json, buff, n_read);
158
159 /*
160 * Append some trailing junk to the buffer passed to the parser. This
161 * helps us ensure that the parser does the right thing even if the
162 * chunk isn't terminated with a '\0'.
163 */
164 appendStringInfoString(&json, "1+23 trailing junk");
165 bytes_left -= n_read;
166 if (bytes_left > 0)
167 {
168 result = pg_parse_json_incremental(&lex, testsem,
169 json.data, n_read,
170 false);
171 if (result != JSON_INCOMPLETE)
172 {
173 fprintf(stderr, "%s\n", json_errdetail(result, &lex));
174 ret = 1;
175 goto cleanup;
176 }
177 resetStringInfo(&json);
178 }
179 else
180 {
181 result = pg_parse_json_incremental(&lex, testsem,
182 json.data, n_read,
183 true);
184 if (result != JSON_SUCCESS)
185 {
186 fprintf(stderr, "%s\n", json_errdetail(result, &lex));
187 ret = 1;
188 goto cleanup;
189 }
190 if (!need_strings)
191 printf("SUCCESS!\n");
192 break;
193 }
194 }
195
196cleanup:
197 fclose(json_file);
199 free(json.data);
200
201 return ret;
202}
static void cleanup(void)
Definition: bootstrap.c:713
#define PG_BINARY_R
Definition: c.h:1232
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
Definition: jsonapi.c:868
JsonLexContext * makeJsonLexContextIncremental(JsonLexContext *lex, int encoding, bool need_escapes)
Definition: jsonapi.c:497
void setJsonLexContextOwnsTokens(JsonLexContext *lex, bool owned_by_context)
Definition: jsonapi.c:542
const JsonSemAction nullSemAction
Definition: jsonapi.c:287
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2401
void freeJsonLexContext(JsonLexContext *lex)
Definition: jsonapi.c:687
JsonParseErrorType
Definition: jsonapi.h:35
@ JSON_INCOMPLETE
Definition: jsonapi.h:37
exit(1)
void pg_logging_init(const char *argv0)
Definition: logging.c:83
void * palloc(Size size)
Definition: mcxt.c:1317
#define pg_fatal(...)
PGDLLIMPORT int optind
Definition: getopt.c:51
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:72
PGDLLIMPORT char * optarg
Definition: getopt.c:53
@ PG_UTF8
Definition: pg_wchar.h:232
char * c
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
JsonLexContext * lex
void * semstate
Definition: jsonapi.h:153
static void usage(const char *progname)
static JsonSemAction sem
#define DEFAULT_CHUNK_SIZE
#define BUFSIZE
#define fstat
Definition: win32_port.h:273

References appendBinaryStringInfo(), appendStringInfoString(), BUFSIZE, cleanup(), StringInfoData::data, DEFAULT_CHUNK_SIZE, exit(), fprintf, free, freeJsonLexContext(), fstat, getopt(), initStringInfo(), json_errdetail(), JSON_INCOMPLETE, JSON_SUCCESS, DoState::lex, lex_owns_tokens, makeJsonLexContextIncremental(), makeStringInfo(), nullSemAction, optarg, optind, palloc(), PG_BINARY_R, pg_fatal, pg_logging_init(), pg_parse_json_incremental(), PG_UTF8, printf, resetStringInfo(), sem, JsonSemAction::semstate, setJsonLexContextOwnsTokens(), stat::st_size, and usage().

◆ usage()

static void usage ( const char *  progname)
static

Definition at line 364 of file test_json_parser_incremental.c.

365{
366 fprintf(stderr, "Usage: %s [OPTION ...] testfile\n", progname);
367 fprintf(stderr, "Options:\n");
368 fprintf(stderr, " -c chunksize size of piece fed to parser (default 64)\n");
369 fprintf(stderr, " -o set JSONLEX_CTX_OWNS_TOKENS for leak checking\n");
370 fprintf(stderr, " -s do semantic processing\n");
371
372}
const char * progname
Definition: main.c:44

References fprintf, and progname.

Referenced by main().

Variable Documentation

◆ lex_owns_tokens

bool lex_owns_tokens = false
static

Definition at line 79 of file test_json_parser_incremental.c.

Referenced by do_object_field_end(), do_scalar(), and main().

◆ sem

JsonSemAction sem
static
Initial value:
= {
.object_start = do_object_start,
.object_end = do_object_end,
.object_field_start = do_object_field_start,
.object_field_end = do_object_field_end,
.array_start = do_array_start,
.array_end = do_array_end,
.array_element_start = do_array_element_start,
.array_element_end = do_array_element_end,
.scalar = do_scalar
}
static JsonParseErrorType do_object_field_start(void *state, char *fname, bool isnull)
static JsonParseErrorType do_array_element_end(void *state, bool isnull)
static JsonParseErrorType do_array_element_start(void *state, bool isnull)
static JsonParseErrorType do_object_end(void *state)
static JsonParseErrorType do_scalar(void *state, char *token, JsonTokenType tokentype)
static JsonParseErrorType do_array_start(void *state)
static JsonParseErrorType do_object_start(void *state)
static JsonParseErrorType do_array_end(void *state)
static JsonParseErrorType do_object_field_end(void *state, char *fname, bool isnull)

Definition at line 67 of file test_json_parser_incremental.c.

Referenced by datum_to_jsonb_internal(), each_worker(), elements_worker(), get_json_object_as_hash(), get_worker(), iterate_json_values(), json_array_length(), json_object_keys(), json_parse_manifest(), json_strip_nulls(), jsonb_from_cstring(), main(), parse_array(), parse_array_element(), parse_object(), parse_object_field(), parse_scalar(), pg_parse_json(), pg_parse_json_incremental(), pg_parse_json_or_errsave(), populate_array_json(), populate_recordset_worker(), PosixSemaphoreCreate(), PosixSemaphoreKill(), and transform_json_string_values().