From ddeea32ffe4ca0362c9781fa0fe99cdfc8e94e10 Mon Sep 17 00:00:00 2001 From: xxchan Date: Tue, 17 Oct 2023 17:45:40 +0800 Subject: [PATCH] fix: fix tab completion for relation (#12908) --- .../batch/subquery/tab_completion.slt.part | 25 +++++++++++++ .../plan_visitor/cardinality_visitor.rs | 36 +++++++++++++------ 2 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 e2e_test/batch/subquery/tab_completion.slt.part diff --git a/e2e_test/batch/subquery/tab_completion.slt.part b/e2e_test/batch/subquery/tab_completion.slt.part new file mode 100644 index 0000000000000..60d87d6ff5e69 --- /dev/null +++ b/e2e_test/batch/subquery/tab_completion.slt.part @@ -0,0 +1,25 @@ +# queries from psql tab completion + +statement ok +create table ttttt(x int); + +statement ok +create table tttt(x int); + +# select * from tt +query I rowsort +SELECT pg_catalog.quote_ident(c.relname) FROM pg_catalog.pg_class c WHERE c.relkind IN ('r', 'S', 'v', 'm', 'f', 'p') AND substring(pg_catalog.quote_ident(c.relname),1,2)='tt' AND pg_catalog.pg_table_is_visible(c.oid) AND c.relnamespace <> (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = 'pg_catalog') +UNION +SELECT pg_catalog.quote_ident(n.nspname) || '.' FROM pg_catalog.pg_namespace n WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,2)='tt' AND (SELECT pg_catalog.count(*) FROM pg_catalog.pg_namespace WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,2) = substring('tt',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1 +UNION +SELECT pg_catalog.quote_ident(n.nspname) || '.' || pg_catalog.quote_ident(c.relname) FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n WHERE c.relnamespace = n.oid AND c.relkind IN ('r', 'S', 'v', 'm', 'f', 'p') AND substring(pg_catalog.quote_ident(n.nspname) || '.' || pg_catalog.quote_ident(c.relname),1,2)='tt' AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,2) = substring('tt',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1) AND (SELECT pg_catalog.count(*) FROM pg_catalog.pg_namespace WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,2) = substring('tt',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1 +LIMIT 1000 +---- +tttt +ttttt + +statement ok +drop table tttt; + +statement ok +drop table ttttt; diff --git a/src/frontend/src/optimizer/plan_visitor/cardinality_visitor.rs b/src/frontend/src/optimizer/plan_visitor/cardinality_visitor.rs index 71b7b17d9ab4e..3b071ddaf3dfe 100644 --- a/src/frontend/src/optimizer/plan_visitor/cardinality_visitor.rs +++ b/src/frontend/src/optimizer/plan_visitor/cardinality_visitor.rs @@ -18,7 +18,6 @@ use std::ops::{Mul, Sub}; use risingwave_pb::plan_common::JoinType; use super::{DefaultBehavior, DefaultValue, PlanVisitor}; -use crate::catalog::system_catalog::pg_catalog::PG_NAMESPACE_TABLE_NAME; use crate::optimizer::plan_node::generic::TopNLimit; use crate::optimizer::plan_node::{ self, PlanNode, PlanTreeNode, PlanTreeNodeBinary, PlanTreeNodeUnary, @@ -44,18 +43,35 @@ impl CardinalityVisitor { // We don't have UNIQUE key now. So we hack here to support some complex queries on // system tables. // TODO(card): remove this after we have UNIQUE key. https://github.com/risingwavelabs/risingwave/issues/12514 - if let Some(scan) = input.as_logical_scan() - && scan.is_sys_table() - && scan.table_name() == PG_NAMESPACE_TABLE_NAME { - if let Some(nspname) = scan - .output_col_idx() - .iter() - .find(|i| scan.table_desc().columns[**i].name == "nspname") { - unique_keys.push([*nspname].into_iter().collect()); + // Hack for unique key `nspname` on `pg_catalog.pg_namespace` + // + // LogicalFilter { predicate: (rw_schemas.name = ...) } + // (below is expanded logical view, see src/frontend/src/catalog/system_catalog/pg_catalog/pg_namespace.rs) + // └─LogicalProject { exprs: [rw_schemas.id, rw_schemas.name, rw_schemas.owner, rw_schemas.acl] } + // └─LogicalScan { table: rw_schemas, columns: [id, name, owner, acl] } + fn try_get_unique_key_from_pg_namespace(plan: &dyn PlanNode) -> Option> { + let proj = plan.as_logical_project()?; + if !proj.is_identity() { + return None; + } + let scan = proj.input(); + let scan = scan.as_logical_scan()?; + if scan.is_sys_table() && scan.table_name() == "rw_schemas" { + if let Some(name) = scan + .output_col_idx() + .iter() + .find(|i| scan.table_desc().columns[**i].name == "name") + { + return Some([*name].into_iter().collect()); + } + } + None + } + if let Some(unique_key) = try_get_unique_key_from_pg_namespace(input) { + unique_keys.push(unique_key); } } - if unique_keys .iter() .any(|unique_key| eq_set.is_superset(unique_key))