1#include "duckdb/function/table/system_functions.hpp"
2
3#include "duckdb/catalog/catalog.hpp"
4#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
5#include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp"
6#include "duckdb/parser/qualified_name.hpp"
7#include "duckdb/planner/constraints/bound_not_null_constraint.hpp"
8#include "duckdb/planner/constraints/bound_unique_constraint.hpp"
9
10#include "duckdb/common/exception.hpp"
11#include "duckdb/common/limits.hpp"
12#include "duckdb/storage/data_table.hpp"
13#include "duckdb/storage/table_storage_info.hpp"
14#include "duckdb/planner/binder.hpp"
15
16#include <algorithm>
17
18namespace duckdb {
19
20struct PragmaStorageFunctionData : public TableFunctionData {
21 explicit PragmaStorageFunctionData(TableCatalogEntry &table_entry) : table_entry(table_entry) {
22 }
23
24 TableCatalogEntry &table_entry;
25 vector<ColumnSegmentInfo> column_segments_info;
26};
27
28struct PragmaStorageOperatorData : public GlobalTableFunctionState {
29 PragmaStorageOperatorData() : offset(0) {
30 }
31
32 idx_t offset;
33};
34
35static unique_ptr<FunctionData> PragmaStorageInfoBind(ClientContext &context, TableFunctionBindInput &input,
36 vector<LogicalType> &return_types, vector<string> &names) {
37 names.emplace_back(args: "row_group_id");
38 return_types.emplace_back(args: LogicalType::BIGINT);
39
40 names.emplace_back(args: "column_name");
41 return_types.emplace_back(args: LogicalType::VARCHAR);
42
43 names.emplace_back(args: "column_id");
44 return_types.emplace_back(args: LogicalType::BIGINT);
45
46 names.emplace_back(args: "column_path");
47 return_types.emplace_back(args: LogicalType::VARCHAR);
48
49 names.emplace_back(args: "segment_id");
50 return_types.emplace_back(args: LogicalType::BIGINT);
51
52 names.emplace_back(args: "segment_type");
53 return_types.emplace_back(args: LogicalType::VARCHAR);
54
55 names.emplace_back(args: "start");
56 return_types.emplace_back(args: LogicalType::BIGINT);
57
58 names.emplace_back(args: "count");
59 return_types.emplace_back(args: LogicalType::BIGINT);
60
61 names.emplace_back(args: "compression");
62 return_types.emplace_back(args: LogicalType::VARCHAR);
63
64 names.emplace_back(args: "stats");
65 return_types.emplace_back(args: LogicalType::VARCHAR);
66
67 names.emplace_back(args: "has_updates");
68 return_types.emplace_back(args: LogicalType::BOOLEAN);
69
70 names.emplace_back(args: "persistent");
71 return_types.emplace_back(args: LogicalType::BOOLEAN);
72
73 names.emplace_back(args: "block_id");
74 return_types.emplace_back(args: LogicalType::BIGINT);
75
76 names.emplace_back(args: "block_offset");
77 return_types.emplace_back(args: LogicalType::BIGINT);
78
79 auto qname = QualifiedName::Parse(input: input.inputs[0].GetValue<string>());
80
81 // look up the table name in the catalog
82 Binder::BindSchemaOrCatalog(context, catalog&: qname.catalog, schema&: qname.schema);
83 auto &table_entry = Catalog::GetEntry<TableCatalogEntry>(context, catalog_name: qname.catalog, schema_name: qname.schema, name: qname.name);
84 auto result = make_uniq<PragmaStorageFunctionData>(args&: table_entry);
85 result->column_segments_info = table_entry.GetColumnSegmentInfo();
86 return std::move(result);
87}
88
89unique_ptr<GlobalTableFunctionState> PragmaStorageInfoInit(ClientContext &context, TableFunctionInitInput &input) {
90 return make_uniq<PragmaStorageOperatorData>();
91}
92
93static void PragmaStorageInfoFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
94 auto &bind_data = data_p.bind_data->Cast<PragmaStorageFunctionData>();
95 auto &data = data_p.global_state->Cast<PragmaStorageOperatorData>();
96 idx_t count = 0;
97 auto &columns = bind_data.table_entry.GetColumns();
98 while (data.offset < bind_data.column_segments_info.size() && count < STANDARD_VECTOR_SIZE) {
99 auto &entry = bind_data.column_segments_info[data.offset++];
100
101 idx_t col_idx = 0;
102 // row_group_id
103 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.row_group_index));
104 // column_name
105 auto &col = columns.GetColumn(index: PhysicalIndex(entry.column_id));
106 output.SetValue(col_idx: col_idx++, index: count, val: Value(col.Name()));
107 // column_id
108 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.column_id));
109 // column_path
110 output.SetValue(col_idx: col_idx++, index: count, val: Value(entry.column_path));
111 // segment_id
112 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.segment_idx));
113 // segment_type
114 output.SetValue(col_idx: col_idx++, index: count, val: Value(entry.segment_type));
115 // start
116 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.segment_start));
117 // count
118 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.segment_count));
119 // compression
120 output.SetValue(col_idx: col_idx++, index: count, val: Value(entry.compression_type));
121 // stats
122 output.SetValue(col_idx: col_idx++, index: count, val: Value(entry.segment_stats));
123 // has_updates
124 output.SetValue(col_idx: col_idx++, index: count, val: Value::BOOLEAN(value: entry.has_updates));
125 // persistent
126 output.SetValue(col_idx: col_idx++, index: count, val: Value::BOOLEAN(value: entry.persistent));
127 // block_id
128 // block_offset
129 if (entry.persistent) {
130 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.block_id));
131 output.SetValue(col_idx: col_idx++, index: count, val: Value::BIGINT(value: entry.block_offset));
132 } else {
133 output.SetValue(col_idx: col_idx++, index: count, val: Value());
134 output.SetValue(col_idx: col_idx++, index: count, val: Value());
135 }
136 count++;
137 }
138 output.SetCardinality(count);
139}
140
141void PragmaStorageInfo::RegisterFunction(BuiltinFunctions &set) {
142 set.AddFunction(function: TableFunction("pragma_storage_info", {LogicalType::VARCHAR}, PragmaStorageInfoFunction,
143 PragmaStorageInfoBind, PragmaStorageInfoInit));
144}
145
146} // namespace duckdb
147