@@ -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]
@@ -2567,6 +2569,234 @@ fn test_struct_trailing_and_nested_bracket() {
25672569 ) ;
25682570}
25692571
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+
25702800#[ test]
25712801fn test_begin_transaction ( ) {
25722802 bigquery ( ) . verified_stmt ( "BEGIN TRANSACTION" ) ;
0 commit comments