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
18namespace duckdb {
19
20struct 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
29static 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
76static void ExtractFunctionsFromSchema(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
86unique_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
102struct ScalarFunctionExtractor {
103 static idx_t FunctionCount(ScalarFunctionCatalogEntry &entry) {
104 return entry.functions.Size();
105 }
106
107 static Value GetFunctionType() {
108 return Value("scalar");
109 }
110
111 static Value GetReturnType(ScalarFunctionCatalogEntry &entry, idx_t offset) {
112 return Value(entry.functions.GetFunctionByOffset(offset).return_type.ToString());
113 }
114
115 static vector<Value> GetParameters(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 GetParameterTypes(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 GetVarArgs(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 GetMacroDefinition(ScalarFunctionCatalogEntry &entry, idx_t offset) {
138 return Value();
139 }
140
141 static Value HasSideEffects(ScalarFunctionCatalogEntry &entry, idx_t offset) {
142 return Value::BOOLEAN(value: entry.functions.GetFunctionByOffset(offset).side_effects ==
143 FunctionSideEffects::HAS_SIDE_EFFECTS);
144 }
145};
146
147struct AggregateFunctionExtractor {
148 static idx_t FunctionCount(AggregateFunctionCatalogEntry &entry) {
149 return entry.functions.Size();
150 }
151
152 static Value GetFunctionType() {
153 return Value("aggregate");
154 }
155
156 static Value GetReturnType(AggregateFunctionCatalogEntry &entry, idx_t offset) {
157 return Value(entry.functions.GetFunctionByOffset(offset).return_type.ToString());
158 }
159
160 static vector<Value> GetParameters(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 GetParameterTypes(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 GetVarArgs(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 GetMacroDefinition(AggregateFunctionCatalogEntry &entry, idx_t offset) {
183 return Value();
184 }
185
186 static Value HasSideEffects(AggregateFunctionCatalogEntry &entry, idx_t offset) {
187 return Value::BOOLEAN(value: entry.functions.GetFunctionByOffset(offset).side_effects ==
188 FunctionSideEffects::HAS_SIDE_EFFECTS);
189 }
190};
191
192struct MacroExtractor {
193 static idx_t FunctionCount(ScalarMacroCatalogEntry &entry) {
194 return 1;
195 }
196
197 static Value GetFunctionType() {
198 return Value("macro");
199 }
200
201 static Value GetReturnType(ScalarMacroCatalogEntry &entry, idx_t offset) {
202 return Value();
203 }
204
205 static vector<Value> GetParameters(ScalarMacroCatalogEntry &entry, idx_t offset) {
206 vector<Value> results;
207 for (auto &param : 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 &param_entry : entry.function->default_parameters) {
213 results.emplace_back(args: param_entry.first);
214 }
215 return results;
216 }
217
218 static Value GetParameterTypes(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 GetVarArgs(ScalarMacroCatalogEntry &entry, idx_t offset) {
230 return Value();
231 }
232
233 static Value GetMacroDefinition(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 HasSideEffects(ScalarMacroCatalogEntry &entry, idx_t offset) {
240 return Value();
241 }
242};
243
244struct TableMacroExtractor {
245 static idx_t FunctionCount(TableMacroCatalogEntry &entry) {
246 return 1;
247 }
248
249 static Value GetFunctionType() {
250 return Value("table_macro");
251 }
252
253 static Value GetReturnType(TableMacroCatalogEntry &entry, idx_t offset) {
254 return Value();
255 }
256
257 static vector<Value> GetParameters(TableMacroCatalogEntry &entry, idx_t offset) {
258 vector<Value> results;
259 for (auto &param : 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 &param_entry : entry.function->default_parameters) {
265 results.emplace_back(args: param_entry.first);
266 }
267 return results;
268 }
269
270 static Value GetParameterTypes(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 GetVarArgs(TableMacroCatalogEntry &entry, idx_t offset) {
282 return Value();
283 }
284
285 static Value GetMacroDefinition(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 HasSideEffects(TableMacroCatalogEntry &entry, idx_t offset) {
294 return Value();
295 }
296};
297
298struct TableFunctionExtractor {
299 static idx_t FunctionCount(TableFunctionCatalogEntry &entry) {
300 return entry.functions.Size();
301 }
302
303 static Value GetFunctionType() {
304 return Value("table");
305 }
306
307 static Value GetReturnType(TableFunctionCatalogEntry &entry, idx_t offset) {
308 return Value();
309 }
310
311 static vector<Value> GetParameters(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 &param : fun.named_parameters) {
318 results.emplace_back(args: param.first);
319 }
320 return results;
321 }
322
323 static Value GetParameterTypes(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 &param : 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 GetVarArgs(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 GetMacroDefinition(TableFunctionCatalogEntry &entry, idx_t offset) {
342 return Value();
343 }
344
345 static Value HasSideEffects(TableFunctionCatalogEntry &entry, idx_t offset) {
346 return Value();
347 }
348};
349
350struct PragmaFunctionExtractor {
351 static idx_t FunctionCount(PragmaFunctionCatalogEntry &entry) {
352 return entry.functions.Size();
353 }
354
355 static Value GetFunctionType() {
356 return Value("pragma");
357 }
358
359 static Value GetReturnType(PragmaFunctionCatalogEntry &entry, idx_t offset) {
360 return Value();
361 }
362
363 static vector<Value> GetParameters(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 &param : fun.named_parameters) {
371 results.emplace_back(args: param.first);
372 }
373 return results;
374 }
375
376 static Value GetParameterTypes(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 &param : 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 GetVarArgs(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 GetMacroDefinition(PragmaFunctionCatalogEntry &entry, idx_t offset) {
395 return Value();
396 }
397
398 static Value HasSideEffects(PragmaFunctionCatalogEntry &entry, idx_t offset) {
399 return Value();
400 }
401};
402
403template <class T, class OP>
404bool ExtractFunctionData(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
458void 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
513void DuckDBFunctionsFun::RegisterFunction(BuiltinFunctions &set) {
514 set.AddFunction(
515 function: TableFunction("duckdb_functions", {}, DuckDBFunctionsFunction, DuckDBFunctionsBind, DuckDBFunctionsInit));
516}
517
518} // namespace duckdb
519