LCOV - code coverage report
Current view: top level - core/db/sqlite - SPSqliteDriver.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 284 441 64.4 %
Date: 2024-05-12 00:16:13 Functions: 41 50 82.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2021-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             :  Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       4             : 
       5             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       6             :  of this software and associated documentation files (the "Software"), to deal
       7             :  in the Software without restriction, including without limitation the rights
       8             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             :  copies of the Software, and to permit persons to whom the Software is
      10             :  furnished to do so, subject to the following conditions:
      11             : 
      12             :  The above copyright notice and this permission notice shall be included in
      13             :  all copies or substantial portions of the Software.
      14             : 
      15             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             :  THE SOFTWARE.
      22             :  **/
      23             : 
      24             : #include "SPSqliteDriver.h"
      25             : #include "SPSqliteDriverHandle.h"
      26             : #include "SPSqliteHandle.h"
      27             : #include "SPDbFieldExtensions.h"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler::db::sqlite {
      30             : 
      31             : static void sp_ts_update_xFunc(sqlite3_context *ctx, int nargs, sqlite3_value **args);
      32             : static void sp_ts_rank_xFunc(sqlite3_context *ctx, int nargs, sqlite3_value **args);
      33             : static void sp_ts_query_valid_xFunc(sqlite3_context *ctx, int nargs, sqlite3_value **args);
      34             : 
      35             : constexpr static auto DATABASE_DEFAULTS = StringView(R"Sql(
      36             : CREATE TABLE IF NOT EXISTS "__objects" (
      37             :         "control" INT NOT NULL PRIMARY KEY DEFAULT 0,
      38             :         "__oid" BIGINT NOT NULL DEFAULT 0
      39             : ) WITHOUT ROWID;
      40             : 
      41             : CREATE TABLE IF NOT EXISTS "__removed" (
      42             :         __oid BIGINT NOT NULL PRIMARY KEY
      43             : ) WITHOUT ROWID;
      44             : 
      45             : CREATE TABLE IF NOT EXISTS "__sessions" (
      46             :         name BLOB NOT NULL PRIMARY KEY,
      47             :         mtime BIGINT NOT NULL,
      48             :         maxage BIGINT NOT NULL,
      49             :         data BLOB
      50             : ) WITHOUT ROWID;
      51             : 
      52             : CREATE TABLE IF NOT EXISTS "__broadcasts" (
      53             :         id INTEGER PRIMARY KEY AUTOINCREMENT,
      54             :         date BIGINT NOT NULL,
      55             :         msg BLOB
      56             : );
      57             : 
      58             : CREATE TABLE IF NOT EXISTS "__login" (
      59             :         id INTEGER PRIMARY KEY AUTOINCREMENT,
      60             :         "user" BIGINT NOT NULL,
      61             :         name TEXT NOT NULL,
      62             :         password BLOB NOT NULL,
      63             :         date BIGINT NOT NULL,
      64             :         success BOOLEAN NOT NULL,
      65             :         addr TEXT,
      66             :         host TEXT,
      67             :         path TEXT
      68             : );
      69             : 
      70             : CREATE TABLE IF NOT EXISTS "__words" (
      71             :         id BIGINT NOT NULL,
      72             :         word TEXT NOT NULL
      73             : );
      74             : 
      75             : CREATE INDEX IF NOT EXISTS "__broadcasts_idx_date" ON "__broadcasts" ("date");
      76             : CREATE INDEX IF NOT EXISTS "__login_idx_user" ON "__login" ("user");
      77             : CREATE INDEX IF NOT EXISTS "__login_idx_date" ON "__login" ("date");
      78             : CREATE UNIQUE INDEX IF NOT EXISTS "__words_idx_id" ON "__words" ("id");
      79             : )Sql");
      80             : 
      81         100 : Driver *Driver::open(pool_t *pool, ApplicationInterface *app, StringView path) {
      82         100 :         if (sqlite3_initialize() == SQLITE_OK) {
      83         100 :                 return new Driver(pool, app, path);
      84             :         } else {
      85           0 :                 std::cout << "[sqlite::Driver] sqlite3_initialize failed\n";
      86             :         }
      87           0 :         return nullptr;
      88             : }
      89             : 
      90         150 : Driver::~Driver() {
      91          75 :         sqlite3_shutdown();
      92         150 : }
      93             : 
      94          75 : bool Driver::init(Handle handle, const Vector<StringView> &) {
      95          75 :         return true;
      96             : }
      97             : 
      98        2474 : void Driver::performWithStorage(Handle handle, const Callback<void(const db::Adapter &)> &cb) const {
      99        2474 :         auto targetPool = pool::acquire();
     100             : 
     101        2473 :         db::sqlite::Handle h(this, handle);
     102        2472 :         db::Adapter storage(&h, _application);
     103        2472 :         pool::userdata_set((void *)&h, config::STORAGE_INTERFACE_KEY.data(), nullptr, targetPool);
     104             : 
     105        2472 :         cb(storage);
     106             : 
     107        2475 :         auto stack = stappler::memory::pool::get<db::Transaction::Stack>(targetPool, config::STORAGE_TRANSACTION_STACK_KEY);
     108        2475 :         if (stack) {
     109        2425 :                 for (auto &it : stack->stack) {
     110           0 :                         if (it->adapter == storage) {
     111           0 :                                 it->adapter = db::Adapter(nullptr, _application);
     112           0 :                                 _application->error("Root", "Incomplete transaction found");
     113             :                         }
     114             :                 }
     115             :         }
     116        2475 :         pool::userdata_set((void *)nullptr, storage.getTransactionKey().data(), nullptr, targetPool);
     117        2473 :         pool::userdata_set((void *)nullptr, config::STORAGE_INTERFACE_KEY.data(), nullptr, targetPool);
     118        2475 : }
     119             : 
     120        2850 : BackendInterface *Driver::acquireInterface(Handle handle, pool_t *pool) const {
     121        2850 :         BackendInterface *ret = nullptr;
     122        2850 :         pool::push(pool);
     123        2850 :         ret = new (pool) db::sqlite::Handle(this, handle);
     124        2850 :         pool::pop();
     125        2850 :         return ret;
     126             : }
     127             : 
     128        2129 : static StringView Driver_exec(pool_t *p, sqlite3 *db, StringView query) {
     129        2129 :         sqlite3_stmt *stmt = nullptr;
     130        2129 :         auto err = sqlite3_prepare_v3(db, query.data(), query.size(), 0, &stmt, nullptr);
     131        2129 :         if (err != SQLITE_OK) {
     132           0 :                 log::error("sqlite::Driver", err, ": ", sqlite3_errstr(int(err)), ": ", sqlite3_errmsg(db), ":\n", query);
     133           0 :                 return StringView();
     134             :         }
     135             : 
     136        2129 :         err = sqlite3_step(stmt);
     137        2129 :         if (err != SQLITE_ROW) {
     138        2025 :                 if (err < 100) {
     139           0 :                         log::error("sqlite::Driver", err, ": ", sqlite3_errstr(int(err)), ": ", sqlite3_errmsg(db), ":\n", query);
     140             :                 }
     141        2025 :                 sqlite3_finalize(stmt);
     142        2025 :                 return StringView();
     143             :         }
     144             : 
     145         104 :         if (p) {
     146         104 :                 StringView result((const char *)sqlite3_column_text(stmt, 0), size_t(sqlite3_column_bytes(stmt, 0)));
     147         104 :                 result = result.pdup(p);
     148         104 :                 sqlite3_finalize(stmt);
     149         104 :                 return result;
     150             :         }
     151             : 
     152           0 :         sqlite3_finalize(stmt);
     153           0 :         return StringView();
     154             : }
     155             : 
     156        2525 : static void sp_sqlite_next_oid_xFunc(sqlite3_context *ctx, int nargs, sqlite3_value **args) {
     157        2525 :         sqlite3_int64 ret = 0;
     158        2525 :         DriverHandle *data = (DriverHandle *)sqlite3_user_data(ctx);
     159        2525 :         std::unique_lock lock(data->mutex);
     160        2525 :         auto err = sqlite3_step(data->oidQuery);
     161        2525 :         if (err == SQLITE_ROW) {
     162        2525 :                 ret = sqlite3_column_int64(data->oidQuery, 0);
     163             :         }
     164        2525 :         if (!ret) {
     165           0 :                 ret = Time::now().toMicros();
     166             :         }
     167        2525 :         sqlite3_reset(data->oidQuery);
     168        2525 :         sqlite3_result_int64(ctx, ret);
     169        2525 : }
     170             : 
     171        1175 : static void sp_sqlite_now_xFunc(sqlite3_context *ctx, int nargs, sqlite3_value **args) {
     172        1175 :         sqlite3_result_int64(ctx, Time::now().toMicros());
     173        1175 : }
     174             : 
     175        1175 : static void sp_sqlite_user_xFunc(sqlite3_context *ctx, int nargs, sqlite3_value **args) {
     176        1175 :         DriverHandle *data = (DriverHandle *)sqlite3_user_data(ctx);
     177        1175 :         sqlite3_result_int64(ctx, data->userId);
     178        1175 : }
     179             : 
     180         154 : Driver::Handle Driver::connect(const Map<StringView, StringView> &params) const {
     181         154 :         auto p = pool::create(pool::acquire());
     182             :         Driver::Handle rec;
     183         154 :         pool::push(p);
     184             : 
     185         154 :         int flags = 0;
     186         154 :         StringView mode;
     187         154 :         StringView dbname("");
     188         154 :         StringView journal;
     189             : 
     190         703 :         for (auto &it : params) {
     191         549 :                 if (it.first == "dbname") {
     192         154 :                         dbname = it.second;
     193         395 :                 } else if (it.first == "mode") {
     194           0 :                         mode = it.second;
     195         395 :                 } else if (it.first == "cache") {
     196          79 :                         if (it.second == "shared") {
     197          79 :                                 flags |= SQLITE_OPEN_SHAREDCACHE;
     198           0 :                         } else if (it.second == "private") {
     199           0 :                                 flags |= SQLITE_OPEN_PRIVATECACHE;
     200             :                         }
     201         316 :                 } else if (it.first == "threading") {
     202          79 :                         if (it.second == "serialized") {
     203          79 :                                 flags |= SQLITE_OPEN_FULLMUTEX;
     204           0 :                         } else if (it.second == "multi" || it.second == "multithread" || it.second == "multithreaded") {
     205           0 :                                 flags |= SQLITE_OPEN_NOMUTEX;
     206             :                         }
     207         237 :                 } else if (it.first == "journal") {
     208         158 :                         if (it.second == "delete" || it.second == "truncate" || it.second == "persist"
     209         158 :                                         || it.second == "memory" || it.second == "wal" || it.second == "off") {
     210          79 :                                 journal = it.second;
     211             :                         }
     212         237 :                 } else if (it.first != "driver" && it.first == "nmin" && it.first == "nkeep"
     213         237 :                                 && it.first == "nmax" && it.first == "exptime" && it.first == "persistent") {
     214           0 :                         std::cout << "[sqlite::Driver] unknown connection parameter: " << it.first << "=" << it.second << "\n";
     215             :                 }
     216             :         }
     217             : 
     218         154 :         if (!mode.empty()) {
     219           0 :                 if (mode == "ro") {
     220           0 :                         flags |= SQLITE_OPEN_READONLY;
     221           0 :                 } else if (mode == "rw") {
     222           0 :                         flags |= SQLITE_OPEN_READWRITE;
     223           0 :                 } else if (mode == "rwc") {
     224           0 :                         flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
     225           0 :                 } else if (mode == "memory") {
     226           0 :                         flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY;
     227             :                 } else {
     228           0 :                         std::cout << "[sqlite::Driver] unknown mode parameter: " << mode << "\n";
     229             :                 }
     230             :         } else {
     231         154 :                 flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
     232             :         }
     233             : 
     234             :         do {
     235         154 :                 sqlite3 *db = nullptr;
     236             : #if WIN32
     237             :                 dbname = StringView(filesystem::native::posixToNative<Interface>(dbname)).pdup();
     238             : #endif
     239         154 :                 if (!dbname.is('/') && !dbname.is(':')) {
     240          25 :                         if (_application) {
     241          25 :                                 dbname = StringView(filepath::merge<Interface>(_application->getDocumentRoot(), dbname)).pdup();
     242             :                         } else {
     243           0 :                                 dbname = StringView(filesystem::writablePath<Interface>(dbname)).pdup();
     244             :                         }
     245          25 :                         stappler::filesystem::mkdir(stappler::filepath::root(dbname));
     246             :                 }
     247         154 :                 if (sqlite3_open_v2(dbname.data(), &db, flags, nullptr) == SQLITE_OK) {
     248         154 :                         sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, nullptr);
     249         154 :                         sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, nullptr);
     250         154 :                         sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 1, nullptr);
     251             : 
     252         154 :                         if (!journal.empty()) {
     253          79 :                                 auto m = stappler::string::toupper<Interface>(journal);
     254          79 :                                 auto mode = stappler::string::toupper<Interface>(Driver_exec(p, db, "PRAGMA journal_mode;"));
     255          79 :                                 if (mode.empty()) {
     256           0 :                                         sqlite3_close(db);
     257           0 :                                         break;
     258             :                                 }
     259             : 
     260          79 :                                 if (mode != m) {
     261          25 :                                         auto query = toString("PRAGMA journal_mode = ", m);
     262          25 :                                         auto cmode = stappler::string::toupper<Interface>(Driver_exec(p, db, query));
     263          25 :                                         if (mode.empty() || cmode != m) {
     264           0 :                                                 std::cout << "[sqlite::Driver] fail to enable journal_mode '" << m << "'\n";
     265           0 :                                                 sqlite3_close(db);
     266           0 :                                                 break;
     267             :                                         }
     268          25 :                                 }
     269          79 :                         }
     270             : 
     271         154 :                         auto queryData = DATABASE_DEFAULTS;
     272         154 :                         auto outPtr = queryData.data();
     273             : 
     274         154 :                         bool success = true;
     275        1694 :                         while (outPtr && *outPtr != 0 && success) {
     276        1694 :                                 auto size = queryData.size() - (outPtr - queryData.data());
     277        1694 :                                 StringView nextQuery(outPtr, size);
     278        1694 :                                 nextQuery.skipChars<StringView::WhiteSpace>();
     279        1694 :                                 if (nextQuery.empty()) {
     280         154 :                                         break;
     281             :                                 }
     282             : 
     283        1540 :                                 sqlite3_stmt *stmt = nullptr;
     284        1540 :                                 auto err = sqlite3_prepare_v3(db, nextQuery.data(), nextQuery.size(), 0, &stmt, &outPtr);
     285        1540 :                                 if (err != SQLITE_OK) {
     286           0 :                                         auto len = outPtr - nextQuery.data();
     287           0 :                                         StringView performedQuery(nextQuery.data(), len);
     288           0 :                                         auto info = getInfo(Connection(db), err);
     289           0 :                                         info.setString(performedQuery, "query");
     290             : #if DEBUG
     291           0 :                                         log::debug("pq::Handle", EncodeFormat::Pretty, info);
     292             : #endif
     293           0 :                                         break;
     294           0 :                                 }
     295             : 
     296        1540 :                                 err = sqlite3_step(stmt);
     297             : 
     298        1540 :                                 if (err != SQLITE_OK && err != SQLITE_DONE && err != SQLITE_ROW) {
     299           0 :                                         auto info = getInfo(Connection(db), err);
     300           0 :                                         info.setString(nextQuery, "query");
     301             : #if DEBUG
     302           0 :                                         log::debug("pq::Handle", EncodeFormat::Pretty, info);
     303             : #endif
     304           0 :                                         sqlite3_finalize(stmt);
     305           0 :                                         break;
     306           0 :                                 }
     307             : 
     308        1540 :                                 success = ResultCursor::statusIsSuccess(err);
     309        1540 :                                 sqlite3_finalize(stmt);
     310             :                         }
     311             : 
     312         154 :                         auto mem = pool::palloc(p, sizeof(DriverHandle));
     313         154 :                         auto h = new (mem) DriverHandle;
     314         154 :                         h->pool = p;
     315         154 :                         h->driver = this;
     316         154 :                         h->conn = db;
     317         154 :                         h->name = dbname.pdup(p);
     318         154 :                         h->ctime = Time::now();
     319         154 :                         h->mutex.lock();
     320             : 
     321             :                         do {
     322         154 :                                 StringView getStmt("SELECT \"__oid\" FROM \"__objects\" WHERE \"control\" = 0;");
     323         154 :                                 sqlite3_stmt *gstmt = nullptr;
     324         154 :                                 auto err = sqlite3_prepare_v3(db, getStmt.data(), getStmt.size(), 0, &gstmt, nullptr);
     325         154 :                                 err = sqlite3_step(gstmt);
     326         154 :                                 if (err == SQLITE_DONE) {
     327          75 :                                         StringView createStmt("INSERT OR IGNORE INTO \"__objects\" (\"__oid\") VALUES (0);");
     328          75 :                                         sqlite3_stmt *cstmt = nullptr;
     329          75 :                                         err = sqlite3_prepare_v3(db, createStmt.data(), createStmt.size(), 0, &cstmt, nullptr);
     330          75 :                                         err = sqlite3_step(cstmt);
     331          75 :                                         sqlite3_finalize(cstmt);
     332             :                                 }
     333         154 :                                 sqlite3_finalize(gstmt);
     334             : 
     335         154 :                                 StringView oidStmt("UPDATE OR IGNORE \"__objects\" SET \"__oid\" = \"__oid\" + 1 WHERE \"control\" = 0 RETURNING \"__oid\";");
     336             : 
     337         154 :                                 sqlite3_stmt *stmt = nullptr;
     338         154 :                                 err = sqlite3_prepare_v3(db, oidStmt.data(), oidStmt.size(), SQLITE_PREPARE_PERSISTENT, &stmt, nullptr);
     339         154 :                                 if (err == SQLITE_OK) {
     340         154 :                                         h->oidQuery = stmt;
     341             :                                 }
     342             :                         } while (0);
     343             : 
     344             :                         do {
     345         154 :                                 StringView str("INSERT INTO \"__words\"(\"id\",\"word\") VALUES(?1, ?2) ON CONFLICT(id) DO UPDATE SET word=word RETURNING \"id\", \"word\";");
     346             : 
     347         154 :                                 sqlite3_stmt *stmt = nullptr;
     348         154 :                                 auto err = sqlite3_prepare_v3(db, str.data(), str.size(), SQLITE_PREPARE_PERSISTENT, &stmt, nullptr);
     349         154 :                                 if (err == SQLITE_OK) {
     350         154 :                                         h->wordsQuery = stmt;
     351             :                                 }
     352             :                         } while (0);
     353             : 
     354         154 :                         sqlite3_create_function_v2(db, "sp_sqlite_next_oid", 0, SQLITE_UTF8, (void *)h,
     355             :                                         sp_sqlite_next_oid_xFunc, nullptr, nullptr, nullptr);
     356         154 :                         sqlite3_create_function_v2(db, "sp_sqlite_now", 0, SQLITE_UTF8, (void *)h,
     357             :                                         sp_sqlite_now_xFunc, nullptr, nullptr, nullptr);
     358         154 :                         sqlite3_create_function_v2(db, "sp_sqlite_user", 0, SQLITE_UTF8, (void *)h,
     359             :                                         sp_sqlite_user_xFunc, nullptr, nullptr, nullptr);
     360             : 
     361         154 :                         sqlite3_create_function_v2(db, "sp_ts_update", 6, SQLITE_UTF8, (void *)h,
     362             :                                         sp_ts_update_xFunc, nullptr, nullptr, nullptr);
     363         154 :                         sqlite3_create_function_v2(db, "sp_ts_rank", 3, SQLITE_UTF8, (void *)h,
     364             :                                         sp_ts_rank_xFunc, nullptr, nullptr, nullptr);
     365         154 :                         sqlite3_create_function_v2(db, "sp_ts_query_valid", 2, SQLITE_UTF8, (void *)h,
     366             :                                         sp_ts_query_valid_xFunc, nullptr, nullptr, nullptr);
     367             : 
     368         154 :                         sqlite3_create_module(db, "sp_unwrap", &s_UnwrapModule, (void *)this);
     369             : 
     370         154 :                         h->mutex.unlock();
     371             : 
     372         154 :                         pool::pre_cleanup_register(p, [h] {
     373         129 :                                 if (h->oidQuery) {
     374         129 :                                         sqlite3_finalize(h->oidQuery);
     375             :                                 }
     376         129 :                                 if (h->wordsQuery) {
     377         129 :                                         sqlite3_finalize(h->wordsQuery);
     378             :                                 }
     379         129 :                                 sqlite3_close(h->conn);
     380         129 :                         });
     381             : 
     382         154 :                         rec = Handle(h);
     383             :                 }
     384             :         } while (0);
     385             : 
     386         153 :         pool::pop();
     387         153 :         if (!rec.get()) {
     388           0 :                 pool::destroy(p);
     389             :         }
     390         154 :         return rec;
     391             : }
     392             : 
     393          54 : void Driver::finish(Handle h) const {
     394          54 :         auto db = (DriverHandle *)h.get();
     395          54 :         if (db && db->pool) {
     396          54 :                 pool::destroy(db->pool);
     397             :         }
     398          54 : }
     399             : 
     400       12118 : Driver::Connection Driver::getConnection(Handle h) const {
     401       12118 :         auto db = (DriverHandle *)h.get();
     402       12118 :         return Driver::Connection(db->conn);
     403             : }
     404             : 
     405        5250 : bool Driver::isValid(Handle) const {
     406        5250 :         return true;
     407             : }
     408             : 
     409        6796 : bool Driver::isValid(Connection) const {
     410        6796 :         return true;
     411             : }
     412             : 
     413        3425 : bool Driver::isIdle(Connection) const {
     414        3425 :         return true;
     415             : }
     416             : 
     417        3425 : Time Driver::getConnectionTime(Handle handle) const {
     418        3425 :         auto db = (DriverHandle *)handle.get();
     419        3425 :         return db->ctime;
     420             : }
     421             : 
     422        5322 : StringView Driver::getDbName(Handle h) const {
     423        5322 :         auto db = (DriverHandle *)h.get();
     424        5322 :         return db->name;
     425             : }
     426             : 
     427           0 : Value Driver::getInfo(Connection conn, int err) const {
     428             :         return Value({
     429           0 :                 stappler::pair("error", Value(err)),
     430           0 :                 stappler::pair("status", Value(sqlite3_errstr(int(err)))),
     431           0 :                 stappler::pair("desc", Value(sqlite3_errmsg((sqlite3 *)conn.get()))),
     432           0 :         });
     433             : }
     434             : 
     435        5900 : void Driver::setUserId(Handle h, int64_t userId) const {
     436        5900 :         auto db = (DriverHandle *)h.get();
     437        5899 :         db->userId = userId;
     438        5899 : }
     439             : 
     440       12050 : uint64_t Driver::insertWord(Handle h, StringView word) const {
     441       12050 :         auto data = (DriverHandle *)h.get();
     442             : 
     443       12050 :         uint64_t hash = hash::hash32(word.data(), word.size(), 0) << 16;
     444             : 
     445       12050 :         std::unique_lock lock(data->mutex);
     446       12050 :         bool success = false;
     447       12075 :         while (!success) {
     448       12075 :                 sqlite3_bind_int64(data->wordsQuery, 1, hash);
     449       12075 :                 sqlite3_bind_text(data->wordsQuery, 2, word.data(), int(word.size()), nullptr);
     450             : 
     451       12075 :                 auto err = sqlite3_step(data->wordsQuery);
     452       12075 :                 if (err == SQLITE_ROW) {
     453       12075 :                         auto w = StringView((const char *)sqlite3_column_text(data->wordsQuery, 1), sqlite3_column_bytes(data->wordsQuery, 1));
     454       12075 :                         if (w == word) {
     455       12050 :                                 success = true;
     456       12050 :                                 sqlite3_reset(data->wordsQuery);
     457       12050 :                                 break;
     458             :                         } else {
     459          25 :                                 log::debug("sqlite::Driver", "Hash collision: ", w, " ", word, " ", hash);
     460             :                         }
     461             :                 }
     462          25 :                 sqlite3_reset(data->wordsQuery);
     463          25 :                 ++ hash;
     464             :         }
     465             : 
     466       12050 :         return hash;
     467       12050 : }
     468             : 
     469         100 : Driver::Driver(pool_t *pool, ApplicationInterface *app, StringView mem)
     470         100 : : sql::Driver(pool, app) {
     471         100 :         _driverPath = mem.pdup();
     472             : 
     473         100 :         auto it = _customFields.emplace(FieldIntArray::FIELD_NAME);
     474         100 :         if (!FieldIntArray::registerForSqlite(it.first->second)) {
     475           0 :                 _customFields.erase(it.first);
     476             :         }
     477             : 
     478         100 :         it = _customFields.emplace(FieldBigIntArray::FIELD_NAME);
     479         100 :         if (!FieldBigIntArray::registerForSqlite(it.first->second)) {
     480           0 :                 _customFields.erase(it.first);
     481             :         }
     482             : 
     483         100 :         it = _customFields.emplace(FieldPoint::FIELD_NAME);
     484         100 :         if (!FieldPoint::registerForSqlite(it.first->second)) {
     485           0 :                 _customFields.erase(it.first);
     486             :         }
     487             : 
     488         100 :         it = _customFields.emplace(FieldTextArray::FIELD_NAME);
     489         100 :         if (!FieldTextArray::registerForSqlite(it.first->second)) {
     490           0 :                 _customFields.erase(it.first);
     491             :         }
     492         100 : }
     493             : 
     494       35863 : bool ResultCursor::statusIsSuccess(int x) {
     495       35863 :         return (x == SQLITE_DONE) || (x == SQLITE_ROW) || (x == SQLITE_OK);
     496             : }
     497             : 
     498       16600 : ResultCursor::ResultCursor(const Driver *d, Driver::Connection conn, Driver::Result res, int status)
     499       16600 : : driver(d), conn(conn), result(res), err(status) { }
     500             : 
     501       16600 : ResultCursor::~ResultCursor() {
     502       16600 :         clear();
     503       16600 : }
     504             : 
     505           0 : bool ResultCursor::isBinaryFormat(size_t field) const {
     506           0 :         return true;
     507             : }
     508             : 
     509           0 : BackendInterface::StorageType ResultCursor::getType(size_t field) const {
     510           0 :         auto t = sqlite3_column_type((sqlite3_stmt *)result.get(), field);
     511           0 :         switch (t) {
     512           0 :         case SQLITE_INTEGER: return BackendInterface::StorageType::Int8; break;
     513           0 :         case SQLITE_FLOAT: return BackendInterface::StorageType::Float8; break;
     514           0 :         case SQLITE_TEXT: return BackendInterface::StorageType::Text; break;
     515           0 :         case SQLITE_BLOB: return BackendInterface::StorageType::Bytes; break;
     516           0 :         case SQLITE_NULL: return BackendInterface::StorageType::Unknown; break;
     517           0 :         default: return BackendInterface::StorageType::Unknown; break;
     518             :         }
     519             :         return BackendInterface::StorageType::Unknown;
     520             : }
     521             : 
     522       86950 : bool ResultCursor::isNull(size_t field) const {
     523       86950 :         return sqlite3_column_type((sqlite3_stmt *)result.get(), field) == SQLITE_NULL;
     524             : }
     525             : 
     526       25999 : StringView ResultCursor::toString(size_t field) const {
     527       25999 :         switch (sqlite3_column_type((sqlite3_stmt *)result.get(), field)) {
     528           0 :         case SQLITE_INTEGER:
     529           0 :                 return StringView(toString(sqlite3_column_int64((sqlite3_stmt *)result.get(), field))).pdup();
     530             :                 break;
     531           0 :         case SQLITE_FLOAT:
     532           0 :                 return StringView(toString(sqlite3_column_double((sqlite3_stmt *)result.get(), field))).pdup();
     533             :                 break;
     534       26019 :         case SQLITE_TEXT:
     535       26016 :                 return StringView((const char *)sqlite3_column_text((sqlite3_stmt *)result.get(), field),
     536       52029 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field));
     537             :                 break;
     538           0 :         case SQLITE_BLOB:
     539           0 :                 return StringView((const char *)sqlite3_column_blob((sqlite3_stmt *)result.get(), field),
     540           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field));
     541             :                 break;
     542           0 :         case SQLITE_NULL:
     543           0 :                 return StringView("(null)");
     544             :                 break;
     545             :         }
     546             : 
     547           0 :         return StringView();
     548             : }
     549             : 
     550       18300 : BytesView ResultCursor::toBytes(size_t field) const {
     551       18300 :         switch (sqlite3_column_type((sqlite3_stmt *)result.get(), field)) {
     552           0 :         case SQLITE_INTEGER: {
     553           0 :                 int64_t value = sqlite3_column_int64((sqlite3_stmt *)result.get(), field);
     554           0 :                 return BytesView((const uint8_t *)&value, sizeof(int64_t)).pdup();
     555             :                 break;
     556             :         }
     557           0 :         case SQLITE_FLOAT: {
     558           0 :                 double value = sqlite3_column_double((sqlite3_stmt *)result.get(), field);
     559           0 :                 return BytesView((const uint8_t *)&value, sizeof(int64_t)).pdup();
     560             :                 break;
     561             :         }
     562           0 :         case SQLITE_TEXT:
     563           0 :                 return BytesView((const uint8_t *)sqlite3_column_text((sqlite3_stmt *)result.get(), field),
     564           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field));
     565             :                 break;
     566       18300 :         case SQLITE_BLOB:
     567       18300 :                 return BytesView((const uint8_t *)sqlite3_column_blob((sqlite3_stmt *)result.get(), field),
     568       36600 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field));
     569             :                 break;
     570           0 :         case SQLITE_NULL:
     571           0 :                 return BytesView();
     572             :                 break;
     573             :         }
     574             : 
     575           0 :         return BytesView();
     576             : }
     577             : 
     578       37650 : int64_t ResultCursor::toInteger(size_t field) const {
     579       37650 :         switch (sqlite3_column_type((sqlite3_stmt *)result.get(), field)) {
     580       37450 :         case SQLITE_INTEGER:
     581       37450 :                 return sqlite3_column_int64((sqlite3_stmt *)result.get(), field);
     582             :                 break;
     583           0 :         case SQLITE_FLOAT:
     584           0 :                 return int64_t(sqlite3_column_double((sqlite3_stmt *)result.get(), field));
     585             :                 break;
     586           0 :         case SQLITE_TEXT:
     587           0 :                 return StringView((const char *)sqlite3_column_text((sqlite3_stmt *)result.get(), field),
     588           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field)).readInteger(10).get(0);
     589             :                 break;
     590           0 :         case SQLITE_BLOB:
     591           0 :                 return int64_t(BytesView((const uint8_t *)sqlite3_column_blob((sqlite3_stmt *)result.get(), field),
     592           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field)).readUnsigned64());
     593             :                 break;
     594         200 :         case SQLITE_NULL:
     595         200 :                 break;
     596             :         }
     597             : 
     598         200 :         return 0;
     599             : }
     600             : 
     601        6100 : double ResultCursor::toDouble(size_t field) const {
     602        6100 :         switch (sqlite3_column_type((sqlite3_stmt *)result.get(), field)) {
     603           0 :         case SQLITE_INTEGER:
     604           0 :                 return double(sqlite3_column_int64((sqlite3_stmt *)result.get(), field));
     605             :                 break;
     606        6100 :         case SQLITE_FLOAT:
     607        6100 :                 return sqlite3_column_double((sqlite3_stmt *)result.get(), field);
     608             :                 break;
     609           0 :         case SQLITE_TEXT:
     610           0 :                 return StringView((const char *)sqlite3_column_text((sqlite3_stmt *)result.get(), field),
     611           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field)).readDouble().get(0);
     612             :                 break;
     613           0 :         case SQLITE_BLOB:
     614           0 :                 return BytesView((const uint8_t *)sqlite3_column_blob((sqlite3_stmt *)result.get(), field),
     615           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field)).readFloat64();
     616             :                 break;
     617           0 :         case SQLITE_NULL:
     618           0 :                 break;
     619             :         }
     620             : 
     621           0 :         return 0.0;
     622             : }
     623       10646 : bool ResultCursor::toBool(size_t field) const {
     624       10646 :         switch (sqlite3_column_type((sqlite3_stmt *)result.get(), field)) {
     625       10650 :         case SQLITE_INTEGER:
     626       10650 :                 return sqlite3_column_int64((sqlite3_stmt *)result.get(), field) != 0;
     627             :                 break;
     628           0 :         case SQLITE_FLOAT:
     629           0 :                 return sqlite3_column_double((sqlite3_stmt *)result.get(), field) != 0.0;
     630             :                 break;
     631           0 :         case SQLITE_TEXT: {
     632           0 :                 StringView data((const char *)sqlite3_column_text((sqlite3_stmt *)result.get(), field),
     633           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field));
     634           0 :                 if (data == "1" || data == "true" || data == "TRUE") {
     635           0 :                         return true;
     636             :                 }
     637           0 :                 break;
     638             :         }
     639           0 :         case SQLITE_BLOB: {
     640           0 :                 BytesView data((const uint8_t *)sqlite3_column_blob((sqlite3_stmt *)result.get(), field),
     641           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field));
     642           0 :                 if (data.empty()) {
     643           0 :                         return false;
     644             :                 } else {
     645           0 :                         return true;
     646             :                 }
     647             :                 break;
     648             :         }
     649           0 :         case SQLITE_NULL:
     650           0 :                 break;
     651             :         }
     652             : 
     653           0 :         return false;
     654             : }
     655           0 : Value ResultCursor::toTypedData(size_t field) const {
     656           0 :         switch (sqlite3_column_type((sqlite3_stmt *)result.get(), field)) {
     657           0 :         case SQLITE_INTEGER:
     658           0 :                 return Value(int64_t(sqlite3_column_int64((sqlite3_stmt *)result.get(), field)));
     659             :                 break;
     660           0 :         case SQLITE_FLOAT:
     661           0 :                 return Value(sqlite3_column_double((sqlite3_stmt *)result.get(), field));
     662             :                 break;
     663           0 :         case SQLITE_TEXT:
     664           0 :                 return Value(StringView((const char *)sqlite3_column_text((sqlite3_stmt *)result.get(), field),
     665           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field)));
     666             :                 break;
     667           0 :         case SQLITE_BLOB:
     668           0 :                 return Value(BytesView((const uint8_t *)sqlite3_column_blob((sqlite3_stmt *)result.get(), field),
     669           0 :                                 sqlite3_column_bytes((sqlite3_stmt *)result.get(), field)));
     670             :                 break;
     671           0 :         case SQLITE_NULL:
     672           0 :                 break;
     673             :         }
     674             : 
     675           0 :         return Value();
     676             : }
     677             : 
     678        7125 : Value ResultCursor::toCustomData(size_t field, const FieldCustom *f) const {
     679        7125 :         auto info = driver->getCustomFieldInfo(f->getDriverTypeName());
     680        7125 :         if (!info) {
     681           0 :                 return Value();
     682             :         }
     683        7125 :         return info->readFromStorage(*f, *this, field);
     684             : }
     685             : 
     686        3025 : int64_t ResultCursor::toId() const {
     687        3025 :         return toInteger(0);
     688             : }
     689       87925 : StringView ResultCursor::getFieldName(size_t field) const {
     690       87925 :         if (auto ptr = sqlite3_column_name((sqlite3_stmt *)result.get(), field)) {
     691       87925 :                 return StringView(ptr);
     692             :         }
     693           0 :         return StringView();
     694             : }
     695       16599 : bool ResultCursor::isSuccess() const {
     696       16599 :         return result.get() && statusIsSuccess(err);
     697             : }
     698       14624 : bool ResultCursor::isEmpty() const {
     699       14624 :         return err != SQLITE_ROW;
     700             : }
     701           0 : bool ResultCursor::isEnded() const {
     702           0 :         return err == SQLITE_DONE;
     703             : }
     704      131549 : size_t ResultCursor::getFieldsCount() const {
     705      131549 :         return sqlite3_column_count((sqlite3_stmt *)result.get());
     706             : }
     707        1675 : size_t ResultCursor::getAffectedRows() const {
     708        1675 :         return sqlite3_changes((sqlite3 *)conn.get());
     709             : }
     710        8375 : size_t ResultCursor::getRowsHint() const {
     711        8375 :         return 0;
     712             : }
     713           0 : Value ResultCursor::getInfo() const {
     714             :         return Value({
     715           0 :                 stappler::pair("error", Value(err)),
     716           0 :                 stappler::pair("status", Value(sqlite3_errstr(int(err)))),
     717           0 :                 stappler::pair("desc", Value(sqlite3_errmsg((sqlite3 *)conn.get()))),
     718           0 :         });
     719             : }
     720             : 
     721       19545 : bool ResultCursor::next() {
     722       19545 :         if (err == SQLITE_ROW) {
     723       19545 :                 err = sqlite3_step((sqlite3_stmt *)result.get());
     724       19550 :                 return err == SQLITE_ROW;
     725             :         }
     726           0 :         return false;
     727             : }
     728             : 
     729           0 : void ResultCursor::reset() {
     730           0 :         if (result.get()) {
     731           0 :                 sqlite3_reset((sqlite3_stmt *)result.get());
     732           0 :                 err = sqlite3_step((sqlite3_stmt *)result.get());
     733           0 :                 result = Driver::Result(nullptr);
     734             :         }
     735           0 : }
     736             : 
     737       33200 : void ResultCursor::clear() {
     738       33200 :         if (result.get()) {
     739       16600 :                 sqlite3_finalize((sqlite3_stmt *)result.get());
     740       16600 :                 result = Driver::Result(nullptr);
     741             :         }
     742       33200 : }
     743             : 
     744           0 : int ResultCursor::getError() const {
     745           0 :         return err;
     746             : }
     747             : 
     748             : }

Generated by: LCOV version 1.14