Skip to content

Commit 2288c18

Browse files
authored
feat(cubesql): Fill pg_description table with cube and members descriptions (#8618)
* Add description to CubeMetaTable and CubeMetaColumn * Fill pg_description table with cube descriptions
1 parent 46b3a36 commit 2288c18

15 files changed

+312
-187
lines changed

rust/cubesql/cubesql/src/compile/engine/context_postgresql.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,11 @@ impl DatabaseProtocol {
327327
context.session_state.all_variables(),
328328
)))
329329
}
330-
"pg_description" => return Some(Arc::new(PgCatalogDescriptionProvider::new())),
330+
"pg_description" => {
331+
return Some(Arc::new(PgCatalogDescriptionProvider::new(
332+
&context.meta.tables,
333+
)))
334+
}
331335
"pg_constraint" => return Some(Arc::new(PgCatalogConstraintProvider::new())),
332336
"pg_depend" => return Some(Arc::new(PgCatalogDependProvider::new())),
333337
"pg_am" => return Some(Arc::new(PgCatalogAmProvider::new())),

rust/cubesql/cubesql/src/compile/engine/information_schema/postgres/pg_description.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{any::Any, sync::Arc};
1+
use std::{any::Any, convert::TryFrom, sync::Arc};
22

33
use async_trait::async_trait;
44

@@ -14,10 +14,19 @@ use datafusion::{
1414
physical_plan::{memory::MemoryExec, ExecutionPlan},
1515
};
1616

17+
use crate::{
18+
compile::engine::information_schema::postgres::PG_CLASS_CLASS_OID, transport::CubeMetaTable,
19+
};
20+
21+
/// See https://www.postgresql.org/docs/16/catalog-pg-description.html
1722
struct PgCatalogDescriptionBuilder {
23+
/// The OID of the object this description pertains to
1824
objoid: UInt32Builder,
25+
/// The OID of the system catalog this object appears in
1926
classoid: UInt32Builder,
27+
/// For a comment on a table column, this is the column number (the objoid and classoid refer to the table itself). For all other object types, this column is zero.
2028
objsubid: Int32Builder,
29+
/// Arbitrary text that serves as the description of this object
2130
description: StringBuilder,
2231
}
2332

@@ -33,6 +42,23 @@ impl PgCatalogDescriptionBuilder {
3342
}
3443
}
3544

