@@ -256,10 +256,22 @@ impl ParserOptions {
256256 }
257257}
258258
259+ #[ derive( Copy , Clone ) ]
260+ enum ParserState {
261+ /// The default state of the parser.
262+ Normal ,
263+ /// The state when parsing a CONNECT BY expression. This allows parsing
264+ /// PRIOR expressions while still allowing prior as an identifier name
265+ /// in other contexts.
266+ ConnectBy ,
267+ }
268+
259269pub struct Parser < ' a > {
260270 tokens : Vec < TokenWithLocation > ,
261271 /// The index of the first unprocessed token in `self.tokens`
262272 index : usize ,
273+ /// The current state of the parser.
274+ state : ParserState ,
263275 /// The current dialect to use
264276 dialect : & ' a dyn Dialect ,
265277 /// Additional options that allow you to mix & match behavior
@@ -290,6 +302,7 @@ impl<'a> Parser<'a> {
290302 Self {
291303 tokens : vec ! [ ] ,
292304 index : 0 ,
305+ state : ParserState :: Normal ,
293306 dialect,
294307 recursion_counter : RecursionCounter :: new ( DEFAULT_REMAINING_DEPTH ) ,
295308 options : ParserOptions :: default ( ) ,
@@ -1040,6 +1053,10 @@ impl<'a> Parser<'a> {
10401053 self . prev_token ( ) ;
10411054 self . parse_bigquery_struct_literal ( )
10421055 }
1056+ Keyword :: PRIOR if matches ! ( self . state, ParserState :: ConnectBy ) => {
1057+ let expr = self . parse_subexpr ( Self :: PLUS_MINUS_PREC ) ?;
1058+ Ok ( Expr :: Prior ( Box :: new ( expr) ) )
1059+ }
10431060 // Here `w` is a word, check if it's a part of a multi-part
10441061 // identifier, a function call, or a simple identifier:
10451062 _ => match self . peek_token ( ) . token {
@@ -7695,6 +7712,17 @@ impl<'a> Parser<'a> {
76957712 None
76967713 } ;
76977714
7715+ let connect_by = if self . dialect . supports_connect_by ( )
7716+ && self
7717+ . parse_one_of_keywords ( & [ Keyword :: START , Keyword :: CONNECT ] )
7718+ . is_some ( )
7719+ {
7720+ self . prev_token ( ) ;
7721+ Some ( self . parse_connect_by ( ) ?)
7722+ } else {
7723+ None
7724+ } ;
7725+
76987726 Ok ( Select {
76997727 distinct,
77007728 top,
@@ -7711,6 +7739,44 @@ impl<'a> Parser<'a> {
77117739 named_window : named_windows,
77127740 qualify,
77137741 value_table_mode,
7742+ connect_by,
7743+ } )
7744+ }
7745+
7746+ /// Invoke `f` after first setting the parser's `ParserState` to `state`.
7747+ ///
7748+ /// Upon return, restores the parser's state to what it started at.
7749+ fn with_state < T , F > ( & mut self , state : ParserState , mut f : F ) -> Result < T , ParserError >
7750+ where
7751+ F : FnMut ( & mut Parser ) -> Result < T , ParserError > ,
7752+ {
7753+ let current_state = self . state ;
7754+ self . state = state;
7755+ let res = f ( self ) ;
7756+ self . state = current_state;
7757+ res
7758+ }
7759+
7760+ pub fn parse_connect_by ( & mut self ) -> Result < ConnectBy , ParserError > {
7761+ let ( condition, relationships) = if self . parse_keywords ( & [ Keyword :: CONNECT , Keyword :: BY ] ) {
7762+ let relationships = self . with_state ( ParserState :: ConnectBy , |parser| {
7763+ parser. parse_comma_separated ( Parser :: parse_expr)
7764+ } ) ?;
7765+ self . expect_keywords ( & [ Keyword :: START , Keyword :: WITH ] ) ?;
7766+ let condition = self . parse_expr ( ) ?;
7767+ ( condition, relationships)
7768+ } else {
7769+ self . expect_keywords ( & [ Keyword :: START , Keyword :: WITH ] ) ?;
7770+ let condition = self . parse_expr ( ) ?;
7771+ self . expect_keywords ( & [ Keyword :: CONNECT , Keyword :: BY ] ) ?;
7772+ let relationships = self . with_state ( ParserState :: ConnectBy , |parser| {
7773+ parser. parse_comma_separated ( Parser :: parse_expr)
7774+ } ) ?;
7775+ ( condition, relationships)
7776+ } ;
7777+ Ok ( ConnectBy {
7778+ condition,
7779+ relationships,
77147780 } )
77157781 }
77167782
0 commit comments