diff --git a/Cargo.lock b/Cargo.lock index 48b838f79edb..3cc68f904dfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3634,7 +3634,6 @@ dependencies = [ "databend-common-meta-stoerr", "databend-common-meta-types", "databend-common-proto-conv", - "enumflags2", "fastrace", "futures", "log", diff --git a/src/query/ast/src/ast/statements/statement.rs b/src/query/ast/src/ast/statements/statement.rs index 050be0264e5f..e8272c8de9b1 100644 --- a/src/query/ast/src/ast/statements/statement.rs +++ b/src/query/ast/src/ast/statements/statement.rs @@ -96,6 +96,10 @@ pub enum Statement { identifiers: Vec, }, + ShowVariables { + show_options: Option, + }, + SetRole { is_default: bool, role_name: String, @@ -431,6 +435,12 @@ impl Display for Statement { write!(f, " {show_options}")?; } } + Statement::ShowVariables { show_options } => { + write!(f, "SHOW VARIABLES")?; + if let Some(show_options) = show_options { + write!(f, " {show_options}")?; + } + } Statement::ShowProcessList { show_options } => { write!(f, "SHOW PROCESSLIST")?; if let Some(show_options) = show_options { diff --git a/src/query/ast/src/parser/statement.rs b/src/query/ast/src/parser/statement.rs index be3b9a70eac9..b4f9c5bf61ce 100644 --- a/src/query/ast/src/parser/statement.rs +++ b/src/query/ast/src/parser/statement.rs @@ -267,6 +267,12 @@ pub fn statement_body(i: Input) -> IResult { }, |(_, _, show_options)| Statement::ShowSettings { show_options }, ); + let show_variables = map( + rule! { + SHOW ~ VARIABLES ~ #show_options? + }, + |(_, _, show_options)| Statement::ShowVariables { show_options }, + ); let show_stages = value(Statement::ShowStages, rule! { SHOW ~ STAGES }); let show_process_list = map( rule! { @@ -2170,6 +2176,7 @@ pub fn statement_body(i: Input) -> IResult { | #explain : "`EXPLAIN [PIPELINE | GRAPH] `" | #explain_analyze : "`EXPLAIN ANALYZE `" | #show_settings : "`SHOW SETTINGS []`" + | #show_variables : "`SHOW VARIABLES []`" | #show_stages : "`SHOW STAGES`" | #show_engines : "`SHOW ENGINES`" | #show_process_list : "`SHOW PROCESSLIST`" diff --git a/src/query/ast/src/parser/token.rs b/src/query/ast/src/parser/token.rs index 7d0c4f194df5..5b9f26ed6bcb 100644 --- a/src/query/ast/src/parser/token.rs +++ b/src/query/ast/src/parser/token.rs @@ -1021,6 +1021,8 @@ pub enum TokenKind { SESSION, #[token("SETTINGS", ignore(ascii_case))] SETTINGS, + #[token("VARIABLES", ignore(ascii_case))] + VARIABLES, #[token("STAGES", ignore(ascii_case))] STAGES, #[token("STATISTIC", ignore(ascii_case))] diff --git a/src/query/ast/tests/it/parser.rs b/src/query/ast/tests/it/parser.rs index 288cf8fd1ec0..c0be807a150b 100644 --- a/src/query/ast/tests/it/parser.rs +++ b/src/query/ast/tests/it/parser.rs @@ -571,6 +571,8 @@ fn test_statement() { r#"UNSET (max_threads, sql_dialect);"#, r#"UNSET session (max_threads, sql_dialect);"#, r#"SET variable a = 3"#, + r#"show variables"#, + r#"show variables like 'v%'"#, r#"SET variable a = select 3"#, r#"SET variable a = (select max(number) from numbers(10))"#, r#"select $1 FROM '@my_stage/my data/'"#, diff --git a/src/query/ast/tests/it/testdata/stmt-error.txt b/src/query/ast/tests/it/testdata/stmt-error.txt index f9bafe557bd8..2bc2bc4e517f 100644 --- a/src/query/ast/tests/it/testdata/stmt-error.txt +++ b/src/query/ast/tests/it/testdata/stmt-error.txt @@ -238,7 +238,7 @@ error: --> SQL:1:6 | 1 | SHOW GRANT FOR ROLE 'role1'; - | ^^^^^ unexpected `GRANT`, expecting `GRANTS`, `CREATE`, `NETWORK`, `VIRTUAL`, `CATALOGS`, `STREAMS`, `FUNCTIONS`, `DATABASES`, `CONNECTIONS`, `TABLE_FUNCTIONS`, `DROP`, `TABLE`, `ROLES`, `TASKS`, `INDEXES`, `COLUMNS`, `PASSWORD`, `PROCEDURES`, `PROCESSLIST`, `STAGES`, `TABLES`, `DICTIONARIES`, `ENGINES`, `METRICS`, `SETTINGS`, `LOCKS`, `SCHEMAS`, `FIELDS`, `VIEWS`, `USERS`, `USER`, `FILE`, or `FULL` + | ^^^^^ unexpected `GRANT`, expecting `GRANTS`, `CREATE`, `NETWORK`, `VIRTUAL`, `CATALOGS`, `STREAMS`, `FUNCTIONS`, `DATABASES`, `CONNECTIONS`, `TABLE_FUNCTIONS`, `DROP`, `TABLE`, `ROLES`, `TASKS`, `INDEXES`, `COLUMNS`, `PASSWORD`, `PROCEDURES`, `PROCESSLIST`, `STAGES`, `TABLES`, `DICTIONARIES`, `ENGINES`, `METRICS`, `SETTINGS`, `VARIABLES`, `LOCKS`, `SCHEMAS`, `FIELDS`, `VIEWS`, `USERS`, `USER`, `FILE`, or `FULL` ---------- Input ---------- diff --git a/src/query/ast/tests/it/testdata/stmt.txt b/src/query/ast/tests/it/testdata/stmt.txt index a009adea63a9..52e504ccf9ea 100644 --- a/src/query/ast/tests/it/testdata/stmt.txt +++ b/src/query/ast/tests/it/testdata/stmt.txt @@ -16199,6 +16199,40 @@ SetStmt { } +---------- Input ---------- +show variables +---------- Output --------- +SHOW VARIABLES +---------- AST ------------ +ShowVariables { + show_options: Some( + ShowOptions { + show_limit: None, + limit: None, + }, + ), +} + + +---------- Input ---------- +show variables like 'v%' +---------- Output --------- +SHOW VARIABLES LIKE 'v%' +---------- AST ------------ +ShowVariables { + show_options: Some( + ShowOptions { + show_limit: Some( + Like { + pattern: "v%", + }, + ), + limit: None, + }, + ), +} + + ---------- Input ---------- SET variable a = select 3 ---------- Output --------- diff --git a/src/query/service/src/interpreters/access/management_mode_access.rs b/src/query/service/src/interpreters/access/management_mode_access.rs index 4d9fb7060943..5fe39b4484f7 100644 --- a/src/query/service/src/interpreters/access/management_mode_access.rs +++ b/src/query/service/src/interpreters/access/management_mode_access.rs @@ -49,6 +49,7 @@ impl AccessChecker for ManagementModeAccess { | RewriteKind::ShowColumns(_, _, _) | RewriteKind::ShowEngines | RewriteKind::ShowSettings + | RewriteKind::ShowVariables | RewriteKind::ShowFunctions | RewriteKind::ShowUserFunctions | RewriteKind::ShowTableFunctions diff --git a/src/query/service/src/table_functions/mod.rs b/src/query/service/src/table_functions/mod.rs index fa892542a35a..2bef2a7cf428 100644 --- a/src/query/service/src/table_functions/mod.rs +++ b/src/query/service/src/table_functions/mod.rs @@ -21,6 +21,7 @@ mod numbers; mod openai; mod others; mod show_grants; +mod show_variables; mod srf; mod sync_crash_me; mod table_function; diff --git a/src/query/service/src/table_functions/show_variables/mod.rs b/src/query/service/src/table_functions/show_variables/mod.rs new file mode 100644 index 000000000000..546f05224005 --- /dev/null +++ b/src/query/service/src/table_functions/show_variables/mod.rs @@ -0,0 +1,16 @@ +// Copyright 2021 Datafuse Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod show_variables_table; +pub use show_variables_table::ShowVariables; diff --git a/src/query/service/src/table_functions/show_variables/show_variables_table.rs b/src/query/service/src/table_functions/show_variables/show_variables_table.rs new file mode 100644 index 000000000000..2a7c66ce53bb --- /dev/null +++ b/src/query/service/src/table_functions/show_variables/show_variables_table.rs @@ -0,0 +1,183 @@ +// Copyright 2021 Datafuse Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::any::Any; +use std::sync::Arc; + +use databend_common_catalog::plan::DataSourcePlan; +use databend_common_catalog::plan::PartStatistics; +use databend_common_catalog::plan::Partitions; +use databend_common_catalog::plan::PushDownInfo; +use databend_common_catalog::table::Table; +use databend_common_catalog::table_args::TableArgs; +use databend_common_catalog::table_context::TableContext; +use databend_common_catalog::table_function::TableFunction; +use databend_common_exception::Result; +use databend_common_expression::types::StringType; +use databend_common_expression::DataBlock; +use databend_common_expression::FromData; +use databend_common_expression::TableDataType; +use databend_common_expression::TableField; +use databend_common_expression::TableSchema; +use databend_common_expression::TableSchemaRefExt; +use databend_common_meta_app::schema::TableIdent; +use databend_common_meta_app::schema::TableInfo; +use databend_common_meta_app::schema::TableMeta; +use databend_common_pipeline_core::processors::OutputPort; +use databend_common_pipeline_core::processors::ProcessorPtr; +use databend_common_pipeline_core::Pipeline; +use databend_common_pipeline_sources::AsyncSource; +use databend_common_pipeline_sources::AsyncSourcer; +use databend_common_sql::validate_function_arg; + +const SHOW_VARIABLES: &str = "show_variables"; + +pub struct ShowVariables { + table_info: TableInfo, +} + +// show variables +impl ShowVariables { + pub fn create( + database_name: &str, + table_func_name: &str, + table_id: u64, + table_args: TableArgs, + ) -> Result> { + let args = table_args.positioned; + // Check args len. + validate_function_arg(table_func_name, args.len(), None, 0)?; + + let table_info = TableInfo { + ident: TableIdent::new(table_id, 0), + desc: format!("'{}'.'{}'", database_name, table_func_name), + name: table_func_name.to_string(), + meta: TableMeta { + schema: Self::schema(), + engine: SHOW_VARIABLES.to_owned(), + ..Default::default() + }, + ..Default::default() + }; + + Ok(Arc::new(Self { table_info })) + } + + fn schema() -> Arc { + TableSchemaRefExt::create(vec![ + TableField::new("name", TableDataType::String), + TableField::new("value", TableDataType::String), + TableField::new("type", TableDataType::String), + ]) + } +} + +#[async_trait::async_trait] +impl Table for ShowVariables { + fn as_any(&self) -> &dyn Any { + self + } + + fn get_table_info(&self) -> &TableInfo { + &self.table_info + } + + #[async_backtrace::framed] + async fn read_partitions( + &self, + _ctx: Arc, + _push_downs: Option, + _dry_run: bool, + ) -> Result<(PartStatistics, Partitions)> { + Ok((PartStatistics::default(), Partitions::default())) + } + + fn table_args(&self) -> Option { + Some(TableArgs::new_positioned(vec![])) + } + + fn read_data( + &self, + ctx: Arc, + _plan: &DataSourcePlan, + pipeline: &mut Pipeline, + _put_cache: bool, + ) -> Result<()> { + pipeline.add_source(|output| ShowVariablesSource::create(ctx.clone(), output), 1)?; + + Ok(()) + } +} + +struct ShowVariablesSource { + ctx: Arc, + finished: bool, +} + +impl ShowVariablesSource { + pub fn create(ctx: Arc, output: Arc) -> Result { + AsyncSourcer::create(ctx.clone(), output, ShowVariablesSource { + ctx, + finished: false, + }) + } +} + +#[async_trait::async_trait] +impl AsyncSource for ShowVariablesSource { + const NAME: &'static str = "show_variables"; + + #[async_backtrace::framed] + async fn generate(&mut self) -> Result> { + if self.finished { + return Ok(None); + } + + let res = show_variables(self.ctx.clone()).await?; + + // Mark done. + self.finished = true; + Ok(res) + } +} + +async fn show_variables(ctx: Arc) -> Result> { + let var = ctx.get_all_variables(); + + let mut names = vec![]; + let mut vars = vec![]; + let mut types = vec![]; + for (name, var) in var { + names.push(name.to_string()); + vars.push(var.to_string()); + types.push(var.as_ref().infer_data_type().to_string()); + } + + Ok(Some(DataBlock::new_from_columns(vec![ + StringType::from_data(names), + StringType::from_data(vars), + StringType::from_data(types), + ]))) +} + +impl TableFunction for ShowVariables { + fn function_name(&self) -> &str { + self.name() + } + + fn as_table<'a>(self: Arc) -> Arc + where Self: 'a { + self + } +} diff --git a/src/query/service/src/table_functions/table_function_factory.rs b/src/query/service/src/table_functions/table_function_factory.rs index 7d406ea1c17a..d3cebd054754 100644 --- a/src/query/service/src/table_functions/table_function_factory.rs +++ b/src/query/service/src/table_functions/table_function_factory.rs @@ -49,6 +49,7 @@ use crate::table_functions::inspect_parquet::InspectParquetTable; use crate::table_functions::list_stage::ListStageTable; use crate::table_functions::numbers::NumbersTable; use crate::table_functions::show_grants::ShowGrants; +use crate::table_functions::show_variables::ShowVariables; use crate::table_functions::srf::RangeTable; use crate::table_functions::sync_crash_me::SyncCrashMeTable; use crate::table_functions::GPT2SQLTable; @@ -283,6 +284,11 @@ impl TableFunctionFactory { (next_id(), Arc::new(TaskHistoryTable::create)), ); + creators.insert( + "show_variables".to_string(), + (next_id(), Arc::new(ShowVariables::create)), + ); + TableFunctionFactory { creators: RwLock::new(creators), } diff --git a/src/query/sql/src/planner/binder/binder.rs b/src/query/sql/src/planner/binder/binder.rs index 5fefdc865120..477c27ff6d80 100644 --- a/src/query/sql/src/planner/binder/binder.rs +++ b/src/query/sql/src/planner/binder/binder.rs @@ -234,6 +234,7 @@ impl<'a> Binder { Statement::ShowProcessList { show_options } => self.bind_show_process_list(bind_context, show_options).await?, Statement::ShowEngines { show_options } => self.bind_show_engines(bind_context, show_options).await?, Statement::ShowSettings { show_options } => self.bind_show_settings(bind_context, show_options).await?, + Statement::ShowVariables { show_options } => self.bind_show_variables(bind_context, show_options).await?, Statement::ShowIndexes { show_options } => self.bind_show_indexes(bind_context, show_options).await?, Statement::ShowLocks(stmt) => self.bind_show_locks(bind_context, stmt).await?, // Catalogs diff --git a/src/query/sql/src/planner/binder/show.rs b/src/query/sql/src/planner/binder/show.rs index d3dedd2baa4b..824662eea3d6 100644 --- a/src/query/sql/src/planner/binder/show.rs +++ b/src/query/sql/src/planner/binder/show.rs @@ -89,6 +89,22 @@ impl Binder { .await } + #[async_backtrace::framed] + pub(in crate::planner::binder) async fn bind_show_variables( + &mut self, + bind_context: &mut BindContext, + show_options: &Option, + ) -> Result { + let (show_limit, limit_str) = get_show_options(show_options, None); + let query = format!( + "SELECT name, value, type FROM show_variables() {} ORDER BY name {}", + show_limit, limit_str, + ); + + self.bind_rewrite_to_query(bind_context, &query, RewriteKind::ShowVariables) + .await + } + #[async_backtrace::framed] pub(in crate::planner::binder) async fn bind_show_metrics( &mut self, diff --git a/src/query/sql/src/planner/plans/plan.rs b/src/query/sql/src/planner/plans/plan.rs index 517606039a60..8655d7f66d62 100644 --- a/src/query/sql/src/planner/plans/plan.rs +++ b/src/query/sql/src/planner/plans/plan.rs @@ -370,6 +370,7 @@ pub enum Plan { #[derive(Clone, Debug)] pub enum RewriteKind { ShowSettings, + ShowVariables, ShowMetrics, ShowProcessList, ShowEngines, diff --git a/tests/sqllogictests/suites/query/show_variables.test b/tests/sqllogictests/suites/query/show_variables.test new file mode 100644 index 000000000000..d55b427f2108 --- /dev/null +++ b/tests/sqllogictests/suites/query/show_variables.test @@ -0,0 +1,32 @@ +statement ok +set variable (a, b) = (select 3, 'x') + +onlyif http +query TTT +show variables +---- +a 3 UInt8 +b 'x' String + +onlyif http +query TTT +show variables where name like 'a' +---- +a 3 UInt8 + +onlyif http +query TTT +show variables where type = 'UInt8' +---- +a 3 UInt8 + +onlyif http +query TTT +show variables where value = '\'x\'' +---- +b 'x' String + +query TTT +select name, value, type from show_variables() where name='a'; +---- +a 3 UInt8