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
17namespace duckdb {
18
19//! The Serialize class is a base class that can be used to serializing objects into a binary buffer
20class Serializer {
21private:
22 uint64_t version = 0L;
23
24public:
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
93class Deserializer {
94private:
95 uint64_t version = 0L;
96
97public:
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
155template <>
156DUCKDB_API string Deserializer::Read();
157
158} // namespace duckdb
159