@@ -7,8 +7,11 @@ package parser
77
88import (
99 "github.com/cockroachdb/cockroach/pkg/sql/parser/statements"
10+ "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
11+ "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
1012 "github.com/cockroachdb/cockroach/pkg/sql/scanner"
1113 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
14+ "github.com/cockroachdb/cockroach/pkg/util/jsonpath"
1215 "github.com/cockroachdb/errors"
1316)
1417
@@ -24,6 +27,11 @@ func init() {
2427
2528var (
2629 ReCache = tree .NewRegexpCache (64 )
30+
31+ errCurrentInRoot = pgerror .Newf (pgcode .Syntax ,
32+ "@ is not allowed in root expressions" )
33+ errLastInNonArray = pgerror .Newf (pgcode .Syntax ,
34+ "LAST is allowed only in array subscripts" )
2735)
2836
2937type Parser struct {
@@ -101,5 +109,78 @@ func (p *Parser) Parse(jsonpath string) (statements.JsonpathStatement, error) {
101109// Parse parses a jsonpath string and returns a jsonpath.Jsonpath object.
102110func Parse (jsonpath string ) (statements.JsonpathStatement , error ) {
103111 var p Parser
104- return p .Parse (jsonpath )
112+ stmt , err := p .Parse (jsonpath )
113+ if err != nil {
114+ return statements.JsonpathStatement {}, err
115+ }
116+ // Similar to flattenJsonPathParseItem in postgres, we do a pass over the AST
117+ // to perform some semantic checks.
118+ if err := walkAST (stmt .AST .Path ); err != nil {
119+ return statements.JsonpathStatement {}, err
120+ }
121+ return stmt , nil
122+ }
123+
124+ // TODO(normanchenn): Similarly to flattenJsonPathParseItem, we could use this to
125+ // generate a normalized jsonpath string, rather than calling stmt.AST.String().
126+ func walkAST (path jsonpath.Path ) error {
127+ return walk (path , 0 /* nestingLevel */ , false /* insideArraySubscript */ )
128+ }
129+
130+ func walk (path jsonpath.Path , nestingLevel int , insideArraySubscript bool ) error {
131+ switch path := path .(type ) {
132+ case jsonpath.Paths :
133+ for _ , p := range path {
134+ if err := walk (p , nestingLevel , insideArraySubscript ); err != nil {
135+ return err
136+ }
137+ }
138+ return nil
139+ case jsonpath.ArrayList :
140+ for _ , p := range path {
141+ if err := walk (p , nestingLevel , true /* insideArraySubscript */ ); err != nil {
142+ return err
143+ }
144+ }
145+ return nil
146+ case jsonpath.ArrayIndexRange :
147+ if err := walk (path .Start , nestingLevel , insideArraySubscript ); err != nil {
148+ return err
149+ }
150+ if err := walk (path .End , nestingLevel , insideArraySubscript ); err != nil {
151+ return err
152+ }
153+ return nil
154+ case jsonpath.Operation :
155+ if err := walk (path .Left , nestingLevel , insideArraySubscript ); err != nil {
156+ return err
157+ }
158+ if path .Right != nil {
159+ if err := walk (path .Right , nestingLevel , insideArraySubscript ); err != nil {
160+ return err
161+ }
162+ }
163+ return nil
164+ case jsonpath.Filter :
165+ if err := walk (path .Condition , nestingLevel + 1 , insideArraySubscript ); err != nil {
166+ return err
167+ }
168+ return nil
169+ case jsonpath.Current :
170+ if nestingLevel <= 0 {
171+ return errCurrentInRoot
172+ }
173+ return nil
174+ case jsonpath.Last :
175+ if ! insideArraySubscript {
176+ return errLastInNonArray
177+ }
178+ return nil
179+ case jsonpath.Root , jsonpath.Key , jsonpath.Wildcard , jsonpath.Regex ,
180+ jsonpath.AnyKey , jsonpath.Scalar :
181+ // These are leaf nodes that don't require any further checks.
182+ return nil
183+ default :
184+ panic (errors .AssertionFailedf ("unhandled path type: %T" , path ))
185+ }
105186}
0 commit comments