From b724be78a46b15d397ac509d79aabf6365d687cf Mon Sep 17 00:00:00 2001 From: jinser Date: Thu, 26 Oct 2023 00:26:15 +0800 Subject: [PATCH] feat: add `comment on` clause support (#12849) Co-authored-by: Richard Chien Co-authored-by: August --- .../batch/catalog/pg_description.slt.part | 81 +++++++++++++---- e2e_test/ddl/show.slt | 56 ++++++++---- e2e_test/extended_mode/basic.slt | 15 ++-- proto/catalog.proto | 11 +++ proto/ddl_service.proto | 10 +++ proto/plan_common.proto | 3 + src/common/src/catalog/column.rs | 8 ++ src/common/src/catalog/mod.rs | 2 + src/common/src/catalog/test_utils.rs | 1 + src/compute/tests/integration_tests.rs | 1 + src/connector/src/parser/avro/util.rs | 1 + src/connector/src/parser/protobuf/parser.rs | 1 + src/connector/src/source/manager.rs | 1 + src/frontend/src/binder/expr/mod.rs | 2 + src/frontend/src/catalog/catalog_service.rs | 10 ++- .../src/catalog/system_catalog/mod.rs | 5 ++ .../pg_catalog/pg_description.rs | 39 +++++---- .../catalog/system_catalog/rw_catalog/mod.rs | 2 + .../rw_catalog/rw_description.rs | 84 ++++++++++++++++++ src/frontend/src/catalog/table_catalog.rs | 8 ++ src/frontend/src/handler/comment.rs | 87 +++++++++++++++++++ src/frontend/src/handler/create_source.rs | 4 + src/frontend/src/handler/create_table.rs | 1 + src/frontend/src/handler/describe.rs | 77 ++++++++++------ src/frontend/src/handler/mod.rs | 6 ++ src/frontend/src/handler/util.rs | 1 + .../optimizer/plan_node/stream_materialize.rs | 1 + src/frontend/src/optimizer/plan_node/utils.rs | 1 + src/frontend/src/session.rs | 5 ++ src/frontend/src/test_utils.rs | 6 +- src/meta/service/src/ddl_service.rs | 26 +++++- src/meta/src/controller/mod.rs | 1 + src/meta/src/manager/catalog/mod.rs | 44 +++++++++- src/meta/src/rpc/ddl_controller.rs | 8 +- src/rpc_client/src/meta_client.rs | 12 ++- src/source/src/source_desc.rs | 1 + src/storage/src/filter_key_extractor.rs | 1 + .../src/delete_range_runner.rs | 1 + src/utils/pgwire/src/pg_response.rs | 1 + 39 files changed, 535 insertions(+), 90 deletions(-) create mode 100644 src/frontend/src/catalog/system_catalog/rw_catalog/rw_description.rs create mode 100644 src/frontend/src/handler/comment.rs diff --git a/e2e_test/batch/catalog/pg_description.slt.part b/e2e_test/batch/catalog/pg_description.slt.part index 41ade5ffbb9b3..44ba006ea4367 100644 --- a/e2e_test/batch/catalog/pg_description.slt.part +++ b/e2e_test/batch/catalog/pg_description.slt.part @@ -1,18 +1,65 @@ -query IIITT -SELECT d.*, c.relname FROM pg_catalog.pg_description d join pg_catalog.pg_class c on d.objoid = c.oid ORDER BY d.objoid limit 15; +statement ok +create table t(a int, b text, c date); + +statement ok +comment on table t is 'Lorem ipsum'; + +statement ok +comment on column t.a is 'Praesent elementum'; + +statement ok +comment on column public.t.c is 'Nullam ultricies'; + +statement ok +comment on column public.t._row_id is 'facilisis enim'; + +query TIIIT +SELECT + c.relname, + ( + SELECT relname FROM pg_catalog.pg_class WHERE oid = d.classoid + ) AS classoid, + d.objsubid, + d.description +FROM + pg_catalog.pg_description d + JOIN pg_catalog.pg_class c + ON d.objoid = c.oid +ORDER BY d.objsubid; ---- -1 NULL 0 NULL pg_type -2 NULL 0 NULL pg_namespace -3 NULL 0 NULL pg_cast -4 NULL 0 NULL pg_matviews -5 NULL 0 NULL pg_user -6 NULL 0 NULL pg_class -7 NULL 0 NULL pg_index -8 NULL 0 NULL pg_opclass -9 NULL 0 NULL pg_collation -10 NULL 0 NULL pg_am -11 NULL 0 NULL pg_operator -12 NULL 0 NULL pg_views -13 NULL 0 NULL pg_attribute -14 NULL 0 NULL pg_database -15 NULL 0 NULL pg_description \ No newline at end of file +t rw_tables -1 facilisis enim +t rw_tables 0 Lorem ipsum +t rw_tables 1 Praesent elementum +t rw_tables 3 Nullam ultricies + +statement ok +comment on table public.t is NULL; + +statement ok +comment on column t._row_id is NULL; + +statement ok +comment on column t.c is ''; + +statement ok +comment on column public.t.b is 'Vivamus fermentum'; + +query TIIIT +SELECT + c.relname, + ( + SELECT relname FROM pg_catalog.pg_class WHERE oid = d.classoid + ) AS classoid, + d.objsubid, + d.description +FROM + pg_catalog.pg_description d + JOIN pg_catalog.pg_class c + ON d.objoid = c.oid +ORDER BY d.objsubid; +---- +t rw_tables 1 Praesent elementum +t rw_tables 2 Vivamus fermentum + +statement ok +drop table t; diff --git a/e2e_test/ddl/show.slt b/e2e_test/ddl/show.slt index 5ae7575668645..9586731207fa7 100644 --- a/e2e_test/ddl/show.slt +++ b/e2e_test/ddl/show.slt @@ -7,15 +7,28 @@ create materialized view mv3 as select sum(v1) as sum_v1 from t3; statement ok create view v3 as select sum(v2) as sum_v2 from t3; -query TTT +statement ok +comment on table t3 is 'volutpat vitae'; + +statement ok +comment on column t3.v1 is 'turpis vehicula'; + +statement ok +comment on column t3.v2 is 'Lorem ipsum dolor sit amet'; + +statement ok +comment on column public.t3._row_id is 'consectetur adipiscing elit'; + +query TTTT describe t3; ---- -v1 integer false -v2 integer false -v3 integer false -_row_id serial true -primary key _row_id NULL -distribution key _row_id NULL +v1 integer false turpis vehicula +v2 integer false Lorem ipsum dolor sit amet +v3 integer false NULL +_row_id serial true consectetur adipiscing elit +primary key _row_id NULL NULL +distribution key _row_id NULL NULL +table description t3 NULL volutpat vitae query TTT show columns from t3; @@ -33,16 +46,29 @@ show indexes from t3; ---- idx1 t3 v1 ASC, v2 ASC v3 v1 -query TTT +statement ok +comment on table public.t3 is 'consectetur turpis'; + +statement ok +comment on column t3.v1 is 'Nemo enim ipsam'; + +statement ok +comment on column t3.v2 is ''; + +statement ok +comment on column t3._row_id is NULL; + +query TTTT describe t3; ---- -v1 integer false -v2 integer false -v3 integer false -_row_id serial true -primary key _row_id NULL -distribution key _row_id NULL -idx1 index(v1 ASC, v2 ASC) include(v3) distributed by(v1) NULL +v1 integer false Nemo enim ipsam +v2 integer false NULL +v3 integer false NULL +_row_id serial true NULL +primary key _row_id NULL NULL +distribution key _row_id NULL NULL +idx1 index(v1 ASC, v2 ASC) include(v3) distributed by(v1) NULL NULL +table description t3 NULL consectetur turpis query TT show create index idx1; diff --git a/e2e_test/extended_mode/basic.slt b/e2e_test/extended_mode/basic.slt index 7869494979e47..054dae2f6a234 100644 --- a/e2e_test/extended_mode/basic.slt +++ b/e2e_test/extended_mode/basic.slt @@ -39,15 +39,16 @@ values(round(42.4382)); statement ok create table t3 (v1 int, v2 int, v3 int); -query TTT +query TTTT describe t3; ---- -v1 integer false -v2 integer false -v3 integer false -_row_id serial true -primary key _row_id NULL -distribution key _row_id NULL +v1 integer false NULL +v2 integer false NULL +v3 integer false NULL +_row_id serial true NULL +primary key _row_id NULL NULL +distribution key _row_id NULL NULL +table description t3 NULL NULL query TTT show columns from t3; diff --git a/proto/catalog.proto b/proto/catalog.proto index 2d4d51b5692b3..c966b7bbe5eb0 100644 --- a/proto/catalog.proto +++ b/proto/catalog.proto @@ -280,6 +280,9 @@ message Table { CreateType create_type = 32; + // This field is used to store the description set by the `comment on` clause. + optional string description = 33; + // Per-table catalog version, used by schema change. `None` for internal tables and tests. // Not to be confused with the global catalog version for notification service. TableVersion version = 100; @@ -317,3 +320,11 @@ message Database { string name = 2; uint32 owner = 3; } + +message Comment { + uint32 table_id = 1; + uint32 schema_id = 2; + uint32 database_id = 3; + optional uint32 column_index = 4; + optional string description = 5; +} diff --git a/proto/ddl_service.proto b/proto/ddl_service.proto index 1efc933a7d033..b3c7f17509f8c 100644 --- a/proto/ddl_service.proto +++ b/proto/ddl_service.proto @@ -318,6 +318,15 @@ message WaitRequest {} message WaitResponse {} +message CommentOnRequest { + catalog.Comment comment = 1; +} + +message CommentOnResponse { + common.Status status = 1; + uint64 version = 2; +} + service DdlService { rpc CreateDatabase(CreateDatabaseRequest) returns (CreateDatabaseResponse); rpc DropDatabase(DropDatabaseRequest) returns (DropDatabaseResponse); @@ -348,4 +357,5 @@ service DdlService { rpc DropConnection(DropConnectionRequest) returns (DropConnectionResponse); rpc GetTables(GetTablesRequest) returns (GetTablesResponse); rpc Wait(WaitRequest) returns (WaitResponse); + rpc CommentOn(CommentOnRequest) returns (CommentOnResponse); } diff --git a/proto/plan_common.proto b/proto/plan_common.proto index d4c7a2e04f138..afea3aff14bc7 100644 --- a/proto/plan_common.proto +++ b/proto/plan_common.proto @@ -37,6 +37,9 @@ message ColumnDesc { GeneratedColumnDesc generated_column = 6; DefaultColumnDesc default_column = 7; } + + // This field is used to store the description set by the `comment on` clause. + optional string description = 8; } message ColumnCatalog { diff --git a/src/common/src/catalog/column.rs b/src/common/src/catalog/column.rs index cde16ef8d7652..b70084fbf864a 100644 --- a/src/common/src/catalog/column.rs +++ b/src/common/src/catalog/column.rs @@ -101,6 +101,7 @@ pub struct ColumnDesc { pub field_descs: Vec, pub type_name: String, pub generated_or_default_column: Option, + pub description: Option, } impl ColumnDesc { @@ -112,6 +113,7 @@ impl ColumnDesc { field_descs: vec![], type_name: String::new(), generated_or_default_column: None, + description: None, } } @@ -129,6 +131,7 @@ impl ColumnDesc { .collect_vec(), type_name: self.type_name.clone(), generated_or_default_column: self.generated_or_default_column.clone(), + description: self.description.clone(), } } @@ -172,6 +175,7 @@ impl ColumnDesc { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, } } @@ -192,6 +196,7 @@ impl ColumnDesc { field_descs: fields, type_name: type_name.to_string(), generated_or_default_column: None, + description: None, } } @@ -206,6 +211,7 @@ impl ColumnDesc { .map(Self::from_field_without_column_id) .collect_vec(), type_name: field.type_name.clone(), + description: None, generated_or_default_column: None, } } @@ -243,6 +249,7 @@ impl From for ColumnDesc { type_name: prost.type_name, field_descs, generated_or_default_column: prost.generated_or_default_column, + description: prost.description.clone(), } } } @@ -262,6 +269,7 @@ impl From<&ColumnDesc> for PbColumnDesc { field_descs: c.field_descs.iter().map(ColumnDesc::to_protobuf).collect(), type_name: c.type_name.clone(), generated_or_default_column: c.generated_or_default_column.clone(), + description: c.description.clone(), } } } diff --git a/src/common/src/catalog/mod.rs b/src/common/src/catalog/mod.rs index e83b4aa638907..1a46cdcf4057a 100644 --- a/src/common/src/catalog/mod.rs +++ b/src/common/src/catalog/mod.rs @@ -110,6 +110,7 @@ pub fn row_id_column_desc() -> ColumnDesc { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, } } @@ -131,6 +132,7 @@ pub fn offset_column_desc() -> ColumnDesc { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, } } diff --git a/src/common/src/catalog/test_utils.rs b/src/common/src/catalog/test_utils.rs index 2cce9b79b346e..6b524edb92430 100644 --- a/src/common/src/catalog/test_utils.rs +++ b/src/common/src/catalog/test_utils.rs @@ -57,6 +57,7 @@ impl ColumnDescTestExt for ColumnDesc { type_name: type_name.to_string(), field_descs: fields, generated_or_default_column: None, + description: None, } } } diff --git a/src/compute/tests/integration_tests.rs b/src/compute/tests/integration_tests.rs index 6d7e93365c275..078dfa05aa448 100644 --- a/src/compute/tests/integration_tests.rs +++ b/src/compute/tests/integration_tests.rs @@ -159,6 +159,7 @@ async fn test_table_materialize() -> StreamResult<()> { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, }) .collect_vec(); let (barrier_tx, barrier_rx) = unbounded_channel(); diff --git a/src/connector/src/parser/avro/util.rs b/src/connector/src/parser/avro/util.rs index 917b23f1af6d0..e1b63962bf23c 100644 --- a/src/connector/src/parser/avro/util.rs +++ b/src/connector/src/parser/avro/util.rs @@ -57,6 +57,7 @@ fn avro_field_to_column_desc( field_descs: vec_column, type_name: schema_name.to_string(), generated_or_default_column: None, + description: None, }) } _ => { diff --git a/src/connector/src/parser/protobuf/parser.rs b/src/connector/src/parser/protobuf/parser.rs index 71d122470902e..0ca0235254000 100644 --- a/src/connector/src/parser/protobuf/parser.rs +++ b/src/connector/src/parser/protobuf/parser.rs @@ -199,6 +199,7 @@ impl ProtobufParserConfig { field_descs, type_name: m.full_name().to_string(), generated_or_default_column: None, + description: None, }) } else { *index += 1; diff --git a/src/connector/src/source/manager.rs b/src/connector/src/source/manager.rs index bdd72a090f9e8..8624550274299 100644 --- a/src/connector/src/source/manager.rs +++ b/src/connector/src/source/manager.rs @@ -123,6 +123,7 @@ impl From<&SourceColumnDesc> for ColumnDesc { field_descs: s.fields.clone(), type_name: "".to_string(), generated_or_default_column: None, + description: None, } } } diff --git a/src/frontend/src/binder/expr/mod.rs b/src/frontend/src/binder/expr/mod.rs index 6da590c2d315d..221056f3a4822 100644 --- a/src/frontend/src/binder/expr/mod.rs +++ b/src/frontend/src/binder/expr/mod.rs @@ -576,6 +576,7 @@ pub fn bind_struct_field(column_def: &StructField) -> Result { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, }) }) .collect::>>()? @@ -589,6 +590,7 @@ pub fn bind_struct_field(column_def: &StructField) -> Result { field_descs, type_name: "".to_string(), generated_or_default_column: None, + description: None, }) } diff --git a/src/frontend/src/catalog/catalog_service.rs b/src/frontend/src/catalog/catalog_service.rs index 8eb6b9e3e4485..be85293acd27f 100644 --- a/src/frontend/src/catalog/catalog_service.rs +++ b/src/frontend/src/catalog/catalog_service.rs @@ -21,7 +21,8 @@ use risingwave_common::error::ErrorCode::InternalError; use risingwave_common::error::{Result, RwError}; use risingwave_common::util::column_index_mapping::ColIndexMapping; use risingwave_pb::catalog::{ - PbCreateType, PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource, PbTable, PbView, + PbComment, PbCreateType, PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource, PbTable, + PbView, }; use risingwave_pb::ddl_service::alter_relation_name_request::Relation; use risingwave_pb::ddl_service::create_connection_request; @@ -111,6 +112,8 @@ pub trait CatalogWriter: Send + Sync { connection: create_connection_request::Payload, ) -> Result<()>; + async fn comment_on(&self, comment: PbComment) -> Result<()>; + async fn drop_table( &self, source_id: Option, @@ -282,6 +285,11 @@ impl CatalogWriter for CatalogWriterImpl { self.wait_version(version).await } + async fn comment_on(&self, comment: PbComment) -> Result<()> { + let version = self.meta_client.comment_on(comment).await?; + self.wait_version(version).await + } + async fn drop_table( &self, source_id: Option, diff --git a/src/frontend/src/catalog/system_catalog/mod.rs b/src/frontend/src/catalog/system_catalog/mod.rs index 4cd271f0495b9..d64db79b8ced1 100644 --- a/src/frontend/src/catalog/system_catalog/mod.rs +++ b/src/frontend/src/catalog/system_catalog/mod.rs @@ -57,6 +57,9 @@ pub struct SystemTableCatalog { // owner of table, should always be default super user, keep it for compatibility. pub owner: u32, + + /// description of table, set by `comment on`. + pub description: Option, } impl SystemTableCatalog { @@ -165,6 +168,7 @@ impl From<&BuiltinTable> for SystemTableCatalog { .collect(), pk: val.pk.to_vec(), owner: DEFAULT_SUPER_USER_ID, + description: None, } } } @@ -412,6 +416,7 @@ prepare_sys_catalog! { { BuiltinCatalog::Table(&RW_HUMMOCK_BRANCHED_OBJECTS), read_hummock_branched_objects await }, { BuiltinCatalog::Table(&RW_HUMMOCK_COMPACTION_GROUP_CONFIGS), read_hummock_compaction_group_configs await }, { BuiltinCatalog::Table(&RW_HUMMOCK_META_CONFIGS), read_hummock_meta_configs await}, + { BuiltinCatalog::Table(&RW_DESCRIPTION), read_rw_description }, } #[cfg(test)] diff --git a/src/frontend/src/catalog/system_catalog/pg_catalog/pg_description.rs b/src/frontend/src/catalog/system_catalog/pg_catalog/pg_description.rs index 8bc91f4a10bb9..593522ceda705 100644 --- a/src/frontend/src/catalog/system_catalog/pg_catalog/pg_description.rs +++ b/src/frontend/src/catalog/system_catalog/pg_catalog/pg_description.rs @@ -21,22 +21,25 @@ use crate::catalog::system_catalog::BuiltinView; /// The catalog `pg_description` stores description. /// Ref: [`https://www.postgresql.org/docs/current/catalog-pg-description.html`] -pub static PG_DESCRIPTION: LazyLock = LazyLock::new(|| { - BuiltinView { - name: "pg_description", - schema: PG_CATALOG_SCHEMA_NAME, - columns: &[ - (DataType::Int32, "objoid"), - (DataType::Int32, "classoid"), - (DataType::Int32, "objsubid"), - (DataType::Varchar, "description"), - ], - sql: "SELECT id AS objoid, NULL::integer AS classoid, 0 AS objsubid, NULL AS description FROM rw_catalog.rw_tables \ - UNION ALL SELECT id AS objoid, NULL::integer AS classoid, 0 AS objsubid, NULL AS description FROM rw_catalog.rw_materialized_views \ - UNION ALL SELECT id AS objoid, NULL::integer AS classoid, 0 AS objsubid, NULL AS description FROM rw_catalog.rw_views \ - UNION ALL SELECT id AS objoid, NULL::integer AS classoid, 0 AS objsubid, NULL AS description FROM rw_catalog.rw_indexes \ - UNION ALL SELECT id AS objoid, NULL::integer AS classoid, 0 AS objsubid, NULL AS description FROM rw_catalog.rw_sources \ - UNION ALL SELECT id AS objoid, NULL::integer AS classoid, 0 AS objsubid, NULL AS description FROM rw_catalog.rw_system_tables\ - ".into(), - } +pub static PG_DESCRIPTION: LazyLock = LazyLock::new(|| BuiltinView { + name: "pg_description", + schema: PG_CATALOG_SCHEMA_NAME, + columns: &[ + (DataType::Int32, "objoid"), + (DataType::Int32, "classoid"), + (DataType::Int32, "objsubid"), + (DataType::Varchar, "description"), + ], + // objsubid = 0 => _row_id (hidden column) + // objsubid is NULL => table self + sql: "SELECT objoid, \ + classoid, \ + CASE \ + WHEN objsubid = 0 THEN -1 \ + WHEN objsubid IS NULL THEN 0 \ + ELSE objsubid \ + END AS objsubid, \ + description FROM rw_catalog.rw_description \ + WHERE description IS NOT NULL;" + .into(), }); diff --git a/src/frontend/src/catalog/system_catalog/rw_catalog/mod.rs b/src/frontend/src/catalog/system_catalog/rw_catalog/mod.rs index 9f89c9eed5e81..517f40b460e94 100644 --- a/src/frontend/src/catalog/system_catalog/rw_catalog/mod.rs +++ b/src/frontend/src/catalog/system_catalog/rw_catalog/mod.rs @@ -17,6 +17,7 @@ mod rw_columns; mod rw_connections; mod rw_databases; mod rw_ddl_progress; +mod rw_description; mod rw_fragments; mod rw_functions; mod rw_hummock_branched_objects; @@ -50,6 +51,7 @@ pub use rw_columns::*; pub use rw_connections::*; pub use rw_databases::*; pub use rw_ddl_progress::*; +pub use rw_description::*; pub use rw_fragments::*; pub use rw_functions::*; pub use rw_hummock_branched_objects::*; diff --git a/src/frontend/src/catalog/system_catalog/rw_catalog/rw_description.rs b/src/frontend/src/catalog/system_catalog/rw_catalog/rw_description.rs new file mode 100644 index 0000000000000..370dec33a2a2a --- /dev/null +++ b/src/frontend/src/catalog/system_catalog/rw_catalog/rw_description.rs @@ -0,0 +1,84 @@ +// Copyright 2023 RisingWave 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::iter; + +use risingwave_common::catalog::RW_CATALOG_SCHEMA_NAME; +use risingwave_common::error::Result; +use risingwave_common::row::OwnedRow; +use risingwave_common::types::{DataType, ScalarImpl}; + +use crate::catalog::system_catalog::{BuiltinTable, SysCatalogReaderImpl}; + +pub const RW_DESCRIPTION: BuiltinTable = BuiltinTable { + name: "rw_description", + schema: RW_CATALOG_SCHEMA_NAME, + columns: &[ + // table_id, view_id, function_id, etc. + (DataType::Int32, "objoid"), + // rw_tables, rw_views, rw_functions, etc. + (DataType::Int32, "classoid"), + // If `objoid` is `table_id`, then non-null `objsubid` is column number. + (DataType::Int32, "objsubid"), + (DataType::Varchar, "description"), + ], + pk: &[0, 1, 2], +}; + +impl SysCatalogReaderImpl { + pub fn read_rw_description(&self) -> Result> { + let build_row = + |table_id, catalog_id, index: Option, description: Option>| { + OwnedRow::new(vec![ + Some(ScalarImpl::Int32(table_id)), + Some(ScalarImpl::Int32(catalog_id)), + index.map(ScalarImpl::Int32), + description.map(ScalarImpl::Utf8), + ]) + }; + + let reader = self.catalog_reader.read_guard(); + let rw_catalog = + reader.get_schema_by_name(&self.auth_context.database, RW_CATALOG_SCHEMA_NAME)?; + let schemas = reader + .iter_schemas(&self.auth_context.database)? + .filter(|schema| schema.id() != rw_catalog.id()); + + let rw_tables_id: i32 = rw_catalog + .get_system_table_by_name("rw_tables") + .map(|st| st.id.table_id) + .unwrap_or_default() as _; + + Ok(schemas + .flat_map(|schema| { + schema.iter_table().flat_map(|table| { + iter::once(build_row( + table.id.table_id as _, + rw_tables_id, + None, + table.description.as_deref().map(Into::into), + )) + .chain(table.columns.iter().map(|col| { + build_row( + table.id.table_id as _, + rw_tables_id, + Some(col.column_id().get_id() as _), + col.column_desc.description.as_deref().map(Into::into), + ) + })) + }) + }) + .collect()) + } +} diff --git a/src/frontend/src/catalog/table_catalog.rs b/src/frontend/src/catalog/table_catalog.rs index b0f9088132f59..750a06da7d231 100644 --- a/src/frontend/src/catalog/table_catalog.rs +++ b/src/frontend/src/catalog/table_catalog.rs @@ -152,6 +152,9 @@ pub struct TableCatalog { /// Indicate whether to create table in background or foreground. pub create_type: CreateType, + + /// description of table, set by `comment on`. + pub description: Option, } // How the stream job was created will determine @@ -438,6 +441,7 @@ impl TableCatalog { cleaned_by_watermark: self.cleaned_by_watermark, stream_job_status: PbStreamJobStatus::Creating.into(), create_type: self.create_type.to_prost().into(), + description: self.description.clone(), } } @@ -551,6 +555,7 @@ impl From for TableCatalog { initialized_at_epoch: tb.initialized_at_epoch.map(Epoch::from), cleaned_by_watermark: matches!(tb.cleaned_by_watermark, true), create_type: CreateType::from_prost(create_type), + description: tb.description, } } } @@ -643,6 +648,7 @@ mod tests { cleaned_by_watermark: false, stream_job_status: PbStreamJobStatus::Creating.into(), create_type: PbCreateType::Foreground.into(), + description: Some("description".to_string()), } .into(); @@ -668,6 +674,7 @@ mod tests { ColumnDesc::new_atomic(DataType::Varchar, "zipcode", 3), ], type_name: ".test.Country".to_string(), + description: None, generated_or_default_column: None, }, is_hidden: false @@ -698,6 +705,7 @@ mod tests { initialized_at_epoch: None, cleaned_by_watermark: false, create_type: CreateType::Foreground, + description: Some("description".to_string()) } ); assert_eq!(table, TableCatalog::from(table.to_prost(0, 0))); diff --git a/src/frontend/src/handler/comment.rs b/src/frontend/src/handler/comment.rs new file mode 100644 index 0000000000000..b0ff42a790346 --- /dev/null +++ b/src/frontend/src/handler/comment.rs @@ -0,0 +1,87 @@ +// Copyright 2023 RisingWave 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 pgwire::pg_response::{PgResponse, StatementType}; +use risingwave_common::error::{ErrorCode, Result}; +use risingwave_pb::catalog::PbComment; +use risingwave_sqlparser::ast::{CommentObject, ObjectName}; + +use super::{HandlerArgs, RwPgResponse}; +use crate::Binder; + +pub async fn handle_comment( + handler_args: HandlerArgs, + object_type: CommentObject, + object_name: ObjectName, + comment: Option, +) -> Result { + let session = handler_args.session; + let comment = comment.filter(|s| !s.is_empty()); + + let comment = { + let mut binder = Binder::new_for_ddl(&session); + // only `Column` and `Table` object are now supported + match object_type { + CommentObject::Column => { + let [tab @ .., col] = object_name.0.as_slice() else { + return Err(ErrorCode::BindError(format!( + "Invalid column: {}", + object_name.real_value() + )) + .into()); + }; + + let (schema, table) = Binder::resolve_schema_qualified_name( + session.database(), + ObjectName(tab.to_vec()), + )?; + + let (database_id, schema_id) = + session.get_database_and_schema_id_for_create(schema)?; + let table = binder.bind_table(None, &table, None)?; + binder.bind_columns_to_context(col.real_value(), table.table_catalog.columns)?; + + let column = binder.bind_column(object_name.0.as_slice())?; + + PbComment { + table_id: table.table_id.into(), + schema_id, + database_id, + column_index: column.as_input_ref().map(|input_ref| input_ref.index as _), + description: comment, + } + } + CommentObject::Table => { + let (schema, table) = + Binder::resolve_schema_qualified_name(session.database(), object_name)?; + let (database_id, schema_id) = + session.get_database_and_schema_id_for_create(schema)?; + let table = binder.bind_table(None, &table, None)?; + + PbComment { + table_id: table.table_id.into(), + schema_id, + database_id, + column_index: None, + description: comment, + } + } + } + }; + + let catalog_writer = session.catalog_writer()?; + catalog_writer.comment_on(comment).await?; + + Ok(PgResponse::empty_result(StatementType::COMMENT)) +} diff --git a/src/frontend/src/handler/create_source.rs b/src/frontend/src/handler/create_source.rs index 6f7de61285cb0..0c2398a608eb8 100644 --- a/src/frontend/src/handler/create_source.rs +++ b/src/frontend/src/handler/create_source.rs @@ -630,6 +630,7 @@ pub(crate) async fn try_bind_columns_from_source( field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, }, is_hidden: false, }, @@ -641,6 +642,7 @@ pub(crate) async fn try_bind_columns_from_source( field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, }, is_hidden: false, }, @@ -775,6 +777,7 @@ fn check_and_add_timestamp_column( field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, }, is_hidden: true, @@ -792,6 +795,7 @@ fn add_upsert_default_key_column(columns: &mut Vec) { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, }, is_hidden: true, }; diff --git a/src/frontend/src/handler/create_table.rs b/src/frontend/src/handler/create_table.rs index 19d9a2f25c4b8..bb02797c21395 100644 --- a/src/frontend/src/handler/create_table.rs +++ b/src/frontend/src/handler/create_table.rs @@ -188,6 +188,7 @@ pub fn bind_sql_columns(column_defs: &[ColumnDef]) -> Result> field_descs, type_name: "".to_string(), generated_or_default_column: None, + description: None, }, is_hidden: false, }); diff --git a/src/frontend/src/handler/describe.rs b/src/frontend/src/handler/describe.rs index 4100b9a20be02..cef7af9dbd324 100644 --- a/src/frontend/src/handler/describe.rs +++ b/src/frontend/src/handler/describe.rs @@ -12,20 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; +use std::fmt::Display; use itertools::Itertools; use pgwire::pg_field_descriptor::PgFieldDescriptor; use pgwire::pg_response::{PgResponse, StatementType}; use pgwire::types::Row; -use risingwave_common::catalog::{ColumnCatalog, ColumnDesc}; use risingwave_common::error::Result; use risingwave_common::types::DataType; use risingwave_sqlparser::ast::{display_comma_separated, ObjectName}; use super::RwPgResponse; use crate::binder::{Binder, Relation}; -use crate::catalog::{CatalogError, IndexCatalog}; +use crate::catalog::CatalogError; use crate::handler::util::col_descs_to_rows; use crate::handler::HandlerArgs; @@ -34,12 +33,9 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res let mut binder = Binder::new_for_system(&session); let relation = binder.bind_relation_by_name(table_name.clone(), None, false)?; // For Source, it doesn't have table catalog so use get source to get column descs. - let (columns, pk_columns, dist_columns, indices): ( - Vec, - Vec, - Vec, - Vec>, - ) = match relation { + + // Vec, Vec, Vec, Vec>, String, Option + let (columns, pk_columns, dist_columns, indices, relname, description) = match relation { Relation::Source(s) => { let pk_column_catalogs = s .catalog @@ -55,7 +51,14 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res .unwrap() }) .collect_vec(); - (s.catalog.columns, pk_column_catalogs, vec![], vec![]) + ( + s.catalog.columns, + pk_column_catalogs, + vec![], + vec![], + s.catalog.name, + None, // Description + ) } Relation::BaseTable(t) => { let pk_column_catalogs = t @@ -75,6 +78,8 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res pk_column_catalogs, dist_columns, t.table_indexes, + t.table_catalog.name, + t.table_catalog.description, ) } Relation::SystemTable(t) => { @@ -89,6 +94,8 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res pk_column_catalogs, vec![], vec![], + t.sys_table_catalog.name.clone(), + None, // Description ) } _ => { @@ -99,18 +106,23 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res // Convert all column descs to rows let mut rows = col_descs_to_rows(columns); + fn concat(display_elems: impl IntoIterator) -> String + where + T: Display, + { + format!( + "{}", + display_comma_separated(&display_elems.into_iter().collect::>()) + ) + } + // Convert primary key to rows if !pk_columns.is_empty() { rows.push(Row::new(vec![ Some("primary key".into()), - Some( - format!( - "{}", - display_comma_separated(&pk_columns.into_iter().map(|x| x.name).collect_vec()), - ) - .into(), - ), - None, + Some(concat(pk_columns.iter().map(|x| &x.name)).into()), + None, // Is Hidden + None, // Description ])); } @@ -118,14 +130,9 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res if !dist_columns.is_empty() { rows.push(Row::new(vec![ Some("distribution key".into()), - Some( - display_comma_separated( - &dist_columns.into_iter().map(|col| col.name).collect_vec(), - ) - .to_string() - .into(), - ), - None, + Some(concat(dist_columns.iter().map(|x| &x.name)).into()), + None, // Is Hidden + None, // Description ])); } @@ -155,10 +162,22 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res .into(), ) }, + // Is Hidden + None, + // Description + // TODO: index description None, ]) })); + rows.push(Row::new(vec![ + Some("table description".into()), + Some(relname.into()), + None, // Is Hidden + description.map(Into::into), // Description + ])); + + // TODO: table name and description as title of response // TODO: recover the original user statement Ok(PgResponse::builder(StatementType::DESCRIBE) .values( @@ -179,6 +198,11 @@ pub fn handle_describe(handler_args: HandlerArgs, table_name: ObjectName) -> Res DataType::Varchar.to_oid(), DataType::Varchar.type_len(), ), + PgFieldDescriptor::new( + "Description".to_owned(), + DataType::Varchar.to_oid(), + DataType::Varchar.type_len(), + ), ], ) .into()) @@ -233,6 +257,7 @@ mod tests { "primary key".into() => "v3".into(), "distribution key".into() => "v3".into(), "idx1".into() => "index(v1 DESC, v2 ASC, v3 ASC) include(v4) distributed by(v1)".into(), + "table description".into() => "t".into(), }; assert_eq!(columns, expected_columns); diff --git a/src/frontend/src/handler/mod.rs b/src/frontend/src/handler/mod.rs index 174ed23e03ec5..8275551fbc4a6 100644 --- a/src/frontend/src/handler/mod.rs +++ b/src/frontend/src/handler/mod.rs @@ -39,6 +39,7 @@ mod alter_system; mod alter_table_column; pub mod alter_user; pub mod cancel_job; +mod comment; pub mod create_connection; mod create_database; pub mod create_function; @@ -525,6 +526,11 @@ pub async fn handle( session, } => transaction::handle_set(handler_args, modes, snapshot, session).await, Statement::CancelJobs(jobs) => handle_cancel(handler_args, jobs).await, + Statement::Comment { + object_type, + object_name, + comment, + } => comment::handle_comment(handler_args, object_type, object_name, comment).await, _ => Err( ErrorCode::NotImplemented(format!("Unhandled statement: {}", stmt), None.into()).into(), ), diff --git a/src/frontend/src/handler/util.rs b/src/frontend/src/handler/util.rs index 66494be928d42..7c1eca3fa9bbf 100644 --- a/src/frontend/src/handler/util.rs +++ b/src/frontend/src/handler/util.rs @@ -187,6 +187,7 @@ pub fn col_descs_to_rows(columns: Vec) -> Vec { Some(c.name.into()), Some(type_name.into()), Some(col.is_hidden.to_string().into()), + c.description.map(Into::into), ]) }) .collect_vec() diff --git a/src/frontend/src/optimizer/plan_node/stream_materialize.rs b/src/frontend/src/optimizer/plan_node/stream_materialize.rs index 9c87f1a34abbd..d5435e9beb397 100644 --- a/src/frontend/src/optimizer/plan_node/stream_materialize.rs +++ b/src/frontend/src/optimizer/plan_node/stream_materialize.rs @@ -250,6 +250,7 @@ impl StreamMaterialize { initialized_at_epoch: None, cleaned_by_watermark: false, create_type: CreateType::Foreground, // Will be updated in the handler itself. + description: None, }) } diff --git a/src/frontend/src/optimizer/plan_node/utils.rs b/src/frontend/src/optimizer/plan_node/utils.rs index f167d73c53a46..f05a8be162554 100644 --- a/src/frontend/src/optimizer/plan_node/utils.rs +++ b/src/frontend/src/optimizer/plan_node/utils.rs @@ -180,6 +180,7 @@ impl TableCatalogBuilder { // NOTE(kwannoel): This may not match the create type of the materialized table. // It should be ignored for internal tables. create_type: CreateType::Foreground, + description: None, } } diff --git a/src/frontend/src/session.rs b/src/frontend/src/session.rs index 67eac0df34d05..0385bd52690ef 100644 --- a/src/frontend/src/session.rs +++ b/src/frontend/src/session.rs @@ -1148,6 +1148,11 @@ fn infer(bound: Option, stmt: Statement) -> Result Ok(vec![PgFieldDescriptor::new( "QUERY PLAN".to_owned(), diff --git a/src/frontend/src/test_utils.rs b/src/frontend/src/test_utils.rs index cf915ae35713d..6cca805f3caae 100644 --- a/src/frontend/src/test_utils.rs +++ b/src/frontend/src/test_utils.rs @@ -32,7 +32,7 @@ use risingwave_common::util::column_index_mapping::ColIndexMapping; use risingwave_pb::backup_service::MetaSnapshotMetadata; use risingwave_pb::catalog::table::OptionalAssociatedSourceId; use risingwave_pb::catalog::{ - PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource, PbTable, PbView, Table, + PbComment, PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource, PbTable, PbView, Table, }; use risingwave_pb::ddl_service::{create_connection_request, DdlProgress}; use risingwave_pb::hummock::write_limits::WriteLimit; @@ -318,6 +318,10 @@ impl CatalogWriter for MockCatalogWriter { unreachable!() } + async fn comment_on(&self, _comment: PbComment) -> Result<()> { + unreachable!() + } + async fn drop_table( &self, source_id: Option, diff --git a/src/meta/service/src/ddl_service.rs b/src/meta/service/src/ddl_service.rs index fac8f89e17b11..6f08ebfb18d17 100644 --- a/src/meta/service/src/ddl_service.rs +++ b/src/meta/service/src/ddl_service.rs @@ -25,7 +25,7 @@ use risingwave_pb::catalog::connection::private_link_service::{ use risingwave_pb::catalog::connection::PbPrivateLinkService; use risingwave_pb::catalog::source::OptionalAssociatedTableId; use risingwave_pb::catalog::table::OptionalAssociatedSourceId; -use risingwave_pb::catalog::{connection, Connection, CreateType, PbSource, PbTable}; +use risingwave_pb::catalog::{connection, Comment, Connection, CreateType, PbSource, PbTable}; use risingwave_pb::ddl_service::ddl_service_server::DdlService; use risingwave_pb::ddl_service::drop_table_request::PbSourceId; use risingwave_pb::ddl_service::*; @@ -717,6 +717,30 @@ impl DdlService for DdlServiceImpl { })) } + async fn comment_on( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + let comment = req.get_comment()?.clone(); + + let version = self + .ddl_controller + .run_command(DdlCommand::CommentOn(Comment { + table_id: comment.table_id, + schema_id: comment.schema_id, + database_id: comment.database_id, + column_index: comment.column_index, + description: comment.description, + })) + .await?; + + Ok(Response::new(CommentOnResponse { + status: None, + version, + })) + } + #[cfg_attr(coverage, coverage(off))] async fn get_tables( &self, diff --git a/src/meta/src/controller/mod.rs b/src/meta/src/controller/mod.rs index d9193acd5591f..c69c615165d11 100644 --- a/src/meta/src/controller/mod.rs +++ b/src/meta/src/controller/mod.rs @@ -131,6 +131,7 @@ impl From> for PbTable { .0 .optional_associated_source_id .map(PbOptionalAssociatedSourceId::AssociatedSourceId), + description: None, } } } diff --git a/src/meta/src/manager/catalog/mod.rs b/src/meta/src/manager/catalog/mod.rs index 15e74e4c2ac9e..d2007dcab45d6 100644 --- a/src/meta/src/manager/catalog/mod.rs +++ b/src/meta/src/manager/catalog/mod.rs @@ -34,8 +34,8 @@ use risingwave_common::catalog::{ use risingwave_common::{bail, ensure}; use risingwave_pb::catalog::table::{OptionalAssociatedSourceId, TableType}; use risingwave_pb::catalog::{ - Connection, CreateType, Database, Function, Index, PbStreamJobStatus, Schema, Sink, Source, - StreamJobStatus, Table, View, + Comment, Connection, CreateType, Database, Function, Index, PbStreamJobStatus, Schema, Sink, + Source, StreamJobStatus, Table, View, }; use risingwave_pb::meta::subscribe_response::{Info, Operation}; use risingwave_pb::user::grant_privilege::{ActionWithGrantOption, Object}; @@ -2365,6 +2365,46 @@ impl CatalogManager { Ok(()) } + pub async fn comment_on(&self, comment: Comment) -> MetaResult { + let core = &mut *self.core.lock().await; + let database_core = &mut core.database; + + database_core.ensure_database_id(comment.database_id)?; + database_core.ensure_schema_id(comment.schema_id)?; + database_core.ensure_table_id(comment.table_id)?; + + let mut tables = BTreeMapTransaction::new(&mut database_core.tables); + + // unwrap is safe because the table id was ensured before + let mut table = tables.get_mut(comment.table_id).unwrap(); + if let Some(col_idx) = comment.column_index { + let column = table + .columns + .get_mut(col_idx as usize) + .ok_or_else(|| MetaError::catalog_id_not_found("column", col_idx))?; + let column_desc = column.column_desc.as_mut().ok_or_else(|| { + anyhow!( + "column desc at index {} for table id {} not found", + col_idx, + comment.table_id + ) + })?; + column_desc.description = comment.description; + } else { + table.description = comment.description; + } + + let new_table = table.clone(); + + commit_meta!(self, tables)?; + + let version = self + .notify_frontend_relation_info(Operation::Update, RelationInfo::Table(new_table)) + .await; + + Ok(version) + } + pub async fn list_connections(&self) -> Vec { self.core.lock().await.database.list_connections() } diff --git a/src/meta/src/rpc/ddl_controller.rs b/src/meta/src/rpc/ddl_controller.rs index 5f40d9a561f4e..8f6e7c0be6915 100644 --- a/src/meta/src/rpc/ddl_controller.rs +++ b/src/meta/src/rpc/ddl_controller.rs @@ -24,7 +24,7 @@ use risingwave_common::util::column_index_mapping::ColIndexMapping; use risingwave_common::util::epoch::Epoch; use risingwave_pb::catalog::connection::private_link_service::PbPrivateLinkProvider; use risingwave_pb::catalog::{ - connection, Connection, CreateType, Database, Function, Schema, Source, Table, View, + connection, Comment, Connection, CreateType, Database, Function, Schema, Source, Table, View, }; use risingwave_pb::ddl_service::alter_relation_name_request::Relation; use risingwave_pb::ddl_service::DdlProgress; @@ -103,6 +103,7 @@ pub enum DdlCommand { AlterSourceColumn(Source), CreateConnection(Connection), DropConnection(ConnectionId), + CommentOn(Comment), } #[derive(Clone)] @@ -260,6 +261,7 @@ impl DdlController { ctrl.drop_connection(connection_id).await } DdlCommand::AlterSourceColumn(source) => ctrl.alter_source_column(source).await, + DdlCommand::CommentOn(comment) => ctrl.comment_on(comment).await, } } .in_current_span(); @@ -1112,4 +1114,8 @@ impl DdlController { } Err(MetaError::cancelled("timeout".into())) } + + async fn comment_on(&self, comment: Comment) -> MetaResult { + self.catalog_manager.comment_on(comment).await + } } diff --git a/src/rpc_client/src/meta_client.rs b/src/rpc_client/src/meta_client.rs index 95b746ea33e6c..b8603fbe46e62 100644 --- a/src/rpc_client/src/meta_client.rs +++ b/src/rpc_client/src/meta_client.rs @@ -40,7 +40,8 @@ use risingwave_hummock_sdk::{ use risingwave_pb::backup_service::backup_service_client::BackupServiceClient; use risingwave_pb::backup_service::*; use risingwave_pb::catalog::{ - Connection, PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource, PbTable, PbView, Table, + Connection, PbComment, PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource, PbTable, + PbView, Table, }; use risingwave_pb::cloud_service::cloud_service_client::CloudServiceClient; use risingwave_pb::cloud_service::*; @@ -407,6 +408,14 @@ impl MetaClient { Ok((resp.table_id.into(), resp.version)) } + pub async fn comment_on(&self, comment: PbComment) -> Result { + let request = CommentOnRequest { + comment: Some(comment), + }; + let resp = self.inner.comment_on(request).await?; + Ok(resp.version) + } + pub async fn alter_relation_name( &self, relation: Relation, @@ -1724,6 +1733,7 @@ macro_rules! for_all_meta_rpc { ,{ ddl_client, create_connection, CreateConnectionRequest, CreateConnectionResponse } ,{ ddl_client, list_connections, ListConnectionsRequest, ListConnectionsResponse } ,{ ddl_client, drop_connection, DropConnectionRequest, DropConnectionResponse } + ,{ ddl_client, comment_on, CommentOnRequest, CommentOnResponse } ,{ ddl_client, get_tables, GetTablesRequest, GetTablesResponse } ,{ ddl_client, wait, WaitRequest, WaitResponse } ,{ hummock_client, unpin_version_before, UnpinVersionBeforeRequest, UnpinVersionBeforeResponse } diff --git a/src/source/src/source_desc.rs b/src/source/src/source_desc.rs index 161bbc41ceb63..e6646c03282a0 100644 --- a/src/source/src/source_desc.rs +++ b/src/source/src/source_desc.rs @@ -197,6 +197,7 @@ pub mod test_utils { field_descs: vec![], type_name: "".to_string(), generated_or_default_column: None, + description: None, } .to_protobuf(), ), diff --git a/src/storage/src/filter_key_extractor.rs b/src/storage/src/filter_key_extractor.rs index b5a79a6f6b42f..6538042566537 100644 --- a/src/storage/src/filter_key_extractor.rs +++ b/src/storage/src/filter_key_extractor.rs @@ -551,6 +551,7 @@ mod tests { cleaned_by_watermark: false, stream_job_status: PbStreamJobStatus::Created.into(), create_type: PbCreateType::Foreground.into(), + description: None, } } diff --git a/src/tests/compaction_test/src/delete_range_runner.rs b/src/tests/compaction_test/src/delete_range_runner.rs index 346cf2fe6acf8..db64dc6334c04 100644 --- a/src/tests/compaction_test/src/delete_range_runner.rs +++ b/src/tests/compaction_test/src/delete_range_runner.rs @@ -154,6 +154,7 @@ async fn compaction_test( cleaned_by_watermark: false, stream_job_status: PbStreamJobStatus::Created.into(), create_type: PbCreateType::Foreground.into(), + description: None, }; let mut delete_range_table = delete_key_table.clone(); delete_range_table.id = 2; diff --git a/src/utils/pgwire/src/pg_response.rs b/src/utils/pgwire/src/pg_response.rs index eeec929732f50..802f651ce4298 100644 --- a/src/utils/pgwire/src/pg_response.rs +++ b/src/utils/pgwire/src/pg_response.rs @@ -53,6 +53,7 @@ pub enum StatementType { CREATE_INDEX, CREATE_FUNCTION, CREATE_CONNECTION, + COMMENT, DESCRIBE, GRANT_PRIVILEGE, DROP_TABLE,