1#include "duckdb/function/table/system_functions.hpp"
2#include "duckdb/main/database_manager.hpp"
3#include "duckdb/main/attached_database.hpp"
4
5namespace duckdb {
6
7struct DuckDBDatabasesData : public GlobalTableFunctionState {
8 DuckDBDatabasesData() : offset(0) {
9 }
10
11 vector<reference<AttachedDatabase>> entries;
12 idx_t offset;
13};
14
15static unique_ptr<FunctionData> DuckDBDatabasesBind(ClientContext &context, TableFunctionBindInput &input,
16 vector<LogicalType> &return_types, vector<string> &names) {
17 names.emplace_back(args: "database_name");
18 return_types.emplace_back(args: LogicalType::VARCHAR);
19
20 names.emplace_back(args: "database_oid");
21 return_types.emplace_back(args: LogicalType::BIGINT);
22
23 names.emplace_back(args: "path");
24 return_types.emplace_back(args: LogicalType::VARCHAR);
25
26 names.emplace_back(args: "internal");
27 return_types.emplace_back(args: LogicalType::BOOLEAN);
28
29 names.emplace_back(args: "type");
30 return_types.emplace_back(args: LogicalType::VARCHAR);
31
32 return nullptr;
33}
34
35unique_ptr<GlobalTableFunctionState> DuckDBDatabasesInit(ClientContext &context, TableFunctionInitInput &input) {
36 auto result = make_uniq<DuckDBDatabasesData>();
37
38 // scan all the schemas for tables and collect them and collect them
39 auto &db_manager = DatabaseManager::Get(db&: context);
40 result->entries = db_manager.GetDatabases(context);
41 return std::move(result);
42}
43
44void DuckDBDatabasesFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
45 auto &data = data_p.global_state->Cast<DuckDBDatabasesData>();
46 if (data.offset >= data.entries.size()) {
47 // finished returning values
48 return;
49 }
50 // start returning values
51 // either fill up the chunk or return all the remaining columns
52 idx_t count = 0;
53 while (data.offset < data.entries.size() && count < STANDARD_VECTOR_SIZE) {
54 auto &entry = data.entries[data.offset++];
55
56 auto &attached = entry.get().Cast<AttachedDatabase>();
57 // return values:
58
59 idx_t col = 0;
60 // database_name, VARCHAR
61 output.SetValue(col_idx: col++, index: count, val: attached.GetName());
62 // database_oid, BIGINT
63 output.SetValue(col_idx: col++, index: count, val: Value::BIGINT(value: attached.oid));
64 // path, VARCHAR
65 bool is_internal = attached.IsSystem() || attached.IsTemporary();
66 Value db_path;
67 if (!is_internal) {
68 bool in_memory = attached.GetCatalog().InMemory();
69 if (!in_memory) {
70 db_path = Value(attached.GetCatalog().GetDBPath());
71 }
72 }
73 output.SetValue(col_idx: col++, index: count, val: db_path);
74 // internal, BOOLEAN
75 output.SetValue(col_idx: col++, index: count, val: Value::BOOLEAN(value: is_internal));
76 // type, VARCHAR
77 output.SetValue(col_idx: col++, index: count, val: Value(attached.GetCatalog().GetCatalogType()));
78
79 count++;
80 }
81 output.SetCardinality(count);
82}
83
84void DuckDBDatabasesFun::RegisterFunction(BuiltinFunctions &set) {
85 set.AddFunction(
86 function: TableFunction("duckdb_databases", {}, DuckDBDatabasesFunction, DuckDBDatabasesBind, DuckDBDatabasesInit));
87}
88
89} // namespace duckdb
90