mirror of
https://github.com/cuberite/SQLiteCpp.git
synced 2025-08-04 09:46:02 -04:00
Fix #23 optimized Statement::getColumn() by name
- fix Statement::getColumn(apName) provided by #45 but was not working instead of using #46 that conflicts with current master - rework it by using a map of columns name as a cache populated the first time the method is called - add corresponding Unit Test
This commit is contained in:
parent
d45ec996a3
commit
7fbfc29677
@ -12,6 +12,7 @@
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <SQLiteCpp/Exception.h>
|
||||
|
||||
@ -274,7 +275,8 @@ public:
|
||||
* Can be used to access the data of the current row of result when applicable,
|
||||
* while the executeStep() method returns true.
|
||||
*
|
||||
* Throw an exception if there is no row to return a Column from :
|
||||
* Throw an exception if there is no row to return a Column from:
|
||||
* - if provided index is out of bound
|
||||
* - before any executeStep() call
|
||||
* - after the last executeStep() returned false
|
||||
* - after a reset() call
|
||||
@ -283,8 +285,7 @@ public:
|
||||
*
|
||||
* @param[in] aIndex Index of the column, starting at 0
|
||||
*
|
||||
* @note This method is no more const, starting in v0.5,
|
||||
* which reflects the fact that the returned Column object will
|
||||
* @note This method is not const, reflecting the fact that the returned Column object will
|
||||
* share the ownership of the underlying sqlite3_stmt.
|
||||
*
|
||||
* @warning The resulting Column object must not be memorized "as-is".
|
||||
@ -302,16 +303,16 @@ public:
|
||||
* while the executeStep() method returns true.
|
||||
*
|
||||
* Throw an exception if there is no row to return a Column from :
|
||||
* - if provided name is not one of the aliased column names
|
||||
* - before any executeStep() call
|
||||
* - after the last executeStep() returned false
|
||||
* - after a reset() call
|
||||
*
|
||||
* Throw an exception if the specified index is out of the [0, getColumnCount()) range.
|
||||
*
|
||||
* @param[in] aName Name of the column, starting at index 0
|
||||
* @param[in] apName Name of the column, starting at index 0
|
||||
*
|
||||
* @note This method is no more const, starting in v0.5,
|
||||
* which reflects the fact that the returned Column object will
|
||||
* @note This method is not const, reflecting the fact that the returned Column object will
|
||||
* share the ownership of the underlying sqlite3_stmt.
|
||||
*
|
||||
* @warning The resulting Column object must not be memorized "as-is".
|
||||
@ -320,8 +321,8 @@ public:
|
||||
* Thus, you should instead extract immediately its data (getInt(), getText()...)
|
||||
* and use or copy this data for any later usage.
|
||||
*/
|
||||
Column getColumn(const char* aName);
|
||||
|
||||
Column getColumn(const char* apName);
|
||||
|
||||
/**
|
||||
* @brief Test if the column value is NULL
|
||||
*
|
||||
@ -424,10 +425,14 @@ private:
|
||||
*/
|
||||
void check(const int aRet);
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, int> TColumnNames;
|
||||
|
||||
private:
|
||||
std::string mQuery; //!< UTF-8 SQL Query
|
||||
Ptr mStmtPtr; //!< Shared Pointer to the prepared SQLite Statement Object
|
||||
int mColumnCount; //!< Number of columns in the result of the prepared statement
|
||||
TColumnNames mColumnNames; //!< Map of columns index by name
|
||||
bool mbOk; //!< true when a row has been fetched with executeStep()
|
||||
bool mbDone; //!< true when the last executeStep() had no more row to fetch
|
||||
};
|
||||
|
@ -258,9 +258,9 @@ Column Statement::getColumn(const int aIndex)
|
||||
|
||||
// Return a copy of the column data specified by its column name starting at 0
|
||||
// (use the Column copy-constructor)
|
||||
Column Statement::getColumn(const char* aName)
|
||||
Column Statement::getColumn(const char* apName)
|
||||
{
|
||||
int aIndex = -1;
|
||||
int Index = -1;
|
||||
|
||||
if (false == mbOk)
|
||||
{
|
||||
@ -268,18 +268,28 @@ Column Statement::getColumn(const char* aName)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < mColumnCount; ++i) {
|
||||
if (sqlite3_column_name(mStmtPtr, i) == aName)
|
||||
break;
|
||||
if (mColumnNames.empty())
|
||||
{
|
||||
for (int i = 0; i < mColumnCount; ++i)
|
||||
{
|
||||
const char* pName = sqlite3_column_name(mStmtPtr, i);
|
||||
mColumnNames[pName] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((aIndex < 0) || (aIndex >= mColumnCount)) {
|
||||
const TColumnNames::const_iterator iIndex = mColumnNames.find(apName);
|
||||
if (iIndex != mColumnNames.end())
|
||||
{
|
||||
Index = (*iIndex).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SQLite::Exception("Column index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
// Share the Statement Object handle with the new Column created
|
||||
return Column(mStmtPtr, aIndex);
|
||||
return Column(mStmtPtr, Index);
|
||||
}
|
||||
|
||||
// Test if the column is NULL
|
||||
|
@ -77,3 +77,45 @@ TEST(Statement, invalid) {
|
||||
} // Close DB test.db3
|
||||
remove("test.db3");
|
||||
}
|
||||
|
||||
|
||||
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 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());
|
||||
|
||||
// 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);
|
||||
|
||||
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");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user