Skip to content

Commit 3b8043a

Browse files
rustyconoverclaude
andcommitted
catalog: surface view column comments via duckdb_columns()
ViewInfo gains a column_comments map decoded in ParseViewInfo and fed into CreateViewInfo.column_comments_map so DuckDB exposes per-column comments on VGI views, the way table column comments already work. VgiSchemaEntry::Scan(TABLE_ENTRY) now also scans the views set: DuckDB stores tables and views in a single CatalogSet, so duckdb_columns() (which scans TABLE_ENTRY) expects views there too. Without this, VGI views never appeared in duckdb_columns() at all. comments.test covers view column comments and view tags. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 4827725 commit 3b8043a

6 files changed

Lines changed: 68 additions & 1 deletion

File tree

src/generated/vgi_protocol_schemas.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// GENERATED by vgi.codegen.cpp_schemas. DO NOT EDIT BY HAND.
33
//
44
// Generator: vgi-gen-cpp-schemas v1
5-
// Content hash: e54a1f0bf14e
5+
// Content hash: 06a70f707a52
66
//
77
// To regenerate:
88
// uv run --project ~/Development/vgi-python vgi-gen-cpp-schemas \
@@ -81,6 +81,7 @@ inline const std::shared_ptr<arrow::Schema> &ViewInfoSchema() {
8181
arrow::field("name", arrow::utf8(), /*nullable=*/false),
8282
arrow::field("schema_name", arrow::utf8(), /*nullable=*/false),
8383
arrow::field("definition", arrow::utf8(), /*nullable=*/false),
84+
arrow::field("column_comments", arrow::map(arrow::utf8(), arrow::utf8()), /*nullable=*/false),
8485
});
8586
return schema;
8687
}

src/include/vgi_catalog_api.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@ struct VgiViewInfo {
467467
std::string definition; // SQL query defining the view
468468
std::string comment;
469469
std::map<std::string, std::string> tags;
470+
// Per-column comments keyed by the view's output column name. Fed into
471+
// CreateViewInfo.column_comments_map so they surface via duckdb_columns().
472+
std::map<std::string, std::string> column_comments;
470473
};
471474

472475
// Macro metadata from the worker

src/storage/vgi_schema_entry.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,14 @@ void VgiSchemaEntry::Scan(ClientContext &context, CatalogType type,
395395
const std::function<void(CatalogEntry &)> &callback) {
396396
switch (type) {
397397
case CatalogType::TABLE_ENTRY:
398+
// DuckDB stores tables and views in a single CatalogSet, so a TABLE_ENTRY
399+
// scan naturally surfaces both — duckdb_tables()/duckdb_constraints() then
400+
// skip non-table entries by type, while duckdb_columns() dispatches views
401+
// to its ViewColumnHelper (which binds the view to expose its columns and
402+
// column comments). VGI keeps views in a separate set, so we must include
403+
// them here too; otherwise VGI views never appear in duckdb_columns().
398404
tables_.Scan(context, callback);
405+
views_.Scan(context, callback);
399406
break;
400407
case CatalogType::VIEW_ENTRY:
401408
views_.Scan(context, callback);

src/storage/vgi_view_set.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ static unique_ptr<ViewCatalogEntry> CreateViewEntryFromInfo(Catalog &catalog, Sc
3131
for (auto &[key, val] : view_info.tags) {
3232
info.tags[key] = val;
3333
}
34+
// Per-column comments — DuckDB aligns these by name against the columns it
35+
// binds from the view's SQL and exposes them via duckdb_columns().
36+
for (auto &[col, comment] : view_info.column_comments) {
37+
info.column_comments_map[col] = Value(comment);
38+
}
3439
// Parse SQL to get SelectStatement
3540
try {
3641
Parser parser;

src/vgi_catalog_api.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,6 +1952,7 @@ VgiViewInfo ParseViewInfo(const std::shared_ptr<arrow::RecordBatch> &batch, cons
19521952
info.definition = row["definition"].value_not_null<std::string>();
19531953
info.comment = row["comment"].value_or("");
19541954
info.tags = row["tags"].value_not_null<std::map<std::string, std::string>>();
1955+
info.column_comments = row["column_comments"].value_not_null<std::map<std::string, std::string>>();
19551956

19561957
return info;
19571958
}

test/sql/integration/table/comments.test

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,56 @@ ORDER BY view_name;
6464
even_numbers Even numbers from 0 to 98
6565
first_ten First 10 integers
6666

67+
# ============================================================================
68+
# View tags (via duckdb_views)
69+
# ============================================================================
70+
71+
# first_ten declares view-level tags; even_numbers declares none (empty map).
72+
query TT
73+
SELECT view_name, tags
74+
FROM duckdb_views()
75+
WHERE database_name = 'example' AND schema_name = 'main'
76+
ORDER BY view_name;
77+
----
78+
even_numbers {}
79+
first_ten {layer=demo, origin=sequence}
80+
81+
# ============================================================================
82+
# View column comments (via duckdb_columns)
83+
# ============================================================================
84+
85+
# first_ten (main schema) carries a comment on its single output column `n`.
86+
query TT
87+
SELECT column_name, comment
88+
FROM duckdb_columns()
89+
WHERE database_name = 'example' AND schema_name = 'main'
90+
AND table_name = 'first_ten'
91+
ORDER BY column_name;
92+
----
93+
n Sequence index 0..9
94+
95+
# small_numbers (data schema) carries a comment on its `value` column —
96+
# exercises a view column comment outside the default schema, aligned by name.
97+
query TT
98+
SELECT column_name, comment
99+
FROM duckdb_columns()
100+
WHERE database_name = 'example' AND schema_name = 'data'
101+
AND table_name = 'small_numbers'
102+
ORDER BY column_name;
103+
----
104+
value Single-digit value 0..9
105+
106+
# even_numbers has a view-level comment but no column comments, so its column
107+
# `n` must report a NULL comment (commented view != commented columns).
108+
query TT
109+
SELECT column_name, comment
110+
FROM duckdb_columns()
111+
WHERE database_name = 'example' AND schema_name = 'main'
112+
AND table_name = 'even_numbers'
113+
ORDER BY column_name;
114+
----
115+
n NULL
116+
67117
# ============================================================================
68118
# Column comments on products table (via duckdb_columns)
69119
# ============================================================================

0 commit comments

Comments
 (0)