1 | #include "duckdb/function/table/system_functions.hpp" |
2 | |
3 | #include "duckdb/catalog/catalog.hpp" |
4 | #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" |
5 | #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" |
6 | #include "duckdb/catalog/catalog_entry/index_catalog_entry.hpp" |
7 | #include "duckdb/common/exception.hpp" |
8 | #include "duckdb/main/client_data.hpp" |
9 | #include "duckdb/storage/data_table.hpp" |
10 | #include "duckdb/storage/index.hpp" |
11 | |
12 | namespace duckdb { |
13 | |
14 | struct DuckDBIndexesData : public GlobalTableFunctionState { |
15 | DuckDBIndexesData() : offset(0) { |
16 | } |
17 | |
18 | vector<reference<CatalogEntry>> entries; |
19 | idx_t offset; |
20 | }; |
21 | |
22 | static unique_ptr<FunctionData> DuckDBIndexesBind(ClientContext &context, TableFunctionBindInput &input, |
23 | vector<LogicalType> &return_types, vector<string> &names) { |
24 | names.emplace_back(args: "database_name" ); |
25 | return_types.emplace_back(args: LogicalType::VARCHAR); |
26 | |
27 | names.emplace_back(args: "database_oid" ); |
28 | return_types.emplace_back(args: LogicalType::BIGINT); |
29 | |
30 | names.emplace_back(args: "schema_name" ); |
31 | return_types.emplace_back(args: LogicalType::VARCHAR); |
32 | |
33 | names.emplace_back(args: "schema_oid" ); |
34 | return_types.emplace_back(args: LogicalType::BIGINT); |
35 | |
36 | names.emplace_back(args: "index_name" ); |
37 | return_types.emplace_back(args: LogicalType::VARCHAR); |
38 | |
39 | names.emplace_back(args: "index_oid" ); |
40 | return_types.emplace_back(args: LogicalType::BIGINT); |
41 | |
42 | names.emplace_back(args: "table_name" ); |
43 | return_types.emplace_back(args: LogicalType::VARCHAR); |
44 | |
45 | names.emplace_back(args: "table_oid" ); |
46 | return_types.emplace_back(args: LogicalType::BIGINT); |
47 | |
48 | names.emplace_back(args: "is_unique" ); |
49 | return_types.emplace_back(args: LogicalType::BOOLEAN); |
50 | |
51 | names.emplace_back(args: "is_primary" ); |
52 | return_types.emplace_back(args: LogicalType::BOOLEAN); |
53 | |
54 | names.emplace_back(args: "expressions" ); |
55 | return_types.emplace_back(args: LogicalType::VARCHAR); |
56 | |
57 | names.emplace_back(args: "sql" ); |
58 | return_types.emplace_back(args: LogicalType::VARCHAR); |
59 | |
60 | return nullptr; |
61 | } |
62 | |
63 | unique_ptr<GlobalTableFunctionState> DuckDBIndexesInit(ClientContext &context, TableFunctionInitInput &input) { |
64 | auto result = make_uniq<DuckDBIndexesData>(); |
65 | |
66 | // scan all the schemas for tables and collect them and collect them |
67 | auto schemas = Catalog::GetAllSchemas(context); |
68 | for (auto &schema : schemas) { |
69 | schema.get().Scan(context, type: CatalogType::INDEX_ENTRY, |
70 | callback: [&](CatalogEntry &entry) { result->entries.push_back(x: entry); }); |
71 | }; |
72 | return std::move(result); |
73 | } |
74 | |
75 | void DuckDBIndexesFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { |
76 | auto &data = data_p.global_state->Cast<DuckDBIndexesData>(); |
77 | if (data.offset >= data.entries.size()) { |
78 | // finished returning values |
79 | return; |
80 | } |
81 | // start returning values |
82 | // either fill up the chunk or return all the remaining columns |
83 | idx_t count = 0; |
84 | while (data.offset < data.entries.size() && count < STANDARD_VECTOR_SIZE) { |
85 | auto &entry = data.entries[data.offset++].get(); |
86 | |
87 | auto &index = entry.Cast<IndexCatalogEntry>(); |
88 | // return values: |
89 | |
90 | idx_t col = 0; |
91 | // database_name, VARCHAR |
92 | output.SetValue(col_idx: col++, index: count, val: index.catalog.GetName()); |
93 | // database_oid, BIGINT |
94 | output.SetValue(col_idx: col++, index: count, val: Value::BIGINT(value: index.catalog.GetOid())); |
95 | // schema_name, VARCHAR |
96 | output.SetValue(col_idx: col++, index: count, val: Value(index.schema.name)); |
97 | // schema_oid, BIGINT |
98 | output.SetValue(col_idx: col++, index: count, val: Value::BIGINT(value: index.schema.oid)); |
99 | // index_name, VARCHAR |
100 | output.SetValue(col_idx: col++, index: count, val: Value(index.name)); |
101 | // index_oid, BIGINT |
102 | output.SetValue(col_idx: col++, index: count, val: Value::BIGINT(value: index.oid)); |
103 | // find the table in the catalog |
104 | auto &table_entry = |
105 | index.schema.catalog.GetEntry<TableCatalogEntry>(context, schema_name: index.GetSchemaName(), name: index.GetTableName()); |
106 | // table_name, VARCHAR |
107 | output.SetValue(col_idx: col++, index: count, val: Value(table_entry.name)); |
108 | // table_oid, BIGINT |
109 | output.SetValue(col_idx: col++, index: count, val: Value::BIGINT(value: table_entry.oid)); |
110 | if (index.index) { |
111 | // is_unique, BOOLEAN |
112 | output.SetValue(col_idx: col++, index: count, val: Value::BOOLEAN(value: index.index->IsUnique())); |
113 | // is_primary, BOOLEAN |
114 | output.SetValue(col_idx: col++, index: count, val: Value::BOOLEAN(value: index.index->IsPrimary())); |
115 | } else { |
116 | output.SetValue(col_idx: col++, index: count, val: Value()); |
117 | output.SetValue(col_idx: col++, index: count, val: Value()); |
118 | } |
119 | // expressions, VARCHAR |
120 | output.SetValue(col_idx: col++, index: count, val: Value()); |
121 | // sql, VARCHAR |
122 | auto sql = index.ToSQL(); |
123 | output.SetValue(col_idx: col++, index: count, val: sql.empty() ? Value() : Value(std::move(sql))); |
124 | |
125 | count++; |
126 | } |
127 | output.SetCardinality(count); |
128 | } |
129 | |
130 | void DuckDBIndexesFun::RegisterFunction(BuiltinFunctions &set) { |
131 | set.AddFunction(function: TableFunction("duckdb_indexes" , {}, DuckDBIndexesFunction, DuckDBIndexesBind, DuckDBIndexesInit)); |
132 | } |
133 | |
134 | } // namespace duckdb |
135 | |