Skip to content

Commit d99799e

Browse files
authored
refactor: columns support display other catalog column info (#17960)
1 parent 171269a commit d99799e

File tree

6 files changed

+147
-89
lines changed

6 files changed

+147
-89
lines changed

src/query/service/src/databases/system/system_database.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl SystemDatabase {
125125
MallocStatsTable::create(sys_db_meta.next_table_id()),
126126
#[cfg(feature = "jemalloc")]
127127
MallocStatsTotalsTable::create(sys_db_meta.next_table_id()),
128-
ColumnsTable::create(sys_db_meta.next_table_id()),
128+
ColumnsTable::create(sys_db_meta.next_table_id(), ctl_name),
129129
UsersTable::create(sys_db_meta.next_table_id()),
130130
EnginesTable::create(sys_db_meta.next_table_id()),
131131
RolesTable::create(sys_db_meta.next_table_id()),

src/query/service/tests/it/storages/system.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ async fn test_columns_table() -> Result<()> {
130130

131131
let mut mint = Mint::new("tests/it/storages/testdata");
132132
let file = &mut mint.new_goldenfile("columns_table.txt").unwrap();
133-
let table = ColumnsTable::create(1);
133+
let table = ColumnsTable::create(1, "default");
134134
run_table_tests(file, ctx, table).await?;
135135

136136
Ok(())

src/query/sql/src/planner/binder/ddl/column.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ impl Binder {
6767
table
6868
};
6969

70-
let default_catalog = self.ctx.get_default_catalog()?.name();
70+
let current_catalog = catalog.name();
7171
let mut select_builder =
72-
SelectBuilder::from(&format!("{}.information_schema.columns", default_catalog));
72+
SelectBuilder::from(&format!("{}.information_schema.columns", current_catalog));
7373

7474
select_builder
7575
.with_column("column_name AS `Field`")

src/query/storages/system/src/columns_table.rs

Lines changed: 137 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414

1515
use std::sync::Arc;
1616

17+
use databend_common_catalog::catalog::Catalog;
18+
use databend_common_catalog::catalog::CatalogManager;
1719
use databend_common_catalog::catalog_kind::CATALOG_DEFAULT;
20+
use databend_common_catalog::database::Database;
1821
use databend_common_catalog::plan::PushDownInfo;
1922
use databend_common_catalog::table::Table;
2023
use databend_common_catalog::table_context::TableContext;
@@ -29,16 +32,20 @@ use databend_common_expression::TableField;
2932
use databend_common_expression::TableSchemaRefExt;
3033
use databend_common_functions::BUILTIN_FUNCTIONS;
3134
use databend_common_meta_app::schema::database_name_ident::DatabaseNameIdent;
35+
use databend_common_meta_app::schema::CatalogInfo;
36+
use databend_common_meta_app::schema::CatalogNameIdent;
3237
use databend_common_meta_app::schema::TableIdent;
3338
use databend_common_meta_app::schema::TableInfo;
3439
use databend_common_meta_app::schema::TableMeta;
40+
use databend_common_meta_app::tenant::Tenant;
3541
use databend_common_sql::Planner;
3642
use databend_common_storages_stream::stream_table::StreamTable;
3743
use databend_common_storages_stream::stream_table::STREAM_ENGINE;
3844
use databend_common_storages_view::view_table::QUERY;
3945
use databend_common_storages_view::view_table::VIEW_ENGINE;
4046
use log::warn;
4147

48+
use crate::generate_catalog_meta;
4249
use crate::table::AsyncOneBlockSystemTable;
4350
use crate::table::AsyncSystemTable;
4451
use crate::util::find_eq_filter;
@@ -61,7 +68,15 @@ impl AsyncSystemTable for ColumnsTable {
6168
ctx: Arc<dyn TableContext>,
6269
push_downs: Option<PushDownInfo>,
6370
) -> Result<DataBlock> {
64-
let rows = self.dump_table_columns(ctx, push_downs).await?;
71+
let catalog_mgr = CatalogManager::instance();
72+
let catalog = catalog_mgr
73+
.get_catalog(
74+
ctx.get_tenant().tenant_name(),
75+
self.get_table_info().catalog(),
76+
ctx.session_state(),
77+
)
78+
.await?;
79+
let rows = self.dump_table_columns(ctx, push_downs, &catalog).await?;
6580
let mut names: Vec<String> = Vec::with_capacity(rows.len());
6681
let mut tables: Vec<String> = Vec::with_capacity(rows.len());
6782
let mut databases: Vec<String> = Vec::with_capacity(rows.len());
@@ -111,7 +126,7 @@ impl AsyncSystemTable for ColumnsTable {
111126
}
112127

113128
impl ColumnsTable {
114-
pub fn create(table_id: u64) -> Arc<dyn Table> {
129+
pub fn create(table_id: u64, ctl_name: &str) -> Arc<dyn Table> {
115130
let schema = TableSchemaRefExt::create(vec![
116131
TableField::new("name", TableDataType::String),
117132
TableField::new("database", TableDataType::String),
@@ -135,6 +150,11 @@ impl ColumnsTable {
135150
engine: "SystemColumns".to_string(),
136151
..Default::default()
137152
},
153+
catalog_info: Arc::new(CatalogInfo {
154+
name_ident: CatalogNameIdent::new(Tenant::new_literal("dummy"), ctl_name).into(),
155+
meta: generate_catalog_meta(ctl_name),
156+
..Default::default()
157+
}),
138158
..Default::default()
139159
};
140160

@@ -146,8 +166,9 @@ impl ColumnsTable {
146166
&self,
147167
ctx: Arc<dyn TableContext>,
148168
push_downs: Option<PushDownInfo>,
169+
catalog: &Arc<dyn Catalog>,
149170
) -> Result<Vec<(String, String, String, TableField)>> {
150-
let database_and_tables = dump_tables(&ctx, push_downs).await?;
171+
let database_and_tables = dump_tables(&ctx, push_downs, catalog).await?;
151172

152173
let mut rows: Vec<(String, String, String, TableField)> = vec![];
153174
for (database, tables) in database_and_tables {
@@ -237,24 +258,24 @@ impl ColumnsTable {
237258
pub(crate) async fn dump_tables(
238259
ctx: &Arc<dyn TableContext>,
239260
push_downs: Option<PushDownInfo>,
261+
catalog: &Arc<dyn Catalog>,
240262
) -> Result<Vec<(String, Vec<Arc<dyn Table>>)>> {
241263
let tenant = ctx.get_tenant();
242264

243265
// For performance considerations, we do not require the most up-to-date table information here:
244266
// - for regular tables, the data is certainly fresh
245267
// - for read-only attached tables, the data may be outdated
268+
let catalog = catalog.clone().disable_table_info_refresh()?;
246269

247-
let catalog = ctx
248-
.get_catalog(CATALOG_DEFAULT)
249-
.await?
250-
.disable_table_info_refresh()?;
251-
252-
let mut tables: Vec<String> = Vec::new();
253-
let mut databases: Vec<String> = Vec::new();
270+
let mut filtered_db_names: Option<Vec<String>> = None;
271+
let mut filtered_table_names: Option<Vec<String>> = None;
254272

255273
if let Some(push_downs) = push_downs {
256274
if let Some(filter) = push_downs.filters.as_ref().map(|f| &f.filter) {
257275
let expr = filter.as_expr(&BUILTIN_FUNCTIONS);
276+
let mut databases: Vec<String> = Vec::new();
277+
let mut tables: Vec<String> = Vec::new();
278+
258279
find_eq_filter(&expr, &mut |col_name, scalar| {
259280
if col_name == "database" {
260281
if let Scalar::String(database) = scalar {
@@ -271,102 +292,134 @@ pub(crate) async fn dump_tables(
271292
}
272293
Ok(())
273294
});
295+
if !databases.is_empty() {
296+
filtered_db_names = Some(databases);
297+
}
298+
if !tables.is_empty() {
299+
filtered_table_names = Some(tables);
300+
}
274301
}
275302
}
276303

277-
let visibility_checker = ctx.get_visibility_checker(false).await?;
304+
let visibility_checker = if catalog.is_external() {
305+
None
306+
} else {
307+
Some(ctx.get_visibility_checker(false).await?)
308+
};
278309

279-
let mut final_dbs: Vec<(String, u64)> = Vec::new();
310+
let mut final_dbs: Vec<Arc<dyn Database>> = Vec::new();
280311

281-
if !databases.is_empty() {
282-
for db in databases {
283-
let db_id = catalog
284-
.get_database(&tenant, &db)
285-
.await?
286-
.get_db_info()
287-
.database_id
288-
.db_id;
289-
if visibility_checker.check_database_visibility(CATALOG_DEFAULT, &db, db_id) {
290-
final_dbs.push((db.to_string(), db_id));
312+
match (filtered_db_names, &visibility_checker) {
313+
(Some(db_names), Some(checker)) => {
314+
// Filtered databases + Visibility check
315+
for db_name in db_names {
316+
let db = catalog.get_database(&tenant, &db_name).await?;
317+
let db_id = db.get_db_info().database_id.db_id;
318+
if checker.check_database_visibility(CATALOG_DEFAULT, &db_name, db_id) {
319+
final_dbs.push(db);
320+
}
291321
}
292322
}
293-
} else {
294-
let catalog_dbs = visibility_checker.get_visibility_database();
295-
// None means has global level privileges
296-
if let Some(catalog_dbs) = catalog_dbs {
297-
for (catalog_name, dbs) in catalog_dbs {
298-
if catalog_name == CATALOG_DEFAULT {
299-
let mut catalog_db_ids = vec![];
300-
let mut catalog_db_names = vec![];
301-
catalog_db_names.extend(
302-
dbs.iter()
303-
.filter_map(|(db_name, _)| *db_name)
304-
.map(|db_name| db_name.to_string()),
305-
);
306-
catalog_db_ids.extend(dbs.iter().filter_map(|(_, db_id)| *db_id));
307-
if let Ok(databases) = catalog
308-
.mget_database_names_by_ids(&tenant, &catalog_db_ids)
309-
.await
310-
{
311-
catalog_db_names.extend(databases.into_iter().flatten());
312-
} else {
313-
let msg = format!("Failed to get database name by id: {}", catalog.name());
314-
warn!("{}", msg);
315-
}
316-
let db_idents = catalog_db_names
323+
(Some(db_names), None) => {
324+
// Filtered databases + No visibility check
325+
for db_name in db_names {
326+
let db = catalog.get_database(&tenant, &db_name).await?;
327+
final_dbs.push(db);
328+
}
329+
}
330+
(None, Some(checker)) => {
331+
// All databases + Visibility check
332+
let catalog_dbs = checker.get_visibility_database();
333+
if let Some(catalog_dbs) = catalog_dbs {
334+
if let Some(dbs_in_default_catalog) =
335+
catalog_dbs.get(&ctx.get_default_catalog()?.name())
336+
{
337+
let db_idents = dbs_in_default_catalog
317338
.iter()
318-
.map(|name| DatabaseNameIdent::new(&tenant, name))
339+
.filter_map(|(db_name, _)| *db_name) // Get only names provided by checker
340+
.map(|db_name| DatabaseNameIdent::new(&tenant, db_name))
319341
.collect::<Vec<DatabaseNameIdent>>();
320-
let dbs: Vec<(String, u64)> = catalog
321-
.mget_databases(&tenant, &db_idents)
322-
.await?
323-
.iter()
324-
.map(|db| (db.name().to_string(), db.get_db_info().database_id.db_id))
325-
.collect();
326-
final_dbs.extend(dbs);
342+
343+
let databases = catalog.mget_databases(&tenant, &db_idents).await?;
344+
// mget_databases returns Vec<Arc<dyn Database>>, checker already filtered by ID/Name
345+
for db in databases {
346+
// Double check visibility in case mget_databases returned something unexpected,
347+
// although checker should be the source of truth here.
348+
let db_id = db.get_db_info().database_id.db_id;
349+
if checker.check_database_visibility(CATALOG_DEFAULT, db.name(), db_id) {
350+
final_dbs.push(db);
351+
} else {
352+
// This case should ideally not happen if checker is correct, but good for safety
353+
warn!("Visibility checker returned database {} but check_database_visibility failed.", db.name());
354+
}
355+
}
327356
}
328-
}
329-
} else {
330-
let all_databases = catalog.list_databases(&tenant).await?;
331-
for db in all_databases {
332-
let db_id = db.get_db_info().database_id.db_id;
333-
let db_name = db.name();
334-
if visibility_checker.check_database_visibility(CATALOG_DEFAULT, db_name, db_id) {
335-
final_dbs.push((db_name.to_string(), db_id));
357+
} else {
358+
// User has global privileges, check all
359+
let all_databases = catalog.list_databases(&tenant).await?;
360+
for db in all_databases {
361+
let db_id = db.get_db_info().database_id.db_id;
362+
let db_name = db.name();
363+
if checker.check_database_visibility(CATALOG_DEFAULT, db_name, db_id) {
364+
final_dbs.push(db);
365+
}
336366
}
337367
}
338368
}
369+
(None, None) => {
370+
// All databases + No visibility check
371+
final_dbs = catalog.list_databases(&tenant).await?;
372+
}
339373
}
340374

341375
let mut final_tables: Vec<(String, Vec<Arc<dyn Table>>)> = Vec::with_capacity(final_dbs.len());
342-
for (database, db_id) in final_dbs {
343-
let tables = if tables.is_empty() {
344-
catalog
345-
.list_tables(&tenant, &database)
346-
.await
347-
.unwrap_or_default()
348-
} else {
349-
let mut res = Vec::new();
350-
for table in &tables {
351-
if let Ok(table) = catalog.get_table(&tenant, &database, table).await {
352-
res.push(table);
376+
377+
for db in final_dbs {
378+
let db_name = db.name().to_string();
379+
let db_id = db.get_db_info().database_id.db_id;
380+
381+
let tables_in_db = match &filtered_table_names {
382+
Some(table_names) => {
383+
// Filtered tables
384+
let mut res = Vec::new();
385+
for table_name in table_names {
386+
// Use get_table for specific names
387+
if let Ok(table) = catalog.get_table(&tenant, &db_name, table_name).await {
388+
res.push(table);
389+
}
353390
}
391+
res
392+
}
393+
None => {
394+
// All tables in database
395+
// Use list_tables for all tables, handle error by returning empty vec
396+
catalog
397+
.list_tables(&tenant, &db_name)
398+
.await
399+
.unwrap_or_default()
354400
}
355-
res
356401
};
357-
let mut filtered_tables = Vec::with_capacity(tables.len());
358-
for table in tables {
359-
if visibility_checker.check_table_visibility(
360-
CATALOG_DEFAULT,
361-
&database,
362-
table.name(),
363-
db_id,
364-
table.get_id(),
365-
) {
402+
403+
let mut filtered_tables = Vec::with_capacity(tables_in_db.len());
404+
for table in tables_in_db {
405+
// Apply table visibility check if checker exists
406+
let is_visible = match &visibility_checker {
407+
Some(checker) => checker.check_table_visibility(
408+
CATALOG_DEFAULT,
409+
&db_name,
410+
table.name(),
411+
db_id,
412+
table.get_id(),
413+
),
414+
None => true, // No checker, all tables are visible
415+
};
416+
417+
if is_visible {
366418
filtered_tables.push(table);
367419
}
368420
}
369-
final_tables.push((database, filtered_tables));
421+
final_tables.push((db_name, filtered_tables));
370422
}
423+
371424
Ok(final_tables)
372425
}

src/query/storages/system/src/tables_table.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ where TablesTable<WITH_HISTORY, WITHOUT_VIEW>: HistoryAware
175175
if let Some((catalog_name, db_name)) =
176176
self.is_external_show_tables_query(&push_downs, &catalog)
177177
{
178-
println!("call show_tables_from_external_catalog");
179178
self.show_tables_from_external_catalog(ctx, catalog_name, db_name)
180179
.await
181180
} else {

tests/sqllogictests/suites/tpch_iceberg/utils.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ show tables from abc;
135135
t
136136
t1
137137

138+
query T
139+
show columns from abc.t1;
140+
----
141+
c1 DATE YES (empty) NULL NULL
142+
c2 VARCHAR YES (empty) NULL NULL
143+
138144
statement error 1302
139145
CREATE TABLE IF NOT EXISTS abc.t2(c1 int) ENGINE = fuse
140146

0 commit comments

Comments
 (0)