/src/Fast-DDS/src/cpp/rtps/persistence/SQLite3PersistenceService.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2018 Proyectos y Sistemas de Mantenimiento SL (eProsima). |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | /** |
16 | | * @file SQLite3PersistenceService.cpp |
17 | | * |
18 | | */ |
19 | | |
20 | | #include <rtps/persistence/SQLite3PersistenceService.h> |
21 | | #include <rtps/persistence/SQLite3PersistenceServiceStatements.h> |
22 | | #include <fastdds/dds/log/Log.hpp> |
23 | | #include <fastdds/rtps/history/WriterHistory.hpp> |
24 | | |
25 | | #include <rtps/persistence/sqlite3.h> |
26 | | |
27 | | #include <sstream> |
28 | | |
29 | | namespace eprosima { |
30 | | namespace fastdds { |
31 | | namespace rtps { |
32 | | |
33 | | /** |
34 | | * @brief Retrieve the schema version of the database |
35 | | * @param db [IN] Database of which we want to get the schema version |
36 | | * @return Integer representing the schema version. Zero if an error occurs during the processing. |
37 | | */ |
38 | | static unsigned int database_version( |
39 | | sqlite3* db) |
40 | 0 | { |
41 | 0 | sqlite3_stmt* version_stmt; |
42 | 0 | unsigned int version = 1; |
43 | 0 | if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &version_stmt, NULL) != SQLITE_OK) |
44 | 0 | { |
45 | 0 | return 0; |
46 | 0 | } |
47 | | |
48 | 0 | if (SQLITE_ROW == sqlite3_step(version_stmt)) |
49 | 0 | { |
50 | 0 | version = sqlite3_column_int(version_stmt, 0); |
51 | 0 | if (version == 0) |
52 | 0 | { |
53 | | //No version information. It really means version 1 |
54 | 0 | version = 1; |
55 | 0 | } |
56 | 0 | } |
57 | 0 | sqlite3_finalize(version_stmt); |
58 | 0 | return version; |
59 | 0 | } |
60 | | |
61 | | static int upgrade( |
62 | | sqlite3* db, |
63 | | int from, |
64 | | int to) |
65 | 0 | { |
66 | 0 | if (from == to) |
67 | 0 | { |
68 | 0 | return SQLITE_OK; |
69 | 0 | } |
70 | | |
71 | 0 | if (from == 1 && to == 2) |
72 | 0 | { |
73 | 0 | return sqlite3_exec(db, SQLite3PersistenceServiceSchemaV2::update_from_v1_statement().c_str(), 0, 0, 0); |
74 | 0 | } |
75 | | |
76 | 0 | if (from == 2 && to == 3 |
77 | 0 | && SQLite3PersistenceServiceSchemaV3::database_create_temporary_defaults_table(db)) |
78 | 0 | { |
79 | 0 | return sqlite3_exec(db, SQLite3PersistenceServiceSchemaV3::update_from_v2_statement().c_str(), 0, 0, 0); |
80 | 0 | } |
81 | | |
82 | | // iterate if not direct upgrade |
83 | 0 | if (from < to) |
84 | 0 | { |
85 | 0 | if (SQLITE_ERROR != upgrade(db, from, to - 1)) |
86 | 0 | { |
87 | 0 | return upgrade(db, to - 1, to); |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | | // unsupported upgrade path |
92 | 0 | EPROSIMA_LOG_ERROR(RTPS_PERSISTENCE, "Unsupported database upgrade from version " << from << " to version " << to); |
93 | 0 | return SQLITE_ERROR; |
94 | 0 | } |
95 | | |
96 | | static sqlite3* open_or_create_database( |
97 | | const char* filename, |
98 | | bool update_schema) |
99 | 0 | { |
100 | 0 | sqlite3* db = NULL; |
101 | 0 | int rc; |
102 | 0 | int version = 3; |
103 | | |
104 | | // Open database |
105 | 0 | int flags = SQLITE_OPEN_READWRITE | |
106 | 0 | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE; |
107 | 0 | rc = sqlite3_open_v2(filename, &db, flags, 0); // malloc that is not erased |
108 | 0 | if (rc != SQLITE_OK) |
109 | 0 | { |
110 | | // In case file cantopen, memory is reserved in db, so it must be free (for valgrind sake) |
111 | 0 | if (rc == SQLITE_CANTOPEN) |
112 | 0 | { |
113 | 0 | sqlite3_close(db); |
114 | 0 | } |
115 | | |
116 | | //probably the database does not exists. Create new and no need to upgrade schema |
117 | 0 | flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | |
118 | 0 | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE; |
119 | 0 | rc = sqlite3_open_v2(filename, &db, flags, 0); |
120 | 0 | if (rc != SQLITE_OK) |
121 | 0 | { |
122 | 0 | EPROSIMA_LOG_ERROR(RTPS_PERSISTENCE, "Unable to create persistence database " << filename); |
123 | 0 | sqlite3_close(db); |
124 | 0 | return NULL; |
125 | 0 | } |
126 | 0 | } |
127 | 0 | else |
128 | 0 | { |
129 | | // Find the database version and handle upgrades |
130 | 0 | int db_version = database_version(db); |
131 | 0 | if (db_version == 0) |
132 | 0 | { |
133 | 0 | EPROSIMA_LOG_ERROR(RTPS_PERSISTENCE, "Error retrieving version on database " << filename); |
134 | 0 | sqlite3_close(db); |
135 | 0 | return NULL; |
136 | 0 | } |
137 | 0 | if (db_version != version) |
138 | 0 | { |
139 | 0 | if (update_schema) |
140 | 0 | { |
141 | 0 | rc = upgrade(db, db_version, version); |
142 | 0 | if (rc != SQLITE_OK) |
143 | 0 | { |
144 | 0 | sqlite3_close(db); |
145 | 0 | return NULL; |
146 | 0 | } |
147 | 0 | } |
148 | 0 | else |
149 | 0 | { |
150 | 0 | EPROSIMA_LOG_ERROR(RTPS_PERSISTENCE, "Old schema version " << db_version << " on database " << filename |
151 | 0 | << ". Set property dds.persistence.update_schema to force automatic schema upgrade"); |
152 | 0 | sqlite3_close(db); |
153 | 0 | return NULL; |
154 | 0 | } |
155 | |
|
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | // Create tables if they don't exist |
160 | 0 | rc = sqlite3_exec(db, SQLite3PersistenceServiceSchemaV3::database_create_statement().c_str(), 0, 0, 0); |
161 | 0 | if (rc != SQLITE_OK) |
162 | 0 | { |
163 | 0 | sqlite3_close(db); |
164 | 0 | return NULL; |
165 | 0 | } |
166 | | |
167 | 0 | return db; |
168 | 0 | } |
169 | | |
170 | | static void finalize_statement( |
171 | | sqlite3_stmt*& stmt) |
172 | 0 | { |
173 | 0 | if (stmt != NULL) |
174 | 0 | { |
175 | 0 | int res = sqlite3_finalize(stmt); |
176 | 0 | if (res != SQLITE_OK) |
177 | 0 | { |
178 | 0 | EPROSIMA_LOG_WARNING(RTPS_PERSISTENCE, "Statement could not be finalized. sqlite3_finalize code: " << res); |
179 | 0 | } |
180 | 0 | stmt = NULL; |
181 | 0 | } |
182 | 0 | } |
183 | | |
184 | | IPersistenceService* create_SQLite3_persistence_service( |
185 | | const char* filename, |
186 | | bool update_schema) |
187 | 0 | { |
188 | 0 | sqlite3* db = open_or_create_database(filename, update_schema); |
189 | 0 | return (db == NULL) ? nullptr : new SQLite3PersistenceService(db); |
190 | 0 | } |
191 | | |
192 | | SQLite3PersistenceService::SQLite3PersistenceService( |
193 | | sqlite3* db) |
194 | 0 | : db_(db) |
195 | | , load_writer_stmt_(NULL) |
196 | | , add_writer_change_stmt_(NULL) |
197 | | , remove_writer_change_stmt_(NULL) |
198 | | , load_writer_last_seq_num_stmt_(NULL) |
199 | | , update_writer_last_seq_num_stmt_(NULL) |
200 | | , load_reader_stmt_(NULL) |
201 | | , update_reader_stmt_(NULL) |
202 | 0 | { |
203 | | // Prepare writer statements |
204 | 0 | sqlite3_prepare_v3(db_, "SELECT seq_num, instance, payload, related_sample_guid, related_sample_seq_num, source_timestamp " |
205 | 0 | "FROM writers_histories WHERE guid=?;", -1, |
206 | 0 | SQLITE_PREPARE_PERSISTENT, |
207 | 0 | &load_writer_stmt_, |
208 | 0 | NULL); |
209 | 0 | sqlite3_prepare_v3(db_, "INSERT INTO writers_histories VALUES(?,?,?,?,?,?,?);", -1, SQLITE_PREPARE_PERSISTENT, |
210 | 0 | &add_writer_change_stmt_, NULL); |
211 | 0 | sqlite3_prepare_v3(db_, "DELETE FROM writers_histories WHERE guid=? AND seq_num=?;", -1, SQLITE_PREPARE_PERSISTENT, |
212 | 0 | &remove_writer_change_stmt_, NULL); |
213 | |
|
214 | 0 | sqlite3_prepare_v3(db_, "SELECT last_seq_num FROM writers_states WHERE guid=?;", -1, SQLITE_PREPARE_PERSISTENT, |
215 | 0 | &load_writer_last_seq_num_stmt_, NULL); |
216 | 0 | sqlite3_prepare_v3(db_, "INSERT OR REPLACE INTO writers_states VALUES(?,?);", -1, SQLITE_PREPARE_PERSISTENT, |
217 | 0 | &update_writer_last_seq_num_stmt_, NULL); |
218 | | |
219 | | // Prepare reader statements |
220 | 0 | sqlite3_prepare_v3(db_, "SELECT writer_guid_prefix,writer_guid_entity,seq_num FROM readers WHERE guid=?;", -1, |
221 | 0 | SQLITE_PREPARE_PERSISTENT, &load_reader_stmt_, NULL); |
222 | 0 | sqlite3_prepare_v3(db_, "INSERT OR REPLACE INTO readers VALUES(?,?,?,?);", -1, SQLITE_PREPARE_PERSISTENT, |
223 | 0 | &update_reader_stmt_, NULL); |
224 | 0 | } |
225 | | |
226 | | SQLite3PersistenceService::~SQLite3PersistenceService() |
227 | 0 | { |
228 | | // Finalize writer statements |
229 | 0 | finalize_statement(load_writer_stmt_); |
230 | 0 | finalize_statement(add_writer_change_stmt_); |
231 | 0 | finalize_statement(remove_writer_change_stmt_); |
232 | | |
233 | | // Finalize reader statements |
234 | 0 | finalize_statement(load_reader_stmt_); |
235 | 0 | finalize_statement(update_reader_stmt_); |
236 | | |
237 | | // Finalize writer seq_num statements |
238 | 0 | finalize_statement(load_writer_last_seq_num_stmt_); |
239 | 0 | finalize_statement(update_writer_last_seq_num_stmt_); |
240 | |
|
241 | 0 | int res = sqlite3_close(db_); |
242 | 0 | if (res != SQLITE_OK) // (0) SQLITE_OK |
243 | 0 | { |
244 | 0 | EPROSIMA_LOG_ERROR(RTPS_PERSISTENCE, "Database could not be closed. sqlite3_close code: " << res); |
245 | 0 | } |
246 | 0 | db_ = NULL; |
247 | 0 | } |
248 | | |
249 | | /** |
250 | | * Get all data stored for a writer. |
251 | | * |
252 | | * @param [in] persistence_guid GUID of the writer used to store samples. |
253 | | * @param [in] writer_guid GUID of the writer to load. |
254 | | * @param [in,out] history History of the writer to load. |
255 | | * @param [out] next_sequence Sequence that should be applied to the next created sample. |
256 | | * |
257 | | * @return True if operation was successful. |
258 | | */ |
259 | | bool SQLite3PersistenceService::load_writer_from_storage( |
260 | | const std::string& persistence_guid, |
261 | | const GUID_t& writer_guid, |
262 | | WriterHistory* history, |
263 | | SequenceNumber_t& next_sequence) |
264 | 0 | { |
265 | 0 | EPROSIMA_LOG_INFO(RTPS_PERSISTENCE, "Loading writer " << writer_guid); |
266 | |
|
267 | 0 | if (load_writer_stmt_ != NULL) |
268 | 0 | { |
269 | 0 | sqlite3_reset(load_writer_stmt_); |
270 | 0 | sqlite3_bind_text(load_writer_stmt_, 1, persistence_guid.c_str(), -1, SQLITE_STATIC); |
271 | |
|
272 | 0 | std::vector<CacheChange_t*>& changes = get_changes(history); |
273 | |
|
274 | 0 | while (SQLITE_ROW == sqlite3_step(load_writer_stmt_)) |
275 | 0 | { |
276 | 0 | SequenceNumber_t sn(sqlite3_column_int64(load_writer_stmt_, 0)); |
277 | 0 | CacheChange_t* change = nullptr; |
278 | 0 | int size = sqlite3_column_bytes(load_writer_stmt_, 2); |
279 | |
|
280 | 0 | change = history->create_change(size, ALIVE); |
281 | 0 | if (nullptr == change) |
282 | 0 | { |
283 | 0 | continue; |
284 | 0 | } |
285 | | |
286 | 0 | SampleIdentity identity; |
287 | 0 | identity.writer_guid(writer_guid); |
288 | 0 | identity.sequence_number(sn); |
289 | |
|
290 | 0 | int instance_size = sqlite3_column_bytes(load_writer_stmt_, 1); |
291 | 0 | instance_size = (instance_size > 16) ? 16 : instance_size; |
292 | 0 | change->kind = ALIVE; |
293 | 0 | change->writerGUID = writer_guid; |
294 | 0 | memcpy(change->instanceHandle.value, sqlite3_column_blob(load_writer_stmt_, 1), instance_size); |
295 | 0 | change->sequenceNumber = identity.sequence_number(); |
296 | 0 | change->serializedPayload.length = size; |
297 | 0 | memcpy(change->serializedPayload.data, sqlite3_column_blob(load_writer_stmt_, 2), size); |
298 | 0 | change->writer_info.previous = nullptr; |
299 | 0 | change->writer_info.next = nullptr; |
300 | 0 | change->writer_info.num_sent_submessages = 0; |
301 | 0 | change->vendor_id = c_VendorId_eProsima; |
302 | | |
303 | | // related sample identity |
304 | 0 | { |
305 | 0 | using namespace std; |
306 | | // GUID_t |
307 | 0 | istringstream is(string(reinterpret_cast<const char*>(sqlite3_column_text(load_writer_stmt_, 3)))); |
308 | 0 | auto& si = change->write_params.related_sample_identity(); |
309 | 0 | is >> si.writer_guid(); |
310 | | // Sequence Number |
311 | 0 | SequenceNumber_t rsn(sqlite3_column_int64(load_writer_stmt_, 4)); |
312 | 0 | si.sequence_number(rsn); |
313 | 0 | } |
314 | | |
315 | | // timestamp |
316 | 0 | change->sourceTimestamp.from_ns(sqlite3_column_int64(load_writer_stmt_, 5)); |
317 | |
|
318 | 0 | set_fragments(history, change); |
319 | |
|
320 | 0 | changes.insert(changes.begin(), change); |
321 | 0 | } |
322 | |
|
323 | 0 | sqlite3_reset(load_writer_last_seq_num_stmt_); |
324 | 0 | sqlite3_bind_text(load_writer_last_seq_num_stmt_, 1, persistence_guid.c_str(), -1, SQLITE_STATIC); |
325 | |
|
326 | 0 | while (SQLITE_ROW == sqlite3_step(load_writer_last_seq_num_stmt_)) |
327 | 0 | { |
328 | 0 | next_sequence = SequenceNumber_t(sqlite3_column_int64(load_writer_last_seq_num_stmt_, 0)); |
329 | 0 | } |
330 | 0 | } |
331 | |
|
332 | 0 | return true; |
333 | 0 | } |
334 | | |
335 | | /** |
336 | | * Add a change to storage. |
337 | | * @param change The cache change to add. |
338 | | * @return True if operation was successful. |
339 | | */ |
340 | | bool SQLite3PersistenceService::add_writer_change_to_storage( |
341 | | const std::string& persistence_guid, |
342 | | const CacheChange_t& change) |
343 | 0 | { |
344 | 0 | EPROSIMA_LOG_INFO(RTPS_PERSISTENCE, |
345 | 0 | "Writer " << change.writerGUID << " storing change for seq " << change.sequenceNumber); |
346 | |
|
347 | 0 | if (add_writer_change_stmt_ != NULL) |
348 | 0 | { |
349 | | //First add the last seq number, it is needed for the foreign key on writers_histories |
350 | 0 | sqlite3_reset(update_writer_last_seq_num_stmt_); |
351 | 0 | sqlite3_bind_text(update_writer_last_seq_num_stmt_, 1, persistence_guid.c_str(), -1, SQLITE_STATIC); |
352 | 0 | sqlite3_bind_int64(update_writer_last_seq_num_stmt_, 2, change.sequenceNumber.to64long()); |
353 | |
|
354 | 0 | if (sqlite3_step(update_writer_last_seq_num_stmt_) == SQLITE_DONE) |
355 | 0 | { |
356 | 0 | sqlite3_reset(add_writer_change_stmt_); |
357 | 0 | sqlite3_bind_text(add_writer_change_stmt_, 1, persistence_guid.c_str(), -1, SQLITE_STATIC); |
358 | 0 | sqlite3_bind_int64(add_writer_change_stmt_, 2, change.sequenceNumber.to64long()); |
359 | 0 | if (change.instanceHandle.isDefined()) |
360 | 0 | { |
361 | 0 | sqlite3_bind_blob(add_writer_change_stmt_, 3, change.instanceHandle.value, 16, SQLITE_STATIC); |
362 | 0 | } |
363 | 0 | else |
364 | 0 | { |
365 | 0 | sqlite3_bind_zeroblob(add_writer_change_stmt_, 3, 16); |
366 | 0 | } |
367 | 0 | sqlite3_bind_blob(add_writer_change_stmt_, 4, change.serializedPayload.data, |
368 | 0 | change.serializedPayload.length, SQLITE_STATIC); |
369 | | |
370 | | // related sample identity |
371 | 0 | std::ostringstream os; |
372 | 0 | auto& si = change.write_params.related_sample_identity(); |
373 | 0 | os << si.writer_guid(); |
374 | | |
375 | | // IMPORTANT: this element must survive until the call (sqlite3_step) has been fulfilled. |
376 | | // Another way would be to use SQLITE_TRANSIENT instead of static, forcing an internal copy, |
377 | | // but this way a copy is saved (with cost of taking care that this string should survive) |
378 | 0 | std::string guids = os.str(); |
379 | |
|
380 | 0 | sqlite3_bind_text(add_writer_change_stmt_, 5, guids.c_str(), -1, SQLITE_STATIC); |
381 | 0 | sqlite3_bind_int64(add_writer_change_stmt_, 6, si.sequence_number().to64long()); |
382 | | |
383 | | // source time stamp |
384 | 0 | sqlite3_bind_int64(add_writer_change_stmt_, 7, change.sourceTimestamp.to_ns()); |
385 | |
|
386 | 0 | return sqlite3_step(add_writer_change_stmt_) == SQLITE_DONE; |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | 0 | return false; |
391 | 0 | } |
392 | | |
393 | | /** |
394 | | * Remove a change from storage. |
395 | | * @param change The cache change to remove. |
396 | | * @return True if operation was successful. |
397 | | */ |
398 | | bool SQLite3PersistenceService::remove_writer_change_from_storage( |
399 | | const std::string& persistence_guid, |
400 | | const CacheChange_t& change) |
401 | 0 | { |
402 | 0 | EPROSIMA_LOG_INFO(RTPS_PERSISTENCE, |
403 | 0 | "Writer " << change.writerGUID << " removing change for seq " << change.sequenceNumber); |
404 | |
|
405 | 0 | if (remove_writer_change_stmt_ != NULL) |
406 | 0 | { |
407 | 0 | sqlite3_reset(remove_writer_change_stmt_); |
408 | 0 | sqlite3_bind_text(remove_writer_change_stmt_, 1, persistence_guid.c_str(), -1, SQLITE_STATIC); |
409 | 0 | sqlite3_bind_int64(remove_writer_change_stmt_, 2, change.sequenceNumber.to64long()); |
410 | 0 | return sqlite3_step(remove_writer_change_stmt_) == SQLITE_DONE; |
411 | 0 | } |
412 | | |
413 | 0 | return false; |
414 | 0 | } |
415 | | |
416 | | /** |
417 | | * Get all data stored for a reader. |
418 | | * @param reader_guid GUID of the reader to load. |
419 | | * @return True if operation was successful. |
420 | | */ |
421 | | bool SQLite3PersistenceService::load_reader_from_storage( |
422 | | const std::string& reader_guid, |
423 | | foonathan::memory::map<GUID_t, SequenceNumber_t, IPersistenceService::map_allocator_t>& seq_map) |
424 | 0 | { |
425 | 0 | EPROSIMA_LOG_INFO(RTPS_PERSISTENCE, "Loading reader " << reader_guid); |
426 | |
|
427 | 0 | if (load_reader_stmt_ != NULL) |
428 | 0 | { |
429 | 0 | sqlite3_reset(load_reader_stmt_); |
430 | 0 | sqlite3_bind_text(load_reader_stmt_, 1, reader_guid.c_str(), -1, SQLITE_STATIC); |
431 | |
|
432 | 0 | while (SQLITE_ROW == sqlite3_step(load_reader_stmt_)) |
433 | 0 | { |
434 | 0 | GUID_t guid; |
435 | 0 | memcpy(guid.guidPrefix.value, sqlite3_column_blob(load_reader_stmt_, 0), GuidPrefix_t::size); |
436 | 0 | memcpy(guid.entityId.value, sqlite3_column_blob(load_reader_stmt_, 1), EntityId_t::size); |
437 | 0 | sqlite3_int64 sn = sqlite3_column_int64(load_reader_stmt_, 2); |
438 | 0 | SequenceNumber_t seq((int32_t)((sn >> 32) & 0xFFFFFFFF), (uint32_t)(sn & 0xFFFFFFFF)); |
439 | 0 | seq_map[guid] = seq; |
440 | 0 | } |
441 | 0 | } |
442 | |
|
443 | 0 | return true; |
444 | 0 | } |
445 | | |
446 | | /** |
447 | | * Update the sequence number associated to a writer on a reader. |
448 | | * @param reader_guid GUID of the reader to update. |
449 | | * @param writer_guid GUID of the associated writer to update. |
450 | | * @param seq_number New sequence number value to set for the associated writer. |
451 | | * @return True if operation was successful. |
452 | | */ |
453 | | bool SQLite3PersistenceService::update_writer_seq_on_storage( |
454 | | const std::string& reader_guid, |
455 | | const GUID_t& writer_guid, |
456 | | const SequenceNumber_t& seq_number) |
457 | 0 | { |
458 | 0 | EPROSIMA_LOG_INFO(RTPS_PERSISTENCE, |
459 | 0 | "Reader " << reader_guid << " setting seq for writer " << writer_guid << " to " << seq_number); |
460 | |
|
461 | 0 | if (update_reader_stmt_ != NULL) |
462 | 0 | { |
463 | 0 | sqlite3_reset(update_reader_stmt_); |
464 | 0 | sqlite3_bind_text(update_reader_stmt_, 1, reader_guid.c_str(), -1, SQLITE_STATIC); |
465 | 0 | sqlite3_bind_blob(update_reader_stmt_, 2, writer_guid.guidPrefix.value, GuidPrefix_t::size, SQLITE_STATIC); |
466 | 0 | sqlite3_bind_blob(update_reader_stmt_, 3, writer_guid.entityId.value, EntityId_t::size, SQLITE_STATIC); |
467 | 0 | sqlite3_bind_int64(update_reader_stmt_, 4, seq_number.to64long()); |
468 | 0 | return sqlite3_step(update_reader_stmt_) == SQLITE_DONE; |
469 | 0 | } |
470 | | |
471 | 0 | return false; |
472 | 0 | } |
473 | | |
474 | | bool SQLite3PersistenceServiceSchemaV3::database_create_temporary_defaults_table( |
475 | | sqlite3* db) |
476 | 0 | { |
477 | 0 | using namespace std; |
478 | |
|
479 | 0 | sqlite3_stmt* insert_default_stmt; |
480 | | |
481 | | // create temporary table |
482 | 0 | int rc = sqlite3_exec( |
483 | 0 | db, |
484 | 0 | "CREATE TEMP TABLE IF NOT EXISTS Defaults (Name TEST PRIMARY KEY, Value TEST);", |
485 | 0 | 0, 0, 0); |
486 | |
|
487 | 0 | if (rc != SQLITE_OK) |
488 | 0 | { |
489 | 0 | return false; |
490 | 0 | } |
491 | | |
492 | | // Insert default values |
493 | 0 | sqlite3_prepare_v3( |
494 | 0 | db, |
495 | 0 | "INSERT OR REPLACE INTO TEMP.Defaults VALUES (?, ?);", |
496 | 0 | -1, SQLITE_PREPARE_PERSISTENT, |
497 | 0 | &insert_default_stmt, NULL); |
498 | | |
499 | | // Default GUID_t value |
500 | 0 | sqlite3_reset(insert_default_stmt); |
501 | 0 | sqlite3_bind_text(insert_default_stmt, 1, "GUID_t", -1, SQLITE_STATIC); |
502 | 0 | sqlite3_bind_text(insert_default_stmt, 2, SQLite3PersistenceServiceSchemaV3::default_guid(), -1, SQLITE_STATIC); |
503 | 0 | rc = sqlite3_step(insert_default_stmt); |
504 | |
|
505 | 0 | if (rc != SQLITE_DONE) |
506 | 0 | { |
507 | 0 | return false; |
508 | 0 | } |
509 | | |
510 | | // Default SequenceNumber_t |
511 | 0 | sqlite3_reset(insert_default_stmt); |
512 | 0 | sqlite3_bind_text(insert_default_stmt, 1, "SequenceNumber_t", -1, SQLITE_STATIC); |
513 | 0 | sqlite3_bind_int64(insert_default_stmt, 2, SQLite3PersistenceServiceSchemaV3::default_seqnum()); |
514 | 0 | rc = sqlite3_step(insert_default_stmt); |
515 | |
|
516 | 0 | if (rc != SQLITE_DONE) |
517 | 0 | { |
518 | 0 | return false; |
519 | 0 | } |
520 | | |
521 | | // Default rtps::Time_t |
522 | 0 | sqlite3_reset(insert_default_stmt); |
523 | 0 | sqlite3_bind_text(insert_default_stmt, 1, "rtps::Time_t", -1, SQLITE_STATIC); |
524 | |
|
525 | 0 | sqlite3_bind_int64(insert_default_stmt, 2, SQLite3PersistenceServiceSchemaV3::now()); |
526 | 0 | rc = sqlite3_step(insert_default_stmt); |
527 | |
|
528 | 0 | if (rc != SQLITE_DONE) |
529 | 0 | { |
530 | 0 | return false; |
531 | 0 | } |
532 | | |
533 | | // free resources |
534 | 0 | finalize_statement(insert_default_stmt); |
535 | |
|
536 | 0 | return true; |
537 | 0 | } |
538 | | |
539 | | const char* SQLite3PersistenceServiceSchemaV3::default_guid() |
540 | 0 | { |
541 | 0 | using namespace std; |
542 | |
|
543 | 0 | static string def_guid; |
544 | |
|
545 | 0 | if (def_guid.empty()) |
546 | 0 | { |
547 | 0 | ostringstream ss; |
548 | 0 | auto def = GUID_t::unknown(); |
549 | 0 | ss << def; |
550 | 0 | def_guid = ss.str(); |
551 | 0 | } |
552 | |
|
553 | 0 | return def_guid.c_str(); |
554 | 0 | } |
555 | | |
556 | | uint64_t SQLite3PersistenceServiceSchemaV3::default_seqnum() |
557 | 0 | { |
558 | 0 | return SequenceNumber_t::unknown().to64long(); |
559 | 0 | } |
560 | | |
561 | | int64_t SQLite3PersistenceServiceSchemaV3::now() |
562 | 0 | { |
563 | 0 | Time_t ts; |
564 | 0 | Time_t::now(ts); |
565 | 0 | return ts.to_ns(); |
566 | 0 | } |
567 | | |
568 | | } /* namespace rtps */ |
569 | | } /* namespace fastdds */ |
570 | | } /* namespace eprosima */ |