diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 2072161..ffa346f 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -435,7 +435,18 @@ public: * * Throw an exception if the specified index is out of the [0, getColumnCount()) range. */ - bool isColumnNull(const int aIndex) const; + bool isColumnNull(const int aIndex); + + /** + * @brief Test if the column value is NULL + * + * @param[in] apName Aliased name of the column, that is, the named specified in the query (not the original name) + * + * @return true if the column value is NULL + * + * Throw an exception if the specified name is not an on of the aliased name of the columns in the result. + */ + bool isColumnNull(const char* apName); /** * @brief Return a pointer to the named assigned to the specified result column (potentially aliased) diff --git a/src/Statement.cpp b/src/Statement.cpp index 28ae75d..2fac7a3 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -336,13 +336,35 @@ Column Statement::getColumn(const char* apName) } // Test if the column is NULL -bool Statement::isColumnNull(const int aIndex) const +bool Statement::isColumnNull(const int aIndex) { checkRow(); checkIndex(aIndex); return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, aIndex)); } +bool Statement::isColumnNull(const char* apName) +{ + checkRow(); + + 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()) + { + throw SQLite::Exception("Unknown column name."); + } + + return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, (*iIndex).second)); +} + // Return the named assigned to the specified result column (potentially aliased) const char* Statement::getColumnName(const int aIndex) const { diff --git a/tests/Statement_test.cpp b/tests/Statement_test.cpp index 89bc1fb..7a0aed9 100644 --- a/tests/Statement_test.cpp +++ b/tests/Statement_test.cpp @@ -528,6 +528,68 @@ TEST(Statement, isColumnNull) { EXPECT_THROW(query.isColumnNull(3), SQLite::Exception); } +TEST(Statement, isColumnNullByName) { + // Create a new database + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + ASSERT_EQ(SQLITE_OK, db.getErrorCode()); + + // Create a new table + EXPECT_EQ(0, db.exec("CREATE TABLE test (msg TEXT, int INTEGER, double REAL)")); + ASSERT_EQ(SQLITE_OK, db.getErrorCode()); + + // Create a first row with no null values, then other rows with each time a NULL value + ASSERT_EQ(1, db.exec("INSERT INTO test VALUES (\"first\", 123, 0.123)")); + ASSERT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 123, 0.123)")); + ASSERT_EQ(1, db.exec("INSERT INTO test VALUES (\"first\", NULL, 0.123)")); + ASSERT_EQ(1, db.exec("INSERT INTO test VALUES (\"first\", 123, NULL)")); + + // Compile a SQL query + const std::string select("SELECT * FROM test"); + SQLite::Statement query(db, select); + EXPECT_EQ(select, query.getQuery()); + EXPECT_EQ(3, query.getColumnCount()); + + // Get the first non-null row + query.executeStep(); + EXPECT_TRUE (query.isOk()); + EXPECT_FALSE(query.isDone()); + EXPECT_THROW(query.isColumnNull(""), SQLite::Exception); + EXPECT_EQ(false, query.isColumnNull("msg")); + EXPECT_EQ(false, query.isColumnNull("int")); + EXPECT_EQ(false, query.isColumnNull("double")); + EXPECT_THROW(query.isColumnNull(3), SQLite::Exception); + + // Get the second row with null text + query.executeStep(); + EXPECT_TRUE (query.isOk()); + EXPECT_FALSE(query.isDone()); + EXPECT_THROW(query.isColumnNull(""), SQLite::Exception); + EXPECT_EQ(true, query.isColumnNull("msg")); + EXPECT_EQ(false, query.isColumnNull(1)); + EXPECT_EQ(false, query.isColumnNull("double")); + EXPECT_THROW(query.isColumnNull(3), SQLite::Exception); + + // Get the second row with null integer + query.executeStep(); + EXPECT_TRUE (query.isOk()); + EXPECT_FALSE(query.isDone()); + EXPECT_THROW(query.isColumnNull(""), SQLite::Exception); + EXPECT_EQ(false, query.isColumnNull("msg")); + EXPECT_EQ(true, query.isColumnNull("int")); + EXPECT_EQ(false, query.isColumnNull("double")); + EXPECT_THROW(query.isColumnNull(3), SQLite::Exception); + + // Get the third row with null float + query.executeStep(); + EXPECT_TRUE (query.isOk()); + EXPECT_FALSE(query.isDone()); + EXPECT_THROW(query.isColumnNull(""), SQLite::Exception); + EXPECT_EQ(false, query.isColumnNull("msg")); + EXPECT_EQ(false, query.isColumnNull("int")); + EXPECT_EQ(true, query.isColumnNull("double")); + EXPECT_THROW(query.isColumnNull(3), SQLite::Exception); +} + TEST(Statement, getColumnByName) { // Create a new database SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);