Skip to content

Commit cc66ccf

Browse files
authored
Merge pull request #333 Added Database and Statement method getChanges() from SRombauts/get-changes
Fix #331 How to get the number of updated/deleted rows?
2 parents 0c46d86 + 64c34bc commit cc66ccf

File tree

8 files changed

+55
-14
lines changed

8 files changed

+55
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,4 @@ Version 3.x - 2021
196196
- #314 Add Database constructor for filesystem::path (#296) from ptrks
197197
- #295 Compile internal SQLite library with -ffunction-sections from smichaku
198198
- #299 Added Savepoint support from catalogm
199+
- #333 Added Database and Statement getChanges()

examples/example1/main.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Demonstrates how-to use the SQLite++ wrapper
66
*
7-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
88
*
99
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
1010
* or copy at http://opensource.org/licenses/MIT)
@@ -308,6 +308,9 @@ int main ()
308308
nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
309309
std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl;
310310

311+
nb = db.getTotalChanges();
312+
std::cout << "Nb of total changes since connection: " << nb << std::endl;
313+
311314
// Check the results : expect two row of result
312315
SQLite::Statement query(db, "SELECT * FROM test");
313316
std::cout << "SELECT * FROM test :\n";

include/SQLiteCpp/Database.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @ingroup SQLiteCpp
44
* @brief Management of a SQLite Database Connection.
55
*
6-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
77
*
88
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
99
* or copy at http://opensource.org/licenses/MIT)
@@ -14,7 +14,7 @@
1414

1515
// c++17: MinGW GCC version > 8
1616
// c++17: Visual Studio 2017 version 15.7
17-
#if ((__cplusplus >= 201703L) && ((!defined(__MINGW32__) && !defined(__MINGW64__)) || (__GNUC__ > 8))) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
17+
#if ((__cplusplus >= 201703L) && ((!defined(__MINGW32__) && !defined(__MINGW64__)) || (__GNUC__ > 8))) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) // NOLINT
1818
#include <filesystem>
1919
#endif // c++17
2020

@@ -169,7 +169,7 @@ class Database
169169

170170
// c++17: MinGW GCC version > 8
171171
// c++17: Visual Studio 2017 version 15.7
172-
#if ((__cplusplus >= 201703L) && ((!defined(__MINGW32__) && !defined(__MINGW64__)) || (__GNUC__ > 8))) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
172+
#if ((__cplusplus >= 201703L) && ((!defined(__MINGW32__) && !defined(__MINGW64__)) || (__GNUC__ > 8))) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) // NOLINT
173173

174174
/**
175175
* @brief Open the provided database std::filesystem::path.
@@ -241,7 +241,7 @@ class Database
241241
void setBusyTimeout(const int aBusyTimeoutMs);
242242

243243
/**
244-
* @brief Shortcut to execute one or multiple statements without results.
244+
* @brief Shortcut to execute one or multiple statements without results. Return the number of changes.
245245
*
246246
* This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
247247
* - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
@@ -404,6 +404,9 @@ class Database
404404
*/
405405
long long getLastInsertRowid() const noexcept;
406406

407+
/// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
408+
int getChanges() const noexcept;
409+
407410
/// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection (not DROP table).
408411
int getTotalChanges() const noexcept;
409412

include/SQLiteCpp/Statement.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @ingroup SQLiteCpp
44
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
55
*
6-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
77
*
88
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
99
* or copy at http://opensource.org/licenses/MIT)
@@ -471,7 +471,7 @@ class Statement
471471
int tryExecuteStep() noexcept;
472472

473473
/**
474-
* @brief Execute a one-step query with no expected result.
474+
* @brief Execute a one-step query with no expected result, and return the number of changes.
475475
*
476476
* This method is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
477477
* - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
@@ -488,7 +488,7 @@ class Statement
488488
*
489489
* @return number of row modified by this SQL statement (INSERT, UPDATE or DELETE)
490490
*
491-
* @throw SQLite::Exception in case of error, or if row of results are returned !
491+
* @throw SQLite::Exception in case of error, or if row of results are returned while they are not expected!
492492
*/
493493
int exec();
494494

@@ -660,6 +660,9 @@ class Statement
660660
const char * getColumnDeclaredType(const int aIndex) const;
661661

662662

663+
/// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
664+
int getChanges() const noexcept;
665+
663666

664667
////////////////////////////////////////////////////////////////////////////
665668

src/Database.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @ingroup SQLiteCpp
44
* @brief Management of a SQLite Database Connection.
55
*
6-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
77
*
88
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
99
* or copy at http://opensource.org/licenses/MIT)
@@ -113,6 +113,7 @@ void Database::setBusyTimeout(const int aBusyTimeoutMs)
113113
}
114114

