1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/function/function_serialization.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/common/field_writer.hpp" |
12 | #include "duckdb/main/client_context.hpp" |
13 | #include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp" |
14 | |
15 | namespace duckdb { |
16 | |
17 | class FunctionSerializer { |
18 | public: |
19 | template <class FUNC> |
20 | static void SerializeBase(FieldWriter &writer, const FUNC &function, FunctionData *bind_info) { |
21 | D_ASSERT(!function.name.empty()); |
22 | writer.WriteString(val: function.name); |
23 | writer.WriteRegularSerializableList(function.arguments); |
24 | writer.WriteRegularSerializableList(function.original_arguments); |
25 | bool serialize = function.serialize; |
26 | writer.WriteField(element: serialize); |
27 | if (serialize) { |
28 | function.serialize(writer, bind_info, function); |
29 | // First check if serialize throws a NotImplementedException, in which case it doesn't require a deserialize |
30 | // function |
31 | D_ASSERT(function.deserialize); |
32 | } |
33 | } |
34 | |
35 | template <class FUNC> |
36 | static void Serialize(FieldWriter &writer, const FUNC &function, const LogicalType &return_type, |
37 | const vector<unique_ptr<Expression>> &children, FunctionData *bind_info) { |
38 | SerializeBase(writer, function, bind_info); |
39 | writer.WriteSerializable(element: return_type); |
40 | writer.WriteSerializableList(elements: children); |
41 | } |
42 | |
43 | template <class FUNC, class CATALOG_ENTRY> |
44 | static FUNC DeserializeBaseInternal(FieldReader &reader, PlanDeserializationState &state, CatalogType type, |
45 | unique_ptr<FunctionData> &bind_info, bool &has_deserialize) { |
46 | auto &context = state.context; |
47 | auto name = reader.ReadRequired<string>(); |
48 | auto arguments = reader.ReadRequiredSerializableList<LogicalType, LogicalType>(); |
49 | // note: original_arguments are optional (can be list of size 0) |
50 | auto original_arguments = reader.ReadRequiredSerializableList<LogicalType, LogicalType>(); |
51 | |
52 | auto &func_catalog = Catalog::GetEntry(context, type, SYSTEM_CATALOG, DEFAULT_SCHEMA, name); |
53 | if (func_catalog.type != type) { |
54 | throw InternalException("Cant find catalog entry for function %s" , name); |
55 | } |
56 | |
57 | auto &functions = func_catalog.Cast<CATALOG_ENTRY>(); |
58 | auto function = functions.functions.GetFunctionByArguments( |
59 | state.context, original_arguments.empty() ? arguments : original_arguments); |
60 | function.arguments = std::move(arguments); |
61 | function.original_arguments = std::move(original_arguments); |
62 | |
63 | has_deserialize = reader.ReadRequired<bool>(); |
64 | if (has_deserialize) { |
65 | if (!function.deserialize) { |
66 | throw SerializationException("Function requires deserialization but no deserialization function for %s" , |
67 | function.name); |
68 | } |
69 | bind_info = function.deserialize(state, reader, function); |
70 | } else { |
71 | D_ASSERT(!function.serialize); |
72 | D_ASSERT(!function.deserialize); |
73 | } |
74 | return function; |
75 | } |
76 | template <class FUNC, class CATALOG_ENTRY> |
77 | static FUNC DeserializeBase(FieldReader &reader, PlanDeserializationState &state, CatalogType type, |
78 | unique_ptr<FunctionData> &bind_info) { |
79 | bool has_deserialize; |
80 | return DeserializeBaseInternal<FUNC, CATALOG_ENTRY>(reader, state, type, bind_info, has_deserialize); |
81 | } |
82 | |
83 | template <class FUNC, class CATALOG_ENTRY> |
84 | static FUNC Deserialize(FieldReader &reader, ExpressionDeserializationState &state, CatalogType type, |
85 | vector<unique_ptr<Expression>> &children, unique_ptr<FunctionData> &bind_info) { |
86 | bool has_deserialize; |
87 | auto function = |
88 | DeserializeBaseInternal<FUNC, CATALOG_ENTRY>(reader, state.gstate, type, bind_info, has_deserialize); |
89 | auto return_type = reader.ReadRequiredSerializable<LogicalType, LogicalType>(); |
90 | children = reader.ReadRequiredSerializableList<Expression>(args&: state.gstate); |
91 | |
92 | // we re-bind the function only if the function did not have an explicit deserialize method |
93 | auto &context = state.gstate.context; |
94 | if (!has_deserialize && function.bind) { |
95 | bind_info = function.bind(context, function, children); |
96 | } |
97 | function.return_type = return_type; |
98 | return function; |
99 | } |
100 | }; |
101 | |
102 | } // namespace duckdb |
103 | |