PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
jsonapi.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  JsonLexContext
 
struct  JsonSemAction
 

Macros

#define jsonapi_StrValType   StringInfoData
 
#define JSONLEX_FREE_STRUCT   (1 << 0)
 
#define JSONLEX_FREE_STRVAL   (1 << 1)
 
#define JSONLEX_CTX_OWNS_TOKENS   (1 << 2)
 

Typedefs

typedef enum JsonTokenType JsonTokenType
 
typedef enum JsonParseErrorType JsonParseErrorType
 
typedef struct JsonParserStack JsonParserStack
 
typedef struct JsonIncrementalState JsonIncrementalState
 
typedef struct JsonLexContext JsonLexContext
 
typedef JsonParseErrorType(* json_struct_action) (void *state)
 
typedef JsonParseErrorType(* json_ofield_action) (void *state, char *fname, bool isnull)
 
typedef JsonParseErrorType(* json_aelem_action) (void *state, bool isnull)
 
typedef JsonParseErrorType(* json_scalar_action) (void *state, char *token, JsonTokenType tokentype)
 
typedef struct JsonSemAction JsonSemAction
 

Enumerations

enum  JsonTokenType {
  JSON_TOKEN_INVALID , JSON_TOKEN_STRING , JSON_TOKEN_NUMBER , JSON_TOKEN_OBJECT_START ,
  JSON_TOKEN_OBJECT_END , JSON_TOKEN_ARRAY_START , JSON_TOKEN_ARRAY_END , JSON_TOKEN_COMMA ,
  JSON_TOKEN_COLON , JSON_TOKEN_TRUE , JSON_TOKEN_FALSE , JSON_TOKEN_NULL ,
  JSON_TOKEN_END
}
 
enum  JsonParseErrorType {
  JSON_SUCCESS , JSON_INCOMPLETE , JSON_INVALID_LEXER_TYPE , JSON_NESTING_TOO_DEEP ,
  JSON_ESCAPING_INVALID , JSON_ESCAPING_REQUIRED , JSON_EXPECTED_ARRAY_FIRST , JSON_EXPECTED_ARRAY_NEXT ,
  JSON_EXPECTED_COLON , JSON_EXPECTED_END , JSON_EXPECTED_JSON , JSON_EXPECTED_MORE ,
  JSON_EXPECTED_OBJECT_FIRST , JSON_EXPECTED_OBJECT_NEXT , JSON_EXPECTED_STRING , JSON_INVALID_TOKEN ,
  JSON_OUT_OF_MEMORY , JSON_UNICODE_CODE_POINT_ZERO , JSON_UNICODE_ESCAPE_FORMAT , JSON_UNICODE_HIGH_ESCAPE ,
  JSON_UNICODE_UNTRANSLATABLE , JSON_UNICODE_HIGH_SURROGATE , JSON_UNICODE_LOW_SURROGATE , JSON_SEM_ACTION_FAILED
}
 

Functions

JsonParseErrorType pg_parse_json (JsonLexContext *lex, const JsonSemAction *sem)
 