45+
fn add_table(&mut self, table_oid: u32, description: impl AsRef<str>) {
46+
self.objoid.append_value(table_oid).unwrap();
47+
self.classoid.append_value(PG_CLASS_CLASS_OID).unwrap();
48+
self.objsubid.append_value(0).unwrap();
49+
self.description.append_value(description).unwrap();
50+
}
51+
52+
fn add_column(&mut self, table_oid: u32, column_idx: usize, description: impl AsRef<str>) {
53+
self.objoid.append_value(table_oid).unwrap();
54+
self.classoid.append_value(PG_CLASS_CLASS_OID).unwrap();
55+
// Column subids starts with 1
56+
self.objsubid
57+
.append_value(i32::try_from(column_idx).unwrap() + 1)
58+
.unwrap();
59+
self.description.append_value(description).unwrap();
60+
}
61+
3662
fn finish(mut self) -> Vec<Arc<dyn Array>> {
3763
let columns: Vec<Arc<dyn Array>> = vec![
3864
Arc::new(self.objoid.finish()),
@@ -50,8 +76,20 @@ pub struct PgCatalogDescriptionProvider {
5076
}
5177

5278
impl PgCatalogDescriptionProvider {
53-
pub fn new() -> Self {
54-
let builder = PgCatalogDescriptionBuilder::new();
79+
pub fn new(tables: &[CubeMetaTable]) -> Self {
80+
let mut builder = PgCatalogDescriptionBuilder::new();
81+
82+
for table in tables {
83+
if let Some(description) = &table.description {
84+
builder.add_table(table.oid, description);
85+
}
86+
87+
for (idx, column) in table.columns.iter().enumerate() {
88+
if let Some(description) = &column.description {
89+
builder.add_column(table.oid, idx, description);
90+
}
91+
}
92+
}
5593

5694
Self {
5795
data: Arc::new(builder.finish()),

rust/cubesql/cubesql/src/compile/snapshots/cubesql__compile__tests__metabase_pg_class_query.snap

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
source: cubesql/src/compile/mod.rs
33
expression: "execute_query(\"\n SELECT *\n FROM (\n SELECT n.nspname,\n c.relname,\n a.attname,\n a.atttypid,\n a.attnotnull or (t.typtype = 'd' AND t.typnotnull) AS attnotnull,\n a.atttypmod,\n a.attlen,\n t.typtypmod,\n row_number() OVER (partition BY a.attrelid ORDER BY a.attnum) AS attnum,\n NULLIF(a.attidentity, '') AS attidentity,\n pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS adsrc,\n dsc.description,\n t.typbasetype,\n t.typtype\n FROM pg_catalog.pg_namespace n\n JOIN pg_catalog.pg_class c ON (c.relnamespace = n.oid)\n JOIN pg_catalog.pg_attribute a ON (a.attrelid=c.oid)\n JOIN pg_catalog.pg_type t ON (a.atttypid = t.oid)\n LEFT JOIN pg_catalog.pg_attrdef def ON (a.attrelid=def.adrelid AND a.attnum = def.adnum)\n LEFT JOIN pg_catalog.pg_description dsc ON (c.oid=dsc.objoid AND a.attnum = dsc.objsubid)\n LEFT JOIN pg_catalog.pg_class dc ON (dc.oid=dsc.classoid AND dc.relname='pg_class')\n LEFT JOIN pg_catalog.pg_namespace dn ON (dc.relnamespace=dn.oid AND dn.nspname='pg_catalog')\n WHERE c.relkind IN ('r', 'p', 'v', 'f', 'm') AND a.attnum > 0 AND NOT a.attisdropped AND n.nspname LIKE 'public' AND c.relname LIKE 'KibanaSampleDataEcommerce') c\n WHERE true\n ORDER BY nspname, c.relname, attnum;\n \".to_string(),\nDatabaseProtocol::PostgreSQL).await?"
44
---
5-
+---------+---------------------------+--------------------+----------+------------+-----------+--------+-----------+--------+-------------+-------+-------------+-------------+---------+
6-
| nspname | relname | attname | atttypid | attnotnull | atttypmod | attlen | typtypmod | attnum | attidentity | adsrc | description | typbasetype | typtype |
7-
+---------+---------------------------+--------------------+----------+------------+-----------+--------+-----------+--------+-------------+-------+-------------+-------------+---------+
8-
| public | KibanaSampleDataEcommerce | count | 20 | true | -1 | 8 | -1 | 1 | NULL | NULL | NULL | 0 | b |
9-
| public | KibanaSampleDataEcommerce | maxPrice | 1700 | true | -1 | -1 | -1 | 2 | NULL | NULL | NULL | 0 | b |
10-
| public | KibanaSampleDataEcommerce | sumPrice | 1700 | true | -1 | -1 | -1 | 3 | NULL | NULL | NULL | 0 | b |
11-
| public | KibanaSampleDataEcommerce | minPrice | 1700 | true | -1 | -1 | -1 | 4 | NULL | NULL | NULL | 0 | b |
12-
| public | KibanaSampleDataEcommerce | avgPrice | 1700 | true | -1 | -1 | -1 | 5 | NULL | NULL | NULL | 0 | b |
13-
| public | KibanaSampleDataEcommerce | countDistinct | 20 | true | -1 | 8 | -1 | 6 | NULL | NULL | NULL | 0 | b |
14-
| public | KibanaSampleDataEcommerce | order_date | 1114 | false | -1 | 8 | -1 | 7 | NULL | NULL | NULL | 0 | b |
15-
| public | KibanaSampleDataEcommerce | last_mod | 1114 | false | -1 | 8 | -1 | 8 | NULL | NULL | NULL | 0 | b |
16-
| public | KibanaSampleDataEcommerce | customer_gender | 25 | false | -1 | -1 | -1 | 9 | NULL | NULL | NULL | 0 | b |
17-
| public | KibanaSampleDataEcommerce | notes | 25 | false | -1 | -1 | -1 | 10 | NULL | NULL | NULL | 0 | b |
18-
| public | KibanaSampleDataEcommerce | taxful_total_price | 1700 | false | -1 | -1 | -1 | 11 | NULL | NULL | NULL | 0 | b |
19-
| public | KibanaSampleDataEcommerce | has_subscription | 16 | false | -1 | 1 | -1 | 12 | NULL | NULL | NULL | 0 | b |
20-
| public | KibanaSampleDataEcommerce | is_male | 16 | true | -1 | 1 | -1 | 13 | NULL | NULL | NULL | 0 | b |
21-
| public | KibanaSampleDataEcommerce | is_female | 16 | true | -1 | 1 | -1 | 14 | NULL | NULL | NULL | 0 | b |
22-
| public | KibanaSampleDataEcommerce | __user | 25 | false | -1 | -1 | -1 | 15 | NULL | NULL | NULL | 0 | b |
23-
| public | KibanaSampleDataEcommerce | __cubeJoinField | 25 | false | -1 | -1 | -1 | 16 | NULL | NULL | NULL | 0 | b |
24-
+---------+---------------------------+--------------------+----------+------------+-----------+--------+-----------+--------+-------------+-------+-------------+-------------+---------+
5+
+---------+---------------------------+--------------------+----------+------------+-----------+--------+-----------+--------+-------------+-------+-----------------------------------------------+-------------+---------+
6+
| nspname | relname | attname | atttypid | attnotnull | atttypmod | attlen | typtypmod | attnum | attidentity | adsrc | description | typbasetype | typtype |
7+
+---------+---------------------------+--------------------+----------+------------+-----------+--------+-----------+--------+-------------+-------+-----------------------------------------------+-------------+---------+
8+
| public | KibanaSampleDataEcommerce | count | 20 | true | -1 | 8 | -1 | 1 | NULL | NULL | Events count | 0 | b |
9+
| public | KibanaSampleDataEcommerce | maxPrice | 1700 | true | -1 | -1 | -1 | 2 | NULL | NULL | NULL | 0 | b |
10+
| public | KibanaSampleDataEcommerce | sumPrice | 1700 | true | -1 | -1 | -1 | 3 | NULL | NULL | NULL | 0 | b |
11+
| public | KibanaSampleDataEcommerce | minPrice | 1700 | true | -1 | -1 | -1 | 4 | NULL | NULL | NULL | 0 | b |
12+
| public | KibanaSampleDataEcommerce | avgPrice | 1700 | true | -1 | -1 | -1 | 5 | NULL | NULL | NULL | 0 | b |
13+
| public | KibanaSampleDataEcommerce | countDistinct | 20 | true | -1 | 8 | -1 | 6 | NULL | NULL | NULL | 0 | b |
14+
| public | KibanaSampleDataEcommerce | order_date | 1114 | false | -1 | 8 | -1 | 7 | NULL | NULL | NULL | 0 | b |
15+
| public | KibanaSampleDataEcommerce | last_mod | 1114 | false | -1 | 8 | -1 | 8 | NULL | NULL | NULL | 0 | b |
16+
| public | KibanaSampleDataEcommerce | customer_gender | 25 | false | -1 | -1 | -1 | 9 | NULL | NULL | Customer gender | 0 | b |
17+
| public | KibanaSampleDataEcommerce | notes | 25 | false | -1 | -1 | -1 | 10 | NULL | NULL | NULL | 0 | b |
18+
| public | KibanaSampleDataEcommerce | taxful_total_price | 1700 | false | -1 | -1 | -1 | 11 | NULL | NULL | NULL | 0 | b |
19+
| public | KibanaSampleDataEcommerce | has_subscription | 16 | false | -1 | 1 | -1 | 12 | NULL | NULL | NULL | 0 | b |
20+
| public | KibanaSampleDataEcommerce | is_male | 16 | true | -1 | 1 | -1 | 13 | NULL | NULL | Male users segment | 0 | b |
21+
| public | KibanaSampleDataEcommerce | is_female | 16 | true | -1 | 1 | -1 | 14 | NULL | NULL | NULL | 0 | b |
22+
| public | KibanaSampleDataEcommerce | __user | 25 | false | -1 | -1 | -1 | 15 | NULL | NULL | Virtual column for security context switching | 0 | b |
23+
| public | KibanaSampleDataEcommerce | __cubeJoinField | 25 | false | -1 | -1 | -1 | 16 | NULL | NULL | Virtual column for joining cubes | 0 | b |
24+
+---------+---------------------------+--------------------+----------+------------+-----------+--------+-----------+--------+-------------+-------+-----------------------------------------------+-------------+---------+

0 commit comments

Comments
 (0)