Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,4 @@ Version 3.x - 2021
- #314 Add Database constructor for filesystem::path (#296) from ptrks
- #295 Compile internal SQLite library with -ffunction-sections from smichaku
- #299 Added Savepoint support from catalogm
- #333 Added Database and Statement getChanges()
5 changes: 4 additions & 1 deletion examples/example1/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* Demonstrates how-to use the SQLite++ wrapper
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand Down Expand Up @@ -308,6 +308,9 @@ int main ()
nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl;

nb = db.getTotalChanges();
std::cout << "Nb of total changes since connection: " << nb << std::endl;

// Check the results : expect two row of result
SQLite::Statement query(db, "SELECT * FROM test");
std::cout << "SELECT * FROM test :\n";
Expand Down
11 changes: 7 additions & 4 deletions include/SQLiteCpp/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @ingroup SQLiteCpp
* @brief Management of a SQLite Database Connection.
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand All @@ -14,7 +14,7 @@

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

Expand Down Expand Up @@ -169,7 +169,7 @@ class Database

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

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

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

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

/// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection (not DROP table).
int getTotalChanges() const noexcept;

Expand Down
9 changes: 6 additions & 3 deletions include/SQLiteCpp/Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @ingroup SQLiteCpp
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand Down Expand Up @@ -471,7 +471,7 @@ class Statement
int tryExecuteStep() noexcept;

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

Expand Down Expand Up @@ -660,6 +660,9 @@ class Statement
const char * getColumnDeclaredType(const int aIndex) const;


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


////////////////////////////////////////////////////////////////////////////

Expand Down
9 changes: 8 additions & 1 deletion src/Database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @ingroup SQLiteCpp
* @brief Management of a SQLite Database Connection.
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand Down Expand Up @@ -113,6 +113,7 @@ void Database::setBusyTimeout(const int aBusyTimeoutMs)
}

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

// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
int Database::getChanges() const noexcept
{
return sqlite3_changes(getHandle());
}

// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection.
int Database::getTotalChanges() const noexcept
{
Expand Down
10 changes: 8 additions & 2 deletions src/Statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @ingroup SQLiteCpp
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand Down Expand Up @@ -167,7 +167,7 @@ bool Statement::executeStep()
return mbHasRow; // true only if one row is accessible by getColumn(N)
}

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

// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
int Statement::getChanges() const noexcept
{
return sqlite3_changes(mStmtPtr);
}

int Statement::getBindParameterCount() const noexcept
{
return sqlite3_bind_parameter_count(mStmtPtr);
Expand Down
4 changes: 3 additions & 1 deletion tests/Column_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @ingroup tests
* @brief Test of a SQLiteCpp Column.
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand Down Expand Up @@ -44,6 +44,7 @@ TEST(Column, basis)
// Execute the one-step query to insert the row
EXPECT_EQ(1, insert.exec());
EXPECT_EQ(1, db.getLastInsertRowid());
EXPECT_EQ(1, db.getChanges());
EXPECT_EQ(1, db.getTotalChanges());

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

SQLite::Statement query(db, "SELECT * FROM test");
Expand Down
20 changes: 18 additions & 2 deletions tests/Database_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @ingroup tests
* @brief Test of a SQLiteCpp Database.
*
* Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
Expand Down Expand Up @@ -211,32 +211,38 @@ TEST(Database, exec)
// NOTE: here exec() returns 0 only because it is the first statements since database connexion,
// but its return is an undefined value for "CREATE TABLE" statements.
db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");
EXPECT_EQ(0, db.getChanges());
EXPECT_EQ(0, db.getLastInsertRowid());
EXPECT_EQ(0, db.getTotalChanges());

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

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

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

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

// delete the third row
EXPECT_EQ(1, db.exec("DELETE FROM test WHERE id='3'"));
EXPECT_EQ(1, db.getChanges());
EXPECT_EQ(3, db.getLastInsertRowid());
EXPECT_EQ(5, db.getTotalChanges());

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

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

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

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

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

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

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

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

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

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

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

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