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> ¶ms) 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 : }
|