Skip to content

Commit 3d1f87f

Browse files
craig[bot]normanchenn
andcommitted
Merge #144389
144389: jsonpath: complete grammar and add unimplemented feature errors r=normanchenn a=normanchenn This commit completes the JSONPath grammar through implementing the grammar rules for all Postgres-compatible JSONPath features. Features that are not yet implemented are marked with unimplemented errors and linked to the JSONPath meta-issue #22513. Epic: None Release note: None Co-authored-by: Norman Chen <[email protected]>
2 parents 56022cd + eed5b58 commit 3d1f87f

File tree

4 files changed

+177
-63
lines changed

4 files changed

+177
-63
lines changed

pkg/sql/logictest/testdata/logic_test/jsonpath

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,27 @@ SELECT '$.number()'::JSONPATH;
195195
statement error unimplemented
196196
SELECT '$.string()'::JSONPATH;
197197

198+
statement error unimplemented
199+
SELECT '$.**'::JSONPATH;
200+
201+
statement error unimplemented
202+
SELECT '$.decimal()'::JSONPATH;
203+
204+
statement error unimplemented
205+
SELECT '$.datetime()'::JSONPATH;
206+
207+
statement error unimplemented
208+
SELECT '$.time()'::JSONPATH;
209+
210+
statement error unimplemented
211+
SELECT '$.time_tz()'::JSONPATH;
212+
213+
statement error unimplemented
214+
SELECT '$.timestamp()'::JSONPATH;
215+
216+
statement error unimplemented
217+
SELECT '$.timestamp_tz()'::JSONPATH;
218+
198219
query T
199220
SELECT '$.*'::JSONPATH
200221
----
@@ -224,10 +245,3 @@ $.*
224245

225246
# statement error unsupported comparison operator
226247
# SELECT * FROM a WHERE j = '$.a'
227-
228-
## Unsupported Jsonpath
229-
230-
# query T
231-
# SELECT '$.a.type()'::JSONPATH
232-
# ----
233-
# $.a.type()

