LCOV - code coverage report
Current view: top level - core/db/sqlite - SPSqliteHandle.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 231 357 64.7 %
Date: 2024-05-12 00:16:13 Functions: 32 43 74.4 %

          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 "SPSqliteHandle.h"
      25             : #include "SPSqliteDriver.h"
      26             : #include "SPSqliteDriverHandle.h"
      27             : #include "sqlite3.h"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler::db::sqlite {
      30             : 
      31             : class SqliteQuery : public db::sql::SqlQuery {
      32             : public:
      33       13775 :         virtual ~SqliteQuery() = default;
      34             : 
      35       13775 :         SqliteQuery(db::QueryInterface *q, const sql::Driver *d)
      36       13775 :         : SqlQuery(q, d) { }
      37             : 
      38         250 :         virtual void writeFullTextWhere(WhereContinue &whi, db::Operator op, const db::Scheme &scheme,
      39             :                         const db::Query::Select &sel, StringView ftsQuery) override {
      40         250 :                 auto functionCall = toString("sp_ts_query_valid(\"", scheme.getName(), "\".\"", sel.field, "\", '", ftsQuery, "')");
      41         250 :                 whi.where(op,
      42         250 :                                 SqlQuery::Field(StringView(functionCall), SqlQuery::Field::PlainText),
      43         250 :                                 Comparation::Equal, RawStringView{StringView("1")});
      44         250 :         }
      45             : };
      46             : 
      47       13775 : SqliteQueryInterface::SqliteQueryInterface(const sql::Driver *d, const sql::QueryStorageHandle *s, Driver::Handle h)
      48       13775 : : driver(d), storage(s), handle(h) { }
      49             : 
      50        1325 : size_t SqliteQueryInterface::push(String &&val) {
      51        1325 :         auto &it = params.emplace_back(BindingData());
      52        1325 :         it.data.assign_strong((uint8_t *)val.data(), val.size() + 1);
      53        1325 :         it.idx = params.size();
      54        1325 :         it.type = Type::Text;
      55        1325 :         return it.idx;
      56             : }
      57             : 
      58        3500 : size_t SqliteQueryInterface::push(const StringView &val) {
      59        3500 :         auto &it = params.emplace_back(BindingData());
      60        3500 :         it.data.assign_strong((uint8_t *)val.data(), val.size() + 1);
      61        3500 :         it.data.data()[val.size()] = 0;
      62        3500 :         it.idx = params.size();
      63        3500 :         it.type = Type::Text;
      64        3500 :         return it.idx;
      65             : }
      66             : 
      67       12850 : size_t SqliteQueryInterface::push(Bytes &&val) {
      68       12850 :         auto &it = params.emplace_back(BindingData());
      69       12850 :         it.data = std::move(val);
      70       12850 :         it.idx = params.size();
      71       12850 :         it.type = Type::Bytes;
      72       12850 :         return it.idx;
      73             : }
      74             : 
      75       26575 : size_t SqliteQueryInterface::push(StringStream &query, const Value &val, bool force, bool compress) {
      76       26575 :         if (!force || val.getType() == Value::Type::EMPTY) {
      77       18025 :                 switch (val.getType()) {
      78          50 :                 case Value::Type::EMPTY: query << "NULL"; break;
      79        3300 :                 case Value::Type::BOOLEAN: query << (val.asBool() ? "TRUE" : "FALSE"); break;
      80        8025 :                 case Value::Type::INTEGER: query << val.asInteger(); break;
      81        1750 :                 case Value::Type::DOUBLE:
      82        1750 :                         if (std::isnan(val.asDouble())) {
      83           0 :                                 query << "'NaN'";
      84        1750 :                         } else if (val.asDouble() == std::numeric_limits<double>::infinity()) {
      85           0 :                                 query << "'-Infinity'";
      86        1750 :                         } else if (-val.asDouble() == std::numeric_limits<double>::infinity()) {
      87           0 :                                 query << "'Infinity'";
      88             :                         } else {
      89        1750 :                                 query << std::setprecision(std::numeric_limits<double>::max_digits10 + 1) << val.asDouble();
      90             :                         }
      91        1750 :                         break;
      92        3100 :                 case Value::Type::CHARSTRING:
      93        3100 :                         query << "?" << push(val.getString());
      94        3100 :                         break;
      95        1800 :                 case Value::Type::BYTESTRING:
      96        1800 :                         query << "?" << push(val.asBytes());
      97        1800 :                         break;
      98           0 :                 case Value::Type::ARRAY:
      99             :                 case Value::Type::DICTIONARY:
     100           0 :                         query << "?" << push(data::write<Interface>(val, EncodeFormat(EncodeFormat::Cbor,
     101           0 :                                         compress ? EncodeFormat::LZ4HCCompression : EncodeFormat::DefaultCompress)));
     102           0 :                         break;
     103           0 :                 default: break;
     104             :                 }
     105             :         } else {
     106       25650 :                 query << "?" << push(data::write<Interface>(val, EncodeFormat(EncodeFormat::Cbor,
     107       17100 :                                 compress ? EncodeFormat::LZ4HCCompression : EncodeFormat::DefaultCompress)));
     108             :         }
     109       26575 :         return params.size();
     110             : }
     111             : 
     112        5500 : void SqliteQueryInterface::bindInt(db::Binder &, StringStream &query, int64_t val) {
     113        5500 :         query << val;
     114        5500 : }
     115        4725 : void SqliteQueryInterface::bindUInt(db::Binder &, StringStream &query, uint64_t val) {
     116        4725 :         query << val;
     117        4725 : }
     118           0 : void SqliteQueryInterface::bindDouble(db::Binder &, StringStream &query, double val) {
     119           0 :         query << std::setprecision(std::numeric_limits<double>::max_digits10 + 1) << val;
     120           0 : }
     121           0 : void SqliteQueryInterface::bindString(db::Binder &, StringStream &query, const String &val) {
     122           0 :         if (auto num = push(String(val))) {
     123           0 :                 query << "?" << num;
     124             :         }
     125           0 : }
     126        1225 : void SqliteQueryInterface::bindMoveString(db::Binder &, StringStream &query, String &&val) {
     127        1225 :         if (auto num = push(std::move(val))) {
     128        1225 :                 query << "?" << num;
     129             :         }
     130        1225 : }
     131         350 : void SqliteQueryInterface::bindStringView(db::Binder &, StringStream &query, const StringView &val) {
     132         350 :         if (auto num = push(val)) {
     133         350 :                 query << "?" << num;
     134             :         }
     135         350 : }
     136          50 : void SqliteQueryInterface::bindBytes(db::Binder &, StringStream &query, const Bytes &val) {
     137          50 :         if (auto num = push(Bytes(val))) {
     138          50 :                 query << "?" << num;
     139             :         }
     140          50 : }
     141         175 : void SqliteQueryInterface::bindMoveBytes(db::Binder &, StringStream &query, Bytes &&val) {
     142         175 :         if (auto num = push(std::move(val))) {
     143         175 :                 query << "?" << num;
     144             :         }
     145         175 : }
     146         475 : void SqliteQueryInterface::bindCoderSource(db::Binder &, StringStream &query, const stappler::CoderSource &val) {
     147         475 :         if (auto num = push(Bytes(val.data(), val.data() + val.size()))) {
     148         475 :                 query << "?" << num;
     149             :         }
     150         475 : }
     151        2250 : void SqliteQueryInterface::bindValue(db::Binder &, StringStream &query, const Value &val) {
     152        2250 :         push(query, val, false);
     153        2250 : }
     154       24325 : void SqliteQueryInterface::bindDataField(db::Binder &, StringStream &query, const db::Binder::DataField &f) {
     155       24325 :         if (f.field && f.field->getType() == db::Type::Custom) {
     156        5200 :                 auto c = f.field->getSlot<db::FieldCustom>();
     157        5200 :                 if (auto info = driver->getCustomFieldInfo(c->getDriverTypeName())) {
     158        5200 :                         if (!info->writeToStorage(*c, *this, query, f.data)) {
     159           0 :                                 query << "NULL";
     160             :                         }
     161             :                 } else {
     162           0 :                         query << "NULL";
     163             :                 }
     164             :         } else {
     165       19125 :                 push(query, f.data, f.force, f.compress);
     166             :         }
     167       24325 : }
     168          50 : void SqliteQueryInterface::bindTypeString(db::Binder &, StringStream &query, const db::Binder::TypeString &type) {
     169          50 :         if (auto num = push(type.str)) {
     170          50 :                 query << "?" << num;
     171             :         }
     172          50 : }
     173             : 
     174        1800 : void SqliteQueryInterface::bindFullText(db::Binder &, StringStream &query, const db::Binder::FullTextField &d) {
     175        1800 :         auto slot = d.field->getSlot<FieldFullTextView>();
     176        1800 :         auto result = slot->searchConfiguration->encodeSearchVectorData(d.data);
     177        1800 :         if (auto num = push(move(result))) {
     178        1800 :                 query << "?" << num;
     179             :         }
     180             : 
     181        1800 :         storage->data->emplace(d.field->getName(), &d.data);
     182        1800 : }
     183             : 
     184         250 : void SqliteQueryInterface::bindFullTextFrom(db::Binder &, StringStream &query, const db::Binder::FullTextFrom &d) {
     185         250 :         auto tableName = toString(d.scheme, "_f_", d.field->getName());
     186         250 :         auto fieldId = toString(d.scheme, "_id");
     187             : 
     188         250 :         auto &storageData = *storage->data;
     189             : 
     190         250 :         auto it = storageData.find(d.query);
     191         250 :         if (it != storageData.end()) {
     192         250 :                 auto q = (TextQueryData *)it->second;
     193         250 :                 query << " INNER JOIN (SELECT DISTINCT \"" << fieldId << "\" as id FROM \"" << tableName << "\" WHERE word IN (";
     194             : 
     195         250 :                 bool first = true;
     196         525 :                 for (auto &w : q->pos) {
     197         275 :                         if (first) { first = false; } else { query << ","; }
     198         275 :                         query << w;
     199             :                 }
     200             : 
     201           0 :                 query << ")) AS \"__" << d.scheme << "_" << d.field->getName() << "\""
     202         250 :                         " ON (\"" << d.scheme << "\".__oid=\"__" << d.scheme << "_" << d.field->getName() << "\".id)";
     203             :         }
     204         250 : }
     205             : 
     206         250 : void SqliteQueryInterface::bindFullTextRank(db::Binder &, StringStream &query, const db::Binder::FullTextRank &d) {
     207         250 :         auto slot = d.field->getSlot<FieldFullTextView>();
     208         250 :         query << " sp_ts_rank(" << d.scheme << ".\"" << d.field->getName() << "\", '" << d.query << "', " << toInt(slot->normalization) << ")";
     209         250 : }
     210             : 
     211         250 : void SqliteQueryInterface::bindFullTextQuery(db::Binder &, StringStream &query, const db::Binder::FullTextQueryRef &d) {
     212         250 :         query << d.scheme << "." << d.field->getName();
     213             : 
     214         250 :         auto it = storage->data->find(query.weak());
     215         250 :         while (it != storage->data->end()) {
     216           0 :                 query << "_";
     217           0 :                 it = storage->data->find(query.weak());
     218             :         }
     219             : 
     220         250 :         auto q = new TextQueryData;
     221         250 :         q->query = &d.query;
     222         250 :         q->query->decompose([&, this] (StringView pos) {
     223         275 :                 emplace_ordered(q->pos, ((const Driver *)driver)->insertWord(handle, pos));
     224         275 :         }, [&, this] (StringView neg) {
     225           0 :                 emplace_ordered(q->neg, ((const Driver *)driver)->insertWord(handle, neg));
     226           0 :         });
     227             : 
     228         250 :         auto str = StringView(query.weak());
     229         250 :         storage->data->emplace(str.pdup(), q);
     230         250 : }
     231             : 
     232         150 : void SqliteQueryInterface::bindIntVector(Binder &, StringStream &query, const Vector<int64_t> &vec) {
     233         150 :         query << "(";
     234         150 :         bool start = true;
     235         325 :         for (auto &it : vec) {
     236         175 :                 if (start) { start = false; } else { query << ","; }
     237         175 :                 query << it;
     238             :         }
     239         150 :         query << ")";
     240         150 : }
     241             : 
     242           0 : void SqliteQueryInterface::bindDoubleVector(Binder &b, StringStream &query, const Vector<double> &vec) {
     243           0 :         query << "(";
     244           0 :         bool start = true;
     245           0 :         for (auto &it : vec) {
     246           0 :                 if (start) { start = false; } else { query << ","; }
     247           0 :                 bindDouble(b, query, it);
     248             :         }
     249           0 :         query << ")";
     250           0 : }
     251             : 
     252           0 : void SqliteQueryInterface::bindStringVector(Binder &b, StringStream &query, const Vector<StringView> &vec) {
     253           0 :         query << "(";
     254           0 :         bool start = true;
     255           0 :         for (auto &it : vec) {
     256           0 :                 if (start) { start = false; } else { query << ","; }
     257           0 :                 bindStringView(b, query, it);
     258             :         }
     259           0 :         query << ")";
     260           0 : }
     261             : 
     262        5450 : void SqliteQueryInterface::clear() {
     263        5450 :         params.clear();
     264        5450 : }
     265             : 
     266        5323 : Handle::Handle(const Driver *d, Driver::Handle h) : SqlHandle(d), driver(d), handle(h) {
     267        5321 :         _profile = stappler::sql::Profile::Sqlite;
     268        5321 :         if (h.get()) {
     269        5322 :                 auto c = d->getConnection(h);
     270        5322 :                 if (c.get()) {
     271        5322 :                         conn = c;
     272        5322 :                         dbName = driver->getDbName(h);
     273             :                 }
     274             :         }
     275        5323 : }
     276             : 
     277           0 : Handle::operator bool() const {
     278           0 :         return conn.get() != nullptr;
     279             : }
     280             : 
     281           0 : Driver::Handle Handle::getHandle() const {
     282           0 :         return handle;
     283             : }
     284             : 
     285           0 : Driver::Connection Handle::getConnection() const {
     286           0 :         return conn;
     287             : }
     288             : 
     289           0 : void Handle::close() {
     290           0 :         conn = Driver::Connection(nullptr);
     291           0 : }
     292             : 
     293       13775 : void Handle::makeQuery(const stappler::Callback<void(sql::SqlQuery &)> &cb, const sql::QueryStorageHandle *storage) {
     294       13775 :         SqliteQueryInterface interface(_driver, storage, handle);
     295       13775 :         SqliteQuery query(&interface, _driver);
     296       13775 :         query.setProfile(_profile);
     297       13775 :         cb(query);
     298       13775 : }
     299             : 
     300       14950 : bool Handle::selectQuery(const sql::SqlQuery &query, const stappler::Callback<bool(sql::Result &)> &cb,
     301             :                 const Callback<void(const Value &)> &errCb) {
     302       14950 :         if (!conn.get() || getTransactionStatus() == db::TransactionStatus::Rollback) {
     303           0 :                 return false;
     304             :         }
     305             : 
     306       14950 :         auto queryInterface = static_cast<SqliteQueryInterface *>(query.getInterface());
     307             : 
     308       14950 :         auto queryString = query.getQuery().weak();
     309             : 
     310       14950 :         sqlite3_stmt *stmt = nullptr;
     311       14950 :         auto err = sqlite3_prepare_v3((sqlite3 *)conn.get(), queryString.data(), queryString.size(), 0, &stmt, nullptr);
     312       14950 :         if (err != SQLITE_OK) {
     313           0 :                 auto info = driver->getInfo(conn, err);
     314           0 :                 info.setString(query.getQuery().str(), "query");
     315             : #if DEBUG
     316           0 :                 log::debug("pq::Handle", EncodeFormat::Pretty, info);
     317             : #endif
     318           0 :                 if (errCb) {
     319           0 :                         errCb(info);
     320             :                 }
     321           0 :                 driver->getApplicationInterface()->debug("Database", "Fail to perform query", std::move(info));
     322           0 :                 driver->getApplicationInterface()->error("Database", "Fail to perform query");
     323           0 :                 cancelTransaction();
     324           0 :                 return false;
     325           0 :         }
     326             : 
     327             :         // bind
     328       32625 :         for (auto &it : queryInterface->params) {
     329       17675 :                 switch (it.type) {
     330        4825 :                 case Type::Text:
     331        4825 :                         sqlite3_bind_text(stmt, it.idx, (const char *)it.data.data(), it.data.size() - 1, SQLITE_STATIC);
     332        4825 :                         break;
     333       12850 :                 case Type::Bytes:
     334       12850 :                         sqlite3_bind_blob(stmt, it.idx, it.data.data(), it.data.size(), SQLITE_STATIC);
     335       12850 :                         break;
     336           0 :                 default:
     337           0 :                         break;
     338             :                 }
     339             :         }
     340             : 
     341       14950 :         err = sqlite3_step(stmt);
     342       14950 :         if (err != SQLITE_OK && err != SQLITE_DONE && err != SQLITE_ROW) {
     343           0 :                 auto info = driver->getInfo(conn, err);
     344           0 :                 info.setString(query.getQuery().str(), "query");
     345             : #if DEBUG
     346           0 :                 log::debug("pq::Handle", EncodeFormat::Pretty, info);
     347             : #endif
     348           0 :                 if (errCb) {
     349           0 :                         errCb(info);
     350             :                 }
     351           0 :                 driver->getApplicationInterface()->debug("Database", "Fail to perform query", std::move(info));
     352           0 :                 driver->getApplicationInterface()->error("Database", "Fail to perform query");
     353           0 :                 sqlite3_finalize(stmt);
     354           0 :                 cancelTransaction();
     355           0 :                 return false;
     356           0 :         }
     357             : 
     358       29900 :         ResultCursor cursor(driver, conn, Driver::Result(stmt), err);
     359       14950 :         db::sql::Result ret(&cursor);
     360       14950 :         cb(ret);
     361       14950 :         return true;
     362       14950 : }
     363             : 
     364       12196 : bool Handle::performSimpleQuery(const StringView &query, const Callback<void(const Value &)> &errCb) {
     365       12196 :         if (getTransactionStatus() == db::TransactionStatus::Rollback) {
     366           0 :                 return false;
     367             :         }
     368             : 
     369       12196 :         StringView queryData = query;
     370             : 
     371       12196 :         const char *outPtr = query.data();
     372       12196 :         bool success = true;
     373       29921 :         while (outPtr && *outPtr != 0 && success) {
     374       17946 :                 auto size = queryData.size() - (outPtr - queryData.data());
     375       17945 :                 StringView nextQuery(outPtr, size);
     376       17944 :                 nextQuery.skipChars<StringView::WhiteSpace>();
     377       17944 :                 if (nextQuery.empty()) {
     378         225 :                         break;
     379             :                 }
     380             : 
     381       17721 :                 sqlite3_stmt *stmt = nullptr;
     382       17721 :                 auto err = sqlite3_prepare_v3((sqlite3 *)conn.get(), nextQuery.data(), nextQuery.size(), 0, &stmt, &outPtr);
     383       17724 :                 if (err != SQLITE_OK) {
     384           0 :                         auto len = outPtr - nextQuery.data();
     385           0 :                         StringView performedQuery(nextQuery.data(), len);
     386           0 :                         auto info = driver->getInfo(conn, err);
     387           0 :                         info.setString(performedQuery, "query");
     388             : #if DEBUG
     389           0 :                         log::debug("pq::Handle", EncodeFormat::Pretty, info);
     390             : #endif
     391           0 :                         if (errCb) {
     392           0 :                                 errCb(info);
     393             :                         }
     394           0 :                         driver->getApplicationInterface()->debug("Database", "Fail to perform query", std::move(info));
     395           0 :                         driver->getApplicationInterface()->error("Database", "Fail to perform query");
     396           0 :                         cancelTransaction();
     397           0 :                         return false;
     398           0 :                 }
     399             : 
     400       17724 :                 err = sqlite3_step(stmt);
     401             : 
     402       17724 :                 if (err != SQLITE_OK && err != SQLITE_DONE && err != SQLITE_ROW) {
     403           0 :                         auto info = driver->getInfo(conn, err);
     404           0 :                         info.setString(nextQuery, "query");
     405             : #if DEBUG
     406           0 :                         log::debug("pq::Handle", EncodeFormat::Pretty, info);
     407             : #endif
     408           0 :                         if (errCb) {
     409           0 :                                 errCb(info);
     410             :                         }
     411           0 :                         driver->getApplicationInterface()->debug("Database", "Fail to perform query", std::move(info));
     412           0 :                         driver->getApplicationInterface()->error("Database", "Fail to perform query");
     413           0 :                         sqlite3_finalize(stmt);
     414           0 :                         cancelTransaction();
     415           0 :                         return false;
     416           0 :                 }
     417             : 
     418       17724 :                 success = ResultCursor::statusIsSuccess(err);
     419       17720 :                 sqlite3_finalize(stmt);
     420             :         }
     421       12200 :         return success;
     422             : }
     423             : 
     424        1650 : bool Handle::performSimpleSelect(const StringView &query, const stappler::Callback<void(sql::Result &)> &cb,
     425             :                 const Callback<void(const Value &)> &errCb) {
     426        1650 :         if (getTransactionStatus() == db::TransactionStatus::Rollback) {
     427           0 :                 return false;
     428             :         }
     429             : 
     430        1650 :         sqlite3_stmt *stmt = nullptr;
     431        1650 :         auto err = sqlite3_prepare_v3((sqlite3 *)conn.get(), query.data(), query.size(), 0, &stmt, nullptr);
     432        1650 :         if (err != SQLITE_OK) {
     433           0 :                 auto info = driver->getInfo(conn, err);
     434           0 :                 info.setString(query, "query");
     435             : #if DEBUG
     436           0 :                 log::debug("pq::Handle", EncodeFormat::Pretty, info);
     437             : #endif
     438           0 :                 if (errCb) {
     439           0 :                         errCb(info);
     440             :                 }
     441           0 :                 driver->getApplicationInterface()->debug("Database", "Fail to perform query", std::move(info));
     442           0 :                 driver->getApplicationInterface()->error("Database", "Fail to perform query");
     443           0 :                 cancelTransaction();
     444           0 :                 return false;
     445           0 :         }
     446             : 
     447        1650 :         err = sqlite3_step(stmt);
     448             : 
     449        1650 :         ResultCursor cursor(driver, conn, Driver::Result(stmt), err);
     450        1650 :         db::sql::Result ret(&cursor);
     451        1650 :         cb(ret);
     452        1650 :         return true;
     453        1650 : }
     454             : 
     455           0 : bool Handle::isSuccess() const {
     456           0 :         return ResultCursor::statusIsSuccess(lastError);
     457             : }
     458             : 
     459        5949 : bool Handle::beginTransaction() {
     460        5949 :         if (transactionStatus != db::TransactionStatus::None) {
     461          50 :                 return false;
     462             :         }
     463             : 
     464        5899 :         if (_driver->getApplicationInterface()) {
     465        5900 :                 driver->setUserId(handle, _driver->getApplicationInterface()->getUserIdFromContext());
     466             :         }
     467             : 
     468        5900 :         switch (level) {
     469        4125 :         case TransactionLevel::Deferred:
     470        4125 :                 if (performSimpleQuery("BEGIN DEFERRED"_weak)) {
     471        4122 :                         level = TransactionLevel::Deferred;
     472        4122 :                         transactionStatus = db::TransactionStatus::Commit;
     473        4122 :                         return true;
     474             :                 }
     475           0 :                 break;
     476           0 :         case TransactionLevel::Immediate:
     477           0 :                 if (performSimpleQuery("BEGIN IMMEDIATE"_weak)) {
     478           0 :                         level = TransactionLevel::Immediate;
     479           0 :                         transactionStatus = db::TransactionStatus::Commit;
     480           0 :                         return true;
     481             :                 }
     482           0 :                 break;
     483        1775 :         case TransactionLevel::Exclusive:
     484        1775 :                 if (performSimpleQuery("BEGIN EXCLUSIVE"_weak)) {
     485        1775 :                         level = TransactionLevel::Exclusive;
     486        1775 :                         transactionStatus = db::TransactionStatus::Commit;
     487        1775 :                         return true;
     488             :                 }
     489           0 :                 break;
     490           0 :         default:
     491           0 :                 break;
     492             :         }
     493           0 :         return false;
     494             : }
     495             : 
     496        5949 : bool Handle::endTransaction() {
     497        5949 :         switch (transactionStatus) {
     498        5899 :         case db::TransactionStatus::Commit:
     499        5899 :                 transactionStatus = db::TransactionStatus::None;
     500        5899 :                 if (performSimpleQuery("COMMIT"_weak)) {
     501        5900 :                         finalizeBroadcast();
     502        5898 :                         return true;
     503             :                 }
     504           0 :                 break;
     505           0 :         case db::TransactionStatus::Rollback:
     506           0 :                 transactionStatus = db::TransactionStatus::None;
     507           0 :                 if (performSimpleQuery("ROLLBACK"_weak)) {
     508           0 :                         finalizeBroadcast();
     509           0 :                         return false;
     510             :                 }
     511           0 :                 break;
     512          50 :         default:
     513          50 :                 break;
     514             :         }
     515          50 :         return false;
     516             : }
     517             : 
     518             : }

Generated by: LCOV version 1.14