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

JsonSemAction sem
 

Macro Definition Documentation

◆ BUFSIZE

#define BUFSIZE   6000

Definition at line 39 of file test_json_parser_incremental.c.

◆ DEFAULT_CHUNK_SIZE

#define DEFAULT_CHUNK_SIZE   60

Definition at line 40 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 273 of file test_json_parser_incremental.c.

274 {
275  /* nothing to do */
276 
277  return JSON_SUCCESS;
278 }
@ JSON_SUCCESS
Definition: jsonapi.h:38

References JSON_SUCCESS.

◆ do_array_element_start()

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

Definition at line 261 of file test_json_parser_incremental.c.

262 {
263  DoState *_state = (DoState *) state;
264 
265  if (!_state->elem_is_first)
266  printf(",\n");
267  _state->elem_is_first = false;
268 
269  return JSON_SUCCESS;
270 }
#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 250 of file test_json_parser_incremental.c.

251 {
252  DoState *_state = (DoState *) state;
253 
254  printf("\n]\n");
255  _state->elem_is_first = false;
256 
257  return JSON_SUCCESS;
258 }

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_array_start()

static JsonParseErrorType do_array_start ( void *  state)
static

Definition at line 239 of file test_json_parser_incremental.c.

240 {
241  DoState *_state = (DoState *) state;
242 
243  printf("[\n");
244  _state->elem_is_first = true;
245 
246  return JSON_SUCCESS;
247 }

References DoState::elem_is_first, JSON_SUCCESS, and printf.

◆ do_object_end()

static JsonParseErrorType do_object_end ( void *  state)
static

Definition at line 205 of file test_json_parser_incremental.c.

206 {
207  DoState *_state = (DoState *) state;
208 
209  printf("\n}\n");
210  _state->elem_is_first = false;
211 
212  return JSON_SUCCESS;
213 }

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 231 of file test_json_parser_incremental.c.

232 {
233  /* nothing to do really */
234 
235  return JSON_SUCCESS;
236 }

References JSON_SUCCESS.

◆ do_object_field_start()

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

Definition at line 216 of file test_json_parser_incremental.c.

217 {
218  DoState *_state = (DoState *) state;
219 
220  if (!_state->elem_is_first)
221  printf(",\n");
222  resetStringInfo(_state->buf);
223  escape_json(_state->buf, fname);
224  printf("%s: ", _state->buf->data);
225  _state->elem_is_first = false;
226 
227  return JSON_SUCCESS;
228 }
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78
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 194 of file test_json_parser_incremental.c.

195 {
196  DoState *_state = (DoState *) state;
197 
198  printf("{\n");
199  _state->elem_is_first = true;
200 
201  return JSON_SUCCESS;
202 }

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 281 of file test_json_parser_incremental.c.

282 {
283  DoState *_state = (DoState *) state;
284 
285  if (tokentype == JSON_TOKEN_STRING)
286  {
287  resetStringInfo(_state->buf);
288  escape_json(_state->buf, token);
289  printf("%s", _state->buf->data);
290  }
291  else
292  printf("%s", token);
293 
294  return JSON_SUCCESS;
295 }
#define token
Definition: indent_globs.h:126
@ JSON_TOKEN_STRING
Definition: jsonapi.h:22

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

◆ escape_json()

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

Definition at line 300 of file test_json_parser_incremental.c.

301 {
302  const char *p;
303 
305  for (p = str; *p; p++)
306  {
307  switch (*p)
308  {
309  case '\b':
310  appendStringInfoString(buf, "\\b");
311  break;
312  case '\f':
313  appendStringInfoString(buf, "\\f");
314  break;
315  case '\n':
316  appendStringInfoString(buf, "\\n");
317  break;
318  case '\r':
319  appendStringInfoString(buf, "\\r");
320  break;
321  case '\t':
322  appendStringInfoString(buf, "\\t");
323  break;
324  case '"':
325  appendStringInfoString(buf, "\\\"");
326  break;
327  case '\\':
328  appendStringInfoString(buf, "\\\\");
329  break;
330  default:
331  if ((unsigned char) *p < ' ')
332  appendStringInfo(buf, "\\u%04x", (int) *p);
333  else
335  break;
336  }
337  }
339 }
const char * str
static char * buf
Definition: pg_test_fsync.c:73
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:204

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 76 of file test_json_parser_incremental.c.

