1 | /** |
2 | * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | * |
16 | * \author guonix |
17 | * \date Oct 2020 |
18 | * \brief |
19 | */ |
20 | |
21 | #include "sqlite_meta_store.h" |
22 | #include <ailego/hash/fnv1.h> |
23 | #include <ailego/internal/platform.h> |
24 | #include "common/error_code.h" |
25 | #include "common/logger.h" |
26 | #include "meta/meta_store_factory.h" |
27 | |
28 | namespace proxima { |
29 | namespace be { |
30 | namespace meta { |
31 | namespace sqlite { |
32 | |
33 | #define SQLITE_SQL_CODE(__VALUE__) SQLITE_SQL_HASH_##__VALUE__ |
34 | #define SQLITE_SQL_STR(__VALUE__) SQLITE_SQL##__VALUE__ |
35 | |
36 | #define DEFINE_SQLITE_SQL(__VALUE__, __SQL__) \ |
37 | constexpr const char *SQLITE_SQL##__VALUE__ = __SQL__; \ |
38 | constexpr uint32_t SQLITE_SQL_HASH_##__VALUE__ = ailego::Fnv1::Hash32(__SQL__) |
39 | |
40 | // Global Sql Statements |
41 | // Create Collection SQL |
42 | DEFINE_SQLITE_SQL(kCreateCollection, |
43 | "INSERT INTO " |
44 | "collections(name, uid, uuid, forward_columns, " |
45 | "max_docs_per_segment, revision, status, " |
46 | "current, io_mode) " |
47 | "VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9);" ); |
48 | |
49 | // Update Collection SQL |
50 | DEFINE_SQLITE_SQL( |
51 | kUpdateCollection, |
52 | "UPDATE collections set name=?1, uid=?2, " |
53 | "forward_columns=?3, max_docs_per_segment=?4, revision=?5, status=?6, " |
54 | "current=?7, io_mode=?8 WHERE uuid=?9;" ); |
55 | |
56 | // Delete Collection SQL |
57 | DEFINE_SQLITE_SQL(kDeleteCollection, "DELETE FROM collections WHERE name=?1;" ); |
58 | |
59 | // Delete Collection by uuid SQL |
60 | DEFINE_SQLITE_SQL(kDeleteCollectionByUUID, |
61 | "DELETE FROM collections WHERE uuid=?1;" ); |
62 | |
63 | // List All Collection SQL |
64 | DEFINE_SQLITE_SQL(kListAllCollections, "SELECT * from collections;" ); |
65 | |
66 | // Create Column SQL |
67 | DEFINE_SQLITE_SQL(kCreateColumn, |
68 | "INSERT INTO " |
69 | "columns(collection_uid, collection_uuid, name, uid, " |
70 | "dimension, index_type, " |
71 | "data_type, parameters) " |
72 | "VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);" ); |
73 | |
74 | // Delete Column SQL |
75 | DEFINE_SQLITE_SQL(kDeleteColumn, |
76 | "DELETE FROM columns WHERE collection_uid=?1;" ); |
77 | |
78 | // Delete Column by uuid SQL |
79 | DEFINE_SQLITE_SQL(kDeleteColumnByUUID, |
80 | "DELETE FROM columns WHERE collection_uuid=?1;" ); |
81 | |
82 | // List Column SQL |
83 | DEFINE_SQLITE_SQL(kListColumn, "SELECT * from columns;" ); |
84 | |
85 | // Create Repository SQL |
86 | DEFINE_SQLITE_SQL(kCreateRepository, |
87 | "INSERT INTO " |
88 | "database_repositories (name, collection_uid, " |
89 | "collection_uuid, table_name, connection, user, password) " |
90 | "VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7);" ); |
91 | |
92 | // Delete Repositories SQL |
93 | DEFINE_SQLITE_SQL(kDeleteRepositoriesByUID, |
94 | "DELETE FROM database_repositories WHERE collection_uid=?1;" ); |
95 | |
96 | // Delete Repositories SQL |
97 | DEFINE_SQLITE_SQL( |
98 | kDeleteRepositoriesByUUID, |
99 | "DELETE FROM database_repositories WHERE collection_uuid=?1;" ); |
100 | |
101 | // List All Repositories SQL |
102 | DEFINE_SQLITE_SQL(kListAllRepositories, "SELECT * from database_repositories;" ); |
103 | |
104 | |
105 | //! Constructor |
106 | SQLiteMetaStore::SQLiteMetaStore() = default; |
107 | |
108 | //! Destructor |
109 | SQLiteMetaStore::~SQLiteMetaStore() { |
110 | do_cleanup(); |
111 | } |
112 | |
113 | //! initialize metastore |
114 | int SQLiteMetaStore::initialize(const ailego::Uri *uri) { |
115 | ailego_assert_with(uri != nullptr, "Invalid uri param passed" ); |
116 | if (initialized_) { |
117 | return 0; |
118 | } |
119 | |
120 | if (!uri || !uri->is_valid()) { |
121 | return PROXIMA_BE_ERROR_CODE(RuntimeError); |
122 | } |
123 | |
124 | // check sqlite3 macro MULTITHREAD or SERIALIZED |
125 | if (sqlite3_threadsafe() == 0) { |
126 | LOG_ERROR( |
127 | "Sqlite should be compiled with macro SQLITE_THREADSAFE = 1 or 2" ); |
128 | return PROXIMA_BE_ERROR_CODE(RuntimeError); |
129 | } |
130 | |
131 | sqlite3 *handle = nullptr; |
132 | database_ = uri->path(); |
133 | int code = |
134 | sqlite3_open_v2(database_.c_str(), &handle, |
135 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); |
136 | if (code != SQLITE_OK) { |
137 | LOG_ERROR("Failed to open sqlite db. msg[%s]" , sqlite3_errstr(code)); |
138 | return PROXIMA_BE_ERROR_CODE(RuntimeError); |
139 | } |
140 | |
141 | //! Synchronize Schema |
142 | code = sync(handle); |
143 | if (code == 0) { |
144 | // init statements |
145 | code = init_statements(database_); |
146 | } |
147 | |
148 | if (code == 0) { |
149 | initialized_ = true; |
150 | } |
151 | |
152 | sqlite3_close(handle); |
153 | return code; |
154 | } |
155 | |
156 | int SQLiteMetaStore::cleanup() { |
157 | return do_cleanup(); |
158 | } |
159 | |
160 | #define SQLITE_METASTORE_INITIALIZE_CHECK() \ |
161 | if (!initialized_) return PROXIMA_BE_ERROR_CODE(RuntimeError) |
162 | |
163 | //! Create the collection |
164 | int SQLiteMetaStore::create_collection(const CollectionObject &collection) { |
165 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
166 | |
167 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kCreateCollection)); |
168 | |
169 | int code = stmt->exec( |
170 | [&collection](sqlite3_stmt *s) -> int { |
171 | sqlite3_bind_text(s, 1, collection.name().c_str(), |
172 | collection.name().length(), nullptr); |
173 | sqlite3_bind_text(s, 2, collection.uid().c_str(), |
174 | collection.uid().length(), nullptr); |
175 | sqlite3_bind_text(s, 3, collection.uuid().c_str(), |
176 | collection.uuid().length(), nullptr); |
177 | sqlite3_bind_text(s, 4, collection.forward_columns().c_str(), |
178 | collection.forward_columns().length(), nullptr); |
179 | sqlite3_bind_int64( |
180 | s, 5, |
181 | static_cast<sqlite3_int64>(collection.max_docs_per_segment())); |
182 | sqlite3_bind_int(s, 6, collection.revision()); |
183 | sqlite3_bind_int(s, 7, collection.status()); |
184 | sqlite3_bind_int(s, 8, collection.current()); |
185 | sqlite3_bind_int(s, 9, collection.io_mode()); |
186 | return 0; |
187 | }, |
188 | nullptr); |
189 | |
190 | if (code != 0) { |
191 | LOG_ERROR("Failed to create collection. code[%d]" , code); |
192 | } |
193 | return code; |
194 | } |
195 | |
196 | //! Update collection declaration |
197 | int SQLiteMetaStore::update_collection(const CollectionObject &collection) { |
198 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
199 | |
200 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kUpdateCollection)); |
201 | int code = stmt->exec( |
202 | [&collection](sqlite3_stmt *s) -> int { |
203 | sqlite3_bind_text(s, 1, collection.name().c_str(), |
204 | collection.name().length(), nullptr); |
205 | sqlite3_bind_text(s, 2, collection.uid().c_str(), |
206 | collection.uid().length(), nullptr); |
207 | sqlite3_bind_text(s, 3, collection.forward_columns().c_str(), |
208 | collection.forward_columns().length(), nullptr); |
209 | sqlite3_bind_int64( |
210 | s, 4, |
211 | static_cast<sqlite3_int64>(collection.max_docs_per_segment())); |
212 | sqlite3_bind_int(s, 5, collection.revision()); |
213 | sqlite3_bind_int(s, 6, collection.status()); |
214 | sqlite3_bind_int(s, 7, collection.current()); |
215 | sqlite3_bind_int(s, 8, collection.io_mode()); |
216 | sqlite3_bind_text(s, 9, collection.uuid().c_str(), |
217 | collection.uuid().length(), nullptr); |
218 | return 0; |
219 | }, |
220 | nullptr); |
221 | if (code != 0) { |
222 | LOG_ERROR("Failed to update collection. code[%d]" , code); |
223 | } |
224 | |
225 | return code; |
226 | } |
227 | |
228 | //! Delete collection |
229 | int SQLiteMetaStore::delete_collection(const std::string &name) { |
230 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
231 | |
232 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kDeleteCollection)); |
233 | |
234 | int code = stmt->exec( |
235 | [&name](sqlite3_stmt *s) -> int { |
236 | sqlite3_bind_text(s, 1, name.c_str(), name.length(), nullptr); |
237 | return 0; |
238 | }, |
239 | nullptr); |
240 | if (code != 0) { |
241 | LOG_ERROR("Failed to delete collection. code[%d]" , code); |
242 | } |
243 | |
244 | return code; |
245 | } |
246 | |
247 | int SQLiteMetaStore::delete_collection_by_uuid(const std::string &uuid) { |
248 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
249 | |
250 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kDeleteCollectionByUUID)); |
251 | |
252 | int code = stmt->exec( |
253 | [&uuid](sqlite3_stmt *s) -> int { |
254 | sqlite3_bind_text(s, 1, uuid.c_str(), uuid.length(), nullptr); |
255 | return 0; |
256 | }, |
257 | nullptr); |
258 | if (code != 0) { |
259 | LOG_ERROR("Failed to delete collection. code[%d]" , code); |
260 | } |
261 | |
262 | return code; |
263 | } |
264 | |
265 | namespace { |
266 | static std::function<int(sqlite3_stmt *)> BuildFetcher( |
267 | CollectionObject *collection_ptr) { |
268 | return [=](sqlite3_stmt *s) -> int { |
269 | collection_ptr->set_id(sqlite3_column_int64(s, 0)); |
270 | collection_ptr->mutable_name()->assign( |
271 | reinterpret_cast<const char *>(sqlite3_column_text(s, 1))); |
272 | collection_ptr->mutable_uid()->assign( |
273 | reinterpret_cast<const char *>(sqlite3_column_text(s, 2))); |
274 | collection_ptr->mutable_uuid()->assign( |
275 | reinterpret_cast<const char *>(sqlite3_column_text(s, 3))); |
276 | collection_ptr->mutable_forward_columns()->assign( |
277 | reinterpret_cast<const char *>(sqlite3_column_text(s, 4))); |
278 | collection_ptr->set_max_docs_per_segment(sqlite3_column_int64(s, 5)); |
279 | collection_ptr->set_revision(sqlite3_column_int(s, 6)); |
280 | collection_ptr->set_status(sqlite3_column_int(s, 7)); |
281 | collection_ptr->set_current(sqlite3_column_int(s, 8)); |
282 | collection_ptr->set_io_mode(sqlite3_column_int(s, 9)); |
283 | return 0; |
284 | }; |
285 | } |
286 | |
287 | static std::function<int(sqlite3_stmt *)> BuildFetcher(ColumnObject *column) { |
288 | return [=](sqlite3_stmt *s) -> int { |
289 | column->set_id(sqlite3_column_int64(s, 0)); |
290 | column->mutable_collection_uid()->assign( |
291 | reinterpret_cast<const char *>(sqlite3_column_text(s, 1))); |
292 | column->mutable_collection_uuid()->assign( |
293 | reinterpret_cast<const char *>(sqlite3_column_text(s, 2))); |
294 | column->mutable_name()->assign( |
295 | reinterpret_cast<const char *>(sqlite3_column_text(s, 3))); |
296 | column->mutable_uid()->assign( |
297 | reinterpret_cast<const char *>(sqlite3_column_text(s, 4))); |
298 | column->set_dimension(sqlite3_column_int(s, 5)); |
299 | column->set_index_type(sqlite3_column_int(s, 6)); |
300 | column->set_data_type(sqlite3_column_int(s, 7)); |
301 | column->mutable_parameters()->assign( |
302 | reinterpret_cast<const char *>(sqlite3_column_text(s, 8))); |
303 | return 0; |
304 | }; |
305 | } |
306 | |
307 | static std::function<int(sqlite3_stmt *)> BuildFetcher( |
308 | DatabaseRepositoryObject *repository) { |
309 | return [=](sqlite3_stmt *s) -> int { |
310 | repository->set_id(sqlite3_column_int64(s, 0)); |
311 | repository->mutable_name()->assign( |
312 | reinterpret_cast<const char *>(sqlite3_column_text(s, 1))); |
313 | repository->mutable_collection_uid()->assign( |
314 | reinterpret_cast<const char *>(sqlite3_column_text(s, 2))); |
315 | repository->mutable_collection_uuid()->assign( |
316 | reinterpret_cast<const char *>(sqlite3_column_text(s, 3))); |
317 | repository->mutable_table()->assign( |
318 | reinterpret_cast<const char *>(sqlite3_column_text(s, 4))); |
319 | repository->mutable_connection()->assign( |
320 | reinterpret_cast<const char *>(sqlite3_column_text(s, 5))); |
321 | repository->mutable_user()->assign( |
322 | reinterpret_cast<const char *>(sqlite3_column_text(s, 6))); |
323 | repository->mutable_password()->assign( |
324 | reinterpret_cast<const char *>(sqlite3_column_text(s, 7))); |
325 | return 0; |
326 | }; |
327 | } |
328 | |
329 | } // namespace |
330 | |
331 | //! Retrieve all collections |
332 | int SQLiteMetaStore::list_collections(CollectionAllocator allocator) const { |
333 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
334 | |
335 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kListAllCollections)); |
336 | |
337 | int code = stmt->exec(nullptr, [&allocator](sqlite3_stmt *s) -> int { |
338 | int fetch_code = BuildFetcher(allocator())(s); |
339 | if (fetch_code != 0) { |
340 | LOG_ERROR("Failed to fetch collection from sqlite statement" ); |
341 | } |
342 | return fetch_code; |
343 | }); |
344 | |
345 | return code; |
346 | } |
347 | |
348 | //! Create column |
349 | int SQLiteMetaStore::create_column(const ColumnObject &column) { |
350 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
351 | |
352 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kCreateColumn)); |
353 | |
354 | int code = stmt->exec( |
355 | [&column](sqlite3_stmt *s) -> int { |
356 | sqlite3_bind_text(s, 1, column.collection_uid().c_str(), |
357 | column.collection_uid().length(), nullptr); |
358 | sqlite3_bind_text(s, 2, column.collection_uuid().c_str(), |
359 | column.collection_uuid().length(), nullptr); |
360 | sqlite3_bind_text(s, 3, column.name().c_str(), column.name().length(), |
361 | nullptr); |
362 | sqlite3_bind_text(s, 4, column.uid().c_str(), column.uid().length(), |
363 | nullptr); |
364 | sqlite3_bind_int(s, 5, column.dimension()); |
365 | sqlite3_bind_int(s, 6, column.index_type()); |
366 | sqlite3_bind_int(s, 7, column.data_type()); |
367 | sqlite3_bind_text(s, 8, column.parameters().c_str(), |
368 | column.parameters().length(), nullptr); |
369 | return 0; |
370 | }, |
371 | nullptr); |
372 | |
373 | if (code != 0) { |
374 | LOG_ERROR("Failed to create column. code[%d]" , code); |
375 | } |
376 | return code; |
377 | } |
378 | |
379 | //! Delete column |
380 | int SQLiteMetaStore::delete_columns_by_uid(const std::string &uid) { |
381 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
382 | |
383 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kDeleteColumn)); |
384 | |
385 | int code = stmt->exec( |
386 | [&uid](sqlite3_stmt *s) -> int { |
387 | sqlite3_bind_text(s, 1, uid.c_str(), uid.length(), nullptr); |
388 | return 0; |
389 | }, |
390 | nullptr); |
391 | if (code != 0) { |
392 | LOG_ERROR("Failed to delete column. code[%d]" , code); |
393 | } |
394 | |
395 | return code; |
396 | } |
397 | |
398 | //! Delete column |
399 | int SQLiteMetaStore::delete_columns_by_uuid(const std::string &uuid) { |
400 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
401 | |
402 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kDeleteColumnByUUID)); |
403 | |
404 | int code = stmt->exec( |
405 | [&uuid](sqlite3_stmt *s) -> int { |
406 | sqlite3_bind_text(s, 1, uuid.c_str(), uuid.length(), nullptr); |
407 | return 0; |
408 | }, |
409 | nullptr); |
410 | if (code != 0) { |
411 | LOG_ERROR("Failed to delete column. code[%d]" , code); |
412 | } |
413 | |
414 | return code; |
415 | } |
416 | |
417 | //! Retrieve columns |
418 | int SQLiteMetaStore::list_columns(ColumnAllocator allocator) const { |
419 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
420 | |
421 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kListColumn)); |
422 | |
423 | int code = stmt->exec(nullptr, [&allocator](sqlite3_stmt *s) -> int { |
424 | int fetch_code = BuildFetcher(allocator())(s); |
425 | if (fetch_code != 0) { |
426 | LOG_ERROR("Failed to fetch column from sqlite statement" ); |
427 | } |
428 | return fetch_code; |
429 | }); |
430 | |
431 | return code; |
432 | } |
433 | |
434 | //! Create repository |
435 | int SQLiteMetaStore::create_repository( |
436 | const DatabaseRepositoryObject &repository) { |
437 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
438 | |
439 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kCreateRepository)); |
440 | |
441 | int code = stmt->exec( |
442 | [&repository](sqlite3_stmt *s) -> int { |
443 | sqlite3_bind_text(s, 1, repository.name().c_str(), |
444 | repository.name().length(), nullptr); |
445 | sqlite3_bind_text(s, 2, repository.collection_uid().c_str(), |
446 | repository.collection_uid().length(), nullptr); |
447 | sqlite3_bind_text(s, 3, repository.collection_uuid().c_str(), |
448 | repository.collection_uuid().length(), nullptr); |
449 | sqlite3_bind_text(s, 4, repository.table().c_str(), |
450 | repository.table().length(), nullptr); |
451 | sqlite3_bind_text(s, 5, repository.connection().c_str(), |
452 | repository.connection().length(), nullptr); |
453 | sqlite3_bind_text(s, 6, repository.user().c_str(), |
454 | repository.user().length(), nullptr); |
455 | sqlite3_bind_text(s, 7, repository.password().c_str(), |
456 | repository.password().length(), nullptr); |
457 | return 0; |
458 | }, |
459 | nullptr); |
460 | |
461 | if (code != 0) { |
462 | LOG_ERROR("Failed to create repository. code[%d]" , code); |
463 | } |
464 | return code; |
465 | } |
466 | |
467 | //! Delete repositories |
468 | int SQLiteMetaStore::delete_repositories_by_uid(const std::string &uid) { |
469 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
470 | |
471 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kDeleteRepositoriesByUID)); |
472 | |
473 | int code = stmt->exec( |
474 | [&uid](sqlite3_stmt *s) -> int { |
475 | sqlite3_bind_text(s, 1, uid.c_str(), uid.length(), nullptr); |
476 | return 0; |
477 | }, |
478 | nullptr); |
479 | if (code != 0) { |
480 | LOG_ERROR("Failed to delete repository. code[%d]" , code); |
481 | } |
482 | |
483 | return code; |
484 | } |
485 | |
486 | //! Delete repositories |
487 | int SQLiteMetaStore::delete_repositories_by_uuid(const std::string &uuid) { |
488 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
489 | |
490 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kDeleteRepositoriesByUUID)); |
491 | |
492 | int code = stmt->exec( |
493 | [&uuid](sqlite3_stmt *s) -> int { |
494 | sqlite3_bind_text(s, 1, uuid.c_str(), uuid.length(), nullptr); |
495 | return 0; |
496 | }, |
497 | nullptr); |
498 | if (code != 0) { |
499 | LOG_ERROR("Failed to delete repository. code[%d]" , code); |
500 | } |
501 | |
502 | return code; |
503 | } |
504 | |
505 | //! Retrieve all repositories |
506 | int SQLiteMetaStore::list_repositories( |
507 | DatabaseRepositoryAllocator allocator) const { |
508 | SQLITE_METASTORE_INITIALIZE_CHECK(); |
509 | |
510 | StatementPtr &stmt = statement(SQLITE_SQL_CODE(kListAllRepositories)); |
511 | |
512 | int code = stmt->exec(nullptr, [&allocator](sqlite3_stmt *s) -> int { |
513 | int fetch_code = BuildFetcher(allocator())(s); |
514 | if (fetch_code != 0) { |
515 | LOG_ERROR("Failed to fetch repository from sqlite statement" ); |
516 | } |
517 | return fetch_code; |
518 | }); |
519 | |
520 | return code; |
521 | } |
522 | |
523 | //! Flush all changes to storage |
524 | int SQLiteMetaStore::flush() const { |
525 | return 0; |
526 | } |
527 | |
528 | int SQLiteMetaStore::do_cleanup() { |
529 | for (auto &stmt : statements_) { |
530 | stmt.second->cleanup(); |
531 | } |
532 | |
533 | statements_.clear(); |
534 | initialized_ = false; |
535 | return 0; |
536 | } |
537 | |
538 | int SQLiteMetaStore::sync(sqlite3 *handle) { |
539 | static const char *kMetaTable = |
540 | "CREATE TABLE IF NOT EXISTS columns ( \n" |
541 | " id INTEGER PRIMARY KEY AUTOINCREMENT, \n" |
542 | " collection_uid TEXT NOT NULL, \n" |
543 | " collection_uuid TEXT NOT NULL, \n" |
544 | " name TEXT NOT NULL, \n" |
545 | " uid TEXT NOT NULL, \n" |
546 | " dimension INTEGER, \n" |
547 | " index_type INTEGER, \n" |
548 | " data_type INTEGER, \n" |
549 | " parameters TEXT DEFAULT '' \n" |
550 | ");" |
551 | "CREATE TABLE IF NOT EXISTS collections (" |
552 | " id INTEGER PRIMARY KEY AUTOINCREMENT, \n" |
553 | " name TEXT NOT NULL, \n" |
554 | " uid TEXT NOT NULL, \n" |
555 | " uuid TEXT NOT NULL UNIQUE, \n" |
556 | " forward_columns TEXT NOT NULL, \n" |
557 | " max_docs_per_segment INTEGER, \n" |
558 | " revision INTEGER, \n" |
559 | " status INTEGER, \n" |
560 | " current INTEGER, \n" |
561 | " io_mode INTEGER\n" |
562 | ");" |
563 | "CREATE TABLE IF NOT EXISTS database_repositories (" |
564 | " id INTEGER PRIMARY KEY AUTOINCREMENT, \n" |
565 | " name TEXT NOT NULL, \n" |
566 | " collection_uid TEXT NOT NULL, \n" |
567 | " collection_uuid TEXT NOT NULL, \n" |
568 | " table_name TEXT NOT NULL, \n" |
569 | " connection TEXT NOT NULL, \n" |
570 | " user TEXT NOT NULL, \n" |
571 | " password TEXT NOT NULL \n" |
572 | ");" ; |
573 | |
574 | int code = sqlite3_exec(handle, kMetaTable, nullptr, nullptr, nullptr); |
575 | if (code != SQLITE_OK) { |
576 | LOG_ERROR("Failed to create table. msg[%s]" , sqlite3_errstr(code)); |
577 | return PROXIMA_BE_ERROR_CODE(RuntimeError); |
578 | } |
579 | return 0; |
580 | } |
581 | |
582 | #define PREPARE_AND_CACHE_SQL(K, DB) \ |
583 | { \ |
584 | int code = put(SQLITE_SQL_CODE(K), \ |
585 | std::make_shared<Statement>(DB, SQLITE_SQL_STR(K))); \ |
586 | if (code != 0) { \ |
587 | code = PROXIMA_BE_ERROR_CODE(RuntimeError); \ |
588 | LOG_ERROR("Failed to prepare sql."); \ |
589 | return code; \ |
590 | } \ |
591 | } |
592 | |
593 | int SQLiteMetaStore::init_statements(const std::string &database) { |
594 | PREPARE_AND_CACHE_SQL(kCreateCollection, database) |
595 | PREPARE_AND_CACHE_SQL(kUpdateCollection, database) |
596 | PREPARE_AND_CACHE_SQL(kDeleteCollection, database) |
597 | PREPARE_AND_CACHE_SQL(kDeleteCollectionByUUID, database) |
598 | PREPARE_AND_CACHE_SQL(kListAllCollections, database) |
599 | |
600 | PREPARE_AND_CACHE_SQL(kCreateColumn, database) |
601 | PREPARE_AND_CACHE_SQL(kDeleteColumn, database) |
602 | PREPARE_AND_CACHE_SQL(kDeleteColumnByUUID, database) |
603 | PREPARE_AND_CACHE_SQL(kListColumn, database) |
604 | |
605 | PREPARE_AND_CACHE_SQL(kCreateRepository, database) |
606 | PREPARE_AND_CACHE_SQL(kDeleteRepositoriesByUID, database) |
607 | PREPARE_AND_CACHE_SQL(kDeleteRepositoriesByUUID, database) |
608 | PREPARE_AND_CACHE_SQL(kListAllRepositories, database) |
609 | return 0; |
610 | } |
611 | |
612 | #undef PREPARE_AND_CACHE_SQL |
613 | |
614 | StatementPtr &SQLiteMetaStore::statement(uint32_t index) const { |
615 | return statements_[index]; |
616 | } |
617 | |
618 | int SQLiteMetaStore::put(uint32_t hash, const StatementPtr &stmt) { |
619 | if (stmt->initialize() == 0) { |
620 | statements_[hash] = stmt; |
621 | return 0; |
622 | } |
623 | LOG_ERROR("Failed to initialize Statement" ); |
624 | return PROXIMA_BE_ERROR_CODE(RuntimeError); |
625 | } |
626 | |
627 | #undef SQLITE_METASTORE_INITIALIZE_CHECK |
628 | #undef DEFINE_SQLITE_SQL |
629 | #undef SQLITE_SQL_STR |
630 | #undef SQLITE_SQL_CODE |
631 | |
632 | META_FACTORY_REGISTER_INSTANCE_ALIAS(sqlite, SQLiteMetaStore); |
633 | |
634 | } // namespace sqlite |
635 | } // namespace meta |
636 | } // namespace be |
637 | } // namespace proxima |
638 | |