From 4cb711e0212b1012dae452d12c95b9d82281e957 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sun, 11 Aug 2024 10:33:28 +0800 Subject: [PATCH 01/51] create temporary table --- Cargo.lock | 30 +++--- Cargo.toml | 4 +- src/meta/app/src/schema/table.rs | 2 +- src/query/ast/src/ast/format/syntax/ddl.rs | 9 +- src/query/ast/src/ast/statements/table.rs | 17 +++- src/query/ast/src/parser/statement.rs | 12 ++- src/query/ast/src/parser/token.rs | 2 + src/query/catalog/Cargo.toml | 2 +- src/query/catalog/src/catalog/manager.rs | 22 ++--- .../catalog/src/catalog/session_catalog.rs | 26 ++++- src/query/catalog/src/table_context.rs | 7 +- src/query/service/Cargo.toml | 2 +- .../interpreter_catalog_create.rs | 2 +- .../src/interpreters/interpreter_txn_abort.rs | 2 +- .../src/interpreters/interpreter_txn_begin.rs | 2 +- .../interpreters/interpreter_txn_commit.rs | 2 +- .../builders/builder_insert_multi_table.rs | 2 +- .../src/servers/admin/v1/stream_status.rs | 3 +- .../src/servers/admin/v1/tenant_tables.rs | 3 +- .../flight_sql/flight_sql_service/catalog.rs | 4 +- .../servers/http/v1/query/execute_state.rs | 2 +- .../src/servers/http/v1/query/http_query.rs | 2 +- .../http/v1/query/http_query_manager.rs | 2 +- src/query/service/src/sessions/query_ctx.rs | 18 +++- .../service/src/sessions/query_ctx_shared.rs | 4 +- src/query/service/src/sessions/session.rs | 2 +- src/query/service/src/sessions/session_ctx.rs | 25 ++++- .../it/servers/http/http_query_handlers.rs | 2 +- .../tests/it/sql/exec/get_table_bind_test.rs | 2 +- .../tests/it/storages/fuse/conflict.rs | 2 +- .../it/storages/fuse/operations/commit.rs | 2 +- .../physical_plans/physical_table_scan.rs | 2 +- .../bind_table_function.rs | 2 +- src/query/sql/src/planner/binder/ddl/table.rs | 17 +++- src/query/sql/src/planner/binder/table.rs | 2 +- .../common/{txn => session}/Cargo.toml | 4 +- .../common/{txn => session}/src/lib.rs | 13 ++- .../common/session/src/session_state.rs | 34 +++++++ .../storages/common/session/src/temp_table.rs | 95 +++++++++++++++++++ .../manager.rs => session/src/transaction.rs} | 0 .../common/table_meta/src/table/table_keys.rs | 1 + src/query/storages/fuse/Cargo.toml | 2 +- .../storages/fuse/src/operations/analyze.rs | 2 +- .../common/generators/snapshot_generator.rs | 2 +- .../processors/multi_table_insert_commit.rs | 2 +- .../storages/system/src/catalogs_table.rs | 2 +- .../storages/system/src/databases_table.rs | 2 +- src/query/storages/system/src/locks_table.rs | 2 +- .../storages/system/src/streams_table.rs | 2 +- src/query/storages/system/src/tables_table.rs | 2 +- src/tests/sqlsmith/src/sql_gen/ddl.rs | 3 +- 51 files changed, 310 insertions(+), 99 deletions(-) rename src/query/storages/common/{txn => session}/Cargo.toml (73%) rename src/query/storages/common/{txn => session}/src/lib.rs (69%) create mode 100644 src/query/storages/common/session/src/session_state.rs create mode 100644 src/query/storages/common/session/src/temp_table.rs rename src/query/storages/common/{txn/src/manager.rs => session/src/transaction.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 47175f66265e..0421e91622f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3267,8 +3267,8 @@ dependencies = [ "databend-common-settings", "databend-common-storage", "databend-common-users", + "databend-storages-common-session", "databend-storages-common-table-meta", - "databend-storages-common-txn", "dyn-clone", "goldenfile", "log", @@ -4308,8 +4308,8 @@ dependencies = [ "databend-storages-common-index", "databend-storages-common-io", "databend-storages-common-pruner", + "databend-storages-common-session", "databend-storages-common-table-meta", - "databend-storages-common-txn", "enum-as-inner 0.5.1", "fastrace", "futures", @@ -5181,8 +5181,8 @@ dependencies = [ "databend-storages-common-cache-manager", "databend-storages-common-index", "databend-storages-common-io", + "databend-storages-common-session", "databend-storages-common-table-meta", - "databend-storages-common-txn", "derive-visitor", "ethnum", "fastrace", @@ -5429,6 +5429,19 @@ dependencies = [ "typetag", ] +[[package]] +name = "databend-storages-common-session" +version = "0.1.0" +dependencies = [ + "databend-common-exception", + "databend-common-meta-app", + "databend-common-meta-types", + "databend-storages-common-table-meta", + "parking_lot 0.12.1", + "serde", + "uuid", +] + [[package]] name = "databend-storages-common-stage" version = "0.1.0" @@ -5467,17 +5480,6 @@ dependencies = [ "zstd 0.12.4", ] -[[package]] -name = "databend-storages-common-txn" -version = "0.1.0" -dependencies = [ - "databend-common-meta-app", - "databend-common-meta-types", - "parking_lot 0.12.1", - "serde", - "uuid", -] - [[package]] name = "datafusion" version = "39.0.0" diff --git a/Cargo.toml b/Cargo.toml index 5e6139f28ad6..9644e2d9f8a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ members = [ "src/query/storages/common/io", "src/query/storages/common/pruner", "src/query/storages/common/stage", - "src/query/storages/common/txn", + "src/query/storages/common/session", "src/query/storages/common/table_meta", "src/query/storages/delta", "src/query/storages/factory", @@ -199,9 +199,9 @@ databend-storages-common-cache-manager = { path = "src/query/storages/common/cac databend-storages-common-index = { path = "src/query/storages/common/index" } databend-storages-common-io = { path = "src/query/storages/common/io" } databend-storages-common-pruner = { path = "src/query/storages/common/pruner" } +databend-storages-common-session = { path = "src/query/storages/common/session" } databend-storages-common-stage = { path = "src/query/storages/common/stage" } databend-storages-common-table-meta = { path = "src/query/storages/common/table_meta" } -databend-storages-common-txn = { path = "src/query/storages/common/txn" } # Crates.io dependencies anyerror = { version = "=0.1.10" } diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index c86ade3a60b9..fc47b7f9ac81 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -71,7 +71,7 @@ impl Display for TableIdent { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct TableNameIdent { pub tenant: Tenant, pub db_name: String, diff --git a/src/query/ast/src/ast/format/syntax/ddl.rs b/src/query/ast/src/ast/format/syntax/ddl.rs index 453935069e42..14029ad0eeec 100644 --- a/src/query/ast/src/ast/format/syntax/ddl.rs +++ b/src/query/ast/src/ast/format/syntax/ddl.rs @@ -31,6 +31,7 @@ use crate::ast::CreateStreamStmt; use crate::ast::CreateTableSource; use crate::ast::CreateTableStmt; use crate::ast::CreateViewStmt; +use crate::ast::TableType; use crate::ast::TimeTravelPoint; pub(crate) fn pretty_create_table(stmt: CreateTableStmt) -> RcDoc<'static> { @@ -40,10 +41,10 @@ pub(crate) fn pretty_create_table(stmt: CreateTableStmt) -> RcDoc<'static> { } else { RcDoc::nil() }) - .append(if stmt.transient { - RcDoc::space().append(RcDoc::text("TRANSIENT")) - } else { - RcDoc::nil() + .append(match stmt.table_type { + TableType::Transient => RcDoc::space().append(RcDoc::text("TRANSIENT")), + TableType::Temporary => RcDoc::space().append(RcDoc::text("TEMPORARY")), + TableType::Normal => RcDoc::nil(), }) .append(RcDoc::space().append(RcDoc::text("TABLE"))) .append(match stmt.create_option { diff --git a/src/query/ast/src/ast/statements/table.rs b/src/query/ast/src/ast/statements/table.rs index bbb78137076a..b63c0dd13374 100644 --- a/src/query/ast/src/ast/statements/table.rs +++ b/src/query/ast/src/ast/statements/table.rs @@ -140,7 +140,14 @@ pub struct CreateTableStmt { pub cluster_by: Vec, pub table_options: BTreeMap, pub as_query: Option>, - pub transient: bool, + pub table_type: TableType, +} + +#[derive(Debug, Clone, PartialEq, Drive, DriveMut)] +pub enum TableType { + Normal, + Transient, + Temporary, } impl Display for CreateTableStmt { @@ -149,9 +156,11 @@ impl Display for CreateTableStmt { if let CreateOption::CreateOrReplace = self.create_option { write!(f, "OR REPLACE ")?; } - if self.transient { - write!(f, "TRANSIENT ")?; - } + match self.table_type { + TableType::Normal => {} + TableType::Transient => write!(f, "TRANSIENT ")?, + TableType::Temporary => write!(f, "TEMPORARY ")?, + }; write!(f, "TABLE ")?; if let CreateOption::CreateIfNotExists = self.create_option { write!(f, "IF NOT EXISTS ")?; diff --git a/src/query/ast/src/parser/statement.rs b/src/query/ast/src/parser/statement.rs index 75960652d2b3..7b2d449fc358 100644 --- a/src/query/ast/src/parser/statement.rs +++ b/src/query/ast/src/parser/statement.rs @@ -697,7 +697,7 @@ pub fn statement_body(i: Input) -> IResult { ); let create_table = map_res( rule! { - CREATE ~ ( OR ~ ^REPLACE )? ~ TRANSIENT? ~ TABLE ~ ( IF ~ ^NOT ~ ^EXISTS )? + CREATE ~ ( OR ~ ^REPLACE )? ~ (TEMP| TEMPORARY|TRANSIENT)? ~ TABLE ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ #dot_separated_idents_1_to_3 ~ #create_table_source? ~ ( #engine )? @@ -709,7 +709,7 @@ pub fn statement_body(i: Input) -> IResult { |( _, opt_or_replace, - opt_transient, + opt_type, _, opt_if_not_exists, (catalog, database, table), @@ -722,6 +722,12 @@ pub fn statement_body(i: Input) -> IResult { )| { let create_option = parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?; + let table_type = match opt_type.map(|t| t.kind) { + None => TableType::Normal, + Some(TRANSIENT) => TableType::Transient, + Some(TEMP) | Some(TEMPORARY) => TableType::Temporary, + _ => unreachable!(), + }; Ok(Statement::CreateTable(CreateTableStmt { create_option, catalog, @@ -735,7 +741,7 @@ pub fn statement_body(i: Input) -> IResult { .unwrap_or_default(), table_options: opt_table_options.unwrap_or_default(), as_query: opt_as_query.map(|(_, query)| Box::new(query)), - transient: opt_transient.is_some(), + table_type, })) }, ); diff --git a/src/query/ast/src/parser/token.rs b/src/query/ast/src/parser/token.rs index 5d154f98a6d4..cebf228c57b2 100644 --- a/src/query/ast/src/parser/token.rs +++ b/src/query/ast/src/parser/token.rs @@ -1300,6 +1300,8 @@ pub enum TokenKind { ROLLBACK, #[token("TEMPORARY", ignore(ascii_case))] TEMPORARY, + #[token("TEMP", ignore(ascii_case))] + TEMP, #[token("SECONDS", ignore(ascii_case))] SECONDS, #[token("DAYS", ignore(ascii_case))] diff --git a/src/query/catalog/Cargo.toml b/src/query/catalog/Cargo.toml index 8450fbc41ee2..de54950c3719 100644 --- a/src/query/catalog/Cargo.toml +++ b/src/query/catalog/Cargo.toml @@ -31,7 +31,7 @@ databend-common-settings = { workspace = true } databend-common-storage = { workspace = true } databend-common-users = { workspace = true } databend-storages-common-table-meta = { workspace = true } -databend-storages-common-txn = { workspace = true } +databend-storages-common-session = { workspace = true } dyn-clone = "1.0.9" log = { workspace = true } parking_lot = { workspace = true } diff --git a/src/query/catalog/src/catalog/manager.rs b/src/query/catalog/src/catalog/manager.rs index 6dd8f56c4536..a76624ef860b 100644 --- a/src/query/catalog/src/catalog/manager.rs +++ b/src/query/catalog/src/catalog/manager.rs @@ -37,7 +37,7 @@ use databend_common_meta_app::tenant::Tenant; use databend_common_meta_store::MetaStore; use databend_common_meta_store::MetaStoreProvider; use databend_common_meta_types::anyerror::func_name; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::SessionState; use super::Catalog; use super::CatalogCreator; @@ -132,10 +132,10 @@ impl CatalogManager { /// /// There are some place that we don't have async context, so we provide /// `get_default_catalog` to allow users fetch default catalog without async. - pub fn get_default_catalog(&self, txn_mgr: TxnManagerRef) -> Result> { + pub fn get_default_catalog(&self, session_state: SessionState) -> Result> { Ok(Arc::new(SessionCatalog::create( self.default_catalog.clone(), - txn_mgr, + session_state, ))) } @@ -143,12 +143,12 @@ impl CatalogManager { pub fn build_catalog( &self, info: Arc, - txn_mgr: TxnManagerRef, + session_state: SessionState, ) -> Result> { let typ = info.meta.catalog_option.catalog_type(); if typ == CatalogType::Default { - return self.get_default_catalog(txn_mgr); + return self.get_default_catalog(session_state); } let creator = self @@ -171,10 +171,10 @@ impl CatalogManager { // TODO: use Tenant or NonEmptyString tenant: &str, catalog_name: &str, - txn_mgr: TxnManagerRef, + session_state: SessionState, ) -> Result> { if catalog_name == CATALOG_DEFAULT { - return self.get_default_catalog(txn_mgr); + return self.get_default_catalog(session_state); } if let Some(ctl) = self.external_catalogs.get(catalog_name) { @@ -187,7 +187,7 @@ impl CatalogManager { // Get catalog from metasrv. let info = self.meta.get_catalog(GetCatalogReq::new(ident)).await?; - self.build_catalog(info, txn_mgr) + self.build_catalog(info, session_state) } /// Create a new catalog. @@ -244,9 +244,9 @@ impl CatalogManager { pub async fn list_catalogs( &self, tenant: &Tenant, - txn_mgr: TxnManagerRef, + session_state: SessionState, ) -> Result>> { - let mut catalogs = vec![self.get_default_catalog(txn_mgr.clone())?]; + let mut catalogs = vec![self.get_default_catalog(session_state.clone())?]; // insert external catalogs. for ctl in self.external_catalogs.values() { @@ -260,7 +260,7 @@ impl CatalogManager { .await?; for info in infos { - catalogs.push(self.build_catalog(info, txn_mgr.clone())?); + catalogs.push(self.build_catalog(info, session_state.clone())?); } Ok(catalogs) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 7814464e1091..7be39ef2cddb 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -16,6 +16,7 @@ use std::any::Any; use std::fmt::Debug; use std::sync::Arc; +use databend_common_arrow::parquet::read; use databend_common_exception::Result; use databend_common_meta_app::schema::CatalogInfo; use databend_common_meta_app::schema::CommitTableMetaReply; @@ -95,8 +96,11 @@ use databend_common_meta_app::schema::VirtualColumnMeta; use databend_common_meta_app::tenant::Tenant; use databend_common_meta_types::MetaId; use databend_common_meta_types::SeqV; -use databend_storages_common_txn::TxnManagerRef; -use databend_storages_common_txn::TxnState; +use databend_storages_common_session::SessionState; +use databend_storages_common_session::TempTblMgrRef; +use databend_storages_common_session::TxnManagerRef; +use databend_storages_common_session::TxnState; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use crate::catalog::Catalog; use crate::catalog::StorageDescription; @@ -109,11 +113,20 @@ use crate::table_function::TableFunction; pub struct SessionCatalog { inner: Arc, txn_mgr: TxnManagerRef, + temp_tbl_mgr: TempTblMgrRef, } impl SessionCatalog { - pub fn create(inner: Arc, txn_mgr: TxnManagerRef) -> Self { - SessionCatalog { inner, txn_mgr } + pub fn create(inner: Arc, session_state: SessionState) -> Self { + let SessionState { + txn_mgr, + temp_tbl_mgr, + } = session_state; + SessionCatalog { + inner, + txn_mgr, + temp_tbl_mgr, + } } } @@ -326,7 +339,10 @@ impl Catalog for SessionCatalog { } async fn create_table(&self, req: CreateTableReq) -> Result { - self.inner.create_table(req).await + match req.table_meta.options.get(OPT_KEY_TEMP_PREFIX) { + Some(_) => self.temp_tbl_mgr.lock().create_table(req), + None => self.inner.create_table(req).await, + } } async fn drop_table_by_id(&self, req: DropTableByIdReq) -> Result { diff --git a/src/query/catalog/src/table_context.rs b/src/query/catalog/src/table_context.rs index 44b62b3d235d..2f03eeeb95ca 100644 --- a/src/query/catalog/src/table_context.rs +++ b/src/query/catalog/src/table_context.rs @@ -58,9 +58,10 @@ use databend_common_storage::StageFileInfo; use databend_common_storage::StageFilesInfo; use databend_common_storage::StorageMetrics; use databend_common_users::GrantObjectVisibilityChecker; +use databend_storages_common_session::SessionState; +use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_txn::TxnManagerRef; use parking_lot::Mutex; use parking_lot::RwLock; use xorf::BinaryFuse16; @@ -360,4 +361,8 @@ pub trait TableContext: Send + Sync { tbl_name: &str, lock_opt: &LockTableOption, ) -> Result>>; + + fn get_session_id(&self) -> String; + + fn session_state(&self) -> SessionState; } diff --git a/src/query/service/Cargo.toml b/src/query/service/Cargo.toml index 3fcbce1ddd0e..603d62e89f80 100644 --- a/src/query/service/Cargo.toml +++ b/src/query/service/Cargo.toml @@ -116,8 +116,8 @@ databend-storages-common-cache = { workspace = true } databend-storages-common-cache-manager = { workspace = true } databend-storages-common-index = { workspace = true } databend-storages-common-io = { workspace = true } +databend-storages-common-session = { workspace = true } databend-storages-common-table-meta = { workspace = true } -databend-storages-common-txn = { workspace = true } derive-visitor = { workspace = true } ethnum = { workspace = true } fastrace = { workspace = true } diff --git a/src/query/service/src/interpreters/interpreter_catalog_create.rs b/src/query/service/src/interpreters/interpreter_catalog_create.rs index 0fc13d70474d..cd330d9c9849 100644 --- a/src/query/service/src/interpreters/interpreter_catalog_create.rs +++ b/src/query/service/src/interpreters/interpreter_catalog_create.rs @@ -115,7 +115,7 @@ impl Interpreter for CreateCatalogInterpreter { }, }; let ctl = catalog_manager - .build_catalog(Arc::new(ctl_info), self.ctx.txn_mgr()) + .build_catalog(Arc::new(ctl_info), self.ctx.session_state()) .map_err(|err| err.add_message("Error creating catalog."))?; // list databases to check if the catalog is valid. diff --git a/src/query/service/src/interpreters/interpreter_txn_abort.rs b/src/query/service/src/interpreters/interpreter_txn_abort.rs index 6f183bf6a9d3..5066b69eaa94 100644 --- a/src/query/service/src/interpreters/interpreter_txn_abort.rs +++ b/src/query/service/src/interpreters/interpreter_txn_abort.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use databend_common_exception::Result; use databend_common_storages_fuse::TableContext; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use crate::interpreters::Interpreter; use crate::pipelines::PipelineBuildResult; diff --git a/src/query/service/src/interpreters/interpreter_txn_begin.rs b/src/query/service/src/interpreters/interpreter_txn_begin.rs index 2a27a9d6b0e7..2eca0dca0f82 100644 --- a/src/query/service/src/interpreters/interpreter_txn_begin.rs +++ b/src/query/service/src/interpreters/interpreter_txn_begin.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use databend_common_exception::Result; use databend_common_storages_fuse::TableContext; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use crate::interpreters::Interpreter; use crate::pipelines::PipelineBuildResult; diff --git a/src/query/service/src/interpreters/interpreter_txn_commit.rs b/src/query/service/src/interpreters/interpreter_txn_commit.rs index d943f3906d63..175c72f656e7 100644 --- a/src/query/service/src/interpreters/interpreter_txn_commit.rs +++ b/src/query/service/src/interpreters/interpreter_txn_commit.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use databend_common_exception::ErrorCode; use databend_common_exception::Result; use databend_common_storages_fuse::TableContext; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use log::error; use log::info; diff --git a/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs b/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs index 20b521ac7fbd..f67b236debe0 100644 --- a/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs +++ b/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs @@ -289,7 +289,7 @@ impl PipelineBuilder { .add_transforms_by_chunk(mutation_aggregator_builders)?; self.main_pipeline.try_resize(1)?; let catalog = CatalogManager::instance() - .build_catalog(targets[0].target_catalog_info.clone(), self.ctx.txn_mgr())?; + .build_catalog(targets[0].target_catalog_info.clone(), self.ctx.session_state())?; self.main_pipeline.add_sink(|input| { Ok(ProcessorPtr::create(AsyncSinker::create( input, diff --git a/src/query/service/src/servers/admin/v1/stream_status.rs b/src/query/service/src/servers/admin/v1/stream_status.rs index c00865a0df77..0d24d78931b1 100644 --- a/src/query/service/src/servers/admin/v1/stream_status.rs +++ b/src/query/service/src/servers/admin/v1/stream_status.rs @@ -18,7 +18,6 @@ use databend_common_meta_app::app_error::AppError; use databend_common_meta_app::app_error::UnknownTableId; use databend_common_meta_app::tenant::Tenant; use databend_common_storages_stream::stream_table::StreamTable; -use databend_storages_common_txn::TxnManager; use fastrace::func_name; use log::debug; use poem::web::Json; @@ -45,7 +44,7 @@ async fn check_stream_status( tenant: &Tenant, params: Query, ) -> Result { - let catalog = CatalogManager::instance().get_default_catalog(TxnManager::init())?; + let catalog = CatalogManager::instance().get_default_catalog(Default::default())?; let db_name = params.database.clone().unwrap_or("default".to_string()); let tbl = catalog .get_table(tenant, &db_name, ¶ms.stream_name) diff --git a/src/query/service/src/servers/admin/v1/tenant_tables.rs b/src/query/service/src/servers/admin/v1/tenant_tables.rs index 33f70a04c22f..89950e15975c 100644 --- a/src/query/service/src/servers/admin/v1/tenant_tables.rs +++ b/src/query/service/src/servers/admin/v1/tenant_tables.rs @@ -19,7 +19,6 @@ use databend_common_catalog::catalog::CatalogManager; use databend_common_config::GlobalConfig; use databend_common_exception::Result; use databend_common_meta_app::tenant::Tenant; -use databend_storages_common_txn::TxnManager; use fastrace::func_name; use poem::web::Json; use poem::web::Path; @@ -54,7 +53,7 @@ pub struct TenantTableInfo { } async fn load_tenant_tables(tenant: &Tenant) -> Result { - let catalog = CatalogManager::instance().get_default_catalog(TxnManager::init())?; + let catalog = CatalogManager::instance().get_default_catalog(Default::default())?; let databases = catalog.list_databases(tenant).await?; diff --git a/src/query/service/src/servers/flight_sql/flight_sql_service/catalog.rs b/src/query/service/src/servers/flight_sql/flight_sql_service/catalog.rs index 2ae956f3f18d..665a64b70b2d 100644 --- a/src/query/service/src/servers/flight_sql/flight_sql_service/catalog.rs +++ b/src/query/service/src/servers/flight_sql/flight_sql_service/catalog.rs @@ -57,12 +57,12 @@ impl CatalogInfoProvider { vec![( catalog_name.clone(), catalog_mgr - .get_catalog(tenant.tenant_name(), &catalog_name, ctx.txn_mgr()) + .get_catalog(tenant.tenant_name(), &catalog_name, ctx.session_state()) .await?, )] } else { catalog_mgr - .list_catalogs(&tenant, ctx.txn_mgr()) + .list_catalogs(&tenant, ctx.session_state()) .await? .iter() .map(|r| (r.name(), r.clone())) diff --git a/src/query/service/src/servers/http/v1/query/execute_state.rs b/src/query/service/src/servers/http/v1/query/execute_state.rs index 6d0e89d9deb5..80ea2a79c9c7 100644 --- a/src/query/service/src/servers/http/v1/query/execute_state.rs +++ b/src/query/service/src/servers/http/v1/query/execute_state.rs @@ -24,7 +24,7 @@ use databend_common_expression::DataBlock; use databend_common_expression::DataSchemaRef; use databend_common_io::prelude::FormatSettings; use databend_common_settings::Settings; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use futures::StreamExt; use log::debug; use log::error; diff --git a/src/query/service/src/servers/http/v1/query/http_query.rs b/src/query/service/src/servers/http/v1/query/http_query.rs index c96037c97098..1a85bf1e8c97 100644 --- a/src/query/service/src/servers/http/v1/query/http_query.rs +++ b/src/query/service/src/servers/http/v1/query/http_query.rs @@ -33,7 +33,7 @@ use databend_common_exception::Result; use databend_common_io::prelude::FormatSettings; use databend_common_metrics::http::metrics_incr_http_response_errors_count; use databend_common_settings::ScopeLevel; -use databend_storages_common_txn::TxnState; +use databend_storages_common_session::TxnState; use fastrace::prelude::*; use log::info; use log::warn; diff --git a/src/query/service/src/servers/http/v1/query/http_query_manager.rs b/src/query/service/src/servers/http/v1/query/http_query_manager.rs index b13a998ecb65..fb39a4f8b5a0 100644 --- a/src/query/service/src/servers/http/v1/query/http_query_manager.rs +++ b/src/query/service/src/servers/http/v1/query/http_query_manager.rs @@ -29,7 +29,7 @@ use databend_common_base::runtime::TrySpawn; use databend_common_config::InnerConfig; use databend_common_exception::ErrorCode; use databend_common_exception::Result; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use parking_lot::Mutex; use tokio::task; diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index 35a1195fed97..b793de479ea4 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -11,7 +11,6 @@ // 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::cmp::min; use std::collections::hash_map::Entry; @@ -105,9 +104,10 @@ use databend_common_storages_result_cache::ResultScan; use databend_common_storages_stage::StageTable; use databend_common_users::GrantObjectVisibilityChecker; use databend_common_users::UserApiProvider; +use databend_storages_common_session::SessionState; +use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_txn::TxnManagerRef; use log::debug; use log::info; use parking_lot::Mutex; @@ -183,7 +183,7 @@ impl QueryContext { let catalog = self .shared .catalog_manager - .build_catalog(table_info.catalog_info.clone(), self.txn_mgr())?; + .build_catalog(table_info.catalog_info.clone(), self.session_state())?; match table_args { None => { let table = catalog.get_table_by_info(table_info); @@ -585,7 +585,7 @@ impl TableContext for QueryContext { .get_catalog( self.get_tenant().tenant_name(), catalog_name.as_ref(), - self.txn_mgr(), + self.session_state(), ) .await } @@ -593,7 +593,7 @@ impl TableContext for QueryContext { fn get_default_catalog(&self) -> Result> { self.shared .catalog_manager - .get_default_catalog(self.txn_mgr()) + .get_default_catalog(self.session_state()) } fn get_id(&self) -> String { @@ -1143,6 +1143,10 @@ impl TableContext for QueryContext { self.shared.session.session_ctx.txn_mgr() } + fn session_state(&self) -> SessionState { + self.shared.session.session_ctx.session_state() + } + fn get_read_block_thresholds(&self) -> BlockThresholds { *self.block_threshold.read() } @@ -1320,6 +1324,10 @@ impl TableContext for QueryContext { LockTableOption::NoLock => Ok(None), } } + + fn get_session_id(&self) -> String { + todo!() + } } impl TrySpawn for QueryContext { diff --git a/src/query/service/src/sessions/query_ctx_shared.rs b/src/query/service/src/sessions/query_ctx_shared.rs index 87aa3f043eca..3144099b96e2 100644 --- a/src/query/service/src/sessions/query_ctx_shared.rs +++ b/src/query/service/src/sessions/query_ctx_shared.rs @@ -356,7 +356,7 @@ impl QueryContextShared { .get_catalog( tenant.tenant_name(), catalog_name, - self.session.session_ctx.txn_mgr(), + self.session.session_ctx.session_state(), ) .await?; let cache_table = catalog.get_table(&tenant, database, table).await?; @@ -386,7 +386,7 @@ impl QueryContextShared { .get_catalog( tenant.tenant_name(), catalog_name, - self.session.session_ctx.txn_mgr(), + self.session.session_ctx.session_state(), ) .await?; diff --git a/src/query/service/src/sessions/session.rs b/src/query/service/src/sessions/session.rs index 78574c029ab1..50b6a64051f4 100644 --- a/src/query/service/src/sessions/session.rs +++ b/src/query/service/src/sessions/session.rs @@ -30,7 +30,7 @@ use databend_common_meta_app::tenant::Tenant; use databend_common_pipeline_core::PlanProfile; use databend_common_settings::Settings; use databend_common_users::GrantObjectVisibilityChecker; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use log::debug; use parking_lot::RwLock; diff --git a/src/query/service/src/sessions/session_ctx.rs b/src/query/service/src/sessions/session_ctx.rs index a6423a51d1a4..38eca3387ae9 100644 --- a/src/query/service/src/sessions/session_ctx.rs +++ b/src/query/service/src/sessions/session_ctx.rs @@ -11,7 +11,6 @@ // 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::collections::HashMap; use std::collections::HashSet; use std::sync::atomic::AtomicBool; @@ -26,8 +25,11 @@ use databend_common_meta_app::principal::RoleInfo; use databend_common_meta_app::principal::UserInfo; use databend_common_meta_app::tenant::Tenant; use databend_common_settings::Settings; -use databend_storages_common_txn::TxnManager; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::SessionState; +use databend_storages_common_session::TempTblMgr; +use databend_storages_common_session::TempTblMgrRef; +use databend_storages_common_session::TxnManager; +use databend_storages_common_session::TxnManagerRef; use parking_lot::Mutex; use parking_lot::RwLock; @@ -73,6 +75,7 @@ pub struct SessionContext { variables: Arc>>, typ: SessionType, txn_mgr: Mutex, + temp_tbl_mgr: Mutex, } impl SessionContext { @@ -94,6 +97,7 @@ impl SessionContext { variables: Default::default(), typ, txn_mgr: Mutex::new(TxnManager::init()), + temp_tbl_mgr: Mutex::new(TempTblMgr::init()), }) } @@ -301,10 +305,18 @@ impl SessionContext { self.txn_mgr.lock().clone() } + pub fn temp_tbl_mgr(&self) -> TempTblMgrRef { + self.temp_tbl_mgr.lock().clone() + } + pub fn set_txn_mgr(&self, txn_mgr: TxnManagerRef) { *self.txn_mgr.lock() = txn_mgr; } + pub fn set_temp_tbl_mgr(&self, temp_tbl_mgr: TempTblMgrRef) { + *self.temp_tbl_mgr.lock() = temp_tbl_mgr; + } + pub fn set_variable(&self, key: String, value: Scalar) { self.variables.write().insert(key, value); } @@ -316,4 +328,11 @@ impl SessionContext { pub fn get_variable(&self, key: &str) -> Option { self.variables.read().get(key).cloned() } + + pub fn session_state(&self) -> SessionState { + SessionState { + txn_mgr: self.txn_mgr(), + temp_tbl_mgr: self.temp_tbl_mgr(), + } + } } diff --git a/src/query/service/tests/it/servers/http/http_query_handlers.rs b/src/query/service/tests/it/servers/http/http_query_handlers.rs index 41ad547b16c5..bd862bb632ee 100644 --- a/src/query/service/tests/it/servers/http/http_query_handlers.rs +++ b/src/query/service/tests/it/servers/http/http_query_handlers.rs @@ -43,7 +43,7 @@ use databend_query::servers::HttpHandlerKind; use databend_query::sessions::QueryAffect; use databend_query::test_kits::ConfigBuilder; use databend_query::test_kits::TestFixture; -use databend_storages_common_txn::TxnState; +use databend_storages_common_session::TxnState; use futures_util::future::try_join_all; use headers::Header; use headers::HeaderMapExt; diff --git a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs index 759f6918261d..a24ca0e9f1d6 100644 --- a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs +++ b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs @@ -142,7 +142,7 @@ use databend_query::sessions::QueryContext; use databend_query::test_kits::*; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use parking_lot::Mutex; use parking_lot::RwLock; use xorf::BinaryFuse16; diff --git a/src/query/service/tests/it/storages/fuse/conflict.rs b/src/query/service/tests/it/storages/fuse/conflict.rs index 71394c28d2ce..86fa1c674ed6 100644 --- a/src/query/service/tests/it/storages/fuse/conflict.rs +++ b/src/query/service/tests/it/storages/fuse/conflict.rs @@ -24,7 +24,7 @@ use databend_common_storages_fuse::operations::SnapshotChanges; use databend_common_storages_fuse::operations::SnapshotGenerator; use databend_storages_common_table_meta::meta::Statistics; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_txn::TxnManager; +use databend_storages_common_session::TxnManager; #[test] /// base snapshot contains segments 1, 2, 3, diff --git a/src/query/service/tests/it/storages/fuse/operations/commit.rs b/src/query/service/tests/it/storages/fuse/operations/commit.rs index e138d5755c9c..cdaa9151b26b 100644 --- a/src/query/service/tests/it/storages/fuse/operations/commit.rs +++ b/src/query/service/tests/it/storages/fuse/operations/commit.rs @@ -147,7 +147,7 @@ use databend_storages_common_table_meta::meta::SegmentInfo; use databend_storages_common_table_meta::meta::Statistics; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::meta::Versioned; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use futures::TryStreamExt; use parking_lot::Mutex; use parking_lot::RwLock; diff --git a/src/query/sql/src/executor/physical_plans/physical_table_scan.rs b/src/query/sql/src/executor/physical_plans/physical_table_scan.rs index dbdc440bf7e8..7db134f63ac1 100644 --- a/src/query/sql/src/executor/physical_plans/physical_table_scan.rs +++ b/src/query/sql/src/executor/physical_plans/physical_table_scan.rs @@ -278,7 +278,7 @@ impl PhysicalPlanBuilder { pub(crate) async fn build_dummy_table_scan(&mut self) -> Result { let catalogs = CatalogManager::instance(); let table = catalogs - .get_default_catalog(self.ctx.txn_mgr())? + .get_default_catalog(self.ctx.session_state())? .get_table(&self.ctx.get_tenant(), "system", "one") .await?; diff --git a/src/query/sql/src/planner/binder/bind_table_reference/bind_table_function.rs b/src/query/sql/src/planner/binder/bind_table_reference/bind_table_function.rs index 9e506f14e60c..6ff2bac8abbd 100644 --- a/src/query/sql/src/planner/binder/bind_table_reference/bind_table_function.rs +++ b/src/query/sql/src/planner/binder/bind_table_reference/bind_table_function.rs @@ -132,7 +132,7 @@ impl Binder { // Other table functions always reside is default catalog let table_meta: Arc = self .catalogs - .get_default_catalog(self.ctx.txn_mgr())? + .get_default_catalog(self.ctx.session_state())? .get_table_function(&func_name.name, table_args)?; let table = table_meta.as_table(); let table_alias_name = if let Some(table_alias) = alias { diff --git a/src/query/sql/src/planner/binder/ddl/table.rs b/src/query/sql/src/planner/binder/ddl/table.rs index 3aa3eccf2cf5..88d650840128 100644 --- a/src/query/sql/src/planner/binder/ddl/table.rs +++ b/src/query/sql/src/planner/binder/ddl/table.rs @@ -44,6 +44,7 @@ use databend_common_ast::ast::ShowTablesStatusStmt; use databend_common_ast::ast::ShowTablesStmt; use databend_common_ast::ast::Statement; use databend_common_ast::ast::TableReference; +use databend_common_ast::ast::TableType; use databend_common_ast::ast::TruncateTableStmt; use databend_common_ast::ast::TypeName; use databend_common_ast::ast::UndropTableStmt; @@ -86,6 +87,7 @@ use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_FORMAT; use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_PREFIX; use databend_storages_common_table_meta::table::OPT_KEY_TABLE_ATTACHED_DATA_URI; use databend_storages_common_table_meta::table::OPT_KEY_TABLE_COMPRESSION; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use derive_visitor::DriveMut; use log::debug; @@ -419,7 +421,7 @@ impl Binder { table_options, cluster_by, as_query, - transient, + table_type, engine, uri_location, } = stmt; @@ -474,10 +476,15 @@ impl Binder { _ => (None, "".to_string()), }; - // If table is TRANSIENT, set a flag in table option - if *transient { - options.insert("TRANSIENT".to_owned(), "T".to_owned()); - } + match table_type { + TableType::Normal => {} + TableType::Transient => { + let _ = options.insert("TRANSIENT".to_owned(), "T".to_owned()); + } + TableType::Temporary => { + let _ = options.insert(OPT_KEY_TEMP_PREFIX.to_string(), self.ctx.get_session_id()); + } + }; // todo(geometry): remove this when geometry stable. if let Some(CreateTableSource::Columns(cols, _)) = &source { diff --git a/src/query/sql/src/planner/binder/table.rs b/src/query/sql/src/planner/binder/table.rs index 32ce35b6a987..2a07d428267c 100644 --- a/src/query/sql/src/planner/binder/table.rs +++ b/src/query/sql/src/planner/binder/table.rs @@ -677,7 +677,7 @@ impl Binder { ) -> Result> { let catalog = self .catalogs - .get_catalog(tenant.tenant_name(), catalog_name, self.ctx.txn_mgr()) + .get_catalog(tenant.tenant_name(), catalog_name, self.ctx.session_state()) .await?; let index_metas = catalog .list_indexes(ListIndexesReq::new(tenant, Some(table_id))) diff --git a/src/query/storages/common/txn/Cargo.toml b/src/query/storages/common/session/Cargo.toml similarity index 73% rename from src/query/storages/common/txn/Cargo.toml rename to src/query/storages/common/session/Cargo.toml index 85177ff5bdad..ceadf5bd0476 100644 --- a/src/query/storages/common/txn/Cargo.toml +++ b/src/query/storages/common/session/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "databend-storages-common-txn" +name = "databend-storages-common-session" version = { workspace = true } authors = { workspace = true } license = { workspace = true } @@ -7,8 +7,10 @@ publish = { workspace = true } edition = { workspace = true } [dependencies] +databend-common-exception = { workspace = true } databend-common-meta-app = { workspace = true } databend-common-meta-types = { workspace = true } +databend-storages-common-table-meta = { workspace = true } parking_lot = { workspace = true } serde = { version = "1.0.194", features = ["derive"] } uuid = { workspace = true } diff --git a/src/query/storages/common/txn/src/lib.rs b/src/query/storages/common/session/src/lib.rs similarity index 69% rename from src/query/storages/common/txn/src/lib.rs rename to src/query/storages/common/session/src/lib.rs index 304e5c273c6f..d731b190a2e2 100644 --- a/src/query/storages/common/txn/src/lib.rs +++ b/src/query/storages/common/session/src/lib.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod manager; -pub use manager::TxnManager; -pub use manager::TxnManagerRef; -pub use manager::TxnState; +mod temp_table; +mod transaction; +pub use temp_table::TempTblMgr; +pub use temp_table::TempTblMgrRef; +pub use transaction::TxnManager; +pub use transaction::TxnManagerRef; +pub use transaction::TxnState; +mod session_state; +pub use session_state::SessionState; diff --git a/src/query/storages/common/session/src/session_state.rs b/src/query/storages/common/session/src/session_state.rs new file mode 100644 index 000000000000..13b9884910e3 --- /dev/null +++ b/src/query/storages/common/session/src/session_state.rs @@ -0,0 +1,34 @@ +// 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 crate::TempTblMgr; +use crate::TempTblMgrRef; +use crate::TxnManager; +use crate::TxnManagerRef; + + +#[derive(Clone, Debug)] +pub struct SessionState { + pub txn_mgr: TxnManagerRef, + pub temp_tbl_mgr: TempTblMgrRef, +} + +impl Default for SessionState { + fn default() -> Self { + SessionState { + txn_mgr: TxnManager::init(), + temp_tbl_mgr: TempTblMgr::init(), + } + } +} diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs new file mode 100644 index 000000000000..b1d4295a6be5 --- /dev/null +++ b/src/query/storages/common/session/src/temp_table.rs @@ -0,0 +1,95 @@ +// 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::collections::hash_map::Entry; +use std::collections::HashMap; +use std::sync::Arc; + +use databend_common_exception::ErrorCode; +use databend_common_exception::Result; +use databend_common_meta_app::schema::CreateOption; +use databend_common_meta_app::schema::CreateTableReply; +use databend_common_meta_app::schema::CreateTableReq; +use databend_common_meta_app::schema::TableMeta; +use databend_common_meta_app::schema::TableNameIdent; +use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; +use parking_lot::Mutex; +#[derive(Debug, Clone)] +pub struct TempTblMgr { + name_to_id: HashMap, + id_to_meta: HashMap, + next_id: u64, +} + +impl TempTblMgr { + pub fn init() -> Arc> { + Arc::new(Mutex::new(TempTblMgr { + name_to_id: HashMap::new(), + id_to_meta: HashMap::new(), + next_id: 0, + })) + } + + pub fn create_table(&mut self, req: CreateTableReq) -> Result { + let CreateTableReq { + create_option, + name_ident, + table_meta, + as_dropped: _, + } = req; + let Some(db_id) = table_meta.options.get(OPT_KEY_DATABASE_ID) else { + return Err(ErrorCode::Internal(format!( + "Database id not set in table options" + ))); + }; + let db_id = db_id.parse::()?; + let table_id = match (self.name_to_id.entry(name_ident.clone()), create_option) { + (Entry::Occupied(_), CreateOption::Create) => { + return Err(ErrorCode::TableAlreadyExists(format!( + "Temporary table {} already exists", + name_ident + ))); + } + (Entry::Occupied(mut e), CreateOption::CreateOrReplace) => { + let table_id = self.next_id; + e.insert(table_id); + self.id_to_meta.insert(table_id, table_meta); + self.next_id += 1; + table_id + } + (Entry::Occupied(e), CreateOption::CreateIfNotExists) => { + let table_id = *e.get(); + table_id + } + (Entry::Vacant(e), _) => { + let table_id = self.next_id; + e.insert(table_id); + self.id_to_meta.insert(table_id, table_meta); + self.next_id += 1; + table_id + } + }; + Ok(CreateTableReply { + table_id, + table_id_seq: None, + db_id, + new_table: true, + spec_vec: None, + prev_table_id: None, + orphan_table_name: None, + }) + } +} + +pub type TempTblMgrRef = Arc>; diff --git a/src/query/storages/common/txn/src/manager.rs b/src/query/storages/common/session/src/transaction.rs similarity index 100% rename from src/query/storages/common/txn/src/manager.rs rename to src/query/storages/common/session/src/transaction.rs diff --git a/src/query/storages/common/table_meta/src/table/table_keys.rs b/src/query/storages/common/table_meta/src/table/table_keys.rs index 60d25545016d..d7726d13fce6 100644 --- a/src/query/storages/common/table_meta/src/table/table_keys.rs +++ b/src/query/storages/common/table_meta/src/table/table_keys.rs @@ -16,6 +16,7 @@ use std::collections::HashSet; use std::sync::LazyLock; pub const OPT_KEY_DATABASE_ID: &str = "database_id"; pub const OPT_KEY_STORAGE_PREFIX: &str = "storage_prefix"; +pub const OPT_KEY_TEMP_PREFIX: &str = "temp_prefix"; pub const OPT_KEY_SNAPSHOT_LOCATION: &str = "snapshot_location"; pub const OPT_KEY_STORAGE_FORMAT: &str = "storage_format"; pub const OPT_KEY_TABLE_COMPRESSION: &str = "compression"; diff --git a/src/query/storages/fuse/Cargo.toml b/src/query/storages/fuse/Cargo.toml index d5a2924e7ea9..d1841e63a984 100644 --- a/src/query/storages/fuse/Cargo.toml +++ b/src/query/storages/fuse/Cargo.toml @@ -48,7 +48,7 @@ databend-storages-common-index = { workspace = true } databend-storages-common-io = { workspace = true } databend-storages-common-pruner = { workspace = true } databend-storages-common-table-meta = { workspace = true } -databend-storages-common-txn = { workspace = true } +databend-storages-common-session = { workspace = true } enum-as-inner = "0.5" fastrace = { workspace = true } futures = { workspace = true } diff --git a/src/query/storages/fuse/src/operations/analyze.rs b/src/query/storages/fuse/src/operations/analyze.rs index 03716934c1e1..b729dbcaedad 100644 --- a/src/query/storages/fuse/src/operations/analyze.rs +++ b/src/query/storages/fuse/src/operations/analyze.rs @@ -138,7 +138,7 @@ impl SinkAnalyzeState { // always use the latest table let tenant = self.ctx.get_tenant(); let catalog = CatalogManager::instance() - .get_catalog(tenant.tenant_name(), &self.catalog, self.ctx.txn_mgr()) + .get_catalog(tenant.tenant_name(), &self.catalog, self.ctx.session_state()) .await?; let table = catalog .get_table(&tenant, &self.database, &self.table) diff --git a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs index 61928e0a7db0..dd73a313c2f4 100644 --- a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs +++ b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs @@ -19,7 +19,7 @@ use databend_common_exception::Result; use databend_common_expression::TableSchema; use databend_storages_common_table_meta::meta::ClusterKey; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use crate::operations::common::ConflictResolveContext; diff --git a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs index c6bccd283b3a..380ac02182c0 100644 --- a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs @@ -34,7 +34,7 @@ use databend_common_meta_types::MatchSeq; use databend_common_pipeline_sinks::AsyncSink; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::meta::Versioned; -use databend_storages_common_txn::TxnManagerRef; +use databend_storages_common_session::TxnManagerRef; use log::debug; use log::error; use log::info; diff --git a/src/query/storages/system/src/catalogs_table.rs b/src/query/storages/system/src/catalogs_table.rs index 01dadc44b47d..9837cf928035 100644 --- a/src/query/storages/system/src/catalogs_table.rs +++ b/src/query/storages/system/src/catalogs_table.rs @@ -53,7 +53,7 @@ impl AsyncSystemTable for CatalogsTable { let mgr = CatalogManager::instance(); let catalog_names = mgr - .list_catalogs(&ctx.get_tenant(), ctx.txn_mgr()) + .list_catalogs(&ctx.get_tenant(), ctx.session_state()) .await? .into_iter() .map(|v| v.name()) diff --git a/src/query/storages/system/src/databases_table.rs b/src/query/storages/system/src/databases_table.rs index fdb70e93aad1..f231584f5a55 100644 --- a/src/query/storages/system/src/databases_table.rs +++ b/src/query/storages/system/src/databases_table.rs @@ -59,7 +59,7 @@ impl AsyncSystemTable for DatabasesTable { let catalogs = CatalogManager::instance(); let catalogs: Vec<(String, Arc)> = catalogs - .list_catalogs(&tenant, ctx.txn_mgr()) + .list_catalogs(&tenant, ctx.session_state()) .await? .iter() .map(|e| (e.name(), e.clone())) diff --git a/src/query/storages/system/src/locks_table.rs b/src/query/storages/system/src/locks_table.rs index 050cac298471..c16136f5477c 100644 --- a/src/query/storages/system/src/locks_table.rs +++ b/src/query/storages/system/src/locks_table.rs @@ -60,7 +60,7 @@ impl AsyncSystemTable for LocksTable { ) -> Result { let tenant = ctx.get_tenant(); let catalog_mgr = CatalogManager::instance(); - let ctls = catalog_mgr.list_catalogs(&tenant, ctx.txn_mgr()).await?; + let ctls = catalog_mgr.list_catalogs(&tenant, ctx.session_state()).await?; let mut lock_table_id = Vec::new(); let mut lock_revision = Vec::new(); diff --git a/src/query/storages/system/src/streams_table.rs b/src/query/storages/system/src/streams_table.rs index ba1f55f771ba..727f56a1fe38 100644 --- a/src/query/storages/system/src/streams_table.rs +++ b/src/query/storages/system/src/streams_table.rs @@ -75,7 +75,7 @@ impl AsyncSystemTable for StreamsTable { let catalog_mgr = CatalogManager::instance(); let ctls = catalog_mgr - .list_catalogs(&tenant, ctx.txn_mgr()) + .list_catalogs(&tenant, ctx.session_state()) .await? .iter() .map(|e| (e.name(), e.clone())) diff --git a/src/query/storages/system/src/tables_table.rs b/src/query/storages/system/src/tables_table.rs index 8090b124a073..ec1e4f3b033f 100644 --- a/src/query/storages/system/src/tables_table.rs +++ b/src/query/storages/system/src/tables_table.rs @@ -122,7 +122,7 @@ where TablesTable: HistoryAware let tenant = ctx.get_tenant(); let catalog_mgr = CatalogManager::instance(); let catalogs = catalog_mgr - .list_catalogs(&tenant, ctx.txn_mgr()) + .list_catalogs(&tenant, ctx.session_state()) .await? .into_iter() .map(|cat| cat.disable_table_info_refresh()) diff --git a/src/tests/sqlsmith/src/sql_gen/ddl.rs b/src/tests/sqlsmith/src/sql_gen/ddl.rs index aa534da67d93..07925482386d 100644 --- a/src/tests/sqlsmith/src/sql_gen/ddl.rs +++ b/src/tests/sqlsmith/src/sql_gen/ddl.rs @@ -24,6 +24,7 @@ use databend_common_ast::ast::Engine; use databend_common_ast::ast::Expr; use databend_common_ast::ast::Identifier; use databend_common_ast::ast::Literal; +use databend_common_ast::ast::TableType; use databend_common_ast::ast::TypeName; use rand::distributions::Alphanumeric; use rand::Rng; @@ -85,7 +86,7 @@ impl<'a, R: Rng> SqlGenerator<'a, R> { cluster_by: vec![], table_options: BTreeMap::new(), as_query: None, - transient: false, + table_type: TableType::Normal, }; tables.push((drop_table, create_table)); } From 2ff9ad28482b7c9f616f7f50e7b5489b9cede465 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sun, 11 Aug 2024 20:42:47 +0800 Subject: [PATCH 02/51] create as select --- .../catalog/src/catalog/session_catalog.rs | 11 ++++++-- .../storages/common/session/src/temp_table.rs | 26 ++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 7be39ef2cddb..d08110e74cbe 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -16,7 +16,6 @@ use std::any::Any; use std::fmt::Debug; use std::sync::Arc; -use databend_common_arrow::parquet::read; use databend_common_exception::Result; use databend_common_meta_app::schema::CatalogInfo; use databend_common_meta_app::schema::CommitTableMetaReply; @@ -358,7 +357,15 @@ impl Catalog for SessionCatalog { } async fn commit_table_meta(&self, req: CommitTableMetaReq) -> Result { - self.inner.commit_table_meta(req).await + let is_temp_table = self + .temp_tbl_mgr + .lock() + .dropped_name_to_id + .contains_key(&req.name_ident); + match is_temp_table { + true => self.temp_tbl_mgr.lock().commit_table_meta(req), + false => self.inner.commit_table_meta(req).await, + } } async fn rename_table(&self, req: RenameTableReq) -> Result { diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index b1d4295a6be5..6fb589ef6c1e 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -18,6 +18,8 @@ use std::sync::Arc; use databend_common_exception::ErrorCode; use databend_common_exception::Result; +use databend_common_meta_app::schema::CommitTableMetaReply; +use databend_common_meta_app::schema::CommitTableMetaReq; use databend_common_meta_app::schema::CreateOption; use databend_common_meta_app::schema::CreateTableReply; use databend_common_meta_app::schema::CreateTableReq; @@ -28,6 +30,7 @@ use parking_lot::Mutex; #[derive(Debug, Clone)] pub struct TempTblMgr { name_to_id: HashMap, + pub dropped_name_to_id: HashMap, id_to_meta: HashMap, next_id: u64, } @@ -37,6 +40,7 @@ impl TempTblMgr { Arc::new(Mutex::new(TempTblMgr { name_to_id: HashMap::new(), id_to_meta: HashMap::new(), + dropped_name_to_id: HashMap::new(), next_id: 0, })) } @@ -46,7 +50,7 @@ impl TempTblMgr { create_option, name_ident, table_meta, - as_dropped: _, + as_dropped, } = req; let Some(db_id) = table_meta.options.get(OPT_KEY_DATABASE_ID) else { return Err(ErrorCode::Internal(format!( @@ -54,7 +58,12 @@ impl TempTblMgr { ))); }; let db_id = db_id.parse::()?; - let table_id = match (self.name_to_id.entry(name_ident.clone()), create_option) { + let name_to_id = if as_dropped { + &mut self.dropped_name_to_id + } else { + &mut self.name_to_id + }; + let table_id = match (name_to_id.entry(name_ident.clone()), create_option) { (Entry::Occupied(_), CreateOption::Create) => { return Err(ErrorCode::TableAlreadyExists(format!( "Temporary table {} already exists", @@ -82,7 +91,7 @@ impl TempTblMgr { }; Ok(CreateTableReply { table_id, - table_id_seq: None, + table_id_seq: Some(0), db_id, new_table: true, spec_vec: None, @@ -90,6 +99,17 @@ impl TempTblMgr { orphan_table_name: None, }) } + + pub fn commit_table_meta(&mut self, req: CommitTableMetaReq) -> Result { + let Some(id) = self.dropped_name_to_id.remove(&req.name_ident) else { + return Err(ErrorCode::Internal(format!( + "table {} doesn't exists, it's a bug", + req.name_ident + ))); + }; + self.name_to_id.insert(req.name_ident.clone(), id); + Ok(CommitTableMetaReply {}) + } } pub type TempTblMgrRef = Arc>; From 983fed105c9338b077f66f980dc657cd74012037 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 12 Aug 2024 02:48:11 +0800 Subject: [PATCH 03/51] fix create as select --- .../catalog/src/catalog/session_catalog.rs | 12 +-- .../storages/common/session/src/temp_table.rs | 86 ++++++++++++------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index d08110e74cbe..88c465737a0a 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -357,14 +357,10 @@ impl Catalog for SessionCatalog { } async fn commit_table_meta(&self, req: CommitTableMetaReq) -> Result { - let is_temp_table = self - .temp_tbl_mgr - .lock() - .dropped_name_to_id - .contains_key(&req.name_ident); - match is_temp_table { - true => self.temp_tbl_mgr.lock().commit_table_meta(req), - false => self.inner.commit_table_meta(req).await, + let reply = self.temp_tbl_mgr.lock().commit_table_meta(&req)?; + match reply { + Some(r) => Ok(r), + None => self.inner.commit_table_meta(req).await, } } diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 6fb589ef6c1e..c72e8270badd 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -27,12 +27,30 @@ use databend_common_meta_app::schema::TableMeta; use databend_common_meta_app::schema::TableNameIdent; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use parking_lot::Mutex; + +/// `TempTblId` is an unique identifier for a temporary table. +/// +/// It should **not** be used as `MetaId`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +pub struct TempTblId { + inner: u64, +} + +impl TempTblId { + pub fn zero() -> Self { + TempTblId { inner: 0 } + } + + pub fn increment(&mut self) { + self.inner += 1; + } +} + #[derive(Debug, Clone)] pub struct TempTblMgr { - name_to_id: HashMap, - pub dropped_name_to_id: HashMap, - id_to_meta: HashMap, - next_id: u64, + name_to_id: HashMap, + id_to_meta: HashMap, + next_id: TempTblId, } impl TempTblMgr { @@ -40,30 +58,31 @@ impl TempTblMgr { Arc::new(Mutex::new(TempTblMgr { name_to_id: HashMap::new(), id_to_meta: HashMap::new(), - dropped_name_to_id: HashMap::new(), - next_id: 0, + next_id: TempTblId::zero(), })) } pub fn create_table(&mut self, req: CreateTableReq) -> Result { let CreateTableReq { create_option, - name_ident, + mut name_ident, table_meta, as_dropped, } = req; + let orphan_table_name = match as_dropped { + true => { + name_ident.table_name = format!("orphan@{}", name_ident.table_name); + Some(name_ident.table_name.clone()) + } + false => None, + }; let Some(db_id) = table_meta.options.get(OPT_KEY_DATABASE_ID) else { return Err(ErrorCode::Internal(format!( "Database id not set in table options" ))); }; let db_id = db_id.parse::()?; - let name_to_id = if as_dropped { - &mut self.dropped_name_to_id - } else { - &mut self.name_to_id - }; - let table_id = match (name_to_id.entry(name_ident.clone()), create_option) { + let new_table = match (self.name_to_id.entry(name_ident.clone()), create_option) { (Entry::Occupied(_), CreateOption::Create) => { return Err(ErrorCode::TableAlreadyExists(format!( "Temporary table {} already exists", @@ -74,41 +93,44 @@ impl TempTblMgr { let table_id = self.next_id; e.insert(table_id); self.id_to_meta.insert(table_id, table_meta); - self.next_id += 1; - table_id - } - (Entry::Occupied(e), CreateOption::CreateIfNotExists) => { - let table_id = *e.get(); - table_id + self.next_id.increment(); + true } + (Entry::Occupied(_), CreateOption::CreateIfNotExists) => false, (Entry::Vacant(e), _) => { let table_id = self.next_id; e.insert(table_id); self.id_to_meta.insert(table_id, table_meta); - self.next_id += 1; - table_id + self.next_id.increment(); + true } }; Ok(CreateTableReply { - table_id, + table_id: 0, table_id_seq: Some(0), db_id, - new_table: true, + new_table, spec_vec: None, prev_table_id: None, - orphan_table_name: None, + orphan_table_name, }) } - pub fn commit_table_meta(&mut self, req: CommitTableMetaReq) -> Result { - let Some(id) = self.dropped_name_to_id.remove(&req.name_ident) else { - return Err(ErrorCode::Internal(format!( - "table {} doesn't exists, it's a bug", - req.name_ident - ))); + pub fn commit_table_meta( + &mut self, + req: &CommitTableMetaReq, + ) -> Result> { + let orhan_name_ident = TableNameIdent { + table_name: req.orphan_table_name.clone().unwrap(), + ..req.name_ident.clone() }; - self.name_to_id.insert(req.name_ident.clone(), id); - Ok(CommitTableMetaReply {}) + match self.name_to_id.remove(&orhan_name_ident) { + Some(id) => { + self.name_to_id.insert(req.name_ident.clone(), id); + Ok(Some(CommitTableMetaReply {})) + } + None => Ok(None), + } } } From 7f38857076f584888c6360df5dbe62fdab926599 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 12 Aug 2024 03:07:24 +0800 Subject: [PATCH 04/51] rename table --- .../catalog/src/catalog/session_catalog.rs | 6 ++++- .../storages/common/session/src/temp_table.rs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 88c465737a0a..54ccf9afffaa 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -365,7 +365,11 @@ impl Catalog for SessionCatalog { } async fn rename_table(&self, req: RenameTableReq) -> Result { - self.inner.rename_table(req).await + let reply = self.temp_tbl_mgr.lock().rename_table(&req)?; + match reply { + Some(r) => Ok(r), + None => self.inner.rename_table(req).await, + } } async fn upsert_table_option( diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index c72e8270badd..c7c5d8fa41fc 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -23,6 +23,8 @@ use databend_common_meta_app::schema::CommitTableMetaReq; use databend_common_meta_app::schema::CreateOption; use databend_common_meta_app::schema::CreateTableReply; use databend_common_meta_app::schema::CreateTableReq; +use databend_common_meta_app::schema::RenameTableReply; +use databend_common_meta_app::schema::RenameTableReq; use databend_common_meta_app::schema::TableMeta; use databend_common_meta_app::schema::TableNameIdent; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; @@ -132,6 +134,30 @@ impl TempTblMgr { None => Ok(None), } } + + pub fn rename_table(&mut self, req: &RenameTableReq) -> Result> { + let RenameTableReq { + if_exists: _, + name_ident, + new_db_name, + new_table_name, + } = req; + match self.name_to_id.remove(&name_ident) { + Some(id) => { + let new_name_ident = TableNameIdent { + table_name: new_table_name.clone(), + db_name: new_db_name.clone(), + ..name_ident.clone() + }; + self.name_to_id.insert(new_name_ident, id); + Ok(Some(RenameTableReply { + table_id: 0, + share_table_info: None, + })) + } + None => Ok(None), + } + } } pub type TempTblMgrRef = Arc>; From 929a4d53a96857d9ec327dc516eea42c0096ca72 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 12 Aug 2024 12:04:42 +0800 Subject: [PATCH 05/51] get_table_meta_by_id --- src/meta/app/src/schema/table.rs | 3 ++ src/query/catalog/src/catalog/interface.rs | 8 ++++- .../catalog/src/catalog/session_catalog.rs | 33 ++++++++++++------- src/query/catalog/src/table.rs | 18 +++++++--- src/query/ee/src/stream/handler.rs | 5 +++ .../src/catalogs/default/database_catalog.rs | 15 +++++++-- .../src/catalogs/default/immutable_catalog.rs | 6 +++- .../src/catalogs/default/mutable_catalog.rs | 6 +++- .../src/catalogs/share/share_catalog.rs | 6 +++- .../service/src/interpreters/common/grant.rs | 6 +++- .../src/servers/admin/v1/stream_status.rs | 4 +-- .../tests/it/sql/exec/get_table_bind_test.rs | 10 ++++-- .../it/storages/fuse/operations/commit.rs | 10 ++++-- .../storages/common/session/src/temp_table.rs | 14 ++++++-- .../table_meta/src/table/stream_keys.rs | 1 + .../storages/hive/hive/src/hive_catalog.rs | 6 +++- src/query/storages/iceberg/src/catalog.rs | 6 +++- src/query/storages/stream/src/stream_table.rs | 20 +++++++---- 18 files changed, 134 insertions(+), 43 deletions(-) diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index fc47b7f9ac81..9c17eb651cfa 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -187,6 +187,9 @@ impl Display for DatabaseType { #[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq, Default)] pub struct TableInfo { + /// For a temp table, + /// `ident.seq` is always 0. + /// `id.table_id` is set as value of `TempTblId`. pub ident: TableIdent, /// For a table it is `db_name.table_name`. diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index f006dc36588c..7ac19c74f169 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -215,7 +215,13 @@ pub trait Catalog: DynClone + Send + Sync + Debug { fn get_table_by_info(&self, table_info: &TableInfo) -> Result>; /// Get the table meta by table id. - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>>; + /// + /// `table_id` can be a temp table id or a meta id as long as `is_temp` is set properly. + async fn get_table_meta_by_id( + &self, + table_id: u64, + is_temp: bool, + ) -> Result>>; // List the tables name by meta ids. async fn mget_table_names_by_ids( diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 54ccf9afffaa..10605f6a10f7 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -241,19 +241,28 @@ impl Catalog for SessionCatalog { self.inner.get_table_by_info(table_info) } - // Get the table meta by meta id. - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { - let state = self.txn_mgr.lock().state(); - match state { - TxnState::Active => { - let mutated_table = self.txn_mgr.lock().get_table_from_buffer_by_id(table_id); - if let Some(t) = mutated_table { - Ok(Some(SeqV::new(t.ident.seq, t.meta.clone()))) - } else { - self.inner.get_table_meta_by_id(table_id).await - } + async fn get_table_meta_by_id( + &self, + table_id: u64, + is_temp: bool, + ) -> Result>> { + if let Some(t) = { + let guard = self.txn_mgr.lock(); + if guard.is_active() { + guard.get_table_from_buffer_by_id(table_id) + } else { + None } - _ => self.inner.get_table_meta_by_id(table_id).await, + } { + return Ok(Some(SeqV::new(t.ident.seq, t.meta.clone()))); + } + match is_temp { + true => Ok(self + .temp_tbl_mgr + .lock() + .get_table_meta_by_id(table_id) + .map(|m| SeqV::new(0, m))), + false => self.inner.get_table_meta_by_id(table_id, is_temp).await, } } diff --git a/src/query/catalog/src/table.rs b/src/query/catalog/src/table.rs index 944591f8b22a..8f585e2a9bfa 100644 --- a/src/query/catalog/src/table.rs +++ b/src/query/catalog/src/table.rs @@ -41,6 +41,7 @@ use databend_common_storage::StorageMetrics; use databend_storages_common_table_meta::meta::SnapshotId; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::table::ChangeType; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use crate::plan::DataSourceInfo; use crate::plan::DataSourcePlan; @@ -413,6 +414,12 @@ pub trait Table: Sync + Send { fn is_read_only(&self) -> bool { false } + + fn is_temp(&self) -> bool { + self.get_table_info() + .options() + .contains_key(OPT_KEY_TEMP_PREFIX) + } } #[async_trait::async_trait] @@ -423,10 +430,13 @@ pub trait TableExt: Table { let tid = table_info.ident.table_id; let catalog = ctx.get_catalog(table_info.catalog()).await?; - let seqv = catalog.get_table_meta_by_id(tid).await?.ok_or_else(|| { - let err = UnknownTableId::new(tid, "TableExt::refresh"); - AppError::from(err) - })?; + let seqv = catalog + .get_table_meta_by_id(tid, self.is_temp()) + .await? + .ok_or_else(|| { + let err = UnknownTableId::new(tid, "TableExt::refresh"); + AppError::from(err) + })?; self.refresh_with_seq_meta(ctx, seqv.seq, seqv.data).await } diff --git a/src/query/ee/src/stream/handler.rs b/src/query/ee/src/stream/handler.rs index 1b9145d6d234..115d1ba389d2 100644 --- a/src/query/ee/src/stream/handler.rs +++ b/src/query/ee/src/stream/handler.rs @@ -39,6 +39,7 @@ use databend_enterprise_stream_handler::StreamHandlerWrapper; use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING; use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING_BEGIN_VER; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; +use databend_storages_common_table_meta::table::OPT_KEY_IS_SOURCE_TEMPORARY; use databend_storages_common_table_meta::table::OPT_KEY_MODE; use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; use databend_storages_common_table_meta::table::OPT_KEY_SOURCE_DATABASE_ID; @@ -122,6 +123,10 @@ impl StreamHandler for RealStreamHandler { options.insert(OPT_KEY_MODE.to_string(), change_desc.mode.to_string()); options.insert(OPT_KEY_SOURCE_DATABASE_ID.to_owned(), db_id.to_string()); options.insert(OPT_KEY_SOURCE_TABLE_ID.to_string(), table_id.to_string()); + options.insert( + OPT_KEY_IS_SOURCE_TEMPORARY.to_string(), + table.is_temp().to_string(), + ); options.insert(OPT_KEY_TABLE_VER.to_string(), change_desc.seq.to_string()); if let Some(snapshot_loc) = change_desc.location { options.insert(OPT_KEY_SNAPSHOT_LOCATION.to_string(), snapshot_loc); diff --git a/src/query/service/src/catalogs/default/database_catalog.rs b/src/query/service/src/catalogs/default/database_catalog.rs index 4fb37eac2494..afa4d7eb1445 100644 --- a/src/query/service/src/catalogs/default/database_catalog.rs +++ b/src/query/service/src/catalogs/default/database_catalog.rs @@ -258,13 +258,22 @@ impl Catalog for DatabaseCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { - let res = self.immutable_catalog.get_table_meta_by_id(table_id).await; + async fn get_table_meta_by_id( + &self, + table_id: MetaId, + is_temp: bool, + ) -> Result>> { + let res = self + .immutable_catalog + .get_table_meta_by_id(table_id, is_temp) + .await; if let Ok(x) = res { Ok(x) } else { - self.mutable_catalog.get_table_meta_by_id(table_id).await + self.mutable_catalog + .get_table_meta_by_id(table_id, is_temp) + .await } } diff --git a/src/query/service/src/catalogs/default/immutable_catalog.rs b/src/query/service/src/catalogs/default/immutable_catalog.rs index 2baad78bf314..5774e2036592 100644 --- a/src/query/service/src/catalogs/default/immutable_catalog.rs +++ b/src/query/service/src/catalogs/default/immutable_catalog.rs @@ -193,7 +193,11 @@ impl Catalog for ImmutableCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { + async fn get_table_meta_by_id( + &self, + table_id: MetaId, + _is_temp: bool, + ) -> Result>> { let table = self .sys_db_meta .get_by_id(&table_id) diff --git a/src/query/service/src/catalogs/default/mutable_catalog.rs b/src/query/service/src/catalogs/default/mutable_catalog.rs index c3678b34bd72..ab48d3c9b5c3 100644 --- a/src/query/service/src/catalogs/default/mutable_catalog.rs +++ b/src/query/service/src/catalogs/default/mutable_catalog.rs @@ -376,7 +376,11 @@ impl Catalog for MutableCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { + async fn get_table_meta_by_id( + &self, + table_id: MetaId, + _is_temp: bool, + ) -> Result>> { let res = self.ctx.meta.get_table_by_id(table_id).await?; Ok(res) } diff --git a/src/query/service/src/catalogs/share/share_catalog.rs b/src/query/service/src/catalogs/share/share_catalog.rs index 41de578bd2a1..51b559250c06 100644 --- a/src/query/service/src/catalogs/share/share_catalog.rs +++ b/src/query/service/src/catalogs/share/share_catalog.rs @@ -343,7 +343,11 @@ impl Catalog for ShareCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id(&self, _table_id: MetaId) -> Result>> { + async fn get_table_meta_by_id( + &self, + _table_id: MetaId, + _is_temp: bool, + ) -> Result>> { Err(ErrorCode::Unimplemented( "Cannot get table by id in SHARE catalog", )) diff --git a/src/query/service/src/interpreters/common/grant.rs b/src/query/service/src/interpreters/common/grant.rs index fb675b6284e4..286601d689ce 100644 --- a/src/query/service/src/interpreters/common/grant.rs +++ b/src/query/service/src/interpreters/common/grant.rs @@ -67,7 +67,11 @@ pub async fn validate_grant_object_exists( GrantObject::TableById(catalog_name, db_id, table_id) => { let catalog = ctx.get_catalog(catalog_name).await?; - if catalog.get_table_meta_by_id(*table_id).await?.is_none() { + if catalog + .get_table_meta_by_id(*table_id, false) + .await? + .is_none() + { return Err(databend_common_exception::ErrorCode::UnknownTableId( format!( "table id `{}`.`{}` not exists in catalog '{}'", diff --git a/src/query/service/src/servers/admin/v1/stream_status.rs b/src/query/service/src/servers/admin/v1/stream_status.rs index 0d24d78931b1..1f96b4d54edc 100644 --- a/src/query/service/src/servers/admin/v1/stream_status.rs +++ b/src/query/service/src/servers/admin/v1/stream_status.rs @@ -51,9 +51,9 @@ async fn check_stream_status( .await?; let stream = StreamTable::try_from_table(tbl.as_ref())?; - let table_id = stream.source_table_id()?; + let (table_id, is_temp) = stream.source_table_id()?; let seqv = catalog - .get_table_meta_by_id(table_id) + .get_table_meta_by_id(table_id, is_temp) .await? .ok_or_else(|| { let err = UnknownTableId::new(table_id, "check_stream_status"); diff --git a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs index a24ca0e9f1d6..5d319a87d461 100644 --- a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs +++ b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs @@ -140,9 +140,9 @@ use databend_common_storage::StageFileInfo; use databend_common_users::GrantObjectVisibilityChecker; use databend_query::sessions::QueryContext; use databend_query::test_kits::*; +use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_session::TxnManagerRef; use parking_lot::Mutex; use parking_lot::RwLock; use xorf::BinaryFuse16; @@ -412,8 +412,12 @@ impl Catalog for FakedCatalog { unimplemented!() } - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { - self.cat.get_table_meta_by_id(table_id).await + async fn get_table_meta_by_id( + &self, + table_id: MetaId, + is_temp: bool, + ) -> Result>> { + self.cat.get_table_meta_by_id(table_id, is_temp).await } } diff --git a/src/query/service/tests/it/storages/fuse/operations/commit.rs b/src/query/service/tests/it/storages/fuse/operations/commit.rs index cdaa9151b26b..6b47cca6e99f 100644 --- a/src/query/service/tests/it/storages/fuse/operations/commit.rs +++ b/src/query/service/tests/it/storages/fuse/operations/commit.rs @@ -142,12 +142,12 @@ use databend_common_storages_fuse::FUSE_TBL_SNAPSHOT_PREFIX; use databend_common_users::GrantObjectVisibilityChecker; use databend_query::sessions::QueryContext; use databend_query::test_kits::*; +use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::SegmentInfo; use databend_storages_common_table_meta::meta::Statistics; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::meta::Versioned; -use databend_storages_common_session::TxnManagerRef; use futures::TryStreamExt; use parking_lot::Mutex; use parking_lot::RwLock; @@ -906,8 +906,12 @@ impl Catalog for FakedCatalog { self.cat.get_table_by_info(table_info) } - async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { - self.cat.get_table_meta_by_id(table_id).await + async fn get_table_meta_by_id( + &self, + table_id: MetaId, + is_temp: bool, + ) -> Result>> { + self.cat.get_table_meta_by_id(table_id, is_temp).await } #[async_backtrace::framed] diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index c7c5d8fa41fc..15bc75d1cd42 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -34,18 +34,22 @@ use parking_lot::Mutex; /// /// It should **not** be used as `MetaId`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -pub struct TempTblId { +struct TempTblId { inner: u64, } impl TempTblId { - pub fn zero() -> Self { + fn zero() -> Self { TempTblId { inner: 0 } } - pub fn increment(&mut self) { + fn increment(&mut self) { self.inner += 1; } + + fn new(inner: u64) -> Self { + Self { inner } + } } #[derive(Debug, Clone)] @@ -158,6 +162,10 @@ impl TempTblMgr { None => Ok(None), } } + + pub fn get_table_meta_by_id(&self, id: u64) -> Option { + self.id_to_meta.get(&TempTblId::new(id)).cloned() + } } pub type TempTblMgrRef = Arc>; diff --git a/src/query/storages/common/table_meta/src/table/stream_keys.rs b/src/query/storages/common/table_meta/src/table/stream_keys.rs index f43277b17267..2cdca522da5f 100644 --- a/src/query/storages/common/table_meta/src/table/stream_keys.rs +++ b/src/query/storages/common/table_meta/src/table/stream_keys.rs @@ -15,6 +15,7 @@ // Stream table options. pub const OPT_KEY_SOURCE_DATABASE_ID: &str = "source_db_id"; pub const OPT_KEY_SOURCE_TABLE_ID: &str = "table_id"; +pub const OPT_KEY_IS_SOURCE_TEMPORARY: &str = "is_source_temp"; pub const OPT_KEY_TABLE_VER: &str = "table_version"; pub const OPT_KEY_MODE: &str = "mode"; diff --git a/src/query/storages/hive/hive/src/hive_catalog.rs b/src/query/storages/hive/hive/src/hive_catalog.rs index a2ebfcb1e5f7..012ce8a1a846 100644 --- a/src/query/storages/hive/hive/src/hive_catalog.rs +++ b/src/query/storages/hive/hive/src/hive_catalog.rs @@ -354,7 +354,11 @@ impl Catalog for HiveCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id(&self, _table_id: MetaId) -> Result>> { + async fn get_table_meta_by_id( + &self, + _table_id: MetaId, + _is_temp: bool, + ) -> Result>> { Err(ErrorCode::Unimplemented( "Cannot get table by id in HIVE catalog", )) diff --git a/src/query/storages/iceberg/src/catalog.rs b/src/query/storages/iceberg/src/catalog.rs index 1394c71acc3c..899ec1e1ff39 100644 --- a/src/query/storages/iceberg/src/catalog.rs +++ b/src/query/storages/iceberg/src/catalog.rs @@ -254,7 +254,11 @@ impl Catalog for IcebergCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id(&self, _table_id: MetaId) -> Result>> { + async fn get_table_meta_by_id( + &self, + _table_id: MetaId, + _is_temp: bool, + ) -> Result>> { unimplemented!() } diff --git a/src/query/storages/stream/src/stream_table.rs b/src/query/storages/stream/src/stream_table.rs index c9408b828c6f..9d9f0d6ba185 100644 --- a/src/query/storages/stream/src/stream_table.rs +++ b/src/query/storages/stream/src/stream_table.rs @@ -42,6 +42,7 @@ use databend_common_storages_fuse::FuseTable; use databend_storages_common_table_meta::table::ChangeType; use databend_storages_common_table_meta::table::StreamMode; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; +use databend_storages_common_table_meta::table::OPT_KEY_IS_SOURCE_TEMPORARY; use databend_storages_common_table_meta::table::OPT_KEY_MODE; use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; use databend_storages_common_table_meta::table::OPT_KEY_SOURCE_DATABASE_ID; @@ -106,7 +107,7 @@ impl StreamTable { }; let desc = &source.get_table_info().desc; - if source.get_table_info().ident.table_id != self.source_table_id()? { + if source.get_table_info().ident.table_id != self.source_table_id()?.0 { return Err(ErrorCode::IllegalStream(format!( "Base table {} dropped, cannot read from stream {}", desc, self.info.desc, @@ -140,18 +141,25 @@ impl StreamTable { self.info.options().get(OPT_KEY_SNAPSHOT_LOCATION).cloned() } - pub fn source_table_id(&self) -> Result { + pub fn source_table_id(&self) -> Result<(u64, bool)> { let table_id = self .info .options() .get(OPT_KEY_SOURCE_TABLE_ID) .ok_or_else(|| ErrorCode::Internal("source table id must be set"))? .parse::()?; - Ok(table_id) + let is_temp = self + .info + .options() + .get(OPT_KEY_IS_SOURCE_TEMPORARY) + .map(|s| s.parse::()) + .transpose()? + .ok_or_else(|| ErrorCode::Internal("source table is_temp must be set"))?; + Ok((table_id, is_temp)) } pub async fn source_table_name(&self, catalog: &dyn Catalog) -> Result { - let source_table_id = self.source_table_id()?; + let source_table_id = self.source_table_id()?.0; catalog .get_table_name_by_id(source_table_id) .await @@ -174,9 +182,9 @@ impl StreamTable { let source_db_id = match source_db_id_opt { Some(v) => v, None => { - let source_table_id = self.source_table_id()?; + let (source_table_id, source_table_is_temp) = self.source_table_id()?; let source_table_meta = catalog - .get_table_meta_by_id(source_table_id) + .get_table_meta_by_id(source_table_id, source_table_is_temp) .await? .ok_or(ErrorCode::Internal("source database id must be set"))?; source_table_meta From 4a8f940ce8188fe16b833344899319eaca57da73 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 12 Aug 2024 15:14:25 +0800 Subject: [PATCH 06/51] get_table_name_by_id --- src/query/catalog/src/catalog/interface.rs | 6 ++++-- .../catalog/src/catalog/session_catalog.rs | 5 ++--- .../src/catalogs/default/database_catalog.rs | 17 ++++++++++++++--- .../src/catalogs/default/immutable_catalog.rs | 6 +++++- .../src/catalogs/default/mutable_catalog.rs | 6 +++++- .../service/src/catalogs/share/share_catalog.rs | 6 +++++- .../tests/it/sql/exec/get_table_bind_test.rs | 8 ++++++-- .../tests/it/storages/fuse/operations/commit.rs | 8 ++++++-- .../storages/common/session/src/temp_table.rs | 4 ++++ .../storages/hive/hive/src/hive_catalog.rs | 6 +++++- src/query/storages/iceberg/src/catalog.rs | 6 +++++- src/query/storages/stream/src/stream_table.rs | 4 ++-- 12 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index 7ac19c74f169..b069b834a172 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -240,8 +240,10 @@ pub trait Catalog: DynClone + Send + Sync + Debug { db_ids: &[MetaId], ) -> Result>>; - // Get the table name by meta id. - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result>; + /// Get the table name by meta id. + /// + /// `table_id` can be a temp table id or a meta id as long as `is_temp` is set properly. + async fn get_table_name_by_id(&self, table_id: u64, is_temp: bool) -> Result>; // Get one table by db and table name. async fn get_table( diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 10605f6a10f7..dd387a8decdd 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -266,7 +266,6 @@ impl Catalog for SessionCatalog { } } - // Mget the dbs name by meta ids. async fn mget_table_names_by_ids( &self, tenant: &Tenant, @@ -275,8 +274,8 @@ impl Catalog for SessionCatalog { self.inner.mget_table_names_by_ids(tenant, table_ids).await } - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { - self.inner.get_table_name_by_id(table_id).await + async fn get_table_name_by_id(&self, table_id: u64, is_temp: bool) -> Result> { + self.inner.get_table_name_by_id(table_id, is_temp).await } // Get the db name by meta id. diff --git a/src/query/service/src/catalogs/default/database_catalog.rs b/src/query/service/src/catalogs/default/database_catalog.rs index afa4d7eb1445..d0dbcd9e5558 100644 --- a/src/query/service/src/catalogs/default/database_catalog.rs +++ b/src/query/service/src/catalogs/default/database_catalog.rs @@ -324,12 +324,23 @@ impl Catalog for DatabaseCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { - let res = self.immutable_catalog.get_table_name_by_id(table_id).await; + async fn get_table_name_by_id( + &self, + table_id: MetaId, + is_temp: bool, + ) -> Result> { + let res = self + .immutable_catalog + .get_table_name_by_id(table_id, is_temp) + .await; match res { Ok(Some(x)) => Ok(Some(x)), - Ok(None) | Err(_) => self.mutable_catalog.get_table_name_by_id(table_id).await, + Ok(None) | Err(_) => { + self.mutable_catalog + .get_table_name_by_id(table_id, is_temp) + .await + } } } diff --git a/src/query/service/src/catalogs/default/immutable_catalog.rs b/src/query/service/src/catalogs/default/immutable_catalog.rs index 5774e2036592..20d7057fd1bf 100644 --- a/src/query/service/src/catalogs/default/immutable_catalog.rs +++ b/src/query/service/src/catalogs/default/immutable_catalog.rs @@ -250,7 +250,11 @@ impl Catalog for ImmutableCatalog { Ok(res) } - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { + async fn get_table_name_by_id( + &self, + table_id: MetaId, + _is_temp: bool, + ) -> Result> { let table_name = self .sys_db_meta .get_by_id(&table_id) diff --git a/src/query/service/src/catalogs/default/mutable_catalog.rs b/src/query/service/src/catalogs/default/mutable_catalog.rs index ab48d3c9b5c3..c7ee84491af7 100644 --- a/src/query/service/src/catalogs/default/mutable_catalog.rs +++ b/src/query/service/src/catalogs/default/mutable_catalog.rs @@ -410,7 +410,11 @@ impl Catalog for MutableCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { + async fn get_table_name_by_id( + &self, + table_id: MetaId, + _is_temp: bool, + ) -> Result> { let res = self.ctx.meta.get_table_name_by_id(table_id).await?; Ok(res) } diff --git a/src/query/service/src/catalogs/share/share_catalog.rs b/src/query/service/src/catalogs/share/share_catalog.rs index 51b559250c06..e0ff27504336 100644 --- a/src/query/service/src/catalogs/share/share_catalog.rs +++ b/src/query/service/src/catalogs/share/share_catalog.rs @@ -364,7 +364,11 @@ impl Catalog for ShareCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id(&self, _table_id: MetaId) -> Result> { + async fn get_table_name_by_id( + &self, + _table_id: MetaId, + _is_temp: bool, + ) -> Result> { Err(ErrorCode::Unimplemented( "Cannot get table name by id in SHARE catalog", )) diff --git a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs index 5d319a87d461..b440a5096a8a 100644 --- a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs +++ b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs @@ -212,8 +212,12 @@ impl Catalog for FakedCatalog { self.cat.mget_database_names_by_ids(tenant, db_ids).await } - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { - self.cat.get_table_name_by_id(table_id).await + async fn get_table_name_by_id( + &self, + table_id: MetaId, + is_temp: bool, + ) -> Result> { + self.cat.get_table_name_by_id(table_id, is_temp).await } async fn get_table( diff --git a/src/query/service/tests/it/storages/fuse/operations/commit.rs b/src/query/service/tests/it/storages/fuse/operations/commit.rs index 6b47cca6e99f..933caccfde03 100644 --- a/src/query/service/tests/it/storages/fuse/operations/commit.rs +++ b/src/query/service/tests/it/storages/fuse/operations/commit.rs @@ -923,8 +923,12 @@ impl Catalog for FakedCatalog { self.cat.mget_table_names_by_ids(tenant, table_id).await } - async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { - self.cat.get_table_name_by_id(table_id).await + async fn get_table_name_by_id( + &self, + table_id: MetaId, + is_temp: bool, + ) -> Result> { + self.cat.get_table_name_by_id(table_id, is_temp).await } async fn get_db_name_by_id(&self, db_id: MetaId) -> Result { diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 15bc75d1cd42..f80028554467 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -55,6 +55,7 @@ impl TempTblId { #[derive(Debug, Clone)] pub struct TempTblMgr { name_to_id: HashMap, + id_to_name: HashMap, id_to_meta: HashMap, next_id: TempTblId, } @@ -63,6 +64,7 @@ impl TempTblMgr { pub fn init() -> Arc> { Arc::new(Mutex::new(TempTblMgr { name_to_id: HashMap::new(), + id_to_name: HashMap::new(), id_to_meta: HashMap::new(), next_id: TempTblId::zero(), })) @@ -98,6 +100,7 @@ impl TempTblMgr { (Entry::Occupied(mut e), CreateOption::CreateOrReplace) => { let table_id = self.next_id; e.insert(table_id); + self.id_to_name.insert(table_id, name_ident.clone()); self.id_to_meta.insert(table_id, table_meta); self.next_id.increment(); true @@ -106,6 +109,7 @@ impl TempTblMgr { (Entry::Vacant(e), _) => { let table_id = self.next_id; e.insert(table_id); + self.id_to_name.insert(table_id, name_ident.clone()); self.id_to_meta.insert(table_id, table_meta); self.next_id.increment(); true diff --git a/src/query/storages/hive/hive/src/hive_catalog.rs b/src/query/storages/hive/hive/src/hive_catalog.rs index 012ce8a1a846..3eac6b48ccdc 100644 --- a/src/query/storages/hive/hive/src/hive_catalog.rs +++ b/src/query/storages/hive/hive/src/hive_catalog.rs @@ -375,7 +375,11 @@ impl Catalog for HiveCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id(&self, _table_id: MetaId) -> Result> { + async fn get_table_name_by_id( + &self, + _table_id: MetaId, + _is_temp: bool, + ) -> Result> { Err(ErrorCode::Unimplemented( "Cannot get table name by id in HIVE catalog", )) diff --git a/src/query/storages/iceberg/src/catalog.rs b/src/query/storages/iceberg/src/catalog.rs index 899ec1e1ff39..b42ff464a2ac 100644 --- a/src/query/storages/iceberg/src/catalog.rs +++ b/src/query/storages/iceberg/src/catalog.rs @@ -273,7 +273,11 @@ impl Catalog for IcebergCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id(&self, _table_id: MetaId) -> Result> { + async fn get_table_name_by_id( + &self, + _table_id: MetaId, + _is_temp: bool, + ) -> Result> { Err(ErrorCode::Unimplemented( "Cannot get table name by id in ICEBERG catalog", )) diff --git a/src/query/storages/stream/src/stream_table.rs b/src/query/storages/stream/src/stream_table.rs index 9d9f0d6ba185..71b2b339f27f 100644 --- a/src/query/storages/stream/src/stream_table.rs +++ b/src/query/storages/stream/src/stream_table.rs @@ -159,9 +159,9 @@ impl StreamTable { } pub async fn source_table_name(&self, catalog: &dyn Catalog) -> Result { - let source_table_id = self.source_table_id()?.0; + let (source_table_id, source_table_is_temp) = self.source_table_id()?; catalog - .get_table_name_by_id(source_table_id) + .get_table_name_by_id(source_table_id, source_table_is_temp) .await .and_then(|opt| { opt.ok_or(ErrorCode::UnknownTable(format!( From 9d899f42cd2db39202daf978a42eb9fbdb89448a Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 12 Aug 2024 23:44:45 +0800 Subject: [PATCH 07/51] not support stream on temp table --- src/query/ee/src/stream/handler.rs | 11 +++++----- .../src/servers/admin/v1/stream_status.rs | 4 ++-- .../table_meta/src/table/stream_keys.rs | 1 - src/query/storages/stream/src/stream_table.rs | 22 ++++++------------- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/query/ee/src/stream/handler.rs b/src/query/ee/src/stream/handler.rs index 115d1ba389d2..529e64a2bb1d 100644 --- a/src/query/ee/src/stream/handler.rs +++ b/src/query/ee/src/stream/handler.rs @@ -39,7 +39,6 @@ use databend_enterprise_stream_handler::StreamHandlerWrapper; use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING; use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING_BEGIN_VER; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; -use databend_storages_common_table_meta::table::OPT_KEY_IS_SOURCE_TEMPORARY; use databend_storages_common_table_meta::table::OPT_KEY_MODE; use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; use databend_storages_common_table_meta::table::OPT_KEY_SOURCE_DATABASE_ID; @@ -69,6 +68,12 @@ impl StreamHandler for RealStreamHandler { plan.table_database, plan.table_name ))); } + if table.is_temp() { + return Err(ErrorCode::IllegalStream(format!( + "The table '{}.{}' is temporary, can't create stream", + plan.table_database, plan.table_name + ))); + } let table_id = table_info.ident.table_id; if !table.change_tracking_enabled() { @@ -123,10 +128,6 @@ impl StreamHandler for RealStreamHandler { options.insert(OPT_KEY_MODE.to_string(), change_desc.mode.to_string()); options.insert(OPT_KEY_SOURCE_DATABASE_ID.to_owned(), db_id.to_string()); options.insert(OPT_KEY_SOURCE_TABLE_ID.to_string(), table_id.to_string()); - options.insert( - OPT_KEY_IS_SOURCE_TEMPORARY.to_string(), - table.is_temp().to_string(), - ); options.insert(OPT_KEY_TABLE_VER.to_string(), change_desc.seq.to_string()); if let Some(snapshot_loc) = change_desc.location { options.insert(OPT_KEY_SNAPSHOT_LOCATION.to_string(), snapshot_loc); diff --git a/src/query/service/src/servers/admin/v1/stream_status.rs b/src/query/service/src/servers/admin/v1/stream_status.rs index 1f96b4d54edc..f2e3e3c2787e 100644 --- a/src/query/service/src/servers/admin/v1/stream_status.rs +++ b/src/query/service/src/servers/admin/v1/stream_status.rs @@ -51,9 +51,9 @@ async fn check_stream_status( .await?; let stream = StreamTable::try_from_table(tbl.as_ref())?; - let (table_id, is_temp) = stream.source_table_id()?; + let table_id = stream.source_table_id()?; let seqv = catalog - .get_table_meta_by_id(table_id, is_temp) + .get_table_meta_by_id(table_id, false) .await? .ok_or_else(|| { let err = UnknownTableId::new(table_id, "check_stream_status"); diff --git a/src/query/storages/common/table_meta/src/table/stream_keys.rs b/src/query/storages/common/table_meta/src/table/stream_keys.rs index 2cdca522da5f..f43277b17267 100644 --- a/src/query/storages/common/table_meta/src/table/stream_keys.rs +++ b/src/query/storages/common/table_meta/src/table/stream_keys.rs @@ -15,7 +15,6 @@ // Stream table options. pub const OPT_KEY_SOURCE_DATABASE_ID: &str = "source_db_id"; pub const OPT_KEY_SOURCE_TABLE_ID: &str = "table_id"; -pub const OPT_KEY_IS_SOURCE_TEMPORARY: &str = "is_source_temp"; pub const OPT_KEY_TABLE_VER: &str = "table_version"; pub const OPT_KEY_MODE: &str = "mode"; diff --git a/src/query/storages/stream/src/stream_table.rs b/src/query/storages/stream/src/stream_table.rs index 71b2b339f27f..e2864ec8fc39 100644 --- a/src/query/storages/stream/src/stream_table.rs +++ b/src/query/storages/stream/src/stream_table.rs @@ -42,7 +42,6 @@ use databend_common_storages_fuse::FuseTable; use databend_storages_common_table_meta::table::ChangeType; use databend_storages_common_table_meta::table::StreamMode; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; -use databend_storages_common_table_meta::table::OPT_KEY_IS_SOURCE_TEMPORARY; use databend_storages_common_table_meta::table::OPT_KEY_MODE; use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; use databend_storages_common_table_meta::table::OPT_KEY_SOURCE_DATABASE_ID; @@ -107,7 +106,7 @@ impl StreamTable { }; let desc = &source.get_table_info().desc; - if source.get_table_info().ident.table_id != self.source_table_id()?.0 { + if source.get_table_info().ident.table_id != self.source_table_id()? { return Err(ErrorCode::IllegalStream(format!( "Base table {} dropped, cannot read from stream {}", desc, self.info.desc, @@ -141,27 +140,20 @@ impl StreamTable { self.info.options().get(OPT_KEY_SNAPSHOT_LOCATION).cloned() } - pub fn source_table_id(&self) -> Result<(u64, bool)> { + pub fn source_table_id(&self) -> Result { let table_id = self .info .options() .get(OPT_KEY_SOURCE_TABLE_ID) .ok_or_else(|| ErrorCode::Internal("source table id must be set"))? .parse::()?; - let is_temp = self - .info - .options() - .get(OPT_KEY_IS_SOURCE_TEMPORARY) - .map(|s| s.parse::()) - .transpose()? - .ok_or_else(|| ErrorCode::Internal("source table is_temp must be set"))?; - Ok((table_id, is_temp)) + Ok(table_id) } pub async fn source_table_name(&self, catalog: &dyn Catalog) -> Result { - let (source_table_id, source_table_is_temp) = self.source_table_id()?; + let source_table_id = self.source_table_id()?; catalog - .get_table_name_by_id(source_table_id, source_table_is_temp) + .get_table_name_by_id(source_table_id, false) .await .and_then(|opt| { opt.ok_or(ErrorCode::UnknownTable(format!( @@ -182,9 +174,9 @@ impl StreamTable { let source_db_id = match source_db_id_opt { Some(v) => v, None => { - let (source_table_id, source_table_is_temp) = self.source_table_id()?; + let source_table_id = self.source_table_id()?; let source_table_meta = catalog - .get_table_meta_by_id(source_table_id, source_table_is_temp) + .get_table_meta_by_id(source_table_id, false) .await? .ok_or(ErrorCode::Internal("source database id must be set"))?; source_table_meta From 36960ce2dbbfc6029b5ca2937085a34ffc7e3d86 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 12 Aug 2024 23:52:38 +0800 Subject: [PATCH 08/51] fix get_table_name_by_id --- src/query/catalog/src/catalog/session_catalog.rs | 5 ++++- src/query/storages/common/session/src/temp_table.rs | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index dd387a8decdd..af6fe650b594 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -275,7 +275,10 @@ impl Catalog for SessionCatalog { } async fn get_table_name_by_id(&self, table_id: u64, is_temp: bool) -> Result> { - self.inner.get_table_name_by_id(table_id, is_temp).await + match is_temp { + true => Ok(self.temp_tbl_mgr.lock().get_table_name_by_id(table_id)), + false => self.inner.get_table_name_by_id(table_id, is_temp).await, + } } // Get the db name by meta id. diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index f80028554467..a38771ab080b 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -170,6 +170,12 @@ impl TempTblMgr { pub fn get_table_meta_by_id(&self, id: u64) -> Option { self.id_to_meta.get(&TempTblId::new(id)).cloned() } + + pub fn get_table_name_by_id(&self, id: u64) -> Option { + self.id_to_name + .get(&TempTblId::new(id)) + .map(|i| i.table_name.clone()) + } } pub type TempTblMgrRef = Arc>; From 74382a4083948bd0bc3b279c5797ba0700b757bd Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 00:31:39 +0800 Subject: [PATCH 09/51] add comment --- src/query/catalog/src/catalog/interface.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index b069b834a172..1b84effdc498 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -223,7 +223,9 @@ pub trait Catalog: DynClone + Send + Sync + Debug { is_temp: bool, ) -> Result>>; - // List the tables name by meta ids. + /// List the tables name by meta ids. + /// + /// **Do not** pass temp table id as meta id. async fn mget_table_names_by_ids( &self, tenant: &Tenant, From 071c1692b84652071771a14660bf740734e81fdc Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 11:19:19 +0800 Subject: [PATCH 10/51] check access --- src/query/catalog/src/catalog/interface.rs | 2 +- src/query/catalog/src/table_context.rs | 2 ++ .../interpreters/access/privilege_access.rs | 19 +++++++++++++++++-- src/query/service/src/sessions/query_ctx.rs | 4 ++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index 1b84effdc498..997a2b443edf 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -224,7 +224,7 @@ pub trait Catalog: DynClone + Send + Sync + Debug { ) -> Result>>; /// List the tables name by meta ids. - /// + /// /// **Do not** pass temp table id as meta id. async fn mget_table_names_by_ids( &self, diff --git a/src/query/catalog/src/table_context.rs b/src/query/catalog/src/table_context.rs index 2f03eeeb95ca..d761c7297ff4 100644 --- a/src/query/catalog/src/table_context.rs +++ b/src/query/catalog/src/table_context.rs @@ -365,4 +365,6 @@ pub trait TableContext: Send + Sync { fn get_session_id(&self) -> String; fn session_state(&self) -> SessionState; + + fn is_temp_table(&self, database_name: &str, table_name: &str) -> bool; } diff --git a/src/query/service/src/interpreters/access/privilege_access.rs b/src/query/service/src/interpreters/access/privilege_access.rs index c9c9fcf4bd80..57e8a8ba4393 100644 --- a/src/query/service/src/interpreters/access/privilege_access.rs +++ b/src/query/service/src/interpreters/access/privilege_access.rs @@ -16,6 +16,7 @@ use std::collections::HashSet; use std::sync::Arc; use databend_common_catalog::catalog::Catalog; +use databend_common_catalog::catalog::CATALOG_DEFAULT; use databend_common_catalog::plan::DataSourceInfo; use databend_common_catalog::table_context::TableContext; use databend_common_exception::ErrorCode; @@ -42,6 +43,7 @@ use databend_common_sql::plans::RewriteKind; use databend_common_sql::Planner; use databend_common_users::RoleCacheManager; use databend_common_users::UserApiProvider; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use crate::interpreters::access::AccessChecker; use crate::sessions::QueryContext; @@ -291,6 +293,10 @@ impl PrivilegeAccess { return Ok(()); } + if catalog_name == CATALOG_DEFAULT && self.ctx.is_temp_table(db_name, table_name) { + return Ok(()); + } + let tenant = self.ctx.get_tenant(); match self.ctx.get_catalog(catalog_name).await { @@ -749,6 +755,9 @@ impl AccessChecker for PrivilegeAccess { check_ownership_access(&identity, &ctl_name, database, show_db_id, &ownerships, &roles_name)?; } Some(RewriteKind::ShowColumns(catalog_name, database, table)) => { + if catalog_name = CATALOG_DEFAULT && self.ctx.is_temp_table(database,table){ + return Ok(()); + } let session = self.ctx.get_current_session(); if self.has_ownership(&session, &GrantObject::Table(catalog_name.clone(), database.clone(), table.clone()), false, false).await? || self.has_ownership(&session, &GrantObject::Database(catalog_name.clone(), database.clone()), false, false).await? { @@ -801,9 +810,10 @@ impl AccessChecker for PrivilegeAccess { DataSourceInfo::TableSource(_) | DataSourceInfo::ResultScanSource(_) => {} } } - if table.is_source_of_view() { + if table.is_source_of_view()||table.table().is_temp() { continue; } + let catalog_name = table.catalog(); // like this sql: copy into t from (select * from @s3); will bind a mock table with name `system.read_parquet(s3)` // this is no means to check table `system.read_parquet(s3)` privilege @@ -922,7 +932,9 @@ impl AccessChecker for PrivilegeAccess { self.validate_table_access(&plan.catalog, &plan.database, &plan.table, UserPrivilegeType::Select, false, false).await? } Plan::CreateTable(plan) => { - self.validate_db_access(&plan.catalog, &plan.database, UserPrivilegeType::Create, false).await?; + if !plan.options.contains_key(OPT_KEY_TEMP_PREFIX){ + self.validate_db_access(&plan.catalog, &plan.database, UserPrivilegeType::Create, false).await?; + } if let Some(query) = &plan.as_select { self.check(ctx, query).await?; } @@ -937,6 +949,9 @@ impl AccessChecker for PrivilegeAccess { } Plan::RenameTable(plan) => { + if plan.options.contains_key(OPT_KEY_TEMP_PREFIX){ + return Ok(()); + } // You must have ALTER and DROP privileges for the original table, // and CREATE for the new db. let privileges = vec![UserPrivilegeType::Alter, UserPrivilegeType::Drop]; diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index b793de479ea4..267b4dd125bf 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -1328,6 +1328,10 @@ impl TableContext for QueryContext { fn get_session_id(&self) -> String { todo!() } + + fn is_temp_table(&self, database_name: &str, table_name: &str) -> bool { + todo!() + } } impl TrySpawn for QueryContext { From a5b99fdd2cf2a662ab0c789205d1922038930ff5 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 13:50:25 +0800 Subject: [PATCH 11/51] forbid grant and revoke --- src/query/catalog/src/table_context.rs | 2 +- .../interpreters/access/privilege_access.rs | 7 +- .../interpreters/interpreter_table_create.rs | 71 ++++++++++--------- .../interpreters/interpreter_table_drop.rs | 25 ++++--- .../builders/builder_insert_multi_table.rs | 6 +- src/query/service/src/sessions/query_ctx.rs | 12 +++- .../tests/it/sql/exec/get_table_bind_test.rs | 13 ++++ .../tests/it/storages/fuse/conflict.rs | 2 +- .../it/storages/fuse/operations/commit.rs | 13 ++++ .../sql/src/planner/binder/ddl/account.rs | 18 +++++ .../common/session/src/session_state.rs | 1 - .../storages/common/session/src/temp_table.rs | 11 ++- .../storages/fuse/src/operations/analyze.rs | 6 +- .../common/generators/snapshot_generator.rs | 2 +- .../processors/multi_table_insert_commit.rs | 2 +- src/query/storages/system/src/locks_table.rs | 4 +- 16 files changed, 135 insertions(+), 60 deletions(-) diff --git a/src/query/catalog/src/table_context.rs b/src/query/catalog/src/table_context.rs index d761c7297ff4..420ab175b1cf 100644 --- a/src/query/catalog/src/table_context.rs +++ b/src/query/catalog/src/table_context.rs @@ -366,5 +366,5 @@ pub trait TableContext: Send + Sync { fn session_state(&self) -> SessionState; - fn is_temp_table(&self, database_name: &str, table_name: &str) -> bool; + fn is_temp_table(&self, catalog_name: &str, database_name: &str, table_name: &str) -> bool; } diff --git a/src/query/service/src/interpreters/access/privilege_access.rs b/src/query/service/src/interpreters/access/privilege_access.rs index 57e8a8ba4393..cd51aeefafb5 100644 --- a/src/query/service/src/interpreters/access/privilege_access.rs +++ b/src/query/service/src/interpreters/access/privilege_access.rs @@ -16,7 +16,6 @@ use std::collections::HashSet; use std::sync::Arc; use databend_common_catalog::catalog::Catalog; -use databend_common_catalog::catalog::CATALOG_DEFAULT; use databend_common_catalog::plan::DataSourceInfo; use databend_common_catalog::table_context::TableContext; use databend_common_exception::ErrorCode; @@ -293,7 +292,7 @@ impl PrivilegeAccess { return Ok(()); } - if catalog_name == CATALOG_DEFAULT && self.ctx.is_temp_table(db_name, table_name) { + if self.ctx.is_temp_table(catalog_name, db_name, table_name) { return Ok(()); } @@ -755,7 +754,7 @@ impl AccessChecker for PrivilegeAccess { check_ownership_access(&identity, &ctl_name, database, show_db_id, &ownerships, &roles_name)?; } Some(RewriteKind::ShowColumns(catalog_name, database, table)) => { - if catalog_name = CATALOG_DEFAULT && self.ctx.is_temp_table(database,table){ + if self.ctx.is_temp_table(catalog_name,database,table){ return Ok(()); } let session = self.ctx.get_current_session(); @@ -949,7 +948,7 @@ impl AccessChecker for PrivilegeAccess { } Plan::RenameTable(plan) => { - if plan.options.contains_key(OPT_KEY_TEMP_PREFIX){ + if self.ctx.is_temp_table(&plan.catalog,&plan.database, &plan.table) { return Ok(()); } // You must have ALTER and DROP privileges for the original table, diff --git a/src/query/service/src/interpreters/interpreter_table_create.rs b/src/query/service/src/interpreters/interpreter_table_create.rs index ac987096832c..f002b11dba46 100644 --- a/src/query/service/src/interpreters/interpreter_table_create.rs +++ b/src/query/service/src/interpreters/interpreter_table_create.rs @@ -72,6 +72,7 @@ use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_FORMAT; use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_PREFIX; use databend_storages_common_table_meta::table::OPT_KEY_TABLE_COMPRESSION; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use log::error; use log::info; @@ -205,21 +206,23 @@ impl CreateTableInterpreter { .expect("internal error: table_id_seq must have been set. CTAS(replace) of table"); let db_id = reply.db_id; - // grant the ownership of the table to the current role. - let current_role = self.ctx.get_current_role(); - if let Some(current_role) = current_role { - let role_api = UserApiProvider::instance().role_api(&tenant); - role_api - .grant_ownership( - &OwnershipObject::Table { - catalog_name: self.plan.catalog.clone(), - db_id, - table_id, - }, - ¤t_role.name, - ) - .await?; - RoleCacheManager::instance().invalidate_cache(&tenant); + if !req.table_meta.options.contains_key(OPT_KEY_TEMP_PREFIX) { + // grant the ownership of the table to the current role. + let current_role = self.ctx.get_current_role(); + if let Some(current_role) = current_role { + let role_api = UserApiProvider::instance().role_api(&tenant); + role_api + .grant_ownership( + &OwnershipObject::Table { + catalog_name: self.plan.catalog.clone(), + db_id, + table_id, + }, + ¤t_role.name, + ) + .await?; + RoleCacheManager::instance().invalidate_cache(&tenant); + } } // If the table creation query contains column definitions, like 'CREATE TABLE t1(a int) AS SELECT * from t2', @@ -359,24 +362,26 @@ impl CreateTableInterpreter { let reply = catalog.create_table(req.clone()).await?; - // grant the ownership of the table to the current role, the above req.table_meta.owner could be removed in future. - if let Some(current_role) = self.ctx.get_current_role() { - let tenant = self.ctx.get_tenant(); - let db = catalog.get_database(&tenant, &self.plan.database).await?; - let db_id = db.get_db_info().ident.db_id; - - let role_api = UserApiProvider::instance().role_api(&tenant); - role_api - .grant_ownership( - &OwnershipObject::Table { - catalog_name: self.plan.catalog.clone(), - db_id, - table_id: reply.table_id, - }, - ¤t_role.name, - ) - .await?; - RoleCacheManager::instance().invalidate_cache(&tenant); + if !req.table_meta.options.contains_key(OPT_KEY_TEMP_PREFIX) { + // grant the ownership of the table to the current role, the above req.table_meta.owner could be removed in future. + if let Some(current_role) = self.ctx.get_current_role() { + let tenant = self.ctx.get_tenant(); + let db = catalog.get_database(&tenant, &self.plan.database).await?; + let db_id = db.get_db_info().ident.db_id; + + let role_api = UserApiProvider::instance().role_api(&tenant); + role_api + .grant_ownership( + &OwnershipObject::Table { + catalog_name: self.plan.catalog.clone(), + db_id, + table_id: reply.table_id, + }, + ¤t_role.name, + ) + .await?; + RoleCacheManager::instance().invalidate_cache(&tenant); + } } // update share spec if needed diff --git a/src/query/service/src/interpreters/interpreter_table_drop.rs b/src/query/service/src/interpreters/interpreter_table_drop.rs index 1d68a13cea40..6a5bfefcaadc 100644 --- a/src/query/service/src/interpreters/interpreter_table_drop.rs +++ b/src/query/service/src/interpreters/interpreter_table_drop.rs @@ -88,6 +88,7 @@ impl Interpreter for DropTableInterpreter { } } }; + let is_temp = tbl.is_temp(); let table_id = tbl.get_table_info().ident.table_id; let engine = tbl.get_table_info().engine(); @@ -127,18 +128,20 @@ impl Interpreter for DropTableInterpreter { }) .await?; - // we should do `drop ownership` after actually drop table, otherwise when we drop the ownership, - // but the table still exists, in the interval maybe some unexpected things will happen. - // drop the ownership - let role_api = UserApiProvider::instance().role_api(&self.plan.tenant); - let owner_object = OwnershipObject::Table { - catalog_name: self.plan.catalog.clone(), - db_id: db.get_db_info().ident.db_id, - table_id, - }; + if !is_temp { + // we should do `drop ownership` after actually drop table, otherwise when we drop the ownership, + // but the table still exists, in the interval maybe some unexpected things will happen. + // drop the ownership + let role_api = UserApiProvider::instance().role_api(&self.plan.tenant); + let owner_object = OwnershipObject::Table { + catalog_name: self.plan.catalog.clone(), + db_id: db.get_db_info().ident.db_id, + table_id, + }; - role_api.revoke_ownership(&owner_object).await?; - RoleCacheManager::instance().invalidate_cache(&tenant); + role_api.revoke_ownership(&owner_object).await?; + RoleCacheManager::instance().invalidate_cache(&tenant); + } let mut build_res = PipelineBuildResult::create(); // if `plan.all`, truncate, then purge the historical data diff --git a/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs b/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs index f67b236debe0..b414b3cca8c2 100644 --- a/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs +++ b/src/query/service/src/pipelines/builders/builder_insert_multi_table.rs @@ -288,8 +288,10 @@ impl PipelineBuilder { self.main_pipeline .add_transforms_by_chunk(mutation_aggregator_builders)?; self.main_pipeline.try_resize(1)?; - let catalog = CatalogManager::instance() - .build_catalog(targets[0].target_catalog_info.clone(), self.ctx.session_state())?; + let catalog = CatalogManager::instance().build_catalog( + targets[0].target_catalog_info.clone(), + self.ctx.session_state(), + )?; self.main_pipeline.add_sink(|input| { Ok(ProcessorPtr::create(AsyncSinker::create( input, diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index 267b4dd125bf..faf572d25350 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -37,6 +37,7 @@ use databend_common_base::base::ProgressValues; use databend_common_base::runtime::profile::Profile; use databend_common_base::runtime::profile::ProfileStatisticsName; use databend_common_base::runtime::TrySpawn; +use databend_common_catalog::catalog::CATALOG_DEFAULT; use databend_common_catalog::lock::LockTableOption; use databend_common_catalog::merge_into_join::MergeIntoJoin; use databend_common_catalog::plan::DataSourceInfo; @@ -1329,8 +1330,15 @@ impl TableContext for QueryContext { todo!() } - fn is_temp_table(&self, database_name: &str, table_name: &str) -> bool { - todo!() + fn is_temp_table(&self, catalog_name: &str, database_name: &str, table_name: &str) -> bool { + catalog_name == CATALOG_DEFAULT + && self + .shared + .session + .session_ctx + .temp_tbl_mgr() + .lock() + .is_temp_table(self.get_tenant(), database_name, table_name) } } diff --git a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs index b440a5096a8a..dddf257fe9c5 100644 --- a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs +++ b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs @@ -140,6 +140,7 @@ use databend_common_storage::StageFileInfo; use databend_common_users::GrantObjectVisibilityChecker; use databend_query::sessions::QueryContext; use databend_query::test_kits::*; +use databend_storages_common_session::SessionState; use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::TableSnapshot; @@ -945,6 +946,18 @@ impl TableContext for CtxDelegation { ) -> Result>> { todo!() } + + fn get_session_id(&self) -> String { + todo!() + } + + fn session_state(&self) -> SessionState { + todo!() + } + + fn is_temp_table(&self, _catalog_name: &str, _database_name: &str, _table_name: &str) -> bool { + false + } } #[tokio::test(flavor = "multi_thread")] diff --git a/src/query/service/tests/it/storages/fuse/conflict.rs b/src/query/service/tests/it/storages/fuse/conflict.rs index 86fa1c674ed6..746e9ebc1b09 100644 --- a/src/query/service/tests/it/storages/fuse/conflict.rs +++ b/src/query/service/tests/it/storages/fuse/conflict.rs @@ -22,9 +22,9 @@ use databend_common_storages_fuse::operations::ConflictResolveContext; use databend_common_storages_fuse::operations::MutationGenerator; use databend_common_storages_fuse::operations::SnapshotChanges; use databend_common_storages_fuse::operations::SnapshotGenerator; +use databend_storages_common_session::TxnManager; use databend_storages_common_table_meta::meta::Statistics; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_session::TxnManager; #[test] /// base snapshot contains segments 1, 2, 3, diff --git a/src/query/service/tests/it/storages/fuse/operations/commit.rs b/src/query/service/tests/it/storages/fuse/operations/commit.rs index 933caccfde03..9e52ca9a7698 100644 --- a/src/query/service/tests/it/storages/fuse/operations/commit.rs +++ b/src/query/service/tests/it/storages/fuse/operations/commit.rs @@ -142,6 +142,7 @@ use databend_common_storages_fuse::FUSE_TBL_SNAPSHOT_PREFIX; use databend_common_users::GrantObjectVisibilityChecker; use databend_query::sessions::QueryContext; use databend_query::test_kits::*; +use databend_storages_common_session::SessionState; use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::Location; use databend_storages_common_table_meta::meta::SegmentInfo; @@ -860,6 +861,18 @@ impl TableContext for CtxDelegation { ) -> Result>> { todo!() } + + fn get_session_id(&self) -> String { + todo!() + } + + fn session_state(&self) -> SessionState { + todo!() + } + + fn is_temp_table(&self, _catalog_name: &str, _database_name: &str, _table_name: &str) -> bool { + false + } } #[derive(Clone, Debug)] diff --git a/src/query/sql/src/planner/binder/ddl/account.rs b/src/query/sql/src/planner/binder/ddl/account.rs index 09e55cf54002..137caf269748 100644 --- a/src/query/sql/src/planner/binder/ddl/account.rs +++ b/src/query/sql/src/planner/binder/ddl/account.rs @@ -152,6 +152,15 @@ impl Binder { let database_name = database_name .clone() .unwrap_or_else(|| self.ctx.get_current_database()); + if self + .ctx + .is_temp_table(&catalog_name, &database_name, table_name) + { + return Err(ErrorCode::StorageOther(format!( + "{} is a temporary table, cannot grant privileges on it", + table_name + ))); + } let db_id = catalog .get_database(&tenant, &database_name) .await? @@ -197,6 +206,15 @@ impl Binder { let database_name = database_name .clone() .unwrap_or_else(|| self.ctx.get_current_database()); + if self + .ctx + .is_temp_table(&catalog_name, &database_name, table_name) + { + return Err(ErrorCode::StorageOther(format!( + "{} is a temporary table, cannot revoke privileges on it", + table_name + ))); + } let db_id = catalog .get_database(&tenant, &database_name) .await? diff --git a/src/query/storages/common/session/src/session_state.rs b/src/query/storages/common/session/src/session_state.rs index 13b9884910e3..cb36fac2beb9 100644 --- a/src/query/storages/common/session/src/session_state.rs +++ b/src/query/storages/common/session/src/session_state.rs @@ -17,7 +17,6 @@ use crate::TempTblMgrRef; use crate::TxnManager; use crate::TxnManagerRef; - #[derive(Clone, Debug)] pub struct SessionState { pub txn_mgr: TxnManagerRef, diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index a38771ab080b..0471bd737a06 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -27,6 +27,7 @@ use databend_common_meta_app::schema::RenameTableReply; use databend_common_meta_app::schema::RenameTableReq; use databend_common_meta_app::schema::TableMeta; use databend_common_meta_app::schema::TableNameIdent; +use databend_common_meta_app::tenant::Tenant; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use parking_lot::Mutex; @@ -150,7 +151,7 @@ impl TempTblMgr { new_db_name, new_table_name, } = req; - match self.name_to_id.remove(&name_ident) { + match self.name_to_id.remove(name_ident) { Some(id) => { let new_name_ident = TableNameIdent { table_name: new_table_name.clone(), @@ -176,6 +177,14 @@ impl TempTblMgr { .get(&TempTblId::new(id)) .map(|i| i.table_name.clone()) } + + pub fn is_temp_table(&self, tenant: Tenant, database_name: &str, table_name: &str) -> bool { + self.name_to_id.contains_key(&TableNameIdent { + table_name: table_name.to_string(), + db_name: database_name.to_string(), + tenant: tenant.clone(), + }) + } } pub type TempTblMgrRef = Arc>; diff --git a/src/query/storages/fuse/src/operations/analyze.rs b/src/query/storages/fuse/src/operations/analyze.rs index b729dbcaedad..f18a7e52ac8e 100644 --- a/src/query/storages/fuse/src/operations/analyze.rs +++ b/src/query/storages/fuse/src/operations/analyze.rs @@ -138,7 +138,11 @@ impl SinkAnalyzeState { // always use the latest table let tenant = self.ctx.get_tenant(); let catalog = CatalogManager::instance() - .get_catalog(tenant.tenant_name(), &self.catalog, self.ctx.session_state()) + .get_catalog( + tenant.tenant_name(), + &self.catalog, + self.ctx.session_state(), + ) .await?; let table = catalog .get_table(&tenant, &self.database, &self.table) diff --git a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs index dd73a313c2f4..bf031d62fbf2 100644 --- a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs +++ b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs @@ -17,9 +17,9 @@ use std::sync::Arc; use databend_common_exception::Result; use databend_common_expression::TableSchema; +use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::ClusterKey; use databend_storages_common_table_meta::meta::TableSnapshot; -use databend_storages_common_session::TxnManagerRef; use crate::operations::common::ConflictResolveContext; diff --git a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs index 380ac02182c0..e6bae2027b98 100644 --- a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs @@ -32,9 +32,9 @@ use databend_common_meta_app::schema::UpdateStreamMetaReq; use databend_common_meta_app::schema::UpdateTableMetaReq; use databend_common_meta_types::MatchSeq; use databend_common_pipeline_sinks::AsyncSink; +use databend_storages_common_session::TxnManagerRef; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::meta::Versioned; -use databend_storages_common_session::TxnManagerRef; use log::debug; use log::error; use log::info; diff --git a/src/query/storages/system/src/locks_table.rs b/src/query/storages/system/src/locks_table.rs index c16136f5477c..c5d2fcdb5ab5 100644 --- a/src/query/storages/system/src/locks_table.rs +++ b/src/query/storages/system/src/locks_table.rs @@ -60,7 +60,9 @@ impl AsyncSystemTable for LocksTable { ) -> Result { let tenant = ctx.get_tenant(); let catalog_mgr = CatalogManager::instance(); - let ctls = catalog_mgr.list_catalogs(&tenant, ctx.session_state()).await?; + let ctls = catalog_mgr + .list_catalogs(&tenant, ctx.session_state()) + .await?; let mut lock_table_id = Vec::new(); let mut lock_revision = Vec::new(); From fa32f2b68062dc241861069664ab136b2d1009a7 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 15:13:10 +0800 Subject: [PATCH 12/51] get table --- .../catalog/src/catalog/session_catalog.rs | 48 +++++++++++-------- .../storages/common/session/src/temp_table.rs | 34 +++++++++++++ 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index af6fe650b594..20f80fb55361 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -302,28 +302,36 @@ impl Catalog for SessionCatalog { db_name: &str, table_name: &str, ) -> Result> { - let state = self.txn_mgr.lock().state(); - match state { - TxnState::Active => { - let mutated_table = self - .txn_mgr - .lock() - .get_table_from_buffer(tenant, db_name, table_name) - .map(|table_info| self.get_table_by_info(&table_info)); - if let Some(t) = mutated_table { - t - } else { - let table = self.inner.get_table(tenant, db_name, table_name).await?; - if table.engine() == "STREAM" { - self.txn_mgr - .lock() - .upsert_table_desc_to_id(table.get_table_info().clone()); - } - Ok(table) - } + let (table_in_txn, is_active) = { + let guard = self.txn_mgr.lock(); + if guard.is_active() { + ( + guard + .get_table_from_buffer(tenant, db_name, table_name) + .map(|table_info| self.get_table_by_info(&table_info)), + true, + ) + } else { + (None, false) } - _ => self.inner.get_table(tenant, db_name, table_name).await, + }; + if let Some(table) = table_in_txn { + return table; + } + if let Some(table) = self + .temp_tbl_mgr + .lock() + .get_table(tenant, db_name, table_name)? + { + return self.get_table_by_info(&table); + } + let table = self.inner.get_table(tenant, db_name, table_name).await?; + if table.engine() == "STREAM" && is_active { + self.txn_mgr + .lock() + .upsert_table_desc_to_id(table.get_table_info().clone()); } + Ok(table) } async fn list_tables(&self, tenant: &Tenant, db_name: &str) -> Result>> { diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 0471bd737a06..ff486b104594 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -25,6 +25,8 @@ use databend_common_meta_app::schema::CreateTableReply; use databend_common_meta_app::schema::CreateTableReq; use databend_common_meta_app::schema::RenameTableReply; use databend_common_meta_app::schema::RenameTableReq; +use databend_common_meta_app::schema::TableIdent; +use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::TableMeta; use databend_common_meta_app::schema::TableNameIdent; use databend_common_meta_app::tenant::Tenant; @@ -51,6 +53,10 @@ impl TempTblId { fn new(inner: u64) -> Self { Self { inner } } + + fn get_inner(&self) -> u64 { + self.inner + } } #[derive(Debug, Clone)] @@ -185,6 +191,34 @@ impl TempTblMgr { tenant: tenant.clone(), }) } + + pub fn get_table( + &self, + tenant: &Tenant, + database_name: &str, + table_name: &str, + ) -> Result> { + let id = self.name_to_id.get(&TableNameIdent { + table_name: table_name.to_string(), + db_name: database_name.to_string(), + tenant: tenant.clone(), + }); + let Some(id) = id else { + return Ok(None); + }; + let Some(meta) = self.id_to_meta.get(id) else { + return Err(ErrorCode::Internal(format!( + "Got table id {:?} but not found meta in temp table manager {:?}", + id, self + ))); + }; + let ident = TableIdent { + table_id: id.get_inner(), + ..Default::default() + }; + let table_info = TableInfo::new(database_name, table_name, ident, meta.clone()); + Ok(Some(table_info)) + } } pub type TempTblMgrRef = Arc>; From 4849907ab3278040554439f9a84700beacc0a933 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 15:26:56 +0800 Subject: [PATCH 13/51] not support inverted index --- src/query/sql/src/planner/binder/ddl/index.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/query/sql/src/planner/binder/ddl/index.rs b/src/query/sql/src/planner/binder/ddl/index.rs index f7f5a0fef4c4..871e31d85e91 100644 --- a/src/query/sql/src/planner/binder/ddl/index.rs +++ b/src/query/sql/src/planner/binder/ddl/index.rs @@ -437,6 +437,12 @@ impl Binder { table.engine() ))); } + if table.is_temp() { + return Err(ErrorCode::UnsupportedIndex(format!( + "Table {} is temporary table, creating inverted index not allowed", + table.name() + ))); + } let table_schema = table.schema(); let table_id = table.get_id(); let index_name = self.normalize_object_identifier(index_name); From 0054373211a6066f4c7bdc7244b46974a3c5f3e9 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 15:27:50 +0800 Subject: [PATCH 14/51] not support virtual column --- src/query/sql/src/planner/binder/ddl/virtual_column.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/query/sql/src/planner/binder/ddl/virtual_column.rs b/src/query/sql/src/planner/binder/ddl/virtual_column.rs index f843888fa130..72ecce0b8972 100644 --- a/src/query/sql/src/planner/binder/ddl/virtual_column.rs +++ b/src/query/sql/src/planner/binder/ddl/virtual_column.rs @@ -65,6 +65,12 @@ impl Binder { "Virtual Column only support FUSE engine", )); } + if table_info.is_temp() { + return Err(ErrorCode::UnsupportedVirtualColumn(format!( + "Table {} is temporary table, creating virtual column not allowed", + table_info.name() + ))); + } let schema = table_info.schema(); let virtual_columns = self From 42b1f0539c690c74e5750778041e448b560fee9a Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 15:29:29 +0800 Subject: [PATCH 15/51] not support agg index --- src/query/sql/src/planner/binder/ddl/index.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/query/sql/src/planner/binder/ddl/index.rs b/src/query/sql/src/planner/binder/ddl/index.rs index 871e31d85e91..fb5565f5d80c 100644 --- a/src/query/sql/src/planner/binder/ddl/index.rs +++ b/src/query/sql/src/planner/binder/ddl/index.rs @@ -260,6 +260,13 @@ impl Binder { ))); } + if table.is_temp() { + return Err(ErrorCode::UnsupportedIndex(format!( + "Table {} is temporary table, creating index not allowed", + table.name() + ))); + } + let table_id = table.get_id(); Self::rewrite_query_with_database(&mut original_query, table_entry.database()); Self::rewrite_query_with_database(&mut query, table_entry.database()); From d93a5d9c256e74c2f20499c6bd345ac5341332dc Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 15:31:55 +0800 Subject: [PATCH 16/51] not support data mask --- .../src/interpreters/interpreter_table_modify_column.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/query/service/src/interpreters/interpreter_table_modify_column.rs b/src/query/service/src/interpreters/interpreter_table_modify_column.rs index ab850ae1bce0..b70835847d5a 100644 --- a/src/query/service/src/interpreters/interpreter_table_modify_column.rs +++ b/src/query/service/src/interpreters/interpreter_table_modify_column.rs @@ -81,6 +81,13 @@ impl ModifyTableColumnInterpreter { .manager .check_enterprise_enabled(self.ctx.get_license_key(), DataMask)?; + if table.is_temp() { + return Err(ErrorCode::UnsupportedDataMask(format!( + "Table {} is temporary table, setting data mask policy not allowed", + table.name() + ))); + } + let meta_api = UserApiProvider::instance().get_meta_store_client(); let handler = get_datamask_handler(); let policy = handler From fab9e465bf92572c9e2e070209e0ad2f9e24b6a7 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 19:29:30 +0800 Subject: [PATCH 17/51] , --- src/meta/api/src/schema_api_test_suite.rs | 14 ++++++++++++++ src/meta/api/src/share_api_test_suite.rs | 2 ++ src/meta/app/src/schema/table.rs | 2 ++ src/meta/binaries/metabench/main.rs | 1 + src/query/catalog/src/catalog/session_catalog.rs | 5 ++++- .../src/interpreters/interpreter_table_drop.rs | 1 + .../interpreter_table_modify_column.rs | 2 +- .../src/interpreters/interpreter_view_drop.rs | 1 + .../sql/src/planner/binder/ddl/virtual_column.rs | 2 +- .../storages/common/session/src/temp_table.rs | 6 ++++++ 10 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/meta/api/src/schema_api_test_suite.rs b/src/meta/api/src/schema_api_test_suite.rs index 1af7b54e0cf1..0df5c2b92980 100644 --- a/src/meta/api/src/schema_api_test_suite.rs +++ b/src/meta/api/src/schema_api_test_suite.rs @@ -1503,6 +1503,7 @@ impl SchemaApiTestSuite { db_id, table_name: table_name.to_string(), tb_id: table_id, + is_temp: false, }) .await?; @@ -1833,6 +1834,7 @@ impl SchemaApiTestSuite { db_id, table_name: tbl_name.to_string(), tb_id, + is_temp: false, }; mt.drop_table_by_id(plan.clone()).await?; @@ -1863,6 +1865,7 @@ impl SchemaApiTestSuite { db_id, table_name: tbl_name.to_string(), tb_id, + is_temp: false, }; let res = mt.drop_table_by_id(plan).await; let err = res.unwrap_err(); @@ -1882,6 +1885,7 @@ impl SchemaApiTestSuite { db_id, table_name: tbl_name.to_string(), tb_id, + is_temp: false, }; mt.drop_table_by_id(plan.clone()).await?; } @@ -4136,6 +4140,7 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, + is_temp: false, }) .await?; } @@ -4161,6 +4166,7 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, + is_temp: false, }) .await?; let table_id = resp.table_id; @@ -4235,6 +4241,7 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, + is_temp: false, }) .await?; } @@ -4261,6 +4268,7 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, + is_temp: false, }) .await?; let table_id = resp.table_id; @@ -4435,6 +4443,7 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, + is_temp: false, }) .await?; } @@ -4675,6 +4684,7 @@ impl SchemaApiTestSuite { db_id: old_db.ident.db_id, table_name: tbl_name_ident.table_name.clone(), tb_id, + is_temp: false, }) .await?; let cur_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -4726,6 +4736,7 @@ impl SchemaApiTestSuite { db_id: old_db.ident.db_id, table_name: tbl_name.to_string(), tb_id, + is_temp: false, }) .await?; let cur_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -4783,6 +4794,7 @@ impl SchemaApiTestSuite { db_id: old_db.ident.db_id, table_name: tbl_name.to_string(), tb_id: tb_info.ident.table_id, + is_temp: false, }) .await?; let cur_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -4884,6 +4896,7 @@ impl SchemaApiTestSuite { db_id: cur_db.ident.db_id, table_name: tbl_name.to_string(), tb_id: new_tb_info.ident.table_id, + is_temp: false, }; let old_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -7478,6 +7491,7 @@ where MT: SchemaApi + kvapi::AsKVApi if_exists: false, db_id: self.db_id, tb_id: self.table_id, + is_temp: false, }; self.mt.drop_table_by_id(req.clone()).await?; diff --git a/src/meta/api/src/share_api_test_suite.rs b/src/meta/api/src/share_api_test_suite.rs index e5f1ae28bfb9..3f74b523df4d 100644 --- a/src/meta/api/src/share_api_test_suite.rs +++ b/src/meta/api/src/share_api_test_suite.rs @@ -362,6 +362,7 @@ impl ShareApiTestSuite { table_name: table_name.to_string(), tb_id: table_id, db_id, + is_temp: false, }; let res = mt.drop_table_by_id(plan).await?; let (share_db_id, share_specs) = res.spec_vec.unwrap(); @@ -2466,6 +2467,7 @@ impl ShareApiTestSuite { table_name: tbl_name.to_string(), tb_id: table_id, db_id, + is_temp: false, }; let _res = mt.drop_table_by_id(plan).await; diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index 9c17eb651cfa..be141ec6d3d8 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -564,6 +564,8 @@ pub struct DropTableByIdReq { pub table_name: String, pub db_id: MetaId, + + pub is_temp: bool, } impl DropTableByIdReq { diff --git a/src/meta/binaries/metabench/main.rs b/src/meta/binaries/metabench/main.rs index 07b07cd84a00..810bf45d0582 100644 --- a/src/meta/binaries/metabench/main.rs +++ b/src/meta/binaries/metabench/main.rs @@ -238,6 +238,7 @@ async fn benchmark_table(client: &Arc, prefix: u64, client_num: u6 db_id, table_name: table_name(), tb_id: t.ident.table_id, + is_temp: false, }) .await; diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 20f80fb55361..03a87009efae 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -364,7 +364,10 @@ impl Catalog for SessionCatalog { } async fn drop_table_by_id(&self, req: DropTableByIdReq) -> Result { - self.inner.drop_table_by_id(req).await + match req.is_temp { + true => self.temp_tbl_mgr.lock().drop_table_by_id(req), + false => self.inner.drop_table_by_id(req).await, + } } async fn undrop_table(&self, req: UndropTableReq) -> Result { diff --git a/src/query/service/src/interpreters/interpreter_table_drop.rs b/src/query/service/src/interpreters/interpreter_table_drop.rs index 6a5bfefcaadc..a675abac2b61 100644 --- a/src/query/service/src/interpreters/interpreter_table_drop.rs +++ b/src/query/service/src/interpreters/interpreter_table_drop.rs @@ -125,6 +125,7 @@ impl Interpreter for DropTableInterpreter { table_name: tbl_name.to_string(), tb_id: tbl.get_table_info().ident.table_id, db_id: db.get_db_info().ident.db_id, + is_temp, }) .await?; diff --git a/src/query/service/src/interpreters/interpreter_table_modify_column.rs b/src/query/service/src/interpreters/interpreter_table_modify_column.rs index b70835847d5a..b994815940a0 100644 --- a/src/query/service/src/interpreters/interpreter_table_modify_column.rs +++ b/src/query/service/src/interpreters/interpreter_table_modify_column.rs @@ -82,7 +82,7 @@ impl ModifyTableColumnInterpreter { .check_enterprise_enabled(self.ctx.get_license_key(), DataMask)?; if table.is_temp() { - return Err(ErrorCode::UnsupportedDataMask(format!( + return Err(ErrorCode::StorageOther(format!( "Table {} is temporary table, setting data mask policy not allowed", table.name() ))); diff --git a/src/query/service/src/interpreters/interpreter_view_drop.rs b/src/query/service/src/interpreters/interpreter_view_drop.rs index f49a984c8079..f2f73238bcec 100644 --- a/src/query/service/src/interpreters/interpreter_view_drop.rs +++ b/src/query/service/src/interpreters/interpreter_view_drop.rs @@ -93,6 +93,7 @@ impl Interpreter for DropViewInterpreter { table_name: self.plan.view_name.clone(), tb_id: table.get_id(), db_id: db.get_db_info().ident.db_id, + is_temp: table.is_temp(), }) .await?; }; diff --git a/src/query/sql/src/planner/binder/ddl/virtual_column.rs b/src/query/sql/src/planner/binder/ddl/virtual_column.rs index 72ecce0b8972..24ee4a2effd7 100644 --- a/src/query/sql/src/planner/binder/ddl/virtual_column.rs +++ b/src/query/sql/src/planner/binder/ddl/virtual_column.rs @@ -66,7 +66,7 @@ impl Binder { )); } if table_info.is_temp() { - return Err(ErrorCode::UnsupportedVirtualColumn(format!( + return Err(ErrorCode::SemanticError(format!( "Table {} is temporary table, creating virtual column not allowed", table_info.name() ))); diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index ff486b104594..c98b3ffb99d3 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -23,6 +23,8 @@ use databend_common_meta_app::schema::CommitTableMetaReq; use databend_common_meta_app::schema::CreateOption; use databend_common_meta_app::schema::CreateTableReply; use databend_common_meta_app::schema::CreateTableReq; +use databend_common_meta_app::schema::DropTableByIdReq; +use databend_common_meta_app::schema::DropTableReply; use databend_common_meta_app::schema::RenameTableReply; use databend_common_meta_app::schema::RenameTableReq; use databend_common_meta_app::schema::TableIdent; @@ -219,6 +221,10 @@ impl TempTblMgr { let table_info = TableInfo::new(database_name, table_name, ident, meta.clone()); Ok(Some(table_info)) } + + pub fn drop_table_by_id(&mut self, req: DropTableByIdReq) -> Result { + todo!() + } } pub type TempTblMgrRef = Arc>; From 5820f624f140c392e694cff7ca6f3a2e7acc48fc Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 13 Aug 2024 20:38:35 +0800 Subject: [PATCH 18/51] drop table by id --- Cargo.lock | 1 + src/meta/app/src/schema/table.rs | 2 +- .../catalog/src/catalog/session_catalog.rs | 5 +- .../fuse/operations/vacuum_drop_tables.rs | 5 +- src/query/ee/src/stream/handler.rs | 1 + .../tests/it/catalogs/database_catalog.rs | 1 + .../service/tests/it/storages/fuse/table.rs | 2 +- src/query/storages/common/session/Cargo.toml | 2 +- src/query/storages/common/session/src/lib.rs | 1 + .../storages/common/session/src/temp_table.rs | 49 +++++++++++++++++-- .../common/table_meta/src/meta/mod.rs | 1 + .../common/table_meta/src/meta/utils.rs | 29 +++++++++++ src/query/storages/fuse/src/fuse_table.rs | 27 ++-------- 13 files changed, 94 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0421e91622f0..e3d89ff3cc6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5436,6 +5436,7 @@ dependencies = [ "databend-common-exception", "databend-common-meta-app", "databend-common-meta-types", + "databend-common-storage", "databend-storages-common-table-meta", "parking_lot 0.12.1", "serde", diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index be141ec6d3d8..a0dc36f7e4f1 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -585,7 +585,7 @@ impl Display for DropTableByIdReq { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct DropTableReply { // db id, share spec vector pub spec_vec: Option<(u64, Vec)>, diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 03a87009efae..7d28c1b0f89f 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -365,7 +365,10 @@ impl Catalog for SessionCatalog { async fn drop_table_by_id(&self, req: DropTableByIdReq) -> Result { match req.is_temp { - true => self.temp_tbl_mgr.lock().drop_table_by_id(req), + true => { + databend_storages_common_session::drop_table_by_id(self.temp_tbl_mgr.clone(), req) + .await + } false => self.inner.drop_table_by_id(req).await, } } diff --git a/src/query/ee/src/storages/fuse/operations/vacuum_drop_tables.rs b/src/query/ee/src/storages/fuse/operations/vacuum_drop_tables.rs index b4021b189177..ee84b7fbffa3 100644 --- a/src/query/ee/src/storages/fuse/operations/vacuum_drop_tables.rs +++ b/src/query/ee/src/storages/fuse/operations/vacuum_drop_tables.rs @@ -35,7 +35,10 @@ pub async fn do_vacuum_drop_table( ) -> Result>> { let mut list_files = vec![]; for (table_info, operator) in tables { - let dir = format!("{}/", FuseTable::parse_storage_prefix(&table_info)?); + let dir = format!( + "{}/", + FuseTable::parse_storage_prefix_from_table_info(&table_info)? + ); info!( "vacuum drop table {:?} dir {:?}, is_external_table:{:?}", diff --git a/src/query/ee/src/stream/handler.rs b/src/query/ee/src/stream/handler.rs index 529e64a2bb1d..8bc94188a126 100644 --- a/src/query/ee/src/stream/handler.rs +++ b/src/query/ee/src/stream/handler.rs @@ -190,6 +190,7 @@ impl StreamHandler for RealStreamHandler { table_name: stream_name.clone(), tb_id: table.get_id(), db_id: db.get_db_info().ident.db_id, + is_temp: false, }) .await } else if plan.if_exists { diff --git a/src/query/service/tests/it/catalogs/database_catalog.rs b/src/query/service/tests/it/catalogs/database_catalog.rs index d9201ea20e0d..1c00d6eede6f 100644 --- a/src/query/service/tests/it/catalogs/database_catalog.rs +++ b/src/query/service/tests/it/catalogs/database_catalog.rs @@ -191,6 +191,7 @@ async fn test_catalogs_table() -> Result<()> { table_name: "test_table".to_string(), tb_id: tbl.get_table_info().ident.table_id, db_id: db.get_db_info().ident.db_id, + is_temp: false, }) .await; assert!(res.is_ok()); diff --git a/src/query/service/tests/it/storages/fuse/table.rs b/src/query/service/tests/it/storages/fuse/table.rs index 7dea159c1a9d..2363b8c47c66 100644 --- a/src/query/service/tests/it/storages/fuse/table.rs +++ b/src/query/service/tests/it/storages/fuse/table.rs @@ -147,7 +147,7 @@ fn test_parse_storage_prefix() -> Result<()> { .meta .options .insert(OPT_KEY_DATABASE_ID.to_owned(), db_id.to_string()); - let prefix = FuseTable::parse_storage_prefix(&tbl_info)?; + let prefix = FuseTable::parse_storage_prefix_from_table_info(&tbl_info)?; assert_eq!(format!("{}/{}", db_id, tbl_id), prefix); Ok(()) } diff --git a/src/query/storages/common/session/Cargo.toml b/src/query/storages/common/session/Cargo.toml index ceadf5bd0476..21e42d7d2c18 100644 --- a/src/query/storages/common/session/Cargo.toml +++ b/src/query/storages/common/session/Cargo.toml @@ -11,9 +11,9 @@ databend-common-exception = { workspace = true } databend-common-meta-app = { workspace = true } databend-common-meta-types = { workspace = true } databend-storages-common-table-meta = { workspace = true } +databend-common-storage = { workspace = true } parking_lot = { workspace = true } serde = { version = "1.0.194", features = ["derive"] } uuid = { workspace = true } - [lints] workspace = true diff --git a/src/query/storages/common/session/src/lib.rs b/src/query/storages/common/session/src/lib.rs index d731b190a2e2..2604d21ae1d6 100644 --- a/src/query/storages/common/session/src/lib.rs +++ b/src/query/storages/common/session/src/lib.rs @@ -21,3 +21,4 @@ pub use transaction::TxnManagerRef; pub use transaction::TxnState; mod session_state; pub use session_state::SessionState; +pub use temp_table::drop_table_by_id; diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index c98b3ffb99d3..4c0fe211a9c4 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -32,9 +32,10 @@ use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::TableMeta; use databend_common_meta_app::schema::TableNameIdent; use databend_common_meta_app::tenant::Tenant; +use databend_common_storage::DataOperator; +use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use parking_lot::Mutex; - /// `TempTblId` is an unique identifier for a temporary table. /// /// It should **not** be used as `MetaId`. @@ -221,10 +222,50 @@ impl TempTblMgr { let table_info = TableInfo::new(database_name, table_name, ident, meta.clone()); Ok(Some(table_info)) } +} - pub fn drop_table_by_id(&mut self, req: DropTableByIdReq) -> Result { - todo!() - } +pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Result { + let DropTableByIdReq { + if_exists, tb_id, .. + } = req; + let dir = { + let mut guard = mgr.lock(); + let entry = guard.id_to_meta.entry(TempTblId::new(tb_id)); + match (entry, if_exists) { + (Entry::Occupied(e), _) => { + let dir = parse_storage_prefix(&e.get().options, tb_id)?; + e.remove(); + let name = guard + .id_to_name + .remove(&TempTblId::new(tb_id)) + .ok_or_else(|| { + ErrorCode::Internal(format!( + "Table not found in temp table manager {:?}, drop table request: {:?}", + *guard, req + )) + })?; + guard.name_to_id.remove(&name).ok_or_else(|| { + ErrorCode::Internal(format!( + "Table not found in temp table manager {:?}, drop table request: {:?}", + guard, req + )) + })?; + dir + } + (Entry::Vacant(_), true) => { + return Err(ErrorCode::UnknownTable(format!( + "Table not found in temp table manager {:?}, drop table request: {:?}", + *guard, req + ))); + } + (Entry::Vacant(_), false) => { + return Ok(Default::default()); + } + } + }; + let op = DataOperator::instance().operator(); + op.remove_all(&dir).await?; + Ok(Default::default()) } pub type TempTblMgrRef = Arc>; diff --git a/src/query/storages/common/table_meta/src/meta/mod.rs b/src/query/storages/common/table_meta/src/meta/mod.rs index 4c6ef8668945..38ae8b5e03c3 100644 --- a/src/query/storages/common/table_meta/src/meta/mod.rs +++ b/src/query/storages/common/table_meta/src/meta/mod.rs @@ -37,6 +37,7 @@ pub use statistics::*; // export legacy versioned table meta types locally, // currently, used by versioned readers only pub(crate) use testing::*; +pub use utils::parse_storage_prefix; pub(crate) use utils::*; pub use versions::testify_version; pub use versions::SegmentInfoVersion; diff --git a/src/query/storages/common/table_meta/src/meta/utils.rs b/src/query/storages/common/table_meta/src/meta/utils.rs index d6202dcb9e8b..512b9d200986 100644 --- a/src/query/storages/common/table_meta/src/meta/utils.rs +++ b/src/query/storages/common/table_meta/src/meta/utils.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::collections::BTreeMap; use std::ops::Add; use chrono::DateTime; @@ -19,6 +20,13 @@ use chrono::Datelike; use chrono::TimeZone; use chrono::Timelike; use chrono::Utc; +use databend_common_exception::ErrorCode; +use databend_common_exception::Result; + +use crate::table::table_storage_prefix; +use crate::table::OPT_KEY_DATABASE_ID; +use crate::table::OPT_KEY_STORAGE_PREFIX; +use crate::table::OPT_KEY_TEMP_PREFIX; pub fn trim_timestamp_to_micro_second(ts: DateTime) -> DateTime { Utc.with_ymd_and_hms( @@ -47,3 +55,24 @@ pub fn monotonically_increased_timestamp( } timestamp } + +pub fn parse_storage_prefix(options: &BTreeMap, table_id: u64) -> Result { + // if OPT_KE_STORAGE_PREFIX is specified, use it as storage prefix + if let Some(prefix) = options.get(OPT_KEY_STORAGE_PREFIX) { + return Ok(prefix.clone()); + } + + // otherwise, use database id and table id as storage prefix + + let db_id = options.get(OPT_KEY_DATABASE_ID).ok_or_else(|| { + ErrorCode::Internal(format!( + "Invalid fuse table, table option {} not found", + OPT_KEY_DATABASE_ID + )) + })?; + let mut prefix = table_storage_prefix(db_id, table_id); + if let Some(temp_prefix) = options.get(OPT_KEY_TEMP_PREFIX) { + prefix = format!("{}/{}", temp_prefix, prefix); + } + Ok(prefix) +} diff --git a/src/query/storages/fuse/src/fuse_table.rs b/src/query/storages/fuse/src/fuse_table.rs index f305c5af33bf..1af56f115a04 100644 --- a/src/query/storages/fuse/src/fuse_table.rs +++ b/src/query/storages/fuse/src/fuse_table.rs @@ -60,18 +60,17 @@ use databend_common_storage::DataOperator; use databend_common_storage::StorageMetrics; use databend_common_storage::StorageMetricsLayer; use databend_storages_common_cache::LoadParams; +use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::meta::ClusterKey; use databend_storages_common_table_meta::meta::SnapshotId; use databend_storages_common_table_meta::meta::Statistics as FuseStatistics; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::meta::TableSnapshotStatistics; use databend_storages_common_table_meta::meta::Versioned; -use databend_storages_common_table_meta::table::table_storage_prefix; use databend_storages_common_table_meta::table::ChangeType; use databend_storages_common_table_meta::table::TableCompression; use databend_storages_common_table_meta::table::OPT_KEY_BLOOM_INDEX_COLUMNS; use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING; -use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use databend_storages_common_table_meta::table::OPT_KEY_LEGACY_SNAPSHOT_LOC; use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_FORMAT; @@ -158,7 +157,7 @@ impl FuseTable { } pub fn do_create(table_info: TableInfo) -> Result> { - let storage_prefix = Self::parse_storage_prefix(&table_info)?; + let storage_prefix = Self::parse_storage_prefix_from_table_info(&table_info)?; let cluster_key_meta = table_info.meta.cluster_key(); let (mut operator, table_type) = match table_info.db_type.clone() { @@ -275,27 +274,9 @@ impl FuseTable { } } - pub fn parse_storage_prefix(table_info: &TableInfo) -> Result { - // if OPT_KE_STORAGE_PREFIX is specified, use it as storage prefix - if let Some(prefix) = table_info.options().get(OPT_KEY_STORAGE_PREFIX) { - return Ok(prefix.clone()); - } - - // otherwise, use database id and table id as storage prefix - - let table_id = table_info.ident.table_id; - let db_id = table_info - .options() - .get(OPT_KEY_DATABASE_ID) - .ok_or_else(|| { - ErrorCode::Internal(format!( - "Invalid fuse table, table option {} not found", - OPT_KEY_DATABASE_ID - )) - })?; - Ok(table_storage_prefix(db_id, table_id)) + pub fn parse_storage_prefix_from_table_info(table_info: &TableInfo) -> Result { + parse_storage_prefix(table_info.options(), table_info.ident.table_id) } - #[fastrace::trace] #[async_backtrace::framed] pub async fn read_table_snapshot_statistics( From fde0bd0f19b0224e873f004af7b929e8e57d98b6 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 14 Aug 2024 17:32:09 +0800 Subject: [PATCH 19/51] refactor --- .../storages/common/session/src/temp_table.rs | 95 ++++++++----------- 1 file changed, 37 insertions(+), 58 deletions(-) diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 4c0fe211a9c4..531ff6c7bb07 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::collections::hash_map::Entry; +use std::collections::BTreeMap; use std::collections::HashMap; use std::sync::Arc; @@ -27,6 +28,7 @@ use databend_common_meta_app::schema::DropTableByIdReq; use databend_common_meta_app::schema::DropTableReply; use databend_common_meta_app::schema::RenameTableReply; use databend_common_meta_app::schema::RenameTableReq; +use databend_common_meta_app::schema::TableCopiedFileInfo; use databend_common_meta_app::schema::TableIdent; use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::TableMeta; @@ -36,47 +38,27 @@ use databend_common_storage::DataOperator; use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use parking_lot::Mutex; -/// `TempTblId` is an unique identifier for a temporary table. -/// -/// It should **not** be used as `MetaId`. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -struct TempTblId { - inner: u64, -} - -impl TempTblId { - fn zero() -> Self { - TempTblId { inner: 0 } - } - fn increment(&mut self) { - self.inner += 1; - } - - fn new(inner: u64) -> Self { - Self { inner } - } - - fn get_inner(&self) -> u64 { - self.inner - } +#[derive(Debug, Clone)] +pub struct TempTblMgr { + name_to_id: HashMap, + id_to_table: HashMap, + next_id: u64, } #[derive(Debug, Clone)] -pub struct TempTblMgr { - name_to_id: HashMap, - id_to_name: HashMap, - id_to_meta: HashMap, - next_id: TempTblId, +pub struct TempTable { + name: TableNameIdent, + meta: TableMeta, + _copied_files: BTreeMap, } impl TempTblMgr { pub fn init() -> Arc> { Arc::new(Mutex::new(TempTblMgr { name_to_id: HashMap::new(), - id_to_name: HashMap::new(), - id_to_meta: HashMap::new(), - next_id: TempTblId::zero(), + id_to_table: HashMap::new(), + next_id: 0, })) } @@ -110,18 +92,24 @@ impl TempTblMgr { (Entry::Occupied(mut e), CreateOption::CreateOrReplace) => { let table_id = self.next_id; e.insert(table_id); - self.id_to_name.insert(table_id, name_ident.clone()); - self.id_to_meta.insert(table_id, table_meta); - self.next_id.increment(); + self.id_to_table.insert(table_id, TempTable { + name: name_ident, + meta: table_meta, + _copied_files: BTreeMap::new(), + }); + self.next_id += 1; true } (Entry::Occupied(_), CreateOption::CreateIfNotExists) => false, (Entry::Vacant(e), _) => { let table_id = self.next_id; e.insert(table_id); - self.id_to_name.insert(table_id, name_ident.clone()); - self.id_to_meta.insert(table_id, table_meta); - self.next_id.increment(); + self.id_to_table.insert(table_id, TempTable { + name: name_ident, + meta: table_meta, + _copied_files: BTreeMap::new(), + }); + self.next_id += 1; true } }; @@ -167,7 +155,9 @@ impl TempTblMgr { db_name: new_db_name.clone(), ..name_ident.clone() }; - self.name_to_id.insert(new_name_ident, id); + self.name_to_id.insert(new_name_ident.clone(), id); + let table = self.id_to_table.get_mut(&id).unwrap(); + table.name = new_name_ident; Ok(Some(RenameTableReply { table_id: 0, share_table_info: None, @@ -178,13 +168,11 @@ impl TempTblMgr { } pub fn get_table_meta_by_id(&self, id: u64) -> Option { - self.id_to_meta.get(&TempTblId::new(id)).cloned() + self.id_to_table.get(&id).map(|t| t.meta.clone()) } pub fn get_table_name_by_id(&self, id: u64) -> Option { - self.id_to_name - .get(&TempTblId::new(id)) - .map(|i| i.table_name.clone()) + self.id_to_table.get(&id).map(|t| t.name.table_name.clone()) } pub fn is_temp_table(&self, tenant: Tenant, database_name: &str, table_name: &str) -> bool { @@ -209,17 +197,17 @@ impl TempTblMgr { let Some(id) = id else { return Ok(None); }; - let Some(meta) = self.id_to_meta.get(id) else { + let Some(table) = self.id_to_table.get(id) else { return Err(ErrorCode::Internal(format!( "Got table id {:?} but not found meta in temp table manager {:?}", id, self ))); }; let ident = TableIdent { - table_id: id.get_inner(), + table_id: *id, ..Default::default() }; - let table_info = TableInfo::new(database_name, table_name, ident, meta.clone()); + let table_info = TableInfo::new(database_name, table_name, ident, table.meta.clone()); Ok(Some(table_info)) } } @@ -230,21 +218,12 @@ pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Resu } = req; let dir = { let mut guard = mgr.lock(); - let entry = guard.id_to_meta.entry(TempTblId::new(tb_id)); + let entry = guard.id_to_table.entry(tb_id); match (entry, if_exists) { (Entry::Occupied(e), _) => { - let dir = parse_storage_prefix(&e.get().options, tb_id)?; - e.remove(); - let name = guard - .id_to_name - .remove(&TempTblId::new(tb_id)) - .ok_or_else(|| { - ErrorCode::Internal(format!( - "Table not found in temp table manager {:?}, drop table request: {:?}", - *guard, req - )) - })?; - guard.name_to_id.remove(&name).ok_or_else(|| { + let dir = parse_storage_prefix(&e.get().meta.options, tb_id)?; + let table = e.remove(); + guard.name_to_id.remove(&table.name).ok_or_else(|| { ErrorCode::Internal(format!( "Table not found in temp table manager {:?}, drop table request: {:?}", guard, req From 1b80edf73e8d558f5afac3bb7869cca1588bc33e Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 14 Aug 2024 21:19:48 +0800 Subject: [PATCH 20/51] update table meta --- src/meta/api/src/schema_api_impl.rs | 1 + src/meta/app/src/schema/mod.rs | 1 + src/meta/app/src/schema/table.rs | 9 ++ .../catalog/src/catalog/session_catalog.rs | 17 ++-- src/query/service/src/sessions/query_ctx.rs | 2 +- .../storages/common/session/src/temp_table.rs | 95 ++++++++++--------- .../common/session/src/transaction.rs | 39 ++++++-- .../storages/fuse/src/operations/commit.rs | 31 ++++-- .../processors/multi_table_insert_commit.rs | 30 ++++-- 9 files changed, 149 insertions(+), 76 deletions(-) diff --git a/src/meta/api/src/schema_api_impl.rs b/src/meta/api/src/schema_api_impl.rs index 91d6f5fbc3fc..5e71a4f43591 100644 --- a/src/meta/api/src/schema_api_impl.rs +++ b/src/meta/api/src/schema_api_impl.rs @@ -3066,6 +3066,7 @@ impl + ?Sized> SchemaApi for KV { copied_files, update_stream_metas, deduplicated_labels, + update_temp_tables: _, } = req; let mut tbl_seqs = HashMap::new(); diff --git a/src/meta/app/src/schema/mod.rs b/src/meta/app/src/schema/mod.rs index f7508a51dba7..88519c3ff7ef 100644 --- a/src/meta/app/src/schema/mod.rs +++ b/src/meta/app/src/schema/mod.rs @@ -131,6 +131,7 @@ pub use table::UpdateMultiTableMetaResult; pub use table::UpdateStreamMetaReq; pub use table::UpdateTableMetaReply; pub use table::UpdateTableMetaReq; +pub use table::UpdateTempTableReq; pub use table::UpsertTableCopiedFileReply; pub use table::UpsertTableCopiedFileReq; pub use table::UpsertTableOptionReply; diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index a0dc36f7e4f1..d42c8ec13940 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -724,12 +724,21 @@ pub struct UpdateTableMetaReq { pub new_table_meta: TableMeta, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct UpdateTempTableReq { + pub table_id: u64, + pub desc: String, + pub new_table_meta: TableMeta, + pub copied_files: BTreeMap, +} + #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct UpdateMultiTableMetaReq { pub update_table_metas: Vec<(UpdateTableMetaReq, TableInfo)>, pub copied_files: Vec<(u64, UpsertTableCopiedFileReq)>, pub update_stream_metas: Vec, pub deduplicated_labels: Vec, + pub update_temp_tables: Vec, } /// The result of updating multiple table meta diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index 7d28c1b0f89f..b648078cfb41 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -318,11 +318,7 @@ impl Catalog for SessionCatalog { if let Some(table) = table_in_txn { return table; } - if let Some(table) = self - .temp_tbl_mgr - .lock() - .get_table(tenant, db_name, table_name)? - { + if let Some(table) = self.temp_tbl_mgr.lock().get_table(db_name, table_name)? { return self.get_table_by_info(&table); } let table = self.inner.get_table(tenant, db_name, table_name).await?; @@ -408,11 +404,18 @@ impl Catalog for SessionCatalog { async fn retryable_update_multi_table_meta( &self, - req: UpdateMultiTableMetaReq, + mut req: UpdateMultiTableMetaReq, ) -> Result { let state = self.txn_mgr.lock().state(); match state { - TxnState::AutoCommit => self.inner.retryable_update_multi_table_meta(req).await, + TxnState::AutoCommit => { + let update_temp_tables = std::mem::take(&mut req.update_temp_tables); + let reply = self.inner.retryable_update_multi_table_meta(req).await?; + self.temp_tbl_mgr + .lock() + .update_multi_table_meta(update_temp_tables); + Ok(reply) + } TxnState::Active => { self.txn_mgr.lock().update_multi_table_meta(req); Ok(Ok(Default::default())) diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index faf572d25350..f129ef78db4c 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -1338,7 +1338,7 @@ impl TableContext for QueryContext { .session_ctx .temp_tbl_mgr() .lock() - .is_temp_table(self.get_tenant(), database_name, table_name) + .is_temp_table(database_name, table_name) } } diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 531ff6c7bb07..754125a82c4b 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -32,8 +32,7 @@ use databend_common_meta_app::schema::TableCopiedFileInfo; use databend_common_meta_app::schema::TableIdent; use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::TableMeta; -use databend_common_meta_app::schema::TableNameIdent; -use databend_common_meta_app::tenant::Tenant; +use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_storage::DataOperator; use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; @@ -41,22 +40,23 @@ use parking_lot::Mutex; #[derive(Debug, Clone)] pub struct TempTblMgr { - name_to_id: HashMap, + desc_to_id: HashMap, id_to_table: HashMap, next_id: u64, } #[derive(Debug, Clone)] pub struct TempTable { - name: TableNameIdent, - meta: TableMeta, - _copied_files: BTreeMap, + pub db_name: String, + pub table_name: String, + pub meta: TableMeta, + pub _copied_files: BTreeMap, } impl TempTblMgr { pub fn init() -> Arc> { Arc::new(Mutex::new(TempTblMgr { - name_to_id: HashMap::new(), + desc_to_id: HashMap::new(), id_to_table: HashMap::new(), next_id: 0, })) @@ -82,18 +82,20 @@ impl TempTblMgr { ))); }; let db_id = db_id.parse::()?; - let new_table = match (self.name_to_id.entry(name_ident.clone()), create_option) { + let desc = format!("{}.{}", name_ident.db_name, name_ident.table_name); + let new_table = match (self.desc_to_id.entry(desc.clone()), create_option) { (Entry::Occupied(_), CreateOption::Create) => { return Err(ErrorCode::TableAlreadyExists(format!( "Temporary table {} already exists", - name_ident + desc ))); } (Entry::Occupied(mut e), CreateOption::CreateOrReplace) => { let table_id = self.next_id; e.insert(table_id); self.id_to_table.insert(table_id, TempTable { - name: name_ident, + db_name: name_ident.db_name, + table_name: name_ident.table_name, meta: table_meta, _copied_files: BTreeMap::new(), }); @@ -105,7 +107,8 @@ impl TempTblMgr { let table_id = self.next_id; e.insert(table_id); self.id_to_table.insert(table_id, TempTable { - name: name_ident, + db_name: name_ident.db_name, + table_name: name_ident.table_name, meta: table_meta, _copied_files: BTreeMap::new(), }); @@ -128,13 +131,15 @@ impl TempTblMgr { &mut self, req: &CommitTableMetaReq, ) -> Result> { - let orhan_name_ident = TableNameIdent { - table_name: req.orphan_table_name.clone().unwrap(), - ..req.name_ident.clone() - }; - match self.name_to_id.remove(&orhan_name_ident) { + let orphan_desc = format!( + "{}.{}", + req.name_ident.db_name, + req.orphan_table_name.as_ref().unwrap() + ); + let desc = format!("{}.{}", req.name_ident.db_name, req.name_ident.table_name); + match self.desc_to_id.remove(&orphan_desc) { Some(id) => { - self.name_to_id.insert(req.name_ident.clone(), id); + self.desc_to_id.insert(desc, id); Ok(Some(CommitTableMetaReply {})) } None => Ok(None), @@ -148,16 +153,14 @@ impl TempTblMgr { new_db_name, new_table_name, } = req; - match self.name_to_id.remove(name_ident) { + let desc = format!("{}.{}", name_ident.db_name, name_ident.table_name); + match self.desc_to_id.remove(&desc) { Some(id) => { - let new_name_ident = TableNameIdent { - table_name: new_table_name.clone(), - db_name: new_db_name.clone(), - ..name_ident.clone() - }; - self.name_to_id.insert(new_name_ident.clone(), id); + let new_desc = format!("{}.{}", new_db_name, new_table_name); + self.desc_to_id.insert(new_desc, id); let table = self.id_to_table.get_mut(&id).unwrap(); - table.name = new_name_ident; + table.db_name = new_db_name.clone(); + table.table_name = new_table_name.clone(); Ok(Some(RenameTableReply { table_id: 0, share_table_info: None, @@ -172,28 +175,17 @@ impl TempTblMgr { } pub fn get_table_name_by_id(&self, id: u64) -> Option { - self.id_to_table.get(&id).map(|t| t.name.table_name.clone()) + self.id_to_table.get(&id).map(|t| t.table_name.clone()) } - pub fn is_temp_table(&self, tenant: Tenant, database_name: &str, table_name: &str) -> bool { - self.name_to_id.contains_key(&TableNameIdent { - table_name: table_name.to_string(), - db_name: database_name.to_string(), - tenant: tenant.clone(), - }) + pub fn is_temp_table(&self, database_name: &str, table_name: &str) -> bool { + let desc = format!("{}.{}", database_name, table_name); + self.desc_to_id.contains_key(&desc) } - pub fn get_table( - &self, - tenant: &Tenant, - database_name: &str, - table_name: &str, - ) -> Result> { - let id = self.name_to_id.get(&TableNameIdent { - table_name: table_name.to_string(), - db_name: database_name.to_string(), - tenant: tenant.clone(), - }); + pub fn get_table(&self, database_name: &str, table_name: &str) -> Result> { + let desc = format!("{}.{}", database_name, table_name); + let id = self.desc_to_id.get(&desc); let Some(id) = id else { return Ok(None); }; @@ -210,6 +202,20 @@ impl TempTblMgr { let table_info = TableInfo::new(database_name, table_name, ident, table.meta.clone()); Ok(Some(table_info)) } + + pub fn update_multi_table_meta(&mut self, req: Vec) { + for r in req { + let UpdateTempTableReq { + table_id, + new_table_meta, + copied_files, + .. + } = r; + let table = self.id_to_table.get_mut(&table_id).unwrap(); + table.meta = new_table_meta; + table._copied_files = copied_files; + } + } } pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Result { @@ -223,7 +229,8 @@ pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Resu (Entry::Occupied(e), _) => { let dir = parse_storage_prefix(&e.get().meta.options, tb_id)?; let table = e.remove(); - guard.name_to_id.remove(&table.name).ok_or_else(|| { + let desc = format!("{}.{}", table.db_name, table.table_name); + guard.desc_to_id.remove(&desc).ok_or_else(|| { ErrorCode::Internal(format!( "Table not found in temp table manager {:?}, drop table request: {:?}", guard, req diff --git a/src/query/storages/common/session/src/transaction.rs b/src/query/storages/common/session/src/transaction.rs index 962ebfcc37d3..90d24431e68f 100644 --- a/src/query/storages/common/session/src/transaction.rs +++ b/src/query/storages/common/session/src/transaction.rs @@ -23,6 +23,7 @@ use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::UpdateMultiTableMetaReq; use databend_common_meta_app::schema::UpdateStreamMetaReq; use databend_common_meta_app::schema::UpdateTableMetaReq; +use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_meta_app::schema::UpsertTableCopiedFileReq; use databend_common_meta_app::tenant::Tenant; use databend_common_meta_types::MatchSeq; @@ -30,6 +31,8 @@ use parking_lot::Mutex; use serde::Deserialize; use serde::Serialize; +use crate::temp_table::TempTable; + #[derive(Debug, Clone)] pub struct TxnManager { state: TxnState, @@ -49,15 +52,15 @@ pub enum TxnState { #[derive(Debug, Clone, Default)] pub struct TxnBuffer { table_desc_to_id: HashMap, - mutated_tables: HashMap, copied_files: HashMap>, update_stream_meta: HashMap, deduplicated_labels: HashSet, - stream_tables: HashMap, - need_purge_files: Vec<(StageInfo, Vec)>, + + temp_table_desc_to_id: HashMap, + mutated_temp_tables: HashMap, } #[derive(Debug, Clone)] @@ -68,12 +71,7 @@ struct StreamSnapshot { impl TxnBuffer { fn clear(&mut self) { - self.table_desc_to_id.clear(); - self.mutated_tables.clear(); - self.copied_files.clear(); - self.update_stream_meta.clear(); - self.deduplicated_labels.clear(); - self.stream_tables.clear(); + std::mem::take(self); } fn update_multi_table_meta(&mut self, mut req: UpdateMultiTableMetaReq) { @@ -95,6 +93,18 @@ impl TxnBuffer { self.update_stream_metas(&req.update_stream_metas); self.deduplicated_labels.extend(req.deduplicated_labels); + + for req in req.update_temp_tables { + let (db_name, table_name) = req.desc.split_once('.').unwrap(); + self.temp_table_desc_to_id + .insert(req.desc.clone(), req.table_id); + self.mutated_temp_tables.insert(req.table_id, TempTable { + db_name: db_name.to_string(), + table_name: table_name.to_string(), + meta: req.new_table_meta.clone(), + _copied_files: req.copied_files.clone(), + }); + } } fn update_stream_metas(&mut self, reqs: &[UpdateStreamMetaReq]) { @@ -250,6 +260,17 @@ impl TxnManager { .iter() .cloned() .collect(), + update_temp_tables: self + .txn_buffer + .mutated_temp_tables + .iter() + .map(|(id, t)| UpdateTempTableReq { + table_id: *id, + new_table_meta: t.meta.clone(), + copied_files: t._copied_files.clone(), + desc: format!("'{}'.'{}'", t.db_name, t.table_name), + }) + .collect(), } } diff --git a/src/query/storages/fuse/src/operations/commit.rs b/src/query/storages/fuse/src/operations/commit.rs index 5dad0a6248b4..6427b640cea9 100644 --- a/src/query/storages/fuse/src/operations/commit.rs +++ b/src/query/storages/fuse/src/operations/commit.rs @@ -31,6 +31,7 @@ use databend_common_meta_app::schema::TableStatistics; use databend_common_meta_app::schema::UpdateMultiTableMetaReq; use databend_common_meta_app::schema::UpdateStreamMetaReq; use databend_common_meta_app::schema::UpdateTableMetaReq; +use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_meta_app::schema::UpsertTableCopiedFileReq; use databend_common_meta_types::MatchSeq; use databend_common_metrics::storage::*; @@ -48,6 +49,7 @@ use databend_storages_common_table_meta::meta::TableSnapshotStatistics; use databend_storages_common_table_meta::meta::Versioned; use databend_storages_common_table_meta::table::OPT_KEY_LEGACY_SNAPSHOT_LOC; use databend_storages_common_table_meta::table::OPT_KEY_SNAPSHOT_LOCATION; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use log::debug; use log::info; use log::warn; @@ -224,19 +226,36 @@ impl FuseTable { let table_id = table_info.ident.table_id; let table_version = table_info.ident.seq; - let req = UpdateTableMetaReq { - table_id, - seq: MatchSeq::Exact(table_version), - new_table_meta, - }; + let mut update_temp_tables = vec![]; + let mut update_table_metas = vec![]; + if new_table_meta.options.contains_key(OPT_KEY_TEMP_PREFIX) { + let req = UpdateTempTableReq { + table_id, + new_table_meta, + copied_files: copied_files + .as_ref() + .map(|c| c.file_info.clone()) + .unwrap_or_default(), + desc: table_info.desc.clone(), + }; + update_temp_tables.push(req); + } else { + let req = UpdateTableMetaReq { + table_id, + seq: MatchSeq::Exact(table_version), + new_table_meta, + }; + update_table_metas.push((req, table_info.clone())); + } // 3. let's roll catalog .update_multi_table_meta(UpdateMultiTableMetaReq { - update_table_metas: vec![(req, table_info.clone())], + update_table_metas, update_stream_metas: update_stream_meta.to_vec(), copied_files: copied_files.iter().map(|c| (table_id, c.clone())).collect(), deduplicated_labels: deduplicated_label.into_iter().collect(), + update_temp_tables, }) .await?; diff --git a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs index e6bae2027b98..bbf90d8d2640 100644 --- a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs @@ -30,6 +30,7 @@ use databend_common_expression::DataBlock; use databend_common_meta_app::schema::UpdateMultiTableMetaReq; use databend_common_meta_app::schema::UpdateStreamMetaReq; use databend_common_meta_app::schema::UpdateTableMetaReq; +use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_meta_types::MatchSeq; use databend_common_pipeline_sinks::AsyncSink; use databend_storages_common_session::TxnManagerRef; @@ -84,21 +85,31 @@ impl AsyncSink for CommitMultiTableInsert { #[async_backtrace::framed] async fn on_finish(&mut self) -> Result<()> { let mut update_table_metas = Vec::with_capacity(self.commit_metas.len()); + let mut update_temp_tables = Vec::with_capacity(self.commit_metas.len()); let mut snapshot_generators = HashMap::with_capacity(self.commit_metas.len()); for (table_id, commit_meta) in std::mem::take(&mut self.commit_metas).into_iter() { // generate snapshot let mut snapshot_generator = AppendGenerator::new(self.ctx.clone(), self.overwrite); snapshot_generator.set_conflict_resolve_context(commit_meta.conflict_resolve_context); let table = self.tables.get(&table_id).unwrap(); - update_table_metas.push(( - build_update_table_meta_req( - table.as_ref(), - &snapshot_generator, - self.ctx.txn_mgr(), - ) - .await?, - table.get_table_info().clone(), - )); + if table.is_temp() { + update_temp_tables.push(UpdateTempTableReq { + table_id, + new_table_meta: table.get_table_info().meta.clone(), + copied_files: Default::default(), + desc: table.get_table_info().desc.clone(), + }); + } else { + update_table_metas.push(( + build_update_table_meta_req( + table.as_ref(), + &snapshot_generator, + self.ctx.txn_mgr(), + ) + .await?, + table.get_table_info().clone(), + )); + } snapshot_generators.insert(table_id, snapshot_generator); } @@ -111,6 +122,7 @@ impl AsyncSink for CommitMultiTableInsert { copied_files: vec![], update_stream_metas: self.update_stream_meta.clone(), deduplicated_labels: self.deduplicated_label.clone().into_iter().collect(), + update_temp_tables: std::mem::take(&mut update_temp_tables), }; let update_meta_result = match self From cf3e7aac989a66be281083c9db689df750f79087 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 14 Aug 2024 21:28:01 +0800 Subject: [PATCH 21/51] fix get table meta by id --- .../catalog/src/catalog/session_catalog.rs | 2 +- .../common/session/src/transaction.rs | 32 +++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index b648078cfb41..f69fe84f4400 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -249,7 +249,7 @@ impl Catalog for SessionCatalog { if let Some(t) = { let guard = self.txn_mgr.lock(); if guard.is_active() { - guard.get_table_from_buffer_by_id(table_id) + guard.get_table_from_buffer_by_id(table_id, is_temp) } else { None } diff --git a/src/query/storages/common/session/src/transaction.rs b/src/query/storages/common/session/src/transaction.rs index 90d24431e68f..c8fe9ea0c954 100644 --- a/src/query/storages/common/session/src/transaction.rs +++ b/src/query/storages/common/session/src/transaction.rs @@ -19,6 +19,7 @@ use std::sync::Arc; use databend_common_meta_app::principal::StageInfo; use databend_common_meta_app::schema::TableCopiedFileInfo; +use databend_common_meta_app::schema::TableIdent; use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::UpdateMultiTableMetaReq; use databend_common_meta_app::schema::UpdateStreamMetaReq; @@ -211,17 +212,28 @@ impl TxnManager { .cloned() } - pub fn get_table_from_buffer_by_id(&self, table_id: u64) -> Option { - self.txn_buffer - .mutated_tables - .get(&table_id) - .cloned() - .or_else(|| { - self.txn_buffer - .stream_tables - .get(&table_id) - .map(|snapshot| snapshot.stream.clone()) + pub fn get_table_from_buffer_by_id(&self, table_id: u64, is_temp: bool) -> Option { + if is_temp { + self.txn_buffer.mutated_temp_tables.get(&table_id).map(|t| { + TableInfo::new( + &t.db_name, + &t.table_name, + TableIdent { table_id, seq: 0 }, + t.meta.clone(), + ) }) + } else { + self.txn_buffer + .mutated_tables + .get(&table_id) + .cloned() + .or_else(|| { + self.txn_buffer + .stream_tables + .get(&table_id) + .map(|snapshot| snapshot.stream.clone()) + }) + } } pub fn req(&self) -> UpdateMultiTableMetaReq { From 62afd0d958bf6ff937b6ec14d908d0ce7da421e7 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Thu, 15 Aug 2024 09:37:56 +0800 Subject: [PATCH 22/51] get_table --- .../service/tests/it/storages/fuse/conflict.rs | 3 +++ .../storages/common/session/src/transaction.rs | 14 ++++++++++++++ .../common/generators/snapshot_generator.rs | 6 +++++- .../common/processors/multi_table_insert_commit.rs | 1 + .../operations/common/processors/sink_commit.rs | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/query/service/tests/it/storages/fuse/conflict.rs b/src/query/service/tests/it/storages/fuse/conflict.rs index 746e9ebc1b09..5bcfe9d22887 100644 --- a/src/query/service/tests/it/storages/fuse/conflict.rs +++ b/src/query/service/tests/it/storages/fuse/conflict.rs @@ -65,6 +65,7 @@ fn test_unresolvable_delete_conflict() { None, TxnManager::init(), 0, + false, ); assert!(result.is_err()); } @@ -156,6 +157,7 @@ fn test_resolvable_delete_conflict() { None, TxnManager::init(), 0, + false, ); let snapshot = result.unwrap(); let expected = vec![("8".to_string(), 1), ("4".to_string(), 1)]; @@ -263,6 +265,7 @@ fn test_resolvable_replace_conflict() { None, TxnManager::init(), 0, + false, ); let snapshot = result.unwrap(); let expected = vec![ diff --git a/src/query/storages/common/session/src/transaction.rs b/src/query/storages/common/session/src/transaction.rs index c8fe9ea0c954..6fa1e43576b8 100644 --- a/src/query/storages/common/session/src/transaction.rs +++ b/src/query/storages/common/session/src/transaction.rs @@ -205,6 +205,20 @@ impl TxnManager { table_name: &str, ) -> Option { let desc = format!("'{}'.'{}'", db_name, table_name); + let temp_table_id = self.txn_buffer.temp_table_desc_to_id.get(&desc); + if let Some(id) = temp_table_id { + let table = self.txn_buffer.mutated_temp_tables.get(id).unwrap(); + return Some(TableInfo::new( + &table.db_name, + &table.table_name, + TableIdent { + table_id: *id, + seq: 0, + }, + table.meta.clone(), + )); + } + self.txn_buffer .table_desc_to_id .get(&desc) diff --git a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs index bf031d62fbf2..254ee710cb92 100644 --- a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs +++ b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs @@ -46,6 +46,7 @@ pub trait SnapshotGenerator { prev_table_seq: Option, txn_mgr: TxnManagerRef, table_id: u64, + is_temp: bool, ) -> Result { let mut snapshot = self.do_generate_new_snapshot(schema, cluster_key_meta, &previous, prev_table_seq)?; @@ -55,7 +56,10 @@ pub trait SnapshotGenerator { // NOTE: // When generating a new snapshot for a mutation of table for the first time, // there is no buffered table ID inside txn_mgr for this table. - guard.is_active() && guard.get_table_from_buffer_by_id(table_id).is_some() + guard.is_active() + && guard + .get_table_from_buffer_by_id(table_id, is_temp) + .is_some() }; if has_pending_transactional_mutations { diff --git a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs index bbf90d8d2640..c1fc8c1b10c9 100644 --- a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs @@ -257,6 +257,7 @@ async fn build_update_table_meta_req( Some(fuse_table.table_info.ident.seq), txn_mgr, table.get_id(), + table.is_temp(), )?; // write snapshot diff --git a/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs b/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs index 55f816e86cad..32c0bc714fe3 100644 --- a/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs @@ -288,6 +288,7 @@ where F: SnapshotGenerator + Send + 'static Some(table_info.ident.seq), self.ctx.txn_mgr(), table_info.ident.table_id, + self.table.is_temp(), ) { Ok(snapshot) => { self.state = State::TryCommit { From 0e9985125e3276902edadabb70bd1fb6311b299b Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Thu, 15 Aug 2024 09:54:00 +0800 Subject: [PATCH 23/51] fix missing header --- src/query/service/src/sessions/session_ctx.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/query/service/src/sessions/session_ctx.rs b/src/query/service/src/sessions/session_ctx.rs index 212072337e98..8386a7244ce6 100644 --- a/src/query/service/src/sessions/session_ctx.rs +++ b/src/query/service/src/sessions/session_ctx.rs @@ -11,6 +11,7 @@ // 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::collections::HashMap; use std::collections::HashSet; use std::sync::atomic::AtomicBool; From c0a8a0b1d009177a25656973ec033b74c70f509f Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Fri, 16 Aug 2024 00:55:33 +0800 Subject: [PATCH 24/51] add create table test --- scripts/ci/ci-run-sqllogic-tests.sh | 3 +- .../interpreters/interpreter_table_create.rs | 1 + src/query/service/src/sessions/query_ctx.rs | 4 +- src/query/sql/src/planner/binder/ddl/table.rs | 5 + .../suites/mysql/create_temp_tables.sql | 575 ++++++++++++++++++ 5 files changed, 585 insertions(+), 3 deletions(-) create mode 100644 tests/sqllogictests/suites/mysql/create_temp_tables.sql diff --git a/scripts/ci/ci-run-sqllogic-tests.sh b/scripts/ci/ci-run-sqllogic-tests.sh index 83e7b6696af3..ea33427e1793 100755 --- a/scripts/ci/ci-run-sqllogic-tests.sh +++ b/scripts/ci/ci-run-sqllogic-tests.sh @@ -19,4 +19,5 @@ fi echo "Run suites using argument: $RUN_DIR" echo "Starting databend-sqllogic tests" -target/${BUILD_PROFILE}/databend-sqllogictests --handlers ${TEST_HANDLERS} ${RUN_DIR} --skip_dir management,explain_native,ee --enable_sandbox --parallel 8 +target/${BUILD_PROFILE}/databend-sqllogictests --handlers "mysql" --run_dir mysql --enable_sandbox --parallel 8 +target/${BUILD_PROFILE}/databend-sqllogictests --handlers ${TEST_HANDLERS} ${RUN_DIR} --skip_dir management,explain_native,ee,mysql --enable_sandbox --parallel 8 diff --git a/src/query/service/src/interpreters/interpreter_table_create.rs b/src/query/service/src/interpreters/interpreter_table_create.rs index f002b11dba46..7d8463863087 100644 --- a/src/query/service/src/interpreters/interpreter_table_create.rs +++ b/src/query/service/src/interpreters/interpreter_table_create.rs @@ -521,6 +521,7 @@ pub static CREATE_TABLE_OPTIONS: LazyLock> = LazyLock::new r.insert(OPT_KEY_RANDOM_SEED); r.insert("transient"); + r.insert(OPT_KEY_TEMP_PREFIX); r }); diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index 20830c5bab02..7eab42a1861a 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -36,8 +36,8 @@ use databend_common_base::base::ProgressValues; use databend_common_base::runtime::profile::Profile; use databend_common_base::runtime::profile::ProfileStatisticsName; use databend_common_base::runtime::TrySpawn; -use databend_common_catalog::catalog::CATALOG_DEFAULT; use databend_common_base::JoinHandle; +use databend_common_catalog::catalog::CATALOG_DEFAULT; use databend_common_catalog::lock::LockTableOption; use databend_common_catalog::merge_into_join::MergeIntoJoin; use databend_common_catalog::plan::DataSourceInfo; @@ -1327,7 +1327,7 @@ impl TableContext for QueryContext { } fn get_session_id(&self) -> String { - todo!() + self.shared.session.id.clone() } fn is_temp_table(&self, catalog_name: &str, database_name: &str, table_name: &str) -> bool { diff --git a/src/query/sql/src/planner/binder/ddl/table.rs b/src/query/sql/src/planner/binder/ddl/table.rs index 88d650840128..516ee590d109 100644 --- a/src/query/sql/src/planner/binder/ddl/table.rs +++ b/src/query/sql/src/planner/binder/ddl/table.rs @@ -482,6 +482,11 @@ impl Binder { let _ = options.insert("TRANSIENT".to_owned(), "T".to_owned()); } TableType::Temporary => { + if engine != Engine::Fuse { + return Err(ErrorCode::BadArguments( + "Temporary table is only supported for FUSE engine", + )); + } let _ = options.insert(OPT_KEY_TEMP_PREFIX.to_string(), self.ctx.get_session_id()); } }; diff --git a/tests/sqllogictests/suites/mysql/create_temp_tables.sql b/tests/sqllogictests/suites/mysql/create_temp_tables.sql new file mode 100644 index 000000000000..18f841a18cfc --- /dev/null +++ b/tests/sqllogictests/suites/mysql/create_temp_tables.sql @@ -0,0 +1,575 @@ +statement ok +DROP TABLE IF EXISTS t + +statement ok +DROP TABLE IF EXISTS t2 + +statement ok +DROP TABLE IF EXISTS t3 + +statement ok +DROP TABLE IF EXISTS t4 + +statement ok +CREATE TEMPORARY TABLE t(c1 int) + +statement ok +CREATE TEMP TABLE IF NOT EXISTS t(c1 int) + +statement error 2302 +CREATE TEMP TABLE t(c1 int) + +statement ok +create temp table t2(a int,b int) Engine = Fuse + +statement ok +insert into t2 values(1,1),(2,2) + +query I +select a+b from t2 +---- +2 +4 + +statement error 2302 +create temp table t2(a int,b int) Engine = Fuse + +statement error 2302 +create temp table t2(a int,b int) Engine = Fuse + +statement error 1005 +create temp table t2(a INT auto_increment) + +statement error 1105 +create temp table t3(a int,b int) engine=null + +statement ok +create temp table t3(`a` int) + +statement ok +create temp table t4(a int) + +statement ok +DROP TABLE IF EXISTS t + +statement ok +DROP TABLE IF EXISTS t2 + +statement ok +DROP TABLE IF EXISTS t3 + +statement ok +DROP TABLE IF EXISTS t4 + +statement ok +DROP DATABASE IF EXISTS db1 + +statement ok +DROP DATABASE IF EXISTS db2 + +statement ok +CREATE DATABASE db1 + +statement ok +CREATE DATABASE db2 + +statement ok +CREATE TEMP TABLE db1.test1(a INT not null, b INT null) Engine = Fuse + +statement ok +INSERT INTO db1.test1 VALUES (1, 2), (2, 3), (3, 4) + +query I +select * from db1.test1 +---- +1 2 +2 3 +3 4 + +statement ok +CREATE TEMP TABLE db2.test2 LIKE db1.test1 ENGINE=fuse + +statement ok +INSERT INTO db2.test2 VALUES (3, 5) + +query I +SELECT a+b FROM db2.test2 +---- +8 + +query TTTTT +DESCRIBE db2.test2 +---- +a INT NO 0 (empty) +b INT YES NULL (empty) + +statement ok +CREATE TEMP TABLE db2.test3(a Varchar null, y Varchar null) ENGINE=fuse AS SELECT * FROM db1.test1 + +query TTTTT +DESCRIBE db2.test3 +---- +a VARCHAR YES NULL (empty) +y VARCHAR YES NULL (empty) + +query T +SELECT a FROM db2.test3 +---- +1 +2 +3 + +statement ok +CREATE TEMP TABLE db2.test4(a Varchar null, y Varchar null) ENGINE=fuse AS SELECT b, a FROM db1.test1 + +statement ok +CREATE TEMP TABLE if not exists db2.test4 AS SELECT b, a FROM db1.test1 + +statement ok +CREATE TEMP TABLE if not exists db2.test4 AS SELECT b, a FROM db1.test1 + +query TTTTT +DESCRIBE db2.test4 +---- +a VARCHAR YES NULL (empty) +y VARCHAR YES NULL (empty) + +query T +SELECT a FROM db2.test4 +---- +2 +3 +4 + +statement error 1 +CREATE TEMP TABLE db2.test5(a Varchar null, y Varchar null) ENGINE=fuse AS SELECT b FROM db1.test1 + +statement error 1006 +CREATE TEMP TABLE db2.test5(a Varchar null, y Varchar null) ENGINE=fuse AS SELECT a, b, a FROM db1.test1 + +statement ok +create temp table db2.test55(id Int8, created timestamp not null DEFAULT CURRENT_TIMESTAMP) + +statement ok +insert into db2.test55(id) select number % 3 from numbers(1000) + +statement ok +insert into db2.test55(id) select number % 3 from numbers(1000) + +query I +select count(distinct created) > 1 from db2.test55; +---- +1 + +statement error 1065 +create temp table db2.test6(id Int8, created timestamp DEFAULT today() + a) + +statement ok +create temp table db2.test6(id Int8 not null, a Int8 not null DEFAULT 1 + 2, created timestamp not null DEFAULT now()) + +query TTTTT +desc db2.test6 +---- +id TINYINT NO 0 (empty) +a TINYINT NO 3 (empty) +created TIMESTAMP NO now() (empty) + +statement ok +INSERT INTO db2.test6 (id) VALUES (1) + +query IIT +SELECT id, a, now() >= created FROM db2.test6; +---- +1 3 1 + +statement ok +alter table db2.test6 add column b timestamp default now() + +statement ok +create temp table db2.test7(tiny TINYINT(10) not null, tiny_unsigned TINYINT(10) UNSIGNED not null, smallint SMALLINT not null, smallint_unsigned SMALLINT UNSIGNED not null, int INT32(15) not null, int_unsigned UINT32(15) not null, bigint BIGINT not null, bigint_unsigned BIGINT UNSIGNED not null,float FLOAT not null, double DOUBLE not null, date DATE not null, datetime DATETIME not null, ts TIMESTAMP not null, str VARCHAR not null default '3', bool BOOLEAN not null, arr ARRAY(INT) not null, tup TUPLE(INT, BOOL) not null, map MAP(INT, STRING) not null, bitmap BITMAP not null, variant VARIANT not null) + +query TTTTT +desc db2.test7 +---- +tiny TINYINT NO 0 (empty) +tiny_unsigned TINYINT UNSIGNED NO 0 (empty) +smallint SMALLINT NO 0 (empty) +smallint_unsigned SMALLINT UNSIGNED NO 0 (empty) +int INT NO 0 (empty) +int_unsigned INT UNSIGNED NO 0 (empty) +bigint BIGINT NO 0 (empty) +bigint_unsigned BIGINT UNSIGNED NO 0 (empty) +float FLOAT NO 0 (empty) +double DOUBLE NO 0 (empty) +date DATE NO '1970-01-01' (empty) +datetime TIMESTAMP NO '1970-01-01 00:00:00.000000' (empty) +ts TIMESTAMP NO '1970-01-01 00:00:00.000000' (empty) +str VARCHAR NO '3' (empty) +bool BOOLEAN NO false (empty) +arr ARRAY(INT32) NO [] (empty) +tup TUPLE(1 INT32, 2 BOOLEAN) NO (NULL, NULL) (empty) +map MAP(INT32, STRING) NO {} (empty) +bitmap BITMAP NO '' (empty) +variant VARIANT NO 'null' (empty) + +statement ok +create transient table db2.test8(tiny TINYINT not null, tiny_unsigned TINYINT UNSIGNED not null, smallint SMALLINT not null, smallint_unsigned SMALLINT UNSIGNED not null, int INT not null, int_unsigned INT UNSIGNED not null, bigint BIGINT not null, bigint_unsigned BIGINT UNSIGNED not null,float FLOAT not null, double DOUBLE not null, date DATE not null, datetime DATETIME not null, ts TIMESTAMP not null, str VARCHAR not null default '3', bool BOOLEAN not null, arr ARRAY(VARCHAR) not null, tup TUPLE(DOUBLE, INT) not null, map MAP(STRING, Date) not null, bitmap BITMAP not null, variant VARIANT not null) + +query TTTTT +desc db2.test8 +---- +tiny TINYINT NO 0 (empty) +tiny_unsigned TINYINT UNSIGNED NO 0 (empty) +smallint SMALLINT NO 0 (empty) +smallint_unsigned SMALLINT UNSIGNED NO 0 (empty) +int INT NO 0 (empty) +int_unsigned INT UNSIGNED NO 0 (empty) +bigint BIGINT NO 0 (empty) +bigint_unsigned BIGINT UNSIGNED NO 0 (empty) +float FLOAT NO 0 (empty) +double DOUBLE NO 0 (empty) +date DATE NO '1970-01-01' (empty) +datetime TIMESTAMP NO '1970-01-01 00:00:00.000000' (empty) +ts TIMESTAMP NO '1970-01-01 00:00:00.000000' (empty) +str VARCHAR NO '3' (empty) +bool BOOLEAN NO false (empty) +arr ARRAY(STRING) NO [] (empty) +tup TUPLE(1 FLOAT64, 2 INT32) NO (NULL, NULL) (empty) +map MAP(STRING, DATE) NO {} (empty) +bitmap BITMAP NO '' (empty) +variant VARIANT NO 'null' (empty) + + +statement ok +use db2 + +statement ok +create temp table test9 like test8 + +statement ok +create temp table test10(a int, b tuple(int, int) default (1, 2), c array(int) default [10,20]) + +query TTTTT +desc test10 +---- +a INT YES NULL (empty) +b TUPLE(1 INT32, 2 INT32) YES (1, 2) (empty) +c ARRAY(INT32) YES [10, 20] (empty) + +statement ok +insert into test10 (a) values (100),(200) + +query ITT +select * from test10 +---- +100 (1,2) [10,20] +200 (1,2) [10,20] + +statement ok +use default + +statement ok +DROP DATABASE db1 + +statement ok +DROP DATABASE db2 + +statement error 1002 +CREATE TEMP TABLE system.test(a INT) + +statement ok +drop table if exists t + +statement error Duplicated column name +create temp table t(a int, a int) + +statement error Duplicated column name +create temp table t(a int, A int) + +statement error Duplicated column name +create temp table t as select number, number from numbers(1) + +statement error 1006 +create temp table t as select 'a' as c1, null as c2; + +statement error 4000 +create temp table tb101 (id int ,c1 datetime) 's3://wubx/tb101' connection=(aws_key_id='minioadmin' aws_ssecret_key='minioadmin' endpoint_url='http://127.0.0.1:9900'); + +statement ok +drop table if exists tt_v2 + +statement error 3001 +create temp table tt_v2 (id int) engine=fuse SNAPSHOT_LOCATION='xx' + +statement error 1301 +create temp table t(a int) x=x + +statement error 1301 +create temp table t(a int) external_location='xxx' + +statement error 1301 +create temp table t(a int) snapshot_loc='xxx' + +statement error 3001 +create temp table t(a int) snapshot_location='xxx' + +statement error 1301 +create temp table t(a int) database_id='xxx' + +statement error 1006 +create temp table t(a int) bloom_index_columns='b' + +statement error 1301 +create temp table t(a decimal(4,2)) bloom_index_columns='a' + +statement ok +create temp table t(a int) + +statement error 1301 +alter table t set options(database_id = "22"); + +statement ok +drop table if exists t; + +statement ok +drop table if exists t_without_engine_desc; + +statement ok +drop table if exists t_with_engine_desc; + +statement ok +drop table if exists t_with_wrong_engine_desc; + +statement ok +create temp table t_without_engine_desc(id int); + +statement ok +create temp table t_with_engine_desc(id int) + +statement error 2302 +create temp table t_with_engine_desc(id int); + +statement error 2302 +create temp table t_with_engine_desc(id int) + +statement error 1005 +create temp table t_with_wrong_engine_desc(id int) engine=abc; + +statement ok +drop table if exists t_without_engine_desc; + +statement ok +drop table if exists t_with_engine_desc; + +statement ok +drop table if exists t_with_wrong_engine_desc; + +statement ok +drop table if exists t_with_bloom_index; + +statement ok +create temp table t_with_bloom_index(a int, b int) bloom_index_columns='b' + +statement ok +drop table if exists t_row_per_block; + +statement error 1301 +create temp table t_row_per_block(a int) row_per_block = 100000000000; + +statement ok +create temp table t_row_per_block(a int) row_per_block = 10000; + +statement error 1301 +alter table t_row_per_block set options(row_per_block = 100000000000); + +statement ok +alter table t_row_per_block set options(row_per_block = 100000); + +statement ok +drop table if exists t_nested + +statement ok +create temp table t_nested(a int, b array(int not null), c array(int null), d map(string, int null), e map(string, string not null), f tuple(int null, string not null, array(int null), array(string not null))) + +query TTTTT +desc t_nested +---- +a INT YES NULL (empty) +b ARRAY(INT32) YES NULL (empty) +c ARRAY(INT32) YES NULL (empty) +d MAP(STRING, INT32) YES NULL (empty) +e MAP(STRING, STRING) YES NULL (empty) +f TUPLE(1 INT32, 2 STRING, 3 ARRAY(INT32), 4 ARRAY(STRING)) YES NULL (empty) + +statement ok +drop table if exists replace_test; + +statement ok +create temp table replace_test(a int); + +statement ok +insert into replace_test values(1); + +query I +select a from replace_test; +---- +1 + +statement error 1005 +create or replace temp table IF NOT EXISTS replace_test(b int); + +statement ok +create or replace temp table replace_test(b int); + +statement error 1065 +select a from replace_test; + +statement ok +drop table if exists t_default + +statement ok +create temp table t_default(a int, b bitmap not null default '1,2', c variant not null default '{"k":"v"}') + +query TTTTT +desc t_default +---- +a INT YES NULL (empty) +b BITMAP NO '1,2' (empty) +c VARIANT NO '{"k":"v"}' (empty) + +statement ok +insert into t_default (a) values(1),(2) + +query ITT +select a, to_string(b), c from t_default +---- +1 1,2 {"k":"v"} +2 1,2 {"k":"v"} + +statement ok +drop table if exists crt1 + +statement ok +create or replace temp table crt1 as select * from numbers(10); + +query I +select count(*) from crt1; +---- +10 + +statement ok +create or replace temp table crt1 as select * from numbers(10); + +query I +select count(*) from crt1; +---- +10 + +statement ok +drop table if exists crt1 + +### Atomic CTAS ### + +# CASE: no (visible)table should be created if anything fails +statement error 1006 +create temp table t as select number/0 from numbers(1); + +# table t should not be created +# expects: ERROR 1105 (HY000): UnknownTable. Code: 1025, Text = error: ... +statement error 1025 +select * from t; + + +# CASE: create or replace + +# normal case +statement ok +create or replace temp table t as select * from numbers(1); + +query I +select count(*) from t; +---- +1 + +statement ok +create or replace temp table t as select * from numbers(2); + +query I +select count(*) from t; +---- +2 + +statement ok +drop table t; + +# replace exists table which created with plain create stmt: +# table t should be replaced, (schema also changed) + +statement ok +create temp table t(c int); + +statement ok +insert into table t values(-1); + +statement ok +create or replace temp table t as select * from numbers(2); + +query I +select * from t order by number; +---- +0 +1 + +statement ok +drop table t; + +# create or replace failed: +# table should not be replaced if anything fails + +statement ok +create or replace temp table t as select * from numbers(1); + +# table t should not be replaced +statement error 1006 +create or replace temp table t as select number/0 from numbers(2); + +query I +select * from t order by number; +---- +0 + +statement ok +drop table t + +# CASE: create if not exist + +# brand new table + +statement ok +create temp table if not exists t as select * from numbers(100); + +query I +select count(*) from t; +---- +100 + + +# table exists + +statement ok +create temp table if not exists t as select * from numbers(1); + +# table not changed +query I +select count(*) from t; +---- +100 + +statement ok +drop table t + +statement error 1081.*is not deterministic +create temp table t(a int) cluster by (a+rand()) + +statement error 1081.*is not deterministic +create temp table t(a string) cluster by (a+uuid()) From b4877955f64c777587529d6c6002d5eec8bd1828 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Fri, 16 Aug 2024 01:13:10 +0800 Subject: [PATCH 25/51] rename folder --- scripts/ci/ci-run-sqllogic-tests.sh | 4 ++-- .../suites/{mysql => temp_table}/create_temp_tables.sql | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/sqllogictests/suites/{mysql => temp_table}/create_temp_tables.sql (100%) diff --git a/scripts/ci/ci-run-sqllogic-tests.sh b/scripts/ci/ci-run-sqllogic-tests.sh index ea33427e1793..fe0500889e51 100755 --- a/scripts/ci/ci-run-sqllogic-tests.sh +++ b/scripts/ci/ci-run-sqllogic-tests.sh @@ -19,5 +19,5 @@ fi echo "Run suites using argument: $RUN_DIR" echo "Starting databend-sqllogic tests" -target/${BUILD_PROFILE}/databend-sqllogictests --handlers "mysql" --run_dir mysql --enable_sandbox --parallel 8 -target/${BUILD_PROFILE}/databend-sqllogictests --handlers ${TEST_HANDLERS} ${RUN_DIR} --skip_dir management,explain_native,ee,mysql --enable_sandbox --parallel 8 +target/${BUILD_PROFILE}/databend-sqllogictests --handlers "mysql" --run_dir temp_table --enable_sandbox --parallel 8 +target/${BUILD_PROFILE}/databend-sqllogictests --handlers ${TEST_HANDLERS} ${RUN_DIR} --skip_dir management,explain_native,ee,temp_table --enable_sandbox --parallel 8 diff --git a/tests/sqllogictests/suites/mysql/create_temp_tables.sql b/tests/sqllogictests/suites/temp_table/create_temp_tables.sql similarity index 100% rename from tests/sqllogictests/suites/mysql/create_temp_tables.sql rename to tests/sqllogictests/suites/temp_table/create_temp_tables.sql From cfedf7dae4dce7b0703c1b7d54bffd967cffd83a Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Fri, 16 Aug 2024 14:35:09 +0800 Subject: [PATCH 26/51] commit before refactor --- src/query/catalog/src/catalog/interface.rs | 18 +++++- .../catalog/src/catalog/session_catalog.rs | 1 + .../interpreters/interpreter_table_create.rs | 5 ++ src/query/service/src/sessions/query_ctx.rs | 4 ++ .../storages/common/session/src/temp_table.rs | 63 ++++++++----------- 5 files changed, 53 insertions(+), 38 deletions(-) diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index 997a2b443edf..0103f8e93b7a 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -92,6 +92,7 @@ use databend_common_meta_app::schema::UpdateMultiTableMetaResult; use databend_common_meta_app::schema::UpdateStreamMetaReq; use databend_common_meta_app::schema::UpdateTableMetaReply; use databend_common_meta_app::schema::UpdateTableMetaReq; +use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_meta_app::schema::UpdateVirtualColumnReply; use databend_common_meta_app::schema::UpdateVirtualColumnReq; use databend_common_meta_app::schema::UpsertTableOptionReply; @@ -102,6 +103,7 @@ use databend_common_meta_store::MetaStore; use databend_common_meta_types::anyerror::func_name; use databend_common_meta_types::MetaId; use databend_common_meta_types::SeqV; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use dyn_clone::DynClone; use crate::database::Database; @@ -356,8 +358,22 @@ pub trait Catalog: DynClone + Send + Sync + Debug { req: UpdateTableMetaReq, table_info: &TableInfo, ) -> Result { + let mut update_table_metas = vec![]; + let mut update_temp_tables = vec![]; + if table_info.meta.options.contains_key(OPT_KEY_TEMP_PREFIX) { + let req = UpdateTempTableReq { + table_id: req.table_id, + desc: table_info.desc.clone(), + new_table_meta: req.new_table_meta, + copied_files: Default::default(), + }; + update_temp_tables.push(req); + } else { + update_table_metas.push((req, table_info.clone())); + } self.update_multi_table_meta(UpdateMultiTableMetaReq { - update_table_metas: vec![(req, table_info.clone())], + update_table_metas, + update_temp_tables, ..Default::default() }) .await diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/catalog/src/catalog/session_catalog.rs index f69fe84f4400..45b8bf5ebe72 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/catalog/src/catalog/session_catalog.rs @@ -410,6 +410,7 @@ impl Catalog for SessionCatalog { match state { TxnState::AutoCommit => { let update_temp_tables = std::mem::take(&mut req.update_temp_tables); + println!("{:?}", update_temp_tables); let reply = self.inner.retryable_update_multi_table_meta(req).await?; self.temp_tbl_mgr .lock() diff --git a/src/query/service/src/interpreters/interpreter_table_create.rs b/src/query/service/src/interpreters/interpreter_table_create.rs index 7d8463863087..e8f0935d8227 100644 --- a/src/query/service/src/interpreters/interpreter_table_create.rs +++ b/src/query/service/src/interpreters/interpreter_table_create.rs @@ -194,6 +194,8 @@ impl CreateTableInterpreter { req.table_meta.drop_on = Some(Utc::now()); let table_meta = req.table_meta.clone(); let reply = catalog.create_table(req.clone()).await?; + println!("create table as select"); + println!("{:?}", self.ctx.session_state().temp_tbl_mgr); if !reply.new_table && self.plan.create_option != CreateOption::CreateOrReplace { return Ok(PipelineBuildResult::create()); } @@ -288,9 +290,11 @@ impl CreateTableInterpreter { // // If the un-drop fails, data inserted and the table will be invisible, and available for vacuum. + let ctx = self.ctx.clone(); pipeline .main_pipeline .lift_on_finished(move |info: &ExecutionInfo| { + println!("{:?}", ctx.session_state().temp_tbl_mgr); let qualified_table_name = format!("{}.{}", db_name, table_name); if info.res.is_ok() { @@ -317,6 +321,7 @@ impl CreateTableInterpreter { info!("create {} as select failed. {:?}", qualified_table_name, e); e })?; + println!("{:?}", ctx.session_state().temp_tbl_mgr); } Ok(()) diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index 7eab42a1861a..16861bdc6019 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -1317,6 +1317,10 @@ impl TableContext for QueryContext { return Ok(None); } + if tbl.is_temp() { + return Ok(None); + } + // Add table lock. let table_lock = LockManager::create_table_lock(tbl.get_table_info().clone())?; match lock_opt { diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 754125a82c4b..c52319243f8f 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -40,7 +40,7 @@ use parking_lot::Mutex; #[derive(Debug, Clone)] pub struct TempTblMgr { - desc_to_id: HashMap, + name_to_id: HashMap, id_to_table: HashMap, next_id: u64, } @@ -56,7 +56,7 @@ pub struct TempTable { impl TempTblMgr { pub fn init() -> Arc> { Arc::new(Mutex::new(TempTblMgr { - desc_to_id: HashMap::new(), + name_to_id: HashMap::new(), id_to_table: HashMap::new(), next_id: 0, })) @@ -65,17 +65,11 @@ impl TempTblMgr { pub fn create_table(&mut self, req: CreateTableReq) -> Result { let CreateTableReq { create_option, - mut name_ident, + name_ident, table_meta, as_dropped, } = req; - let orphan_table_name = match as_dropped { - true => { - name_ident.table_name = format!("orphan@{}", name_ident.table_name); - Some(name_ident.table_name.clone()) - } - false => None, - }; + let orphan_table_name = as_dropped.then(|| format!("orphan@{}", name_ident.table_name)); let Some(db_id) = table_meta.options.get(OPT_KEY_DATABASE_ID) else { return Err(ErrorCode::Internal(format!( "Database id not set in table options" @@ -83,32 +77,24 @@ impl TempTblMgr { }; let db_id = db_id.parse::()?; let desc = format!("{}.{}", name_ident.db_name, name_ident.table_name); - let new_table = match (self.desc_to_id.entry(desc.clone()), create_option) { - (Entry::Occupied(_), CreateOption::Create) => { + let table_id = self.next_id; + let new_table = match (self.name_to_id.contains_key(&desc), create_option) { + (true, CreateOption::Create) => { return Err(ErrorCode::TableAlreadyExists(format!( "Temporary table {} already exists", desc ))); } - (Entry::Occupied(mut e), CreateOption::CreateOrReplace) => { - let table_id = self.next_id; - e.insert(table_id); - self.id_to_table.insert(table_id, TempTable { - db_name: name_ident.db_name, - table_name: name_ident.table_name, - meta: table_meta, - _copied_files: BTreeMap::new(), - }); - self.next_id += 1; - true - } - (Entry::Occupied(_), CreateOption::CreateIfNotExists) => false, - (Entry::Vacant(e), _) => { - let table_id = self.next_id; - e.insert(table_id); + (true, CreateOption::CreateIfNotExists) => false, + _ => { + let desc = orphan_table_name + .as_ref() + .map(|o| format!("{}.{}", name_ident.db_name, o)) + .unwrap_or(desc); + self.name_to_id.insert(desc, table_id); self.id_to_table.insert(table_id, TempTable { db_name: name_ident.db_name, - table_name: name_ident.table_name, + table_name: orphan_table_name.clone().unwrap_or(name_ident.table_name), meta: table_meta, _copied_files: BTreeMap::new(), }); @@ -117,7 +103,7 @@ impl TempTblMgr { } }; Ok(CreateTableReply { - table_id: 0, + table_id, table_id_seq: Some(0), db_id, new_table, @@ -137,9 +123,12 @@ impl TempTblMgr { req.orphan_table_name.as_ref().unwrap() ); let desc = format!("{}.{}", req.name_ident.db_name, req.name_ident.table_name); - match self.desc_to_id.remove(&orphan_desc) { + match self.name_to_id.remove(&orphan_desc) { Some(id) => { - self.desc_to_id.insert(desc, id); + self.name_to_id.insert(desc, id); + let table = self.id_to_table.get_mut(&id).unwrap(); + table.db_name = req.name_ident.db_name.clone(); + table.table_name = req.name_ident.table_name.clone(); Ok(Some(CommitTableMetaReply {})) } None => Ok(None), @@ -154,10 +143,10 @@ impl TempTblMgr { new_table_name, } = req; let desc = format!("{}.{}", name_ident.db_name, name_ident.table_name); - match self.desc_to_id.remove(&desc) { + match self.name_to_id.remove(&desc) { Some(id) => { let new_desc = format!("{}.{}", new_db_name, new_table_name); - self.desc_to_id.insert(new_desc, id); + self.name_to_id.insert(new_desc, id); let table = self.id_to_table.get_mut(&id).unwrap(); table.db_name = new_db_name.clone(); table.table_name = new_table_name.clone(); @@ -180,12 +169,12 @@ impl TempTblMgr { pub fn is_temp_table(&self, database_name: &str, table_name: &str) -> bool { let desc = format!("{}.{}", database_name, table_name); - self.desc_to_id.contains_key(&desc) + self.name_to_id.contains_key(&desc) } pub fn get_table(&self, database_name: &str, table_name: &str) -> Result> { let desc = format!("{}.{}", database_name, table_name); - let id = self.desc_to_id.get(&desc); + let id = self.name_to_id.get(&desc); let Some(id) = id else { return Ok(None); }; @@ -230,7 +219,7 @@ pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Resu let dir = parse_storage_prefix(&e.get().meta.options, tb_id)?; let table = e.remove(); let desc = format!("{}.{}", table.db_name, table.table_name); - guard.desc_to_id.remove(&desc).ok_or_else(|| { + guard.name_to_id.remove(&desc).ok_or_else(|| { ErrorCode::Internal(format!( "Table not found in temp table manager {:?}, drop table request: {:?}", guard, req From c8768c6776bc130b3e6cce972083305841fd8aaf Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sat, 17 Aug 2024 11:53:05 +0800 Subject: [PATCH 27/51] refactor --- src/meta/api/src/schema_api_test_suite.rs | 14 -- src/meta/api/src/share_api_test_suite.rs | 2 - src/meta/app/src/schema/table.rs | 2 - src/meta/binaries/metabench/main.rs | 1 - src/query/catalog/src/catalog/interface.rs | 18 +-- src/query/catalog/src/catalog/manager.rs | 6 +- src/query/catalog/src/catalog/mod.rs | 1 - src/query/catalog/src/table.rs | 11 +- src/query/ee/src/stream/handler.rs | 1 - src/query/service/Cargo.toml | 1 - .../src/catalogs/default/database_catalog.rs | 152 ++++++++---------- .../src/catalogs/default/immutable_catalog.rs | 16 +- src/query/service/src/catalogs/default/mod.rs | 3 +- .../src/catalogs/default/mutable_catalog.rs | 12 +- .../src/catalogs/default}/session_catalog.rs | 85 +++++----- src/query/service/src/catalogs/mod.rs | 1 - .../src/catalogs/share/share_catalog.rs | 12 +- .../service/src/interpreters/common/grant.rs | 6 +- .../interpreters/interpreter_table_drop.rs | 1 - .../src/interpreters/interpreter_view_drop.rs | 1 - .../src/servers/admin/v1/stream_status.rs | 2 +- .../table_functions/table_function_factory.rs | 4 +- .../tests/it/catalogs/database_catalog.rs | 1 - .../it/databases/system/system_database.rs | 4 +- .../tests/it/sql/exec/get_table_bind_test.rs | 16 +- .../tests/it/storages/fuse/conflict.rs | 3 - .../it/storages/fuse/operations/commit.rs | 16 +- .../storages/common/session/src/temp_table.rs | 63 ++++++-- .../common/session/src/transaction.rs | 32 ++-- .../storages/common/table_meta/src/lib.rs | 1 + .../common/table_meta/src}/table_id_ranges.rs | 7 +- .../common/generators/snapshot_generator.rs | 6 +- .../processors/multi_table_insert_commit.rs | 1 - .../common/processors/sink_commit.rs | 1 - .../storages/hive/hive/src/hive_catalog.rs | 12 +- src/query/storages/iceberg/src/catalog.rs | 12 +- src/query/storages/stream/src/stream_table.rs | 4 +- 37 files changed, 232 insertions(+), 299 deletions(-) rename src/query/{catalog/src/catalog => service/src/catalogs/default}/session_catalog.rs (90%) rename src/query/{service/src/catalogs/default => storages/common/table_meta/src}/table_id_ranges.rs (84%) diff --git a/src/meta/api/src/schema_api_test_suite.rs b/src/meta/api/src/schema_api_test_suite.rs index bb39756f7c68..cf4903e749ec 100644 --- a/src/meta/api/src/schema_api_test_suite.rs +++ b/src/meta/api/src/schema_api_test_suite.rs @@ -1514,7 +1514,6 @@ impl SchemaApiTestSuite { db_id, table_name: table_name.to_string(), tb_id: table_id, - is_temp: false, }) .await?; @@ -1845,7 +1844,6 @@ impl SchemaApiTestSuite { db_id, table_name: tbl_name.to_string(), tb_id, - is_temp: false, }; mt.drop_table_by_id(plan.clone()).await?; @@ -1876,7 +1874,6 @@ impl SchemaApiTestSuite { db_id, table_name: tbl_name.to_string(), tb_id, - is_temp: false, }; let res = mt.drop_table_by_id(plan).await; let err = res.unwrap_err(); @@ -1896,7 +1893,6 @@ impl SchemaApiTestSuite { db_id, table_name: tbl_name.to_string(), tb_id, - is_temp: false, }; mt.drop_table_by_id(plan.clone()).await?; } @@ -4151,7 +4147,6 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, - is_temp: false, }) .await?; } @@ -4177,7 +4172,6 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, - is_temp: false, }) .await?; let table_id = resp.table_id; @@ -4252,7 +4246,6 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, - is_temp: false, }) .await?; } @@ -4279,7 +4272,6 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, - is_temp: false, }) .await?; let table_id = resp.table_id; @@ -4454,7 +4446,6 @@ impl SchemaApiTestSuite { db_id, table_name: req.name_ident.table_name.clone(), tb_id: resp.table_id, - is_temp: false, }) .await?; } @@ -4695,7 +4686,6 @@ impl SchemaApiTestSuite { db_id: old_db.ident.db_id, table_name: tbl_name_ident.table_name.clone(), tb_id, - is_temp: false, }) .await?; let cur_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -4747,7 +4737,6 @@ impl SchemaApiTestSuite { db_id: old_db.ident.db_id, table_name: tbl_name.to_string(), tb_id, - is_temp: false, }) .await?; let cur_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -4805,7 +4794,6 @@ impl SchemaApiTestSuite { db_id: old_db.ident.db_id, table_name: tbl_name.to_string(), tb_id: tb_info.ident.table_id, - is_temp: false, }) .await?; let cur_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -4907,7 +4895,6 @@ impl SchemaApiTestSuite { db_id: cur_db.ident.db_id, table_name: tbl_name.to_string(), tb_id: new_tb_info.ident.table_id, - is_temp: false, }; let old_db = mt.get_database(Self::req_get_db(&tenant, db_name)).await?; @@ -7670,7 +7657,6 @@ where MT: SchemaApi + kvapi::AsKVApi if_exists: false, db_id: self.db_id, tb_id: self.table_id, - is_temp: false, }; self.mt.drop_table_by_id(req.clone()).await?; diff --git a/src/meta/api/src/share_api_test_suite.rs b/src/meta/api/src/share_api_test_suite.rs index 3f74b523df4d..e5f1ae28bfb9 100644 --- a/src/meta/api/src/share_api_test_suite.rs +++ b/src/meta/api/src/share_api_test_suite.rs @@ -362,7 +362,6 @@ impl ShareApiTestSuite { table_name: table_name.to_string(), tb_id: table_id, db_id, - is_temp: false, }; let res = mt.drop_table_by_id(plan).await?; let (share_db_id, share_specs) = res.spec_vec.unwrap(); @@ -2467,7 +2466,6 @@ impl ShareApiTestSuite { table_name: tbl_name.to_string(), tb_id: table_id, db_id, - is_temp: false, }; let _res = mt.drop_table_by_id(plan).await; diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index d42c8ec13940..2b202f49bf3f 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -564,8 +564,6 @@ pub struct DropTableByIdReq { pub table_name: String, pub db_id: MetaId, - - pub is_temp: bool, } impl DropTableByIdReq { diff --git a/src/meta/binaries/metabench/main.rs b/src/meta/binaries/metabench/main.rs index 810bf45d0582..07b07cd84a00 100644 --- a/src/meta/binaries/metabench/main.rs +++ b/src/meta/binaries/metabench/main.rs @@ -238,7 +238,6 @@ async fn benchmark_table(client: &Arc, prefix: u64, client_num: u6 db_id, table_name: table_name(), tb_id: t.ident.table_id, - is_temp: false, }) .await; diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index 0103f8e93b7a..de0f50ca5d57 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -103,6 +103,7 @@ use databend_common_meta_store::MetaStore; use databend_common_meta_types::anyerror::func_name; use databend_common_meta_types::MetaId; use databend_common_meta_types::SeqV; +use databend_storages_common_session::SessionState; use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use dyn_clone::DynClone; @@ -217,13 +218,7 @@ pub trait Catalog: DynClone + Send + Sync + Debug { fn get_table_by_info(&self, table_info: &TableInfo) -> Result>; /// Get the table meta by table id. - /// - /// `table_id` can be a temp table id or a meta id as long as `is_temp` is set properly. - async fn get_table_meta_by_id( - &self, - table_id: u64, - is_temp: bool, - ) -> Result>>; + async fn get_table_meta_by_id(&self, table_id: u64) -> Result>>; /// List the tables name by meta ids. /// @@ -245,9 +240,7 @@ pub trait Catalog: DynClone + Send + Sync + Debug { ) -> Result>>; /// Get the table name by meta id. - /// - /// `table_id` can be a temp table id or a meta id as long as `is_temp` is set properly. - async fn get_table_name_by_id(&self, table_id: u64, is_temp: bool) -> Result>; + async fn get_table_name_by_id(&self, table_id: u64) -> Result>; // Get one table by db and table name. async fn get_table( @@ -401,6 +394,7 @@ pub trait Catalog: DynClone + Send + Sync + Debug { req: TruncateTableReq, ) -> Result; + // TODO: implement lock related functions async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result>; async fn create_lock_revision(&self, req: CreateLockRevReq) -> Result; @@ -459,4 +453,8 @@ pub trait Catalog: DynClone + Send + Sync + Debug { ) -> Result; async fn drop_sequence(&self, req: DropSequenceReq) -> Result; + + fn set_session_state(&self, _state: SessionState) -> Arc { + unimplemented!() + } } diff --git a/src/query/catalog/src/catalog/manager.rs b/src/query/catalog/src/catalog/manager.rs index a76624ef860b..a63955b706e4 100644 --- a/src/query/catalog/src/catalog/manager.rs +++ b/src/query/catalog/src/catalog/manager.rs @@ -41,7 +41,6 @@ use databend_storages_common_session::SessionState; use super::Catalog; use super::CatalogCreator; -use crate::catalog::session_catalog::SessionCatalog; pub const CATALOG_DEFAULT: &str = "default"; @@ -133,10 +132,7 @@ impl CatalogManager { /// There are some place that we don't have async context, so we provide /// `get_default_catalog` to allow users fetch default catalog without async. pub fn get_default_catalog(&self, session_state: SessionState) -> Result> { - Ok(Arc::new(SessionCatalog::create( - self.default_catalog.clone(), - session_state, - ))) + Ok(self.default_catalog.set_session_state(session_state)) } /// build_catalog builds a catalog from catalog info. diff --git a/src/query/catalog/src/catalog/mod.rs b/src/query/catalog/src/catalog/mod.rs index 32a27407ff84..8befa374491f 100644 --- a/src/query/catalog/src/catalog/mod.rs +++ b/src/query/catalog/src/catalog/mod.rs @@ -16,7 +16,6 @@ mod interface; /// the catalog manager implementation mod manager; -mod session_catalog; pub use interface::Catalog; pub use interface::CatalogCreator; diff --git a/src/query/catalog/src/table.rs b/src/query/catalog/src/table.rs index 8f585e2a9bfa..88c6d5ee52ee 100644 --- a/src/query/catalog/src/table.rs +++ b/src/query/catalog/src/table.rs @@ -430,13 +430,10 @@ pub trait TableExt: Table { let tid = table_info.ident.table_id; let catalog = ctx.get_catalog(table_info.catalog()).await?; - let seqv = catalog - .get_table_meta_by_id(tid, self.is_temp()) - .await? - .ok_or_else(|| { - let err = UnknownTableId::new(tid, "TableExt::refresh"); - AppError::from(err) - })?; + let seqv = catalog.get_table_meta_by_id(tid).await?.ok_or_else(|| { + let err = UnknownTableId::new(tid, "TableExt::refresh"); + AppError::from(err) + })?; self.refresh_with_seq_meta(ctx, seqv.seq, seqv.data).await } diff --git a/src/query/ee/src/stream/handler.rs b/src/query/ee/src/stream/handler.rs index 8bc94188a126..529e64a2bb1d 100644 --- a/src/query/ee/src/stream/handler.rs +++ b/src/query/ee/src/stream/handler.rs @@ -190,7 +190,6 @@ impl StreamHandler for RealStreamHandler { table_name: stream_name.clone(), tb_id: table.get_id(), db_id: db.get_db_info().ident.db_id, - is_temp: false, }) .await } else if plan.if_exists { diff --git a/src/query/service/Cargo.toml b/src/query/service/Cargo.toml index 6cd073628a36..da7f051c70b0 100644 --- a/src/query/service/Cargo.toml +++ b/src/query/service/Cargo.toml @@ -177,7 +177,6 @@ typetag = { workspace = true } uuid = { workspace = true } walkdir = { workspace = true } xorf = { version = "0.11.0", default-features = false, features = ["binary-fuse"] } - [dev-dependencies] arrow-cast = { workspace = true } criterion = { workspace = true } diff --git a/src/query/service/src/catalogs/default/database_catalog.rs b/src/query/service/src/catalogs/default/database_catalog.rs index d0dbcd9e5558..a86b75fdcad5 100644 --- a/src/query/service/src/catalogs/default/database_catalog.rs +++ b/src/query/service/src/catalogs/default/database_catalog.rs @@ -104,13 +104,14 @@ use databend_common_meta_app::tenant::Tenant; use databend_common_meta_app::KeyWithTenant; use databend_common_meta_types::MetaId; use databend_common_meta_types::SeqV; +use databend_storages_common_session::SessionState; use log::info; use crate::catalogs::default::ImmutableCatalog; use crate::catalogs::default::MutableCatalog; +use crate::catalogs::default::SessionCatalog; use crate::storages::Table; use crate::table_functions::TableFunctionFactory; - /// Combine two catalogs together /// - read/search like operations are always performed at /// upper layer first, and bottom layer later(if necessary) @@ -120,7 +121,7 @@ pub struct DatabaseCatalog { /// the upper layer, read only immutable_catalog: Arc, /// bottom layer, writing goes here - mutable_catalog: Arc, + session_catalog: Arc, /// table function engine factories table_function_factory: Arc, } @@ -136,10 +137,11 @@ impl DatabaseCatalog { pub async fn try_create_with_config(conf: InnerConfig) -> Result { let immutable_catalog = ImmutableCatalog::try_create_with_config(&conf).await?; let mutable_catalog = MutableCatalog::try_create_with_config(conf).await?; + let session_catalog = SessionCatalog::create(mutable_catalog, SessionState::default()); let table_function_factory = TableFunctionFactory::create(); let res = DatabaseCatalog { immutable_catalog: Arc::new(immutable_catalog), - mutable_catalog: Arc::new(mutable_catalog), + session_catalog: Arc::new(session_catalog), table_function_factory: Arc::new(table_function_factory), }; Ok(res) @@ -162,9 +164,9 @@ impl Catalog for DatabaseCatalog { fn disable_table_info_refresh(self: Arc) -> Result> { let mut me = self.as_ref().clone(); - let mut mutable_catalog = me.mutable_catalog.as_ref().clone(); - mutable_catalog.disable_table_info_refresh(); - me.mutable_catalog = Arc::new(mutable_catalog); + let mut session_catalog = me.session_catalog.as_ref().clone(); + session_catalog.disable_table_info_refresh(); + me.session_catalog = Arc::new(session_catalog); Ok(Arc::new(me)) } @@ -174,7 +176,7 @@ impl Catalog for DatabaseCatalog { match r { Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.mutable_catalog.get_database(tenant, db_name).await + self.session_catalog.get_database(tenant, db_name).await } else { Err(e) } @@ -186,7 +188,7 @@ impl Catalog for DatabaseCatalog { #[async_backtrace::framed] async fn list_databases(&self, tenant: &Tenant) -> Result>> { let mut dbs = self.immutable_catalog.list_databases(tenant).await?; - let mut other = self.mutable_catalog.list_databases(tenant).await?; + let mut other = self.session_catalog.list_databases(tenant).await?; dbs.append(&mut other); Ok(dbs) } @@ -206,7 +208,7 @@ impl Catalog for DatabaseCatalog { ))); } // create db in BOTTOM layer only - self.mutable_catalog.create_database(req).await + self.session_catalog.create_database(req).await } #[async_backtrace::framed] @@ -221,7 +223,7 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.drop_database(req).await; } - self.mutable_catalog.drop_database(req).await + self.session_catalog.drop_database(req).await } #[async_backtrace::framed] @@ -240,7 +242,7 @@ impl Catalog for DatabaseCatalog { return self.immutable_catalog.rename_database(req).await; } - self.mutable_catalog.rename_database(req).await + self.session_catalog.rename_database(req).await } fn get_table_by_info(&self, table_info: &TableInfo) -> Result> { @@ -249,7 +251,7 @@ impl Catalog for DatabaseCatalog { Ok(t) => Ok(t), Err(e) => { if e.code() == ErrorCode::UNKNOWN_TABLE { - self.mutable_catalog.get_table_by_info(table_info) + self.session_catalog.get_table_by_info(table_info) } else { Err(e) } @@ -258,22 +260,13 @@ impl Catalog for DatabaseCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id( - &self, - table_id: MetaId, - is_temp: bool, - ) -> Result>> { - let res = self - .immutable_catalog - .get_table_meta_by_id(table_id, is_temp) - .await; + async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { + let res = self.immutable_catalog.get_table_meta_by_id(table_id).await; if let Ok(x) = res { Ok(x) } else { - self.mutable_catalog - .get_table_meta_by_id(table_id, is_temp) - .await + self.session_catalog.get_table_meta_by_id(table_id).await } } @@ -313,7 +306,7 @@ impl Catalog for DatabaseCatalog { // Fetching table names for remaining system table IDs let other = self - .mutable_catalog + .session_catalog .mget_table_names_by_ids(tenant, &mut_table_ids) .await?; @@ -324,23 +317,12 @@ impl Catalog for DatabaseCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id( - &self, - table_id: MetaId, - is_temp: bool, - ) -> Result> { - let res = self - .immutable_catalog - .get_table_name_by_id(table_id, is_temp) - .await; + async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { + let res = self.immutable_catalog.get_table_name_by_id(table_id).await; match res { Ok(Some(x)) => Ok(Some(x)), - Ok(None) | Err(_) => { - self.mutable_catalog - .get_table_name_by_id(table_id, is_temp) - .await - } + Ok(None) | Err(_) => self.session_catalog.get_table_name_by_id(table_id).await, } } @@ -351,7 +333,7 @@ impl Catalog for DatabaseCatalog { if let Ok(x) = res { Ok(x) } else { - self.mutable_catalog.get_db_name_by_id(db_id).await + self.session_catalog.get_db_name_by_id(db_id).await } } @@ -381,7 +363,7 @@ impl Catalog for DatabaseCatalog { .await?; let other = self - .mutable_catalog + .session_catalog .mget_database_names_by_ids(tenant, &mut_db_ids) .await?; @@ -405,7 +387,7 @@ impl Catalog for DatabaseCatalog { Ok(v) => Ok(v), Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.mutable_catalog + self.session_catalog .get_table(tenant, db_name, table_name) .await } else { @@ -422,7 +404,7 @@ impl Catalog for DatabaseCatalog { Ok(x) => Ok(x), Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.mutable_catalog.list_tables(tenant, db_name).await + self.session_catalog.list_tables(tenant, db_name).await } else { Err(e) } @@ -444,7 +426,7 @@ impl Catalog for DatabaseCatalog { Ok(x) => Ok(x), Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.mutable_catalog + self.session_catalog .list_tables_history(tenant, db_name) .await } else { @@ -465,12 +447,12 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.create_table(req).await; } - self.mutable_catalog.create_table(req).await + self.session_catalog.create_table(req).await } #[async_backtrace::framed] async fn drop_table_by_id(&self, req: DropTableByIdReq) -> Result { - let res = self.mutable_catalog.drop_table_by_id(req).await?; + let res = self.session_catalog.drop_table_by_id(req).await?; Ok(res) } @@ -485,7 +467,7 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.undrop_table(req).await; } - self.mutable_catalog.undrop_table(req).await + self.session_catalog.undrop_table(req).await } #[async_backtrace::framed] @@ -499,7 +481,7 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.undrop_table_by_id(req).await; } - self.mutable_catalog.undrop_table_by_id(req).await + self.session_catalog.undrop_table_by_id(req).await } #[async_backtrace::framed] @@ -513,13 +495,13 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.undrop_database(req).await; } - self.mutable_catalog.undrop_database(req).await + self.session_catalog.undrop_database(req).await } async fn commit_table_meta(&self, req: CommitTableMetaReq) -> Result { info!("commit_table_meta from req:{:?}", req); - self.mutable_catalog.commit_table_meta(req).await + self.session_catalog.commit_table_meta(req).await } #[async_backtrace::framed] @@ -540,17 +522,17 @@ impl Catalog for DatabaseCatalog { )); } - self.mutable_catalog.rename_table(req).await + self.session_catalog.rename_table(req).await } #[async_backtrace::framed] async fn create_table_index(&self, req: CreateTableIndexReq) -> Result { - self.mutable_catalog.create_table_index(req).await + self.session_catalog.create_table_index(req).await } #[async_backtrace::framed] async fn drop_table_index(&self, req: DropTableIndexReq) -> Result { - self.mutable_catalog.drop_table_index(req).await + self.session_catalog.drop_table_index(req).await } #[async_backtrace::framed] @@ -560,7 +542,7 @@ impl Catalog for DatabaseCatalog { db_name: &str, req: GetTableCopiedFileReq, ) -> Result { - self.mutable_catalog + self.session_catalog .get_table_copied_file_info(tenant, db_name, req) .await } @@ -571,7 +553,7 @@ impl Catalog for DatabaseCatalog { table_info: &TableInfo, req: TruncateTableReq, ) -> Result { - self.mutable_catalog.truncate_table(table_info, req).await + self.session_catalog.truncate_table(table_info, req).await } #[async_backtrace::framed] @@ -581,7 +563,7 @@ impl Catalog for DatabaseCatalog { db_name: &str, req: UpsertTableOptionReq, ) -> Result { - self.mutable_catalog + self.session_catalog .upsert_table_option(tenant, db_name, req) .await } @@ -591,7 +573,7 @@ impl Catalog for DatabaseCatalog { &self, reqs: UpdateMultiTableMetaReq, ) -> Result { - self.mutable_catalog + self.session_catalog .retryable_update_multi_table_meta(reqs) .await } @@ -601,39 +583,39 @@ impl Catalog for DatabaseCatalog { &self, req: SetTableColumnMaskPolicyReq, ) -> Result { - self.mutable_catalog.set_table_column_mask_policy(req).await + self.session_catalog.set_table_column_mask_policy(req).await } // Table index #[async_backtrace::framed] async fn create_index(&self, req: CreateIndexReq) -> Result { - self.mutable_catalog.create_index(req).await + self.session_catalog.create_index(req).await } #[async_backtrace::framed] async fn drop_index(&self, req: DropIndexReq) -> Result { - self.mutable_catalog.drop_index(req).await + self.session_catalog.drop_index(req).await } #[async_backtrace::framed] async fn get_index(&self, req: GetIndexReq) -> Result { - self.mutable_catalog.get_index(req).await + self.session_catalog.get_index(req).await } #[async_backtrace::framed] async fn update_index(&self, req: UpdateIndexReq) -> Result { - self.mutable_catalog.update_index(req).await + self.session_catalog.update_index(req).await } #[async_backtrace::framed] async fn list_indexes(&self, req: ListIndexesReq) -> Result> { - self.mutable_catalog.list_indexes(req).await + self.session_catalog.list_indexes(req).await } #[async_backtrace::framed] async fn list_index_ids_by_table_id(&self, req: ListIndexesByIdReq) -> Result> { - self.mutable_catalog.list_index_ids_by_table_id(req).await + self.session_catalog.list_index_ids_by_table_id(req).await } #[async_backtrace::framed] @@ -641,7 +623,7 @@ impl Catalog for DatabaseCatalog { &self, req: ListIndexesByIdReq, ) -> Result> { - self.mutable_catalog.list_indexes_by_table_id(req).await + self.session_catalog.list_indexes_by_table_id(req).await } // Virtual column @@ -651,7 +633,7 @@ impl Catalog for DatabaseCatalog { &self, req: CreateVirtualColumnReq, ) -> Result { - self.mutable_catalog.create_virtual_column(req).await + self.session_catalog.create_virtual_column(req).await } #[async_backtrace::framed] @@ -659,7 +641,7 @@ impl Catalog for DatabaseCatalog { &self, req: UpdateVirtualColumnReq, ) -> Result { - self.mutable_catalog.update_virtual_column(req).await + self.session_catalog.update_virtual_column(req).await } #[async_backtrace::framed] @@ -667,7 +649,7 @@ impl Catalog for DatabaseCatalog { &self, req: DropVirtualColumnReq, ) -> Result { - self.mutable_catalog.drop_virtual_column(req).await + self.session_catalog.drop_virtual_column(req).await } #[async_backtrace::framed] @@ -675,7 +657,7 @@ impl Catalog for DatabaseCatalog { &self, req: ListVirtualColumnsReq, ) -> Result> { - self.mutable_catalog.list_virtual_columns(req).await + self.session_catalog.list_virtual_columns(req).await } fn get_table_function( @@ -696,60 +678,68 @@ impl Catalog for DatabaseCatalog { fn get_table_engines(&self) -> Vec { // only return mutable_catalog storage table engines - self.mutable_catalog.get_table_engines() + self.session_catalog.get_table_engines() } #[async_backtrace::framed] async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result> { - self.mutable_catalog.list_lock_revisions(req).await + self.session_catalog.list_lock_revisions(req).await } #[async_backtrace::framed] async fn create_lock_revision(&self, req: CreateLockRevReq) -> Result { - self.mutable_catalog.create_lock_revision(req).await + self.session_catalog.create_lock_revision(req).await } #[async_backtrace::framed] async fn extend_lock_revision(&self, req: ExtendLockRevReq) -> Result<()> { - self.mutable_catalog.extend_lock_revision(req).await + self.session_catalog.extend_lock_revision(req).await } #[async_backtrace::framed] async fn delete_lock_revision(&self, req: DeleteLockRevReq) -> Result<()> { - self.mutable_catalog.delete_lock_revision(req).await + self.session_catalog.delete_lock_revision(req).await } #[async_backtrace::framed] async fn list_locks(&self, req: ListLocksReq) -> Result> { - self.mutable_catalog.list_locks(req).await + self.session_catalog.list_locks(req).await } async fn get_drop_table_infos( &self, req: ListDroppedTableReq, ) -> Result<(Vec>, Vec)> { - self.mutable_catalog.get_drop_table_infos(req).await + self.session_catalog.get_drop_table_infos(req).await } async fn gc_drop_tables(&self, req: GcDroppedTableReq) -> Result { - self.mutable_catalog.gc_drop_tables(req).await + self.session_catalog.gc_drop_tables(req).await } async fn create_sequence(&self, req: CreateSequenceReq) -> Result { - self.mutable_catalog.create_sequence(req).await + self.session_catalog.create_sequence(req).await } async fn get_sequence(&self, req: GetSequenceReq) -> Result { - self.mutable_catalog.get_sequence(req).await + self.session_catalog.get_sequence(req).await } async fn get_sequence_next_value( &self, req: GetSequenceNextValueReq, ) -> Result { - self.mutable_catalog.get_sequence_next_value(req).await + self.session_catalog.get_sequence_next_value(req).await } async fn drop_sequence(&self, req: DropSequenceReq) -> Result { - self.mutable_catalog.drop_sequence(req).await + self.session_catalog.drop_sequence(req).await + } + + fn set_session_state(&self, state: SessionState) -> Arc { + Arc::new(DatabaseCatalog { + session_catalog: Arc::new(SessionCatalog::create(self.session_catalog.inner(), state)), + immutable_catalog: self.immutable_catalog.clone(), + table_function_factory: self.table_function_factory.clone(), + }) } } diff --git a/src/query/service/src/catalogs/default/immutable_catalog.rs b/src/query/service/src/catalogs/default/immutable_catalog.rs index 20d7057fd1bf..8741e18e9d07 100644 --- a/src/query/service/src/catalogs/default/immutable_catalog.rs +++ b/src/query/service/src/catalogs/default/immutable_catalog.rs @@ -93,10 +93,10 @@ use databend_common_meta_app::schema::VirtualColumnMeta; use databend_common_meta_app::tenant::Tenant; use databend_common_meta_types::MetaId; use databend_common_meta_types::SeqV; +use databend_storages_common_table_meta::table_id_ranges::SYS_DB_ID_BEGIN; +use databend_storages_common_table_meta::table_id_ranges::SYS_TBL_ID_BEGIN; use crate::catalogs::InMemoryMetas; -use crate::catalogs::SYS_DB_ID_BEGIN; -use crate::catalogs::SYS_TBL_ID_BEGIN; use crate::databases::Database; use crate::databases::InformationSchemaDatabase; use crate::databases::SystemDatabase; @@ -193,11 +193,7 @@ impl Catalog for ImmutableCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id( - &self, - table_id: MetaId, - _is_temp: bool, - ) -> Result>> { + async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { let table = self .sys_db_meta .get_by_id(&table_id) @@ -250,11 +246,7 @@ impl Catalog for ImmutableCatalog { Ok(res) } - async fn get_table_name_by_id( - &self, - table_id: MetaId, - _is_temp: bool, - ) -> Result> { + async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { let table_name = self .sys_db_meta .get_by_id(&table_id) diff --git a/src/query/service/src/catalogs/default/mod.rs b/src/query/service/src/catalogs/default/mod.rs index e73f64f6feba..70f330a9853a 100644 --- a/src/query/service/src/catalogs/default/mod.rs +++ b/src/query/service/src/catalogs/default/mod.rs @@ -16,10 +16,11 @@ mod catalog_context; mod database_catalog; mod immutable_catalog; mod mutable_catalog; -pub mod table_id_ranges; +mod session_catalog; pub mod table_memory_meta; pub use catalog_context::CatalogContext; pub use database_catalog::DatabaseCatalog; pub use immutable_catalog::ImmutableCatalog; pub use mutable_catalog::MutableCatalog; +pub use session_catalog::SessionCatalog; diff --git a/src/query/service/src/catalogs/default/mutable_catalog.rs b/src/query/service/src/catalogs/default/mutable_catalog.rs index c7ee84491af7..c3678b34bd72 100644 --- a/src/query/service/src/catalogs/default/mutable_catalog.rs +++ b/src/query/service/src/catalogs/default/mutable_catalog.rs @@ -376,11 +376,7 @@ impl Catalog for MutableCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id( - &self, - table_id: MetaId, - _is_temp: bool, - ) -> Result>> { + async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { let res = self.ctx.meta.get_table_by_id(table_id).await?; Ok(res) } @@ -410,11 +406,7 @@ impl Catalog for MutableCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id( - &self, - table_id: MetaId, - _is_temp: bool, - ) -> Result> { + async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { let res = self.ctx.meta.get_table_name_by_id(table_id).await?; Ok(res) } diff --git a/src/query/catalog/src/catalog/session_catalog.rs b/src/query/service/src/catalogs/default/session_catalog.rs similarity index 90% rename from src/query/catalog/src/catalog/session_catalog.rs rename to src/query/service/src/catalogs/default/session_catalog.rs index 45b8bf5ebe72..dfb00983ed53 100644 --- a/src/query/catalog/src/catalog/session_catalog.rs +++ b/src/query/service/src/catalogs/default/session_catalog.rs @@ -16,6 +16,11 @@ use std::any::Any; use std::fmt::Debug; use std::sync::Arc; +use databend_common_catalog::catalog::StorageDescription; +use databend_common_catalog::database::Database; +use databend_common_catalog::table::Table; +use databend_common_catalog::table_args::TableArgs; +use databend_common_catalog::table_function::TableFunction; use databend_common_exception::Result; use databend_common_meta_app::schema::CatalogInfo; use databend_common_meta_app::schema::CommitTableMetaReply; @@ -101,22 +106,17 @@ use databend_storages_common_session::TxnManagerRef; use databend_storages_common_session::TxnState; use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; -use crate::catalog::Catalog; -use crate::catalog::StorageDescription; -use crate::database::Database; -use crate::table::Table; -use crate::table_args::TableArgs; -use crate::table_function::TableFunction; - +use crate::catalogs::default::MutableCatalog; +use crate::catalogs::Catalog; #[derive(Clone, Debug)] pub struct SessionCatalog { - inner: Arc, + inner: MutableCatalog, txn_mgr: TxnManagerRef, temp_tbl_mgr: TempTblMgrRef, } impl SessionCatalog { - pub fn create(inner: Arc, session_state: SessionState) -> Self { + pub fn create(inner: MutableCatalog, session_state: SessionState) -> Self { let SessionState { txn_mgr, temp_tbl_mgr, @@ -142,10 +142,6 @@ impl Catalog for SessionCatalog { self.inner.info() } - fn disable_table_info_refresh(self: Arc) -> Result> { - self.inner.clone().disable_table_info_refresh() - } - /// Database. // Get the database by name. @@ -241,31 +237,24 @@ impl Catalog for SessionCatalog { self.inner.get_table_by_info(table_info) } - async fn get_table_meta_by_id( - &self, - table_id: u64, - is_temp: bool, - ) -> Result>> { + async fn get_table_meta_by_id(&self, table_id: u64) -> Result>> { if let Some(t) = { let guard = self.txn_mgr.lock(); if guard.is_active() { - guard.get_table_from_buffer_by_id(table_id, is_temp) + guard.get_table_from_buffer_by_id(table_id) } else { None } } { return Ok(Some(SeqV::new(t.ident.seq, t.meta.clone()))); } - match is_temp { - true => Ok(self - .temp_tbl_mgr - .lock() - .get_table_meta_by_id(table_id) - .map(|m| SeqV::new(0, m))), - false => self.inner.get_table_meta_by_id(table_id, is_temp).await, + if let Some(meta) = self.temp_tbl_mgr.lock().get_table_meta_by_id(table_id) { + return Ok(Some(SeqV::new(0, meta))); } + self.inner.get_table_meta_by_id(table_id).await } + // TODO: implement this async fn mget_table_names_by_ids( &self, tenant: &Tenant, @@ -274,11 +263,11 @@ impl Catalog for SessionCatalog { self.inner.mget_table_names_by_ids(tenant, table_ids).await } - async fn get_table_name_by_id(&self, table_id: u64, is_temp: bool) -> Result> { - match is_temp { - true => Ok(self.temp_tbl_mgr.lock().get_table_name_by_id(table_id)), - false => self.inner.get_table_name_by_id(table_id, is_temp).await, + async fn get_table_name_by_id(&self, table_id: u64) -> Result> { + if let Some(name) = self.temp_tbl_mgr.lock().get_table_name_by_id(table_id) { + return Ok(Some(name)); } + self.inner.get_table_name_by_id(table_id).await } // Get the db name by meta id. @@ -330,9 +319,12 @@ impl Catalog for SessionCatalog { Ok(table) } + // TODO: implement this async fn list_tables(&self, tenant: &Tenant, db_name: &str) -> Result>> { self.inner.list_tables(tenant, db_name).await } + + // TODO: implement this async fn list_tables_history( &self, tenant: &Tenant, @@ -341,6 +333,7 @@ impl Catalog for SessionCatalog { self.inner.list_tables_history(tenant, db_name).await } + // TODO: implement this async fn get_drop_table_infos( &self, req: ListDroppedTableReq, @@ -348,6 +341,7 @@ impl Catalog for SessionCatalog { self.inner.get_drop_table_infos(req).await } + // TODO: implement this async fn gc_drop_tables(&self, req: GcDroppedTableReq) -> Result { self.inner.gc_drop_tables(req).await } @@ -360,19 +354,23 @@ impl Catalog for SessionCatalog { } async fn drop_table_by_id(&self, req: DropTableByIdReq) -> Result { - match req.is_temp { - true => { - databend_storages_common_session::drop_table_by_id(self.temp_tbl_mgr.clone(), req) - .await - } - false => self.inner.drop_table_by_id(req).await, + if let Some(reply) = databend_storages_common_session::drop_table_by_id( + self.temp_tbl_mgr.clone(), + req.clone(), + ) + .await? + { + return Ok(reply); } + self.inner.drop_table_by_id(req).await } + // TODO: implement this async fn undrop_table(&self, req: UndropTableReq) -> Result { self.inner.undrop_table(req).await } + // TODO: implement this async fn undrop_table_by_id(&self, req: UndropTableByIdReq) -> Result { self.inner.undrop_table_by_id(req).await } @@ -399,6 +397,9 @@ impl Catalog for SessionCatalog { db_name: &str, req: UpsertTableOptionReq, ) -> Result { + if let Some(reply) = self.temp_tbl_mgr.lock().upsert_table_option(req.clone())? { + return Ok(reply); + } self.inner.upsert_table_option(tenant, db_name, req).await } @@ -440,6 +441,7 @@ impl Catalog for SessionCatalog { self.inner.drop_table_index(req).await } + // TODO: implement this async fn get_table_copied_file_info( &self, tenant: &Tenant, @@ -457,6 +459,7 @@ impl Catalog for SessionCatalog { Ok(reply) } + // TODO: implement this async fn truncate_table( &self, table_info: &TableInfo, @@ -554,3 +557,13 @@ impl Catalog for SessionCatalog { self.inner.drop_sequence(req).await } } + +impl SessionCatalog { + pub fn disable_table_info_refresh(&mut self) { + self.inner.disable_table_info_refresh(); + } + + pub fn inner(&self) -> MutableCatalog { + self.inner.clone() + } +} diff --git a/src/query/service/src/catalogs/mod.rs b/src/query/service/src/catalogs/mod.rs index 2da8cb67110f..4edd30b0df35 100644 --- a/src/query/service/src/catalogs/mod.rs +++ b/src/query/service/src/catalogs/mod.rs @@ -16,7 +16,6 @@ pub mod default; pub mod share; pub use databend_common_catalog::catalog::Catalog; pub use databend_common_storages_hive as hive; -pub use default::table_id_ranges::*; pub use default::table_memory_meta::InMemoryMetas; pub use default::DatabaseCatalog; pub use share::ShareCatalog; diff --git a/src/query/service/src/catalogs/share/share_catalog.rs b/src/query/service/src/catalogs/share/share_catalog.rs index bffaaaaa8c13..cd32a7a53a2e 100644 --- a/src/query/service/src/catalogs/share/share_catalog.rs +++ b/src/query/service/src/catalogs/share/share_catalog.rs @@ -352,11 +352,7 @@ impl Catalog for ShareCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id( - &self, - _table_id: MetaId, - _is_temp: bool, - ) -> Result>> { + async fn get_table_meta_by_id(&self, _table_id: MetaId) -> Result>> { Err(ErrorCode::Unimplemented( "Cannot get table by id in SHARE catalog", )) @@ -373,11 +369,7 @@ impl Catalog for ShareCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id( - &self, - _table_id: MetaId, - _is_temp: bool, - ) -> Result> { + async fn get_table_name_by_id(&self, _table_id: MetaId) -> Result> { Err(ErrorCode::Unimplemented( "Cannot get table name by id in SHARE catalog", )) diff --git a/src/query/service/src/interpreters/common/grant.rs b/src/query/service/src/interpreters/common/grant.rs index 286601d689ce..fb675b6284e4 100644 --- a/src/query/service/src/interpreters/common/grant.rs +++ b/src/query/service/src/interpreters/common/grant.rs @@ -67,11 +67,7 @@ pub async fn validate_grant_object_exists( GrantObject::TableById(catalog_name, db_id, table_id) => { let catalog = ctx.get_catalog(catalog_name).await?; - if catalog - .get_table_meta_by_id(*table_id, false) - .await? - .is_none() - { + if catalog.get_table_meta_by_id(*table_id).await?.is_none() { return Err(databend_common_exception::ErrorCode::UnknownTableId( format!( "table id `{}`.`{}` not exists in catalog '{}'", diff --git a/src/query/service/src/interpreters/interpreter_table_drop.rs b/src/query/service/src/interpreters/interpreter_table_drop.rs index a675abac2b61..6a5bfefcaadc 100644 --- a/src/query/service/src/interpreters/interpreter_table_drop.rs +++ b/src/query/service/src/interpreters/interpreter_table_drop.rs @@ -125,7 +125,6 @@ impl Interpreter for DropTableInterpreter { table_name: tbl_name.to_string(), tb_id: tbl.get_table_info().ident.table_id, db_id: db.get_db_info().ident.db_id, - is_temp, }) .await?; diff --git a/src/query/service/src/interpreters/interpreter_view_drop.rs b/src/query/service/src/interpreters/interpreter_view_drop.rs index f2f73238bcec..f49a984c8079 100644 --- a/src/query/service/src/interpreters/interpreter_view_drop.rs +++ b/src/query/service/src/interpreters/interpreter_view_drop.rs @@ -93,7 +93,6 @@ impl Interpreter for DropViewInterpreter { table_name: self.plan.view_name.clone(), tb_id: table.get_id(), db_id: db.get_db_info().ident.db_id, - is_temp: table.is_temp(), }) .await?; }; diff --git a/src/query/service/src/servers/admin/v1/stream_status.rs b/src/query/service/src/servers/admin/v1/stream_status.rs index f2e3e3c2787e..0d24d78931b1 100644 --- a/src/query/service/src/servers/admin/v1/stream_status.rs +++ b/src/query/service/src/servers/admin/v1/stream_status.rs @@ -53,7 +53,7 @@ async fn check_stream_status( let table_id = stream.source_table_id()?; let seqv = catalog - .get_table_meta_by_id(table_id, false) + .get_table_meta_by_id(table_id) .await? .ok_or_else(|| { let err = UnknownTableId::new(table_id, "check_stream_status"); 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 a6164a5a7183..751b5116149f 100644 --- a/src/query/service/src/table_functions/table_function_factory.rs +++ b/src/query/service/src/table_functions/table_function_factory.rs @@ -27,6 +27,8 @@ use databend_common_storages_fuse::table_functions::FuseEncodingFunc; use databend_common_storages_fuse::table_functions::FuseStatisticsFunc; use databend_common_storages_fuse::table_functions::TableFunctionTemplate; use databend_common_storages_stream::stream_status_table_func::StreamStatusTable; +use databend_storages_common_table_meta::table_id_ranges::SYS_TBL_FUC_ID_END; +use databend_storages_common_table_meta::table_id_ranges::SYS_TBL_FUNC_ID_BEGIN; use itertools::Itertools; use parking_lot::RwLock; @@ -34,8 +36,6 @@ use super::ExecuteBackgroundJobTable; use super::LicenseInfoTable; use super::SuggestedBackgroundTasksTable; use super::TenantQuotaTable; -use crate::catalogs::SYS_TBL_FUC_ID_END; -use crate::catalogs::SYS_TBL_FUNC_ID_BEGIN; use crate::storages::fuse::table_functions::ClusteringInformationFunc; use crate::storages::fuse::table_functions::FuseSegmentFunc; use crate::storages::fuse::table_functions::FuseSnapshotFunc; diff --git a/src/query/service/tests/it/catalogs/database_catalog.rs b/src/query/service/tests/it/catalogs/database_catalog.rs index 1c00d6eede6f..d9201ea20e0d 100644 --- a/src/query/service/tests/it/catalogs/database_catalog.rs +++ b/src/query/service/tests/it/catalogs/database_catalog.rs @@ -191,7 +191,6 @@ async fn test_catalogs_table() -> Result<()> { table_name: "test_table".to_string(), tb_id: tbl.get_table_info().ident.table_id, db_id: db.get_db_info().ident.db_id, - is_temp: false, }) .await; assert!(res.is_ok()); diff --git a/src/query/service/tests/it/databases/system/system_database.rs b/src/query/service/tests/it/databases/system/system_database.rs index 03b6d0c83a43..fcb5cc50f0fd 100644 --- a/src/query/service/tests/it/databases/system/system_database.rs +++ b/src/query/service/tests/it/databases/system/system_database.rs @@ -14,10 +14,10 @@ use databend_common_exception::Result; use databend_query::catalogs::InMemoryMetas; -use databend_query::catalogs::SYS_DB_ID_BEGIN; -use databend_query::catalogs::SYS_TBL_ID_BEGIN; use databend_query::databases::SystemDatabase; use databend_query::test_kits::*; +use databend_storages_common_table_meta::table_id_ranges::SYS_DB_ID_BEGIN; +use databend_storages_common_table_meta::table_id_ranges::SYS_TBL_ID_BEGIN; #[test] fn test_disable_system_table() -> Result<()> { diff --git a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs index dddf257fe9c5..8a258e50f9da 100644 --- a/src/query/service/tests/it/sql/exec/get_table_bind_test.rs +++ b/src/query/service/tests/it/sql/exec/get_table_bind_test.rs @@ -213,12 +213,8 @@ impl Catalog for FakedCatalog { self.cat.mget_database_names_by_ids(tenant, db_ids).await } - async fn get_table_name_by_id( - &self, - table_id: MetaId, - is_temp: bool, - ) -> Result> { - self.cat.get_table_name_by_id(table_id, is_temp).await + async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { + self.cat.get_table_name_by_id(table_id).await } async fn get_table( @@ -417,12 +413,8 @@ impl Catalog for FakedCatalog { unimplemented!() } - async fn get_table_meta_by_id( - &self, - table_id: MetaId, - is_temp: bool, - ) -> Result>> { - self.cat.get_table_meta_by_id(table_id, is_temp).await + async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { + self.cat.get_table_meta_by_id(table_id).await } } diff --git a/src/query/service/tests/it/storages/fuse/conflict.rs b/src/query/service/tests/it/storages/fuse/conflict.rs index 5bcfe9d22887..746e9ebc1b09 100644 --- a/src/query/service/tests/it/storages/fuse/conflict.rs +++ b/src/query/service/tests/it/storages/fuse/conflict.rs @@ -65,7 +65,6 @@ fn test_unresolvable_delete_conflict() { None, TxnManager::init(), 0, - false, ); assert!(result.is_err()); } @@ -157,7 +156,6 @@ fn test_resolvable_delete_conflict() { None, TxnManager::init(), 0, - false, ); let snapshot = result.unwrap(); let expected = vec![("8".to_string(), 1), ("4".to_string(), 1)]; @@ -265,7 +263,6 @@ fn test_resolvable_replace_conflict() { None, TxnManager::init(), 0, - false, ); let snapshot = result.unwrap(); let expected = vec![ diff --git a/src/query/service/tests/it/storages/fuse/operations/commit.rs b/src/query/service/tests/it/storages/fuse/operations/commit.rs index 9e52ca9a7698..d1e3ab6292ad 100644 --- a/src/query/service/tests/it/storages/fuse/operations/commit.rs +++ b/src/query/service/tests/it/storages/fuse/operations/commit.rs @@ -919,12 +919,8 @@ impl Catalog for FakedCatalog { self.cat.get_table_by_info(table_info) } - async fn get_table_meta_by_id( - &self, - table_id: MetaId, - is_temp: bool, - ) -> Result>> { - self.cat.get_table_meta_by_id(table_id, is_temp).await + async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { + self.cat.get_table_meta_by_id(table_id).await } #[async_backtrace::framed] @@ -936,12 +932,8 @@ impl Catalog for FakedCatalog { self.cat.mget_table_names_by_ids(tenant, table_id).await } - async fn get_table_name_by_id( - &self, - table_id: MetaId, - is_temp: bool, - ) -> Result> { - self.cat.get_table_name_by_id(table_id, is_temp).await + async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { + self.cat.get_table_name_by_id(table_id).await } async fn get_db_name_by_id(&self, db_id: MetaId) -> Result { diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index c52319243f8f..e637de8cd304 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -33,9 +33,13 @@ use databend_common_meta_app::schema::TableIdent; use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::TableMeta; use databend_common_meta_app::schema::UpdateTempTableReq; +use databend_common_meta_app::schema::UpsertTableOptionReply; +use databend_common_meta_app::schema::UpsertTableOptionReq; use databend_common_storage::DataOperator; use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; +use databend_storages_common_table_meta::table_id_ranges::TEMP_TBL_ID_BEGIN; +use databend_storages_common_table_meta::table_id_ranges::TEMP_TBL_ID_END; use parking_lot::Mutex; #[derive(Debug, Clone)] @@ -58,10 +62,17 @@ impl TempTblMgr { Arc::new(Mutex::new(TempTblMgr { name_to_id: HashMap::new(), id_to_table: HashMap::new(), - next_id: 0, + next_id: TEMP_TBL_ID_BEGIN, })) } + fn inc_next_id(&mut self) { + self.next_id += 1; + if self.next_id > TEMP_TBL_ID_END { + panic!("Temp table id used up"); + } + } + pub fn create_table(&mut self, req: CreateTableReq) -> Result { let CreateTableReq { create_option, @@ -98,7 +109,7 @@ impl TempTblMgr { meta: table_meta, _copied_files: BTreeMap::new(), }); - self.next_id += 1; + self.inc_next_id(); true } }; @@ -205,17 +216,41 @@ impl TempTblMgr { table._copied_files = copied_files; } } + + pub fn upsert_table_option( + &mut self, + req: UpsertTableOptionReq, + ) -> Result> { + let UpsertTableOptionReq { + table_id, options, .. + } = req; + let table = self.id_to_table.get_mut(&table_id); + let Some(table) = table else { + return Ok(None); + }; + for (k, v) in options { + if let Some(v) = v { + table.meta.options.insert(k, v); + } else { + table.meta.options.remove(&k); + } + } + Ok(Some(UpsertTableOptionReply { + share_vec_table_info: None, + })) + } } -pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Result { - let DropTableByIdReq { - if_exists, tb_id, .. - } = req; +pub async fn drop_table_by_id( + mgr: TempTblMgrRef, + req: DropTableByIdReq, +) -> Result> { + let DropTableByIdReq { tb_id, .. } = req; let dir = { let mut guard = mgr.lock(); let entry = guard.id_to_table.entry(tb_id); - match (entry, if_exists) { - (Entry::Occupied(e), _) => { + match entry { + Entry::Occupied(e) => { let dir = parse_storage_prefix(&e.get().meta.options, tb_id)?; let table = e.remove(); let desc = format!("{}.{}", table.db_name, table.table_name); @@ -227,20 +262,14 @@ pub async fn drop_table_by_id(mgr: TempTblMgrRef, req: DropTableByIdReq) -> Resu })?; dir } - (Entry::Vacant(_), true) => { - return Err(ErrorCode::UnknownTable(format!( - "Table not found in temp table manager {:?}, drop table request: {:?}", - *guard, req - ))); - } - (Entry::Vacant(_), false) => { - return Ok(Default::default()); + Entry::Vacant(_) => { + return Ok(None); } } }; let op = DataOperator::instance().operator(); op.remove_all(&dir).await?; - Ok(Default::default()) + Ok(Some(DropTableReply { spec_vec: None })) } pub type TempTblMgrRef = Arc>; diff --git a/src/query/storages/common/session/src/transaction.rs b/src/query/storages/common/session/src/transaction.rs index 6fa1e43576b8..913e89c513f0 100644 --- a/src/query/storages/common/session/src/transaction.rs +++ b/src/query/storages/common/session/src/transaction.rs @@ -226,9 +226,11 @@ impl TxnManager { .cloned() } - pub fn get_table_from_buffer_by_id(&self, table_id: u64, is_temp: bool) -> Option { - if is_temp { - self.txn_buffer.mutated_temp_tables.get(&table_id).map(|t| { + pub fn get_table_from_buffer_by_id(&self, table_id: u64) -> Option { + self.txn_buffer + .mutated_temp_tables + .get(&table_id) + .map(|t| { TableInfo::new( &t.db_name, &t.table_name, @@ -236,18 +238,18 @@ impl TxnManager { t.meta.clone(), ) }) - } else { - self.txn_buffer - .mutated_tables - .get(&table_id) - .cloned() - .or_else(|| { - self.txn_buffer - .stream_tables - .get(&table_id) - .map(|snapshot| snapshot.stream.clone()) - }) - } + .or_else(|| { + self.txn_buffer + .mutated_tables + .get(&table_id) + .cloned() + .or_else(|| { + self.txn_buffer + .stream_tables + .get(&table_id) + .map(|snapshot| snapshot.stream.clone()) + }) + }) } pub fn req(&self) -> UpdateMultiTableMetaReq { diff --git a/src/query/storages/common/table_meta/src/lib.rs b/src/query/storages/common/table_meta/src/lib.rs index 24db31be2f20..4691c9baad43 100644 --- a/src/query/storages/common/table_meta/src/lib.rs +++ b/src/query/storages/common/table_meta/src/lib.rs @@ -18,3 +18,4 @@ pub mod meta; pub mod readers; pub mod table; +pub mod table_id_ranges; diff --git a/src/query/service/src/catalogs/default/table_id_ranges.rs b/src/query/storages/common/table_meta/src/table_id_ranges.rs similarity index 84% rename from src/query/service/src/catalogs/default/table_id_ranges.rs rename to src/query/storages/common/table_meta/src/table_id_ranges.rs index 10fd576337cd..fb8d827bdfab 100644 --- a/src/query/service/src/catalogs/default/table_id_ranges.rs +++ b/src/query/storages/common/table_meta/src/table_id_ranges.rs @@ -24,6 +24,7 @@ pub const SYS_TBL_FUNC_ID_BEGIN: u64 = SYS_TBL_ID_END; // max id for table tables (exclusive) pub const SYS_TBL_FUC_ID_END: u64 = SYS_TBL_FUNC_ID_BEGIN + 10000; -// min id for system tables (inclusive) -// max id for local tables is u64:MAX -pub const LOCAL_TBL_ID_BEGIN: u64 = SYS_TBL_ID_END; +// min id for temp tables (inclusive) +pub const TEMP_TBL_ID_BEGIN: u64 = SYS_TBL_FUC_ID_END; +// max id for temp tables (exclusive) +pub const TEMP_TBL_ID_END: u64 = TEMP_TBL_ID_BEGIN + 10000; diff --git a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs index 254ee710cb92..bf031d62fbf2 100644 --- a/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs +++ b/src/query/storages/fuse/src/operations/common/generators/snapshot_generator.rs @@ -46,7 +46,6 @@ pub trait SnapshotGenerator { prev_table_seq: Option, txn_mgr: TxnManagerRef, table_id: u64, - is_temp: bool, ) -> Result { let mut snapshot = self.do_generate_new_snapshot(schema, cluster_key_meta, &previous, prev_table_seq)?; @@ -56,10 +55,7 @@ pub trait SnapshotGenerator { // NOTE: // When generating a new snapshot for a mutation of table for the first time, // there is no buffered table ID inside txn_mgr for this table. - guard.is_active() - && guard - .get_table_from_buffer_by_id(table_id, is_temp) - .is_some() + guard.is_active() && guard.get_table_from_buffer_by_id(table_id).is_some() }; if has_pending_transactional_mutations { diff --git a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs index c1fc8c1b10c9..bbf90d8d2640 100644 --- a/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/multi_table_insert_commit.rs @@ -257,7 +257,6 @@ async fn build_update_table_meta_req( Some(fuse_table.table_info.ident.seq), txn_mgr, table.get_id(), - table.is_temp(), )?; // write snapshot diff --git a/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs b/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs index 21489d2bac3a..4fafb34cd072 100644 --- a/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs +++ b/src/query/storages/fuse/src/operations/common/processors/sink_commit.rs @@ -288,7 +288,6 @@ where F: SnapshotGenerator + Send + 'static Some(table_info.ident.seq), self.ctx.txn_mgr(), table_info.ident.table_id, - self.table.is_temp(), ) { Ok(snapshot) => { self.state = State::TryCommit { diff --git a/src/query/storages/hive/hive/src/hive_catalog.rs b/src/query/storages/hive/hive/src/hive_catalog.rs index 3eac6b48ccdc..a2ebfcb1e5f7 100644 --- a/src/query/storages/hive/hive/src/hive_catalog.rs +++ b/src/query/storages/hive/hive/src/hive_catalog.rs @@ -354,11 +354,7 @@ impl Catalog for HiveCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id( - &self, - _table_id: MetaId, - _is_temp: bool, - ) -> Result>> { + async fn get_table_meta_by_id(&self, _table_id: MetaId) -> Result>> { Err(ErrorCode::Unimplemented( "Cannot get table by id in HIVE catalog", )) @@ -375,11 +371,7 @@ impl Catalog for HiveCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id( - &self, - _table_id: MetaId, - _is_temp: bool, - ) -> Result> { + async fn get_table_name_by_id(&self, _table_id: MetaId) -> Result> { Err(ErrorCode::Unimplemented( "Cannot get table name by id in HIVE catalog", )) diff --git a/src/query/storages/iceberg/src/catalog.rs b/src/query/storages/iceberg/src/catalog.rs index b42ff464a2ac..1394c71acc3c 100644 --- a/src/query/storages/iceberg/src/catalog.rs +++ b/src/query/storages/iceberg/src/catalog.rs @@ -254,11 +254,7 @@ impl Catalog for IcebergCatalog { } #[async_backtrace::framed] - async fn get_table_meta_by_id( - &self, - _table_id: MetaId, - _is_temp: bool, - ) -> Result>> { + async fn get_table_meta_by_id(&self, _table_id: MetaId) -> Result>> { unimplemented!() } @@ -273,11 +269,7 @@ impl Catalog for IcebergCatalog { } #[async_backtrace::framed] - async fn get_table_name_by_id( - &self, - _table_id: MetaId, - _is_temp: bool, - ) -> Result> { + async fn get_table_name_by_id(&self, _table_id: MetaId) -> Result> { Err(ErrorCode::Unimplemented( "Cannot get table name by id in ICEBERG catalog", )) diff --git a/src/query/storages/stream/src/stream_table.rs b/src/query/storages/stream/src/stream_table.rs index e2864ec8fc39..c9408b828c6f 100644 --- a/src/query/storages/stream/src/stream_table.rs +++ b/src/query/storages/stream/src/stream_table.rs @@ -153,7 +153,7 @@ impl StreamTable { pub async fn source_table_name(&self, catalog: &dyn Catalog) -> Result { let source_table_id = self.source_table_id()?; catalog - .get_table_name_by_id(source_table_id, false) + .get_table_name_by_id(source_table_id) .await .and_then(|opt| { opt.ok_or(ErrorCode::UnknownTable(format!( @@ -176,7 +176,7 @@ impl StreamTable { None => { let source_table_id = self.source_table_id()?; let source_table_meta = catalog - .get_table_meta_by_id(source_table_id, false) + .get_table_meta_by_id(source_table_id) .await? .ok_or(ErrorCode::Internal("source database id must be set"))?; source_table_meta From c8bd0159c901016a6f8e8428747991ac80bb457c Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sat, 17 Aug 2024 12:34:26 +0800 Subject: [PATCH 28/51] make lint --- Cargo.lock | 31 +++++++++++--------- src/query/catalog/Cargo.toml | 2 +- src/query/service/src/sessions/query_ctx.rs | 1 + src/query/storages/common/session/Cargo.toml | 2 +- src/query/storages/fuse/Cargo.toml | 2 +- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4fca94202846..6975b9305952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3253,8 +3253,8 @@ dependencies = [ "databend-common-settings", "databend-common-storage", "databend-common-users", + "databend-storages-common-session", "databend-storages-common-table-meta", - "databend-storages-common-txn", "dyn-clone", "goldenfile", "log", @@ -4297,8 +4297,8 @@ dependencies = [ "databend-storages-common-index", "databend-storages-common-io", "databend-storages-common-pruner", + "databend-storages-common-session", "databend-storages-common-table-meta", - "databend-storages-common-txn", "enum-as-inner 0.5.1", "fastrace", "futures", @@ -5171,8 +5171,8 @@ dependencies = [ "databend-storages-common-cache-manager", "databend-storages-common-index", "databend-storages-common-io", + "databend-storages-common-session", "databend-storages-common-table-meta", - "databend-storages-common-txn", "derive-visitor", "ethnum", "fastrace", @@ -5419,6 +5419,20 @@ dependencies = [ "typetag", ] +[[package]] +name = "databend-storages-common-session" +version = "0.1.0" +dependencies = [ + "databend-common-exception", + "databend-common-meta-app", + "databend-common-meta-types", + "databend-common-storage", + "databend-storages-common-table-meta", + "parking_lot 0.12.3", + "serde", + "uuid", +] + [[package]] name = "databend-storages-common-stage" version = "0.1.0" @@ -5457,17 +5471,6 @@ dependencies = [ "zstd 0.12.4", ] -[[package]] -name = "databend-storages-common-txn" -version = "0.1.0" -dependencies = [ - "databend-common-meta-app", - "databend-common-meta-types", - "parking_lot 0.12.3", - "serde", - "uuid", -] - [[package]] name = "datafusion" version = "39.0.0" diff --git a/src/query/catalog/Cargo.toml b/src/query/catalog/Cargo.toml index d9b4f50aa8d5..37234b32145b 100644 --- a/src/query/catalog/Cargo.toml +++ b/src/query/catalog/Cargo.toml @@ -31,8 +31,8 @@ databend-common-pipeline-core = { workspace = true } databend-common-settings = { workspace = true } databend-common-storage = { workspace = true } databend-common-users = { workspace = true } -databend-storages-common-table-meta = { workspace = true } databend-storages-common-session = { workspace = true } +databend-storages-common-table-meta = { workspace = true } dyn-clone = "1.0.9" log = { workspace = true } parking_lot = { workspace = true } diff --git a/src/query/service/src/sessions/query_ctx.rs b/src/query/service/src/sessions/query_ctx.rs index 16861bdc6019..0ba9e2cc58e4 100644 --- a/src/query/service/src/sessions/query_ctx.rs +++ b/src/query/service/src/sessions/query_ctx.rs @@ -11,6 +11,7 @@ // 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::cmp::min; use std::collections::hash_map::Entry; diff --git a/src/query/storages/common/session/Cargo.toml b/src/query/storages/common/session/Cargo.toml index 21e42d7d2c18..9f6e18a85cb6 100644 --- a/src/query/storages/common/session/Cargo.toml +++ b/src/query/storages/common/session/Cargo.toml @@ -10,8 +10,8 @@ edition = { workspace = true } databend-common-exception = { workspace = true } databend-common-meta-app = { workspace = true } databend-common-meta-types = { workspace = true } -databend-storages-common-table-meta = { workspace = true } databend-common-storage = { workspace = true } +databend-storages-common-table-meta = { workspace = true } parking_lot = { workspace = true } serde = { version = "1.0.194", features = ["derive"] } uuid = { workspace = true } diff --git a/src/query/storages/fuse/Cargo.toml b/src/query/storages/fuse/Cargo.toml index d1841e63a984..efed0789d7d4 100644 --- a/src/query/storages/fuse/Cargo.toml +++ b/src/query/storages/fuse/Cargo.toml @@ -47,8 +47,8 @@ databend-storages-common-cache-manager = { workspace = true } databend-storages-common-index = { workspace = true } databend-storages-common-io = { workspace = true } databend-storages-common-pruner = { workspace = true } -databend-storages-common-table-meta = { workspace = true } databend-storages-common-session = { workspace = true } +databend-storages-common-table-meta = { workspace = true } enum-as-inner = "0.5" fastrace = { workspace = true } futures = { workspace = true } From 3e4b73fa69c5355bd1c578b744193247ac868fb8 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sat, 17 Aug 2024 21:01:04 +0800 Subject: [PATCH 29/51] regenerate golden file --- src/query/ast/tests/it/testdata/stmt.txt | 46 ++++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/query/ast/tests/it/testdata/stmt.txt b/src/query/ast/tests/it/testdata/stmt.txt index 7a80b161848c..3982f9a16c9b 100644 --- a/src/query/ast/tests/it/testdata/stmt.txt +++ b/src/query/ast/tests/it/testdata/stmt.txt @@ -1654,7 +1654,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -1705,7 +1705,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -1756,7 +1756,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -1804,7 +1804,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -1887,7 +1887,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2031,7 +2031,7 @@ CreateTable( ignore_result: false, }, ), - transient: false, + table_type: Normal, }, ) @@ -2132,7 +2132,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2209,7 +2209,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2362,7 +2362,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2492,7 +2492,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2597,7 +2597,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2657,7 +2657,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2701,7 +2701,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2773,7 +2773,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -2847,7 +2847,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -3186,7 +3186,7 @@ CreateTable( "storage_format": "native", }, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -3325,7 +3325,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -4734,7 +4734,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -4814,7 +4814,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -4875,7 +4875,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -4934,7 +4934,7 @@ CreateTable( cluster_by: [], table_options: {}, as_query: None, - transient: false, + table_type: Normal, }, ) @@ -5033,7 +5033,7 @@ CreateTable( ignore_result: false, }, ), - transient: false, + table_type: Normal, }, ) @@ -12771,7 +12771,7 @@ CreateTable( "comment": "table comment", }, as_query: None, - transient: false, + table_type: Normal, }, ) From 54925ed3352a3a142ea0db0a9b8d1d4cff6c6a93 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sat, 17 Aug 2024 21:10:43 +0800 Subject: [PATCH 30/51] fix catalog and add drop table test --- .../src/catalogs/default/database_catalog.rs | 9 ++++++ .../suites/temp_table/drop_temp_tables.sql | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/sqllogictests/suites/temp_table/drop_temp_tables.sql diff --git a/src/query/service/src/catalogs/default/database_catalog.rs b/src/query/service/src/catalogs/default/database_catalog.rs index a86b75fdcad5..8ad7e12e6d8a 100644 --- a/src/query/service/src/catalogs/default/database_catalog.rs +++ b/src/query/service/src/catalogs/default/database_catalog.rs @@ -742,4 +742,13 @@ impl Catalog for DatabaseCatalog { table_function_factory: self.table_function_factory.clone(), }) } + + fn get_stream_source_table(&self, _stream_desc: &str) -> Result>> { + self.session_catalog.get_stream_source_table(_stream_desc) + } + + fn cache_stream_source_table(&self, _stream: TableInfo, _source: TableInfo) { + self.session_catalog + .cache_stream_source_table(_stream, _source) + } } diff --git a/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql b/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql new file mode 100644 index 000000000000..658d522fc629 --- /dev/null +++ b/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql @@ -0,0 +1,32 @@ +statement ok +DROP TABLE IF EXISTS t + +statement ok +CREATE TEMPORARY TABLE t(c1 int) ENGINE = Null + +statement ok +DROP TABLE t + +statement ok +DROP TABLE IF EXISTS t + +statement error 1025 +DROP TABLE t + +statement ok +DROP TABLE if exists database_error.t + +statement ok +DROP TABLE IF EXISTS catalog_error.database_error.t + +statement error 1003 +DROP TABLE database_error.t + +statement error 1119 +DROP TABLE catalog_error.database_error.t + +statement error 1025 +DROP TABLE system.abc + +statement ok +DROP TABLE if exists system.abc From a2839829e9f234bc0ee2d25665aeb28180b231db Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sun, 18 Aug 2024 11:11:26 +0800 Subject: [PATCH 31/51] fix catalog --- tests/sqllogictests/suites/temp_table/drop_temp_tables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql b/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql index 658d522fc629..f0751cd8ac39 100644 --- a/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql @@ -2,7 +2,7 @@ statement ok DROP TABLE IF EXISTS t statement ok -CREATE TEMPORARY TABLE t(c1 int) ENGINE = Null +CREATE TEMPORARY TABLE t(c1 int) statement ok DROP TABLE t From 3cbc84ff233df8f330a698e5c0f986ae9dc3332b Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sun, 18 Aug 2024 12:58:53 +0800 Subject: [PATCH 32/51] add alter temp table test --- .../suites/temp_table/alter_temp_tables.sql | 257 ++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 tests/sqllogictests/suites/temp_table/alter_temp_tables.sql diff --git a/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql b/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql new file mode 100644 index 000000000000..b327c7a69a41 --- /dev/null +++ b/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql @@ -0,0 +1,257 @@ +statement ok +USE default + +statement ok +set sql_dialect = 'PostgreSQL' + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t0` + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t1` + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t2` + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t3` + +statement ok +CREATE TEMP TABLE `05_0003_at_t0`(a int not null) + +statement ok +INSERT INTO TABLE `05_0003_at_t0` values(1) + +query I +SELECT * FROM `05_0003_at_t0` +---- +1 + +statement ok +ALTER TABLE `05_0003_at_t0` RENAME TO `05_0003_at_t1` + +statement error 1025 +ALTER TABLE `05_0003_at_t0` RENAME TO `05_0003_at_t1` + +statement ok +ALTER TABLE IF EXISTS `05_0003_at_t0` RENAME TO `05_0003_at_t1` + +statement error 1025 +DROP TABLE `05_0003_at_t0` + +query I +SELECT * FROM `05_0003_at_t1` +---- +1 + +statement error 1005 +ALTER TABLE `05_0003_at_t1` RENAME TO system.`05_0003_at_t1` + +statement error 1025 +ALTER TABLE system.abc drop column c1 + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t1` + +statement ok +CREATE TEMP TABLE `05_0003_at_t2`(a int not null, c int not null) + +statement ok +INSERT INTO TABLE `05_0003_at_t2` values(1,2) + +statement error 1065 +ALTER TABLE `05_0003_at_t2` rename column a to a + +statement error 1110 +ALTER TABLE `05_0003_at_t2` rename column a to _row_id + +statement error 1065 +ALTER TABLE `05_0003_at_t2` rename column a to c + +statement error 1065 +ALTER TABLE `05_0003_at_t2` rename column d to e + +statement ok +ALTER TABLE `05_0003_at_t2` rename column a to b + +query I +SELECT b FROM `05_0003_at_t2` +---- +1 + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t2` + +statement ok +set hide_options_in_show_create_table=0 + +statement ok +CREATE TEMP TABLE `05_0003_at_t3`(a int not null, b int not null, c int not null) bloom_index_columns='a,b,c' COMPRESSION='zstd' STORAGE_FORMAT='native' + +query TT +SHOW CREATE TABLE `05_0003_at_t3` +---- +05_0003_at_t3 CREATE TEMP TABLE "05_0003_at_t3" ( a INT NOT NULL, b INT NOT NULL, c INT NOT NULL ) ENGINE=FUSE BLOOM_INDEX_COLUMNS='a,b,c' COMPRESSION='zstd' STORAGE_FORMAT='native' + +statement ok +ALTER TABLE `05_0003_at_t3` drop column c + +query TT +SHOW CREATE TABLE `05_0003_at_t3` +---- +05_0003_at_t3 CREATE TEMP TABLE "05_0003_at_t3" ( a INT NOT NULL, b INT NOT NULL ) ENGINE=FUSE BLOOM_INDEX_COLUMNS='a,b' COMPRESSION='zstd' STORAGE_FORMAT='native' + +statement ok +ALTER TABLE `05_0003_at_t3` rename column b to c + +query TT +SHOW CREATE TABLE `05_0003_at_t3` +---- +05_0003_at_t3 CREATE TEMP TABLE "05_0003_at_t3" ( a INT NOT NULL, c INT NOT NULL ) ENGINE=FUSE BLOOM_INDEX_COLUMNS='a,c' COMPRESSION='zstd' STORAGE_FORMAT='native' + +statement error 1301 +ALTER TABLE `05_0003_at_t3` MODIFY COLUMN c decimal(5,2) not null + +statement ok +ALTER TABLE `05_0003_at_t3` MODIFY COLUMN c float not null + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t3` + +statement ok +set hide_options_in_show_create_table=1 + +statement ok +CREATE TEMP TABLE "05_0003_at_t4" ( a string not null, b string null, c array(string) null, d tuple(string, string) null ) ENGINE=FUSE COMPRESSION='zstd' STORAGE_FORMAT='native' + +statement ok +INSERT INTO TABLE `05_0003_at_t4` values('a', 'b', ['c1', 'c2'], ('d1', 'd2')) + +query TT +SHOW CREATE TABLE `05_0003_at_t4` +---- +05_0003_at_t4 CREATE TEMP TABLE "05_0003_at_t4" ( a VARCHAR NOT NULL, b VARCHAR NULL, c ARRAY(STRING) NULL, d TUPLE(1 STRING, 2 STRING) NULL ) ENGINE=FUSE + +query TTTT +SELECT * FROM `05_0003_at_t4` +---- +a b ['c1','c2'] ('d1','d2') + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN a binary not null + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN b binary null + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN c array(binary) null + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN d tuple(binary, binary) null + +query TT +SHOW CREATE TABLE `05_0003_at_t4` +---- +05_0003_at_t4 CREATE TEMP TABLE "05_0003_at_t4" ( a BINARY NOT NULL, b BINARY NULL, c ARRAY(BINARY) NULL, d TUPLE(1 BINARY, 2 BINARY) NULL ) ENGINE=FUSE + +query +SELECT * FROM `05_0003_at_t4` +---- +61 62 [6331,6332] (6431,6432) + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN a string not null + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN b string null + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN c array(string) null + +statement ok +ALTER TABLE `05_0003_at_t4` MODIFY COLUMN d tuple(string, string) null + +query TT +SHOW CREATE TABLE `05_0003_at_t4` +---- +05_0003_at_t4 CREATE TEMP TABLE "05_0003_at_t4" ( a VARCHAR NOT NULL, b VARCHAR NULL, c ARRAY(STRING) NULL, d TUPLE(1 STRING, 2 STRING) NULL ) ENGINE=FUSE + +query TTTT +SELECT * FROM `05_0003_at_t4` +---- +a b ['c1','c2'] ('d1','d2') + +statement ok +DROP TABLE IF EXISTS `05_0003_at_t4` + +statement ok +drop table if exists t; + +statement ok +create temp table t(c1 int, c2 int); + +statement ok +alter table t modify c1 varchar, c2 varchar; + +query TT +DESC t; +---- +c1 VARCHAR YES NULL (empty) +c2 VARCHAR YES NULL (empty) + +statement ok +alter table t modify c1 varchar comment 'c1-column', c2 int comment 'test'; + +query TTTTT +select database,table,name,data_type,comment from system.columns where table='t' and database='default'; +---- +default t c1 VARCHAR 'c1-column' +default t c2 INT 'test' + +statement ok +alter table t comment='s1'; + +query TT +select name, comment from system.tables where name='t' and database='default'; +---- +t s1 + +query TT +show create temp table t; +---- +t CREATE TEMP TABLE t ( c1 VARCHAR NULL COMMENT 'c1-column', c2 INT NULL COMMENT 'test' ) ENGINE=FUSE COMMENT = 's1' + +statement ok +drop table if exists t1; + +statement ok +create temp table t1(id int) comment ='t1-comment'; + +query TT +show create temp table t1; +---- +t1 CREATE TEMP TABLE t1 ( id INT NULL ) ENGINE=FUSE COMMENT = 't1-comment' + +query TT +select name, comment from system.tables where name='t1' and database='default'; +---- +t1 t1-comment + +statement ok +alter table t1 comment='t1-new-comment'; + +query TT +show create temp table t1; +---- +t1 CREATE TEMP TABLE t1 ( id INT NULL ) ENGINE=FUSE COMMENT = 't1-new-comment' + +query TT +select name, comment from system.tables where name='t1' and database='default'; +---- +t1 t1-new-comment + +statement ok +DROP TABLE IF EXISTS t; + +statement ok +DROP TABLE IF EXISTS t1; From 1f1f6af25b37da23f38632826ee0f396e55aca1b Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sun, 18 Aug 2024 13:17:10 +0800 Subject: [PATCH 33/51] fix show create table --- .../src/interpreters/interpreter_table_show_create.rs | 8 ++++++++ .../storages/common/table_meta/src/table/table_keys.rs | 1 + .../sqllogictests/suites/temp_table/alter_temp_tables.sql | 6 +++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/query/service/src/interpreters/interpreter_table_show_create.rs b/src/query/service/src/interpreters/interpreter_table_show_create.rs index 3874a13d800c..a657649b332b 100644 --- a/src/query/service/src/interpreters/interpreter_table_show_create.rs +++ b/src/query/service/src/interpreters/interpreter_table_show_create.rs @@ -35,6 +35,7 @@ use databend_storages_common_table_meta::table::is_internal_opt_key; use databend_storages_common_table_meta::table::StreamMode; use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_PREFIX; use databend_storages_common_table_meta::table::OPT_KEY_TABLE_ATTACHED_DATA_URI; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use crate::interpreters::Interpreter; use crate::pipelines::PipelineBuildResult; @@ -154,6 +155,13 @@ impl ShowCreateTableInterpreter { ) } + if table.options().contains_key(OPT_KEY_TEMP_PREFIX) { + table_create_sql = format!( + "CREATE TEMP TABLE {} (\n", + display_ident(name, quoted_ident_case_sensitive, sql_dialect) + ) + } + let table_info = table.get_table_info(); // Append columns and indexes. diff --git a/src/query/storages/common/table_meta/src/table/table_keys.rs b/src/query/storages/common/table_meta/src/table/table_keys.rs index d7726d13fce6..11944ebc72f8 100644 --- a/src/query/storages/common/table_meta/src/table/table_keys.rs +++ b/src/query/storages/common/table_meta/src/table/table_keys.rs @@ -65,6 +65,7 @@ pub static INTERNAL_TABLE_OPTION_KEYS: LazyLock> = LazyLoc r.insert(OPT_KEY_DATABASE_ID); r.insert(OPT_KEY_ENGINE_META); r.insert(OPT_KEY_CHANGE_TRACKING_BEGIN_VER); + r.insert(OPT_KEY_TEMP_PREFIX); r }); diff --git a/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql b/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql index b327c7a69a41..11661ce81581 100644 --- a/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql @@ -217,7 +217,7 @@ select name, comment from system.tables where name='t' and database='default'; t s1 query TT -show create temp table t; +show create table t; ---- t CREATE TEMP TABLE t ( c1 VARCHAR NULL COMMENT 'c1-column', c2 INT NULL COMMENT 'test' ) ENGINE=FUSE COMMENT = 's1' @@ -228,7 +228,7 @@ statement ok create temp table t1(id int) comment ='t1-comment'; query TT -show create temp table t1; +show create table t1; ---- t1 CREATE TEMP TABLE t1 ( id INT NULL ) ENGINE=FUSE COMMENT = 't1-comment' @@ -241,7 +241,7 @@ statement ok alter table t1 comment='t1-new-comment'; query TT -show create temp table t1; +show create table t1; ---- t1 CREATE TEMP TABLE t1 ( id INT NULL ) ENGINE=FUSE COMMENT = 't1-new-comment' From 83f56b8de481b79ce9799df2809f15460ee86a37 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Sun, 18 Aug 2024 13:27:28 +0800 Subject: [PATCH 34/51] add rename temp table test --- tests/sqllogictests/data/tpch.tar.gz | Bin 0 -> 49152 bytes .../suites/temp_table/rename_temp_tables.sql | 98 ++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 tests/sqllogictests/data/tpch.tar.gz create mode 100644 tests/sqllogictests/suites/temp_table/rename_temp_tables.sql diff --git a/tests/sqllogictests/data/tpch.tar.gz b/tests/sqllogictests/data/tpch.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..22eabb636871d56c7f7d6c88ea15d9fac58f621c GIT binary patch literal 49152 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�|4Lp5{oxg-RVMvG5GyGK>t06Z+}pRw|p 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
(WT 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 Date: Sun, 18 Aug 2024 15:05:39 +0800 Subject: [PATCH 35/51] add truncate test --- .../src/catalogs/default/session_catalog.rs | 30 ++++++----- .../storages/common/session/src/temp_table.rs | 54 +++++++++++++------ .../common/session/src/transaction.rs | 4 +- .../common/table_meta/src/table_id_ranges.rs | 4 ++ .../temp_table/truncate_temp_tables.sql | 41 ++++++++++++++ 5 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql diff --git a/src/query/service/src/catalogs/default/session_catalog.rs b/src/query/service/src/catalogs/default/session_catalog.rs index dfb00983ed53..ef03157b23cf 100644 --- a/src/query/service/src/catalogs/default/session_catalog.rs +++ b/src/query/service/src/catalogs/default/session_catalog.rs @@ -105,6 +105,7 @@ use databend_storages_common_session::TempTblMgrRef; use databend_storages_common_session::TxnManagerRef; use databend_storages_common_session::TxnState; use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; +use databend_storages_common_table_meta::table_id_ranges::is_temp_table_id; use crate::catalogs::default::MutableCatalog; use crate::catalogs::Catalog; @@ -248,10 +249,11 @@ impl Catalog for SessionCatalog { } { return Ok(Some(SeqV::new(t.ident.seq, t.meta.clone()))); } - if let Some(meta) = self.temp_tbl_mgr.lock().get_table_meta_by_id(table_id) { - return Ok(Some(SeqV::new(0, meta))); + if is_temp_table_id(table_id) { + self.temp_tbl_mgr.lock().get_table_meta_by_id(table_id) + } else { + self.inner.get_table_meta_by_id(table_id).await } - self.inner.get_table_meta_by_id(table_id).await } // TODO: implement this @@ -376,10 +378,10 @@ impl Catalog for SessionCatalog { } async fn commit_table_meta(&self, req: CommitTableMetaReq) -> Result { - let reply = self.temp_tbl_mgr.lock().commit_table_meta(&req)?; - match reply { - Some(r) => Ok(r), - None => self.inner.commit_table_meta(req).await, + if is_temp_table_id(req.table_id) { + self.temp_tbl_mgr.lock().commit_table_meta(&req) + } else { + self.inner.commit_table_meta(req).await } } @@ -397,10 +399,11 @@ impl Catalog for SessionCatalog { db_name: &str, req: UpsertTableOptionReq, ) -> Result { - if let Some(reply) = self.temp_tbl_mgr.lock().upsert_table_option(req.clone())? { - return Ok(reply); + if is_temp_table_id(req.table_id) { + self.temp_tbl_mgr.lock().upsert_table_option(req) + } else { + self.inner.upsert_table_option(tenant, db_name, req).await } - self.inner.upsert_table_option(tenant, db_name, req).await } async fn retryable_update_multi_table_meta( @@ -459,13 +462,16 @@ impl Catalog for SessionCatalog { Ok(reply) } - // TODO: implement this async fn truncate_table( &self, table_info: &TableInfo, req: TruncateTableReq, ) -> Result { - self.inner.truncate_table(table_info, req).await + if is_temp_table_id(req.table_id) { + self.temp_tbl_mgr.lock().truncate_table(req.table_id) + } else { + self.inner.truncate_table(table_info, req).await + } } async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result> { diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index e637de8cd304..05230dbb295a 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -32,14 +32,16 @@ use databend_common_meta_app::schema::TableCopiedFileInfo; use databend_common_meta_app::schema::TableIdent; use databend_common_meta_app::schema::TableInfo; use databend_common_meta_app::schema::TableMeta; +use databend_common_meta_app::schema::TruncateTableReply; use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_meta_app::schema::UpsertTableOptionReply; use databend_common_meta_app::schema::UpsertTableOptionReq; +use databend_common_meta_types::SeqV; use databend_common_storage::DataOperator; use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; +use databend_storages_common_table_meta::table_id_ranges::is_temp_table_id; use databend_storages_common_table_meta::table_id_ranges::TEMP_TBL_ID_BEGIN; -use databend_storages_common_table_meta::table_id_ranges::TEMP_TBL_ID_END; use parking_lot::Mutex; #[derive(Debug, Clone)] @@ -54,7 +56,7 @@ pub struct TempTable { pub db_name: String, pub table_name: String, pub meta: TableMeta, - pub _copied_files: BTreeMap, + pub copied_files: BTreeMap, } impl TempTblMgr { @@ -68,7 +70,7 @@ impl TempTblMgr { fn inc_next_id(&mut self) { self.next_id += 1; - if self.next_id > TEMP_TBL_ID_END { + if !is_temp_table_id(self.next_id) { panic!("Temp table id used up"); } } @@ -107,7 +109,7 @@ impl TempTblMgr { db_name: name_ident.db_name, table_name: orphan_table_name.clone().unwrap_or(name_ident.table_name), meta: table_meta, - _copied_files: BTreeMap::new(), + copied_files: BTreeMap::new(), }); self.inc_next_id(); true @@ -124,10 +126,7 @@ impl TempTblMgr { }) } - pub fn commit_table_meta( - &mut self, - req: &CommitTableMetaReq, - ) -> Result> { + pub fn commit_table_meta(&mut self, req: &CommitTableMetaReq) -> Result { let orphan_desc = format!( "{}.{}", req.name_ident.db_name, @@ -140,9 +139,12 @@ impl TempTblMgr { let table = self.id_to_table.get_mut(&id).unwrap(); table.db_name = req.name_ident.db_name.clone(); table.table_name = req.name_ident.table_name.clone(); - Ok(Some(CommitTableMetaReply {})) + Ok(CommitTableMetaReply {}) } - None => Ok(None), + None => Err(ErrorCode::UnknownTable(format!( + "Temporary table {}.{} not found", + req.name_ident.db_name, req.name_ident.table_name + ))), } } @@ -170,8 +172,11 @@ impl TempTblMgr { } } - pub fn get_table_meta_by_id(&self, id: u64) -> Option { - self.id_to_table.get(&id).map(|t| t.meta.clone()) + pub fn get_table_meta_by_id(&self, id: u64) -> Result>> { + Ok(self + .id_to_table + .get(&id) + .map(|t| SeqV::new(0, t.meta.clone()))) } pub fn get_table_name_by_id(&self, id: u64) -> Option { @@ -213,20 +218,23 @@ impl TempTblMgr { } = r; let table = self.id_to_table.get_mut(&table_id).unwrap(); table.meta = new_table_meta; - table._copied_files = copied_files; + table.copied_files = copied_files; } } pub fn upsert_table_option( &mut self, req: UpsertTableOptionReq, - ) -> Result> { + ) -> Result { let UpsertTableOptionReq { table_id, options, .. } = req; let table = self.id_to_table.get_mut(&table_id); let Some(table) = table else { - return Ok(None); + return Err(ErrorCode::UnknownTable(format!( + "Temporary table id {} not found", + table_id + ))); }; for (k, v) in options { if let Some(v) = v { @@ -235,9 +243,21 @@ impl TempTblMgr { table.meta.options.remove(&k); } } - Ok(Some(UpsertTableOptionReply { + Ok(UpsertTableOptionReply { share_vec_table_info: None, - })) + }) + } + + pub fn truncate_table(&mut self, id: u64) -> Result { + let table = self.id_to_table.get_mut(&id); + let Some(table) = table else { + return Err(ErrorCode::UnknownTable(format!( + "Temporary table id {} not found", + id + ))); + }; + table.copied_files.clear(); + Ok(TruncateTableReply {}) } } diff --git a/src/query/storages/common/session/src/transaction.rs b/src/query/storages/common/session/src/transaction.rs index 913e89c513f0..e03339bdb458 100644 --- a/src/query/storages/common/session/src/transaction.rs +++ b/src/query/storages/common/session/src/transaction.rs @@ -103,7 +103,7 @@ impl TxnBuffer { db_name: db_name.to_string(), table_name: table_name.to_string(), meta: req.new_table_meta.clone(), - _copied_files: req.copied_files.clone(), + copied_files: req.copied_files.clone(), }); } } @@ -295,7 +295,7 @@ impl TxnManager { .map(|(id, t)| UpdateTempTableReq { table_id: *id, new_table_meta: t.meta.clone(), - copied_files: t._copied_files.clone(), + copied_files: t.copied_files.clone(), desc: format!("'{}'.'{}'", t.db_name, t.table_name), }) .collect(), diff --git a/src/query/storages/common/table_meta/src/table_id_ranges.rs b/src/query/storages/common/table_meta/src/table_id_ranges.rs index fb8d827bdfab..b604afa800e1 100644 --- a/src/query/storages/common/table_meta/src/table_id_ranges.rs +++ b/src/query/storages/common/table_meta/src/table_id_ranges.rs @@ -28,3 +28,7 @@ pub const SYS_TBL_FUC_ID_END: u64 = SYS_TBL_FUNC_ID_BEGIN + 10000; pub const TEMP_TBL_ID_BEGIN: u64 = SYS_TBL_FUC_ID_END; // max id for temp tables (exclusive) pub const TEMP_TBL_ID_END: u64 = TEMP_TBL_ID_BEGIN + 10000; + +pub fn is_temp_table_id(id: u64) -> bool { + (TEMP_TBL_ID_BEGIN..TEMP_TBL_ID_END).contains(&id) +} diff --git a/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql b/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql new file mode 100644 index 000000000000..22e307ae2de1 --- /dev/null +++ b/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql @@ -0,0 +1,41 @@ +statement ok +DROP TABLE IF EXISTS t1 + +statement ok +CREATE TEMP TABLE t1(c1 int) + +statement ok +INSERT INTO TABLE t1 values(1) + +statement ok +SELECT * FROM t1 + +statement ok +TRUNCATE TABLE t1 + +statement ok +DROP TABLE IF EXISTS t1 + +statement ok +DROP TABLE IF EXISTS t2 + +statement ok +CREATE TEMP TABLE t2(c1 int) ENGINE = FUSE + +statement ok +INSERT INTO TABLE t2 values(1) + +query I +SELECT * FROM t2 +---- +1 + +statement ok +TRUNCATE TABLE t2 + +statement ok +SELECT * FROM t2 + +statement ok +DROP TABLE IF EXISTS t2 + From 09779f7adfe2d2b817cf2864617fe3fac0bb2e2f Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 11:58:35 +0800 Subject: [PATCH 36/51] add copy into test --- src/meta/app/src/schema/table.rs | 10 ++ .../src/catalogs/default/session_catalog.rs | 22 +++- .../storages/common/session/src/temp_table.rs | 21 +++ .../storages/fuse/src/operations/commit.rs | 4 +- tests/sqllogictests/data/tpch.tar.gz | Bin 49152 -> 0 bytes .../suites/stage/copy_into_temp_table.sql | 123 ++++++++++++++++++ 6 files changed, 172 insertions(+), 8 deletions(-) delete mode 100644 tests/sqllogictests/data/tpch.tar.gz create mode 100644 tests/sqllogictests/suites/stage/copy_into_temp_table.sql diff --git a/src/meta/app/src/schema/table.rs b/src/meta/app/src/schema/table.rs index 2b202f49bf3f..1b0641f103af 100644 --- a/src/meta/app/src/schema/table.rs +++ b/src/meta/app/src/schema/table.rs @@ -739,6 +739,16 @@ pub struct UpdateMultiTableMetaReq { pub update_temp_tables: Vec, } +impl UpdateMultiTableMetaReq { + pub fn is_empty(&self) -> bool { + self.update_table_metas.is_empty() + && self.copied_files.is_empty() + && self.update_stream_metas.is_empty() + && self.deduplicated_labels.is_empty() + && self.update_temp_tables.is_empty() + } +} + /// The result of updating multiple table meta /// /// If update fails due to table version mismatch, the `Err` will contain the (table id, seq , table meta)s that fail to update. diff --git a/src/query/service/src/catalogs/default/session_catalog.rs b/src/query/service/src/catalogs/default/session_catalog.rs index ef03157b23cf..9b417386eedd 100644 --- a/src/query/service/src/catalogs/default/session_catalog.rs +++ b/src/query/service/src/catalogs/default/session_catalog.rs @@ -414,8 +414,11 @@ impl Catalog for SessionCatalog { match state { TxnState::AutoCommit => { let update_temp_tables = std::mem::take(&mut req.update_temp_tables); - println!("{:?}", update_temp_tables); - let reply = self.inner.retryable_update_multi_table_meta(req).await?; + let reply = if req.is_empty() { + Ok(Default::default()) + } else { + self.inner.retryable_update_multi_table_meta(req).await? + }; self.temp_tbl_mgr .lock() .update_multi_table_meta(update_temp_tables); @@ -444,7 +447,6 @@ impl Catalog for SessionCatalog { self.inner.drop_table_index(req).await } - // TODO: implement this async fn get_table_copied_file_info( &self, tenant: &Tenant, @@ -452,10 +454,15 @@ impl Catalog for SessionCatalog { req: GetTableCopiedFileReq, ) -> Result { let table_id = req.table_id; - let mut reply = self - .inner - .get_table_copied_file_info(tenant, db_name, req) - .await?; + let mut reply = if is_temp_table_id(table_id) { + self.temp_tbl_mgr + .lock() + .get_table_copied_file_info(req.clone())? + } else { + self.inner + .get_table_copied_file_info(tenant, db_name, req) + .await? + }; reply .file_info .extend(self.txn_mgr.lock().get_table_copied_file_info(table_id)); @@ -474,6 +481,7 @@ impl Catalog for SessionCatalog { } } + // TODO: implement this async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result> { self.inner.list_lock_revisions(req).await } diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 05230dbb295a..25d9feabf5c1 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -26,6 +26,8 @@ use databend_common_meta_app::schema::CreateTableReply; use databend_common_meta_app::schema::CreateTableReq; use databend_common_meta_app::schema::DropTableByIdReq; use databend_common_meta_app::schema::DropTableReply; +use databend_common_meta_app::schema::GetTableCopiedFileReply; +use databend_common_meta_app::schema::GetTableCopiedFileReq; use databend_common_meta_app::schema::RenameTableReply; use databend_common_meta_app::schema::RenameTableReq; use databend_common_meta_app::schema::TableCopiedFileInfo; @@ -259,6 +261,25 @@ impl TempTblMgr { table.copied_files.clear(); Ok(TruncateTableReply {}) } + + pub fn get_table_copied_file_info( + &self, + req: GetTableCopiedFileReq, + ) -> Result { + let Some(table) = self.id_to_table.get(&req.table_id) else { + return Err(ErrorCode::UnknownTable(format!( + "Temporary table id {} not found", + req.table_id + ))); + }; + let mut file_info = BTreeMap::new(); + for name in req.files { + if let Some(info) = table.copied_files.get(&name) { + file_info.insert(name, info.clone()); + } + } + Ok(GetTableCopiedFileReply { file_info }) + } } pub async fn drop_table_by_id( diff --git a/src/query/storages/fuse/src/operations/commit.rs b/src/query/storages/fuse/src/operations/commit.rs index d993269472f4..f9e7019b4baa 100644 --- a/src/query/storages/fuse/src/operations/commit.rs +++ b/src/query/storages/fuse/src/operations/commit.rs @@ -230,6 +230,7 @@ impl FuseTable { let mut update_temp_tables = vec![]; let mut update_table_metas = vec![]; + let mut copied_files_req = vec![]; if new_table_meta.options.contains_key(OPT_KEY_TEMP_PREFIX) { let req = UpdateTempTableReq { table_id, @@ -248,6 +249,7 @@ impl FuseTable { new_table_meta, }; update_table_metas.push((req, table_info.clone())); + copied_files_req = copied_files.iter().map(|c| (table_id, c.clone())).collect(); } // 3. let's roll @@ -255,7 +257,7 @@ impl FuseTable { .update_multi_table_meta(UpdateMultiTableMetaReq { update_table_metas, update_stream_metas: update_stream_meta.to_vec(), - copied_files: copied_files.iter().map(|c| (table_id, c.clone())).collect(), + copied_files: copied_files_req, deduplicated_labels: deduplicated_label.into_iter().collect(), update_temp_tables, }) diff --git a/tests/sqllogictests/data/tpch.tar.gz b/tests/sqllogictests/data/tpch.tar.gz deleted file mode 100644 index 22eabb636871d56c7f7d6c88ea15d9fac58f621c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49152 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�|4Lp5{oxg-RVMvG5GyGK>t06Z+}pRw|p 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
(WT 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 Date: Mon, 19 Aug 2024 12:43:05 +0800 Subject: [PATCH 37/51] fix copied file --- .../storages/common/session/src/transaction.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/query/storages/common/session/src/transaction.rs b/src/query/storages/common/session/src/transaction.rs index e03339bdb458..597f29eeb93b 100644 --- a/src/query/storages/common/session/src/transaction.rs +++ b/src/query/storages/common/session/src/transaction.rs @@ -28,6 +28,7 @@ use databend_common_meta_app::schema::UpdateTempTableReq; use databend_common_meta_app::schema::UpsertTableCopiedFileReq; use databend_common_meta_app::tenant::Tenant; use databend_common_meta_types::MatchSeq; +use databend_storages_common_table_meta::table_id_ranges::is_temp_table_id; use parking_lot::Mutex; use serde::Deserialize; use serde::Serialize; @@ -314,10 +315,17 @@ impl TxnManager { if !self.is_active() { return ret; } - let reqs = self.txn_buffer.copied_files.get(&table_id); - if let Some(reqs) = reqs { - for req in reqs { - ret.extend(req.file_info.clone().into_iter()); + if is_temp_table_id(table_id) { + let temp_table = self.txn_buffer.mutated_temp_tables.get(&table_id); + if let Some(temp_table) = temp_table { + ret.extend(temp_table.copied_files.clone()); + } + } else { + let reqs = self.txn_buffer.copied_files.get(&table_id); + if let Some(reqs) = reqs { + for req in reqs { + ret.extend(req.file_info.clone().into_iter()); + } } } ret From 57d8ae3fa497642d9515e0a37890bee5e66503b8 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 13:02:30 +0800 Subject: [PATCH 38/51] add log --- Cargo.lock | 1 + src/query/storages/common/session/Cargo.toml | 1 + src/query/storages/common/session/src/temp_table.rs | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 6975b9305952..cdf353786320 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5428,6 +5428,7 @@ dependencies = [ "databend-common-meta-types", "databend-common-storage", "databend-storages-common-table-meta", + "log", "parking_lot 0.12.3", "serde", "uuid", diff --git a/src/query/storages/common/session/Cargo.toml b/src/query/storages/common/session/Cargo.toml index 9f6e18a85cb6..e2685d772bc3 100644 --- a/src/query/storages/common/session/Cargo.toml +++ b/src/query/storages/common/session/Cargo.toml @@ -12,6 +12,7 @@ databend-common-meta-app = { workspace = true } databend-common-meta-types = { workspace = true } databend-common-storage = { workspace = true } databend-storages-common-table-meta = { workspace = true } +log = { workspace = true } parking_lot = { workspace = true } serde = { version = "1.0.194", features = ["derive"] } uuid = { workspace = true } diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 25d9feabf5c1..1796006f2387 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -44,6 +44,7 @@ use databend_storages_common_table_meta::meta::parse_storage_prefix; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use databend_storages_common_table_meta::table_id_ranges::is_temp_table_id; use databend_storages_common_table_meta::table_id_ranges::TEMP_TBL_ID_BEGIN; +use log::info; use parking_lot::Mutex; #[derive(Debug, Clone)] @@ -194,6 +195,10 @@ impl TempTblMgr { let desc = format!("{}.{}", database_name, table_name); let id = self.name_to_id.get(&desc); let Some(id) = id else { + info!( + "Table {}.{} not found in temp table manager {:?}", + database_name, table_name, self + ); return Ok(None); }; let Some(table) = self.id_to_table.get(id) else { From f8d7cd8e8bb10dfa822e39d315f224b836c3ce16 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 15:45:59 +0800 Subject: [PATCH 39/51] add some check --- src/query/catalog/src/catalog/interface.rs | 3 - .../src/catalogs/default/session_catalog.rs | 99 +++++++++++++++++-- 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/src/query/catalog/src/catalog/interface.rs b/src/query/catalog/src/catalog/interface.rs index de0f50ca5d57..a9518696d83c 100644 --- a/src/query/catalog/src/catalog/interface.rs +++ b/src/query/catalog/src/catalog/interface.rs @@ -221,8 +221,6 @@ pub trait Catalog: DynClone + Send + Sync + Debug { async fn get_table_meta_by_id(&self, table_id: u64) -> Result>>; /// List the tables name by meta ids. - /// - /// **Do not** pass temp table id as meta id. async fn mget_table_names_by_ids( &self, tenant: &Tenant, @@ -394,7 +392,6 @@ pub trait Catalog: DynClone + Send + Sync + Debug { req: TruncateTableReq, ) -> Result; - // TODO: implement lock related functions async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result>; async fn create_lock_revision(&self, req: CreateLockRevReq) -> Result; diff --git a/src/query/service/src/catalogs/default/session_catalog.rs b/src/query/service/src/catalogs/default/session_catalog.rs index 9b417386eedd..e20d71e9a498 100644 --- a/src/query/service/src/catalogs/default/session_catalog.rs +++ b/src/query/service/src/catalogs/default/session_catalog.rs @@ -21,6 +21,7 @@ use databend_common_catalog::database::Database; use databend_common_catalog::table::Table; use databend_common_catalog::table_args::TableArgs; use databend_common_catalog::table_function::TableFunction; +use databend_common_exception::ErrorCode; use databend_common_exception::Result; use databend_common_meta_app::schema::CatalogInfo; use databend_common_meta_app::schema::CommitTableMetaReply; @@ -169,6 +170,12 @@ impl Catalog for SessionCatalog { } async fn create_index(&self, req: CreateIndexReq) -> Result { + if is_temp_table_id(req.meta.table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "CreateIndex: table id {} is a temporary table id", + req.meta.table_id + ))); + } self.inner.create_index(req).await } @@ -185,10 +192,22 @@ impl Catalog for SessionCatalog { } async fn list_indexes(&self, req: ListIndexesReq) -> Result> { + if req.table_id.is_some_and(is_temp_table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "ListIndexes: table id {} is a temporary table id", + req.table_id.unwrap() + ))); + } self.inner.list_indexes(req).await } async fn list_index_ids_by_table_id(&self, req: ListIndexesByIdReq) -> Result> { + if is_temp_table_id(req.table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "ListIndexIdsByTableId: table id {} is a temporary table id", + req.table_id + ))); + } self.inner.list_index_ids_by_table_id(req).await } @@ -196,6 +215,12 @@ impl Catalog for SessionCatalog { &self, req: ListIndexesByIdReq, ) -> Result> { + if is_temp_table_id(req.table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "ListIndexesByTableId: table id {} is a temporary table id", + req.table_id + ))); + } self.inner.list_indexes_by_table_id(req).await } @@ -203,6 +228,12 @@ impl Catalog for SessionCatalog { &self, req: CreateVirtualColumnReq, ) -> Result { + if is_temp_table_id(req.name_ident.table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "CreateVirtualColumn: table id {} is a temporary table id", + req.name_ident.table_id() + ))); + } self.inner.create_virtual_column(req).await } @@ -210,6 +241,12 @@ impl Catalog for SessionCatalog { &self, req: UpdateVirtualColumnReq, ) -> Result { + if is_temp_table_id(req.name_ident.table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "UpdateVirtualColumn: table id {} is a temporary table id", + req.name_ident.table_id() + ))); + } self.inner.update_virtual_column(req).await } @@ -217,6 +254,12 @@ impl Catalog for SessionCatalog { &self, req: DropVirtualColumnReq, ) -> Result { + if is_temp_table_id(req.name_ident.table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "DropVirtualColumn: table id {} is a temporary table id", + req.name_ident.table_id() + ))); + } self.inner.drop_virtual_column(req).await } @@ -224,6 +267,12 @@ impl Catalog for SessionCatalog { &self, req: ListVirtualColumnsReq, ) -> Result> { + if req.table_id.is_some_and(is_temp_table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "ListVirtualColumns: table id {} is a temporary table id", + req.table_id.unwrap() + ))); + } self.inner.list_virtual_columns(req).await } @@ -256,7 +305,6 @@ impl Catalog for SessionCatalog { } } - // TODO: implement this async fn mget_table_names_by_ids( &self, tenant: &Tenant, @@ -321,12 +369,10 @@ impl Catalog for SessionCatalog { Ok(table) } - // TODO: implement this async fn list_tables(&self, tenant: &Tenant, db_name: &str) -> Result>> { self.inner.list_tables(tenant, db_name).await } - // TODO: implement this async fn list_tables_history( &self, tenant: &Tenant, @@ -335,7 +381,6 @@ impl Catalog for SessionCatalog { self.inner.list_tables_history(tenant, db_name).await } - // TODO: implement this async fn get_drop_table_infos( &self, req: ListDroppedTableReq, @@ -343,7 +388,6 @@ impl Catalog for SessionCatalog { self.inner.get_drop_table_infos(req).await } - // TODO: implement this async fn gc_drop_tables(&self, req: GcDroppedTableReq) -> Result { self.inner.gc_drop_tables(req).await } @@ -367,12 +411,10 @@ impl Catalog for SessionCatalog { self.inner.drop_table_by_id(req).await } - // TODO: implement this async fn undrop_table(&self, req: UndropTableReq) -> Result { self.inner.undrop_table(req).await } - // TODO: implement this async fn undrop_table_by_id(&self, req: UndropTableByIdReq) -> Result { self.inner.undrop_table_by_id(req).await } @@ -436,14 +478,32 @@ impl Catalog for SessionCatalog { &self, req: SetTableColumnMaskPolicyReq, ) -> Result { + if is_temp_table_id(req.table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "SetTableColumnMaskPolicy: table id {} is a temporary table id", + req.table_id + ))); + } self.inner.set_table_column_mask_policy(req).await } async fn create_table_index(&self, req: CreateTableIndexReq) -> Result { + if is_temp_table_id(req.table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "CreateTableIndex: table id {} is a temporary table id", + req.table_id + ))); + } self.inner.create_table_index(req).await } async fn drop_table_index(&self, req: DropTableIndexReq) -> Result { + if is_temp_table_id(req.table_id) { + return Err(ErrorCode::StorageUnsupported(format!( + "DropTableIndex: table id {} is a temporary table id", + req.table_id + ))); + } self.inner.drop_table_index(req).await } @@ -481,20 +541,43 @@ impl Catalog for SessionCatalog { } } - // TODO: implement this async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result> { + if is_temp_table_id(req.lock_key.get_table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "ListLockRevisions: table id {} is a temporary table id", + req.lock_key.get_table_id() + ))); + } self.inner.list_lock_revisions(req).await } async fn create_lock_revision(&self, req: CreateLockRevReq) -> Result { + if is_temp_table_id(req.lock_key.get_table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "CreateLockRevision: table id {} is a temporary table id", + req.lock_key.get_table_id() + ))); + } self.inner.create_lock_revision(req).await } async fn extend_lock_revision(&self, req: ExtendLockRevReq) -> Result<()> { + if is_temp_table_id(req.lock_key.get_table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "ExtendLockRevision: table id {} is a temporary table id", + req.lock_key.get_table_id() + ))); + } self.inner.extend_lock_revision(req).await } async fn delete_lock_revision(&self, req: DeleteLockRevReq) -> Result<()> { + if is_temp_table_id(req.lock_key.get_table_id()) { + return Err(ErrorCode::StorageUnsupported(format!( + "DeleteLockRevision: table id {} is a temporary table id", + req.lock_key.get_table_id() + ))); + } self.inner.delete_lock_revision(req).await } From dc8519184446c877a15ca3ebe0cb8adb7c930a95 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 16:17:25 +0800 Subject: [PATCH 40/51] add drop_all_temp_tables() --- src/query/storages/common/session/src/lib.rs | 2 ++ .../storages/common/session/src/temp_table.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/query/storages/common/session/src/lib.rs b/src/query/storages/common/session/src/lib.rs index 2604d21ae1d6..51c272d54356 100644 --- a/src/query/storages/common/session/src/lib.rs +++ b/src/query/storages/common/session/src/lib.rs @@ -21,4 +21,6 @@ pub use transaction::TxnManagerRef; pub use transaction::TxnState; mod session_state; pub use session_state::SessionState; +#[allow(unused_imports)] +pub use temp_table::drop_all_temp_tables; pub use temp_table::drop_table_by_id; diff --git a/src/query/storages/common/session/src/temp_table.rs b/src/query/storages/common/session/src/temp_table.rs index 1796006f2387..07cc432e2bea 100644 --- a/src/query/storages/common/session/src/temp_table.rs +++ b/src/query/storages/common/session/src/temp_table.rs @@ -318,4 +318,23 @@ pub async fn drop_table_by_id( Ok(Some(DropTableReply { spec_vec: None })) } +pub async fn drop_all_temp_tables(mgr: TempTblMgrRef) -> Result<()> { + let dirs = { + let mut guard = mgr.lock(); + let mut dirs = Vec::new(); + for (id, table) in &guard.id_to_table { + let dir = parse_storage_prefix(&table.meta.options, *id)?; + dirs.push(dir); + } + guard.id_to_table.clear(); + guard.name_to_id.clear(); + dirs + }; + let op = DataOperator::instance().operator(); + for dir in dirs { + op.remove_all(&dir).await?; + } + Ok(()) +} + pub type TempTblMgrRef = Arc>; From ac64cf704cb98878172bf200ad0172cba2fc01aa Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 20:50:07 +0800 Subject: [PATCH 41/51] refine error message --- src/query/sql/src/planner/binder/ddl/account.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/query/sql/src/planner/binder/ddl/account.rs b/src/query/sql/src/planner/binder/ddl/account.rs index 1f7d4b9be370..ebbdfb0f7fb8 100644 --- a/src/query/sql/src/planner/binder/ddl/account.rs +++ b/src/query/sql/src/planner/binder/ddl/account.rs @@ -157,8 +157,8 @@ impl Binder { .is_temp_table(&catalog_name, &database_name, table_name) { return Err(ErrorCode::StorageOther(format!( - "{} is a temporary table, cannot grant privileges on it", - table_name + "{}.{}.{} is a temporary table, cannot grant privileges on it", + catalog_name, database_name, table_name ))); } let db_id = catalog @@ -211,8 +211,8 @@ impl Binder { .is_temp_table(&catalog_name, &database_name, table_name) { return Err(ErrorCode::StorageOther(format!( - "{} is a temporary table, cannot revoke privileges on it", - table_name + "{}.{}.{} is a temporary table, cannot revoke privileges on it", + catalog_name, database_name, table_name ))); } let db_id = catalog From 15e7455c490e67a9ed73ac59561ba1a8e100ffc6 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 21:11:32 +0800 Subject: [PATCH 42/51] forbid alter temp prefix --- .../src/interpreters/interpreter_table_set_options.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/query/service/src/interpreters/interpreter_table_set_options.rs b/src/query/service/src/interpreters/interpreter_table_set_options.rs index 518d80a07aed..3210493b61fe 100644 --- a/src/query/service/src/interpreters/interpreter_table_set_options.rs +++ b/src/query/service/src/interpreters/interpreter_table_set_options.rs @@ -27,6 +27,7 @@ use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING; use databend_storages_common_table_meta::table::OPT_KEY_CHANGE_TRACKING_BEGIN_VER; use databend_storages_common_table_meta::table::OPT_KEY_DATABASE_ID; use databend_storages_common_table_meta::table::OPT_KEY_STORAGE_FORMAT; +use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; use log::error; use super::interpreter_table_create::is_valid_block_per_segment; @@ -82,6 +83,13 @@ impl Interpreter for SetOptionsInterpreter { OPT_KEY_DATABASE_ID ))); } + if self.plan.set_options.contains_key(OPT_KEY_TEMP_PREFIX) { + error!("{}", &error_str); + return Err(ErrorCode::TableOptionInvalid(format!( + "can't change {} for alter table statement", + OPT_KEY_TEMP_PREFIX + ))); + } for table_option in self.plan.set_options.iter() { let key = table_option.0.to_lowercase(); if !is_valid_create_opt(&key) { From 1a80cee6f4bc51c7c6c37700ad59d72584c9a2d4 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Mon, 19 Aug 2024 23:15:33 +0800 Subject: [PATCH 43/51] remove useless println --- src/query/service/src/interpreters/interpreter_table_create.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/query/service/src/interpreters/interpreter_table_create.rs b/src/query/service/src/interpreters/interpreter_table_create.rs index e8f0935d8227..1e18ae4edeed 100644 --- a/src/query/service/src/interpreters/interpreter_table_create.rs +++ b/src/query/service/src/interpreters/interpreter_table_create.rs @@ -194,8 +194,6 @@ impl CreateTableInterpreter { req.table_meta.drop_on = Some(Utc::now()); let table_meta = req.table_meta.clone(); let reply = catalog.create_table(req.clone()).await?; - println!("create table as select"); - println!("{:?}", self.ctx.session_state().temp_tbl_mgr); if !reply.new_table && self.plan.create_option != CreateOption::CreateOrReplace { return Ok(PipelineBuildResult::create()); } From 0b9f5e05e302a269c51576fd2c062e1086b2c6cc Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 20 Aug 2024 00:06:22 +0800 Subject: [PATCH 44/51] adjust slt --- .../suites/temp_table/alter_temp_tables.sql | 20 +------------------ .../suites/temp_table/create_temp_tables.sql | 12 ----------- .../suites/temp_table/drop_temp_tables.sql | 3 --- .../suites/temp_table/rename_temp_tables.sql | 9 --------- .../temp_table/truncate_temp_tables.sql | 6 ------ 5 files changed, 1 insertion(+), 49 deletions(-) diff --git a/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql b/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql index 11661ce81581..751646b8b6e2 100644 --- a/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/alter_temp_tables.sql @@ -4,18 +4,6 @@ USE default statement ok set sql_dialect = 'PostgreSQL' -statement ok -DROP TABLE IF EXISTS `05_0003_at_t0` - -statement ok -DROP TABLE IF EXISTS `05_0003_at_t1` - -statement ok -DROP TABLE IF EXISTS `05_0003_at_t2` - -statement ok -DROP TABLE IF EXISTS `05_0003_at_t3` - statement ok CREATE TEMP TABLE `05_0003_at_t0`(a int not null) @@ -248,10 +236,4 @@ t1 CREATE TEMP TABLE t1 ( id INT NULL ) ENGINE=FUSE COMMENT = 't1-new-comment' query TT select name, comment from system.tables where name='t1' and database='default'; ---- -t1 t1-new-comment - -statement ok -DROP TABLE IF EXISTS t; - -statement ok -DROP TABLE IF EXISTS t1; +t1 t1-new-comment \ No newline at end of file diff --git a/tests/sqllogictests/suites/temp_table/create_temp_tables.sql b/tests/sqllogictests/suites/temp_table/create_temp_tables.sql index 18f841a18cfc..41ab22cd0b5c 100644 --- a/tests/sqllogictests/suites/temp_table/create_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/create_temp_tables.sql @@ -1,15 +1,3 @@ -statement ok -DROP TABLE IF EXISTS t - -statement ok -DROP TABLE IF EXISTS t2 - -statement ok -DROP TABLE IF EXISTS t3 - -statement ok -DROP TABLE IF EXISTS t4 - statement ok CREATE TEMPORARY TABLE t(c1 int) diff --git a/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql b/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql index f0751cd8ac39..2281b8a78ebf 100644 --- a/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/drop_temp_tables.sql @@ -1,6 +1,3 @@ -statement ok -DROP TABLE IF EXISTS t - statement ok CREATE TEMPORARY TABLE t(c1 int) diff --git a/tests/sqllogictests/suites/temp_table/rename_temp_tables.sql b/tests/sqllogictests/suites/temp_table/rename_temp_tables.sql index 6f91c4f29f8c..051018db0d69 100644 --- a/tests/sqllogictests/suites/temp_table/rename_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/rename_temp_tables.sql @@ -1,9 +1,3 @@ -statement ok -DROP TABLE IF EXISTS t0 - -statement ok -DROP TABLE IF EXISTS t1 - statement ok CREATE TEMP TABLE t0(a int) @@ -93,6 +87,3 @@ SELECT * FROM t1 statement error 1006 RENAME TABLE t1 to system.t1 -statement ok -DROP TABLE IF EXISTS t1 - diff --git a/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql b/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql index 22e307ae2de1..c01941207fd7 100644 --- a/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql +++ b/tests/sqllogictests/suites/temp_table/truncate_temp_tables.sql @@ -1,6 +1,3 @@ -statement ok -DROP TABLE IF EXISTS t1 - statement ok CREATE TEMP TABLE t1(c1 int) @@ -36,6 +33,3 @@ TRUNCATE TABLE t2 statement ok SELECT * FROM t2 -statement ok -DROP TABLE IF EXISTS t2 - From 0ce30cd874393142c10a987b800f5a3906aaa45d Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 20 Aug 2024 16:37:23 +0800 Subject: [PATCH 45/51] add privilege test --- .../src/catalogs/default/session_catalog.rs | 25 +++-------- .../18_rbac/18_0012_temp_table.result | 27 ++++++++++++ .../0_stateless/18_rbac/18_0012_temp_table.sh | 41 +++++++++++++++++++ 3 files changed, 73 insertions(+), 20 deletions(-) create mode 100644 tests/suites/0_stateless/18_rbac/18_0012_temp_table.result create mode 100755 tests/suites/0_stateless/18_rbac/18_0012_temp_table.sh diff --git a/src/query/service/src/catalogs/default/session_catalog.rs b/src/query/service/src/catalogs/default/session_catalog.rs index e20d71e9a498..f5dedcbd6d36 100644 --- a/src/query/service/src/catalogs/default/session_catalog.rs +++ b/src/query/service/src/catalogs/default/session_catalog.rs @@ -193,20 +193,14 @@ impl Catalog for SessionCatalog { async fn list_indexes(&self, req: ListIndexesReq) -> Result> { if req.table_id.is_some_and(is_temp_table_id) { - return Err(ErrorCode::StorageUnsupported(format!( - "ListIndexes: table id {} is a temporary table id", - req.table_id.unwrap() - ))); + return Ok(vec![]); } self.inner.list_indexes(req).await } async fn list_index_ids_by_table_id(&self, req: ListIndexesByIdReq) -> Result> { if is_temp_table_id(req.table_id) { - return Err(ErrorCode::StorageUnsupported(format!( - "ListIndexIdsByTableId: table id {} is a temporary table id", - req.table_id - ))); + return Ok(vec![]); } self.inner.list_index_ids_by_table_id(req).await } @@ -216,10 +210,7 @@ impl Catalog for SessionCatalog { req: ListIndexesByIdReq, ) -> Result> { if is_temp_table_id(req.table_id) { - return Err(ErrorCode::StorageUnsupported(format!( - "ListIndexesByTableId: table id {} is a temporary table id", - req.table_id - ))); + return Ok(vec![]); } self.inner.list_indexes_by_table_id(req).await } @@ -268,10 +259,7 @@ impl Catalog for SessionCatalog { req: ListVirtualColumnsReq, ) -> Result> { if req.table_id.is_some_and(is_temp_table_id) { - return Err(ErrorCode::StorageUnsupported(format!( - "ListVirtualColumns: table id {} is a temporary table id", - req.table_id.unwrap() - ))); + return Ok(vec![]); } self.inner.list_virtual_columns(req).await } @@ -543,10 +531,7 @@ impl Catalog for SessionCatalog { async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result> { if is_temp_table_id(req.lock_key.get_table_id()) { - return Err(ErrorCode::StorageUnsupported(format!( - "ListLockRevisions: table id {} is a temporary table id", - req.lock_key.get_table_id() - ))); + return Ok(vec![]); } self.inner.list_lock_revisions(req).await } diff --git a/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result b/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result new file mode 100644 index 000000000000..1dca08016fa3 --- /dev/null +++ b/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result @@ -0,0 +1,27 @@ +>>>> drop user if exists 'owner' +>>>> drop role if exists role1 +>>>> create user 'owner' IDENTIFIED BY 'password' with DEFAULT_ROLE='role1' +>>>> create role role1 +>>>> create or replace database test +>>>> grant role role1 to owner +mysql: [Warning] Using a password on the command line interface can be insecure. +ERROR 1105 (HY000) at line 1: PermissionDenied. Code: 1063, Text = Permission denied: privilege [Create] is required on 'default'.'test'.* for user 'owner'@'%' with roles [role1]. Note: Please ensure that your current role have the appropriate permissions to create a new Database|Table|UDF|Stage.. +mysql: [Warning] Using a password on the command line interface can be insecure. +1 +2 +1 +2 +1 +3 +3 +3 NULL +2 +1 +mysql: [Warning] Using a password on the command line interface can be insecure. +ERROR 1105 (HY000) at line 1: UnknownTable. Code: 1025, Text = error: + --> SQL:1:15 + | +1 | select * from test.t2 + | ^^^^^^^ Unknown table "default".test.t2 . + +. diff --git a/tests/suites/0_stateless/18_rbac/18_0012_temp_table.sh b/tests/suites/0_stateless/18_rbac/18_0012_temp_table.sh new file mode 100755 index 000000000000..bad173e21f4b --- /dev/null +++ b/tests/suites/0_stateless/18_rbac/18_0012_temp_table.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +. "$CURDIR"/../../../shell_env.sh + +export TEST_USER_NAME="owner" +export TEST_USER_PASSWORD="password" +export MYSQL_CLIENT_CONNECT="mysql --ssl-mode=DISABLED -u${TEST_USER_NAME} -p${TEST_USER_PASSWORD} --host ${QUERY_MYSQL_HANDLER_HOST} --port ${QUERY_MYSQL_HANDLER_PORT} -s" + + +stmt "drop user if exists 'owner'" +stmt "drop role if exists role1" +stmt "create user 'owner' IDENTIFIED BY '$TEST_USER_PASSWORD' with DEFAULT_ROLE='role1'" +stmt 'create role role1' +stmt "create or replace database test" + +stmt 'grant role role1 to owner' + +# no privilege to create a normal table +echo "create table test.t1(a int);" | $MYSQL_CLIENT_CONNECT || true + +echo "create temp table test.t1(a int); + show grants for role role1; + insert into table test.t1 values(1),(2); + select * from test.t1; + delete from test.t1 where a=1; + select * from test.t1; + update test.t1 set a=3 where a=2; + select * from test.t1; + rename table test.t1 to test.t2; + select * from test.t2; + alter table test.t2 add column b int; + select * from test.t2; + insert into test.t2 values(3,4); + select block_count from fuse_snapshot('test','t2') limit 1; + optimize table test.t2 compact; + select block_count from fuse_snapshot('test','t2') limit 1; + " | $MYSQL_CLIENT_CONNECT + +# unknown table +echo "select * from test.t2;" | $MYSQL_CLIENT_CONNECT || true \ No newline at end of file From d3052d87b398dd4ffd2417aff16b5ad7cee340c6 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Tue, 20 Aug 2024 20:33:30 +0800 Subject: [PATCH 46/51] fix --- tests/suites/0_stateless/18_rbac/18_0012_temp_table.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result b/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result index 1dca08016fa3..f007b33dfc4b 100644 --- a/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result +++ b/tests/suites/0_stateless/18_rbac/18_0012_temp_table.result @@ -14,7 +14,7 @@ mysql: [Warning] Using a password on the command line interface can be insecure. 1 3 3 -3 NULL +3 NULL 2 1 mysql: [Warning] Using a password on the command line interface can be insecure. From d901518c8d7db1acc26ab27e885c4a7b10cdde58 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 21 Aug 2024 01:01:51 +0800 Subject: [PATCH 47/51] add assert --- src/query/catalog/src/table.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/query/catalog/src/table.rs b/src/query/catalog/src/table.rs index 913a2bf90f35..8fac6608a2b4 100644 --- a/src/query/catalog/src/table.rs +++ b/src/query/catalog/src/table.rs @@ -42,6 +42,7 @@ use databend_storages_common_table_meta::meta::SnapshotId; use databend_storages_common_table_meta::meta::TableSnapshot; use databend_storages_common_table_meta::table::ChangeType; use databend_storages_common_table_meta::table::OPT_KEY_TEMP_PREFIX; +use databend_storages_common_table_meta::table_id_ranges::is_temp_table_id; use crate::plan::DataSourceInfo; use crate::plan::DataSourcePlan; @@ -428,9 +429,13 @@ pub trait Table: Sync + Send { } fn is_temp(&self) -> bool { - self.get_table_info() + let is_temp = self + .get_table_info() .options() - .contains_key(OPT_KEY_TEMP_PREFIX) + .contains_key(OPT_KEY_TEMP_PREFIX); + let is_id_temp = is_temp_table_id(self.get_id()); + assert_eq!(is_temp, is_id_temp); + is_temp } fn use_own_sample_block(&self) -> bool { From 084118d580c3a33e8308a59a82337ae57b8279e8 Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 21 Aug 2024 09:49:24 +0800 Subject: [PATCH 48/51] change print to log --- src/query/service/src/catalogs/default/session_catalog.rs | 4 ++-- .../service/src/interpreters/interpreter_table_create.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/query/service/src/catalogs/default/session_catalog.rs b/src/query/service/src/catalogs/default/session_catalog.rs index f5dedcbd6d36..b2136e7a9532 100644 --- a/src/query/service/src/catalogs/default/session_catalog.rs +++ b/src/query/service/src/catalogs/default/session_catalog.rs @@ -275,7 +275,7 @@ impl Catalog for SessionCatalog { self.inner.get_table_by_info(table_info) } - async fn get_table_meta_by_id(&self, table_id: u64) -> Result>> { + async fn get_table_meta_by_id(&self, table_id: MetaId) -> Result>> { if let Some(t) = { let guard = self.txn_mgr.lock(); if guard.is_active() { @@ -301,7 +301,7 @@ impl Catalog for SessionCatalog { self.inner.mget_table_names_by_ids(tenant, table_ids).await } - async fn get_table_name_by_id(&self, table_id: u64) -> Result> { + async fn get_table_name_by_id(&self, table_id: MetaId) -> Result> { if let Some(name) = self.temp_tbl_mgr.lock().get_table_name_by_id(table_id) { return Ok(Some(name)); } diff --git a/src/query/service/src/interpreters/interpreter_table_create.rs b/src/query/service/src/interpreters/interpreter_table_create.rs index 449531cc3398..46b418925bac 100644 --- a/src/query/service/src/interpreters/interpreter_table_create.rs +++ b/src/query/service/src/interpreters/interpreter_table_create.rs @@ -296,7 +296,7 @@ impl CreateTableInterpreter { pipeline .main_pipeline .lift_on_finished(move |info: &ExecutionInfo| { - println!("{:?}", ctx.session_state().temp_tbl_mgr); + info!("{:?}", ctx.session_state().temp_tbl_mgr); let qualified_table_name = format!("{}.{}", db_name, table_name); if info.res.is_ok() { @@ -323,7 +323,7 @@ impl CreateTableInterpreter { info!("create {} as select failed. {:?}", qualified_table_name, e); e })?; - println!("{:?}", ctx.session_state().temp_tbl_mgr); + info!("{:?}", ctx.session_state().temp_tbl_mgr); } Ok(()) From bf121da6fa51e49a8c9a4e36288c1e9af0cc046d Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 21 Aug 2024 10:05:29 +0800 Subject: [PATCH 49/51] add temp table storage prefix --- src/query/storages/common/table_meta/src/meta/utils.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/query/storages/common/table_meta/src/meta/utils.rs b/src/query/storages/common/table_meta/src/meta/utils.rs index 512b9d200986..b853266a7d53 100644 --- a/src/query/storages/common/table_meta/src/meta/utils.rs +++ b/src/query/storages/common/table_meta/src/meta/utils.rs @@ -28,6 +28,8 @@ use crate::table::OPT_KEY_DATABASE_ID; use crate::table::OPT_KEY_STORAGE_PREFIX; use crate::table::OPT_KEY_TEMP_PREFIX; +const TEMP_TABLE_STORAGE_PREFIX: &str = "_tmp_tbl"; + pub fn trim_timestamp_to_micro_second(ts: DateTime) -> DateTime { Utc.with_ymd_and_hms( ts.year(), @@ -72,7 +74,7 @@ pub fn parse_storage_prefix(options: &BTreeMap, table_id: u64) - })?; let mut prefix = table_storage_prefix(db_id, table_id); if let Some(temp_prefix) = options.get(OPT_KEY_TEMP_PREFIX) { - prefix = format!("{}/{}", temp_prefix, prefix); + prefix = format!("{}/{}/{}", prefix, TEMP_TABLE_STORAGE_PREFIX, temp_prefix); } Ok(prefix) } From 927924fd9a61187d574e1246734a92752dd01ebb Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Wed, 21 Aug 2024 21:14:03 +0800 Subject: [PATCH 50/51] make lint --- Cargo.lock | 8 +- .../src/catalogs/default/database_catalog.rs | 116 +++++++++--------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31df729bf535..5d3225cce85b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10577,18 +10577,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/src/query/service/src/catalogs/default/database_catalog.rs b/src/query/service/src/catalogs/default/database_catalog.rs index 6f5dfa6ac859..a518fafd4487 100644 --- a/src/query/service/src/catalogs/default/database_catalog.rs +++ b/src/query/service/src/catalogs/default/database_catalog.rs @@ -129,7 +129,7 @@ pub struct DatabaseCatalog { /// the upper layer, read only immutable_catalog: Arc, /// bottom layer, writing goes here - session_catalog: Arc, + mutable_catalog: Arc, /// table function engine factories table_function_factory: Arc, } @@ -149,7 +149,7 @@ impl DatabaseCatalog { let table_function_factory = TableFunctionFactory::create(); let res = DatabaseCatalog { immutable_catalog: Arc::new(immutable_catalog), - session_catalog: Arc::new(session_catalog), + mutable_catalog: Arc::new(session_catalog), table_function_factory: Arc::new(table_function_factory), }; Ok(res) @@ -172,9 +172,9 @@ impl Catalog for DatabaseCatalog { fn disable_table_info_refresh(self: Arc) -> Result> { let mut me = self.as_ref().clone(); - let mut session_catalog = me.session_catalog.as_ref().clone(); + let mut session_catalog = me.mutable_catalog.as_ref().clone(); session_catalog.disable_table_info_refresh(); - me.session_catalog = Arc::new(session_catalog); + me.mutable_catalog = Arc::new(session_catalog); Ok(Arc::new(me)) } @@ -184,7 +184,7 @@ impl Catalog for DatabaseCatalog { match r { Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.session_catalog.get_database(tenant, db_name).await + self.mutable_catalog.get_database(tenant, db_name).await } else { Err(e) } @@ -196,7 +196,7 @@ impl Catalog for DatabaseCatalog { #[async_backtrace::framed] async fn list_databases(&self, tenant: &Tenant) -> Result>> { let mut dbs = self.immutable_catalog.list_databases(tenant).await?; - let mut other = self.session_catalog.list_databases(tenant).await?; + let mut other = self.mutable_catalog.list_databases(tenant).await?; dbs.append(&mut other); Ok(dbs) } @@ -216,7 +216,7 @@ impl Catalog for DatabaseCatalog { ))); } // create db in BOTTOM layer only - self.session_catalog.create_database(req).await + self.mutable_catalog.create_database(req).await } #[async_backtrace::framed] @@ -231,7 +231,7 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.drop_database(req).await; } - self.session_catalog.drop_database(req).await + self.mutable_catalog.drop_database(req).await } #[async_backtrace::framed] @@ -250,7 +250,7 @@ impl Catalog for DatabaseCatalog { return self.immutable_catalog.rename_database(req).await; } - self.session_catalog.rename_database(req).await + self.mutable_catalog.rename_database(req).await } fn get_table_by_info(&self, table_info: &TableInfo) -> Result> { @@ -259,7 +259,7 @@ impl Catalog for DatabaseCatalog { Ok(t) => Ok(t), Err(e) => { if e.code() == ErrorCode::UNKNOWN_TABLE { - self.session_catalog.get_table_by_info(table_info) + self.mutable_catalog.get_table_by_info(table_info) } else { Err(e) } @@ -274,7 +274,7 @@ impl Catalog for DatabaseCatalog { if let Ok(x) = res { Ok(x) } else { - self.session_catalog.get_table_meta_by_id(table_id).await + self.mutable_catalog.get_table_meta_by_id(table_id).await } } @@ -314,7 +314,7 @@ impl Catalog for DatabaseCatalog { // Fetching table names for remaining system table IDs let other = self - .session_catalog + .mutable_catalog .mget_table_names_by_ids(tenant, &mut_table_ids) .await?; @@ -330,7 +330,7 @@ impl Catalog for DatabaseCatalog { match res { Ok(Some(x)) => Ok(Some(x)), - Ok(None) | Err(_) => self.session_catalog.get_table_name_by_id(table_id).await, + Ok(None) | Err(_) => self.mutable_catalog.get_table_name_by_id(table_id).await, } } @@ -341,7 +341,7 @@ impl Catalog for DatabaseCatalog { if let Ok(x) = res { Ok(x) } else { - self.session_catalog.get_db_name_by_id(db_id).await + self.mutable_catalog.get_db_name_by_id(db_id).await } } @@ -371,7 +371,7 @@ impl Catalog for DatabaseCatalog { .await?; let other = self - .session_catalog + .mutable_catalog .mget_database_names_by_ids(tenant, &mut_db_ids) .await?; @@ -395,7 +395,7 @@ impl Catalog for DatabaseCatalog { Ok(v) => Ok(v), Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.session_catalog + self.mutable_catalog .get_table(tenant, db_name, table_name) .await } else { @@ -412,7 +412,7 @@ impl Catalog for DatabaseCatalog { Ok(x) => Ok(x), Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.session_catalog.list_tables(tenant, db_name).await + self.mutable_catalog.list_tables(tenant, db_name).await } else { Err(e) } @@ -434,7 +434,7 @@ impl Catalog for DatabaseCatalog { Ok(x) => Ok(x), Err(e) => { if e.code() == ErrorCode::UNKNOWN_DATABASE { - self.session_catalog + self.mutable_catalog .list_tables_history(tenant, db_name) .await } else { @@ -455,12 +455,12 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.create_table(req).await; } - self.session_catalog.create_table(req).await + self.mutable_catalog.create_table(req).await } #[async_backtrace::framed] async fn drop_table_by_id(&self, req: DropTableByIdReq) -> Result { - let res = self.session_catalog.drop_table_by_id(req).await?; + let res = self.mutable_catalog.drop_table_by_id(req).await?; Ok(res) } @@ -475,7 +475,7 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.undrop_table(req).await; } - self.session_catalog.undrop_table(req).await + self.mutable_catalog.undrop_table(req).await } #[async_backtrace::framed] @@ -489,7 +489,7 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.undrop_table_by_id(req).await; } - self.session_catalog.undrop_table_by_id(req).await + self.mutable_catalog.undrop_table_by_id(req).await } #[async_backtrace::framed] @@ -503,13 +503,13 @@ impl Catalog for DatabaseCatalog { { return self.immutable_catalog.undrop_database(req).await; } - self.session_catalog.undrop_database(req).await + self.mutable_catalog.undrop_database(req).await } async fn commit_table_meta(&self, req: CommitTableMetaReq) -> Result { info!("commit_table_meta from req:{:?}", req); - self.session_catalog.commit_table_meta(req).await + self.mutable_catalog.commit_table_meta(req).await } #[async_backtrace::framed] @@ -530,17 +530,17 @@ impl Catalog for DatabaseCatalog { )); } - self.session_catalog.rename_table(req).await + self.mutable_catalog.rename_table(req).await } #[async_backtrace::framed] async fn create_table_index(&self, req: CreateTableIndexReq) -> Result { - self.session_catalog.create_table_index(req).await + self.mutable_catalog.create_table_index(req).await } #[async_backtrace::framed] async fn drop_table_index(&self, req: DropTableIndexReq) -> Result { - self.session_catalog.drop_table_index(req).await + self.mutable_catalog.drop_table_index(req).await } #[async_backtrace::framed] @@ -550,7 +550,7 @@ impl Catalog for DatabaseCatalog { db_name: &str, req: GetTableCopiedFileReq, ) -> Result { - self.session_catalog + self.mutable_catalog .get_table_copied_file_info(tenant, db_name, req) .await } @@ -561,7 +561,7 @@ impl Catalog for DatabaseCatalog { table_info: &TableInfo, req: TruncateTableReq, ) -> Result { - self.session_catalog.truncate_table(table_info, req).await + self.mutable_catalog.truncate_table(table_info, req).await } #[async_backtrace::framed] @@ -571,7 +571,7 @@ impl Catalog for DatabaseCatalog { db_name: &str, req: UpsertTableOptionReq, ) -> Result { - self.session_catalog + self.mutable_catalog .upsert_table_option(tenant, db_name, req) .await } @@ -581,7 +581,7 @@ impl Catalog for DatabaseCatalog { &self, reqs: UpdateMultiTableMetaReq, ) -> Result { - self.session_catalog + self.mutable_catalog .retryable_update_multi_table_meta(reqs) .await } @@ -591,39 +591,39 @@ impl Catalog for DatabaseCatalog { &self, req: SetTableColumnMaskPolicyReq, ) -> Result { - self.session_catalog.set_table_column_mask_policy(req).await + self.mutable_catalog.set_table_column_mask_policy(req).await } // Table index #[async_backtrace::framed] async fn create_index(&self, req: CreateIndexReq) -> Result { - self.session_catalog.create_index(req).await + self.mutable_catalog.create_index(req).await } #[async_backtrace::framed] async fn drop_index(&self, req: DropIndexReq) -> Result { - self.session_catalog.drop_index(req).await + self.mutable_catalog.drop_index(req).await } #[async_backtrace::framed] async fn get_index(&self, req: GetIndexReq) -> Result { - self.session_catalog.get_index(req).await + self.mutable_catalog.get_index(req).await } #[async_backtrace::framed] async fn update_index(&self, req: UpdateIndexReq) -> Result { - self.session_catalog.update_index(req).await + self.mutable_catalog.update_index(req).await } #[async_backtrace::framed] async fn list_indexes(&self, req: ListIndexesReq) -> Result> { - self.session_catalog.list_indexes(req).await + self.mutable_catalog.list_indexes(req).await } #[async_backtrace::framed] async fn list_index_ids_by_table_id(&self, req: ListIndexesByIdReq) -> Result> { - self.session_catalog.list_index_ids_by_table_id(req).await + self.mutable_catalog.list_index_ids_by_table_id(req).await } #[async_backtrace::framed] @@ -631,7 +631,7 @@ impl Catalog for DatabaseCatalog { &self, req: ListIndexesByIdReq, ) -> Result> { - self.session_catalog.list_indexes_by_table_id(req).await + self.mutable_catalog.list_indexes_by_table_id(req).await } // Virtual column @@ -641,7 +641,7 @@ impl Catalog for DatabaseCatalog { &self, req: CreateVirtualColumnReq, ) -> Result { - self.session_catalog.create_virtual_column(req).await + self.mutable_catalog.create_virtual_column(req).await } #[async_backtrace::framed] @@ -649,7 +649,7 @@ impl Catalog for DatabaseCatalog { &self, req: UpdateVirtualColumnReq, ) -> Result { - self.session_catalog.update_virtual_column(req).await + self.mutable_catalog.update_virtual_column(req).await } #[async_backtrace::framed] @@ -657,7 +657,7 @@ impl Catalog for DatabaseCatalog { &self, req: DropVirtualColumnReq, ) -> Result { - self.session_catalog.drop_virtual_column(req).await + self.mutable_catalog.drop_virtual_column(req).await } #[async_backtrace::framed] @@ -665,7 +665,7 @@ impl Catalog for DatabaseCatalog { &self, req: ListVirtualColumnsReq, ) -> Result> { - self.session_catalog.list_virtual_columns(req).await + self.mutable_catalog.list_virtual_columns(req).await } fn get_table_function( @@ -686,77 +686,77 @@ impl Catalog for DatabaseCatalog { fn get_table_engines(&self) -> Vec { // only return mutable_catalog storage table engines - self.session_catalog.get_table_engines() + self.mutable_catalog.get_table_engines() } #[async_backtrace::framed] async fn list_lock_revisions(&self, req: ListLockRevReq) -> Result> { - self.session_catalog.list_lock_revisions(req).await + self.mutable_catalog.list_lock_revisions(req).await } #[async_backtrace::framed] async fn create_lock_revision(&self, req: CreateLockRevReq) -> Result { - self.session_catalog.create_lock_revision(req).await + self.mutable_catalog.create_lock_revision(req).await } #[async_backtrace::framed] async fn extend_lock_revision(&self, req: ExtendLockRevReq) -> Result<()> { - self.session_catalog.extend_lock_revision(req).await + self.mutable_catalog.extend_lock_revision(req).await } #[async_backtrace::framed] async fn delete_lock_revision(&self, req: DeleteLockRevReq) -> Result<()> { - self.session_catalog.delete_lock_revision(req).await + self.mutable_catalog.delete_lock_revision(req).await } #[async_backtrace::framed] async fn list_locks(&self, req: ListLocksReq) -> Result> { - self.session_catalog.list_locks(req).await + self.mutable_catalog.list_locks(req).await } async fn get_drop_table_infos( &self, req: ListDroppedTableReq, ) -> Result<(Vec>, Vec)> { - self.session_catalog.get_drop_table_infos(req).await + self.mutable_catalog.get_drop_table_infos(req).await } async fn gc_drop_tables(&self, req: GcDroppedTableReq) -> Result { - self.session_catalog.gc_drop_tables(req).await + self.mutable_catalog.gc_drop_tables(req).await } async fn create_sequence(&self, req: CreateSequenceReq) -> Result { - self.session_catalog.create_sequence(req).await + self.mutable_catalog.create_sequence(req).await } async fn get_sequence(&self, req: GetSequenceReq) -> Result { - self.session_catalog.get_sequence(req).await + self.mutable_catalog.get_sequence(req).await } async fn get_sequence_next_value( &self, req: GetSequenceNextValueReq, ) -> Result { - self.session_catalog.get_sequence_next_value(req).await + self.mutable_catalog.get_sequence_next_value(req).await } async fn drop_sequence(&self, req: DropSequenceReq) -> Result { - self.session_catalog.drop_sequence(req).await + self.mutable_catalog.drop_sequence(req).await } fn set_session_state(&self, state: SessionState) -> Arc { Arc::new(DatabaseCatalog { - session_catalog: Arc::new(SessionCatalog::create(self.session_catalog.inner(), state)), + mutable_catalog: Arc::new(SessionCatalog::create(self.mutable_catalog.inner(), state)), immutable_catalog: self.immutable_catalog.clone(), table_function_factory: self.table_function_factory.clone(), }) } fn get_stream_source_table(&self, _stream_desc: &str) -> Result>> { - self.session_catalog.get_stream_source_table(_stream_desc) + self.mutable_catalog.get_stream_source_table(_stream_desc) } fn cache_stream_source_table(&self, _stream: TableInfo, _source: TableInfo) { - self.session_catalog + self.mutable_catalog .cache_stream_source_table(_stream, _source) } From b12e0ab944f57eb791b57fd3963d73de8573ffac Mon Sep 17 00:00:00 2001 From: sky <3374614481@qq.com> Date: Thu, 22 Aug 2024 13:49:38 +0800 Subject: [PATCH 51/51] fix prefix --- src/query/storages/common/table_meta/src/meta/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/storages/common/table_meta/src/meta/utils.rs b/src/query/storages/common/table_meta/src/meta/utils.rs index b853266a7d53..99c274675878 100644 --- a/src/query/storages/common/table_meta/src/meta/utils.rs +++ b/src/query/storages/common/table_meta/src/meta/utils.rs @@ -74,7 +74,7 @@ pub fn parse_storage_prefix(options: &BTreeMap, table_id: u64) - })?; let mut prefix = table_storage_prefix(db_id, table_id); if let Some(temp_prefix) = options.get(OPT_KEY_TEMP_PREFIX) { - prefix = format!("{}/{}/{}", prefix, TEMP_TABLE_STORAGE_PREFIX, temp_prefix); + prefix = format!("{}/{}/{}", TEMP_TABLE_STORAGE_PREFIX, temp_prefix, prefix); } Ok(prefix) }