From 3af95da230010f2aaacda6739e0769a92d933d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Thu, 13 Mar 2014 21:44:07 +0100 Subject: [PATCH] Added comments and test arround Database::exec() method --- examples/example1/main.cpp | 2 +- include/SQLiteCpp/Database.h | 13 +++++++--- src/Database.cpp | 4 +-- tests/Database_test.cpp | 47 +++++++++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/examples/example1/main.cpp b/examples/example1/main.cpp index 673c3f9..034a788 100644 --- a/examples/example1/main.cpp +++ b/examples/example1/main.cpp @@ -195,8 +195,8 @@ int main (void) SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n"; + // Create a new table with an explicit "id" column aliasing the underlying rowid db.exec("DROP TABLE IF EXISTS test"); - db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); // first row diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 9e1c46e..3bf57e5 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -93,8 +93,8 @@ public: * @brief Shortcut to execute one or multiple statements without results. * * This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" : - * - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP" * - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE" + * - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP" * - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK" * * @see Statement::exec() to handle precompiled statements (for better performances) without results @@ -102,7 +102,8 @@ public: * * @param[in] apQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements * - * @return number of rows modified by those SQL statements (INSERT, UPDATE or DELETE) + * @return number of rows modified by the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements) + * @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement. * * @throw SQLite::Exception in case of error */ @@ -112,8 +113,8 @@ public: * @brief Shortcut to execute one or multiple statements without results. * * This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" : - * - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP" * - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE" + * - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP" * - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK" * * @see Statement::exec() to handle precompiled statements (for better performances) without results @@ -121,7 +122,8 @@ public: * * @param[in] aQueries one or multiple UTF-8 encoded, semicolon-separate SQL statements * - * @return number of rows modified by those SQL statements (INSERT, UPDATE or DELETE) + * @return number of rows modified by the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements) + * @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement. * * @throw SQLite::Exception in case of error */ @@ -217,6 +219,9 @@ public: /** * @brief Get the rowid of the most recent successful INSERT into the database from the current connection. * + * Each entry in an SQLite table always has a unique 64-bit signed integer key called the rowid. + * If the table has a column of type INTEGER PRIMARY KEY, then it is an alias for the rowid. + * * @return Rowid of the most recent successful INSERT into the database, or 0 if there was none. */ inline sqlite3_int64 getLastInsertRowid(void) const noexcept // nothrow diff --git a/src/Database.cpp b/src/Database.cpp index eb7bc5a..c92b2a9 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -61,13 +61,13 @@ Database::~Database(void) noexcept // nothrow SQLITECPP_ASSERT(SQLITE_OK == ret, sqlite3_errmsg(mpSQLite)); // See SQLITECPP_ENABLE_ASSERT_HANDLER } -// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT...). +// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...). int Database::exec(const char* apQueries) { int ret = sqlite3_exec(mpSQLite, apQueries, NULL, NULL, NULL); check(ret); - // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE) + // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only) return sqlite3_changes(mpSQLite); } diff --git a/tests/Database_test.cpp b/tests/Database_test.cpp index 1db9746..a7d1da7 100644 --- a/tests/Database_test.cpp +++ b/tests/Database_test.cpp @@ -32,8 +32,10 @@ void assertion_failed(const char* apFile, const long apLine, const char* apFunc, TEST(Database, ctorExecCreateDropExist) { remove("test.db3"); { - EXPECT_THROW(SQLite::Database absent("test.db3"), SQLite::Exception); + // Try to open an unexisting database + EXPECT_THROW(SQLite::Database not_found("test.db3"), SQLite::Exception); + // Create a new database SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); EXPECT_STREQ("test.db3", db.getFilename().c_str()); EXPECT_FALSE(db.tableExists("test")); @@ -58,15 +60,52 @@ TEST(Database, ctorExecCreateDropExist) { TEST(Database, ctorExecAndGet) { remove("test.db3"); { + // Create a new database SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); - EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")); + // Create a new table with an explicit "id" column aliasing the underlying rowid + // 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.getLastInsertRowid()); - // first row - EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"test\")")); + // 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.getLastInsertRowid()); + // 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(2, db.getLastInsertRowid()); + + // third row : insert the "third" text value into new row of id 3 + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"third\")")); + EXPECT_EQ(3, db.getLastInsertRowid()); + + // 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(3, db.getLastInsertRowid()); // last inserted row ID is still 3 + + // delete the third row + EXPECT_EQ(1, db.exec("DELETE FROM test WHERE id='3'")); + EXPECT_EQ(3, db.getLastInsertRowid()); + + // drop the whole table, ie the two remaining columns + // NOTE: here exec() returns 1, like the last time, as it is an undefined value for "DROP TABLE" statements + db.exec("DROP TABLE IF EXISTS test"); + EXPECT_FALSE(db.tableExists("test")); + + // Re-Create the same table + // NOTE: here exec() returns 1, like the last time, as it is an undefined value for "CREATE TABLE" statements + db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); + + // 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(2, db.getLastInsertRowid()); + + // insert two rows with only one statement => returns 2 + EXPECT_EQ(2, db.exec("INSERT INTO test VALUES (NULL, \"third\"), (NULL, \"fourth\");")); + EXPECT_EQ(4, db.getLastInsertRowid()); + } // Close DB test.db3 remove("test.db3"); }