1#include "duckdb/function/table/system_functions.hpp"
2
3#include "duckdb/catalog/catalog.hpp"
4#include "duckdb/catalog/duck_catalog.hpp"
5#include "duckdb/catalog/dependency_manager.hpp"
6#include "duckdb/common/exception.hpp"
7#include "duckdb/main/client_context.hpp"
8
9namespace duckdb {
10
11struct DependencyInformation {
12 DependencyInformation(CatalogEntry &object, CatalogEntry &dependent, DependencyType type)
13 : object(object), dependent(dependent), type(type) {
14 }
15
16 CatalogEntry &object;
17 CatalogEntry &dependent;
18 DependencyType type;
19};
20
21struct DuckDBDependenciesData : public GlobalTableFunctionState {
22 DuckDBDependenciesData() : offset(0) {
23 }
24
25 vector<DependencyInformation> entries;
26 idx_t offset;
27};
28
29static unique_ptr<FunctionData> DuckDBDependenciesBind(ClientContext &context, TableFunctionBindInput &input,
30 vector<LogicalType> &return_types, vector<string> &names) {
31 names.emplace_back(args: "classid");
32 return_types.emplace_back(args: LogicalType::BIGINT);
33
34 names.emplace_back(args: "objid");
35 return_types.emplace_back(args: LogicalType::BIGINT);
36
37 names.emplace_back(args: "objsubid");
38 return_types.emplace_back(args: LogicalType::INTEGER);
39
40 names.emplace_back(args: "refclassid");
41 return_types.emplace_back(args: LogicalType::BIGINT);
42
43 names.emplace_back(args: "refobjid");
44 return_types.emplace_back(args: LogicalType::BIGINT);
45
46 names.emplace_back(args: "refobjsubid");
47 return_types.emplace_back(args: LogicalType::INTEGER);
48
49 names.emplace_back(args: "deptype");
50 return_types.emplace_back(args: LogicalType::VARCHAR);
51
52 return nullptr;
53}
54
55unique_ptr<GlobalTableFunctionState> DuckDBDependenciesInit(ClientContext &context, TableFunctionInitInput &input) {
56 auto result = make_uniq<DuckDBDependenciesData>();
57
58 // scan all the schemas and collect them
59 auto &catalog = Catalog::GetCatalog(context, INVALID_CATALOG);
60 if (catalog.IsDuckCatalog()) {
61 auto &duck_catalog = catalog.Cast<DuckCatalog>();
62 auto &dependency_manager = duck_catalog.GetDependencyManager();
63 dependency_manager.Scan(callback: [&](CatalogEntry &obj, CatalogEntry &dependent, DependencyType type) {
64 result->entries.emplace_back(args&: obj, args&: dependent, args&: type);
65 });
66 }
67
68 return std::move(result);
69}
70
71void DuckDBDependenciesFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
72 auto &data = data_p.global_state->Cast<DuckDBDependenciesData>();
73 if (data.offset >= data.entries.size()) {
74 // finished returning values
75 return;
76 }
77 // start returning values
78 // either fill up the chunk or return all the remaining columns
79 idx_t count = 0;
80 while (data.offset < data.entries.size() && count < STANDARD_VECTOR_SIZE) {
81 auto &entry = data.entries[data.offset];
82
83 // return values:
84 // classid, LogicalType::BIGINT
85 output.SetValue(col_idx: 0, index: count, val: Value::BIGINT(value: 0));
86 // objid, LogicalType::BIGINT
87 output.SetValue(col_idx: 1, index: count, val: Value::BIGINT(value: entry.object.oid));
88 // objsubid, LogicalType::INTEGER
89 output.SetValue(col_idx: 2, index: count, val: Value::INTEGER(value: 0));
90 // refclassid, LogicalType::BIGINT
91 output.SetValue(col_idx: 3, index: count, val: Value::BIGINT(value: 0));
92 // refobjid, LogicalType::BIGINT
93 output.SetValue(col_idx: 4, index: count, val: Value::BIGINT(value: entry.dependent.oid));
94 // refobjsubid, LogicalType::INTEGER
95 output.SetValue(col_idx: 5, index: count, val: Value::INTEGER(value: 0));
96 // deptype, LogicalType::VARCHAR
97 string dependency_type_str;
98 switch (entry.type) {
99 case DependencyType::DEPENDENCY_REGULAR:
100 dependency_type_str = "n";
101 break;
102 case DependencyType::DEPENDENCY_AUTOMATIC:
103 dependency_type_str = "a";
104 break;
105 default:
106 throw NotImplementedException("Unimplemented dependency type");
107 }
108 output.SetValue(col_idx: 6, index: count, val: Value(dependency_type_str));
109
110 data.offset++;
111 count++;
112 }
113 output.SetCardinality(count);
114}
115
116void DuckDBDependenciesFun::RegisterFunction(BuiltinFunctions &set) {
117 set.AddFunction(function: TableFunction("duckdb_dependencies", {}, DuckDBDependenciesFunction, DuckDBDependenciesBind,
118 DuckDBDependenciesInit));
119}
120
121} // namespace duckdb
122