1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/common/serializer.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/catalog/catalog.hpp" |
12 | #include "duckdb/common/common.hpp" |
13 | #include "duckdb/common/exception.hpp" |
14 | #include "duckdb/common/vector.hpp" |
15 | #include <type_traits> |
16 | |
17 | namespace duckdb { |
18 | |
19 | //! The Serialize class is a base class that can be used to serializing objects into a binary buffer |
20 | class Serializer { |
21 | private: |
22 | uint64_t version = 0L; |
23 | |
24 | public: |
25 | bool is_query_plan = false; |
26 | |
27 | virtual ~Serializer() { |
28 | } |
29 | |
30 | //! Sets the version of the serialization that writers are expected to use |
31 | //! The version is mostly the most recent one, unless modifying old data or streaming to |
32 | //! an older version |
33 | void SetVersion(uint64_t v) { |
34 | D_ASSERT(this->version == 0); // version can only be set once |
35 | this->version = v; |
36 | } |
37 | |
38 | //! Returns the version of serialization that writers are expected to use |
39 | uint64_t GetVersion() { |
40 | return version; |
41 | } |
42 | |
43 | virtual void WriteData(const_data_ptr_t buffer, idx_t write_size) = 0; |
44 | |
45 | template <class T> |
46 | void Write(T element) { |
47 | static_assert(std::is_trivially_destructible<T>(), "Write element must be trivially destructible" ); |
48 | |
49 | WriteData(buffer: const_data_ptr_cast(&element), write_size: sizeof(T)); |
50 | } |
51 | |
52 | //! Write data from a string buffer directly (without length prefix) |
53 | void WriteBufferData(const string &str) { |
54 | WriteData(buffer: const_data_ptr_cast(src: str.c_str()), write_size: str.size()); |
55 | } |
56 | //! Write a string with a length prefix |
57 | void WriteString(const string &val) { |
58 | WriteStringLen(val: const_data_ptr_cast(src: val.c_str()), len: val.size()); |
59 | } |
60 | void WriteStringLen(const_data_ptr_t val, idx_t len) { |
61 | Write<uint32_t>(element: (uint32_t)len); |
62 | if (len > 0) { |
63 | WriteData(buffer: val, write_size: len); |
64 | } |
65 | } |
66 | |
67 | template <class T> |
68 | void WriteList(const vector<unique_ptr<T>> &list) { |
69 | Write<uint32_t>(element: (uint32_t)list.size()); |
70 | for (auto &child : list) { |
71 | child->Serialize(*this); |
72 | } |
73 | } |
74 | |
75 | void WriteStringVector(const vector<string> &list) { |
76 | Write<uint32_t>(element: (uint32_t)list.size()); |
77 | for (auto &child : list) { |
78 | WriteString(val: child); |
79 | } |
80 | } |
81 | |
82 | template <class T> |
83 | void WriteOptional(const unique_ptr<T> &element) { |
84 | Write<bool>(element ? true : false); |
85 | if (element) { |
86 | element->Serialize(*this); |
87 | } |
88 | } |
89 | }; |
90 | |
91 | //! The Deserializer class assists in deserializing a binary blob back into an |
92 | //! object |
93 | class Deserializer { |
94 | private: |
95 | uint64_t version = 0L; |
96 | |
97 | public: |
98 | virtual ~Deserializer() { |
99 | } |
100 | |
101 | //! Sets the version of the serialization that readers are expected to use |
102 | //! The version is mostly the most recent one, unless reading old data or streaming from |
103 | //! an older version |
104 | void SetVersion(uint64_t v) { |
105 | D_ASSERT(this->version == 0); // version can only be set once |
106 | this->version = v; |
107 | } |
108 | |
109 | //! Returns the version of serialization that readers are expected to use |
110 | uint64_t GetVersion() { |
111 | return version; |
112 | } |
113 | |
114 | //! Reads [read_size] bytes into the buffer |
115 | virtual void ReadData(data_ptr_t buffer, idx_t read_size) = 0; |
116 | |
117 | //! Gets the context for the deserializer |
118 | virtual ClientContext &GetContext() { |
119 | throw InternalException("This deserializer does not have a client-context" ); |
120 | }; |
121 | |
122 | //! Gets the catalog for the deserializer |
123 | virtual optional_ptr<Catalog> GetCatalog() { |
124 | return nullptr; |
125 | }; |
126 | |
127 | template <class T> |
128 | T Read() { |
129 | T value; |
130 | ReadData(buffer: data_ptr_cast(&value), read_size: sizeof(T)); |
131 | return value; |
132 | } |
133 | |
134 | template <class T, typename... ARGS> |
135 | void ReadList(vector<unique_ptr<T>> &list, ARGS &&... args) { |
136 | auto select_count = Read<uint32_t>(); |
137 | for (uint32_t i = 0; i < select_count; i++) { |
138 | auto child = T::Deserialize(*this, std::forward<ARGS>(args)...); |
139 | list.push_back(std::move(child)); |
140 | } |
141 | } |
142 | |
143 | template <class T, class RETURN_TYPE = T, typename... ARGS> |
144 | unique_ptr<RETURN_TYPE> ReadOptional(ARGS &&... args) { |
145 | auto has_entry = Read<bool>(); |
146 | if (has_entry) { |
147 | return T::Deserialize(*this, std::forward<ARGS>(args)...); |
148 | } |
149 | return nullptr; |
150 | } |
151 | |
152 | void ReadStringVector(vector<string> &list); |
153 | }; |
154 | |
155 | template <> |
156 | DUCKDB_API string Deserializer::Read(); |
157 | |
158 | } // namespace duckdb |
159 | |