@@ -20,10 +20,12 @@ mod test_utils;
2020
2121use std:: ops:: Deref ;
2222
23+ use sqlparser:: ast:: helpers:: attached_token:: AttachedToken ;
2324use sqlparser:: ast:: * ;
2425use sqlparser:: dialect:: { BigQueryDialect , GenericDialect } ;
26+ use sqlparser:: keywords:: Keyword ;
2527use sqlparser:: parser:: { ParserError , ParserOptions } ;
26- use sqlparser:: tokenizer:: { Location , Span } ;
28+ use sqlparser:: tokenizer:: { Location , Span , Token , TokenWithSpan , Word } ;
2729use test_utils:: * ;
2830
2931#[ test]
@@ -2569,23 +2571,234 @@ fn test_struct_trailing_and_nested_bracket() {
25692571
25702572#[ test]
25712573fn test_export_data ( ) {
2572- bigquery ( ) . verified_stmt ( concat ! (
2574+ let stmt = bigquery ( ) . verified_stmt ( concat ! (
25732575 "EXPORT DATA OPTIONS(" ,
25742576 "uri = 'gs://bucket/folder/*', " ,
25752577 "format = 'PARQUET', " ,
25762578 "overwrite = true" ,
25772579 ") AS " ,
25782580 "SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
25792581 ) ) ;
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 (
2660+ Value :: Number ( "10" . to_string( ) , false ) . with_empty_span( )
2661+ ) ) ,
2662+ offset: None ,
2663+ limit_by: vec![ ] ,
2664+ } ) ,
2665+ fetch: None ,
2666+ locks: vec![ ] ,
2667+ for_clause: None ,
2668+ settings: None ,
2669+ format_clause: None ,
2670+ pipe_operators: vec![ ] ,
2671+ } )
2672+ } )
2673+ ) ;
25802674
2581- bigquery ( ) . verified_stmt ( concat ! (
2675+ let stmt = bigquery ( ) . verified_stmt ( concat ! (
25822676 "EXPORT DATA WITH CONNECTION myconnection.myproject.us OPTIONS(" ,
25832677 "uri = 'gs://bucket/folder/*', " ,
25842678 "format = 'PARQUET', " ,
25852679 "overwrite = true" ,
25862680 ") AS " ,
25872681 "SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
25882682 ) ) ;
2683+
2684+ assert_eq ! (
2685+ stmt,
2686+ Statement :: ExportData ( ExportData {
2687+ options: vec![
2688+ SqlOption :: KeyValue {
2689+ key: Ident :: new( "uri" ) ,
2690+ value: Expr :: Value (
2691+ Value :: SingleQuotedString ( "gs://bucket/folder/*" . to_owned( ) )
2692+ . with_empty_span( )
2693+ ) ,
2694+ } ,
2695+ SqlOption :: KeyValue {
2696+ key: Ident :: new( "format" ) ,
2697+ value: Expr :: Value (
2698+ Value :: SingleQuotedString ( "PARQUET" . to_owned( ) ) . with_empty_span( )
2699+ ) ,
2700+ } ,
2701+ SqlOption :: KeyValue {
2702+ key: Ident :: new( "overwrite" ) ,
2703+ value: Expr :: Value ( Value :: Boolean ( true ) . with_empty_span( ) ) ,
2704+ } ,
2705+ ] ,
2706+ connection: Some ( ObjectName :: from( vec![
2707+ Ident :: new( "myconnection" ) ,
2708+ Ident :: new( "myproject" ) ,
2709+ Ident :: new( "us" )
2710+ ] ) ) ,
2711+ query: Box :: new( Query {
2712+ with: None ,
2713+ body: Box :: new( SetExpr :: Select ( Box :: new( Select {
2714+ select_token: AttachedToken ( TokenWithSpan :: new(
2715+ Token :: Word ( Word {
2716+ value: "SELECT" . to_string( ) ,
2717+ quote_style: None ,
2718+ keyword: Keyword :: SELECT ,
2719+ } ) ,
2720+ Span :: empty( )
2721+ ) ) ,
2722+ distinct: None ,
2723+ top: None ,
2724+ top_before_distinct: false ,
2725+ projection: vec![
2726+ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new( "field1" ) ) ) ,
2727+ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new( "field2" ) ) ) ,
2728+ ] ,
2729+ exclude: None ,
2730+ into: None ,
2731+ from: vec![ TableWithJoins {
2732+ relation: table_from_name( ObjectName :: from( vec![
2733+ Ident :: new( "mydataset" ) ,
2734+ Ident :: new( "table1" )
2735+ ] ) ) ,
2736+ joins: vec![ ] ,
2737+ } ] ,
2738+ lateral_views: vec![ ] ,
2739+ prewhere: None ,
2740+ selection: None ,
2741+ group_by: GroupByExpr :: Expressions ( vec![ ] , vec![ ] ) ,
2742+ cluster_by: vec![ ] ,
2743+ distribute_by: vec![ ] ,
2744+ sort_by: vec![ ] ,
2745+ having: None ,
2746+ named_window: vec![ ] ,
2747+ qualify: None ,
2748+ window_before_qualify: false ,
2749+ value_table_mode: None ,
2750+ connect_by: None ,
2751+ flavor: SelectFlavor :: Standard ,
2752+ } ) ) ) ,
2753+ order_by: Some ( OrderBy {
2754+ kind: OrderByKind :: Expressions ( vec![ OrderByExpr {
2755+ expr: Expr :: Identifier ( Ident :: new( "field1" ) ) ,
2756+ options: OrderByOptions {
2757+ asc: None ,
2758+ nulls_first: None ,
2759+ } ,
2760+ with_fill: None ,
2761+ } , ] ) ,
2762+ interpolate: None ,
2763+ } ) ,
2764+ limit_clause: Some ( LimitClause :: LimitOffset {
2765+ limit: Some ( Expr :: Value (
2766+ Value :: Number ( "10" . to_string( ) , false ) . with_empty_span( )
2767+ ) ) ,
2768+ offset: None ,
2769+ limit_by: vec![ ] ,
2770+ } ) ,
2771+ fetch: None ,
2772+ locks: vec![ ] ,
2773+ for_clause: None ,
2774+ settings: None ,
2775+ format_clause: None ,
2776+ pipe_operators: vec![ ] ,
2777+ } )
2778+ } )
2779+ ) ;
2780+
2781+ // at least one option (uri) is required
2782+ let err = bigquery ( )
2783+ . parse_sql_statements ( concat ! (
2784+ "EXPORT DATA OPTIONS() AS " ,
2785+ "SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
2786+ ) )
2787+ . unwrap_err ( ) ;
2788+ assert_eq ! (
2789+ err. to_string( ) ,
2790+ "sql parser error: Expected: identifier, found: )"
2791+ ) ;
2792+
2793+ let err = bigquery ( )
2794+ . parse_sql_statements ( concat ! (
2795+ "EXPORT DATA AS SELECT field1, field2 FROM mydataset.table1 ORDER BY field1 LIMIT 10" ,
2796+ ) )
2797+ . unwrap_err ( ) ;
2798+ assert_eq ! (
2799+ err. to_string( ) ,
2800+ "sql parser error: Expected: OPTIONS, found: AS"
2801+ ) ;
25892802}
25902803
25912804#[ test]
0 commit comments