diff --git a/examples/example1/main.cpp b/examples/example1/main.cpp index 92cb7d2..a8296c1 100644 --- a/examples/example1/main.cpp +++ b/examples/example1/main.cpp @@ -140,28 +140,22 @@ int main () query.reset(); std::cout << "SQLite statement '" << query.getQuery().c_str() << "' reseted (" << query.getColumnCount() << " columns in the result)\n"; - // Execute the first step of the query, to get the fist row of results, and name of columns - if (query.executeStep()) - { - // Show how to get the aliased names of the result columns. - const std::string name0 = query.getColumn(0).getName(); - const std::string name1 = query.getColumn(1).getName(); - const std::string name2 = query.getColumn(2).getName(); - std::cout << "aliased result [\"" << name0.c_str() << "\", \"" << name1.c_str() << "\", \"" << name2.c_str() << "\"]\n"; + // Show how to get the aliased names of the result columns. + const std::string name0 = query.getColumnName(0); + const std::string name1 = query.getColumnName(1); + const std::string name2 = query.getColumnName(2); + std::cout << "aliased result [\"" << name0.c_str() << "\", \"" << name1.c_str() << "\", \"" << name2.c_str() << "\"]\n"; #ifdef SQLITE_ENABLE_COLUMN_METADATA - // Show how to get origin names of the table columns from which theses result columns come from. - // Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be - // also defined at compile times of the SQLite library itself. - const std::string oname0 = query.getColumn(0).getOriginName(); - const std::string oname1 = query.getColumn(1).getOriginName(); - const std::string oname2 = query.getColumn(2).getOriginName(); - std::cout << "origin table 'test' [\"" << oname0.c_str() << "\", \"" << oname1.c_str() << "\", \"" << oname2.c_str() << "\"]\n"; + // Show how to get origin names of the table columns from which theses result columns come from. + // Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be + // also defined at compile times of the SQLite library itself. + const std::string oname0 = query.getColumnOriginName(0); + const std::string oname1 = query.getColumnOriginName(1); + const std::string oname2 = query.getColumnOriginName(2); + std::cout << "origin table 'test' [\"" << oname0.c_str() << "\", \"" << oname1.c_str() << "\", \"" << oname2.c_str() << "\"]\n"; #endif - // Demonstrates that inserting column value in a std:ostream is natural - std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\", " << query.getColumn(2) << ")\n"; - } - // Loop to execute the rest of the query step by step, to get one a row of results at a time + // Loop to execute the query step by step, to get one a row of results at a time while (query.executeStep()) { // Demonstrates that inserting column value in a std:ostream is natural diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 5b620b3..e595e41 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -297,7 +297,7 @@ public: Column getColumn(const int aIndex); /** - * @brief Return a copy of the column data specified by its column name + * @brief Return a copy of the column data specified by its column name (less efficient than using an index) * * Can be used to access the data of the current row of result when applicable, * while the executeStep() method returns true. @@ -308,9 +308,11 @@ public: * - after the last executeStep() returned false * - after a reset() call * - * Throw an exception if the specified index is out of the [0, getColumnCount()) range. + * Throw an exception if the specified name is not an on of the aliased name of the columns in the result. * - * @param[in] apName Name of the column, starting at index 0 + * @param[in] apName Aliased name of the column, that is, the named specified in the query (not the original name) + * + * @note Uses a map of column names to indexes, build on first call. * * @note This method is not const, reflecting the fact that the returned Column object will * share the ownership of the underlying sqlite3_stmt. @@ -329,9 +331,33 @@ public: * @param[in] aIndex Index of the column, starting at 0 * * @return true if the column value is NULL + * + * Throw an exception if the specified index is out of the [0, getColumnCount()) range. */ bool isColumnNull(const int aIndex) const; + /** + * @brief Return a pointer to the named assigned to the specified result column (potentially aliased) + * + * @see getColumnOriginName() to get original column name (not aliased) + * + * Throw an exception if the specified index is out of the [0, getColumnCount()) range. + */ + const char* getColumnName(const int aIndex) const; + +#ifdef SQLITE_ENABLE_COLUMN_METADATA + /** + * @brief Return a pointer to the table column name that is the origin of the specified result column + * + * Require definition of the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro : + * - when building the SQLite library itself (which is the case for the Debian libsqlite3 binary for instance), + * - and also when compiling this wrapper. + * + * Throw an exception if the specified index is out of the [0, getColumnCount()) range. + */ + const char* getColumnOriginName(const int aIndex) const; +#endif + //////////////////////////////////////////////////////////////////////////// /// @brief Return the UTF-8 SQL Query. @@ -423,7 +449,35 @@ private: * * @param[in] SQLite return code to test against the SQLITE_OK expected value */ - void check(const int aRet); + inline void Statement::check(const int aRet) const + { + if (SQLITE_OK != aRet) + { + throw SQLite::Exception(sqlite3_errmsg(mStmtPtr)); + } + } + + /** + * @brief Check if there is a row of result returnes by executeStep(), else throw a SQLite::Exception. + */ + inline void Statement::checkRow() const + { + if (false == mbOk) + { + throw SQLite::Exception("No row to get a column from. executeStep() was not called or did not returned true."); + } + } + + /** + * @brief Check if there is a Column index is in the range of columns in the result. + */ + inline void Statement::checkIndex(const int aIndex) const + { + if ((aIndex < 0) || (aIndex >= mColumnCount)) + { + throw SQLite::Exception("Column index out of range."); + } + } private: typedef std::map TColumnNames; diff --git a/src/Statement.cpp b/src/Statement.cpp index 597fcae..e219938 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -54,7 +54,7 @@ void Statement::reset() { mbOk = false; mbDone = false; - int ret = sqlite3_reset(mStmtPtr); + const int ret = sqlite3_reset(mStmtPtr); check(ret); } @@ -65,56 +65,56 @@ void Statement::clearBindings(void) { mbOk = false; mbDone = false; - int ret = sqlite3_clear_bindings(mStmtPtr); + const int ret = sqlite3_clear_bindings(mStmtPtr); check(ret); } // Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const int& aValue) { - int ret = sqlite3_bind_int(mStmtPtr, aIndex, aValue); + const int ret = sqlite3_bind_int(mStmtPtr, aIndex, aValue); check(ret); } // Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const sqlite3_int64& aValue) { - int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue); + const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue); check(ret); } // Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const double& aValue) { - int ret = sqlite3_bind_double(mStmtPtr, aIndex, aValue); + const int ret = sqlite3_bind_double(mStmtPtr, aIndex, aValue); check(ret); } // Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const std::string& aValue) { - int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(), static_cast(aValue.size()), SQLITE_TRANSIENT); + const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(), static_cast(aValue.size()), SQLITE_TRANSIENT); check(ret); } // Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const char* apValue) { - int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_TRANSIENT); + const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_TRANSIENT); check(ret); } // Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const void* apValue, const int aSize) { - int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_TRANSIENT); + const int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_TRANSIENT); check(ret); } // Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex) { - int ret = sqlite3_bind_null(mStmtPtr, aIndex); + const int ret = sqlite3_bind_null(mStmtPtr, aIndex); check(ret); } @@ -122,56 +122,56 @@ void Statement::bind(const int aIndex) // Bind an int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const int& aValue) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_int(mStmtPtr, index, aValue); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_int(mStmtPtr, index, aValue); check(ret); } // Bind a 64bits int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const sqlite3_int64& aValue) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_int64(mStmtPtr, index, aValue); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_int64(mStmtPtr, index, aValue); check(ret); } // Bind a double (64bits float) value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const double& aValue) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_double(mStmtPtr, index, aValue); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_double(mStmtPtr, index, aValue); check(ret); } // Bind a string value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const std::string& aValue) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_text(mStmtPtr, index, aValue.c_str(), static_cast(aValue.size()), SQLITE_TRANSIENT); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_text(mStmtPtr, index, aValue.c_str(), static_cast(aValue.size()), SQLITE_TRANSIENT); check(ret); } // Bind a text value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const char* apValue) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_text(mStmtPtr, index, apValue, -1, SQLITE_TRANSIENT); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_text(mStmtPtr, index, apValue, -1, SQLITE_TRANSIENT); check(ret); } // Bind a binary blob value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const void* apValue, const int aSize) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_blob(mStmtPtr, index, apValue, aSize, SQLITE_TRANSIENT); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_blob(mStmtPtr, index, apValue, aSize, SQLITE_TRANSIENT); check(ret); } // Bind a NULL value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName) { - int index = sqlite3_bind_parameter_index(mStmtPtr, apName); - int ret = sqlite3_bind_null(mStmtPtr, index); + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_null(mStmtPtr, index); check(ret); } @@ -181,7 +181,7 @@ bool Statement::executeStep() { if (false == mbDone) { - int ret = sqlite3_step(mStmtPtr); + const int ret = sqlite3_step(mStmtPtr); if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it { mbOk = true; @@ -200,7 +200,7 @@ bool Statement::executeStep() } else { - throw SQLite::Exception("Statement needs to be reset"); + throw SQLite::Exception("Statement needs to be reseted."); } return mbOk; // true only if one row is accessible by getColumn(N) @@ -211,7 +211,7 @@ int Statement::exec() { if (false == mbDone) { - int ret = sqlite3_step(mStmtPtr); + const int ret = sqlite3_step(mStmtPtr); if (SQLITE_DONE == ret) // the statement has finished executing successfully { mbOk = false; @@ -221,7 +221,7 @@ int Statement::exec() { mbOk = false; mbDone = false; - throw SQLite::Exception("exec() does not expect results"); + throw SQLite::Exception("exec() does not expect results. Use executeStep."); } else { @@ -232,7 +232,7 @@ int Statement::exec() } else { - throw SQLite::Exception("Statement need to be reseted"); + throw SQLite::Exception("Statement need to be reseted."); } // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE) @@ -243,14 +243,8 @@ int Statement::exec() // (use the Column copy-constructor) Column Statement::getColumn(const int aIndex) { - if (false == mbOk) - { - throw SQLite::Exception("No row to get a column from"); - } - else if ((aIndex < 0) || (aIndex >= mColumnCount)) - { - throw SQLite::Exception("Column index out of range"); - } + checkRow(); + checkIndex(aIndex); // Share the Statement Object handle with the new Column created return Column(mStmtPtr, aIndex); @@ -260,62 +254,50 @@ Column Statement::getColumn(const int aIndex) // (use the Column copy-constructor) Column Statement::getColumn(const char* apName) { - int Index = -1; + checkRow(); - if (false == mbOk) + if (mColumnNames.empty()) { - throw SQLite::Exception("No row to get a column from"); + for (int i = 0; i < mColumnCount; ++i) + { + const char* pName = sqlite3_column_name(mStmtPtr, i); + mColumnNames[pName] = i; + } } - else - { - if (mColumnNames.empty()) - { - for (int i = 0; i < mColumnCount; ++i) - { - const char* pName = sqlite3_column_name(mStmtPtr, i); - mColumnNames[pName] = i; - } - } - const TColumnNames::const_iterator iIndex = mColumnNames.find(apName); - if (iIndex != mColumnNames.end()) - { - Index = (*iIndex).second; - } - else - { - throw SQLite::Exception("Column index out of range"); - } + const TColumnNames::const_iterator iIndex = mColumnNames.find(apName); + if (iIndex == mColumnNames.end()) + { + throw SQLite::Exception("Unknown column name."); } // Share the Statement Object handle with the new Column created - return Column(mStmtPtr, Index); + return Column(mStmtPtr, (*iIndex).second); } // Test if the column is NULL bool Statement::isColumnNull(const int aIndex) const { - if (false == mbOk) - { - throw SQLite::Exception("No row to get a column from"); - } - else if ((aIndex < 0) || (aIndex >= mColumnCount)) - { - throw SQLite::Exception("Column index out of range"); - } - + checkRow(); + checkIndex(aIndex); return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, aIndex)); } -// Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message -void Statement::check(const int aRet) +// Return the named assigned to the specified result column (potentially aliased) +const char* Statement::getColumnName(const int aIndex) const { - if (SQLITE_OK != aRet) - { - throw SQLite::Exception(sqlite3_errmsg(mStmtPtr)); - } + checkIndex(aIndex); + return sqlite3_column_name(mStmtPtr, aIndex); } +#ifdef SQLITE_ENABLE_COLUMN_METADATA +// Return the named assigned to the specified result column (potentially aliased) +const char* Statement::getColumnOriginName(const int aIndex) const +{ + checkIndex(aIndex); + return sqlite3_column_origin_name(mStmtPtr, aIndex); +} +#endif //////////////////////////////////////////////////////////////////////////////// // Internal class : shared pointer to the sqlite3_stmt SQLite Statement Object @@ -332,7 +314,7 @@ Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery) : mpStmt(NULL), mpRefCount(NULL) { - int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast(aQuery.size()), &mpStmt, NULL); + const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast(aQuery.size()), &mpStmt, NULL); if (SQLITE_OK != ret) { throw SQLite::Exception(sqlite3_errmsg(mpSQLite)); diff --git a/tests/Statement_test.cpp b/tests/Statement_test.cpp index 19fd48b..e725a8d 100644 --- a/tests/Statement_test.cpp +++ b/tests/Statement_test.cpp @@ -18,115 +18,131 @@ TEST(Statement, invalid) { - remove("test.db3"); - { - // Create a new database - SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); - EXPECT_EQ(SQLITE_OK, db.getErrorCode()); - EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); + // Create a new database + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); - // Compile a SQL query, but without any table in the database - EXPECT_THROW(SQLite::Statement query(db, "SELECT * FROM test"), SQLite::Exception); - EXPECT_EQ(SQLITE_ERROR, db.getErrorCode()); - EXPECT_EQ(SQLITE_ERROR, db.getExtendedErrorCode()); + // Compile a SQL query, but without any table in the database + EXPECT_THROW(SQLite::Statement query(db, "SELECT * FROM test"), SQLite::Exception); + EXPECT_EQ(SQLITE_ERROR, db.getErrorCode()); + EXPECT_EQ(SQLITE_ERROR, db.getExtendedErrorCode()); - EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")); - EXPECT_EQ(SQLITE_OK, db.getErrorCode()); - EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); - // Compile a SQL query with no parameter - SQLite::Statement query(db, "SELECT * FROM test"); - EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str()); - EXPECT_EQ(2, query.getColumnCount ()); - EXPECT_FALSE(query.isOk()); - EXPECT_FALSE(query.isDone()); - EXPECT_THROW(query.isColumnNull(-1), SQLite::Exception); - EXPECT_THROW(query.isColumnNull(0), SQLite::Exception); - EXPECT_THROW(query.isColumnNull(1), SQLite::Exception); - EXPECT_THROW(query.isColumnNull(2), SQLite::Exception); - EXPECT_THROW(query.getColumn(-1), SQLite::Exception); - EXPECT_THROW(query.getColumn(0), SQLite::Exception); - EXPECT_THROW(query.getColumn(1), SQLite::Exception); - EXPECT_THROW(query.getColumn(2), SQLite::Exception); + // Compile a SQL query with no parameter + SQLite::Statement query(db, "SELECT * FROM test"); + EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str()); + EXPECT_EQ(2, query.getColumnCount ()); + EXPECT_FALSE(query.isOk()); + EXPECT_FALSE(query.isDone()); + EXPECT_THROW(query.isColumnNull(-1), SQLite::Exception); + EXPECT_THROW(query.isColumnNull(0), SQLite::Exception); + EXPECT_THROW(query.isColumnNull(1), SQLite::Exception); + EXPECT_THROW(query.isColumnNull(2), SQLite::Exception); + EXPECT_THROW(query.getColumn(-1), SQLite::Exception); + EXPECT_THROW(query.getColumn(0), SQLite::Exception); + EXPECT_THROW(query.getColumn(1), SQLite::Exception); + EXPECT_THROW(query.getColumn(2), SQLite::Exception); - query.reset(); - EXPECT_FALSE(query.isOk()); - EXPECT_FALSE(query.isDone()); + query.reset(); + EXPECT_FALSE(query.isOk()); + EXPECT_FALSE(query.isDone()); - query.executeStep(); - EXPECT_FALSE(query.isOk()); - EXPECT_TRUE( query.isDone()); - query.reset(); - EXPECT_FALSE(query.isOk()); - EXPECT_FALSE(query.isDone()); + query.executeStep(); + EXPECT_FALSE(query.isOk()); + EXPECT_TRUE( query.isDone()); + query.reset(); + EXPECT_FALSE(query.isOk()); + EXPECT_FALSE(query.isDone()); - query.reset(); - EXPECT_THROW(query.bind(-1, 123), SQLite::Exception); - EXPECT_THROW(query.bind(0, 123), SQLite::Exception); - EXPECT_THROW(query.bind(1, 123), SQLite::Exception); - EXPECT_THROW(query.bind(2, 123), SQLite::Exception); - EXPECT_THROW(query.bind(0, "abc"), SQLite::Exception); - EXPECT_THROW(query.bind(0), SQLite::Exception); - EXPECT_EQ(SQLITE_RANGE, db.getErrorCode()); - EXPECT_EQ(SQLITE_RANGE, db.getExtendedErrorCode()); + query.reset(); + EXPECT_THROW(query.bind(-1, 123), SQLite::Exception); + EXPECT_THROW(query.bind(0, 123), SQLite::Exception); + EXPECT_THROW(query.bind(1, 123), SQLite::Exception); + EXPECT_THROW(query.bind(2, 123), SQLite::Exception); + EXPECT_THROW(query.bind(0, "abc"), SQLite::Exception); + EXPECT_THROW(query.bind(0), SQLite::Exception); + EXPECT_EQ(SQLITE_RANGE, db.getErrorCode()); + EXPECT_EQ(SQLITE_RANGE, db.getExtendedErrorCode()); - query.exec(); // exec() instead of executeStep() as there is no result - EXPECT_THROW(query.isColumnNull(0), SQLite::Exception); - EXPECT_THROW(query.getColumn(0), SQLite::Exception); + query.exec(); // exec() instead of executeStep() as there is no result + EXPECT_THROW(query.isColumnNull(0), SQLite::Exception); + EXPECT_THROW(query.getColumn(0), SQLite::Exception); - // Add a first row - EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\")")); - EXPECT_EQ(1, db.getLastInsertRowid()); - EXPECT_EQ(1, db.getTotalChanges()); + // Add a first row + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\")")); + EXPECT_EQ(1, db.getLastInsertRowid()); + EXPECT_EQ(1, db.getTotalChanges()); - query.reset(); - EXPECT_FALSE(query.isOk()); - EXPECT_FALSE(query.isDone()); + query.reset(); + EXPECT_FALSE(query.isOk()); + EXPECT_FALSE(query.isDone()); - EXPECT_THROW(query.exec(), SQLite::Exception); // exec() shall throw as it does not expect a result - - } // Close DB test.db3 - remove("test.db3"); + EXPECT_THROW(query.exec(), SQLite::Exception); // exec() shall throw as it does not expect a result } +// TODO: test every kind of binding TEST(Statement, getColumnByName) { - remove("test.db3"); - { - // Create a new database - SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); - EXPECT_EQ(SQLITE_OK, db.getErrorCode()); - EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); + // Create a new database + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); - // Create a new table - EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT, int INTEGER, double REAL)")); - EXPECT_EQ(SQLITE_OK, db.getErrorCode()); - EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); + // Create a new table + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT, int INTEGER, double REAL)")); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + EXPECT_EQ(SQLITE_OK, db.getExtendedErrorCode()); - // Create a first row - EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\", 123, 0.123)")); - EXPECT_EQ(1, db.getLastInsertRowid()); - EXPECT_EQ(1, db.getTotalChanges()); + // Create a first row + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\", 123, 0.123)")); + EXPECT_EQ(1, db.getLastInsertRowid()); + EXPECT_EQ(1, db.getTotalChanges()); - // Compile a SQL query - SQLite::Statement query(db, "SELECT * FROM test"); - EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str()); - EXPECT_EQ(4, query.getColumnCount()); - query.executeStep(); - EXPECT_TRUE (query.isOk()); - EXPECT_FALSE(query.isDone()); + // Compile a SQL query + SQLite::Statement query(db, "SELECT * FROM test"); + EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str()); + EXPECT_EQ(4, query.getColumnCount()); + query.executeStep(); + EXPECT_TRUE (query.isOk()); + EXPECT_FALSE(query.isDone()); - // Look for unexisting columns - EXPECT_THROW(query.getColumn("unknown"), SQLite::Exception); - EXPECT_THROW(query.getColumn(""), SQLite::Exception); + // Look for unexisting columns + EXPECT_THROW(query.getColumn("unknown"), SQLite::Exception); + EXPECT_THROW(query.getColumn(""), SQLite::Exception); - const std::string msg = query.getColumn("msg"); - const int integer = query.getColumn("int"); - const double real = query.getColumn("double"); - EXPECT_EQ("first", msg); - EXPECT_EQ(123, integer); - EXPECT_EQ(0.123, real); - - } // Close DB test.db3 - remove("test.db3"); + const std::string msg = query.getColumn("msg"); + const int integer = query.getColumn("int"); + const double real = query.getColumn("double"); + EXPECT_EQ("first", msg); + EXPECT_EQ(123, integer); + EXPECT_EQ(0.123, real); +} + +TEST(Statement, getName) { + // Create a new database + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT)")); + + // Compile a SQL query, using the "id" column name as-is, but aliasing the "msg" column with new name "value" + SQLite::Statement query(db, "SELECT id, msg as value FROM test"); + query.executeStep(); + + const std::string name0 = query.getColumnName(0); + const std::string name1 = query.getColumnName(1); + EXPECT_EQ("id", name0); + EXPECT_EQ("value", name1); + +#ifdef SQLITE_ENABLE_COLUMN_METADATA + // Show how to get origin names of the table columns from which theses result columns come from. + // Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be + // also defined at compile times of the SQLite library itself. + const std::string oname0 = query.getColumnOriginName(0); + const std::string oname1 = query.getColumnOriginName(1); + EXPECT_EQ("id", oname0); + EXPECT_EQ("msg", oname1); +#endif }