@@ -279,6 +279,50 @@ impl UserQuery {
279279 // 3. Single place to construct Logical plan from this AST
280280 // 4. Single place to rewrite-optimize-adjust logical plan
281281 // etc
282+ if self . session . config . read_only {
283+ match statement {
284+ DFStatement :: Statement ( s) => match * s {
285+ Statement :: Query ( subquery) => {
286+ return self . execute_query_statement ( subquery) . await ;
287+ }
288+ Statement :: Use ( entity) => {
289+ return self . execute_use_statement ( entity) . await ;
290+ }
291+ other => {
292+ return ex_error:: NotSupportedStatementInReadOnlyModeSnafu {
293+ statement : other. to_string ( ) ,
294+ }
295+ . fail ( ) ;
296+ }
297+ } ,
298+ DFStatement :: Explain ( explain) => match * explain. statement {
299+ DFStatement :: Statement ( s) => match * s {
300+ Statement :: Query ( ..) | Statement :: Use ( ..) => {
301+ return self . execute_sql ( & self . query ) . await ;
302+ }
303+ other => {
304+ return ex_error:: NotSupportedStatementInReadOnlyModeSnafu {
305+ statement : other. to_string ( ) ,
306+ }
307+ . fail ( ) ;
308+ }
309+ } ,
310+ other => {
311+ return ex_error:: NotSupportedStatementInReadOnlyModeSnafu {
312+ statement : other. to_string ( ) ,
313+ }
314+ . fail ( ) ;
315+ }
316+ } ,
317+ other => {
318+ return ex_error:: NotSupportedStatementInReadOnlyModeSnafu {
319+ statement : other. to_string ( ) ,
320+ }
321+ . fail ( ) ;
322+ }
323+ }
324+ }
325+
282326 if let DFStatement :: Statement ( s) = statement {
283327 match * s {
284328 Statement :: AlterSession {
@@ -300,29 +344,7 @@ impl UserQuery {
300344 return self . status_response ( ) ;
301345 }
302346 Statement :: Use ( entity) => {
303- let ( variable, value) = match entity {
304- Use :: Catalog ( n) => ( "catalog" , n. to_string ( ) ) ,
305- Use :: Schema ( n) => ( "schema" , n. to_string ( ) ) ,
306- Use :: Database ( n) => ( "database" , n. to_string ( ) ) ,
307- Use :: Warehouse ( n) => ( "warehouse" , n. to_string ( ) ) ,
308- Use :: Role ( n) => ( "role" , n. to_string ( ) ) ,
309- Use :: Object ( n) => ( "object" , n. to_string ( ) ) ,
310- Use :: SecondaryRoles ( sr) => ( "secondary_roles" , sr. to_string ( ) ) ,
311- Use :: Default => ( "" , String :: new ( ) ) ,
312- } ;
313- if variable. is_empty ( ) | value. is_empty ( ) {
314- return ex_error:: OnyUseWithVariablesSnafu . fail ( ) ;
315- }
316- let params = HashMap :: from ( [ (
317- variable. to_string ( ) ,
318- SessionProperty :: from_str_value (
319- variable. to_string ( ) ,
320- value,
321- Some ( self . session . ctx . session_id ( ) ) ,
322- ) ,
323- ) ] ) ;
324- self . session . set_session_variable ( true , params) ?;
325- return self . status_response ( ) ;
347+ return self . execute_use_statement ( entity) . await ;
326348 }
327349 Statement :: Set ( statement) => {
328350 use datafusion:: sql:: sqlparser:: ast:: Set ;
@@ -397,9 +419,8 @@ impl UserQuery {
397419 Statement :: Truncate { table_names, .. } => {
398420 return Box :: pin ( self . truncate_table ( table_names) ) . await ;
399421 }
400- Statement :: Query ( mut subquery) => {
401- self . traverse_and_update_query ( subquery. as_mut ( ) ) . await ;
402- return Box :: pin ( self . execute_with_custom_plan ( & subquery. to_string ( ) ) ) . await ;
422+ Statement :: Query ( subquery) => {
423+ return self . execute_query_statement ( subquery) . await ;
403424 }
404425 Statement :: Drop { .. } => return Box :: pin ( self . drop_query ( * s) ) . await ,
405426 Statement :: Merge { .. } => return Box :: pin ( self . merge_query ( * s) ) . await ,
@@ -418,6 +439,60 @@ impl UserQuery {
418439 self . execute_sql ( & self . query ) . await
419440 }
420441
442+ #[ instrument(
443+ name = "UserQuery::execute_query_statement" ,
444+ level = "debug" ,
445+ skip( self ) ,
446+ fields(
447+ statement,
448+ query_id = self . query_context. query_id. to_string( ) ,
449+ ) ,
450+ err
451+ ) ]
452+ pub async fn execute_query_statement (
453+ & mut self ,
454+ mut subquery : Box < Query > ,
455+ ) -> Result < QueryResult > {
456+ self . traverse_and_update_query ( subquery. as_mut ( ) ) . await ;
457+ Box :: pin ( self . execute_with_custom_plan ( & subquery. to_string ( ) ) ) . await
458+ }
459+
460+ #[ instrument(
461+ name = "UserQuery::execute_use_statement" ,
462+ level = "debug" ,
463+ skip( self ) ,
464+ fields(
465+ statement,
466+ query_id = self . query_context. query_id. to_string( ) ,
467+ ) ,
468+ err
469+ ) ]
470+ pub async fn execute_use_statement ( & mut self , entity : Use ) -> Result < QueryResult > {
471+ let ( variable, value) = match entity {
472+ Use :: Catalog ( n) => ( "catalog" , n. to_string ( ) ) ,
473+ Use :: Schema ( n) => ( "schema" , n. to_string ( ) ) ,
474+ Use :: Database ( n) => ( "database" , n. to_string ( ) ) ,
475+ Use :: Warehouse ( n) => ( "warehouse" , n. to_string ( ) ) ,
476+ Use :: Role ( n) => ( "role" , n. to_string ( ) ) ,
477+ Use :: Object ( n) => ( "object" , n. to_string ( ) ) ,
478+ Use :: SecondaryRoles ( sr) => ( "secondary_roles" , sr. to_string ( ) ) ,
479+ Use :: Default => ( "" , String :: new ( ) ) ,
480+ } ;
481+ if variable. is_empty ( ) | value. is_empty ( ) {
482+ return ex_error:: OnyUseWithVariablesSnafu . fail ( ) ;
483+ }
484+ let params = HashMap :: from ( [ (
485+ variable. to_string ( ) ,
486+ SessionProperty :: from_str_value (
487+ variable. to_string ( ) ,
488+ value,
489+ Some ( self . session . ctx . session_id ( ) ) ,
490+ ) ,
491+ ) ] ) ;
492+ self . session . set_session_variable ( true , params) ?;
493+ self . status_response ( )
494+ }
495+
421496 #[ instrument( name = "UserQuery::get_catalog" , level = "trace" , skip( self ) , err) ]
422497 pub fn get_catalog ( & self , name : & str ) -> Result < Arc < dyn CatalogProvider > > {
423498 self . session
0 commit comments