pkg/sql/scanner/jsonpath_scan.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ func (s *JSONPathScanner) Scan(lval ScanSymType) {
108108
case '@':
109109
lval.SetID(lexbase.CURRENT)
110110
return
111+
case '*':
112+
if s.peek() == '*' { // **
113+
s.pos++
114+
lval.SetID(lexbase.ANY)
115+
return
116+
}
117+
return
111118
default:
112119
if sqllexbase.IsDigit(ch) {
113120
s.scanNumber(lval, ch)

pkg/util/jsonpath/parser/jsonpath.y

Lines changed: 147 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ func setErr(jsonpathlex jsonpathLexer, err error) int {
2121
return 1
2222
}
2323

24-
// TODO(normanchenn): link meta-issue to unimplemented errors.
2524
func unimplemented(jsonpathlex jsonpathLexer, feature string) int {
2625
jsonpathlex.(*lexer).Unimplemented(feature)
2726
return 1
@@ -160,60 +159,20 @@ func regexBinaryOp(left jsonpath.Path, regex string) (jsonpath.Operation, error)
160159
%token <str> LESS_EQUALS GREATER_EQUALS NOT_EQUALS
161160
%token <str> ERROR
162161

163-
%token <str> STRICT
164-
%token <str> LAX
165-
166-
%token <str> VARIABLE
167-
%token <str> TO
168-
169-
%token <str> TRUE
170-
%token <str> FALSE
171-
172-
%token <str> EQUAL
173-
%token <str> NOT_EQUAL
174-
%token <str> LESS
175-
%token <str> LESS_EQUAL
176-
%token <str> GREATER
177-
%token <str> GREATER_EQUAL
178-
179-
%token <str> ROOT
180-
181-
%token <str> AND
182-
%token <str> OR
183-
%token <str> NOT
184-
185-
%token <str> CURRENT
186-
187-
%token <str> STR
188-
%token <str> NULL
189-
190-
%token <str> LIKE_REGEX
191-
%token <str> FLAG
192-
193-
%token <str> LAST
194-
%token <str> EXISTS
195-
%token <str> IS
196-
%token <str> UNKNOWN
197-
%token <str> STARTS
198-
%token <str> WITH
199-
200-
%token <str> SIZE
201-
202-
%token <str> TYPE
203-
204-
%token <str> KEYVALUE
205-
206-
%token <str> ABS
207-
%token <str> CEILING
208-
%token <str> FLOOR
209-
210-
%token <str> BIGINT
211-
%token <str> BOOLEAN
212-
%token <str> DATE
213-
%token <str> DOUBLE
214-
%token <str> INTEGER
215-
%token <str> NUMBER
216-
%token <str> STRING
162+
%token <str> STRICT LAX
163+
%token <str> ROOT CURRENT
164+
%token <str> VARIABLE STR NULL
165+
%token <str> TRUE FALSE
166+
%token <str> EQUAL NOT_EQUAL LESS LESS_EQUAL GREATER GREATER_EQUAL
167+
%token <str> AND OR NOT
168+
%token <str> LIKE_REGEX FLAG
169+
%token <str> TO LAST
170+
%token <str> EXISTS IS UNKNOWN STARTS WITH
171+
%token <str> ANY
172+
%token <str> SIZE TYPE KEYVALUE
173+
%token <str> ABS CEILING FLOOR
174+
%token <str> BIGINT BOOLEAN DATE DOUBLE INTEGER NUMBER STRING
175+
%token <str> DECIMAL DATETIME TIME TIME_TZ TIMESTAMP TIMESTAMP_TZ
217176

218177
%type <jsonpath.Jsonpath> jsonpath
219178
%type <jsonpath.Path> expr_or_predicate
@@ -378,6 +337,34 @@ accessor_op:
378337
{
379338
$$.val = $2.path()
380339
}
340+
| '.' any_path
341+
{
342+
return unimplemented(jsonpathlex, ".**")
343+
}
344+
| '.' DECIMAL '(' opt_csv_list ')'
345+
{
346+
return unimplemented(jsonpathlex, ".decimal()")
347+
}
348+
| '.' DATETIME '(' opt_datetime_template ')'
349+
{
350+
return unimplemented(jsonpathlex, ".datetime()")
351+
}
352+
| '.' TIME '(' opt_datetime_precision ')'
353+
{
354+
return unimplemented(jsonpathlex, ".time()")
355+
}
356+
| '.' TIME_TZ '(' opt_datetime_precision ')'
357+
{
358+
return unimplemented(jsonpathlex, ".time_tz()")
359+
}
360+
| '.' TIMESTAMP '(' opt_datetime_precision ')'
361+
{
362+
return unimplemented(jsonpathlex, ".timestamp()")
363+
}
364+
| '.' TIMESTAMP_TZ '(' opt_datetime_precision ')'
365+
{
366+
return unimplemented(jsonpathlex, ".timestamp_tz()")
367+
}
381368
;
382369

383370
key:
@@ -577,6 +564,105 @@ method:
577564
}
578565
;
579566

567+
any_path:
568+
ANY
569+
{
570+
// Unimplemented from .**.
571+
}
572+
| ANY '{' any_level '}'
573+
{
574+
// Unimplemented from .**.
575+
}
576+
| ANY '{' any_level TO any_level '}'
577+
{
578+
// Unimplemented from .**.
579+
}
580+
;
581+
582+
any_level:
583+
ICONST
584+
{
585+
// Unimplemented from .**.
586+
}
587+
| LAST
588+
{
589+
// Unimplemented from .**.
590+
}
591+
;
592+
593+
opt_csv_list:
594+
csv_list
595+
{
596+
// Unimplemented from .decimal().
597+
}
598+
| /* empty */
599+
{
600+
// Unimplemented from .decimal().
601+
}
602+
;
603+
604+
csv_list:
605+
csv_elem
606+
{
607+
// Unimplemented from .decimal().
608+
}
609+
| csv_list ',' csv_elem
610+
{
611+
// Unimplemented from .decimal().
612+
}
613+
;
614+
615+
csv_elem:
616+
ICONST
617+
{
618+
// Unimplemented from .decimal().
619+
}
620+
| '+' ICONST %prec UMINUS
621+
{
622+
// Unimplemented from .decimal().
623+
}
624+
| '-' ICONST %prec UMINUS
625+
{
626+
// Unimplemented from .decimal().
627+
}
628+
;
629+
630+
opt_datetime_template:
631+
datetime_template
632+
{
633+
// Unimplemented from .datetime().
634+
}
635+
| /* empty */
636+
{
637+
// Unimplemented from .datetime().
638+
}
639+
;
640+
641+
datetime_template:
642+
STR
643+
{
644+
// Unimplemented from .datetime().
645+
}
646+
;
647+
648+
opt_datetime_precision:
649+
datetime_precision
650+
{
651+
// Unimplemented from .time(), time_tz(), .timestamp(), .timestamp_tz().
652+
}
653+
| /* empty */
654+
{
655+
// Unimplemented from .time(), time_tz(), .timestamp(), .timestamp_tz().
656+
}
657+
;
658+
659+
datetime_precision:
660+
ICONST
661+
{
662+
// Unimplemented from .time(), time_tz(), .timestamp(), .timestamp_tz().
663+
}
664+
;
665+
580666
scalar_value:
581667
VARIABLE
582668
{
@@ -632,6 +718,8 @@ unreserved_keyword:
632718
| BOOLEAN
633719
| CEILING
634720
| DATE
721+
| DATETIME
722+
| DECIMAL
635723
| DOUBLE
636724
| EXISTS
637725
| FALSE
@@ -649,6 +737,10 @@ unreserved_keyword:
649737
| STARTS
650738
| STRICT
651739
| STRING
740+
| TIME
741+
| TIMESTAMP
742+
| TIMESTAMP_TZ
743+
| TIME_TZ
652744
| TO
653745
| TRUE
654746
| TYPE

pkg/util/jsonpath/parser/lexer.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ func (l *lexer) setErr(err error) {
9898
}
9999

100100
func (l *lexer) Unimplemented(feature string) {
101-
l.lastError = unimp.New(feature, "this syntax")
101+
// Link to meta-issue for unimplemented JSONPath features.
102+
l.lastError = unimp.NewWithIssuef(22513, "this syntax: %s", feature)
102103
lastTok := l.lastToken()
103104
l.lastError = parser.PopulateErrorDetails(lastTok.id, lastTok.str, lastTok.pos, l.lastError, l.in)
104105
l.lastError = &tree.UnsupportedError{

0 commit comments

Comments
 (0)