115115
// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
116+
// Return the number of changes.
116117
int Database::exec(const char* apQueries)
117118
{
118119
const int ret = tryExec(apQueries);
@@ -155,6 +156,12 @@ long long Database::getLastInsertRowid() const noexcept
155156
return sqlite3_last_insert_rowid(getHandle());
156157
}
157158

159+
// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
160+
int Database::getChanges() const noexcept
161+
{
162+
return sqlite3_changes(getHandle());
163+
}
164+
158165
// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection.
159166
int Database::getTotalChanges() const noexcept
160167
{

src/Statement.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @ingroup SQLiteCpp
44
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
55
*
6-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
77
*
88
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
99
* or copy at http://opensource.org/licenses/MIT)
@@ -167,7 +167,7 @@ bool Statement::executeStep()
167167
return mbHasRow; // true only if one row is accessible by getColumn(N)
168168
}
169169

170-
// Execute a one-step query with no expected result
170+
// Execute a one-step query with no expected result, and return the number of changes.
171171
int Statement::exec()
172172
{
173173
const int ret = tryExecuteStep();
@@ -310,6 +310,12 @@ const char * Statement::getColumnDeclaredType(const int aIndex) const
310310
}
311311
}
312312

313+
// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
314+
int Statement::getChanges() const noexcept
315+
{
316+
return sqlite3_changes(mStmtPtr);
317+
}
318+
313319
int Statement::getBindParameterCount() const noexcept
314320
{
315321
return sqlite3_bind_parameter_count(mStmtPtr);

tests/Column_test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @ingroup tests
44
* @brief Test of a SQLiteCpp Column.
55
*
6-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
77
*
88
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
99
* or copy at http://opensource.org/licenses/MIT)
@@ -44,6 +44,7 @@ TEST(Column, basis)
4444
// Execute the one-step query to insert the row
4545
EXPECT_EQ(1, insert.exec());
4646
EXPECT_EQ(1, db.getLastInsertRowid());
47+
EXPECT_EQ(1, db.getChanges());
4748
EXPECT_EQ(1, db.getTotalChanges());
4849

4950
EXPECT_THROW(insert.exec(), SQLite::Exception); // exec() shall throw as it needs to be reseted
@@ -230,6 +231,7 @@ TEST(Column, stream)
230231
insert.bind(1, str);
231232
// Execute the one-step query to insert the row
232233
EXPECT_EQ(1, insert.exec());
234+
EXPECT_EQ(1, db.getChanges());
233235
EXPECT_EQ(1, db.getTotalChanges());
234236

235237
SQLite::Statement query(db, "SELECT * FROM test");

tests/Database_test.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @ingroup tests
44
* @brief Test of a SQLiteCpp Database.
55
*
6-
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6+
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
77
*
88
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
99
* or copy at http://opensource.org/licenses/MIT)
@@ -211,32 +211,38 @@ TEST(Database, exec)
211211
// NOTE: here exec() returns 0 only because it is the first statements since database connexion,
212212
// but its return is an undefined value for "CREATE TABLE" statements.
213213
db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");
214+
EXPECT_EQ(0, db.getChanges());
214215
EXPECT_EQ(0, db.getLastInsertRowid());
215216
EXPECT_EQ(0, db.getTotalChanges());
216217

217218
// first row : insert the "first" text value into new row of id 1
218219
EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\")"));
220+
EXPECT_EQ(1, db.getChanges());
219221
EXPECT_EQ(1, db.getLastInsertRowid());
220222
EXPECT_EQ(1, db.getTotalChanges());
221223

222224
// second row : insert the "second" text value into new row of id 2
223225
EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"second\")"));
226+
EXPECT_EQ(1, db.getChanges());
224227
EXPECT_EQ(2, db.getLastInsertRowid());
225228
EXPECT_EQ(2, db.getTotalChanges());
226229

227230
// third row : insert the "third" text value into new row of id 3
228231
const std::string insert("INSERT INTO test VALUES (NULL, \"third\")");
229232
EXPECT_EQ(1, db.exec(insert));
233+
EXPECT_EQ(1, db.getChanges());
230234
EXPECT_EQ(3, db.getLastInsertRowid());
231235
EXPECT_EQ(3, db.getTotalChanges());
232236

233237
// update the second row : update text value to "second_updated"
234238
EXPECT_EQ(1, db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'"));
239+
EXPECT_EQ(1, db.getChanges());
235240
EXPECT_EQ(3, db.getLastInsertRowid()); // last inserted row ID is still 3
236241
EXPECT_EQ(4, db.getTotalChanges());
237242

238243
// delete the third row
239244
EXPECT_EQ(1, db.exec("DELETE FROM test WHERE id='3'"));
245+
EXPECT_EQ(1, db.getChanges());
240246
EXPECT_EQ(3, db.getLastInsertRowid());
241247
EXPECT_EQ(5, db.getTotalChanges());
242248

@@ -253,12 +259,14 @@ TEST(Database, exec)
253259

254260
// insert two rows with two *different* statements => returns only 1, ie. for the second INSERT statement
255261
EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\");INSERT INTO test VALUES (NULL, \"second\");"));
262+
EXPECT_EQ(1, db.getChanges());
256263
EXPECT_EQ(2, db.getLastInsertRowid());
257264
EXPECT_EQ(7, db.getTotalChanges());
258265

