Line data Source code
1 : %top{
2 : /*-------------------------------------------------------------------------
3 : *
4 : * jsonpath_scan.l
5 : * Lexical parser for jsonpath datatype
6 : *
7 : * Splits jsonpath string into tokens represented as JsonPathString structs.
8 : * Decodes unicode and hex escaped strings.
9 : *
10 : * Copyright (c) 2019-2026, PostgreSQL Global Development Group
11 : *
12 : * IDENTIFICATION
13 : * src/backend/utils/adt/jsonpath_scan.l
14 : *
15 : *-------------------------------------------------------------------------
16 : */
17 :
18 : #include "postgres.h"
19 :
20 : /*
21 : * NB: include jsonpath_gram.h only AFTER including jsonpath_internal.h,
22 : * because jsonpath_internal.h contains the declaration for JsonPathString.
23 : */
24 : #include "jsonpath_internal.h"
25 : #include "jsonpath_gram.h"
26 :
27 : #include "mb/pg_wchar.h"
28 : #include "nodes/miscnodes.h"
29 : #include "nodes/pg_list.h"
30 : }
31 :
32 : %{
33 : struct jsonpath_yy_extra_type
34 : {
35 : JsonPathString scanstring;
36 : };
37 :
38 : static void addstring(bool init, char *s, int l, yyscan_t yyscanner);
39 : static void addchar(bool init, char c, yyscan_t yyscanner);
40 : static enum yytokentype checkKeyword(yyscan_t yyscanner);
41 : static bool parseUnicode(char *s, int l, struct Node *escontext, yyscan_t yyscanner);
42 : static bool parseHexChar(char *s, struct Node *escontext, yyscan_t yyscanner);
43 :
44 : /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
45 : #undef fprintf
46 : #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
47 :
48 : static void
49 0 : fprintf_to_ereport(const char *fmt, const char *msg)
50 : {
51 0 : ereport(ERROR, (errmsg_internal("%s", msg)));
52 : }
53 :
54 : /* LCOV_EXCL_START */
55 :
56 : %}
57 :
58 : %option 8bit
59 : %option never-interactive
60 : %option nodefault
61 : %option noinput
62 : %option nounput
63 : %option noyywrap
64 : %option warn
65 : %option prefix="jsonpath_yy"
66 : %option extra-type="struct jsonpath_yy_extra_type *"
67 : %option reentrant
68 : %option bison-bridge
69 : %option noyyalloc
70 : %option noyyrealloc
71 : %option noyyfree
72 :
73 : /*
74 : * We use exclusive states for quoted and non-quoted strings,
75 : * quoted variable names and C-style comments.
76 : * Exclusive states:
77 : * <xq> - quoted strings
78 : * <xnq> - non-quoted strings
79 : * <xvq> - quoted variable names
80 : * <xc> - C-style comment
81 : */
82 :
83 : %x xq
84 : %x xnq
85 : %x xvq
86 : %x xc
87 :
88 : special [\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/]
89 : blank [ \t\n\r\f]
90 : /* "other" means anything that's not special, blank, or '\' or '"' */
91 : other [^\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/\\\" \t\n\r\f]
92 :
93 : decdigit [0-9]
94 : hexdigit [0-9A-Fa-f]
95 : octdigit [0-7]
96 : bindigit [0-1]
97 :
98 : /* DecimalInteger in ECMAScript; must not start with 0 unless it's exactly 0 */
99 : decinteger (0|[1-9](_?{decdigit})*)
100 : /* DecimalDigits in ECMAScript; only used as part of other rules */
101 : decdigits {decdigit}(_?{decdigit})*
102 : /* Non-decimal integers; in ECMAScript, these must not have underscore after prefix */
103 : hexinteger 0[xX]{hexdigit}(_?{hexdigit})*
104 : octinteger 0[oO]{octdigit}(_?{octdigit})*
105 : bininteger 0[bB]{bindigit}(_?{bindigit})*
106 :
107 : decimal ({decinteger}\.{decdigits}?|\.{decdigits})
108 : real ({decinteger}|{decimal})[Ee][-+]?{decdigits}
109 : realfail ({decinteger}|{decimal})[Ee][-+]
110 :
111 : decinteger_junk {decinteger}{other}
112 : decimal_junk {decimal}{other}
113 : real_junk {real}{other}
114 :
115 : unicode \\u({hexdigit}{4}|\{{hexdigit}{1,6}\})
116 : unicodefail \\u({hexdigit}{0,3}|\{{hexdigit}{0,6})
117 : hex_char \\x{hexdigit}{2}
118 : hex_fail \\x{hexdigit}{0,1}
119 :
120 : %%
121 :
122 : <xnq>{other}+ {
123 4 : addstring(false, yytext, yyleng, yyscanner);
124 : }
125 4 :
126 2580 : <xnq>{blank}+ {
127 2580 : yylval->str = yyextra->scanstring;
128 2580 : BEGIN INITIAL;
129 2580 : return checkKeyword(yyscanner);
130 : }
131 :
132 0 : <xnq>\/\* {
133 0 : yylval->str = yyextra->scanstring;
134 0 : BEGIN xc;
135 : }
136 0 :
137 4544 : <xnq>({special}|\") {
138 4544 : yylval->str = yyextra->scanstring;
139 4544 : yyless(0);
140 4544 : BEGIN INITIAL;
141 4544 : return checkKeyword(yyscanner);
142 : }
143 :
144 938 : <xnq><<EOF>> {
145 938 : yylval->str = yyextra->scanstring;
146 938 : BEGIN INITIAL;
147 938 : return checkKeyword(yyscanner);
148 : }
149 :
150 4 : <xnq,xq,xvq>\\b { addchar(false, '\b', yyscanner); }
151 4 :
152 4 : <xnq,xq,xvq>\\f { addchar(false, '\f', yyscanner); }
153 4 :
154 4 : <xnq,xq,xvq>\\n { addchar(false, '\n', yyscanner); }
155 4 :
156 4 : <xnq,xq,xvq>\\r { addchar(false, '\r', yyscanner); }
157 4 :
158 8 : <xnq,xq,xvq>\\t { addchar(false, '\t', yyscanner); }
159 8 :
160 4 : <xnq,xq,xvq>\\v { addchar(false, '\v', yyscanner); }
161 4 :
162 84 : <xnq,xq,xvq>{unicode}+ {
163 84 : if (!parseUnicode(yytext, yyleng, escontext, yyscanner))
164 0 : yyterminate();
165 : }
166 36 :
167 8 : <xnq,xq,xvq>{hex_char} {
168 8 : if (!parseHexChar(yytext, escontext, yyscanner))
169 0 : yyterminate();
170 : }
171 8 :
172 24 : <xnq,xq,xvq>{unicode}*{unicodefail} {
173 24 : jsonpath_yyerror(NULL, escontext, yyscanner,
174 : "invalid Unicode escape sequence");
175 0 : yyterminate();
176 : }
177 :
178 0 : <xnq,xq,xvq>{hex_fail} {
179 0 : jsonpath_yyerror(NULL, escontext, yyscanner,
180 : "invalid hexadecimal character sequence");
181 0 : yyterminate();
182 : }
183 :
184 4 : <xnq,xq,xvq>{unicode}+\\ {
185 : /* throw back the \\, and treat as unicode */
186 4 : yyless(yyleng - 1);
187 4 : if (!parseUnicode(yytext, yyleng, escontext, yyscanner))
188 0 : yyterminate();
189 : }
190 4 :
191 84 : <xnq,xq,xvq>\\. { addchar(false, yytext[1], yyscanner); }
192 84 :
193 0 : <xnq,xq,xvq>\\ {
194 0 : jsonpath_yyerror(NULL, escontext, yyscanner,
195 : "unexpected end after backslash");
196 0 : yyterminate();
197 : }
198 :
199 0 : <xq,xvq><<EOF>> {
200 0 : jsonpath_yyerror(NULL, escontext, yyscanner,
201 : "unterminated quoted string");
202 0 : yyterminate();
203 : }
204 :
205 1448 : <xq>\" {
206 1448 : yylval->str = yyextra->scanstring;
207 1448 : BEGIN INITIAL;
208 1448 : return STRING_P;
209 : }
210 :
211 68 : <xvq>\" {
212 68 : yylval->str = yyextra->scanstring;
213 68 : BEGIN INITIAL;
214 68 : return VARIABLE_P;
215 : }
216 :
217 1564 : <xq,xvq>[^\\\"]+ { addstring(false, yytext, yyleng, yyscanner); }
218 1564 :
219 0 : <xc>\*\/ { BEGIN INITIAL; }
220 0 :
221 0 : <xc>[^\*]+ { }
222 0 :
223 0 : <xc>\* { }
224 0 :
225 0 : <xc><<EOF>> {
226 0 : jsonpath_yyerror(NULL, escontext, yyscanner,
227 : "unexpected end of comment");
228 0 : yyterminate();
229 : }
230 124 : \&\& { return AND_P; }
231 124 :
232 72 : \|\| { return OR_P; }
233 :
234 16 : \! { return NOT_P; }
235 :
236 236 : \*\* { return ANY_P; }
237 :
238 504 : \< { return LESS_P; }
239 :
240 28 : \<\= { return LESSEQUAL_P; }
241 :
242 668 : \=\= { return EQUAL_P; }
243 :
244 0 : \<\> { return NOTEQUAL_P; }
245 :
246 8 : \!\= { return NOTEQUAL_P; }
247 :
248 224 : \>\= { return GREATEREQUAL_P; }
249 :
250 296 : \> { return GREATER_P; }
251 :
252 408 : \${other}+ {
253 408 : addstring(true, yytext + 1, yyleng - 1, yyscanner);
254 408 : addchar(false, '\0', yyscanner);
255 408 : yylval->str = yyextra->scanstring;
256 408 : return VARIABLE_P;
257 : }
258 :
259 68 : \$\" {
260 68 : addchar(true, '\0', yyscanner);
261 68 : BEGIN xvq;
262 : }
263 68 :
264 34120 : {special} { return *yytext; }
265 :
266 6876 : {blank}+ { /* ignore */ }
267 6876 :
268 0 : \/\* {
269 0 : addchar(true, '\0', yyscanner);
270 0 : BEGIN xc;
271 : }
272 0 :
273 200 : {real} {
274 200 : addstring(true, yytext, yyleng, yyscanner);
275 200 : addchar(false, '\0', yyscanner);
276 200 : yylval->str = yyextra->scanstring;
277 200 : return NUMERIC_P;
278 : }
279 :
280 172 : {decimal} {
281 172 : addstring(true, yytext, yyleng, yyscanner);
282 172 : addchar(false, '\0', yyscanner);
283 172 : yylval->str = yyextra->scanstring;
284 172 : return NUMERIC_P;
285 : }
286 :
287 1548 : {decinteger} {
288 1548 : addstring(true, yytext, yyleng, yyscanner);
289 1548 : addchar(false, '\0', yyscanner);
290 1548 : yylval->str = yyextra->scanstring;
291 1548 : return INT_P;
292 : }
293 :
294 8 : {hexinteger} {
295 8 : addstring(true, yytext, yyleng, yyscanner);
296 8 : addchar(false, '\0', yyscanner);
297 8 : yylval->str = yyextra->scanstring;
298 8 : return INT_P;
299 : }
300 :
301 8 : {octinteger} {
302 8 : addstring(true, yytext, yyleng, yyscanner);
303 8 : addchar(false, '\0', yyscanner);
304 8 : yylval->str = yyextra->scanstring;
305 8 : return INT_P;
306 : }
307 :
308 8 : {bininteger} {
309 8 : addstring(true, yytext, yyleng, yyscanner);
310 8 : addchar(false, '\0', yyscanner);
311 8 : yylval->str = yyextra->scanstring;
312 8 : return INT_P;
313 : }
314 :
315 0 : {realfail} {
316 0 : jsonpath_yyerror(NULL, escontext, yyscanner,
317 : "invalid numeric literal");
318 0 : yyterminate();
319 : }
320 : {decinteger_junk} {
321 60 : jsonpath_yyerror(NULL, escontext, yyscanner,
322 : "trailing junk after numeric literal");
323 16 : yyterminate();
324 : }
325 : {decimal_junk} {
326 28 : jsonpath_yyerror(NULL, escontext, yyscanner,
327 : "trailing junk after numeric literal");
328 0 : yyterminate();
329 : }
330 : {real_junk} {
331 4 : jsonpath_yyerror(NULL, escontext, yyscanner,
332 : "trailing junk after numeric literal");
333 0 : yyterminate();
334 : }
335 : \" {
336 1520 : addchar(true, '\0', yyscanner);
337 1520 : BEGIN xq;
338 : }
339 1520 :
340 0 : \\ {
341 0 : yyless(0);
342 0 : addchar(true, '\0', yyscanner);
343 0 : BEGIN xnq;
344 : }
345 0 :
346 8062 : {other}+ {
347 8062 : addstring(true, yytext, yyleng, yyscanner);
348 8062 : BEGIN xnq;
349 : }
350 8062 :
351 7370 : <<EOF>> { yyterminate(); }
352 :
353 0 : %%
354 :
355 : /* LCOV_EXCL_STOP */
356 :
357 : /* see scan.l */
358 : #undef yyextra
359 : #define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
360 :
361 : void
362 280 : jsonpath_yyerror(JsonPathParseResult **result, struct Node *escontext,
363 : yyscan_t yyscanner,
364 : const char *message)
365 : {
366 280 : struct yyguts_t *yyg = (struct yyguts_t *) yyscanner; /* needed for yytext
367 : * macro */
368 :
369 : /* don't overwrite escontext if it's already been set */
370 280 : if (SOFT_ERROR_OCCURRED(escontext))
371 12 : return;
372 :
373 268 : if (*yytext == YY_END_OF_BUFFER_CHAR)
374 : {
375 40 : errsave(escontext,
376 : (errcode(ERRCODE_SYNTAX_ERROR),
377 : /* translator: %s is typically "syntax error" */
378 : errmsg("%s at end of jsonpath input", _(message))));
379 : }
380 : else
381 : {
382 228 : errsave(escontext,
383 : (errcode(ERRCODE_SYNTAX_ERROR),
384 : /* translator: first %s is typically "syntax error" */
385 : errmsg("%s at or near \"%s\" of jsonpath input",
386 : _(message), yytext)));
387 : }
388 : }
389 :
390 : typedef struct JsonPathKeyword
391 : {
392 : int16 len;
393 : bool lowercase;
394 : int val;
395 : const char *keyword;
396 : } JsonPathKeyword;
397 :
398 : /*
399 : * Array of key words should be sorted by length and then
400 : * alphabetical order
401 : */
402 : static const JsonPathKeyword keywords[] = {
403 : {2, false, IS_P, "is"},
404 : {2, false, TO_P, "to"},
405 : {3, false, ABS_P, "abs"},
406 : {3, false, LAX_P, "lax"},
407 : {4, false, DATE_P, "date"},
408 : {4, false, FLAG_P, "flag"},
409 : {4, false, LAST_P, "last"},
410 : {4, true, NULL_P, "null"},
411 : {4, false, SIZE_P, "size"},
412 : {4, false, TIME_P, "time"},
413 : {4, true, TRUE_P, "true"},
414 : {4, false, TYPE_P, "type"},
415 : {4, false, WITH_P, "with"},
416 : {5, false, STR_BTRIM_P, "btrim"},
417 : {5, true, FALSE_P, "false"},
418 : {5, false, FLOOR_P, "floor"},
419 : {5, false, STR_LOWER_P, "lower"},
420 : {5, false, STR_LTRIM_P, "ltrim"},
421 : {5, false, STR_RTRIM_P, "rtrim"},
422 : {5, false, STR_UPPER_P, "upper"},
423 : {6, false, BIGINT_P, "bigint"},
424 : {6, false, DOUBLE_P, "double"},
425 : {6, false, EXISTS_P, "exists"},
426 : {6, false, NUMBER_P, "number"},
427 : {6, false, STARTS_P, "starts"},
428 : {6, false, STRICT_P, "strict"},
429 : {6, false, STRINGFUNC_P, "string"},
430 : {7, false, BOOLEAN_P, "boolean"},
431 : {7, false, CEILING_P, "ceiling"},
432 : {7, false, DECIMAL_P, "decimal"},
433 : {7, false, STR_INITCAP_P, "initcap"},
434 : {7, false, INTEGER_P, "integer"},
435 : {7, false, STR_REPLACE_P, "replace"},
436 : {7, false, TIME_TZ_P, "time_tz"},
437 : {7, false, UNKNOWN_P, "unknown"},
438 : {8, false, DATETIME_P, "datetime"},
439 : {8, false, KEYVALUE_P, "keyvalue"},
440 : {9, false, TIMESTAMP_P, "timestamp"},
441 : {10, false, LIKE_REGEX_P, "like_regex"},
442 : {10, false, STR_SPLIT_PART_P, "split_part"},
443 : {12, false, TIMESTAMP_TZ_P, "timestamp_tz"},
444 : };
445 :
446 : /*
447 : * Check if current scanstring value is a keyword
448 : */
449 : static enum yytokentype
450 8062 : checkKeyword(yyscan_t yyscanner)
451 : {
452 8062 : int res = IDENT_P;
453 : int diff;
454 8062 : const JsonPathKeyword *StopLow = keywords,
455 8062 : *StopHigh = keywords + lengthof(keywords),
456 : *StopMiddle;
457 :
458 8062 : if (yyextra->scanstring.len > keywords[lengthof(keywords) - 1].len)
459 4 : return res;
460 :
461 44582 : while (StopLow < StopHigh)
462 : {
463 42020 : StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
464 :
465 42020 : if (StopMiddle->len == yyextra->scanstring.len)
466 15856 : diff = pg_strncasecmp(StopMiddle->keyword, yyextra->scanstring.val,
467 15856 : yyextra->scanstring.len);
468 : else
469 26164 : diff = StopMiddle->len - yyextra->scanstring.len;
470 :
471 42020 : if (diff < 0)
472 11036 : StopLow = StopMiddle + 1;
473 30984 : else if (diff > 0)
474 25488 : StopHigh = StopMiddle;
475 : else
476 : {
477 5496 : if (StopMiddle->lowercase)
478 196 : diff = strncmp(StopMiddle->keyword, yyextra->scanstring.val,
479 196 : yyextra->scanstring.len);
480 :
481 5496 : if (diff == 0)
482 5496 : res = StopMiddle->val;
483 :
484 5496 : break;
485 : }
486 : }
487 :
488 8058 : return res;
489 : }
490 :
491 : /*
492 : * Resize scanstring so that it can append string of given length.
493 : * Reinitialize if required.
494 : */
495 : static void
496 16114 : resizeString(bool init, int appendLen, yyscan_t yyscanner)
497 : {
498 16114 : if (init)
499 : {
500 12002 : yyextra->scanstring.total = Max(32, appendLen);
501 12002 : yyextra->scanstring.val = (char *) palloc(yyextra->scanstring.total);
502 12002 : yyextra->scanstring.len = 0;
503 : }
504 : else
505 : {
506 4112 : if (yyextra->scanstring.len + appendLen >= yyextra->scanstring.total)
507 : {
508 0 : while (yyextra->scanstring.len + appendLen >= yyextra->scanstring.total)
509 0 : yyextra->scanstring.total *= 2;
510 0 : yyextra->scanstring.val = repalloc(yyextra->scanstring.val, yyextra->scanstring.total);
511 : }
512 : }
513 16114 : }
514 :
515 : /* Add set of bytes at "s" of length "l" to scanstring */
516 : static void
517 12062 : addstring(bool init, char *s, int l, yyscan_t yyscanner)
518 : {
519 12062 : resizeString(init, l + 1, yyscanner);
520 12062 : memcpy(yyextra->scanstring.val + yyextra->scanstring.len, s, l);
521 12062 : yyextra->scanstring.len += l;
522 12062 : }
523 :
524 : /* Add single byte "c" to scanstring */
525 : static void
526 4052 : addchar(bool init, char c, yyscan_t yyscanner)
527 : {
528 4052 : resizeString(init, 1, yyscanner);
529 4052 : yyextra->scanstring.val[yyextra->scanstring.len] = c;
530 4052 : if (c != '\0')
531 112 : yyextra->scanstring.len++;
532 4052 : }
533 :
534 : /* Interface to jsonpath parser */
535 : JsonPathParseResult *
536 7706 : parsejsonpath(const char *str, int len, struct Node *escontext)
537 : {
538 : JsonPathParseResult *parseresult;
539 : yyscan_t scanner;
540 : struct jsonpath_yy_extra_type yyext;
541 :
542 7706 : if (jsonpath_yylex_init(&scanner) != 0)
543 0 : elog(ERROR, "yylex_init() failed: %m");
544 :
545 7706 : yyset_extra(&yyext, scanner);
546 :
547 7706 : if (len <= 0)
548 4 : len = strlen(str);
549 :
550 7706 : jsonpath_yy_scan_bytes(str, len, scanner);
551 :
552 7706 : if (jsonpath_yyparse(&parseresult, escontext, scanner) != 0)
553 12 : jsonpath_yyerror(NULL, escontext, scanner, "invalid input"); /* shouldn't happen */
554 :
555 7398 : jsonpath_yylex_destroy(scanner);
556 :
557 7398 : return parseresult;
558 : }
559 :
560 : /* Turn hex character into integer */
561 : static bool
562 584 : hexval(char c, int *result, struct Node *escontext, yyscan_t yyscanner)
563 : {
564 584 : if (c >= '0' && c <= '9')
565 : {
566 392 : *result = c - '0';
567 392 : return true;
568 : }
569 192 : if (c >= 'a' && c <= 'f')
570 : {
571 168 : *result = c - 'a' + 0xA;
572 168 : return true;
573 : }
574 24 : if (c >= 'A' && c <= 'F')
575 : {
576 24 : *result = c - 'A' + 0xA;
577 24 : return true;
578 : }
579 0 : jsonpath_yyerror(NULL, escontext, yyscanner, "invalid hexadecimal digit");
580 0 : return false;
581 : }
582 :
583 : /* Add given unicode character to scanstring */
584 : static bool
585 96 : addUnicodeChar(char32_t ch, struct Node *escontext, yyscan_t yyscanner)
586 : {
587 96 : if (ch == 0)
588 : {
589 : /* We can't allow this, since our TEXT type doesn't */
590 16 : ereturn(escontext, false,
591 : (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
592 : errmsg("unsupported Unicode escape sequence"),
593 : errdetail("\\u0000 cannot be converted to text.")));
594 : }
595 : else
596 : {
597 : char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1];
598 :
599 : /*
600 : * If we're trapping the error status, call the noerror form of the
601 : * conversion function. Otherwise call the normal form which provides
602 : * more detailed errors.
603 : */
604 :
605 80 : if (!escontext || !IsA(escontext, ErrorSaveContext))
606 80 : pg_unicode_to_server(ch, (unsigned char *) cbuf);
607 0 : else if (!pg_unicode_to_server_noerror(ch, (unsigned char *) cbuf))
608 0 : ereturn(escontext, false,
609 : (errcode(ERRCODE_SYNTAX_ERROR),
610 : errmsg("could not convert Unicode to server encoding")));
611 80 : addstring(false, cbuf, strlen(cbuf), yyscanner);
612 : }
613 80 : return true;
614 : }
615 :
616 : /* Add unicode character, processing any surrogate pairs */
617 : static bool
618 144 : addUnicode(char32_t ch, int *hi_surrogate, struct Node *escontext, yyscan_t yyscanner)
619 : {
620 144 : if (is_utf16_surrogate_first(ch))
621 : {
622 40 : if (*hi_surrogate != -1)
623 8 : ereturn(escontext, false,
624 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
625 : errmsg("invalid input syntax for type %s", "jsonpath"),
626 : errdetail("Unicode high surrogate must not follow "
627 : "a high surrogate.")));
628 32 : *hi_surrogate = ch;
629 32 : return true;
630 : }
631 104 : else if (is_utf16_surrogate_second(ch))
632 : {
633 32 : if (*hi_surrogate == -1)
634 16 : ereturn(escontext, false,
635 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
636 : errmsg("invalid input syntax for type %s", "jsonpath"),
637 : errdetail("Unicode low surrogate must follow a high "
638 : "surrogate.")));
639 16 : ch = surrogate_pair_to_codepoint(*hi_surrogate, ch);
640 16 : *hi_surrogate = -1;
641 : }
642 72 : else if (*hi_surrogate != -1)
643 : {
644 0 : ereturn(escontext, false,
645 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
646 : errmsg("invalid input syntax for type %s", "jsonpath"),
647 : errdetail("Unicode low surrogate must follow a high "
648 : "surrogate.")));
649 : }
650 :
651 88 : return addUnicodeChar(ch, escontext, yyscanner);
652 : }
653 :
654 : /*
655 : * parseUnicode was adopted from json_lex_string() in
656 : * src/backend/utils/adt/json.c
657 : */
658 : static bool
659 88 : parseUnicode(char *s, int l, struct Node *escontext, yyscan_t yyscanner)
660 : {
661 88 : int i = 2;
662 88 : int hi_surrogate = -1;
663 :
664 192 : for (i = 2; i < l; i += 2) /* skip '\u' */
665 : {
666 144 : char32_t ch = 0;
667 : int j,
668 : si;
669 :
670 144 : if (s[i] == '{') /* parse '\u{XX...}' */
671 : {
672 112 : while (s[++i] != '}' && i < l)
673 : {
674 88 : if (!hexval(s[i], &si, escontext, yyscanner))
675 0 : return false;
676 88 : ch = (ch << 4) | si;
677 : }
678 24 : i++; /* skip '}' */
679 : }
680 : else /* parse '\uXXXX' */
681 : {
682 600 : for (j = 0; j < 4 && i < l; j++)
683 : {
684 480 : if (!hexval(s[i++], &si, escontext, yyscanner))
685 0 : return false;
686 480 : ch = (ch << 4) | si;
687 : }
688 : }
689 :
690 144 : if (!addUnicode(ch, &hi_surrogate, escontext, yyscanner))
691 0 : return false;
692 : }
693 :
694 48 : if (hi_surrogate != -1)
695 : {
696 8 : ereturn(escontext, false,
697 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
698 : errmsg("invalid input syntax for type %s", "jsonpath"),
699 : errdetail("Unicode low surrogate must follow a high "
700 : "surrogate.")));
701 : }
702 :
703 40 : return true;
704 : }
705 :
706 : /* Parse sequence of hex-encoded characters */
707 : static bool
708 8 : parseHexChar(char *s, struct Node *escontext, yyscan_t yyscanner)
709 : {
710 : int s2,
711 : s3,
712 : ch;
713 :
714 8 : if (!hexval(s[2], &s2, escontext, yyscanner))
715 0 : return false;
716 8 : if (!hexval(s[3], &s3, escontext, yyscanner))
717 0 : return false;
718 :
719 8 : ch = (s2 << 4) | s3;
720 :
721 8 : return addUnicodeChar(ch, escontext, yyscanner);
722 : }
723 :
724 : /*
725 : * Interface functions to make flex use palloc() instead of malloc().
726 : * It'd be better to make these static, but flex insists otherwise.
727 : */
728 :
729 : void *
730 30824 : jsonpath_yyalloc(yy_size_t bytes, yyscan_t yyscanner)
731 : {
732 30824 : return palloc(bytes);
733 : }
734 :
735 : void *
736 0 : jsonpath_yyrealloc(void *ptr, yy_size_t bytes, yyscan_t yyscanner)
737 : {
738 0 : if (ptr)
739 0 : return repalloc(ptr, bytes);
740 : else
741 0 : return palloc(bytes);
742 : }
743 :
744 : void
745 36990 : jsonpath_yyfree(void *ptr, yyscan_t yyscanner)
746 : {
747 36990 : if (ptr)
748 29592 : pfree(ptr);
749 36990 : }
|