Add Statement::getColumnName(aIndex)

- enable getting names befor gettings rows of result
This commit is contained in:
Sébastien Rombauts 2015-05-03 17:21:04 +02:00
parent 078365febc
commit 8797f16d12
4 changed files with 236 additions and 190 deletions

View File

@ -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

View File

@ -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<std::string, int> TColumnNames;

View File

@ -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<int>(aValue.size()), SQLITE_TRANSIENT);
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(), static_cast<int>(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<int>(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<int>(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<int>(aQuery.size()), &mpStmt, NULL);
const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast<int>(aQuery.size()), &mpStmt, NULL);
if (SQLITE_OK != ret)
{
throw SQLite::Exception(sqlite3_errmsg(mpSQLite));

View File

@ -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
}