Skip to content

Commit e26114c

Browse files
committed
Make JSON path numeric literals more correct
Per ECMAScript standard (ECMA-262, referenced by SQL standard), the syntax forms .1 1. should be allowed for decimal numeric literals, but the existing implementation rejected them. Also, by the same standard, reject trailing junk after numeric literals. Note that the ECMAScript standard for numeric literals is in respects like these slightly different from the JSON standard, which might be the original cause for this discrepancy. A change is that this kind of syntax is now rejected: 1.type() This needs to be written as (1).type() This is correct; normal JavaScript also does not accept this syntax. We also need to fix up the jsonpath output function for this case. We put parentheses around numeric items if they are followed by another path item. Reviewed-by: Nikita Glukhov <[email protected]> Discussion: https://www.postgresql.org/message-id/flat/[email protected]
1 parent 91c0570 commit e26114c

File tree

4 files changed

+176
-98
lines changed

4 files changed

+176
-98
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,13 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
500500
escape_json(buf, jspGetString(v, NULL));
501501
break;
502502
case jpiNumeric:
503+
if (jspHasNext(v))
504+
appendStringInfoChar(buf, '(');
503505
appendStringInfoString(buf,
504506
DatumGetCString(DirectFunctionCall1(numeric_out,
505507
NumericGetDatum(jspGetNumeric(v)))));
508+
if (jspHasNext(v))
509+
appendStringInfoChar(buf, ')');
506510
break;
507511
case jpiBool:
508512
if (jspGetBool(v))

src/backend/utils/adt/jsonpath_scan.l

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,13 @@ other [^\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/\\\" \t\n\r\f]
8282

8383
digit [0-9]
8484
integer (0|[1-9]{digit}*)
85-
decimal {integer}\.{digit}+
86-
decimalfail {integer}\.
85+
decimal ({integer}\.{digit}*|\.{digit}+)
8786
real ({integer}|{decimal})[Ee][-+]?{digit}+
88-
realfail1 ({integer}|{decimal})[Ee]
89-
realfail2 ({integer}|{decimal})[Ee][-+]
87+
realfail ({integer}|{decimal})[Ee][-+]
88+
89+
integer_junk {integer}{other}
90+
decimal_junk {decimal}{other}
91+
real_junk {real}{other}
9092

9193
hex_dig [0-9A-Fa-f]
9294
unicode \\u({hex_dig}{4}|\{{hex_dig}{1,6}\})
@@ -242,16 +244,10 @@ hex_fail \\x{hex_dig}{0,1}
242244
return INT_P;
243245
}
244246

245-
{decimalfail} {
246-
/* throw back the ., and treat as integer */
247-
yyless(yyleng - 1);
248-
addstring(true, yytext, yyleng);
249-
addchar(false, '\0');
250-
yylval->str = scanstring;
251-
return INT_P;
252-
}
253-
254-
({realfail1}|{realfail2}) { yyerror(NULL, "invalid floating point number"); }
247+
{realfail} { yyerror(NULL, "invalid numeric literal"); }
248+
{integer_junk} { yyerror(NULL, "trailing junk after numeric literal"); }
249+
{decimal_junk} { yyerror(NULL, "trailing junk after numeric literal"); }
250+
{real_junk} { yyerror(NULL, "trailing junk after numeric literal"); }
255251

256252
\" {
257253
addchar(true, '\0');

0 commit comments

Comments
 (0)