/src/duckdb/src/main/extension/extension_loader.cpp
Line | Count | Source |
1 | | #include "duckdb/main/extension/extension_loader.hpp" |
2 | | |
3 | | #include "duckdb/function/scalar_function.hpp" |
4 | | #include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" |
5 | | #include "duckdb/parser/parsed_data/create_schema_info.hpp" |
6 | | #include "duckdb/parser/parsed_data/create_type_info.hpp" |
7 | | #include "duckdb/parser/parsed_data/create_copy_function_info.hpp" |
8 | | #include "duckdb/parser/parsed_data/create_pragma_function_info.hpp" |
9 | | #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" |
10 | | #include "duckdb/parser/parsed_data/create_table_function_info.hpp" |
11 | | #include "duckdb/parser/parsed_data/create_window_function_info.hpp" |
12 | | #include "duckdb/parser/parsed_data/create_macro_info.hpp" |
13 | | #include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" |
14 | | #include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp" |
15 | | #include "duckdb/parser/parsed_data/create_collation_info.hpp" |
16 | | #include "duckdb/main/extension_install_info.hpp" |
17 | | #include "duckdb/catalog/catalog.hpp" |
18 | | #include "duckdb/main/client_data.hpp" |
19 | | #include "duckdb/main/config.hpp" |
20 | | #include "duckdb/main/secret/secret_manager.hpp" |
21 | | #include "duckdb/main/database.hpp" |
22 | | #include "duckdb/main/profiler/metrics_manager.hpp" |
23 | | |
24 | | #include "duckdb/main/extension_callback_manager.hpp" |
25 | | #include "re2/re2.h" |
26 | | |
27 | | namespace duckdb { |
28 | | |
29 | | ExtensionLoader::ExtensionLoader(const ExtensionActiveLoad &load_info) |
30 | 19.7k | : db(load_info.db), extension_info(load_info.info) { |
31 | 19.7k | loader_info.extension_name = load_info.extension_name; |
32 | 19.7k | loader_info.extension_alias = load_info.alias; |
33 | 19.7k | } |
34 | | |
35 | 0 | ExtensionLoader::ExtensionLoader(DatabaseInstance &db, const string &name) : db(db) { |
36 | 0 | loader_info.extension_name = Identifier(name); |
37 | 0 | } |
38 | | |
39 | 539k | DatabaseInstance &ExtensionLoader::GetDatabaseInstance() const { |
40 | 539k | return db; |
41 | 539k | } |
42 | | |
43 | 0 | void ExtensionLoader::SetDescription(const string &description) { |
44 | 0 | loader_info.extension_description = description; |
45 | 0 | } |
46 | | |
47 | 0 | void ExtensionLoader::UseDedicatedSchemaForExtension(const Identifier &extension_schema_name) { |
48 | 0 | CreateSchema(extension_schema_name); |
49 | 0 | UseDefaultSchema(extension_schema_name); |
50 | 0 | AddSchemaToSearchPath(extension_schema_name); |
51 | 0 | } |
52 | | |
53 | 0 | void ExtensionLoader::UseDedicatedSchemaForExtension() { |
54 | 0 | auto registered_ext_name = GetRegisteredExtensionName(); |
55 | 0 | UseDedicatedSchemaForExtension(registered_ext_name); |
56 | 0 | } |
57 | | |
58 | 0 | void ExtensionLoader::CreateSchema(const Identifier &name) const { |
59 | 0 | auto &system_catalog = Catalog::GetSystemCatalog(db); |
60 | 0 | auto data = CatalogTransaction::GetSystemTransaction(db); |
61 | |
|
62 | 0 | CreateSchemaInfo info; |
63 | 0 | info.SetQualifiedName(QualifiedName(info.GetQualifiedName().Catalog(), name, info.GetQualifiedName().Name())); |
64 | 0 | info.internal = true; |
65 | | // TODO; we can give the user more control here |
66 | 0 | info.on_conflict = OnCreateConflict::ERROR_ON_CONFLICT; |
67 | 0 | system_catalog.CreateSchema(data, info); |
68 | 0 | } |
69 | | |
70 | 0 | void ExtensionLoader::UseDefaultSchema(const Identifier &name) { |
71 | 0 | if (loader_info.extension_schema != DEFAULT_SCHEMA && name != DEFAULT_SCHEMA && |
72 | 0 | loader_info.extension_schema != name) { |
73 | 0 | throw InvalidInputException("Cannot set extension schema to '%s', schema is already set to '%s'", name, |
74 | 0 | loader_info.extension_schema); |
75 | 0 | } |
76 | 0 | if (name == "pg_catalog") { |
77 | 0 | throw InvalidInputException("Cannot set default extension schema to '%s'", name); |
78 | 0 | } |
79 | 0 | if (name == DEFAULT_SCHEMA) { |
80 | 0 | loader_info.extension_schema = Identifier::DefaultSchema(); |
81 | 0 | return; |
82 | 0 | } |
83 | 0 | loader_info.extension_schema = name; |
84 | 0 | } |
85 | | |
86 | 0 | void ExtensionLoader::AddSchemaToSearchPath(const Identifier &schema_name) const { |
87 | | // adds an explicitly set extension schema to the search path |
88 | 0 | if (loader_info.extension_schema != schema_name || schema_name == DEFAULT_SCHEMA || |
89 | 0 | loader_info.extension_schema == DEFAULT_SCHEMA) { |
90 | 0 | throw InvalidInputException("Cannot add schema '%s' to search path, first set the extension schema explicitly " |
91 | 0 | "with UseDefaultSchema()", |
92 | 0 | schema_name); |
93 | 0 | } |
94 | | |
95 | | // check if schema already exists in the system catalog |
96 | 0 | auto &system_catalog = Catalog::GetSystemCatalog(db); |
97 | 0 | auto data = CatalogTransaction::GetSystemTransaction(db); |
98 | 0 | auto schema = system_catalog.GetSchema(data, schema_name, OnEntryNotFound::RETURN_NULL); |
99 | 0 | if (!schema) { |
100 | 0 | throw InvalidInputException("Cannot add schema '%s' to search path: schema does not exist. " |
101 | 0 | "Call CreateExtensionSchema() first.", |
102 | 0 | schema_name); |
103 | 0 | } |
104 | | |
105 | | // TODO: remove extension schema from search path if loading extension failed |
106 | 0 | ExtensionCallbackManager::Get(db).AddExtensionSchema(loader_info.extension_schema); |
107 | 0 | } |
108 | | |
109 | 0 | void ExtensionLoader::RefreshSearchPath(ClientContext &context) { |
110 | 0 | ClientData::Get(context).catalog_search_path->RefreshSetPaths(); |
111 | 0 | } |
112 | | |
113 | 19.7k | void ExtensionLoader::FinalizeLoad() { |
114 | | // Set extension description, if provided |
115 | 19.7k | if (!loader_info.extension_description.empty() && extension_info) { |
116 | 0 | auto info = make_uniq<ExtensionLoadedInfo>(); |
117 | 0 | info->description = loader_info.extension_description; |
118 | 0 | extension_info->load_info = std::move(info); |
119 | 0 | } |
120 | 19.7k | } |
121 | | |
122 | 13.1k | void ExtensionLoader::RegisterFunction(ScalarFunction function) { |
123 | 13.1k | ScalarFunctionSet set {function.name}; |
124 | 13.1k | set.AddFunction(std::move(function)); |
125 | 13.1k | RegisterFunction(std::move(set)); |
126 | 13.1k | } |
127 | | |
128 | 230k | void ExtensionLoader::RegisterFunction(ScalarFunctionSet function) { |
129 | 230k | CreateScalarFunctionInfo info(std::move(function)); |
130 | 230k | info.SetQualifiedName( |
131 | 230k | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
132 | 230k | info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; |
133 | 230k | RegisterFunction(std::move(info)); |
134 | 230k | } |
135 | | |
136 | 2.21M | void ExtensionLoader::RegisterFunction(CreateScalarFunctionInfo function) { |
137 | 2.21M | D_ASSERT(!function.functions.name.empty()); |
138 | 2.21M | function.extension_name = GetRegisteredExtensionName(); |
139 | 2.21M | if (function.GetQualifiedName().Schema() == DEFAULT_SCHEMA) { |
140 | 2.21M | function.SetQualifiedName(QualifiedName(function.GetQualifiedName().Catalog(), loader_info.extension_schema, |
141 | 2.21M | function.GetQualifiedName().Name())); |
142 | 2.21M | } |
143 | 2.21M | auto &system_catalog = Catalog::GetSystemCatalog(db); |
144 | 2.21M | auto data = CatalogTransaction::GetSystemTransaction(db); |
145 | 2.21M | system_catalog.CreateFunction(data, function); |
146 | 2.21M | } |
147 | | |
148 | 0 | void ExtensionLoader::RegisterFunction(AggregateFunction function) { |
149 | 0 | AggregateFunctionSet set {function.name}; |
150 | 0 | set.AddFunction(std::move(function)); |
151 | 0 | RegisterFunction(std::move(set)); |
152 | 0 | } |
153 | | |
154 | 0 | void ExtensionLoader::RegisterFunction(AggregateFunctionSet function) { |
155 | 0 | CreateAggregateFunctionInfo info(std::move(function)); |
156 | 0 | info.SetQualifiedName( |
157 | 0 | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
158 | 0 | info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; |
159 | 0 | RegisterFunction(std::move(info)); |
160 | 0 | } |
161 | | |
162 | 441k | void ExtensionLoader::RegisterFunction(CreateAggregateFunctionInfo function) { |
163 | 441k | D_ASSERT(!function.functions.name.empty()); |
164 | 441k | if (function.GetQualifiedName().Schema() == DEFAULT_SCHEMA) { |
165 | 441k | function.SetQualifiedName(QualifiedName(function.GetQualifiedName().Catalog(), loader_info.extension_schema, |
166 | 441k | function.GetQualifiedName().Name())); |
167 | 441k | } |
168 | 441k | function.extension_name = GetRegisteredExtensionName(); |
169 | 441k | auto &system_catalog = Catalog::GetSystemCatalog(db); |
170 | 441k | auto data = CatalogTransaction::GetSystemTransaction(db); |
171 | 441k | system_catalog.CreateFunction(data, function); |
172 | 441k | } |
173 | | |
174 | 0 | void ExtensionLoader::RegisterFunction(WindowFunction function) { |
175 | 0 | WindowFunctionSet set {function.name}; |
176 | 0 | set.AddFunction(std::move(function)); |
177 | 0 | RegisterFunction(std::move(set)); |
178 | 0 | } |
179 | | |
180 | 0 | void ExtensionLoader::RegisterFunction(WindowFunctionSet function) { |
181 | 0 | CreateWindowFunctionInfo info(std::move(function)); |
182 | 0 | info.SetQualifiedName( |
183 | 0 | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
184 | 0 | info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; |
185 | 0 | RegisterFunction(std::move(info)); |
186 | 0 | } |
187 | | |
188 | 0 | void ExtensionLoader::RegisterFunction(CreateWindowFunctionInfo function) { |
189 | 0 | D_ASSERT(!function.functions.name.empty()); |
190 | 0 | if (function.GetQualifiedName().Schema() == DEFAULT_SCHEMA) { |
191 | 0 | function.SetQualifiedName(QualifiedName(function.GetQualifiedName().Catalog(), loader_info.extension_schema, |
192 | 0 | function.GetQualifiedName().Name())); |
193 | 0 | } |
194 | 0 | function.extension_name = GetRegisteredExtensionName(); |
195 | 0 | auto &system_catalog = Catalog::GetSystemCatalog(db); |
196 | 0 | auto data = CatalogTransaction::GetSystemTransaction(db); |
197 | 0 | system_catalog.CreateFunction(data, function); |
198 | 0 | } |
199 | | |
200 | 0 | void ExtensionLoader::RegisterFunction(CreateSecretFunction function) { |
201 | 0 | D_ASSERT(!function.secret_type.empty()); |
202 | 0 | auto &config = DBConfig::GetConfig(db); |
203 | 0 | config.secret_manager->RegisterSecretFunction(std::move(function), OnCreateConflict::ERROR_ON_CONFLICT); |
204 | 0 | } |
205 | | |
206 | 0 | void ExtensionLoader::RegisterFunction(TableFunction function) { |
207 | 0 | TableFunctionSet set {function.name}; |
208 | 0 | set.AddFunction(std::move(function)); |
209 | 0 | RegisterFunction(std::move(set)); |
210 | 0 | } |
211 | | |
212 | 118k | void ExtensionLoader::RegisterFunction(TableFunctionSet function) { |
213 | 118k | D_ASSERT(!function.name.empty()); |
214 | 118k | CreateTableFunctionInfo info(std::move(function)); |
215 | 118k | info.SetQualifiedName( |
216 | 118k | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
217 | 118k | info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; |
218 | 118k | RegisterFunction(std::move(info)); |
219 | 118k | } |
220 | | |
221 | 118k | void ExtensionLoader::RegisterFunction(CreateTableFunctionInfo info) { |
222 | 118k | D_ASSERT(!info.functions.name.empty()); |
223 | 118k | info.extension_name = GetRegisteredExtensionName(); |
224 | 118k | if (info.GetQualifiedName().Schema() == DEFAULT_SCHEMA) { |
225 | 118k | info.SetQualifiedName(QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, |
226 | 118k | info.GetQualifiedName().Name())); |
227 | 118k | } |
228 | 118k | auto &system_catalog = Catalog::GetSystemCatalog(db); |
229 | 118k | auto data = CatalogTransaction::GetSystemTransaction(db); |
230 | 118k | system_catalog.CreateFunction(data, info); |
231 | 118k | } |
232 | | |
233 | 6.58k | void ExtensionLoader::RegisterFunction(PragmaFunction function) { |
234 | 6.58k | D_ASSERT(!function.name.empty()); |
235 | 6.58k | PragmaFunctionSet set {function.name}; |
236 | 6.58k | set.AddFunction(std::move(function)); |
237 | 6.58k | RegisterFunction(std::move(set)); |
238 | 6.58k | } |
239 | | |
240 | 13.1k | void ExtensionLoader::RegisterFunction(PragmaFunctionSet function) { |
241 | 13.1k | D_ASSERT(!function.name.empty()); |
242 | 13.1k | CreatePragmaFunctionInfo info(std::move(function)); |
243 | 13.1k | info.extension_name = GetRegisteredExtensionName(); |
244 | 13.1k | info.SetQualifiedName( |
245 | 13.1k | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
246 | 13.1k | auto &system_catalog = Catalog::GetSystemCatalog(db); |
247 | 13.1k | auto data = CatalogTransaction::GetSystemTransaction(db); |
248 | 13.1k | system_catalog.CreatePragmaFunction(data, info); |
249 | 13.1k | } |
250 | | |
251 | 26.3k | void ExtensionLoader::RegisterFunction(CopyFunction function) { |
252 | 26.3k | CreateCopyFunctionInfo info(std::move(function)); |
253 | 26.3k | info.extension_name = GetRegisteredExtensionName(); |
254 | 26.3k | info.SetQualifiedName( |
255 | 26.3k | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
256 | 26.3k | auto &system_catalog = Catalog::GetSystemCatalog(db); |
257 | 26.3k | auto data = CatalogTransaction::GetSystemTransaction(db); |
258 | 26.3k | system_catalog.CreateCopyFunction(data, info); |
259 | 26.3k | } |
260 | | |
261 | 39.4k | void ExtensionLoader::RegisterFunction(CreateMacroInfo &info) { |
262 | 39.4k | info.extension_name = GetRegisteredExtensionName(); |
263 | 39.4k | if (info.GetQualifiedName().Schema() == DEFAULT_SCHEMA) { |
264 | 39.4k | info.SetQualifiedName(QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, |
265 | 39.4k | info.GetQualifiedName().Name())); |
266 | 39.4k | } |
267 | 39.4k | auto &system_catalog = Catalog::GetSystemCatalog(db); |
268 | 39.4k | auto data = CatalogTransaction::GetSystemTransaction(db); |
269 | 39.4k | system_catalog.CreateFunction(data, info); |
270 | 39.4k | } |
271 | | |
272 | 0 | void ExtensionLoader::RegisterCollation(CreateCollationInfo &info) { |
273 | 0 | info.extension_name = GetRegisteredExtensionName(); |
274 | 0 | auto &system_catalog = Catalog::GetSystemCatalog(db); |
275 | 0 | auto data = CatalogTransaction::GetSystemTransaction(db); |
276 | 0 | if (info.GetQualifiedName().Schema() == DEFAULT_SCHEMA) { |
277 | 0 | info.SetQualifiedName(QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, |
278 | 0 | info.GetQualifiedName().Name())); |
279 | 0 | } |
280 | 0 | info.on_conflict = OnCreateConflict::IGNORE_ON_CONFLICT; |
281 | 0 | system_catalog.CreateCollation(data, info); |
282 | | |
283 | | // Also register as a function for serialisation |
284 | 0 | CreateScalarFunctionInfo finfo(info.function); |
285 | 0 | finfo.extension_name = GetRegisteredExtensionName(); |
286 | 0 | finfo.SetQualifiedName(QualifiedName(finfo.GetQualifiedName().Catalog(), loader_info.extension_schema, |
287 | 0 | finfo.GetQualifiedName().Name())); |
288 | 0 | finfo.on_conflict = OnCreateConflict::IGNORE_ON_CONFLICT; |
289 | 0 | system_catalog.CreateFunction(data, finfo); |
290 | 0 | } |
291 | | |
292 | 0 | void ExtensionLoader::RegisterCoordinateSystem(CreateCoordinateSystemInfo &info) { |
293 | 0 | auto &system_catalog = Catalog::GetSystemCatalog(db); |
294 | 0 | auto data = CatalogTransaction::GetSystemTransaction(db); |
295 | 0 | system_catalog.CreateCoordinateSystem(data, info); |
296 | 0 | } |
297 | | |
298 | 0 | void ExtensionLoader::AddFunctionOverload(ScalarFunction function) { |
299 | 0 | auto &scalar_function = GetFunction(function.name); |
300 | 0 | scalar_function.functions.AddFunction(std::move(function)); |
301 | 0 | } |
302 | | |
303 | 0 | void ExtensionLoader::AddFunctionOverload(ScalarFunctionSet functions) { // NOLINT |
304 | 0 | D_ASSERT(!functions.name.empty()); |
305 | 0 | auto &scalar_function = GetFunction(functions.name); |
306 | 0 | for (auto &function : functions.functions) { |
307 | 0 | function.name = functions.name; |
308 | 0 | scalar_function.functions.AddFunction(std::move(function)); |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | 0 | void ExtensionLoader::AddFunctionOverload(TableFunctionSet functions) { // NOLINT |
313 | 0 | auto &table_function = GetTableFunction(functions.name); |
314 | 0 | for (auto &function : functions.functions) { |
315 | 0 | function.name = functions.name; |
316 | 0 | table_function.functions.AddFunction(std::move(function)); |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | 0 | static optional_ptr<CatalogEntry> TryGetEntry(DatabaseInstance &db, const Identifier &name, CatalogType type) { |
321 | 0 | D_ASSERT(!name.empty()); |
322 | 0 | auto &system_catalog = Catalog::GetSystemCatalog(db); |
323 | 0 | auto data = CatalogTransaction::GetSystemTransaction(db); |
324 | 0 | auto &schema = system_catalog.GetSchema(data, Identifier::DefaultSchema()); |
325 | 0 | return schema.GetEntry(data, type, name); |
326 | 0 | } |
327 | | |
328 | 0 | optional_ptr<CatalogEntry> ExtensionLoader::TryGetFunction(const Identifier &name) { |
329 | 0 | return TryGetEntry(db, name, CatalogType::SCALAR_FUNCTION_ENTRY); |
330 | 0 | } |
331 | | |
332 | 0 | ScalarFunctionCatalogEntry &ExtensionLoader::GetFunction(const Identifier &name) { |
333 | 0 | auto catalog_entry = TryGetFunction(name); |
334 | 0 | if (!catalog_entry) { |
335 | 0 | throw InvalidInputException("Function with name \"%s\" not found in ExtensionLoader::GetFunction", name); |
336 | 0 | } |
337 | 0 | return catalog_entry->Cast<ScalarFunctionCatalogEntry>(); |
338 | 0 | } |
339 | | |
340 | 0 | optional_ptr<CatalogEntry> ExtensionLoader::TryGetTableFunction(const Identifier &name) { |
341 | 0 | return TryGetEntry(db, name, CatalogType::TABLE_FUNCTION_ENTRY); |
342 | 0 | } |
343 | | |
344 | 0 | TableFunctionCatalogEntry &ExtensionLoader::GetTableFunction(const Identifier &name) { |
345 | 0 | auto catalog_entry = TryGetTableFunction(name); |
346 | 0 | if (!catalog_entry) { |
347 | 0 | throw InvalidInputException("Function with name \"%s\" not found in ExtensionLoader::GetTableFunction", name); |
348 | 0 | } |
349 | 0 | return catalog_entry->Cast<TableFunctionCatalogEntry>(); |
350 | 0 | } |
351 | | |
352 | 6.58k | void ExtensionLoader::RegisterType(string type_name, LogicalType type, bind_logical_type_function_t bind_modifiers) { |
353 | 6.58k | D_ASSERT(!type_name.empty()); |
354 | 6.58k | CreateTypeInfo info(std::move(type_name), std::move(type), bind_modifiers); |
355 | 6.58k | info.temporary = true; |
356 | 6.58k | info.internal = true; |
357 | 6.58k | info.extension_name = GetRegisteredExtensionName(); |
358 | 6.58k | info.SetQualifiedName( |
359 | 6.58k | QualifiedName(info.GetQualifiedName().Catalog(), loader_info.extension_schema, info.GetQualifiedName().Name())); |
360 | 6.58k | auto &system_catalog = Catalog::GetSystemCatalog(db); |
361 | 6.58k | auto data = CatalogTransaction::GetSystemTransaction(db); |
362 | 6.58k | system_catalog.CreateType(data, info); |
363 | 6.58k | } |
364 | | |
365 | 0 | void ExtensionLoader::RegisterSecretType(SecretType secret_type) { |
366 | 0 | auto &config = DBConfig::GetConfig(db); |
367 | 0 | config.secret_manager->RegisterSecretType(secret_type); |
368 | 0 | } |
369 | | |
370 | | void ExtensionLoader::RegisterCastFunction(const LogicalType &source, const LogicalType &target, |
371 | 513k | bind_cast_function_t bind_function, int64_t implicit_cast_cost) { |
372 | 513k | auto &config = DBConfig::GetConfig(db); |
373 | 513k | auto &casts = config.GetCastFunctions(); |
374 | 513k | casts.RegisterCastFunction(source, target, bind_function, implicit_cast_cost); |
375 | 513k | } |
376 | | |
377 | | void ExtensionLoader::RegisterCastFunction(const LogicalType &source, const LogicalType &target, BoundCastInfo function, |
378 | 39.4k | int64_t implicit_cast_cost) { |
379 | 39.4k | auto &config = DBConfig::GetConfig(db); |
380 | 39.4k | auto &casts = config.GetCastFunctions(); |
381 | 39.4k | casts.RegisterCastFunction(source, target, std::move(function), implicit_cast_cost); |
382 | 39.4k | } |
383 | | |
384 | 0 | void ExtensionLoader::RegisterCombineTypesRule(CombineTypesRule rule) { |
385 | 0 | DBConfig::GetConfig(db).GetCastFunctions().RegisterCombineTypesRule(rule); |
386 | 0 | } |
387 | | |
388 | 0 | void ExtensionLoader::RegisterMetric(MetricInfo info) { |
389 | 0 | MetricsManager::Get(db).RegisterMetric(std::move(info)); |
390 | 0 | } |
391 | | |
392 | | } // namespace duckdb |