259266
#if (SQLITE_VERSION_NUMBER >= 3007011)
260267
// insert two rows with only one statement (starting with SQLite 3.7.11) => returns 2
261268
EXPECT_EQ(2, db.exec("INSERT INTO test VALUES (NULL, \"third\"), (NULL, \"fourth\");"));
269+
EXPECT_EQ(2, db.getChanges());
262270
EXPECT_EQ(4, db.getLastInsertRowid());
263271
EXPECT_EQ(9, db.getTotalChanges());
264272
#endif
@@ -271,32 +279,38 @@ TEST(Database, tryExec)
271279

272280
// Create a new table with an explicit "id" column aliasing the underlying rowid
273281
EXPECT_EQ(SQLite::OK, db.tryExec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"));
282+
EXPECT_EQ(0, db.getChanges());
274283
EXPECT_EQ(0, db.getLastInsertRowid());
275284
EXPECT_EQ(0, db.getTotalChanges());
276285

277286
// first row : insert the "first" text value into new row of id 1
278287
EXPECT_EQ(SQLite::OK, db.tryExec("INSERT INTO test VALUES (NULL, \"first\")"));
288+
EXPECT_EQ(1, db.getChanges());
279289
EXPECT_EQ(1, db.getLastInsertRowid());
280290
EXPECT_EQ(1, db.getTotalChanges());
281291

282292
// second row : insert the "second" text value into new row of id 2
283293
EXPECT_EQ(SQLite::OK, db.tryExec("INSERT INTO test VALUES (NULL, \"second\")"));
294+
EXPECT_EQ(1, db.getChanges());
284295
EXPECT_EQ(2, db.getLastInsertRowid());
285296
EXPECT_EQ(2, db.getTotalChanges());
286297

287298
// third row : insert the "third" text value into new row of id 3
288299
const std::string insert("INSERT INTO test VALUES (NULL, \"third\")");
289300
EXPECT_EQ(SQLite::OK, db.tryExec(insert));
301+
EXPECT_EQ(1, db.getChanges());
290302
EXPECT_EQ(3, db.getLastInsertRowid());
291303
EXPECT_EQ(3, db.getTotalChanges());
292304

293305
// update the second row : update text value to "second_updated"
294306
EXPECT_EQ(SQLite::OK, db.tryExec("UPDATE test SET value=\"second-updated\" WHERE id='2'"));
307+
EXPECT_EQ(1, db.getChanges());
295308
EXPECT_EQ(3, db.getLastInsertRowid()); // last inserted row ID is still 3
296309
EXPECT_EQ(4, db.getTotalChanges());
297310

298311
// delete the third row
299312
EXPECT_EQ(SQLite::OK, db.tryExec("DELETE FROM test WHERE id='3'"));
313+
EXPECT_EQ(1, db.getChanges());
300314
EXPECT_EQ(3, db.getLastInsertRowid());
301315
EXPECT_EQ(5, db.getTotalChanges());
302316

@@ -309,14 +323,16 @@ TEST(Database, tryExec)
309323
EXPECT_EQ(SQLite::OK, db.tryExec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"));
310324
EXPECT_EQ(5, db.getTotalChanges());
311325

312-
// insert two rows with two *different* statements => returns only 1, ie. for the second INSERT statement
326+
// insert two rows with two *different* statements => only 1 change, ie. for the second INSERT statement
313327
EXPECT_EQ(SQLite::OK, db.tryExec("INSERT INTO test VALUES (NULL, \"first\");INSERT INTO test VALUES (NULL, \"second\");"));
328+
EXPECT_EQ(1, db.getChanges());
314329
EXPECT_EQ(2, db.getLastInsertRowid());
315330
EXPECT_EQ(7, db.getTotalChanges());
316331

317332
#if (SQLITE_VERSION_NUMBER >= 3007011)
318333
// insert two rows with only one statement (starting with SQLite 3.7.11)
319334
EXPECT_EQ(SQLite::OK, db.tryExec("INSERT INTO test VALUES (NULL, \"third\"), (NULL, \"fourth\");"));
335+
EXPECT_EQ(2, db.getChanges());
320336
EXPECT_EQ(4, db.getLastInsertRowid());
321337
EXPECT_EQ(9, db.getTotalChanges());
322338
#endif

0 commit comments

Comments
 (0)