1
2#include "duckdb/function/macro_function.hpp"
3
4#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp"
5#include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp"
6#include "duckdb/common/string_util.hpp"
7#include "duckdb/function/scalar_macro_function.hpp"
8#include "duckdb/function/table_macro_function.hpp"
9#include "duckdb/parser/expression/columnref_expression.hpp"
10#include "duckdb/parser/expression/comparison_expression.hpp"
11#include "duckdb/parser/expression/function_expression.hpp"
12
13namespace duckdb {
14
15// MacroFunction::MacroFunction(unique_ptr<ParsedExpression> expression) : expression(std::move(expression)) {}
16
17MacroFunction::MacroFunction(MacroType type) : type(type) {
18}
19
20string MacroFunction::ValidateArguments(MacroFunction &macro_def, const string &name, FunctionExpression &function_expr,
21 vector<unique_ptr<ParsedExpression>> &positionals,
22 unordered_map<string, unique_ptr<ParsedExpression>> &defaults) {
23
24 // separate positional and default arguments
25 for (auto &arg : function_expr.children) {
26 if (!arg->alias.empty()) {
27 // default argument
28 if (!macro_def.default_parameters.count(x: arg->alias)) {
29 return StringUtil::Format(fmt_str: "Macro %s does not have default parameter %s!", params: name, params: arg->alias);
30 } else if (defaults.count(x: arg->alias)) {
31 return StringUtil::Format(fmt_str: "Duplicate default parameters %s!", params: arg->alias);
32 }
33 defaults[arg->alias] = std::move(arg);
34 } else if (!defaults.empty()) {
35 return "Positional parameters cannot come after parameters with a default value!";
36 } else {
37 // positional argument
38 positionals.push_back(x: std::move(arg));
39 }
40 }
41
42 // validate if the right number of arguments was supplied
43 string error;
44 auto &parameters = macro_def.parameters;
45 if (parameters.size() != positionals.size()) {
46 error = StringUtil::Format(
47 fmt_str: "Macro function '%s(%s)' requires ", params: name,
48 params: StringUtil::Join(input: parameters, count: parameters.size(), separator: ", ", f: [](const unique_ptr<ParsedExpression> &p) {
49 return (p->Cast<ColumnRefExpression>()).column_names[0];
50 }));
51 error += parameters.size() == 1 ? "a single positional argument"
52 : StringUtil::Format(fmt_str: "%i positional arguments", params: parameters.size());
53 error += ", but ";
54 error += positionals.size() == 1 ? "a single positional argument was"
55 : StringUtil::Format(fmt_str: "%i positional arguments were", params: positionals.size());
56 error += " provided.";
57 return error;
58 }
59
60 // Add the default values for parameters that have defaults, that were not explicitly assigned to
61 for (auto it = macro_def.default_parameters.begin(); it != macro_def.default_parameters.end(); it++) {
62 auto &parameter_name = it->first;
63 auto &parameter_default = it->second;
64 if (!defaults.count(x: parameter_name)) {
65 // This parameter was not set yet, set it with the default value
66 defaults[parameter_name] = parameter_default->Copy();
67 }
68 }
69
70 return error;
71}
72
73void MacroFunction::CopyProperties(MacroFunction &other) const {
74 other.type = type;
75 for (auto &param : parameters) {
76 other.parameters.push_back(x: param->Copy());
77 }
78 for (auto &kv : default_parameters) {
79 other.default_parameters[kv.first] = kv.second->Copy();
80 }
81}
82
83string MacroFunction::ToSQL(const string &schema, const string &name) const {
84 vector<string> param_strings;
85 for (auto &param : parameters) {
86 param_strings.push_back(x: param->ToString());
87 }
88 for (auto &named_param : default_parameters) {
89 param_strings.push_back(x: StringUtil::Format(fmt_str: "%s := %s", params: named_param.first, params: named_param.second->ToString()));
90 }
91
92 return StringUtil::Format(fmt_str: "CREATE MACRO %s.%s(%s) AS ", params: schema, params: name, params: StringUtil::Join(input: param_strings, separator: ", "));
93}
94
95void MacroFunction::Serialize(Serializer &main_serializer) const {
96 FieldWriter writer(main_serializer);
97 writer.WriteField(element: type);
98 writer.WriteSerializableList(elements: parameters);
99 writer.WriteField<uint32_t>(element: (uint32_t)default_parameters.size());
100 auto &serializer = writer.GetSerializer();
101 for (auto &kv : default_parameters) {
102 serializer.WriteString(val: kv.first);
103 kv.second->Serialize(serializer);
104 }
105 SerializeInternal(writer);
106 writer.Finalize();
107}
108
109unique_ptr<MacroFunction> MacroFunction::Deserialize(Deserializer &main_source) {
110 FieldReader reader(main_source);
111 auto type = reader.ReadRequired<MacroType>();
112 auto parameters = reader.ReadRequiredSerializableList<ParsedExpression>();
113 auto default_param_count = reader.ReadRequired<uint32_t>();
114 unordered_map<string, unique_ptr<ParsedExpression>> default_parameters;
115 auto &source = reader.GetSource();
116 for (idx_t i = 0; i < default_param_count; i++) {
117 auto name = source.Read<string>();
118 default_parameters[name] = ParsedExpression::Deserialize(source);
119 }
120 unique_ptr<MacroFunction> result;
121 switch (type) {
122 case MacroType::SCALAR_MACRO:
123 result = ScalarMacroFunction::Deserialize(reader);
124 break;
125 case MacroType::TABLE_MACRO:
126 result = TableMacroFunction::Deserialize(reader);
127 break;
128 default:
129 throw InternalException("Cannot deserialize macro type");
130 }
131 result->parameters = std::move(parameters);
132 result->default_parameters = std::move(default_parameters);
133 reader.Finalize();
134 return result;
135}
136
137} // namespace duckdb
138