@@ -20,10 +20,12 @@ mod test_utils;
20
20
21
21
use std:: ops:: Deref ;
22
22
23
+ use sqlparser:: ast:: helpers:: attached_token:: AttachedToken ;
23
24
use sqlparser:: ast:: * ;
24
25
use sqlparser:: dialect:: { BigQueryDialect , GenericDialect } ;
26
+ use sqlparser:: keywords:: Keyword ;
25
27
use sqlparser:: parser:: { ParserError , ParserOptions } ;
26
- use sqlparser:: tokenizer:: { Location , Span } ;
28
+ use sqlparser:: tokenizer:: { Location , Span , Token , TokenWithSpan , Word } ;
27
29
use test_utils:: * ;
28
30
29
31
#[ test]
@@ -2567,6 +2569,234 @@ fn test_struct_trailing_and_nested_bracket() {
2567
2569
) ;
2568
2570
}
2569
2571
2572
+ #[ test]
2573
+ fn test_export_data ( ) {
2574
+ let stmt = bigquery ( ) . verified_stmt ( concat ! (
2575
+ "EXPORT DATA OPTIONS(" ,
2576
+ "uri = 'gs://bucket/folder/*', " ,
2577
+ "format = 'PARQUET', " ,
2578
+ "overwrite = true" ,
2579
+ ") AS " ,
2580
+ "SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
2581
+ ) ) ;
2582
+ assert_eq ! (
2583
+ stmt,
2584
+ Statement :: ExportData ( ExportData {
2585
+ options: vec![
2586
+ SqlOption :: KeyValue {
2587
+ key: Ident :: new( "uri" ) ,
2588
+ value: Expr :: Value (
2589
+ Value :: SingleQuotedString ( "gs://bucket/folder/*" . to_owned( ) )
2590
+ . with_empty_span( )
2591
+ ) ,
2592
+ } ,
2593
+ SqlOption :: KeyValue {
2594
+ key: Ident :: new( "format" ) ,
2595
+ value: Expr :: Value (
2596
+ Value :: SingleQuotedString ( "PARQUET" . to_owned( ) ) . with_empty_span( )
2597
+ ) ,
2598
+ } ,
2599
+ SqlOption :: KeyValue {
2600
+ key: Ident :: new( "overwrite" ) ,
2601
+ value: Expr :: Value ( Value :: Boolean ( true ) . with_empty_span( ) ) ,
2602
+ } ,
2603
+ ] ,
2604
+ connection: None ,
2605
+ query: Box :: new( Query {
2606
+ with: None ,
2607
+ body: Box :: new( SetExpr :: Select ( Box :: new( Select {
2608
+ select_token: AttachedToken ( TokenWithSpan :: new(
2609
+ Token :: Word ( Word {
2610
+ value: "SELECT" . to_string( ) ,
2611
+ quote_style: None ,
2612
+ keyword: Keyword :: SELECT ,
2613
+ } ) ,
2614
+ Span :: empty( )
2615
+ ) ) ,
2616
+ distinct: None ,
2617
+ top: None ,
2618
+ top_before_distinct: false ,
2619
+ projection: vec![
2620
+ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new( "field1" ) ) ) ,
2621
+ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new( "field2" ) ) ) ,
2622
+ ] ,
2623
+ exclude: None ,
2624
+ into: None ,
2625
+ from: vec![ TableWithJoins {
2626
+ relation: table_from_name( ObjectName :: from( vec![
2627
+ Ident :: new( "mydataset" ) ,
2628
+ Ident :: new( "table1" )
2629
+ ] ) ) ,
2630
+ joins: vec![ ] ,
2631
+ } ] ,
2632
+ lateral_views: vec![ ] ,
2633
+ prewhere: None ,
2634
+ selection: None ,
2635
+ group_by: GroupByExpr :: Expressions ( vec![ ] , vec![ ] ) ,
2636
+ cluster_by: vec![ ] ,
2637
+ distribute_by: vec![ ] ,
2638
+ sort_by: vec![ ] ,
2639
+ having: None ,
2640
+ named_window: vec![ ] ,
2641
+ qualify: None ,
2642
+ window_before_qualify: false ,
2643
+ value_table_mode: None ,
2644
+ connect_by: None ,
2645
+ flavor: SelectFlavor :: Standard ,
2646
+ } ) ) ) ,
2647
+ order_by: Some ( OrderBy {
2648
+ kind: OrderByKind :: Expressions ( vec![ OrderByExpr {
2649
+ expr: Expr :: Identifier ( Ident :: new( "field1" ) ) ,
2650
+ options: OrderByOptions {
2651
+ asc: None ,
2652
+ nulls_first: None ,
2653
+ } ,
2654
+ with_fill: None ,
2655
+ } , ] ) ,
2656
+ interpolate: None ,
2657
+ } ) ,
2658
+ limit_clause: Some ( LimitClause :: LimitOffset {
2659
+ limit: Some ( Expr :: Value ( number( "10" ) . with_empty_span( ) ) ) ,
2660
+ offset: None ,
2661
+ limit_by: vec![ ] ,
2662
+ } ) ,
2663
+ fetch: None ,
2664
+ locks: vec![ ] ,
2665
+ for_clause: None ,
2666
+ settings: None ,
2667
+ format_clause: None ,
2668
+ pipe_operators: vec![ ] ,
2669
+ } )
2670
+ } )
2671
+ ) ;
2672
+
2673
+ let stmt = bigquery ( ) . verified_stmt ( concat ! (
2674
+ "EXPORT DATA WITH CONNECTION myconnection.myproject.us OPTIONS(" ,
2675
+ "uri = 'gs://bucket/folder/*', " ,
2676
+ "format = 'PARQUET', " ,
2677
+ "overwrite = true" ,
2678
+ ") AS " ,
2679
+ "SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
2680
+ ) ) ;
2681
+
2682
+ assert_eq ! (
2683
+ stmt,
2684
+ Statement :: ExportData ( ExportData {
2685
+ options: vec![
2686
+ SqlOption :: KeyValue {
2687
+ key: Ident :: new( "uri" ) ,
2688
+ value: Expr :: Value (
2689
+ Value :: SingleQuotedString ( "gs://bucket/folder/*" . to_owned( ) )
2690
+ . with_empty_span( )
2691
+ ) ,
2692
+ } ,
2693
+ SqlOption :: KeyValue {
2694
+ key: Ident :: new( "format" ) ,
2695
+ value: Expr :: Value (
2696
+ Value :: SingleQuotedString ( "PARQUET" . to_owned( ) ) . with_empty_span( )
2697
+ ) ,
2698
+ } ,
2699
+ SqlOption :: KeyValue {
2700
+ key: Ident :: new( "overwrite" ) ,
2701
+ value: Expr :: Value ( Value :: Boolean ( true ) . with_empty_span( ) ) ,
2702
+ } ,
2703
+ ] ,
2704
+ connection: Some ( ObjectName :: from( vec![
2705
+ Ident :: new( "myconnection" ) ,
2706
+ Ident :: new( "myproject" ) ,
2707
+ Ident :: new( "us" )
2708
+ ] ) ) ,
2709
+ query: Box :: new( Query {
2710
+ with: None ,
2711
+ body: Box :: new( SetExpr :: Select ( Box :: new( Select {
2712
+ select_token: AttachedToken ( TokenWithSpan :: new(
2713
+ Token :: Word ( Word {
2714
+ value: "SELECT" . to_string( ) ,
2715
+ quote_style: None ,
2716
+ keyword: Keyword :: SELECT ,
2717
+ } ) ,
2718
+ Span :: empty( )
2719
+ ) ) ,
2720
+ distinct: None ,
2721
+ top: None ,
2722
+ top_before_distinct: false ,
2723
+ projection: vec![
2724
+ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new( "field1" ) ) ) ,
2725
+ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new( "field2" ) ) ) ,
2726
+ ] ,
2727
+ exclude: None ,
2728
+ into: None ,
2729
+ from: vec![ TableWithJoins {
2730
+ relation: table_from_name( ObjectName :: from( vec![
2731
+ Ident :: new( "mydataset" ) ,
2732
+ Ident :: new( "table1" )
2733
+ ] ) ) ,
2734
+ joins: vec![ ] ,
2735
+ } ] ,
2736
+ lateral_views: vec![ ] ,
2737
+ prewhere: None ,
2738
+ selection: None ,
2739
+ group_by: GroupByExpr :: Expressions ( vec![ ] , vec![ ] ) ,
2740
+ cluster_by: vec![ ] ,
2741
+ distribute_by: vec![ ] ,
2742
+ sort_by: vec![ ] ,
2743
+ having: None ,
2744
+ named_window: vec![ ] ,
2745
+ qualify: None ,
2746
+ window_before_qualify: false ,
2747
+ value_table_mode: None ,
2748
+ connect_by: None ,
2749
+ flavor: SelectFlavor :: Standard ,
2750
+ } ) ) ) ,
2751
+ order_by: Some ( OrderBy {
2752
+ kind: OrderByKind :: Expressions ( vec![ OrderByExpr {
2753
+ expr: Expr :: Identifier ( Ident :: new( "field1" ) ) ,
2754
+ options: OrderByOptions {
2755
+ asc: None ,
2756
+ nulls_first: None ,
2757
+ } ,
2758
+ with_fill: None ,
2759
+ } , ] ) ,
2760
+ interpolate: None ,
2761
+ } ) ,
2762
+ limit_clause: Some ( LimitClause :: LimitOffset {
2763
+ limit: Some ( Expr :: Value ( number( "10" ) . with_empty_span( ) ) ) ,
2764
+ offset: None ,
2765
+ limit_by: vec![ ] ,
2766
+ } ) ,
2767
+ fetch: None ,
2768
+ locks: vec![ ] ,
2769
+ for_clause: None ,
2770
+ settings: None ,
2771
+ format_clause: None ,
2772
+ pipe_operators: vec![ ] ,
2773
+ } )
2774
+ } )
2775
+ ) ;
2776
+
2777
+ // at least one option (uri) is required
2778
+ let err = bigquery ( )
2779
+ . parse_sql_statements ( concat ! (
2780
+ "EXPORT DATA OPTIONS() AS " ,
2781
+ "SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
2782
+ ) )
2783
+ . unwrap_err ( ) ;
2784
+ assert_eq ! (
2785
+ err. to_string( ) ,
2786
+ "sql parser error: Expected: identifier, found: )"
2787
+ ) ;
2788
+
2789
+ let err = bigquery ( )
2790
+ . parse_sql_statements ( concat ! (
2791
+ "EXPORT DATA AS SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
2792
+ ) )
2793
+ . unwrap_err ( ) ;
2794
+ assert_eq ! (
2795
+ err. to_string( ) ,
2796
+ "sql parser error: Expected: OPTIONS, found: AS"
2797
+ ) ;
2798
+ }
2799
+
2570
2800
#[ test]
2571
2801
fn test_begin_transaction ( ) {
2572
2802
bigquery ( ) . verified_stmt ( "BEGIN TRANSACTION" ) ;
0 commit comments