JsonParseErrorType pg_parse_json_incremental (JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
 
JsonParseErrorType json_count_array_elements (JsonLexContext *lex, int *elements)
 
JsonLexContextmakeJsonLexContextCstringLen (JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
 
JsonLexContextmakeJsonLexContextIncremental (JsonLexContext *lex, int encoding, bool need_escapes)
 
void setJsonLexContextOwnsTokens (JsonLexContext *lex, bool owned_by_context)
 
void freeJsonLexContext (JsonLexContext *lex)
 
JsonParseErrorType json_lex (JsonLexContext *lex)
 
char * json_errdetail (JsonParseErrorType error, JsonLexContext *lex)
 
bool IsValidJsonNumber (const char *str, size_t len)
 

Variables

PGDLLIMPORT const JsonSemAction nullSemAction
 

Macro Definition Documentation

◆ jsonapi_StrValType

#define jsonapi_StrValType   StringInfoData

Definition at line 73 of file jsonapi.h.

◆ JSONLEX_CTX_OWNS_TOKENS

#define JSONLEX_CTX_OWNS_TOKENS   (1 << 2)

Definition at line 99 of file jsonapi.h.

◆ JSONLEX_FREE_STRUCT

#define JSONLEX_FREE_STRUCT   (1 << 0)

Definition at line 97 of file jsonapi.h.

◆ JSONLEX_FREE_STRVAL

#define JSONLEX_FREE_STRVAL   (1 << 1)

Definition at line 98 of file jsonapi.h.

Typedef Documentation

◆ json_aelem_action

typedef JsonParseErrorType(* json_aelem_action) (void *state, bool isnull)

Definition at line 129 of file jsonapi.h.

◆ json_ofield_action

typedef JsonParseErrorType(* json_ofield_action) (void *state, char *fname, bool isnull)

Definition at line 128 of file jsonapi.h.

◆ json_scalar_action

typedef JsonParseErrorType(* json_scalar_action) (void *state, char *token, JsonTokenType tokentype)

Definition at line 130 of file jsonapi.h.

◆ json_struct_action

typedef JsonParseErrorType(* json_struct_action) (void *state)

Definition at line 127 of file jsonapi.h.

◆ JsonIncrementalState

Definition at line 64 of file jsonapi.h.

◆ JsonLexContext

◆ JsonParseErrorType

◆ JsonParserStack

Definition at line 63 of file jsonapi.h.

◆ JsonSemAction

typedef struct JsonSemAction JsonSemAction

◆ JsonTokenType

Enumeration Type Documentation

◆ JsonParseErrorType

Enumerator
JSON_SUCCESS 
JSON_INCOMPLETE 
JSON_INVALID_LEXER_TYPE 
JSON_NESTING_TOO_DEEP 
JSON_ESCAPING_INVALID 
JSON_ESCAPING_REQUIRED 
JSON_EXPECTED_ARRAY_FIRST 
JSON_EXPECTED_ARRAY_NEXT 
JSON_EXPECTED_COLON 
JSON_EXPECTED_END 
JSON_EXPECTED_JSON 
JSON_EXPECTED_MORE 
JSON_EXPECTED_OBJECT_FIRST 
JSON_EXPECTED_OBJECT_NEXT 
JSON_EXPECTED_STRING 
JSON_INVALID_TOKEN 
JSON_OUT_OF_MEMORY 
JSON_UNICODE_CODE_POINT_ZERO 
JSON_UNICODE_ESCAPE_FORMAT 
JSON_UNICODE_HIGH_ESCAPE 
JSON_UNICODE_UNTRANSLATABLE 
JSON_UNICODE_HIGH_SURROGATE 
JSON_UNICODE_LOW_SURROGATE 
JSON_SEM_ACTION_FAILED 

Definition at line 34 of file jsonapi.h.

35{
59 JSON_SEM_ACTION_FAILED, /* error should already be reported */
JsonParseErrorType
Definition: jsonapi.h:35
@ JSON_OUT_OF_MEMORY
Definition: jsonapi.h:52
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:59
@ JSON_EXPECTED_ARRAY_FIRST
Definition: jsonapi.h:42
@ JSON_EXPECTED_MORE
Definition: jsonapi.h:47
@ JSON_UNICODE_HIGH_SURROGATE
Definition: jsonapi.h:57
@ JSON_EXPECTED_COLON
Definition: jsonapi.h:44
@ JSON_EXPECTED_OBJECT_FIRST
Definition: jsonapi.h:48
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:53
@ JSON_INVALID_LEXER_TYPE
Definition: jsonapi.h:38
@ JSON_EXPECTED_STRING
Definition: jsonapi.h:50
@ JSON_UNICODE_ESCAPE_FORMAT
Definition: jsonapi.h:54
@ JSON_SUCCESS
Definition: jsonapi.h:36
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:56
@ JSON_EXPECTED_OBJECT_NEXT
Definition: jsonapi.h:49
@ JSON_ESCAPING_REQUIRED
Definition: jsonapi.h:41
@ JSON_EXPECTED_JSON
Definition: jsonapi.h:46
@ JSON_INVALID_TOKEN
Definition: jsonapi.h:51
@ JSON_ESCAPING_INVALID
Definition: jsonapi.h:40
@ JSON_INCOMPLETE
Definition: jsonapi.h:37
@ JSON_EXPECTED_END
Definition: jsonapi.h:45
@ JSON_EXPECTED_ARRAY_NEXT
Definition: jsonapi.h:43
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:55
@ JSON_NESTING_TOO_DEEP
Definition: jsonapi.h:39
@ JSON_UNICODE_LOW_SURROGATE
Definition: jsonapi.h:58

◆ JsonTokenType

Enumerator
JSON_TOKEN_INVALID 
JSON_TOKEN_STRING 
JSON_TOKEN_NUMBER 
JSON_TOKEN_OBJECT_START 
JSON_TOKEN_OBJECT_END 
JSON_TOKEN_ARRAY_START 
JSON_TOKEN_ARRAY_END 
JSON_TOKEN_COMMA 
JSON_TOKEN_COLON 
JSON_TOKEN_TRUE 
JSON_TOKEN_FALSE 
JSON_TOKEN_NULL 
JSON_TOKEN_END 

Definition at line 17 of file jsonapi.h.

18{
JsonTokenType
Definition: jsonapi.h:18
@ JSON_TOKEN_INVALID
Definition: jsonapi.h:19
@ JSON_TOKEN_COMMA
Definition: jsonapi.h:26
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:29
@ JSON_TOKEN_END
Definition: jsonapi.h:31
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:28
@ JSON_TOKEN_OBJECT_END
Definition: jsonapi.h:23
@ JSON_TOKEN_NULL
Definition: jsonapi.h:30
@ JSON_TOKEN_ARRAY_END
Definition: jsonapi.h:25
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:22
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:21
@ JSON_TOKEN_STRING
Definition: jsonapi.h:20
@ JSON_TOKEN_COLON
Definition: jsonapi.h:27
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:24

Function Documentation

◆ freeJsonLexContext()

void freeJsonLexContext ( JsonLexContext lex)

Definition at line 687 of file jsonapi.c.

689{
690 static const JsonLexContext empty = {0};
691
692 if (!lex || lex == &failed_oom)
693 return;
694
695 if (lex->flags & JSONLEX_FREE_STRVAL)
697
698 if (lex->errormsg)
700
701 if (lex->incremental)
702 {
704 FREE(lex->inc_state);
705 FREE(lex->pstack->prediction);
706
708 {
709 int i;
710
711 /* Clean up any tokens that were left behind. */
712 for (i = 0; i <= lex->lex_level; i++)
713 FREE(lex->pstack->fnames[i]);
714 }
715
716 FREE(lex->pstack->fnames);
717 FREE(lex->pstack->fnull);
718 FREE(lex->pstack->scalar_val);
719 FREE(lex->pstack);
720 }
721
722 if (lex->flags & JSONLEX_FREE_STRUCT)
723 FREE(lex);
724 else
725 *lex = empty;
int i
Definition: isn.c:77
#define jsonapi_destroyStringInfo
Definition: jsonapi.c:84
static JsonLexContext failed_oom
Definition: jsonapi.c:294
#define jsonapi_termStringInfo(s)
Definition: jsonapi.c:83
#define FREE(s)
Definition: jsonapi.c:69
#define JSONLEX_FREE_STRVAL
Definition: jsonapi.h:98
#define JSONLEX_FREE_STRUCT
Definition: jsonapi.h:97
#define JSONLEX_CTX_OWNS_TOKENS
Definition: jsonapi.h:99
jsonapi_StrValType partial_token
Definition: jsonapi.c:167
bits32 flags
Definition: jsonapi.h:111
struct jsonapi_StrValType * strval
Definition: jsonapi.h:117
struct jsonapi_StrValType * errormsg
Definition: jsonapi.h:118
JsonParserStack * pstack
Definition: jsonapi.h:114
JsonIncrementalState * inc_state
Definition: jsonapi.h:115
bool incremental
Definition: jsonapi.h:108
bool * fnull
Definition: jsonapi.c:151
char * prediction
Definition: jsonapi.c:147
char * scalar_val
Definition: jsonapi.c:153
char ** fnames
Definition: jsonapi.c:150

References JsonLexContext::errormsg, failed_oom, JsonLexContext::flags, JsonParserStack::fnames, JsonParserStack::fnull, FREE, i, JsonLexContext::inc_state, JsonLexContext::incremental, jsonapi_destroyStringInfo, jsonapi_termStringInfo, JSONLEX_CTX_OWNS_TOKENS, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, JsonLexContext::lex_level, JsonIncrementalState::partial_token, JsonParserStack::prediction, JsonLexContext::pstack, JsonParserStack::scalar_val, and JsonLexContext::strval.

Referenced by datum_to_jsonb_internal(), each_worker(), elements_worker(), get_json_object_as_hash(), get_worker(), handle_oauth_sasl_error(), iterate_json_values(), json_object_keys(), json_parse_manifest(), json_parse_manifest_incremental_shutdown(), json_validate(), main(), parse_oauth_json(), populate_array_json(), populate_recordset_worker(), and transform_json_string_values().

◆ IsValidJsonNumber()

bool IsValidJsonNumber ( const char *  str,
size_t  len 
)

Definition at line 339 of file jsonapi.c.

340{
341 bool numeric_error;
342 size_t total_len;
343 JsonLexContext dummy_lex = {0};
344
345 if (len <= 0)
346 return false;
347
348 /*
349 * json_lex_number expects a leading '-' to have been eaten already.
350 *
351 * having to cast away the constness of str is ugly, but there's not much
352 * easy alternative.
353 */
354 if (*str == '-')
355 {
356 dummy_lex.input = str + 1;
357 dummy_lex.input_length = len - 1;
358 }
359 else
360 {
361 dummy_lex.input = str;
362 dummy_lex.input_length = len;
363 }
364
365 dummy_lex.token_start = dummy_lex.input;
366
367 json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
368
369 return (!numeric_error) && (total_len == dummy_lex.input_length);
370}
const char * str
static JsonParseErrorType json_lex_number(JsonLexContext *lex, const char *s, bool *num_err, size_t *total_len)
Definition: jsonapi.c:2247
const void size_t len
const char * input
Definition: jsonapi.h:102
const char * token_start
Definition: jsonapi.h:105
size_t input_length
Definition: jsonapi.h:103

References JsonLexContext::input, JsonLexContext::input_length, json_lex_number(), len, str, and JsonLexContext::token_start.

Referenced by hstore_to_json_loose(), and hstore_to_jsonb_loose().

◆ json_count_array_elements()

JsonParseErrorType json_count_array_elements ( JsonLexContext lex,
int *  elements 
)

Definition at line 803 of file jsonapi.c.

805{
806 JsonLexContext copylex;
807 int count;
808 JsonParseErrorType result;
809
810 if (lex == &failed_oom)
811 return JSON_OUT_OF_MEMORY;
812
813 /*
814 * It's safe to do this with a shallow copy because the lexical routines
815 * don't scribble on the input. They do scribble on the other pointers
816 * etc, so doing this with a copy makes that safe.
817 */
818 memcpy(&copylex, lex, sizeof(JsonLexContext));
819 copylex.need_escapes = false; /* not interested in values here */
820 copylex.lex_level++;
821
822 count = 0;
823 result = lex_expect(JSON_PARSE_ARRAY_START, &copylex,
825 if (result != JSON_SUCCESS)
826 return result;
827 if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
828 {
829 while (1)
830 {
831 count++;
832 result = parse_array_element(&copylex, &nullSemAction);
833 if (result != JSON_SUCCESS)
834 return result;
835 if (copylex.token_type != JSON_TOKEN_COMMA)
836 break;
837 result = json_lex(&copylex);
838 if (result != JSON_SUCCESS)
839 return result;
840 }
841 }
842 result = lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex,
844 if (result != JSON_SUCCESS)
845 return result;
846
847 *elements = count;
848 return JSON_SUCCESS;
@ JSON_PARSE_ARRAY_START
Definition: jsonapi.c:97
@ JSON_PARSE_ARRAY_NEXT
Definition: jsonapi.c:98
static JsonTokenType lex_peek(JsonLexContext *lex)
Definition: jsonapi.c:305
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:317
const JsonSemAction nullSemAction
Definition: jsonapi.c:287
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1588
static JsonParseErrorType parse_array_element(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1467
bool need_escapes
Definition: jsonapi.h:116
JsonTokenType token_type
Definition: jsonapi.h:109

References failed_oom, json_lex(), JSON_OUT_OF_MEMORY, JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COMMA, lex_expect(), JsonLexContext::lex_level, lex_peek(), JsonLexContext::need_escapes, nullSemAction, parse_array_element(), and JsonLexContext::token_type.

Referenced by get_array_start().

◆ json_errdetail()

char * json_errdetail ( JsonParseErrorType  error,
JsonLexContext lex 
)

Definition at line 2401 of file jsonapi.c.

2403{
2404 if (error == JSON_OUT_OF_MEMORY || lex == &failed_oom)
2405 {
2406 /* Short circuit. Allocating anything for this case is unhelpful. */
2407 return _("out of memory");
2408 }
2409
2410 if (lex->errormsg)
2412 else
2414
2415 /*
2416 * A helper for error messages that should print the current token. The
2417 * format must contain exactly one %.*s specifier.
2418 */
2419#define json_token_error(lex, format) \
2420 jsonapi_appendStringInfo((lex)->errormsg, _(format), \
2421 (int) ((lex)->token_terminator - (lex)->token_start), \
2422 (lex)->token_start);
2423
2424 switch (error)
2425 {
2426 case JSON_INCOMPLETE:
2427 case JSON_SUCCESS:
2428 /* fall through to the error code after switch */
2429 break;
2431 if (lex->incremental)
2432 return _("Recursive descent parser cannot use incremental lexer.");
2433 else
2434 return _("Incremental parser requires incremental lexer.");
2436 return (_("JSON nested too deep, maximum permitted depth is 6400."));
2438 json_token_error(lex, "Escape sequence \"\\%.*s\" is invalid.");
2439 break;
2442 _("Character with value 0x%02x must be escaped."),
2443 (unsigned char) *(lex->token_terminator));
2444 break;
2445 case JSON_EXPECTED_END:
2446 json_token_error(lex, "Expected end of input, but found \"%.*s\".");
2447 break;
2449 json_token_error(lex, "Expected array element or \"]\", but found \"%.*s\".");
2450 break;
2452 json_token_error(lex, "Expected \",\" or \"]\", but found \"%.*s\".");
2453 break;
2455 json_token_error(lex, "Expected \":\", but found \"%.*s\".");
2456 break;
2457 case JSON_EXPECTED_JSON:
2458 json_token_error(lex, "Expected JSON value, but found \"%.*s\".");
2459 break;
2460 case JSON_EXPECTED_MORE:
2461 return _("The input string ended unexpectedly.");
2463 json_token_error(lex, "Expected string or \"}\", but found \"%.*s\".");
2464 break;
2466 json_token_error(lex, "Expected \",\" or \"}\", but found \"%.*s\".");
2467 break;
2469 json_token_error(lex, "Expected string, but found \"%.*s\".");
2470 break;
2471 case JSON_INVALID_TOKEN:
2472 json_token_error(lex, "Token \"%.*s\" is invalid.");
2473 break;
2474 case JSON_OUT_OF_MEMORY:
2475 /* should have been handled above; use the error path */
2476 break;
2478 return _("\\u0000 cannot be converted to text.");
2480 return _("\"\\u\" must be followed by four hexadecimal digits.");
2482 /* note: this case is only reachable in frontend not backend */
2483 return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
2485
2486 /*
2487 * Note: this case is only reachable in backend and not frontend.
2488 * #ifdef it away so the frontend doesn't try to link against
2489 * backend functionality.
2490 */
2491#ifndef FRONTEND
2492 return psprintf(_("Unicode escape value could not be translated to the server's encoding %s."),
2494#else
2495 Assert(false);
2496 break;
2497#endif
2499 return _("Unicode high surrogate must not follow a high surrogate.");
2501 return _("Unicode low surrogate must follow a high surrogate.");
2503 /* fall through to the error code after switch */
2504 break;
2505 }
2506#undef json_token_error
2507
2508 /* Note that lex->errormsg can be NULL in shlib code. */
2509 if (lex->errormsg && lex->errormsg->len == 0)
2510 {
2511 /*
2512 * We don't use a default: case, so that the compiler will warn about
2513 * unhandled enum values. But this needs to be here anyway to cover
2514 * the possibility of an incorrect input.
2515 */
2517 "unexpected json parse error type: %d",
2518 (int) error);
2519 }
2520
2521#ifdef JSONAPI_USE_PQEXPBUFFER
2522 if (PQExpBufferBroken(lex->errormsg))
2523 return _("out of memory while constructing error description");
2524#endif
2525
2526 return lex->errormsg->data;
#define _(x)
Definition: elog.c:91
Assert(PointerIsAligned(start, uint64))
#define json_token_error(lex, format)
#define jsonapi_makeStringInfo
Definition: jsonapi.c:80
#define jsonapi_resetStringInfo
Definition: jsonapi.c:82
#define jsonapi_appendStringInfo
Definition: jsonapi.c:76
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1267
#define PQExpBufferBroken(str)
Definition: pqexpbuffer.h:59
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
static void error(void)
Definition: sql-dyntest.c:147
const char * token_terminator
Definition: jsonapi.h:106

References _, Assert(), error(), JsonLexContext::errormsg, failed_oom, GetDatabaseEncodingName(), JsonLexContext::incremental, JSON_ESCAPING_INVALID, JSON_ESCAPING_REQUIRED, JSON_EXPECTED_ARRAY_FIRST, JSON_EXPECTED_ARRAY_NEXT, JSON_EXPECTED_COLON, JSON_EXPECTED_END, JSON_EXPECTED_JSON, JSON_EXPECTED_MORE, JSON_EXPECTED_OBJECT_FIRST, JSON_EXPECTED_OBJECT_NEXT, JSON_EXPECTED_STRING, JSON_INCOMPLETE, JSON_INVALID_LEXER_TYPE, JSON_INVALID_TOKEN, JSON_NESTING_TOO_DEEP, JSON_OUT_OF_MEMORY, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, json_token_error, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, jsonapi_appendStringInfo, jsonapi_makeStringInfo, jsonapi_resetStringInfo, PQExpBufferBroken, psprintf(), and JsonLexContext::token_terminator.

Referenced by handle_oauth_sasl_error(), json_errsave_error(), json_parse_manifest(), json_parse_manifest_incremental_chunk(), main(), and parse_oauth_json().

◆ json_lex()

JsonParseErrorType json_lex ( JsonLexContext lex)

Definition at line 1588 of file jsonapi.c.

1590{
1591 const char *s;
1592 const char *const end = lex->input + lex->input_length;
1593 JsonParseErrorType result;
1594
1595 if (lex == &failed_oom || lex->inc_state == &failed_inc_oom)
1596 return JSON_OUT_OF_MEMORY;
1597
1598 if (lex->incremental)
1599 {
1600 if (lex->inc_state->partial_completed)
1601 {
1602 /*
1603 * We just lexed a completed partial token on the last call, so
1604 * reset everything
1605 */
1607 lex->token_terminator = lex->input;
1608 lex->inc_state->partial_completed = false;
1609 }
1610
1611#ifdef JSONAPI_USE_PQEXPBUFFER
1612 /* Make sure our partial token buffer is valid before using it below. */
1614 return JSON_OUT_OF_MEMORY;
1615#endif
1616 }
1617
1618 s = lex->token_terminator;
1619
1620 if (lex->incremental && lex->inc_state->partial_token.len)
1621 {
1622 /*
1623 * We have a partial token. Extend it and if completed lex it by a
1624 * recursive call
1625 */
1627 size_t added = 0;
1628 bool tok_done = false;
1629 JsonLexContext dummy_lex = {0};
1630 JsonParseErrorType partial_result;
1631
1632 if (ptok->data[0] == '"')
1633 {
1634 /*
1635 * It's a string. Accumulate characters until we reach an
1636 * unescaped '"'.
1637 */
1638 int escapes = 0;
1639
1640 for (int i = ptok->len - 1; i > 0; i--)
1641 {
1642 /* count the trailing backslashes on the partial token */
1643 if (ptok->data[i] == '\\')
1644 escapes++;
1645 else
1646 break;
1647 }
1648
1649 for (size_t i = 0; i < lex->input_length; i++)
1650 {
1651 char c = lex->input[i];
1652
1654 added++;
1655 if (c == '"' && escapes % 2 == 0)
1656 {
1657 tok_done = true;
1658 break;
1659 }
1660 if (c == '\\')
1661 escapes++;
1662 else
1663 escapes = 0;
1664 }
1665 }
1666 else
1667 {
1668 /* not a string */
1669 char c = ptok->data[0];
1670
1671 if (c == '-' || (c >= '0' && c <= '9'))
1672 {
1673 /* for numbers look for possible numeric continuations */
1674
1675 bool numend = false;
1676
1677 for (size_t i = 0; i < lex->input_length && !numend; i++)
1678 {
1679 char cc = lex->input[i];
1680
1681 switch (cc)
1682 {
1683 case '+':
1684 case '-':
1685 case 'e':
1686 case 'E':
1687 case '0':
1688 case '1':
1689 case '2':
1690 case '3':
1691 case '4':
1692 case '5':
1693 case '6':
1694 case '7':
1695 case '8':
1696 case '9':
1697 {
1699 added++;
1700 }
1701 break;
1702 default:
1703 numend = true;
1704 }
1705 }
1706 }
1707
1708 /*
1709 * Add any remaining alphanumeric chars. This takes care of the
1710 * {null, false, true} literals as well as any trailing
1711 * alphanumeric junk on non-string tokens.
1712 */
1713 for (size_t i = added; i < lex->input_length; i++)
1714 {
1715 char cc = lex->input[i];
1716
1717 if (JSON_ALPHANUMERIC_CHAR(cc))
1718 {
1720 added++;
1721 }
1722 else
1723 {
1724 tok_done = true;
1725 break;
1726 }
1727 }
1728 if (added == lex->input_length &&
1730 {
1731 tok_done = true;
1732 }
1733 }
1734
1735 if (!tok_done)
1736 {
1737 /* We should have consumed the whole chunk in this case. */
1738 Assert(added == lex->input_length);
1739
1740 if (!lex->inc_state->is_last_chunk)
1741 return JSON_INCOMPLETE;
1742
1743 /* json_errdetail() needs access to the accumulated token. */
1744 lex->token_start = ptok->data;
1745 lex->token_terminator = ptok->data + ptok->len;
1746 return JSON_INVALID_TOKEN;
1747 }
1748
1749 /*
1750 * Everything up to lex->input[added] has been added to the partial
1751 * token, so move the input past it.
1752 */
1753 lex->input += added;
1754 lex->input_length -= added;
1755
1756 dummy_lex.input = dummy_lex.token_terminator =
1757 dummy_lex.line_start = ptok->data;
1758 dummy_lex.line_number = lex->line_number;
1759 dummy_lex.input_length = ptok->len;
1760 dummy_lex.input_encoding = lex->input_encoding;
1761 dummy_lex.incremental = false;
1762 dummy_lex.need_escapes = lex->need_escapes;
1763 dummy_lex.strval = lex->strval;
1764
1765 partial_result = json_lex(&dummy_lex);
1766
1767 /*
1768 * We either have a complete token or an error. In either case we need
1769 * to point to the partial token data for the semantic or error
1770 * routines. If it's not an error we'll readjust on the next call to
1771 * json_lex.
1772 */
1773 lex->token_type = dummy_lex.token_type;
1774 lex->line_number = dummy_lex.line_number;
1775
1776 /*
1777 * We know the prev_token_terminator must be back in some previous
1778 * piece of input, so we just make it NULL.
1779 */
1780 lex->prev_token_terminator = NULL;
1781
1782 /*
1783 * Normally token_start would be ptok->data, but it could be later,
1784 * see json_lex_string's handling of invalid escapes.
1785 */
1786 lex->token_start = dummy_lex.token_start;
1787 lex->token_terminator = dummy_lex.token_terminator;
1788 if (partial_result == JSON_SUCCESS)
1789 {
1790 /* make sure we've used all the input */
1791 if (lex->token_terminator - lex->token_start != ptok->len)
1792 {
1793 Assert(false);
1794 return JSON_INVALID_TOKEN;
1795 }
1796
1797 lex->inc_state->partial_completed = true;
1798 }
1799 return partial_result;
1800 /* end of partial token processing */
1801 }
1802
1803 /* Skip leading whitespace. */
1804 while (s < end && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
1805 {
1806 if (*s++ == '\n')
1807 {
1808 ++lex->line_number;
1809 lex->line_start = s;
1810 }
1811 }
1812 lex->token_start = s;
1813
1814 /* Determine token type. */
1815 if (s >= end)
1816 {
1817 lex->token_start = NULL;
1819 lex->token_terminator = s;
1821 }
1822 else
1823 {
1824 switch (*s)
1825 {
1826 /* Single-character token, some kind of punctuation mark. */
1827 case '{':
1829 lex->token_terminator = s + 1;
1831 break;
1832 case '}':
1834 lex->token_terminator = s + 1;
1836 break;
1837 case '[':
1839 lex->token_terminator = s + 1;
1841 break;
1842 case ']':
1844 lex->token_terminator = s + 1;
1846 break;
1847 case ',':
1849 lex->token_terminator = s + 1;
1851 break;
1852 case ':':
1854 lex->token_terminator = s + 1;
1856 break;
1857 case '"':
1858 /* string */
1859 result = json_lex_string(lex);
1860 if (result != JSON_SUCCESS)
1861 return result;
1863 break;
1864 case '-':
1865 /* Negative number. */
1866 result = json_lex_number(lex, s + 1, NULL, NULL);
1867 if (result != JSON_SUCCESS)
1868 return result;
1870 break;
1871 case '0':
1872 case '1':
1873 case '2':
1874 case '3':
1875 case '4':
1876 case '5':
1877 case '6':
1878 case '7':
1879 case '8':
1880 case '9':
1881 /* Positive number. */
1882 result = json_lex_number(lex, s, NULL, NULL);
1883 if (result != JSON_SUCCESS)
1884 return result;
1886 break;
1887 default:
1888 {
1889 const char *p;
1890
1891 /*
1892 * We're not dealing with a string, number, legal
1893 * punctuation mark, or end of string. The only legal
1894 * tokens we might find here are true, false, and null,
1895 * but for error reporting purposes we scan until we see a
1896 * non-alphanumeric character. That way, we can report
1897 * the whole word as an unexpected token, rather than just
1898 * some unintuitive prefix thereof.
1899 */
1900 for (p = s; p < end && JSON_ALPHANUMERIC_CHAR(*p); p++)
1901 /* skip */ ;
1902
1903 /*
1904 * We got some sort of unexpected punctuation or an
1905 * otherwise unexpected character, so just complain about
1906 * that one character.
1907 */
1908 if (p == s)
1909 {
1911 lex->token_terminator = s + 1;
1912 return JSON_INVALID_TOKEN;
1913 }
1914
1915 if (lex->incremental && !lex->inc_state->is_last_chunk &&
1916 p == lex->input + lex->input_length)
1917 {
1919 return JSON_INCOMPLETE;
1920 }
1921
1922 /*
1923 * We've got a real alphanumeric token here. If it
1924 * happens to be true, false, or null, all is well. If
1925 * not, error out.
1926 */
1928 lex->token_terminator = p;
1929 if (p - s == 4)
1930 {
1931 if (memcmp(s, "true", 4) == 0)
1933 else if (memcmp(s, "null", 4) == 0)
1935 else
1936 return JSON_INVALID_TOKEN;
1937 }
1938 else if (p - s == 5 && memcmp(s, "false", 5) == 0)
1940 else
1941 return JSON_INVALID_TOKEN;
1942 }
1943 } /* end of switch */
1944 }
1945
1946 if (lex->incremental && lex->token_type == JSON_TOKEN_END && !lex->inc_state->is_last_chunk)
1947 return JSON_INCOMPLETE;
1948 else
1949 return JSON_SUCCESS;
static JsonParseErrorType json_lex_string(JsonLexContext *lex)
Definition: jsonapi.c:1963
#define JSON_ALPHANUMERIC_CHAR(c)
Definition: jsonapi.c:326
#define jsonapi_appendStringInfoCharMacro
Definition: jsonapi.c:79
static JsonIncrementalState failed_inc_oom
Definition: jsonapi.c:295
#define jsonapi_appendBinaryStringInfo
Definition: jsonapi.c:77
#define jsonapi_StrValType
Definition: jsonapi.h:73
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
char * c
int input_encoding
Definition: jsonapi.h:104
const char * prev_token_terminator
Definition: jsonapi.h:107
const char * line_start
Definition: jsonapi.h:113
int line_number
Definition: jsonapi.h:112

References Assert(), failed_inc_oom, failed_oom, i, JsonLexContext::inc_state, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, JsonIncrementalState::is_last_chunk, JSON_ALPHANUMERIC_CHAR, JSON_INCOMPLETE, JSON_INVALID_TOKEN, json_lex(), json_lex_number(), json_lex_string(), JSON_OUT_OF_MEMORY, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_COMMA, JSON_TOKEN_END, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, jsonapi_appendBinaryStringInfo, jsonapi_appendStringInfoCharMacro, jsonapi_resetStringInfo, jsonapi_StrValType, JsonLexContext::line_number, JsonLexContext::line_start, JsonLexContext::need_escapes, JsonIncrementalState::partial_completed, JsonIncrementalState::partial_token, PQExpBufferDataBroken, JsonLexContext::prev_token_terminator, JsonLexContext::strval, JsonLexContext::token_start, JsonLexContext::token_terminator, and JsonLexContext::token_type.

Referenced by json_count_array_elements(), json_get_first_token(), json_lex(), json_typeof(), lex_expect(), parse_array(), parse_object(), parse_object_field(), parse_scalar(), pg_parse_json(), and pg_parse_json_incremental().

◆ makeJsonLexContextCstringLen()

JsonLexContext * makeJsonLexContextCstringLen ( JsonLexContext lex,
const char *  json,
size_t  len,
int  encoding,
bool  need_escapes 
)

Definition at line 392 of file jsonapi.c.

394{
395 if (lex == NULL)
396 {
397 lex = ALLOC0(sizeof(JsonLexContext));
398 if (!lex)
399 return &failed_oom;
401 }
402 else
403 memset(lex, 0, sizeof(JsonLexContext));
404
405 lex->errormsg = NULL;
406 lex->input = lex->token_terminator = lex->line_start = json;
407 lex->line_number = 1;
408 lex->input_length = len;
410 lex->need_escapes = need_escapes;
411 if (need_escapes)
412 {
413 /*
414 * This call can fail in shlib code. We defer error handling to time
415 * of use (json_lex_string()) since we might not need to parse any
416 * strings anyway.
417 */
420 }
421
422 return lex;
423}
#define ALLOC0(size)
Definition: jsonapi.c:58
int32 encoding
Definition: pg_database.h:41

References ALLOC0, encoding, JsonLexContext::errormsg, failed_oom, JsonLexContext::flags, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, jsonapi_makeStringInfo, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, len, JsonLexContext::line_number, JsonLexContext::line_start, JsonLexContext::need_escapes, JsonLexContext::strval, and JsonLexContext::token_terminator.

Referenced by get_json_object_as_hash(), handle_oauth_sasl_error(), json_parse_manifest(), json_recv(), jsonb_from_cstring(), main(), makeJsonLexContext(), parse_oauth_json(), and populate_array_json().

◆ makeJsonLexContextIncremental()

JsonLexContext * makeJsonLexContextIncremental ( JsonLexContext lex,
int  encoding,
bool  need_escapes 
)

Definition at line 497 of file jsonapi.c.

500{
501 if (lex == NULL)
502 {
503 lex = ALLOC0(sizeof(JsonLexContext));
504 if (!lex)
505 return &failed_oom;
506
508 }
509 else
510 memset(lex, 0, sizeof(JsonLexContext));
511
512 lex->line_number = 1;
514
516 {
517 if (lex->flags & JSONLEX_FREE_STRUCT)
518 {
519 FREE(lex);
520 return &failed_oom;
521 }
522
523 /* lex->inc_state tracks the OOM failure; we can return here. */
524 return lex;
525 }
526
527 lex->need_escapes = need_escapes;
528 if (need_escapes)
529 {
530 /*
531 * This call can fail in shlib code. We defer error handling to time
532 * of use (json_lex_string()) since we might not need to parse any
533 * strings anyway.
534 */
537 }
538
539 return lex;
static bool allocate_incremental_state(JsonLexContext *lex)
Definition: jsonapi.c:433

References ALLOC0, allocate_incremental_state(), encoding, failed_oom, JsonLexContext::flags, FREE, JsonLexContext::input_encoding, jsonapi_makeStringInfo, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, JsonLexContext::line_number, JsonLexContext::need_escapes, and JsonLexContext::strval.

Referenced by json_parse_manifest_incremental_init(), and main().

◆ pg_parse_json()

JsonParseErrorType pg_parse_json ( JsonLexContext lex,
const JsonSemAction sem 
)

Definition at line 744 of file jsonapi.c.

746{
747#ifdef FORCE_JSON_PSTACK
748 /*
749 * We don't need partial token processing, there is only one chunk. But we
750 * still need to init the partial token string so that freeJsonLexContext
751 * works, so perform the full incremental initialization.
752 */
754 return JSON_OUT_OF_MEMORY;
755
756 return pg_parse_json_incremental(lex, sem, lex->input, lex->input_length, true);
757
758#else
759
760 JsonTokenType tok;
761 JsonParseErrorType result;
762
763 if (lex == &failed_oom)
764 return JSON_OUT_OF_MEMORY;
765 if (lex->incremental)
767
768 /* get the initial token */
769 result = json_lex(lex);
770 if (result != JSON_SUCCESS)
771 return result;
772
773 tok = lex_peek(lex);
774
775 /* parse by recursive descent */
776 switch (tok)
777 {
779 result = parse_object(lex, sem);
780 break;
782 result = parse_array(lex, sem);
783 break;
784 default:
785 result = parse_scalar(lex, sem); /* json can be a bare scalar */
786 }
787
788 if (result == JSON_SUCCESS)
790
791 return result;
792#endif
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
Definition: jsonapi.c:868
@ JSON_PARSE_END
Definition: jsonapi.c:103
static JsonParseErrorType parse_object(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1388
static JsonParseErrorType parse_scalar(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1252
static JsonParseErrorType parse_array(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1511
static JsonSemAction sem

References allocate_incremental_state(), failed_oom, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_length, JSON_INVALID_LEXER_TYPE, json_lex(), JSON_OUT_OF_MEMORY, JSON_PARSE_END, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_END, JSON_TOKEN_OBJECT_START, lex_expect(), lex_peek(), parse_array(), parse_object(), parse_scalar(), pg_parse_json_incremental(), and sem.

Referenced by handle_oauth_sasl_error(), json_parse_manifest(), json_validate(), main(), parse_oauth_json(), and pg_parse_json_or_errsave().

◆ pg_parse_json_incremental()

JsonParseErrorType pg_parse_json_incremental ( JsonLexContext lex,
const JsonSemAction sem,
const char *  json,
size_t  len,
bool  is_last 
)

Definition at line 868 of file jsonapi.c.

874{
875 JsonTokenType tok;
876 JsonParseErrorType result;
878 JsonParserStack *pstack = lex->pstack;
879
880 if (lex == &failed_oom || lex->inc_state == &failed_inc_oom)
881 return JSON_OUT_OF_MEMORY;
882 if (!lex->incremental)
884
885 lex->input = lex->token_terminator = lex->line_start = json;
886 lex->input_length = len;
887 lex->inc_state->is_last_chunk = is_last;
888 lex->inc_state->started = true;
889
890 /* get the initial token */
891 result = json_lex(lex);
892 if (result != JSON_SUCCESS)
893 return result;
894
895 tok = lex_peek(lex);
896
897 /* use prediction stack for incremental parsing */
898
899 if (!have_prediction(pstack))
900 {
902
903 push_prediction(pstack, goal);
904 }
905
906 while (have_prediction(pstack))
907 {
908 char top = pop_prediction(pstack);
909 td_entry entry;
910
911 /*
912 * these first two branches are the guts of the Table Driven method
913 */
914 if (top == tok)
915 {
916 /*
917 * tok can only be a terminal symbol, so top must be too. the
918 * token matches the top of the stack, so get the next token.
919 */
920 if (tok < JSON_TOKEN_END)
921 {
922 result = json_lex(lex);
923 if (result != JSON_SUCCESS)
924 return result;
925 tok = lex_peek(lex);
926 }
927 }
928 else if (IS_NT(top) && (entry = td_parser_table[OFS(top)][tok]).prod != NULL)
929 {
930 /*
931 * the token is in the director set for a production of the
932 * non-terminal at the top of the stack, so push the reversed RHS
933 * of the production onto the stack.
934 */
935 push_prediction(pstack, entry);
936 }
937 else if (IS_SEM(top))
938 {
939 /*
940 * top is a semantic action marker, so take action accordingly.
941 * It's important to have these markers in the prediction stack
942 * before any token they might need so we don't advance the token
943 * prematurely. Note in a couple of cases we need to do something
944 * both before and after the token.
945 */
946 switch (top)
947 {
948 case JSON_SEM_OSTART:
949 {
951
952 if (lex->lex_level >= JSON_TD_MAX_STACK)
954
955 if (ostart != NULL)
956 {
957 result = (*ostart) (sem->semstate);
958 if (result != JSON_SUCCESS)
959 return result;
960 }
961
962 if (!inc_lex_level(lex))
963 return JSON_OUT_OF_MEMORY;
964 }
965 break;
966 case JSON_SEM_OEND:
967 {
969
970 dec_lex_level(lex);
971 if (oend != NULL)
972 {
973 result = (*oend) (sem->semstate);
974 if (result != JSON_SUCCESS)
975 return result;
976 }
977 }
978 break;
979 case JSON_SEM_ASTART:
980 {
982
983 if (lex->lex_level >= JSON_TD_MAX_STACK)
985
986 if (astart != NULL)
987 {
988 result = (*astart) (sem->semstate);
989 if (result != JSON_SUCCESS)
990 return result;
991 }
992
993 if (!inc_lex_level(lex))
994 return JSON_OUT_OF_MEMORY;
995 }
996 break;
997 case JSON_SEM_AEND:
998 {
1000
1001 dec_lex_level(lex);
1002 if (aend != NULL)
1003 {
1004 result = (*aend) (sem->semstate);
1005 if (result != JSON_SUCCESS)
1006 return result;
1007 }
1008 }
1009 break;
1011 {
1012 /*
1013 * all we do here is save out the field name. We have
1014 * to wait to get past the ':' to see if the next
1015 * value is null so we can call the semantic routine
1016 */
1017 char *fname = NULL;
1020
1021 if ((ostart != NULL || oend != NULL) && lex->need_escapes)
1022 {
1023 fname = STRDUP(lex->strval->data);
1024 if (fname == NULL)
1025 return JSON_OUT_OF_MEMORY;
1026 }
1027 set_fname(lex, fname);
1028 }
1029 break;
1031 {
1032 /*
1033 * the current token should be the first token of the
1034 * value
1035 */
1036 bool isnull = tok == JSON_TOKEN_NULL;
1038
1039 set_fnull(lex, isnull);
1040
1041 if (ostart != NULL)
1042 {
1043 char *fname = get_fname(lex);
1044
1045 result = (*ostart) (sem->semstate, fname, isnull);
1046 if (result != JSON_SUCCESS)
1047 return result;
1048 }
1049 }
1050 break;
1052 {
1054
1055 if (oend != NULL)
1056 {
1057 char *fname = get_fname(lex);
1058 bool isnull = get_fnull(lex);
1059
1060 result = (*oend) (sem->semstate, fname, isnull);
1061 if (result != JSON_SUCCESS)
1062 return result;
1063 }
1064 }
1065 break;
1067 {
1069 bool isnull = tok == JSON_TOKEN_NULL;
1070
1071 set_fnull(lex, isnull);
1072
1073 if (astart != NULL)
1074 {
1075 result = (*astart) (sem->semstate, isnull);
1076 if (result != JSON_SUCCESS)
1077 return result;
1078 }
1079 }
1080 break;
1081 case JSON_SEM_AELEM_END:
1082 {
1084
1085 if (aend != NULL)
1086 {
1087 bool isnull = get_fnull(lex);
1088
1089 result = (*aend) (sem->semstate, isnull);
1090 if (result != JSON_SUCCESS)
1091 return result;
1092 }
1093 }
1094 break;
1096 {
1097 json_scalar_action sfunc = sem->scalar;
1098
1099 pstack->scalar_val = NULL;
1100
1101 if (sfunc != NULL)
1102 {
1103 /*
1104 * extract the de-escaped string value, or the raw
1105 * lexeme
1106 */
1107 /*
1108 * XXX copied from RD parser but looks like a
1109 * buglet
1110 */
1111 if (tok == JSON_TOKEN_STRING)
1112 {
1113 if (lex->need_escapes)
1114 {
1115 pstack->scalar_val = STRDUP(lex->strval->data);
1116 if (pstack->scalar_val == NULL)
1117 return JSON_OUT_OF_MEMORY;
1118 }
1119 }
1120 else
1121 {
1122 ptrdiff_t tlen = (lex->token_terminator - lex->token_start);
1123
1124 pstack->scalar_val = ALLOC(tlen + 1);
1125 if (pstack->scalar_val == NULL)
1126 return JSON_OUT_OF_MEMORY;
1127
1128 memcpy(pstack->scalar_val, lex->token_start, tlen);
1129 pstack->scalar_val[tlen] = '\0';
1130 }
1131 pstack->scalar_tok = tok;
1132 }
1133 }
1134 break;
1136 {
1137 /*
1138 * We'd like to be able to get rid of this business of
1139 * two bits of scalar action, but we can't. It breaks
1140 * certain semantic actions which expect that when
1141 * called the lexer has consumed the item. See for
1142 * example get_scalar() in jsonfuncs.c.
1143 */
1144 json_scalar_action sfunc = sem->scalar;
1145
1146 if (sfunc != NULL)
1147 {
1148 result = (*sfunc) (sem->semstate, pstack->scalar_val, pstack->scalar_tok);
1149
1150 /*
1151 * Either ownership of the token passed to the
1152 * callback, or we need to free it now. Either
1153 * way, clear our pointer to it so it doesn't get
1154 * freed in the future.
1155 */
1156 if (lex->flags & JSONLEX_CTX_OWNS_TOKENS)
1157 FREE(pstack->scalar_val);
1158 pstack->scalar_val = NULL;
1159
1160 if (result != JSON_SUCCESS)
1161 return result;
1162 }
1163 }
1164 break;
1165 default:
1166 /* should not happen */
1167 break;
1168 }
1169 }
1170 else
1171 {
1172 /*
1173 * The token didn't match the stack top if it's a terminal nor a
1174 * production for the stack top if it's a non-terminal.
1175 *
1176 * Various cases here are Asserted to be not possible, as the
1177 * token would not appear at the top of the prediction stack
1178 * unless the lookahead matched.
1179 */
1180 switch (top)
1181 {
1182 case JSON_TOKEN_STRING:
1183 if (next_prediction(pstack) == JSON_TOKEN_COLON)
1184 ctx = JSON_PARSE_STRING;
1185 else
1186 {
1187 Assert(false);
1188 ctx = JSON_PARSE_VALUE;
1189 }
1190 break;
1191 case JSON_TOKEN_NUMBER:
1192 case JSON_TOKEN_TRUE:
1193 case JSON_TOKEN_FALSE:
1194 case JSON_TOKEN_NULL:
1197 Assert(false);
1198 ctx = JSON_PARSE_VALUE;
1199 break;
1201 Assert(false);
1203 break;
1205 Assert(false);
1207 break;
1208 case JSON_TOKEN_COMMA:
1209 Assert(false);
1210 if (next_prediction(pstack) == JSON_TOKEN_STRING)
1212 else
1214 break;
1215 case JSON_TOKEN_COLON:
1217 break;
1218 case JSON_TOKEN_END:
1219 ctx = JSON_PARSE_END;
1220 break;
1223 break;
1226 break;
1229 break;
1230 case JSON_NT_KEY_PAIRS:
1232 break;
1233 default:
1234 ctx = JSON_PARSE_VALUE;
1235 }
1236 return report_parse_error(ctx, lex);
1237 }
1238 }
1239
1240 return JSON_SUCCESS;
#define JSON_TD_MAX_STACK
Definition: jsonapi.c:431
JsonParseContext
Definition: jsonapi.c:94
@ JSON_PARSE_OBJECT_LABEL
Definition: jsonapi.c:100
@ JSON_PARSE_VALUE
Definition: jsonapi.c:95
@ JSON_PARSE_OBJECT_START
Definition: jsonapi.c:99
@ JSON_PARSE_OBJECT_NEXT
Definition: jsonapi.c:101
@ JSON_PARSE_STRING
Definition: jsonapi.c:96
#define TD_ENTRY(PROD)
Definition: jsonapi.c:239
@ JSON_SEM_SCALAR_CALL
Definition: jsonapi.c:134
@ JSON_SEM_OSTART
Definition: jsonapi.c:124
@ JSON_SEM_AELEM_START
Definition: jsonapi.c:131
@ JSON_SEM_AELEM_END
Definition: jsonapi.c:132
@ JSON_SEM_SCALAR_INIT
Definition: jsonapi.c:133
@ JSON_SEM_ASTART
Definition: jsonapi.c:126
@ JSON_SEM_OFIELD_INIT
Definition: jsonapi.c:128
@ JSON_SEM_OFIELD_END
Definition: jsonapi.c:130
@ JSON_SEM_OEND
Definition: jsonapi.c:125
@ JSON_SEM_OFIELD_START
Definition: jsonapi.c:129
@ JSON_SEM_AEND
Definition: jsonapi.c:127
static void set_fnull(JsonLexContext *lex, bool fnull)
Definition: jsonapi.c:668
#define OFS(NT)
Definition: jsonapi.c:177
static bool inc_lex_level(JsonLexContext *lex)
Definition: jsonapi.c:561
static bool have_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:641
static void set_fname(JsonLexContext *lex, char *fname)
Definition: jsonapi.c:647
static char next_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:634
static void push_prediction(JsonParserStack *pstack, td_entry entry)
Definition: jsonapi.c:620
#define IS_NT(x)
Definition: jsonapi.c:180
static char * get_fname(JsonLexContext *lex)
Definition: jsonapi.c:662
static char JSON_PROD_GOAL[]
Definition: jsonapi.c:272
#define STRDUP(s)
Definition: jsonapi.c:56
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
Definition: jsonapi.c:2357
#define IS_SEM(x)
Definition: jsonapi.c:179
static td_entry td_parser_table[JSON_NUM_NONTERMINALS][JSON_NUM_TERMINALS]
Definition: jsonapi.c:241
static char pop_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:627
#define ALLOC(size)
Definition: jsonapi.c:57
static bool get_fnull(JsonLexContext *lex)
Definition: jsonapi.c:674
@ JSON_NT_MORE_ARRAY_ELEMENTS
Definition: jsonapi.c:117
@ JSON_NT_MORE_KEY_PAIRS
Definition: jsonapi.c:119
@ JSON_NT_ARRAY_ELEMENTS
Definition: jsonapi.c:116
@ JSON_NT_KEY_PAIRS
Definition: jsonapi.c:118
static void dec_lex_level(JsonLexContext *lex)
Definition: jsonapi.c:613
JsonParseErrorType(* json_struct_action)(void *state)
Definition: jsonapi.h:127
JsonParseErrorType(* json_aelem_action)(void *state, bool isnull)
Definition: jsonapi.h:129
JsonParseErrorType(* json_ofield_action)(void *state, char *fname, bool isnull)
Definition: jsonapi.h:128
JsonParseErrorType(* json_scalar_action)(void *state, char *token, JsonTokenType tokentype)
Definition: jsonapi.h:130
JsonTokenType scalar_tok
Definition: jsonapi.c:152
json_struct_action array_end
Definition: jsonapi.h:157
json_struct_action object_start
Definition: jsonapi.h:154
json_ofield_action object_field_start
Definition: jsonapi.h:158
json_aelem_action array_element_start
Definition: jsonapi.h:160
json_scalar_action scalar
Definition: jsonapi.h:162
void * semstate
Definition: jsonapi.h:153
json_aelem_action array_element_end
Definition: jsonapi.h:161
json_struct_action array_start
Definition: jsonapi.h:156
json_struct_action object_end
Definition: jsonapi.h:155
json_ofield_action object_field_end
Definition: jsonapi.h:159
Definition: jsonapi.c:234

References ALLOC, JsonSemAction::array_element_end, JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, Assert(), dec_lex_level(), failed_inc_oom, failed_oom, JsonLexContext::flags, FREE, get_fname(), get_fnull(), have_prediction(), inc_lex_level(), JsonLexContext::inc_state, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_length, JsonIncrementalState::is_last_chunk, IS_NT, IS_SEM, JSON_INVALID_LEXER_TYPE, json_lex(), JSON_NESTING_TOO_DEEP, JSON_NT_ARRAY_ELEMENTS, JSON_NT_KEY_PAIRS, JSON_NT_MORE_ARRAY_ELEMENTS, JSON_NT_MORE_KEY_PAIRS, JSON_OUT_OF_MEMORY, JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_PARSE_END, JSON_PARSE_OBJECT_LABEL, JSON_PARSE_OBJECT_NEXT, JSON_PARSE_OBJECT_START, JSON_PARSE_STRING, JSON_PARSE_VALUE, JSON_PROD_GOAL, JSON_SEM_AELEM_END, JSON_SEM_AELEM_START, JSON_SEM_AEND, JSON_SEM_ASTART, JSON_SEM_OEND, JSON_SEM_OFIELD_END, JSON_SEM_OFIELD_INIT, JSON_SEM_OFIELD_START, JSON_SEM_OSTART, JSON_SEM_SCALAR_CALL, JSON_SEM_SCALAR_INIT, JSON_SUCCESS, JSON_TD_MAX_STACK, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_COMMA, JSON_TOKEN_END, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, JSONLEX_CTX_OWNS_TOKENS, len, JsonLexContext::lex_level, lex_peek(), JsonLexContext::line_start, JsonLexContext::need_escapes, next_prediction(), JsonSemAction::object_end, JsonSemAction::object_field_end, JsonSemAction::object_field_start, JsonSemAction::object_start, OFS, pop_prediction(), JsonLexContext::pstack, push_prediction(), report_parse_error(), JsonSemAction::scalar, JsonParserStack::scalar_tok, JsonParserStack::scalar_val, sem, JsonSemAction::semstate, set_fname(), set_fnull(), JsonIncrementalState::started, STRDUP, JsonLexContext::strval, TD_ENTRY, td_parser_table, JsonLexContext::token_start, and JsonLexContext::token_terminator.

Referenced by json_parse_manifest_incremental_chunk(), main(), and pg_parse_json().

◆ setJsonLexContextOwnsTokens()

void setJsonLexContextOwnsTokens ( JsonLexContext lex,
bool  owned_by_context 
)

Definition at line 542 of file jsonapi.c.

544{
545 if (lex->incremental && lex->inc_state->started)
546 {
547 /*
548 * Switching this flag after parsing has already started is a
549 * programming error.
550 */
551 Assert(false);
552 return;
553 }
554
555 if (owned_by_context)
557 else
558 lex->flags &= ~JSONLEX_CTX_OWNS_TOKENS;

References Assert(), JsonLexContext::flags, JsonLexContext::inc_state, JsonLexContext::incremental, JSONLEX_CTX_OWNS_TOKENS, and JsonIncrementalState::started.

Referenced by handle_oauth_sasl_error(), main(), and parse_oauth_json().

Variable Documentation

◆ nullSemAction

PGDLLIMPORT const JsonSemAction nullSemAction
extern

Definition at line 287 of file jsonapi.c.

Referenced by json_count_array_elements(), json_in(), json_recv(), json_validate(), and main().