@@ -8,22 +8,18 @@ use arrow_json::writer::JsonArray;
88use arrow_json:: WriterBuilder ;
99use async_trait:: async_trait;
1010use bytes:: Bytes ;
11- use datafusion:: execution:: context:: SessionContext ;
12- use datafusion:: execution:: SessionStateBuilder ;
13- use datafusion:: prelude:: { CsvReadOptions , SessionConfig } ;
11+ use datafusion:: prelude:: CsvReadOptions ;
1412use datafusion_iceberg:: catalog:: catalog:: IcebergCatalog ;
15- use datafusion_iceberg:: planner:: IcebergQueryPlanner ;
1613use iceberg_rest_catalog:: apis:: configuration:: Configuration ;
1714use iceberg_rest_catalog:: catalog:: RestCatalog ;
1815use object_store:: path:: Path ;
1916use object_store:: { ObjectStore , PutPayload } ;
2017use runtime:: datafusion:: execution:: SqlExecutor ;
21- use runtime:: datafusion:: type_planner :: CustomTypePlanner ;
18+ use runtime:: datafusion:: session :: Session ;
2219use rusoto_core:: { HttpClient , Region } ;
2320use rusoto_credential:: StaticProvider ;
2421use rusoto_s3:: { GetBucketAclRequest , S3Client , S3 } ;
2522use snafu:: ResultExt ;
26- use std:: env;
2723use std:: sync:: Arc ;
2824use url:: Url ;
2925use uuid:: Uuid ;
@@ -77,16 +73,21 @@ pub trait ControlService: Send + Sync {
7773pub struct ControlServiceImpl {
7874 storage_profile_repo : Arc < dyn StorageProfileRepository > ,
7975 warehouse_repo : Arc < dyn WarehouseRepository > ,
76+ executor : SqlExecutor ,
8077}
8178
8279impl ControlServiceImpl {
8380 pub fn new (
8481 storage_profile_repo : Arc < dyn StorageProfileRepository > ,
8582 warehouse_repo : Arc < dyn WarehouseRepository > ,
8683 ) -> Self {
84+ let session = Session :: default ( ) ;
85+ #[ allow( clippy:: unwrap_used) ]
86+ let executor = SqlExecutor :: new ( session. ctx ) . unwrap ( ) ;
8787 Self {
8888 storage_profile_repo,
8989 warehouse_repo,
90+ executor,
9091 }
9192 }
9293}
@@ -203,29 +204,13 @@ impl ControlService for ControlServiceImpl {
203204 #[ tracing:: instrument( level = "debug" , skip( self ) ) ]
204205 #[ allow( clippy:: large_futures) ]
205206 async fn query ( & self , query : & str ) -> ControlPlaneResult < ( Vec < RecordBatch > , Vec < ColumnInfo > ) > {
206- let sql_parser_dialect =
207- env:: var ( "SQL_PARSER_DIALECT" ) . unwrap_or_else ( |_| "snowflake" . to_string ( ) ) ;
208- let state = SessionStateBuilder :: new ( )
209- . with_config (
210- SessionConfig :: new ( )
211- . with_information_schema ( true )
212- . set_str ( "datafusion.sql_parser.dialect" , & sql_parser_dialect) ,
213- )
214- . with_default_features ( )
215- . with_query_planner ( Arc :: new ( IcebergQueryPlanner { } ) )
216- . with_type_planner ( Arc :: new ( CustomTypePlanner { } ) )
217- . build ( ) ;
218- let ctx = SessionContext :: new_with_state ( state) ;
219-
220- // TODO: Should be shared context
221- let executor = SqlExecutor :: new ( ctx) . context ( crate :: error:: ExecutionSnafu ) ?;
222-
223- let query = executor. preprocess_query ( query) ;
224- let statement = executor
207+ let query = self . executor . preprocess_query ( query) ;
208+ let statement = self
209+ . executor
225210 . parse_query ( & query)
226211 . context ( super :: error:: DataFusionSnafu ) ?;
227212
228- let table_ref = executor. get_table_path ( & statement) ;
213+ let table_ref = self . executor . get_table_path ( & statement) ;
229214 let warehouse_name = table_ref
230215 . as_ref ( )
231216 . and_then ( |table_ref| table_ref. catalog ( ) )
@@ -236,7 +221,7 @@ impl ControlService for ControlServiceImpl {
236221 ( String :: from ( "datafusion" ) , String :: new ( ) )
237222 } else {
238223 let warehouse = self . get_warehouse_by_name ( warehouse_name. clone ( ) ) . await ?;
239- if executor. ctx . catalog ( warehouse. name . as_str ( ) ) . is_none ( ) {
224+ if self . executor . ctx . catalog ( warehouse. name . as_str ( ) ) . is_none ( ) {
240225 let storage_profile = self . get_profile ( warehouse. storage_profile_id ) . await ?;
241226
242227 let config = {
@@ -254,24 +239,27 @@ impl ControlService for ControlServiceImpl {
254239 ) ;
255240
256241 let catalog = IcebergCatalog :: new ( Arc :: new ( rest_client) , None ) . await ?;
257- executor
258- . ctx
259- . register_catalog ( warehouse. name . clone ( ) , Arc :: new ( catalog) ) ;
242+ if self . executor . ctx . catalog ( warehouse. name . as_str ( ) ) . is_none ( ) {
243+ self . executor
244+ . ctx
245+ . register_catalog ( warehouse. name . clone ( ) , Arc :: new ( catalog) ) ;
246+ }
260247
261248 let object_store = storage_profile
262249 . get_object_store ( )
263250 . context ( crate :: error:: InvalidStorageProfileSnafu ) ?;
264251 let endpoint_url = storage_profile
265252 . get_object_store_endpoint_url ( )
266253 . map_err ( |_| ControlPlaneError :: MissingStorageEndpointURL ) ?;
267- executor
254+ self . executor
268255 . ctx
269256 . register_object_store ( & endpoint_url, Arc :: from ( object_store) ) ;
270257 }
271258 ( warehouse. name , warehouse. location )
272259 } ;
273260
274- let records: Vec < RecordBatch > = executor
261+ let records: Vec < RecordBatch > = self
262+ . executor
275263 . query ( & query, catalog_name. as_str ( ) , warehouse_location. as_str ( ) )
276264 . await
277265 . context ( crate :: error:: ExecutionSnafu ) ?
@@ -388,28 +376,26 @@ impl ControlService for ControlServiceImpl {
388376 . await
389377 . context ( crate :: error:: ObjectStoreSnafu ) ?;
390378
391- // Create table from CSV
392- let config = {
393- let mut config = Configuration :: new ( ) ;
394- config. base_path = "http://0.0.0.0:3000/catalog" . to_string ( ) ;
395- config
396- } ;
397- let object_store_builder = storage_profile
398- . get_object_store_builder ( )
399- . context ( crate :: error:: InvalidStorageProfileSnafu ) ?;
400- let rest_client = RestCatalog :: new (
401- Some ( warehouse_id. to_string ( ) . as_str ( ) ) ,
402- config,
403- object_store_builder,
404- ) ;
405- let catalog = IcebergCatalog :: new ( Arc :: new ( rest_client) , None ) . await ?;
406- let state = SessionStateBuilder :: new ( )
407- . with_default_features ( )
408- . with_query_planner ( Arc :: new ( IcebergQueryPlanner { } ) )
409- . build ( ) ;
410-
411- let ctx = SessionContext :: new_with_state ( state) ;
412- ctx. register_catalog ( warehouse_name. clone ( ) , Arc :: new ( catalog) ) ;
379+ if self . executor . ctx . catalog ( warehouse. name . as_str ( ) ) . is_none ( ) {
380+ // Create table from CSV
381+ let config = {
382+ let mut config = Configuration :: new ( ) ;
383+ config. base_path = "http://0.0.0.0:3000/catalog" . to_string ( ) ;
384+ config
385+ } ;
386+ let object_store_builder = storage_profile
387+ . get_object_store_builder ( )
388+ . context ( crate :: error:: InvalidStorageProfileSnafu ) ?;
389+ let rest_client = RestCatalog :: new (
390+ Some ( warehouse_id. to_string ( ) . as_str ( ) ) ,
391+ config,
392+ object_store_builder,
393+ ) ;
394+ let catalog = IcebergCatalog :: new ( Arc :: new ( rest_client) , None ) . await ?;
395+ self . executor
396+ . ctx
397+ . register_catalog ( warehouse. name . clone ( ) , Arc :: new ( catalog) ) ;
398+ }
413399
414400 // Register CSV file as a table
415401 let storage_endpoint_url = storage_profile
@@ -429,15 +415,18 @@ impl ControlService for ControlServiceImpl {
429415 url : storage_endpoint_url,
430416 } ,
431417 ) ?;
432- ctx. register_object_store ( & endpoint_url, Arc :: from ( object_store) ) ;
433- ctx. register_csv ( table_name, path_string, CsvReadOptions :: new ( ) )
418+ self . executor
419+ . ctx
420+ . register_object_store ( & endpoint_url, Arc :: from ( object_store) ) ;
421+ self . executor
422+ . ctx
423+ . register_csv ( table_name, path_string, CsvReadOptions :: new ( ) )
434424 . await ?;
435425
436426 let insert_query = format ! (
437427 "INSERT INTO {warehouse_name}.{database_name}.{table_name} SELECT * FROM {table_name}"
438428 ) ;
439- let executor = SqlExecutor :: new ( ctx) . context ( crate :: error:: ExecutionSnafu ) ?;
440- executor
429+ self . executor
441430 . execute_with_custom_plan ( & insert_query, warehouse_name. as_str ( ) )
442431 . await
443432 . context ( crate :: error:: ExecutionSnafu ) ?;
@@ -553,6 +542,7 @@ mod tests {
553542 } ;
554543 use crate :: repository:: InMemoryStorageProfileRepository ;
555544 use crate :: repository:: InMemoryWarehouseRepository ;
545+ use std:: env;
556546
557547 #[ tokio:: test]
558548 async fn test_create_warehouse_failed_no_storage_profile ( ) {
0 commit comments