LCOV - code coverage report
Current view: top level - core/db/sql - SPSqlHandle.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 278 418 66.5 %
Date: 2024-05-12 00:16:13 Functions: 54 62 87.1 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2018-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 "SPSqlHandle.h"
      25             : #include "SPSqlDriver.h"
      26             : #include "SPDbFile.h"
      27             : #include "SPDbScheme.h"
      28             : #include "SPDbUser.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::db::sql {
      31             : 
      32         375 : StringView SqlHandle::getKeyValueSchemeName() {
      33         375 :         return "__sessions";
      34             : }
      35             : 
      36        1550 : String SqlHandle::getNameForDelta(const Scheme &scheme) {
      37        3100 :         return toString("__delta_", scheme.getName());
      38             : }
      39             : 
      40         250 : Value SqlHandle::get(const stappler::CoderSource &key) {
      41         250 :         Value ret;
      42         250 :         makeQuery([&, this] (SqlQuery &query) {
      43         250 :                 query.select("data").from(getKeyValueSchemeName()).where("name", Comparation::Equal, key).finalize();
      44         500 :                 selectQuery(query, [&] (Result &res) {
      45         250 :                         if (!res.empty()) {
      46         500 :                                 ret = data::read<Interface, BytesView>(res.current().toBytes(0));
      47             :                         }
      48         250 :                         return true;
      49             :                 });
      50         250 :         }, nullptr);
      51         250 :         return ret;
      52           0 : }
      53             : 
      54        5699 : SqlHandle::SqlHandle(const Driver *driver) : _driver(driver) { }
      55             : 
      56         125 : bool SqlHandle::set(const stappler::CoderSource &key, const Value &data, stappler::TimeInterval maxage) {
      57         125 :         bool ret = false;
      58         125 :         makeQuery([&, this] (SqlQuery &query) {
      59         125 :                 query.insert(getKeyValueSchemeName()).fields("name", "mtime", "maxage", "data")
      60         125 :                         .values(key, stappler::Time::now().toSeconds(), maxage.toSeconds(), data::write<Interface>(data, stappler::data::EncodeFormat::Cbor))
      61         250 :                         .onConflict("name").doUpdate().excluded("mtime").excluded("maxage").excluded("data")
      62         125 :                         .finalize();
      63         125 :                 ret = (performQuery(query) != stappler::maxOf<size_t>());
      64         125 :         }, nullptr);
      65         125 :         return ret;
      66             : }
      67             : 
      68         100 : bool SqlHandle::clear(const stappler::CoderSource &key) {
      69         100 :         bool ret = false;
      70         100 :         makeQuery([&, this] (SqlQuery &query) {
      71         100 :                 query.remove("__sessions").where("name", Comparation::Equal, key).finalize();
      72         100 :                 ret = (performQuery(query) == 1); // one row should be affected
      73         100 :         }, nullptr);
      74         100 :         return ret;
      75             : }
      76             : 
      77         575 : db::User * SqlHandle::authorizeUser(const db::Auth &auth, const StringView &iname, const StringView &password) {
      78         575 :         auto namePair = auth.getNameField(iname);
      79         575 :         auto paswodField = auth.getPasswordField();
      80             : 
      81         575 :         if (!namePair.first || !paswodField) {
      82           0 :                 _driver->getApplicationInterface()->error("Auth", "Invalid scheme: fields 'name', 'email' and 'password' is not defined");
      83           0 :                 return nullptr;
      84             :         }
      85             : 
      86         575 :         auto minTime = stappler::Time::now() - config::AUTH_MAX_TIME;
      87             : 
      88         575 :         bool transactionStarted = false;
      89         575 :         if (transactionStatus == TransactionStatus::None) {
      90          50 :                 transactionStarted = beginTransaction();
      91             :         }
      92             : 
      93         575 :         db::User *ret = nullptr;
      94         575 :         makeQuery([&, this] (SqlQuery &query) {
      95         575 :                 query.with("u", [&] (SqlQuery::GenericQuery &q) {
      96         575 :                         q.select().from(auth.getScheme().getName())
      97        1150 :                                 .where(namePair.first->getName(), Comparation::Equal, std::move(namePair.second));
      98        1150 :                 }).with("l", [&] (SqlQuery::GenericQuery &q) {
      99        1150 :                         q.select().count("failed_count").from("__login").innerJoinOn("u", [&] (SqlQuery::WhereBegin &w) {
     100         575 :                                 w.where(SqlQuery::Field( "__login", "user"), Comparation::Equal, SqlQuery::Field("u", "__oid"))
     101         575 :                                                 .where(Operator::And, SqlQuery::Field( "__login", "success"), Comparation::Equal, Value(false))
     102        1725 :                                                 .where(Operator::And, SqlQuery::Field( "__login", "date"), Comparation::GreatherThen, uint64_t((minTime).toSeconds()));
     103         575 :                         });
     104        1150 :                 }).select().from("l", "u").finalize();
     105             : 
     106         575 :                 size_t count = 0;
     107         575 :                 Value ud;
     108         575 :                 selectQuery(query, [&, this] (Result &res) {
     109         575 :                         count = res.current().toInteger(0);
     110             : 
     111         575 :                         if (count >= size_t(config::AUTH_MAX_LOGIN_ATTEMPT)) {
     112           0 :                                 _driver->getApplicationInterface()->error("Auth", "Autorization blocked", Value{
     113           0 :                                         stappler::pair("cooldown", Value((int64_t)config::AUTH_MAX_TIME.toSeconds())),
     114           0 :                                         stappler::pair("failedAttempts", Value((int64_t)count)),
     115           0 :                                 });
     116           0 :                                 return false;
     117             :                         }
     118             : 
     119         575 :                         auto dv = res.decode(auth.getScheme(), Vector<const Field *>());
     120         575 :                         if (dv.size() == 1) {
     121         550 :                                 ud = std::move(dv.getValue(0));
     122             :                         }
     123         575 :                         return true;
     124         575 :                 });
     125             : 
     126         575 :                 if (!ud) {
     127          25 :                         return;
     128             :                 }
     129             : 
     130         550 :                 bool success = false;
     131         550 :                 auto req = _driver->getApplicationInterface()->getRequestData();
     132         550 :                 auto passwd = ud.getBytes("password");
     133             : 
     134         550 :                 auto userId = ud.getInteger("__oid");
     135         550 :                 if (auth.authorizeWithPassword(password, passwd, count)) {
     136         550 :                         ret = new db::User(std::move(ud), auth.getScheme());
     137         550 :                         success = true;
     138             :                 }
     139             : 
     140         550 :                 query.clear();
     141             : 
     142         550 :                 query.with("u", [&] (SqlQuery::GenericQuery &q) {
     143         550 :                         q.select().from(auth.getScheme().getName())
     144         550 :                                 .where(namePair.first->getName(), Comparation::Equal, std::move(namePair.second));
     145        1100 :                 }).with("l", [&] (SqlQuery::GenericQuery &q) {
     146        1100 :                         q.select().aggregate("MAX", SqlQuery::Field("id").as("maxId")).from("__login").innerJoinOn("u", [&] (SqlQuery::WhereBegin &w) {
     147         550 :                                 w.where(SqlQuery::Field( "__login", "user"), Comparation::Equal, SqlQuery::Field("u", "__oid"))
     148         550 :                                                 .where(Operator::And, SqlQuery::Field( "__login", "success"), Comparation::Equal, Value(true))
     149        1100 :                                                 .where(Operator::And, SqlQuery::Field( "__login", "date"), Comparation::GreatherThen, uint64_t((minTime).toSeconds()));
     150         550 :                         });
     151        1100 :                 }).select().from("l", "u").finalize();
     152             : 
     153        1100 :                 selectQuery(query, [&, this] (Result &res) {
     154         550 :                         query.clear();
     155         550 :                         int64_t id = 0;
     156         550 :                         if (!res.empty() && (id = res.readId())) {
     157         500 :                                 query.update("__login").set("date", stappler::Time::now().toSeconds())
     158         500 :                                                 .where("id", Comparation::Equal, Value(id)).finalize();
     159         500 :                                 performQuery(query);
     160             :                         } else {
     161          50 :                                 auto &f = query.insert("__login")
     162          50 :                                         .fields("user", "name", "password", "date", "success", "addr", "host", "path");
     163          50 :                                 if (req) {
     164         650 :                                         f.values(userId, iname, passwd, stappler::Time::now().toSeconds(), Value(success),
     165          50 :                                                         SqlQuery::TypeString(req.address, "inet"),
     166         100 :                                                         req.hostname.str<Interface>(),
     167         100 :                                                         req.uri.str<Interface>())
     168          50 :                                                 .finalize();
     169             :                                 } else {
     170           0 :                                         f.values(userId, iname, passwd, stappler::Time::now().toSeconds(), Value(success),
     171           0 :                                                         SqlQuery::TypeString("NULL", "inet"), String("NULL"), String("NULL"))
     172           0 :                                                 .finalize();
     173             :                                 }
     174          50 :                                 performQuery(query);
     175             :                         }
     176         550 :                         return true;
     177             :                 });
     178         575 :         }, nullptr);
     179             : 
     180         575 :         if (transactionStarted) {
     181          50 :                 endTransaction();
     182             :         }
     183             : 
     184         575 :         return ret;
     185         575 : }
     186             : 
     187           0 : void SqlHandle::makeSessionsCleanup() {
     188           0 :         bool transactionStarted = false;
     189           0 :         if (transactionStatus == TransactionStatus::None) {
     190           0 :                 beginTransaction();
     191           0 :                 transactionStarted = true;
     192             :         }
     193             : 
     194           0 :         StringStream query;
     195           0 :         query << "DELETE FROM __sessions WHERE (mtime + maxage + 10) < " << stappler::Time::now().toSeconds() << ";";
     196           0 :         performSimpleQuery(query.weak());
     197             : 
     198           0 :         query.clear();
     199           0 :         query << "DELETE FROM __removed RETURNING __oid;";
     200           0 :         performSimpleSelect(query.weak(), [&, this] (Result &res) {
     201           0 :                 if (res.empty()) {
     202           0 :                         return;
     203             :                 }
     204             : 
     205           0 :                 query.clear();
     206           0 :                 query << "SELECT obj.__oid AS id FROM __files obj WHERE obj.__oid IN (";
     207             : 
     208           0 :                 bool first = true;
     209           0 :                 for (auto it : res) {
     210           0 :                         if (first) { first = false; } else { query << ","; }
     211           0 :                         query << it.at(0);
     212             :                 }
     213           0 :                 query << ");";
     214           0 :                 performSimpleSelect(query.weak(), [&, this] (Result &res) {
     215           0 :                         if (!res.empty()) {
     216           0 :                                 query.clear();
     217           0 :                                 query << "DELETE FROM __files WHERE __oid IN (";
     218           0 :                                 first = true;
     219             :                                 // check for files to remove
     220           0 :                                 for (auto it : res) {
     221           0 :                                         if (auto fileId = it.toInteger(0)) {
     222           0 :                                                 db::File::removeFile(_driver->getApplicationInterface(), fileId);
     223           0 :                                                 if (first) { first = false; } else { query << ","; }
     224           0 :                                                 query << fileId;
     225             :                                         }
     226             :                                 }
     227           0 :                                 query << ");";
     228           0 :                                 performSimpleQuery(query.weak());
     229             :                         }
     230           0 :                 });
     231             :         });
     232             : 
     233           0 :         query.clear();
     234           0 :         query << "DELETE FROM __broadcasts WHERE date < " << (stappler::Time::now() - stappler::TimeInterval::seconds(10)).toMicroseconds() << ";";
     235           0 :         performSimpleQuery(query.weak());
     236             : 
     237           0 :         if (transactionStarted) {
     238           0 :                 endTransaction();
     239             :         }
     240           0 : }
     241             : 
     242        6273 : void SqlHandle::finalizeBroadcast() {
     243        6273 :         if (!_bcasts.empty()) {
     244           0 :                 makeQuery([&, this] (SqlQuery &query) {
     245           0 :                         auto vals = query.insert("__broadcasts").fields("date", "msg").values();
     246           0 :                         for (auto &it : _bcasts) {
     247           0 :                                 vals.values(it.first, std::move(it.second));
     248             :                         }
     249           0 :                         query.finalize();
     250           0 :                         performQuery(query);
     251           0 :                         _bcasts.clear();
     252           0 :                 }, nullptr);
     253             :         }
     254        6274 : }
     255             : 
     256           0 : int64_t SqlHandle::processBroadcasts(const stappler::Callback<void(BytesView)> &cb, int64_t value) {
     257           0 :         int64_t maxId = value;
     258           0 :         makeQuery([&, this] (SqlQuery &query) {
     259           0 :                 if (value <= 0) {
     260           0 :                         query.select("last_value").from("__broadcasts_id_seq").finalize();
     261           0 :                         maxId = selectQueryId(query);
     262             :                 } else {
     263           0 :                         query.select("id", "date", "msg").from("__broadcasts")
     264           0 :                                         .where("id", Comparation::GreatherThen, value).finalize();
     265           0 :                         selectQuery(query, [&] (Result &res) {
     266           0 :                                 for (auto it : res) {
     267           0 :                                         if (it.size() >= 3) {
     268           0 :                                                 auto msgId = it.toInteger(0);
     269           0 :                                                 auto msgData = it.toBytes(2);
     270           0 :                                                 if (!msgData.empty()) {
     271           0 :                                                         if (msgId > maxId) {
     272           0 :                                                                 maxId = msgId;
     273             :                                                         }
     274           0 :                                                         cb(msgData);
     275             :                                                 }
     276             :                                         }
     277             :                                 }
     278           0 :                                 return true;
     279             :                         });
     280             :                 }
     281           0 :         }, nullptr);
     282           0 :         return maxId;
     283             : }
     284             : 
     285          50 : void SqlHandle::broadcast(const Bytes &bytes) {
     286          50 :         if (getTransactionStatus() == db::TransactionStatus::None) {
     287          50 :                 makeQuery([&, this] (SqlQuery &query) {
     288          50 :                         query.insert("__broadcasts").fields("date", "msg").values(stappler::Time::now(), Bytes(bytes)).finalize();
     289          50 :                         performQuery(query);
     290          50 :                 }, nullptr);
     291          50 :                 if (isNotificationsSupported()) {
     292           0 :                         makeQuery([&, this] (SqlQuery &query) {
     293           0 :                                 query.getStream() << "NOTIFY " << config::BROADCAST_CHANNEL_NAME << ";";
     294           0 :                                 performQuery(query);
     295           0 :                         }, nullptr);
     296             :                 }
     297             :         } else {
     298           0 :                 _bcasts.emplace_back(stappler::Time::now(), bytes);
     299             :         }
     300          50 : }
     301             : 
     302         100 : static bool Handle_convertViewDelta(Value &it) {
     303         100 :         auto vid_it = it.asDict().find("__vid");
     304         100 :         auto d_it = it.asDict().find("__delta");
     305         100 :         if (vid_it != it.asDict().end() && d_it != it.asDict().end()) {
     306           0 :                 if (vid_it->second.getInteger()) {
     307           0 :                         d_it->second.setString("update", "action");
     308           0 :                         it.asDict().erase(vid_it);
     309             :                 } else {
     310           0 :                         d_it->second.setString("delete", "action");
     311           0 :                         auto dict_it = it.asDict().begin();
     312           0 :                         while (dict_it != it.asDict().end()) {
     313           0 :                                 if (dict_it->first != "__oid" && dict_it->first != "__delta") {
     314           0 :                                         dict_it = it.asDict().erase(dict_it);
     315             :                                 } else {
     316           0 :                                         ++ dict_it;
     317             :                                 }
     318             :                         }
     319           0 :                         return false;
     320             :                 }
     321             :         }
     322         100 :         return true;
     323             : }
     324             : 
     325          50 : static void Handle_mergeViews(Value &objs, Value &vals) {
     326         150 :         for (auto &it : objs.asArray()) {
     327         100 :                 if (!Handle_convertViewDelta(it)) {
     328           0 :                         continue;
     329             :                 }
     330             : 
     331         100 :                 if (auto oid = it.getInteger("__oid")) {
     332         100 :                         auto v_it = std::lower_bound(vals.asArray().begin(), vals.asArray().end(), oid,
     333         200 :                                         [&] (const Value &l, int64_t r) -> bool {
     334         200 :                                 return (l.isInteger() ? l.getInteger() : l.getInteger("__oid")) < r;
     335         100 :                         });
     336         100 :                         if (v_it != vals.asArray().end()) {
     337         100 :                                 auto objId = v_it->getInteger("__oid");
     338         100 :                                 if (objId == oid) {
     339         100 :                                         v_it->erase("__oid");
     340         100 :                                         if (it.hasValue("__views")) {
     341           0 :                                                 it.getValue("__views").addValue(std::move(*v_it));
     342             :                                         } else {
     343         100 :                                                 it.emplace("__views").addValue(std::move(*v_it));
     344             :                                         }
     345         100 :                                         v_it->setInteger(oid);
     346             :                                 }
     347             :                         }
     348             :                 }
     349             :         }
     350          50 : }
     351             : 
     352        1025 : int64_t SqlHandle::getDeltaValue(const Scheme &scheme) {
     353        1025 :         if (scheme.hasDelta()) {
     354         275 :                 int64_t ret = 0;
     355         275 :                 makeQuery([&, this] (SqlQuery &q) {
     356         275 :                         q.select().aggregate("max", SqlQuery::Field("d", "time"))
     357         275 :                                         .from(SqlQuery::Field(getNameForDelta(scheme)).as("d")).finalize();
     358         550 :                         selectQuery(q, [&] (Result &res) {
     359         275 :                                 if (res) {
     360         550 :                                         ret = res.current().toInteger(0);
     361             :                                 }
     362         275 :                                 return true;
     363             :                         });
     364         275 :                 }, nullptr);
     365         275 :                 return ret;
     366             :         }
     367         750 :         return 0;
     368             : }
     369             : 
     370          50 : int64_t SqlHandle::getDeltaValue(const Scheme &scheme, const db::FieldView &view, uint64_t tag) {
     371          50 :         if (view.delta) {
     372          50 :                 int64_t ret = 0;
     373          50 :                 makeQuery([&, this] (SqlQuery &q) {
     374          50 :                         String deltaName = toString(scheme.getName(), "_f_", view.name, "_delta");
     375          50 :                         q.select().aggregate("max", SqlQuery::Field("d", "time"))
     376          50 :                                         .from(SqlQuery::Field(deltaName).as("d")).where("tag", Comparation::Equal, tag).finalize();
     377         100 :                         selectQuery(q, [&] (Result &res) {
     378          50 :                                 if (res) {
     379         100 :                                         ret = res.current().toInteger(0);
     380             :                                 }
     381          50 :                                 return true;
     382             :                         });
     383          50 :                 }, nullptr);
     384          50 :                 return ret;
     385             :         }
     386           0 :         return 0;
     387             : }
     388             : 
     389          25 : Value SqlHandle::getHistory(const Scheme &scheme, const stappler::Time &time, bool resolveUsers) {
     390          25 :         Value ret;
     391          25 :         if (!scheme.hasDelta()) {
     392           0 :                 return ret;
     393             :         }
     394             : 
     395          25 :         makeQuery([&, this] (SqlQuery &q) {
     396          25 :                 q.select().from(getNameForDelta(scheme)).where("time", Comparation::GreatherThen, time.toMicroseconds())
     397          25 :                                 .order(db::Ordering::Descending, "time").finalize();
     398             : 
     399          50 :                 selectQuery(q, [&, this] (Result &res) {
     400         150 :                         for (auto it : res) {
     401         125 :                                 auto &d = ret.emplace();
     402         625 :                                 for (size_t i = 0; i < it.size(); ++ i) {
     403         500 :                                         auto name = res.name(i);
     404         500 :                                         if (name == "action") {
     405         125 :                                                 switch (DeltaAction(it.toInteger(i))) {
     406          25 :                                                 case DeltaAction::Create: d.setString("create", "action"); break;
     407         100 :                                                 case DeltaAction::Update: d.setString("update", "action"); break;
     408           0 :                                                 case DeltaAction::Delete: d.setString("delete", "action"); break;
     409           0 :                                                 case DeltaAction::Append: d.setString("append", "action"); break;
     410           0 :                                                 case DeltaAction::Erase:d.setString("erase", "action");  break;
     411           0 :                                                 default: break;
     412             :                                                 }
     413         375 :                                         } else if (name == "time") {
     414         125 :                                                 d.setString(Time::microseconds(it.toInteger(i)).toHttp<Interface>(), "http-date");
     415         125 :                                                 d.setInteger(it.toInteger(i), "time");
     416         275 :                                         } else if (name == "user" && resolveUsers) {
     417         125 :                                                 if (auto u = db::User::get(db::Adapter(this, _driver->getApplicationInterface()), it.toInteger(i))) {
     418           0 :                                                         auto &ud = d.emplace("user");
     419           0 :                                                         ud.setInteger(u->getObjectId(), "id");
     420           0 :                                                         ud.setString(u->getName(), "name");
     421             :                                                 } else {
     422         125 :                                                         d.setInteger(it.toInteger(i), name.str<Interface>());
     423             :                                                 }
     424         125 :                                         } else if (name != "id") {
     425         125 :                                                 d.setInteger(it.toInteger(i), name.str<Interface>());
     426             :                                         }
     427             :                                 }
     428             :                         }
     429          25 :                         return true;
     430             :                 });
     431          25 :         }, nullptr);
     432          25 :         return ret;
     433           0 : }
     434             : 
     435          25 : Value SqlHandle::getHistory(const db::FieldView &view, const Scheme *scheme, uint64_t tag, const stappler::Time &time, bool resolveUsers) {
     436          25 :         Value ret;
     437          25 :         if (!view.delta) {
     438           0 :                 return ret;
     439             :         }
     440             : 
     441          25 :         makeQuery([&, this] (SqlQuery &q) {
     442          25 :                 String name = toString(scheme->getName(), "_f_", view.name, "_delta");
     443          25 :                 q.select().from(name).where("time", Comparation::GreatherThen, time.toMicroseconds())
     444          25 :                                 .where(Operator::And, "tag", Comparation::Equal, tag)
     445          25 :                                 .order(db::Ordering::Descending, "time").finalize();
     446             : 
     447          50 :                 selectQuery(q, [&, this] (Result &res) {
     448          25 :                         for (auto it : res) {
     449           0 :                                 auto &d = ret.emplace();
     450           0 :                                 for (size_t i = 0; i < it.size(); ++ i) {
     451           0 :                                         auto name = res.name(i);
     452           0 :                                         if (name == "tag") {
     453           0 :                                                 d.setInteger(it.toInteger(i), "tag");
     454           0 :                                         } else if (name == "time") {
     455           0 :                                                 d.setString(Time::microseconds(it.toInteger(i)).toHttp<Interface>(), "http-date");
     456           0 :                                                 d.setInteger(it.toInteger(i), "time");
     457          25 :                                         } else if (name == "user" && resolveUsers) {
     458           0 :                                                 if (auto u = db::User::get(db::Adapter(this, _driver->getApplicationInterface()), it.toInteger(i))) {
     459           0 :                                                         auto &ud = d.emplace("user");
     460           0 :                                                         ud.setInteger(u->getObjectId(), "id");
     461           0 :                                                         ud.setString(u->getName(), "name");
     462             :                                                 } else {
     463           0 :                                                         d.setInteger(it.toInteger(i), name.str<Interface>());
     464             :                                                 }
     465           0 :                                         } else if (name != "id") {
     466           0 :                                                 d.setInteger(it.toInteger(i), name.str<Interface>());
     467             :                                         }
     468             :                                 }
     469             :                         }
     470          25 :                         return true;
     471             :                 });
     472          25 :         }, nullptr);
     473             : 
     474          25 :         return ret;
     475           0 : }
     476             : 
     477          25 : Value SqlHandle::getDeltaData(const Scheme &scheme, const stappler::Time &time) {
     478          25 :         Value ret;
     479          25 :         if (scheme.hasDelta()) {
     480          25 :                 makeQuery([&, this] (SqlQuery &q) {
     481          25 :                         FieldResolver resv(scheme);
     482          25 :                         q.writeQueryDelta(scheme, time, Set<const Field *>(), false);
     483          25 :                         q.finalize();
     484          25 :                         ret = selectValueQuery(scheme, q, resv.getVirtuals());
     485          25 :                 }, nullptr);
     486             :         }
     487          25 :         return ret;
     488           0 : }
     489             : 
     490          50 : SPUNUSED static void Handle_writeSelectViewDataQuery(SqlQuery &q, const db::Scheme &s, uint64_t oid, const db::FieldView &f, const Value &data) {
     491          50 :         auto fs = f.scheme;
     492             : 
     493          50 :         auto fieldName = toString(fs->getName(), "_id");
     494          50 :         auto sel = q.select(SqlQuery::Field(fieldName).as("__oid")).field("__vid");
     495             : 
     496          50 :         sel.from(toString(s.getName(), "_f_", f.getName(), "_view"))
     497         100 :                 .where(toString(s.getName(), "_id"), db::Comparation::Equal, oid)
     498          50 :                 .parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &w) {
     499          50 :                         auto subw = w.where();
     500         150 :                         for (auto &it : data.asArray()) {
     501         100 :                                 subw.where(db::Operator::Or, fieldName, db::Comparation::Equal, it.getInteger("__oid"));
     502             :                         }
     503         100 :         }).order(db::Ordering::Ascending, SqlQuery::Field(fieldName)).finalize();
     504          50 : }
     505             : 
     506          25 : Value SqlHandle::getDeltaData(const Scheme &scheme, const db::FieldView &view, const stappler::Time &time, uint64_t tag) {
     507          25 :         Value ret;
     508          25 :         if (view.delta) {
     509          25 :                 makeQuery([&, this] (SqlQuery &q) {
     510          25 :                         Field field(&view);
     511          25 :                         QueryList list(_driver->getApplicationInterface(), &scheme);
     512          25 :                         list.selectById(&scheme, tag);
     513          25 :                         list.setField(view.scheme, &field);
     514             : 
     515          25 :                         FieldResolver resv(scheme);
     516             : 
     517          25 :                         q.writeQueryViewDelta(list, time, Set<const Field *>(), false);
     518          25 :                         auto r = selectValueQuery(*view.scheme, q, resv.getVirtuals());
     519          25 :                         if (r.isArray() && r.size() > 0) {
     520           0 :                                 q.clear();
     521           0 :                                 Field f(&view);
     522           0 :                                 Handle_writeSelectViewDataQuery(q, scheme, tag, view, r);
     523           0 :                                 selectValueQuery(r, view, q);
     524           0 :                                 ret = std::move(r);
     525             :                         }
     526          25 :                 }, nullptr);
     527             :         }
     528          25 :         return ret;
     529           0 : }
     530             : 
     531        3625 : int64_t SqlHandle::selectQueryId(const SqlQuery &query) {
     532        3625 :         if (getTransactionStatus() == db::TransactionStatus::Rollback) {
     533           0 :                 return 0;
     534             :         }
     535        3625 :         int64_t id = 0;
     536        3625 :         selectQuery(query, [&] (Result &res) {
     537        3625 :                 if (!res.empty()) {
     538        3625 :                         id = res.readId();
     539        3625 :                         return true;
     540             :                 }
     541           0 :                 return false;
     542             :         });
     543        3625 :         return id;
     544             : }
     545             : 
     546        1850 : size_t SqlHandle::performQuery(const SqlQuery &query) {
     547        1850 :         if (getTransactionStatus() == db::TransactionStatus::Rollback) {
     548           0 :                 return stappler::maxOf<size_t>();
     549             :         }
     550        1850 :         size_t ret = stappler::maxOf<size_t>();
     551        1850 :         selectQuery(query, [&] (Result &res) {
     552        1850 :                 if (res.success()) {
     553        1850 :                         ret = res.getAffectedRows();
     554        1850 :                         return true;
     555             :                 }
     556           0 :                 return false;
     557             :         });
     558        1850 :         return ret;
     559             : }
     560             : 
     561       10350 : Value SqlHandle::selectValueQuery(const Scheme &scheme, const SqlQuery &query, const Vector<const Field *> &virtuals) {
     562       10350 :         Value ret;
     563       10350 :         selectQuery(query, [&] (Result &result) {
     564       10350 :                 if (result) {
     565       10350 :                         ret = result.decode(scheme, virtuals);
     566       10350 :                         return true;
     567             :                 }
     568           0 :                 return false;
     569             :         });
     570       10350 :         return ret;
     571           0 : }
     572             : 
     573          50 : Value SqlHandle::selectValueQuery(const Field &field, const SqlQuery &query, const Vector<const Field *> &virtuals) {
     574          50 :         Value ret;
     575          50 :         selectQuery(query, [&] (Result &result) {
     576          50 :                 if (result) {
     577          50 :                         ret = result.decode(field, virtuals);
     578          50 :                         return true;
     579             :                 }
     580           0 :                 return false;
     581             :         });
     582          50 :         return ret;
     583           0 : }
     584             : 
     585          50 : void SqlHandle::selectValueQuery(Value &objs, const FieldView &field, const SqlQuery &query) {
     586          50 :         selectQuery(query, [&] (Result &result) {
     587          50 :                 if (result) {
     588          50 :                         auto vals = result.decode(field);
     589          50 :                         if (!vals.isArray()) {
     590           0 :                                 for (auto &it : objs.asArray()) {
     591           0 :                                         Handle_convertViewDelta(it);
     592             :                                 }
     593          50 :                         } else if (vals.isArray() && objs.isArray()) {
     594          50 :                                 Handle_mergeViews(objs, vals);
     595             :                         }
     596          50 :                         return true;
     597          50 :                 }
     598           0 :                 return false;
     599             :         });
     600          50 : }
     601             : 
     602             : }

Generated by: LCOV version 1.14