Branch data Line data Source code
1 : : /******************************************************************************
2 : : ------------- Copyright (c) 2009-2023 H a r a l d A c h i t z ---------------
3 : : ---------- < h a r a l d dot a c h i t z at g m a i l dot c o m > ------------
4 : : ---- This Source Code Form is subject to the terms of the Mozilla Public -----
5 : : ---- License, v. 2.0. If a copy of the MPL was not distributed with this -----
6 : : ---------- file, You can obtain one at http://mozilla.org/MPL/2.0/. ----------
7 : : ******************************************************************************/
8 : :
9 : : #include <sl3/database.hpp>
10 : :
11 : : #include <sqlite3.h>
12 : :
13 : : #include "connection.hpp"
14 : :
15 : : namespace
16 : : {
17 : : sqlite3*
18 : 102 : opendb (const std::string& name, int openFlags)
19 : : {
20 [ + - ]: 102 : if (openFlags == 0)
21 : : {
22 : 102 : openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
23 : : }
24 : :
25 : 102 : sqlite3* db = nullptr;
26 [ + - ]: 102 : auto sl3rc = sqlite3_open_v2 (name.c_str (), &db, openFlags, nullptr);
27 : :
28 [ + + ]: 102 : if (sl3rc != SQLITE_OK)
29 : : {
30 : : using scope_guard
31 : : = std::unique_ptr<sqlite3, decltype (&sqlite3_close)>;
32 : 1 : scope_guard guard{db, &sqlite3_close};
33 [ + - + - ]: 1 : throw sl3::SQLite3Error{sl3rc, sqlite3_errmsg (db)};
34 : 1 : }
35 : 101 : return db;
36 : : }
37 : :
38 : : }
39 : :
40 : : namespace sl3
41 : : {
42 : :
43 : : std::string
44 : 4 : getErrStr (int errcode)
45 : : {
46 [ + - + - ]: 8 : return std::string (sqlite3_errstr (errcode));
47 : : }
48 : :
49 : 102 : Database::Database (const std::string& name, int flags)
50 [ + + + - : 102 : : _connection{new internal::Connection{opendb (name, flags)}}
+ - ]
51 : : {
52 [ + - ]: 101 : sqlite3_extended_result_codes (_connection->db (), true);
53 : 101 : }
54 : :
55 : 11 : Database::Database (Database&& other) noexcept
56 : 11 : : _connection (std::move (other._connection))
57 : : {
58 : : // always have a connection, but an invalid one
59 : 11 : other._connection.reset (new internal::Connection{nullptr});
60 : 11 : }
61 : :
62 : 112 : Database::~Database () noexcept
63 : : {
64 [ + - ]: 112 : if (_connection != nullptr)
65 : : {
66 : 112 : _connection->close ();
67 : : }
68 : 112 : }
69 : :
70 : : Command
71 : 55 : Database::prepare (const std::string& sql)
72 : : {
73 [ + + ]: 55 : return {_connection, sql};
74 : : }
75 : :
76 : : Command
77 : 9 : Database::prepare (const std::string& sql, const DbValues& parameters)
78 : : {
79 [ + - + + ]: 14 : return {_connection, sql, parameters};
80 : : }
81 : :
82 : : void
83 : 1 : Database::execute (const std::string& sql)
84 : : {
85 : 1 : execute (sql.c_str ());
86 : 1 : }
87 : :
88 : : void
89 : 102 : Database::execute (const char* sql)
90 : : {
91 [ + + ]: 102 : _connection->ensureValid ();
92 : 100 : char* dbMsg = nullptr;
93 : :
94 [ + - ]: 100 : int rc = sqlite3_exec (_connection->db (), sql, nullptr, nullptr, &dbMsg);
95 : :
96 [ + + ]: 100 : if (rc != SQLITE_OK)
97 : : {
98 : : using scope_guard = std::unique_ptr<char, decltype (&sqlite3_free)>;
99 : 6 : scope_guard guard (dbMsg, &sqlite3_free);
100 [ + - ]: 6 : throw SQLite3Error{rc, dbMsg};
101 : 6 : }
102 : 94 : }
103 : :
104 : : void
105 : 7 : Database::execute (const std::string& sql, RowCallback& cb)
106 : : {
107 [ + + + - ]: 7 : prepare (sql).execute (cb);
108 : 5 : }
109 : :
110 : : void
111 : 29 : Database::execute (const std::string& sql, Callback cb)
112 : : {
113 [ + + + - ]: 29 : prepare (sql).execute (std::move (cb));
114 : 27 : }
115 : :
116 : : Dataset
117 : 20 : Database::select (const std::string& sql)
118 : : {
119 [ + + + - ]: 22 : return Command (_connection, sql).select ();
120 : : }
121 : :
122 : : Dataset
123 : 22 : Database::select (const std::string& sql, const Types& types)
124 : : {
125 [ + + + + ]: 33 : return Command (_connection, sql).select (types);
126 : : }
127 : :
128 : : DbValue
129 : 7 : Database::selectValue (const std::string& sql)
130 : : {
131 : 7 : DbValue retVal (Type::Variant);
132 : :
133 : 19 : Callback cb = [&retVal] (Columns cols) -> bool {
134 [ + - + - ]: 5 : retVal = cols.getValue (0);
135 : 5 : return false; // exit after first row
136 : 7 : };
137 : :
138 [ + + ]: 9 : Command cmd (_connection, sql);
139 [ + - + - ]: 5 : cmd.execute (cb);
140 : :
141 : 10 : return retVal;
142 : 9 : }
143 : :
144 : : DbValue
145 : 5 : Database::selectValue (const std::string& sql, Type type)
146 : : {
147 : 5 : DbValue retVal{type};
148 : :
149 : 13 : Callback cb = [&retVal, type] (Columns cols) -> bool {
150 [ + + + - ]: 3 : retVal = cols.getValue (0, type);
151 : 2 : return false; // exit after first row
152 : 5 : };
153 : :
154 [ + + ]: 7 : Command cmd (_connection, sql);
155 [ + - + + ]: 5 : cmd.execute (cb);
156 : :
157 : 4 : return retVal;
158 : 9 : }
159 : :
160 : : int
161 : 5 : Database::getMostRecentErrCode ()
162 : : {
163 : 5 : _connection->ensureValid ();
164 : 4 : return sqlite3_extended_errcode (_connection->db ());
165 : : }
166 : :
167 : : std::string
168 : 5 : Database::getMostRecentErrMsg ()
169 : : {
170 : 5 : _connection->ensureValid ();
171 [ + - + - ]: 8 : return std::string (sqlite3_errmsg (_connection->db ()));
172 : : }
173 : :
174 : : std::size_t
175 : 9 : Database::getTotalChanges ()
176 : : {
177 : 9 : _connection->ensureValid ();
178 : : return static_cast<std::size_t> (
179 : 8 : sqlite3_total_changes (_connection->db ()));
180 : : }
181 : :
182 : : std::size_t
183 : 5 : Database::getRecentlyChanged ()
184 : : {
185 : 5 : _connection->ensureValid ();
186 : 4 : return static_cast<std::size_t> (sqlite3_changes (_connection->db ()));
187 : : }
188 : :
189 : : int64_t
190 : 4 : Database::getLastInsertRowid ()
191 : : {
192 : 4 : _connection->ensureValid ();
193 : 3 : return sqlite3_last_insert_rowid (_connection->db ());
194 : : }
195 : :
196 : : sqlite3*
197 : 2 : Database::db ()
198 : : {
199 : 2 : return _connection->db ();
200 : : }
201 : :
202 : : auto
203 : 4 : Database::beginTransaction () -> Transaction
204 : : {
205 : 4 : return Transaction{*this};
206 : : }
207 : :
208 : 4 : Database::Transaction::Transaction (Database& db)
209 : 4 : : _db (&db)
210 : : {
211 : 4 : _db->execute ("BEGIN TRANSACTION");
212 : 4 : }
213 : :
214 : 2 : Database::Transaction::Transaction (Transaction&& other) noexcept
215 : 2 : : _db (other._db)
216 : : {
217 : 2 : other._db = nullptr; // ensure other does not commit in d'tor
218 : 2 : }
219 : :
220 : 6 : Database::Transaction::~Transaction ()
221 : : {
222 [ + + ]: 6 : if (_db)
223 : 2 : _db->execute ("ROLLBACK TRANSACTION");
224 : 6 : }
225 : :
226 : : void
227 : 3 : Database::Transaction::commit ()
228 : : {
229 [ + + ]: 3 : if (_db)
230 : : {
231 : 2 : _db->execute ("COMMIT TRANSACTION");
232 : 2 : _db = nullptr;
233 : : }
234 : 3 : }
235 : :
236 : : } // ns
|