Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
database_protocol.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#include "database_protocol.h"
6#include <cstring>
7
9
10// Protocol serialization implementation
11std::vector<uint8_t> protocol_serializer::serialize_header(const message_header& header) {
12 std::vector<uint8_t> buffer;
13 buffer.reserve(20); // Header size
14
15 write_uint32(buffer, header.magic);
16 write_uint16(buffer, header.version);
17 write_uint16(buffer, static_cast<uint16_t>(header.type));
18 write_uint64(buffer, header.request_id);
19 write_uint32(buffer, header.payload_size);
20
21 return buffer;
22}
23
24kcenon::common::Result<message_header> protocol_serializer::deserialize_header(const std::vector<uint8_t>& data) {
25 if (data.size() < 20) {
26 return error_info{static_cast<int>(error_code::invalid_argument), "Header too small"};
27 }
28
29 message_header header;
30 size_t offset = 0;
31
32 header.magic = read_uint32(data, offset);
33 header.version = read_uint16(data, offset);
34 header.type = static_cast<message_type>(read_uint16(data, offset));
35 header.request_id = read_uint64(data, offset);
36 header.payload_size = read_uint32(data, offset);
37
38 if (!header.is_valid()) {
39 return error_info{static_cast<int>(error_code::invalid_argument), "Invalid header magic or version"};
40 }
41
42 return header;
43}
44
45// Implementations for request/response serialization
46std::vector<uint8_t> protocol_serializer::serialize(const connect_request& request) {
47 std::vector<uint8_t> buffer;
48 write_string(buffer, request.database_type);
49 write_string(buffer, request.connection_string);
50
51 // Serialize options map
52 write_uint32(buffer, static_cast<uint32_t>(request.options.size()));
53 for (const auto& [key, value] : request.options) {
54 write_string(buffer, key);
55 write_string(buffer, value);
56 }
57
58 return buffer;
59}
60
61kcenon::common::Result<connect_request> protocol_serializer::deserialize_connect_request(const std::vector<uint8_t>& data) {
62 connect_request request;
63 size_t offset = 0;
64 if (data.size() < 4) {
65 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small"};
66 }
67 request.database_type = read_string(data, offset);
68 request.connection_string = read_string(data, offset);
69
70 // Deserialize options map
71 if (offset + 4 > data.size()) {
72 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small for options"};
73 }
74 uint32_t options_count = read_uint32(data, offset);
75 for (uint32_t i = 0; i < options_count; ++i) {
76 if (offset >= data.size()) {
77 return error_info{static_cast<int>(error_code::invalid_argument), "Data truncated in options"};
78 }
79 std::string key = read_string(data, offset);
80 std::string value = read_string(data, offset);
81 request.options[key] = value;
82 }
83
84 return request;
85}
86
87std::vector<uint8_t> protocol_serializer::serialize(const query_request& request) {
88 std::vector<uint8_t> buffer;
89 write_uint8(buffer, static_cast<uint8_t>(request.operation));
90 write_string(buffer, request.query_string);
91
92 // Serialize parameters vector
93 write_uint32(buffer, static_cast<uint32_t>(request.parameters.size()));
94 for (const auto& param : request.parameters) {
95 write_string(buffer, param);
96 }
97
98 return buffer;
99}
100
101kcenon::common::Result<query_request> protocol_serializer::deserialize_query_request(const std::vector<uint8_t>& data) {
102 query_request request;
103 size_t offset = 0;
104 if (data.empty()) {
105 return error_info{static_cast<int>(error_code::invalid_argument), "Empty data"};
106 }
107 request.operation = static_cast<query_operation>(read_uint8(data, offset));
108 request.query_string = read_string(data, offset);
109
110 // Deserialize parameters vector
111 if (offset + 4 > data.size()) {
112 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small for parameters"};
113 }
114 uint32_t param_count = read_uint32(data, offset);
115 request.parameters.reserve(param_count);
116 for (uint32_t i = 0; i < param_count; ++i) {
117 if (offset >= data.size()) {
118 return error_info{static_cast<int>(error_code::invalid_argument), "Data truncated in parameters"};
119 }
120 request.parameters.push_back(read_string(data, offset));
121 }
122
123 return request;
124}
125
126std::vector<uint8_t> protocol_serializer::serialize(const query_response& response) {
127 std::vector<uint8_t> buffer;
128 write_uint8(buffer, response.success ? 1 : 0);
129 write_uint64(buffer, response.affected_rows);
130 write_uint64(buffer, response.last_insert_id);
131 write_uint32(buffer, static_cast<uint32_t>(response.error_code));
132 write_string(buffer, response.error_message);
133
134 // Serialize column names
135 write_uint32(buffer, static_cast<uint32_t>(response.column_names.size()));
136 for (const auto& column : response.column_names) {
137 write_string(buffer, column);
138 }
139
140 // Serialize rows (vector of maps)
141 write_uint32(buffer, static_cast<uint32_t>(response.rows.size()));
142 for (const auto& row : response.rows) {
143 // Each row is a map<string, string>
144 write_uint32(buffer, static_cast<uint32_t>(row.size()));
145 for (const auto& [key, value] : row) {
146 write_string(buffer, key);
147 write_string(buffer, value);
148 }
149 }
150
151 return buffer;
152}
153
154kcenon::common::Result<query_response> protocol_serializer::deserialize_query_response(const std::vector<uint8_t>& data) {
155 query_response response;
156 size_t offset = 0;
157 if (data.empty()) {
158 return error_info{static_cast<int>(error_code::invalid_argument), "Empty data"};
159 }
160 response.success = (read_uint8(data, offset) != 0);
161 response.affected_rows = read_uint64(data, offset);
162 response.last_insert_id = read_uint64(data, offset);
163 response.error_code = static_cast<int32_t>(read_uint32(data, offset));
164 response.error_message = read_string(data, offset);
165
166 // Deserialize column names
167 if (offset + 4 > data.size()) {
168 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small for column names"};
169 }
170 uint32_t column_count = read_uint32(data, offset);
171 response.column_names.reserve(column_count);
172 for (uint32_t i = 0; i < column_count; ++i) {
173 if (offset >= data.size()) {
174 return error_info{static_cast<int>(error_code::invalid_argument), "Data truncated in column names"};
175 }
176 response.column_names.push_back(read_string(data, offset));
177 }
178
179 // Deserialize rows
180 if (offset + 4 > data.size()) {
181 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small for rows"};
182 }
183 uint32_t row_count = read_uint32(data, offset);
184 response.rows.reserve(row_count);
185 for (uint32_t i = 0; i < row_count; ++i) {
186 if (offset + 4 > data.size()) {
187 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small for row"};
188 }
189 uint32_t field_count = read_uint32(data, offset);
190 std::map<std::string, std::string> row;
191 for (uint32_t j = 0; j < field_count; ++j) {
192 if (offset >= data.size()) {
193 return error_info{static_cast<int>(error_code::invalid_argument), "Data truncated in row fields"};
194 }
195 std::string key = read_string(data, offset);
196 std::string value = read_string(data, offset);
197 row[key] = value;
198 }
199 response.rows.push_back(std::move(row));
200 }
201
202 return response;
203}
204
205std::vector<uint8_t> protocol_serializer::serialize(const connect_response& response) {
206 std::vector<uint8_t> buffer;
207 write_uint8(buffer, response.success ? 1 : 0);
208 write_string(buffer, response.session_id);
209 write_string(buffer, response.error_message);
210 return buffer;
211}
212
213kcenon::common::Result<connect_response> protocol_serializer::deserialize_connect_response(const std::vector<uint8_t>& data) {
214 connect_response response;
215 size_t offset = 0;
216 if (data.empty()) {
217 return error_info{static_cast<int>(error_code::invalid_argument), "Empty data"};
218 }
219 response.success = (read_uint8(data, offset) != 0);
220 response.session_id = read_string(data, offset);
221 response.error_message = read_string(data, offset);
222 return response;
223}
224
225std::vector<uint8_t> protocol_serializer::serialize(const transaction_request& request) {
226 std::vector<uint8_t> buffer;
227 write_uint16(buffer, static_cast<uint16_t>(request.operation));
228 return buffer;
229}
230
231kcenon::common::Result<transaction_request> protocol_serializer::deserialize_transaction_request(const std::vector<uint8_t>& data) {
232 transaction_request request;
233 size_t offset = 0;
234 if (data.size() < 2) {
235 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small"};
236 }
237 request.operation = static_cast<message_type>(read_uint16(data, offset));
238 return request;
239}
240
241std::vector<uint8_t> protocol_serializer::serialize(const error_response& response) {
242 std::vector<uint8_t> buffer;
243 write_uint32(buffer, response.error_code);
244 write_string(buffer, response.error_message);
245 write_string(buffer, response.error_context);
246 return buffer;
247}
248
249kcenon::common::Result<error_response> protocol_serializer::deserialize_error_response(const std::vector<uint8_t>& data) {
250 error_response response;
251 size_t offset = 0;
252 if (data.size() < 4) {
253 return error_info{static_cast<int>(error_code::invalid_argument), "Data too small"};
254 }
255 response.error_code = static_cast<int32_t>(read_uint32(data, offset));
256 response.error_message = read_string(data, offset);
257 response.error_context = read_string(data, offset);
258 return response;
259}
260
261std::vector<uint8_t> protocol_serializer::serialize(const transaction_response& response) {
262 std::vector<uint8_t> buffer;
263 write_uint8(buffer, response.success ? 1 : 0);
264 write_string(buffer, response.error_message);
265 return buffer;
266}
267
268kcenon::common::Result<transaction_response> protocol_serializer::deserialize_transaction_response(const std::vector<uint8_t>& data) {
269 transaction_response response;
270 size_t offset = 0;
271 if (data.empty()) {
272 return error_info{static_cast<int>(error_code::invalid_argument), "Empty data"};
273 }
274 response.success = (read_uint8(data, offset) != 0);
275 response.error_message = read_string(data, offset);
276 return response;
277}
278
279// Helper methods for primitive types (little-endian)
280void protocol_serializer::write_uint8(std::vector<uint8_t>& buffer, uint8_t value) {
281 buffer.push_back(value);
282}
283
284void protocol_serializer::write_uint16(std::vector<uint8_t>& buffer, uint16_t value) {
285 buffer.push_back(static_cast<uint8_t>(value & 0xFF));
286 buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));
287}
288
289void protocol_serializer::write_uint32(std::vector<uint8_t>& buffer, uint32_t value) {
290 buffer.push_back(static_cast<uint8_t>(value & 0xFF));
291 buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));
292 buffer.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));
293 buffer.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));
294}
295
296void protocol_serializer::write_uint64(std::vector<uint8_t>& buffer, uint64_t value) {
297 for (int i = 0; i < 8; ++i) {
298 buffer.push_back(static_cast<uint8_t>((value >> (i * 8)) & 0xFF));
299 }
300}
301
302void protocol_serializer::write_string(std::vector<uint8_t>& buffer, const std::string& value) {
303 write_uint32(buffer, static_cast<uint32_t>(value.size()));
304 buffer.insert(buffer.end(), value.begin(), value.end());
305}
306
307uint8_t protocol_serializer::read_uint8(const std::vector<uint8_t>& buffer, size_t& offset) {
308 return buffer[offset++];
309}
310
311uint16_t protocol_serializer::read_uint16(const std::vector<uint8_t>& buffer, size_t& offset) {
312 uint16_t value = buffer[offset] | (static_cast<uint16_t>(buffer[offset + 1]) << 8);
313 offset += 2;
314 return value;
315}
316
317uint32_t protocol_serializer::read_uint32(const std::vector<uint8_t>& buffer, size_t& offset) {
318 uint32_t value = buffer[offset] | (static_cast<uint32_t>(buffer[offset + 1]) << 8) |
319 (static_cast<uint32_t>(buffer[offset + 2]) << 16) |
320 (static_cast<uint32_t>(buffer[offset + 3]) << 24);
321 offset += 4;
322 return value;
323}
324
325uint64_t protocol_serializer::read_uint64(const std::vector<uint8_t>& buffer, size_t& offset) {
326 uint64_t value = 0;
327 for (int i = 0; i < 8; ++i) {
328 value |= (static_cast<uint64_t>(buffer[offset + i]) << (i * 8));
329 }
330 offset += 8;
331 return value;
332}
333
334std::string protocol_serializer::read_string(const std::vector<uint8_t>& buffer, size_t& offset) {
335 uint32_t length = read_uint32(buffer, offset);
336 if (length == 0) {
337 return "";
338 }
339 std::string value(reinterpret_cast<const char*>(&buffer[offset]), length);
340 offset += length;
341 return value;
342}
343
344} // namespace database::protocol
static std::string read_string(const std::vector< uint8_t > &buffer, size_t &offset)
static kcenon::common::Result< connect_request > deserialize_connect_request(const std::vector< uint8_t > &data)
Deserialize connect request.
static kcenon::common::Result< message_header > deserialize_header(const std::vector< uint8_t > &data)
Deserialize message header from bytes.
static void write_string(std::vector< uint8_t > &buffer, const std::string &value)
static void write_uint8(std::vector< uint8_t > &buffer, uint8_t value)
static uint32_t read_uint32(const std::vector< uint8_t > &buffer, size_t &offset)
static std::vector< uint8_t > serialize(const connect_request &request)
Serialize connect request.
static kcenon::common::Result< query_request > deserialize_query_request(const std::vector< uint8_t > &data)
Deserialize query request.
static void write_uint16(std::vector< uint8_t > &buffer, uint16_t value)
static void write_uint64(std::vector< uint8_t > &buffer, uint64_t value)
static kcenon::common::Result< connect_response > deserialize_connect_response(const std::vector< uint8_t > &data)
Deserialize connect response.
static std::vector< uint8_t > serialize_header(const message_header &header)
Serialize message header to bytes.
static kcenon::common::Result< transaction_response > deserialize_transaction_response(const std::vector< uint8_t > &data)
Deserialize transaction response.
static void write_uint32(std::vector< uint8_t > &buffer, uint32_t value)
static kcenon::common::Result< query_response > deserialize_query_response(const std::vector< uint8_t > &data)
Deserialize query response.
static uint16_t read_uint16(const std::vector< uint8_t > &buffer, size_t &offset)
static uint64_t read_uint64(const std::vector< uint8_t > &buffer, size_t &offset)
static kcenon::common::Result< error_response > deserialize_error_response(const std::vector< uint8_t > &data)
Deserialize error response.
static kcenon::common::Result< transaction_request > deserialize_transaction_request(const std::vector< uint8_t > &data)
Deserialize transaction request.
static uint8_t read_uint8(const std::vector< uint8_t > &buffer, size_t &offset)
message_type
Database protocol message types.
query_operation
Type of query operation.
kcenon::common::error_info error_info
Primary error type.
Definition result.h:36
std::map< std::string, std::string > options
Common header for all protocol messages.
bool is_valid() const
Validate message header.
std::vector< std::string > parameters
std::vector< std::map< std::string, std::string > > rows
std::vector< std::string > column_names