@@ -413,13 +413,18 @@ impl<'a> DFParser<'a> {
413
413
parser. parse_statements ( )
414
414
}
415
415
416
+ pub fn parse_sql_into_expr ( sql : & str ) -> Result < ExprWithAlias , DataFusionError > {
417
+ DFParserBuilder :: new ( sql) . build ( ) ?. parse_into_expr ( )
418
+ }
419
+
416
420
pub fn parse_sql_into_expr_with_dialect (
417
421
sql : & str ,
418
422
dialect : & dyn Dialect ,
419
423
) -> Result < ExprWithAlias , DataFusionError > {
420
- let mut parser = DFParserBuilder :: new ( sql) . with_dialect ( dialect) . build ( ) ?;
421
-
422
- parser. parse_expr ( )
424
+ DFParserBuilder :: new ( sql)
425
+ . with_dialect ( dialect)
426
+ . build ( ) ?
427
+ . parse_into_expr ( )
423
428
}
424
429
425
430
/// Parse a sql string into one or [`Statement`]s
@@ -465,6 +470,19 @@ impl<'a> DFParser<'a> {
465
470
)
466
471
}
467
472
473
+ fn expect_token (
474
+ & mut self ,
475
+ expected : & str ,
476
+ token : Token ,
477
+ ) -> Result < ( ) , DataFusionError > {
478
+ let next_token = self . parser . peek_token_ref ( ) ;
479
+ if next_token. token != token {
480
+ self . expected ( expected, next_token. clone ( ) )
481
+ } else {
482
+ Ok ( ( ) )
483
+ }
484
+ }
485
+
468
486
/// Parse a new expression
469
487
pub fn parse_statement ( & mut self ) -> Result < Statement , DataFusionError > {
470
488
match self . parser . peek_token ( ) . token {
@@ -514,6 +532,16 @@ impl<'a> DFParser<'a> {
514
532
Ok ( self . parser . parse_expr_with_alias ( ) ?)
515
533
}
516
534
535
+ /// Parses the entire SQL string into an expression.
536
+ ///
537
+ /// In contrast to [`parse_expr`], this function will report an error if the input
538
+ /// contains any trailing, unparsed tokens.
539
+ pub fn parse_into_expr ( & mut self ) -> Result < ExprWithAlias , DataFusionError > {
540
+ let expr = self . parse_expr ( ) ?;
541
+ self . expect_token ( "end of expression" , Token :: EOF ) ?;
542
+ Ok ( expr)
543
+ }
544
+
517
545
/// Helper method to parse a statement and handle errors consistently, especially for recursion limits
518
546
fn parse_and_handle_statement ( & mut self ) -> Result < Statement , DataFusionError > {
519
547
self . parser
@@ -1021,7 +1049,7 @@ mod tests {
1021
1049
use super :: * ;
1022
1050
use datafusion_common:: assert_contains;
1023
1051
use sqlparser:: ast:: Expr :: Identifier ;
1024
- use sqlparser:: ast:: { BinaryOperator , DataType , Expr , Ident } ;
1052
+ use sqlparser:: ast:: { BinaryOperator , DataType , Expr , Ident , ValueWithSpan } ;
1025
1053
use sqlparser:: dialect:: SnowflakeDialect ;
1026
1054
use sqlparser:: tokenizer:: Span ;
1027
1055
@@ -1783,4 +1811,77 @@ mod tests {
1783
1811
"SQL error: RecursionLimitExceeded (current limit: 1)"
1784
1812
) ;
1785
1813
}
1814
+
1815
+ fn expect_parse_expr_ok ( sql : & str , expected : ExprWithAlias ) {
1816
+ let expr = DFParser :: parse_sql_into_expr ( sql) . unwrap ( ) ;
1817
+ assert_eq ! ( expr, expected, "actual:\n {:#?}" , expr) ;
1818
+ }
1819
+
1820
+ /// Parses sql and asserts that the expected error message was found
1821
+ fn expect_parse_expr_error ( sql : & str , expected_error : & str ) {
1822
+ match DFParser :: parse_sql_into_expr ( sql) {
1823
+ Ok ( expr) => {
1824
+ panic ! ( "Expected parse error for '{sql}', but was successful: {expr:?}" ) ;
1825
+ }
1826
+ Err ( e) => {
1827
+ let error_message = e. to_string ( ) ;
1828
+ assert ! (
1829
+ error_message. contains( expected_error) ,
1830
+ "Expected error '{expected_error}' not found in actual error '{error_message}'"
1831
+ ) ;
1832
+ }
1833
+ }
1834
+ }
1835
+
1836
+ #[ test]
1837
+ fn literal ( ) {
1838
+ expect_parse_expr_ok (
1839
+ "1234" ,
1840
+ ExprWithAlias {
1841
+ expr : Expr :: Value ( ValueWithSpan :: from ( Value :: Number (
1842
+ "1234" . to_string ( ) ,
1843
+ false ,
1844
+ ) ) ) ,
1845
+ alias : None ,
1846
+ } ,
1847
+ )
1848
+ }
1849
+
1850
+ #[ test]
1851
+ fn literal_with_alias ( ) {
1852
+ expect_parse_expr_ok (
1853
+ "1234 as foo" ,
1854
+ ExprWithAlias {
1855
+ expr : Expr :: Value ( ValueWithSpan :: from ( Value :: Number (
1856
+ "1234" . to_string ( ) ,
1857
+ false ,
1858
+ ) ) ) ,
1859
+ alias : Some ( Ident :: from ( "foo" ) ) ,
1860
+ } ,
1861
+ )
1862
+ }
1863
+
1864
+ #[ test]
1865
+ fn literal_with_alias_and_trailing_tokens ( ) {
1866
+ expect_parse_expr_error ( "1234 as foo.bar" , "Unexpected token ." )
1867
+ }
1868
+
1869
+ #[ test]
1870
+ fn literal_with_alias_and_trailing_whitespace ( ) {
1871
+ expect_parse_expr_ok (
1872
+ "1234 as foo " ,
1873
+ ExprWithAlias {
1874
+ expr : Expr :: Value ( ValueWithSpan :: from ( Value :: Number (
1875
+ "1234" . to_string ( ) ,
1876
+ false ,
1877
+ ) ) ) ,
1878
+ alias : Some ( Ident :: from ( "foo" ) ) ,
1879
+ } ,
1880
+ )
1881
+ }
1882
+
1883
+ #[ test]
1884
+ fn literal_with_alias_and_trailing_whitespace_and_token ( ) {
1885
+ expect_parse_expr_error ( "1234 as foo bar" , "Unexpected token bar" )
1886
+ }
1786
1887
}
0 commit comments