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
12namespace duckdb {
13
14struct DuckDBIndexesData : public GlobalTableFunctionState {
15 DuckDBIndexesData() : offset(0) {
16 }
17
18 vector<reference<CatalogEntry>> entries;
19 idx_t offset;
20};
21
22static 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
63unique_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
75void 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
130void DuckDBIndexesFun::RegisterFunction(BuiltinFunctions &set) {
131 set.AddFunction(function: TableFunction("duckdb_indexes", {}, DuckDBIndexesFunction, DuckDBIndexesBind, DuckDBIndexesInit));
132}
133
134} // namespace duckdb
135