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/scalar_function_catalog_entry.hpp" |
6 | #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" |
7 | #include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp" |
8 | #include "duckdb/catalog/catalog_entry/table_macro_catalog_entry.hpp" |
9 | #include "duckdb/function/table_macro_function.hpp" |
10 | #include "duckdb/function/scalar_macro_function.hpp" |
11 | |
12 | #include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp" |
13 | #include "duckdb/catalog/catalog_entry/pragma_function_catalog_entry.hpp" |
14 | #include "duckdb/parser/expression/columnref_expression.hpp" |
15 | #include "duckdb/common/algorithm.hpp" |
16 | #include "duckdb/main/client_data.hpp" |
17 | |
18 | namespace duckdb { |
19 | |
20 | struct DuckDBFunctionsData : public GlobalTableFunctionState { |
21 | DuckDBFunctionsData() : offset(0), offset_in_entry(0) { |
22 | } |
23 | |
24 | vector<reference<CatalogEntry>> entries; |
25 | idx_t offset; |
26 | idx_t offset_in_entry; |
27 | }; |
28 | |
29 | static unique_ptr<FunctionData> DuckDBFunctionsBind(ClientContext &context, TableFunctionBindInput &input, |
30 | vector<LogicalType> &return_types, vector<string> &names) { |
31 | names.emplace_back(args: "database_name" ); |
32 | return_types.emplace_back(args: LogicalType::VARCHAR); |
33 | |
34 | names.emplace_back(args: "schema_name" ); |
35 | return_types.emplace_back(args: LogicalType::VARCHAR); |
36 | |
37 | names.emplace_back(args: "function_name" ); |
38 | return_types.emplace_back(args: LogicalType::VARCHAR); |
39 | |
40 | names.emplace_back(args: "function_type" ); |
41 | return_types.emplace_back(args: LogicalType::VARCHAR); |
42 | |
43 | names.emplace_back(args: "description" ); |
44 | return_types.emplace_back(args: LogicalType::VARCHAR); |
45 | |
46 | names.emplace_back(args: "return_type" ); |
47 | return_types.emplace_back(args: LogicalType::VARCHAR); |
48 | |
49 | names.emplace_back(args: "parameters" ); |
50 | return_types.push_back(x: LogicalType::LIST(child: LogicalType::VARCHAR)); |
51 | |
52 | names.emplace_back(args: "parameter_types" ); |
53 | return_types.push_back(x: LogicalType::LIST(child: LogicalType::VARCHAR)); |
54 | |
55 | names.emplace_back(args: "varargs" ); |
56 | return_types.emplace_back(args: LogicalType::VARCHAR); |
57 | |
58 | names.emplace_back(args: "macro_definition" ); |
59 | return_types.emplace_back(args: LogicalType::VARCHAR); |
60 | |
61 | names.emplace_back(args: "has_side_effects" ); |
62 | return_types.emplace_back(args: LogicalType::BOOLEAN); |
63 | |
64 | names.emplace_back(args: "internal" ); |
65 | return_types.emplace_back(args: LogicalType::BOOLEAN); |
66 | |
67 | names.emplace_back(args: "function_oid" ); |
68 | return_types.emplace_back(args: LogicalType::BIGINT); |
69 | |
70 | names.emplace_back(args: "example" ); |
71 | return_types.emplace_back(args: LogicalType::VARCHAR); |
72 | |
73 | return nullptr; |
74 | } |
75 | |
76 | static void (ClientContext &context, SchemaCatalogEntry &schema, |
77 | DuckDBFunctionsData &result) { |
78 | schema.Scan(context, type: CatalogType::SCALAR_FUNCTION_ENTRY, |
79 | callback: [&](CatalogEntry &entry) { result.entries.push_back(x: entry); }); |
80 | schema.Scan(context, type: CatalogType::TABLE_FUNCTION_ENTRY, |
81 | callback: [&](CatalogEntry &entry) { result.entries.push_back(x: entry); }); |
82 | schema.Scan(context, type: CatalogType::PRAGMA_FUNCTION_ENTRY, |
83 | callback: [&](CatalogEntry &entry) { result.entries.push_back(x: entry); }); |
84 | } |
85 | |
86 | unique_ptr<GlobalTableFunctionState> DuckDBFunctionsInit(ClientContext &context, TableFunctionInitInput &input) { |
87 | auto result = make_uniq<DuckDBFunctionsData>(); |
88 | |
89 | // scan all the schemas for tables and collect them and collect them |
90 | auto schemas = Catalog::GetAllSchemas(context); |
91 | for (auto &schema : schemas) { |
92 | ExtractFunctionsFromSchema(context, schema&: schema.get(), result&: *result); |
93 | }; |
94 | |
95 | std::sort(first: result->entries.begin(), last: result->entries.end(), |
96 | comp: [&](reference<CatalogEntry> a, reference<CatalogEntry> b) { |
97 | return (int32_t)a.get().type < (int32_t)b.get().type; |
98 | }); |
99 | return std::move(result); |
100 | } |
101 | |
102 | struct { |
103 | static idx_t (ScalarFunctionCatalogEntry &entry) { |
104 | return entry.functions.Size(); |
105 | } |
106 | |
107 | static Value () { |
108 | return Value("scalar" ); |
109 | } |
110 | |
111 | static Value (ScalarFunctionCatalogEntry &entry, idx_t offset) { |
112 | return Value(entry.functions.GetFunctionByOffset(offset).return_type.ToString()); |
113 | } |
114 | |
115 | static vector<Value> (ScalarFunctionCatalogEntry &entry, idx_t offset) { |
116 | vector<Value> results; |
117 | for (idx_t i = 0; i < entry.functions.GetFunctionByOffset(offset).arguments.size(); i++) { |
118 | results.emplace_back(args: "col" + to_string(val: i)); |
119 | } |
120 | return results; |
121 | } |
122 | |
123 | static Value (ScalarFunctionCatalogEntry &entry, idx_t offset) { |
124 | vector<Value> results; |
125 | auto fun = entry.functions.GetFunctionByOffset(offset); |
126 | for (idx_t i = 0; i < fun.arguments.size(); i++) { |
127 | results.emplace_back(args: fun.arguments[i].ToString()); |
128 | } |
129 | return Value::LIST(child_type: LogicalType::VARCHAR, values: std::move(results)); |
130 | } |
131 | |
132 | static Value (ScalarFunctionCatalogEntry &entry, idx_t offset) { |
133 | auto fun = entry.functions.GetFunctionByOffset(offset); |
134 | return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); |
135 | } |
136 | |
137 | static Value (ScalarFunctionCatalogEntry &entry, idx_t offset) { |
138 | return Value(); |
139 | } |
140 | |
141 | static Value (ScalarFunctionCatalogEntry &entry, idx_t offset) { |
142 | return Value::BOOLEAN(value: entry.functions.GetFunctionByOffset(offset).side_effects == |
143 | FunctionSideEffects::HAS_SIDE_EFFECTS); |
144 | } |
145 | }; |
146 | |
147 | struct { |
148 | static idx_t (AggregateFunctionCatalogEntry &entry) { |
149 | return entry.functions.Size(); |
150 | } |
151 | |
152 | static Value () { |
153 | return Value("aggregate" ); |
154 | } |
155 | |
156 | static Value (AggregateFunctionCatalogEntry &entry, idx_t offset) { |
157 | return Value(entry.functions.GetFunctionByOffset(offset).return_type.ToString()); |
158 | } |
159 | |
160 | static vector<Value> (AggregateFunctionCatalogEntry &entry, idx_t offset) { |
161 | vector<Value> results; |
162 | for (idx_t i = 0; i < entry.functions.GetFunctionByOffset(offset).arguments.size(); i++) { |
163 | results.emplace_back(args: "col" + to_string(val: i)); |
164 | } |
165 | return results; |
166 | } |
167 | |
168 | static Value (AggregateFunctionCatalogEntry &entry, idx_t offset) { |
169 | vector<Value> results; |
170 | auto fun = entry.functions.GetFunctionByOffset(offset); |
171 | for (idx_t i = 0; i < fun.arguments.size(); i++) { |
172 | results.emplace_back(args: fun.arguments[i].ToString()); |
173 | } |
174 | return Value::LIST(child_type: LogicalType::VARCHAR, values: std::move(results)); |
175 | } |
176 | |
177 | static Value (AggregateFunctionCatalogEntry &entry, idx_t offset) { |
178 | auto fun = entry.functions.GetFunctionByOffset(offset); |
179 | return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); |
180 | } |
181 | |
182 | static Value (AggregateFunctionCatalogEntry &entry, idx_t offset) { |
183 | return Value(); |
184 | } |
185 | |
186 | static Value (AggregateFunctionCatalogEntry &entry, idx_t offset) { |
187 | return Value::BOOLEAN(value: entry.functions.GetFunctionByOffset(offset).side_effects == |
188 | FunctionSideEffects::HAS_SIDE_EFFECTS); |
189 | } |
190 | }; |
191 | |
192 | struct { |
193 | static idx_t (ScalarMacroCatalogEntry &entry) { |
194 | return 1; |
195 | } |
196 | |
197 | static Value () { |
198 | return Value("macro" ); |
199 | } |
200 | |
201 | static Value (ScalarMacroCatalogEntry &entry, idx_t offset) { |
202 | return Value(); |
203 | } |
204 | |
205 | static vector<Value> (ScalarMacroCatalogEntry &entry, idx_t offset) { |
206 | vector<Value> results; |
207 | for (auto ¶m : entry.function->parameters) { |
208 | D_ASSERT(param->type == ExpressionType::COLUMN_REF); |
209 | auto &colref = param->Cast<ColumnRefExpression>(); |
210 | results.emplace_back(args: colref.GetColumnName()); |
211 | } |
212 | for (auto ¶m_entry : entry.function->default_parameters) { |
213 | results.emplace_back(args: param_entry.first); |
214 | } |
215 | return results; |
216 | } |
217 | |
218 | static Value (ScalarMacroCatalogEntry &entry, idx_t offset) { |
219 | vector<Value> results; |
220 | for (idx_t i = 0; i < entry.function->parameters.size(); i++) { |
221 | results.emplace_back(args: LogicalType::VARCHAR); |
222 | } |
223 | for (idx_t i = 0; i < entry.function->default_parameters.size(); i++) { |
224 | results.emplace_back(args: LogicalType::VARCHAR); |
225 | } |
226 | return Value::LIST(child_type: LogicalType::VARCHAR, values: std::move(results)); |
227 | } |
228 | |
229 | static Value (ScalarMacroCatalogEntry &entry, idx_t offset) { |
230 | return Value(); |
231 | } |
232 | |
233 | static Value (ScalarMacroCatalogEntry &entry, idx_t offset) { |
234 | D_ASSERT(entry.function->type == MacroType::SCALAR_MACRO); |
235 | auto &func = entry.function->Cast<ScalarMacroFunction>(); |
236 | return func.expression->ToString(); |
237 | } |
238 | |
239 | static Value (ScalarMacroCatalogEntry &entry, idx_t offset) { |
240 | return Value(); |
241 | } |
242 | }; |
243 | |
244 | struct { |
245 | static idx_t (TableMacroCatalogEntry &entry) { |
246 | return 1; |
247 | } |
248 | |
249 | static Value () { |
250 | return Value("table_macro" ); |
251 | } |
252 | |
253 | static Value (TableMacroCatalogEntry &entry, idx_t offset) { |
254 | return Value(); |
255 | } |
256 | |
257 | static vector<Value> (TableMacroCatalogEntry &entry, idx_t offset) { |
258 | vector<Value> results; |
259 | for (auto ¶m : entry.function->parameters) { |
260 | D_ASSERT(param->type == ExpressionType::COLUMN_REF); |
261 | auto &colref = param->Cast<ColumnRefExpression>(); |
262 | results.emplace_back(args: colref.GetColumnName()); |
263 | } |
264 | for (auto ¶m_entry : entry.function->default_parameters) { |
265 | results.emplace_back(args: param_entry.first); |
266 | } |
267 | return results; |
268 | } |
269 | |
270 | static Value (TableMacroCatalogEntry &entry, idx_t offset) { |
271 | vector<Value> results; |
272 | for (idx_t i = 0; i < entry.function->parameters.size(); i++) { |
273 | results.emplace_back(args: LogicalType::VARCHAR); |
274 | } |
275 | for (idx_t i = 0; i < entry.function->default_parameters.size(); i++) { |
276 | results.emplace_back(args: LogicalType::VARCHAR); |
277 | } |
278 | return Value::LIST(child_type: LogicalType::VARCHAR, values: std::move(results)); |
279 | } |
280 | |
281 | static Value (TableMacroCatalogEntry &entry, idx_t offset) { |
282 | return Value(); |
283 | } |
284 | |
285 | static Value (TableMacroCatalogEntry &entry, idx_t offset) { |
286 | if (entry.function->type == MacroType::SCALAR_MACRO) { |
287 | auto &func = entry.function->Cast<ScalarMacroFunction>(); |
288 | return func.expression->ToString(); |
289 | } |
290 | return Value(); |
291 | } |
292 | |
293 | static Value (TableMacroCatalogEntry &entry, idx_t offset) { |
294 | return Value(); |
295 | } |
296 | }; |
297 | |
298 | struct { |
299 | static idx_t (TableFunctionCatalogEntry &entry) { |
300 | return entry.functions.Size(); |
301 | } |
302 | |
303 | static Value () { |
304 | return Value("table" ); |
305 | } |
306 | |
307 | static Value (TableFunctionCatalogEntry &entry, idx_t offset) { |
308 | return Value(); |
309 | } |
310 | |
311 | static vector<Value> (TableFunctionCatalogEntry &entry, idx_t offset) { |
312 | vector<Value> results; |
313 | auto fun = entry.functions.GetFunctionByOffset(offset); |
314 | for (idx_t i = 0; i < fun.arguments.size(); i++) { |
315 | results.emplace_back(args: "col" + to_string(val: i)); |
316 | } |
317 | for (auto ¶m : fun.named_parameters) { |
318 | results.emplace_back(args: param.first); |
319 | } |
320 | return results; |
321 | } |
322 | |
323 | static Value (TableFunctionCatalogEntry &entry, idx_t offset) { |
324 | vector<Value> results; |
325 | auto fun = entry.functions.GetFunctionByOffset(offset); |
326 | |
327 | for (idx_t i = 0; i < fun.arguments.size(); i++) { |
328 | results.emplace_back(args: fun.arguments[i].ToString()); |
329 | } |
330 | for (auto ¶m : fun.named_parameters) { |
331 | results.emplace_back(args: param.second.ToString()); |
332 | } |
333 | return Value::LIST(child_type: LogicalType::VARCHAR, values: std::move(results)); |
334 | } |
335 | |
336 | static Value (TableFunctionCatalogEntry &entry, idx_t offset) { |
337 | auto fun = entry.functions.GetFunctionByOffset(offset); |
338 | return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); |
339 | } |
340 | |
341 | static Value (TableFunctionCatalogEntry &entry, idx_t offset) { |
342 | return Value(); |
343 | } |
344 | |
345 | static Value (TableFunctionCatalogEntry &entry, idx_t offset) { |
346 | return Value(); |
347 | } |
348 | }; |
349 | |
350 | struct { |
351 | static idx_t (PragmaFunctionCatalogEntry &entry) { |
352 | return entry.functions.Size(); |
353 | } |
354 | |
355 | static Value () { |
356 | return Value("pragma" ); |
357 | } |
358 | |
359 | static Value (PragmaFunctionCatalogEntry &entry, idx_t offset) { |
360 | return Value(); |
361 | } |
362 | |
363 | static vector<Value> (PragmaFunctionCatalogEntry &entry, idx_t offset) { |
364 | vector<Value> results; |
365 | auto fun = entry.functions.GetFunctionByOffset(offset); |
366 | |
367 | for (idx_t i = 0; i < fun.arguments.size(); i++) { |
368 | results.emplace_back(args: "col" + to_string(val: i)); |
369 | } |
370 | for (auto ¶m : fun.named_parameters) { |
371 | results.emplace_back(args: param.first); |
372 | } |
373 | return results; |
374 | } |
375 | |
376 | static Value (PragmaFunctionCatalogEntry &entry, idx_t offset) { |
377 | vector<Value> results; |
378 | auto fun = entry.functions.GetFunctionByOffset(offset); |
379 | |
380 | for (idx_t i = 0; i < fun.arguments.size(); i++) { |
381 | results.emplace_back(args: fun.arguments[i].ToString()); |
382 | } |
383 | for (auto ¶m : fun.named_parameters) { |
384 | results.emplace_back(args: param.second.ToString()); |
385 | } |
386 | return Value::LIST(child_type: LogicalType::VARCHAR, values: std::move(results)); |
387 | } |
388 | |
389 | static Value (PragmaFunctionCatalogEntry &entry, idx_t offset) { |
390 | auto fun = entry.functions.GetFunctionByOffset(offset); |
391 | return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); |
392 | } |
393 | |
394 | static Value (PragmaFunctionCatalogEntry &entry, idx_t offset) { |
395 | return Value(); |
396 | } |
397 | |
398 | static Value (PragmaFunctionCatalogEntry &entry, idx_t offset) { |
399 | return Value(); |
400 | } |
401 | }; |
402 | |
403 | template <class T, class OP> |
404 | bool (FunctionEntry &entry, idx_t function_idx, DataChunk &output, idx_t output_offset) { |
405 | auto &function = entry.Cast<T>(); |
406 | idx_t col = 0; |
407 | |
408 | // database_name, LogicalType::VARCHAR |
409 | output.SetValue(col_idx: col++, index: output_offset, val: Value(function.schema.catalog.GetName())); |
410 | |
411 | // schema_name, LogicalType::VARCHAR |
412 | output.SetValue(col_idx: col++, index: output_offset, val: Value(function.schema.name)); |
413 | |
414 | // function_name, LogicalType::VARCHAR |
415 | output.SetValue(col_idx: col++, index: output_offset, val: Value(function.name)); |
416 | |
417 | // function_type, LogicalType::VARCHAR |
418 | output.SetValue(col_idx: col++, index: output_offset, val: Value(OP::GetFunctionType())); |
419 | |
420 | // function_description, LogicalType::VARCHAR |
421 | output.SetValue(col_idx: col++, index: output_offset, val: entry.description.empty() ? Value() : entry.description); |
422 | |
423 | // return_type, LogicalType::VARCHAR |
424 | output.SetValue(col_idx: col++, index: output_offset, val: OP::GetReturnType(function, function_idx)); |
425 | |
426 | // parameters, LogicalType::LIST(LogicalType::VARCHAR) |
427 | auto parameters = OP::GetParameters(function, function_idx); |
428 | for (idx_t param_idx = 0; param_idx < function.parameter_names.size() && param_idx < parameters.size(); |
429 | param_idx++) { |
430 | parameters[param_idx] = Value(function.parameter_names[param_idx]); |
431 | } |
432 | output.SetValue(col_idx: col++, index: output_offset, val: Value::LIST(LogicalType::VARCHAR, std::move(parameters))); |
433 | |
434 | // parameter_types, LogicalType::LIST(LogicalType::VARCHAR) |
435 | output.SetValue(col_idx: col++, index: output_offset, val: OP::GetParameterTypes(function, function_idx)); |
436 | |
437 | // varargs, LogicalType::VARCHAR |
438 | output.SetValue(col_idx: col++, index: output_offset, val: OP::GetVarArgs(function, function_idx)); |
439 | |
440 | // macro_definition, LogicalType::VARCHAR |
441 | output.SetValue(col_idx: col++, index: output_offset, val: OP::GetMacroDefinition(function, function_idx)); |
442 | |
443 | // has_side_effects, LogicalType::BOOLEAN |
444 | output.SetValue(col_idx: col++, index: output_offset, val: OP::HasSideEffects(function, function_idx)); |
445 | |
446 | // internal, LogicalType::BOOLEAN |
447 | output.SetValue(col_idx: col++, index: output_offset, val: Value::BOOLEAN(value: function.internal)); |
448 | |
449 | // function_oid, LogicalType::BIGINT |
450 | output.SetValue(col_idx: col++, index: output_offset, val: Value::BIGINT(value: function.oid)); |
451 | |
452 | // example, LogicalType::VARCHAR |
453 | output.SetValue(col_idx: col++, index: output_offset, val: entry.example.empty() ? Value() : entry.example); |
454 | |
455 | return function_idx + 1 == OP::FunctionCount(function); |
456 | } |
457 | |
458 | void DuckDBFunctionsFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { |
459 | auto &data = data_p.global_state->Cast<DuckDBFunctionsData>(); |
460 | if (data.offset >= data.entries.size()) { |
461 | // finished returning values |
462 | return; |
463 | } |
464 | // start returning values |
465 | // either fill up the chunk or return all the remaining columns |
466 | idx_t count = 0; |
467 | while (data.offset < data.entries.size() && count < STANDARD_VECTOR_SIZE) { |
468 | auto &entry = data.entries[data.offset].get().Cast<FunctionEntry>(); |
469 | bool finished; |
470 | |
471 | switch (entry.type) { |
472 | case CatalogType::SCALAR_FUNCTION_ENTRY: |
473 | finished = ExtractFunctionData<ScalarFunctionCatalogEntry, ScalarFunctionExtractor>( |
474 | entry, function_idx: data.offset_in_entry, output, output_offset: count); |
475 | break; |
476 | case CatalogType::AGGREGATE_FUNCTION_ENTRY: |
477 | finished = ExtractFunctionData<AggregateFunctionCatalogEntry, AggregateFunctionExtractor>( |
478 | entry, function_idx: data.offset_in_entry, output, output_offset: count); |
479 | break; |
480 | case CatalogType::TABLE_MACRO_ENTRY: |
481 | finished = ExtractFunctionData<TableMacroCatalogEntry, TableMacroExtractor>(entry, function_idx: data.offset_in_entry, |
482 | output, output_offset: count); |
483 | break; |
484 | |
485 | case CatalogType::MACRO_ENTRY: |
486 | finished = ExtractFunctionData<ScalarMacroCatalogEntry, MacroExtractor>(entry, function_idx: data.offset_in_entry, output, |
487 | output_offset: count); |
488 | break; |
489 | case CatalogType::TABLE_FUNCTION_ENTRY: |
490 | finished = ExtractFunctionData<TableFunctionCatalogEntry, TableFunctionExtractor>( |
491 | entry, function_idx: data.offset_in_entry, output, output_offset: count); |
492 | break; |
493 | case CatalogType::PRAGMA_FUNCTION_ENTRY: |
494 | finished = ExtractFunctionData<PragmaFunctionCatalogEntry, PragmaFunctionExtractor>( |
495 | entry, function_idx: data.offset_in_entry, output, output_offset: count); |
496 | break; |
497 | default: |
498 | throw InternalException("FIXME: unrecognized function type in duckdb_functions" ); |
499 | } |
500 | if (finished) { |
501 | // finished with this function, move to the next function |
502 | data.offset++; |
503 | data.offset_in_entry = 0; |
504 | } else { |
505 | // more functions remain |
506 | data.offset_in_entry++; |
507 | } |
508 | count++; |
509 | } |
510 | output.SetCardinality(count); |
511 | } |
512 | |
513 | void DuckDBFunctionsFun::RegisterFunction(BuiltinFunctions &set) { |
514 | set.AddFunction( |
515 | function: TableFunction("duckdb_functions" , {}, DuckDBFunctionsFunction, DuckDBFunctionsBind, DuckDBFunctionsInit)); |
516 | } |
517 | |
518 | } // namespace duckdb |
519 | |