mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
jsonpath scanner: reentrant scanner
Use the flex %option reentrant to make the generated scanner reentrant and thread-safe. Note: The parser was already pure. Simplify flex scan buffer management: Instead of constructing the buffer from pieces and then using yy_scan_buffer(), we can just use yy_scan_string(), which does the same thing internally. (Actually, we use yy_scan_bytes() here because we already have the length.) Use flex yyextra to handle context information, instead of global variables. This complements the other changes to make the scanner reentrant. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Reviewed-by: Andreas Karlsson <andreas@proxel.se> Discussion: https://www.postgresql.org/message-id/flat/eb6faeac-2a8a-4b69-9189-c33c520e5b7b@eisentraut.org
This commit is contained in:
@ -7,7 +7,7 @@ GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) \
|
|||||||
GUC_check_errhint \
|
GUC_check_errhint \
|
||||||
write_stderr \
|
write_stderr \
|
||||||
yyerror \
|
yyerror \
|
||||||
jsonpath_yyerror:3 \
|
jsonpath_yyerror:4 \
|
||||||
parser_yyerror \
|
parser_yyerror \
|
||||||
replication_yyerror:2 \
|
replication_yyerror:2 \
|
||||||
scanner_yyerror \
|
scanner_yyerror \
|
||||||
|
@ -60,8 +60,10 @@ static bool makeItemLikeRegex(JsonPathParseItem *expr,
|
|||||||
%name-prefix="jsonpath_yy"
|
%name-prefix="jsonpath_yy"
|
||||||
%parse-param {JsonPathParseResult **result}
|
%parse-param {JsonPathParseResult **result}
|
||||||
%parse-param {struct Node *escontext}
|
%parse-param {struct Node *escontext}
|
||||||
|
%parse-param {yyscan_t yyscanner}
|
||||||
%lex-param {JsonPathParseResult **result}
|
%lex-param {JsonPathParseResult **result}
|
||||||
%lex-param {struct Node *escontext}
|
%lex-param {struct Node *escontext}
|
||||||
|
%lex-param {yyscan_t yyscanner}
|
||||||
|
|
||||||
%union
|
%union
|
||||||
{
|
{
|
||||||
|
@ -22,17 +22,25 @@ typedef struct JsonPathString
|
|||||||
int total;
|
int total;
|
||||||
} JsonPathString;
|
} JsonPathString;
|
||||||
|
|
||||||
|
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||||
|
#define YY_TYPEDEF_YY_SCANNER_T
|
||||||
|
typedef void *yyscan_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "utils/jsonpath.h"
|
#include "utils/jsonpath.h"
|
||||||
#include "jsonpath_gram.h"
|
#include "jsonpath_gram.h"
|
||||||
|
|
||||||
#define YY_DECL extern int jsonpath_yylex(YYSTYPE *yylval_param, \
|
#define YY_DECL extern int jsonpath_yylex(YYSTYPE *yylval_param, \
|
||||||
JsonPathParseResult **result, \
|
JsonPathParseResult **result, \
|
||||||
struct Node *escontext)
|
struct Node *escontext, \
|
||||||
|
yyscan_t yyscanner)
|
||||||
YY_DECL;
|
YY_DECL;
|
||||||
extern int jsonpath_yyparse(JsonPathParseResult **result,
|
extern int jsonpath_yyparse(JsonPathParseResult **result,
|
||||||
struct Node *escontext);
|
struct Node *escontext,
|
||||||
|
yyscan_t yyscanner);
|
||||||
extern void jsonpath_yyerror(JsonPathParseResult **result,
|
extern void jsonpath_yyerror(JsonPathParseResult **result,
|
||||||
struct Node *escontext,
|
struct Node *escontext,
|
||||||
|
yyscan_t yyscanner,
|
||||||
const char *message);
|
const char *message);
|
||||||
|
|
||||||
#endif /* JSONPATH_INTERNAL_H */
|
#endif /* JSONPATH_INTERNAL_H */
|
||||||
|
@ -30,18 +30,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%{
|
%{
|
||||||
static JsonPathString scanstring;
|
struct jsonpath_yy_extra_type
|
||||||
|
{
|
||||||
|
JsonPathString scanstring;
|
||||||
|
};
|
||||||
|
#define YY_EXTRA_TYPE struct jsonpath_yy_extra_type *
|
||||||
|
|
||||||
/* Handles to the buffer that the lexer uses internally */
|
static void addstring(bool init, char *s, int l, yyscan_t yyscanner);
|
||||||
static YY_BUFFER_STATE scanbufhandle;
|
static void addchar(bool init, char c, yyscan_t yyscanner);
|
||||||
static char *scanbuf;
|
static enum yytokentype checkKeyword(yyscan_t yyscanner);
|
||||||
static int scanbuflen;
|
static bool parseUnicode(char *s, int l, struct Node *escontext, yyscan_t yyscanner);
|
||||||
|
static bool parseHexChar(char *s, struct Node *escontext, yyscan_t yyscanner);
|
||||||
static void addstring(bool init, char *s, int l);
|
|
||||||
static void addchar(bool init, char c);
|
|
||||||
static enum yytokentype checkKeyword(void);
|
|
||||||
static bool parseUnicode(char *s, int l, struct Node *escontext);
|
|
||||||
static bool parseHexChar(char *s, struct Node *escontext);
|
|
||||||
|
|
||||||
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
|
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
|
||||||
#undef fprintf
|
#undef fprintf
|
||||||
@ -65,6 +64,7 @@ fprintf_to_ereport(const char *fmt, const char *msg)
|
|||||||
%option noyywrap
|
%option noyywrap
|
||||||
%option warn
|
%option warn
|
||||||
%option prefix="jsonpath_yy"
|
%option prefix="jsonpath_yy"
|
||||||
|
%option reentrant
|
||||||
%option bison-bridge
|
%option bison-bridge
|
||||||
%option noyyalloc
|
%option noyyalloc
|
||||||
%option noyyrealloc
|
%option noyyrealloc
|
||||||
@ -120,63 +120,63 @@ hex_fail \\x{hexdigit}{0,1}
|
|||||||
%%
|
%%
|
||||||
|
|
||||||
<xnq>{other}+ {
|
<xnq>{other}+ {
|
||||||
addstring(false, yytext, yyleng);
|
addstring(false, yytext, yyleng, yyscanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq>{blank}+ {
|
<xnq>{blank}+ {
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
BEGIN INITIAL;
|
BEGIN INITIAL;
|
||||||
return checkKeyword();
|
return checkKeyword(yyscanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq>\/\* {
|
<xnq>\/\* {
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
BEGIN xc;
|
BEGIN xc;
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq>({special}|\") {
|
<xnq>({special}|\") {
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
yyless(0);
|
yyless(0);
|
||||||
BEGIN INITIAL;
|
BEGIN INITIAL;
|
||||||
return checkKeyword();
|
return checkKeyword(yyscanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq><<EOF>> {
|
<xnq><<EOF>> {
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
BEGIN INITIAL;
|
BEGIN INITIAL;
|
||||||
return checkKeyword();
|
return checkKeyword(yyscanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq,xq,xvq>\\b { addchar(false, '\b'); }
|
<xnq,xq,xvq>\\b { addchar(false, '\b', yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>\\f { addchar(false, '\f'); }
|
<xnq,xq,xvq>\\f { addchar(false, '\f', yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>\\n { addchar(false, '\n'); }
|
<xnq,xq,xvq>\\n { addchar(false, '\n', yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>\\r { addchar(false, '\r'); }
|
<xnq,xq,xvq>\\r { addchar(false, '\r', yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>\\t { addchar(false, '\t'); }
|
<xnq,xq,xvq>\\t { addchar(false, '\t', yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>\\v { addchar(false, '\v'); }
|
<xnq,xq,xvq>\\v { addchar(false, '\v', yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>{unicode}+ {
|
<xnq,xq,xvq>{unicode}+ {
|
||||||
if (!parseUnicode(yytext, yyleng, escontext))
|
if (!parseUnicode(yytext, yyleng, escontext, yyscanner))
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq,xq,xvq>{hex_char} {
|
<xnq,xq,xvq>{hex_char} {
|
||||||
if (!parseHexChar(yytext, escontext))
|
if (!parseHexChar(yytext, escontext, yyscanner))
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq,xq,xvq>{unicode}*{unicodefail} {
|
<xnq,xq,xvq>{unicode}*{unicodefail} {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"invalid Unicode escape sequence");
|
"invalid Unicode escape sequence");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq,xq,xvq>{hex_fail} {
|
<xnq,xq,xvq>{hex_fail} {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"invalid hexadecimal character sequence");
|
"invalid hexadecimal character sequence");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
@ -184,37 +184,37 @@ hex_fail \\x{hexdigit}{0,1}
|
|||||||
<xnq,xq,xvq>{unicode}+\\ {
|
<xnq,xq,xvq>{unicode}+\\ {
|
||||||
/* throw back the \\, and treat as unicode */
|
/* throw back the \\, and treat as unicode */
|
||||||
yyless(yyleng - 1);
|
yyless(yyleng - 1);
|
||||||
if (!parseUnicode(yytext, yyleng, escontext))
|
if (!parseUnicode(yytext, yyleng, escontext, yyscanner))
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<xnq,xq,xvq>\\. { addchar(false, yytext[1]); }
|
<xnq,xq,xvq>\\. { addchar(false, yytext[1], yyscanner); }
|
||||||
|
|
||||||
<xnq,xq,xvq>\\ {
|
<xnq,xq,xvq>\\ {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"unexpected end after backslash");
|
"unexpected end after backslash");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<xq,xvq><<EOF>> {
|
<xq,xvq><<EOF>> {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"unterminated quoted string");
|
"unterminated quoted string");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<xq>\" {
|
<xq>\" {
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
BEGIN INITIAL;
|
BEGIN INITIAL;
|
||||||
return STRING_P;
|
return STRING_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
<xvq>\" {
|
<xvq>\" {
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
BEGIN INITIAL;
|
BEGIN INITIAL;
|
||||||
return VARIABLE_P;
|
return VARIABLE_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
<xq,xvq>[^\\\"]+ { addstring(false, yytext, yyleng); }
|
<xq,xvq>[^\\\"]+ { addstring(false, yytext, yyleng, yyscanner); }
|
||||||
|
|
||||||
<xc>\*\/ { BEGIN INITIAL; }
|
<xc>\*\/ { BEGIN INITIAL; }
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ hex_fail \\x{hexdigit}{0,1}
|
|||||||
<xc>\* { }
|
<xc>\* { }
|
||||||
|
|
||||||
<xc><<EOF>> {
|
<xc><<EOF>> {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"unexpected end of comment");
|
"unexpected end of comment");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
@ -250,14 +250,14 @@ hex_fail \\x{hexdigit}{0,1}
|
|||||||
\> { return GREATER_P; }
|
\> { return GREATER_P; }
|
||||||
|
|
||||||
\${other}+ {
|
\${other}+ {
|
||||||
addstring(true, yytext + 1, yyleng - 1);
|
addstring(true, yytext + 1, yyleng - 1, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return VARIABLE_P;
|
return VARIABLE_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
\$\" {
|
\$\" {
|
||||||
addchar(true, '\0');
|
addchar(true, '\0', yyscanner);
|
||||||
BEGIN xvq;
|
BEGIN xvq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,85 +266,85 @@ hex_fail \\x{hexdigit}{0,1}
|
|||||||
{blank}+ { /* ignore */ }
|
{blank}+ { /* ignore */ }
|
||||||
|
|
||||||
\/\* {
|
\/\* {
|
||||||
addchar(true, '\0');
|
addchar(true, '\0', yyscanner);
|
||||||
BEGIN xc;
|
BEGIN xc;
|
||||||
}
|
}
|
||||||
|
|
||||||
{real} {
|
{real} {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return NUMERIC_P;
|
return NUMERIC_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
{decimal} {
|
{decimal} {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return NUMERIC_P;
|
return NUMERIC_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
{decinteger} {
|
{decinteger} {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return INT_P;
|
return INT_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
{hexinteger} {
|
{hexinteger} {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return INT_P;
|
return INT_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
{octinteger} {
|
{octinteger} {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return INT_P;
|
return INT_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
{bininteger} {
|
{bininteger} {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
addchar(false, '\0');
|
addchar(false, '\0', yyscanner);
|
||||||
yylval->str = scanstring;
|
yylval->str = yyextra->scanstring;
|
||||||
return INT_P;
|
return INT_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
{realfail} {
|
{realfail} {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"invalid numeric literal");
|
"invalid numeric literal");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
{decinteger_junk} {
|
{decinteger_junk} {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"trailing junk after numeric literal");
|
"trailing junk after numeric literal");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
{decimal_junk} {
|
{decimal_junk} {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"trailing junk after numeric literal");
|
"trailing junk after numeric literal");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
{real_junk} {
|
{real_junk} {
|
||||||
jsonpath_yyerror(NULL, escontext,
|
jsonpath_yyerror(NULL, escontext, yyscanner,
|
||||||
"trailing junk after numeric literal");
|
"trailing junk after numeric literal");
|
||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
\" {
|
\" {
|
||||||
addchar(true, '\0');
|
addchar(true, '\0', yyscanner);
|
||||||
BEGIN xq;
|
BEGIN xq;
|
||||||
}
|
}
|
||||||
|
|
||||||
\\ {
|
\\ {
|
||||||
yyless(0);
|
yyless(0);
|
||||||
addchar(true, '\0');
|
addchar(true, '\0', yyscanner);
|
||||||
BEGIN xnq;
|
BEGIN xnq;
|
||||||
}
|
}
|
||||||
|
|
||||||
{other}+ {
|
{other}+ {
|
||||||
addstring(true, yytext, yyleng);
|
addstring(true, yytext, yyleng, yyscanner);
|
||||||
BEGIN xnq;
|
BEGIN xnq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,10 +354,17 @@ hex_fail \\x{hexdigit}{0,1}
|
|||||||
|
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
|
|
||||||
|
/* see scan.l */
|
||||||
|
#undef yyextra
|
||||||
|
#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
|
||||||
|
|
||||||
void
|
void
|
||||||
jsonpath_yyerror(JsonPathParseResult **result, struct Node *escontext,
|
jsonpath_yyerror(JsonPathParseResult **result, struct Node *escontext,
|
||||||
|
yyscan_t yyscanner,
|
||||||
const char *message)
|
const char *message)
|
||||||
{
|
{
|
||||||
|
struct yyguts_t * yyg = (struct yyguts_t *) yyscanner; /* needed for yytext macro */
|
||||||
|
|
||||||
/* don't overwrite escontext if it's already been set */
|
/* don't overwrite escontext if it's already been set */
|
||||||
if (SOFT_ERROR_OCCURRED(escontext))
|
if (SOFT_ERROR_OCCURRED(escontext))
|
||||||
return;
|
return;
|
||||||
@ -427,9 +434,11 @@ static const JsonPathKeyword keywords[] = {
|
|||||||
{ 12,false, TIMESTAMP_TZ_P, "timestamp_tz"},
|
{ 12,false, TIMESTAMP_TZ_P, "timestamp_tz"},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Check if current scanstring value is a keyword */
|
/*
|
||||||
|
* Check if current scanstring value is a keyword
|
||||||
|
*/
|
||||||
static enum yytokentype
|
static enum yytokentype
|
||||||
checkKeyword()
|
checkKeyword(yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
int res = IDENT_P;
|
int res = IDENT_P;
|
||||||
int diff;
|
int diff;
|
||||||
@ -437,18 +446,18 @@ checkKeyword()
|
|||||||
*StopHigh = keywords + lengthof(keywords),
|
*StopHigh = keywords + lengthof(keywords),
|
||||||
*StopMiddle;
|
*StopMiddle;
|
||||||
|
|
||||||
if (scanstring.len > keywords[lengthof(keywords) - 1].len)
|
if (yyextra->scanstring.len > keywords[lengthof(keywords) - 1].len)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
while (StopLow < StopHigh)
|
while (StopLow < StopHigh)
|
||||||
{
|
{
|
||||||
StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
|
StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
|
||||||
|
|
||||||
if (StopMiddle->len == scanstring.len)
|
if (StopMiddle->len == yyextra->scanstring.len)
|
||||||
diff = pg_strncasecmp(StopMiddle->keyword, scanstring.val,
|
diff = pg_strncasecmp(StopMiddle->keyword, yyextra->scanstring.val,
|
||||||
scanstring.len);
|
yyextra->scanstring.len);
|
||||||
else
|
else
|
||||||
diff = StopMiddle->len - scanstring.len;
|
diff = StopMiddle->len - yyextra->scanstring.len;
|
||||||
|
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
StopLow = StopMiddle + 1;
|
StopLow = StopMiddle + 1;
|
||||||
@ -457,8 +466,8 @@ checkKeyword()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (StopMiddle->lowercase)
|
if (StopMiddle->lowercase)
|
||||||
diff = strncmp(StopMiddle->keyword, scanstring.val,
|
diff = strncmp(StopMiddle->keyword, yyextra->scanstring.val,
|
||||||
scanstring.len);
|
yyextra->scanstring.len);
|
||||||
|
|
||||||
if (diff == 0)
|
if (diff == 0)
|
||||||
res = StopMiddle->val;
|
res = StopMiddle->val;
|
||||||
@ -470,85 +479,47 @@ checkKeyword()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Called before any actual parsing is done
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
jsonpath_scanner_init(const char *str, int slen)
|
|
||||||
{
|
|
||||||
if (slen <= 0)
|
|
||||||
slen = strlen(str);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Might be left over after ereport()
|
|
||||||
*/
|
|
||||||
yy_init_globals();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make a scan buffer with special termination needed by flex.
|
|
||||||
*/
|
|
||||||
|
|
||||||
scanbuflen = slen;
|
|
||||||
scanbuf = palloc(slen + 2);
|
|
||||||
memcpy(scanbuf, str, slen);
|
|
||||||
scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
|
|
||||||
scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
|
|
||||||
|
|
||||||
BEGIN(INITIAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called after parsing is done to clean up after jsonpath_scanner_init()
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
jsonpath_scanner_finish(void)
|
|
||||||
{
|
|
||||||
yy_delete_buffer(scanbufhandle);
|
|
||||||
pfree(scanbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resize scanstring so that it can append string of given length.
|
* Resize scanstring so that it can append string of given length.
|
||||||
* Reinitialize if required.
|
* Reinitialize if required.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
resizeString(bool init, int appendLen)
|
resizeString(bool init, int appendLen, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
if (init)
|
if (init)
|
||||||
{
|
{
|
||||||
scanstring.total = Max(32, appendLen);
|
yyextra->scanstring.total = Max(32, appendLen);
|
||||||
scanstring.val = (char *) palloc(scanstring.total);
|
yyextra->scanstring.val = (char *) palloc(yyextra->scanstring.total);
|
||||||
scanstring.len = 0;
|
yyextra->scanstring.len = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (scanstring.len + appendLen >= scanstring.total)
|
if (yyextra->scanstring.len + appendLen >= yyextra->scanstring.total)
|
||||||
{
|
{
|
||||||
while (scanstring.len + appendLen >= scanstring.total)
|
while (yyextra->scanstring.len + appendLen >= yyextra->scanstring.total)
|
||||||
scanstring.total *= 2;
|
yyextra->scanstring.total *= 2;
|
||||||
scanstring.val = repalloc(scanstring.val, scanstring.total);
|
yyextra->scanstring.val = repalloc(yyextra->scanstring.val, yyextra->scanstring.total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add set of bytes at "s" of length "l" to scanstring */
|
/* Add set of bytes at "s" of length "l" to scanstring */
|
||||||
static void
|
static void
|
||||||
addstring(bool init, char *s, int l)
|
addstring(bool init, char *s, int l, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
resizeString(init, l + 1);
|
resizeString(init, l + 1, yyscanner);
|
||||||
memcpy(scanstring.val + scanstring.len, s, l);
|
memcpy(yyextra->scanstring.val + yyextra->scanstring.len, s, l);
|
||||||
scanstring.len += l;
|
yyextra->scanstring.len += l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add single byte "c" to scanstring */
|
/* Add single byte "c" to scanstring */
|
||||||
static void
|
static void
|
||||||
addchar(bool init, char c)
|
addchar(bool init, char c, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
resizeString(init, 1);
|
resizeString(init, 1, yyscanner);
|
||||||
scanstring.val[scanstring.len] = c;
|
yyextra->scanstring.val[yyextra->scanstring.len] = c;
|
||||||
if (c != '\0')
|
if (c != '\0')
|
||||||
scanstring.len++;
|
yyextra->scanstring.len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interface to jsonpath parser */
|
/* Interface to jsonpath parser */
|
||||||
@ -556,20 +527,30 @@ JsonPathParseResult *
|
|||||||
parsejsonpath(const char *str, int len, struct Node *escontext)
|
parsejsonpath(const char *str, int len, struct Node *escontext)
|
||||||
{
|
{
|
||||||
JsonPathParseResult *parseresult;
|
JsonPathParseResult *parseresult;
|
||||||
|
yyscan_t scanner;
|
||||||
|
struct jsonpath_yy_extra_type yyext;
|
||||||
|
|
||||||
jsonpath_scanner_init(str, len);
|
if (jsonpath_yylex_init(&scanner) != 0)
|
||||||
|
elog(ERROR, "yylex_init() failed: %m");
|
||||||
|
|
||||||
if (jsonpath_yyparse(&parseresult, escontext) != 0)
|
yyset_extra(&yyext, scanner);
|
||||||
jsonpath_yyerror(NULL, escontext, "invalid input"); /* shouldn't happen */
|
|
||||||
|
|
||||||
jsonpath_scanner_finish();
|
if (len <= 0)
|
||||||
|
len = strlen(str);
|
||||||
|
|
||||||
|
jsonpath_yy_scan_bytes(str, len, scanner);
|
||||||
|
|
||||||
|
if (jsonpath_yyparse(&parseresult, escontext, scanner) != 0)
|
||||||
|
jsonpath_yyerror(NULL, escontext, scanner, "invalid input"); /* shouldn't happen */
|
||||||
|
|
||||||
|
jsonpath_yylex_destroy(scanner);
|
||||||
|
|
||||||
return parseresult;
|
return parseresult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn hex character into integer */
|
/* Turn hex character into integer */
|
||||||
static bool
|
static bool
|
||||||
hexval(char c, int *result, struct Node *escontext)
|
hexval(char c, int *result, struct Node *escontext, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
{
|
{
|
||||||
@ -586,13 +567,13 @@ hexval(char c, int *result, struct Node *escontext)
|
|||||||
*result = c - 'A' + 0xA;
|
*result = c - 'A' + 0xA;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
jsonpath_yyerror(NULL, escontext, "invalid hexadecimal digit");
|
jsonpath_yyerror(NULL, escontext, yyscanner, "invalid hexadecimal digit");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add given unicode character to scanstring */
|
/* Add given unicode character to scanstring */
|
||||||
static bool
|
static bool
|
||||||
addUnicodeChar(int ch, struct Node *escontext)
|
addUnicodeChar(int ch, struct Node *escontext, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
if (ch == 0)
|
if (ch == 0)
|
||||||
{
|
{
|
||||||
@ -618,14 +599,14 @@ addUnicodeChar(int ch, struct Node *escontext)
|
|||||||
ereturn(escontext, false,
|
ereturn(escontext, false,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("could not convert Unicode to server encoding")));
|
errmsg("could not convert Unicode to server encoding")));
|
||||||
addstring(false, cbuf, strlen(cbuf));
|
addstring(false, cbuf, strlen(cbuf), yyscanner);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add unicode character, processing any surrogate pairs */
|
/* Add unicode character, processing any surrogate pairs */
|
||||||
static bool
|
static bool
|
||||||
addUnicode(int ch, int *hi_surrogate, struct Node *escontext)
|
addUnicode(int ch, int *hi_surrogate, struct Node *escontext, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
if (is_utf16_surrogate_first(ch))
|
if (is_utf16_surrogate_first(ch))
|
||||||
{
|
{
|
||||||
@ -658,7 +639,7 @@ addUnicode(int ch, int *hi_surrogate, struct Node *escontext)
|
|||||||
"surrogate.")));
|
"surrogate.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return addUnicodeChar(ch, escontext);
|
return addUnicodeChar(ch, escontext, yyscanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -666,7 +647,7 @@ addUnicode(int ch, int *hi_surrogate, struct Node *escontext)
|
|||||||
* src/backend/utils/adt/json.c
|
* src/backend/utils/adt/json.c
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
parseUnicode(char *s, int l, struct Node *escontext)
|
parseUnicode(char *s, int l, struct Node *escontext, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
int i = 2;
|
int i = 2;
|
||||||
int hi_surrogate = -1;
|
int hi_surrogate = -1;
|
||||||
@ -680,7 +661,7 @@ parseUnicode(char *s, int l, struct Node *escontext)
|
|||||||
{
|
{
|
||||||
while (s[++i] != '}' && i < l)
|
while (s[++i] != '}' && i < l)
|
||||||
{
|
{
|
||||||
if (!hexval(s[i], &si, escontext))
|
if (!hexval(s[i], &si, escontext, yyscanner))
|
||||||
return false;
|
return false;
|
||||||
ch = (ch << 4) | si;
|
ch = (ch << 4) | si;
|
||||||
}
|
}
|
||||||
@ -690,13 +671,13 @@ parseUnicode(char *s, int l, struct Node *escontext)
|
|||||||
{
|
{
|
||||||
for (j = 0; j < 4 && i < l; j++)
|
for (j = 0; j < 4 && i < l; j++)
|
||||||
{
|
{
|
||||||
if (!hexval(s[i++], &si, escontext))
|
if (!hexval(s[i++], &si, escontext, yyscanner))
|
||||||
return false;
|
return false;
|
||||||
ch = (ch << 4) | si;
|
ch = (ch << 4) | si;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! addUnicode(ch, &hi_surrogate, escontext))
|
if (! addUnicode(ch, &hi_surrogate, escontext, yyscanner))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,17 +695,17 @@ parseUnicode(char *s, int l, struct Node *escontext)
|
|||||||
|
|
||||||
/* Parse sequence of hex-encoded characters */
|
/* Parse sequence of hex-encoded characters */
|
||||||
static bool
|
static bool
|
||||||
parseHexChar(char *s, struct Node *escontext)
|
parseHexChar(char *s, struct Node *escontext, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
int s2, s3, ch;
|
int s2, s3, ch;
|
||||||
if (!hexval(s[2], &s2, escontext))
|
if (!hexval(s[2], &s2, escontext, yyscanner))
|
||||||
return false;
|
return false;
|
||||||
if (!hexval(s[3], &s3, escontext))
|
if (!hexval(s[3], &s3, escontext, yyscanner))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ch = (s2 << 4) | s3;
|
ch = (s2 << 4) | s3;
|
||||||
|
|
||||||
return addUnicodeChar(ch, escontext);
|
return addUnicodeChar(ch, escontext, yyscanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -733,13 +714,13 @@ parseHexChar(char *s, struct Node *escontext)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void *
|
void *
|
||||||
jsonpath_yyalloc(yy_size_t bytes)
|
jsonpath_yyalloc(yy_size_t bytes, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
return palloc(bytes);
|
return palloc(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
jsonpath_yyrealloc(void *ptr, yy_size_t bytes)
|
jsonpath_yyrealloc(void *ptr, yy_size_t bytes, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
if (ptr)
|
if (ptr)
|
||||||
return repalloc(ptr, bytes);
|
return repalloc(ptr, bytes);
|
||||||
@ -748,7 +729,7 @@ jsonpath_yyrealloc(void *ptr, yy_size_t bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
jsonpath_yyfree(void *ptr)
|
jsonpath_yyfree(void *ptr, yyscan_t yyscanner)
|
||||||
{
|
{
|
||||||
if (ptr)
|
if (ptr)
|
||||||
pfree(ptr);
|
pfree(ptr);
|
||||||
|
Reference in New Issue
Block a user