77 {
78  char buff[BUFSIZE];
79  FILE *json_file;
80  JsonParseErrorType result;
81  JsonLexContext lex;
82  StringInfoData json;
83  int n_read;
84  size_t chunk_size = DEFAULT_CHUNK_SIZE;
85  struct stat statbuf;
86  off_t bytes_left;
87  JsonSemAction *testsem = &nullSemAction;
88  char *testfile;
89  int c;
90  bool need_strings = false;
91 
92  pg_logging_init(argv[0]);
93 
94  while ((c = getopt(argc, argv, "c:s")) != -1)
95  {
96  switch (c)
97  {
98  case 'c': /* chunksize */
99  sscanf(optarg, "%zu", &chunk_size);
100  if (chunk_size > BUFSIZE)
101  pg_fatal("chunk size cannot exceed %d", BUFSIZE);
102  break;
103  case 's': /* do semantic processing */
104  testsem = &sem;
105  sem.semstate = palloc(sizeof(struct DoState));
106  ((struct DoState *) sem.semstate)->lex = &lex;
107  ((struct DoState *) sem.semstate)->buf = makeStringInfo();
108  need_strings = true;
109  break;
110  }
111  }
112 
113  if (optind < argc)
114  {
115  testfile = pg_strdup(argv[optind]);
116  optind++;
117  }
118  else
119  {
120  usage(argv[0]);
121  exit(1);
122  }
123 
124  makeJsonLexContextIncremental(&lex, PG_UTF8, need_strings);
125  initStringInfo(&json);
126 
127  if ((json_file = fopen(testfile, "r")) == NULL)
128  pg_fatal("error opening input: %m");
129 
130  if (fstat(fileno(json_file), &statbuf) != 0)
131  pg_fatal("error statting input: %m");
132 
133  bytes_left = statbuf.st_size;
134 
135  for (;;)
136  {
137  /* We will break when there's nothing left to read */
138 
139  if (bytes_left < chunk_size)
140  chunk_size = bytes_left;
141 
142  n_read = fread(buff, 1, chunk_size, json_file);
143  if (n_read < chunk_size)
144  pg_fatal("error reading input file: %d", ferror(json_file));
145 
146  appendBinaryStringInfo(&json, buff, n_read);
147 
148  /*
149  * Append some trailing junk to the buffer passed to the parser. This
150  * helps us ensure that the parser does the right thing even if the
151  * chunk isn't terminated with a '\0'.
152  */
153  appendStringInfoString(&json, "1+23 trailing junk");
154  bytes_left -= n_read;
155  if (bytes_left > 0)
156  {
157  result = pg_parse_json_incremental(&lex, testsem,
158  json.data, n_read,
159  false);
160  if (result != JSON_INCOMPLETE)
161  {
162  fprintf(stderr, "%s\n", json_errdetail(result, &lex));
163  exit(1);
164  }
165  resetStringInfo(&json);
166  }
167  else
168  {
169  result = pg_parse_json_incremental(&lex, testsem,
170  json.data, n_read,
171  true);
172  if (result != JSON_SUCCESS)
173  {
174  fprintf(stderr, "%s\n", json_errdetail(result, &lex));
175  exit(1);
176  }
177  if (!need_strings)
178  printf("SUCCESS!\n");
179  break;
180  }
181  }
182  fclose(json_file);
183  exit(0);
184 }
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, JsonSemAction *sem, char *json, int len, bool is_last)
Definition: jsonapi.c:649
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2096
JsonSemAction nullSemAction
Definition: jsonapi.c:224
JsonLexContext * makeJsonLexContextIncremental(JsonLexContext *lex, int encoding, bool need_escapes)
Definition: jsonapi.c:366
JsonParseErrorType
Definition: jsonapi.h:37
@ JSON_INCOMPLETE
Definition: jsonapi.h:39
exit(1)
void pg_logging_init(const char *argv0)
Definition: logging.c:83
void * palloc(Size size)
Definition: mcxt.c:1316
#define pg_fatal(...)
PGDLLIMPORT int optind
Definition: getopt.c:50
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:71
PGDLLIMPORT char * optarg
Definition: getopt.c:52
@ PG_UTF8
Definition: pg_wchar.h:232
#define fprintf
Definition: port.h:242
char * c
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
JsonLexContext * lex
void * semstate
Definition: jsonapi.h:134
static void usage(const char *progname)
JsonSemAction sem
#define DEFAULT_CHUNK_SIZE
#define BUFSIZE
#define fstat
Definition: win32_port.h:283

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

◆ usage()

static void usage ( const char *  progname)
static

Definition at line 342 of file test_json_parser_incremental.c.

343 {
344  fprintf(stderr, "Usage: %s [OPTION ...] testfile\n", progname);
345  fprintf(stderr, "Options:\n");
346  fprintf(stderr, " -c chunksize size of piece fed to parser (default 64)n");
347  fprintf(stderr, " -s do semantic processing\n");
348 
349 }
const char * progname
Definition: main.c:44

References fprintf, and progname.

Referenced by main().

Variable Documentation

◆ sem

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 63 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().