mirror of
https://github.com/cuberite/SQLiteCpp.git
synced 2025-08-04 17:56:13 -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 <sqlite3.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <SQLiteCpp/Exception.h>
|
#include <SQLiteCpp/Exception.h>
|
||||||
|
|
||||||
@ -274,7 +275,8 @@ public:
|
|||||||
* Can be used to access the data of the current row of result when applicable,
|
* Can be used to access the data of the current row of result when applicable,
|
||||||
* while the executeStep() method returns true.
|
* 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
|
* - before any executeStep() call
|
||||||
* - after the last executeStep() returned false
|
* - after the last executeStep() returned false
|
||||||
* - after a reset() call
|
* - after a reset() call
|
||||||
@ -283,8 +285,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param[in] aIndex Index of the column, starting at 0
|
* @param[in] aIndex Index of the column, starting at 0
|
||||||
*
|
*
|
||||||
* @note This method is no more const, starting in v0.5,
|
* @note This method is not const, reflecting the fact that the returned Column object will
|
||||||
* which reflects the fact that the returned Column object will
|
|
||||||
* share the ownership of the underlying sqlite3_stmt.
|
* share the ownership of the underlying sqlite3_stmt.
|
||||||
*
|
*
|
||||||
* @warning The resulting Column object must not be memorized "as-is".
|
* @warning The resulting Column object must not be memorized "as-is".
|
||||||
@ -302,16 +303,16 @@ public:
|
|||||||
* while the executeStep() method returns true.
|
* 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 name is not one of the aliased column names
|
||||||
* - before any executeStep() call
|
* - before any executeStep() call
|
||||||
* - after the last executeStep() returned false
|
* - after the last executeStep() returned false
|
||||||
* - after a reset() call
|
* - after a reset() call
|
||||||
*
|
*
|
||||||
* Throw an exception if the specified index is out of the [0, getColumnCount()) range.
|
* 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,
|
* @note This method is not const, reflecting the fact that the returned Column object will
|
||||||
* which reflects the fact that the returned Column object will
|
|
||||||
* share the ownership of the underlying sqlite3_stmt.
|
* share the ownership of the underlying sqlite3_stmt.
|
||||||
*
|
*
|
||||||
* @warning The resulting Column object must not be memorized "as-is".
|
* @warning The resulting Column object must not be memorized "as-is".
|
||||||
@ -320,7 +321,7 @@ public:
|
|||||||
* Thus, you should instead extract immediately its data (getInt(), getText()...)
|
* Thus, you should instead extract immediately its data (getInt(), getText()...)
|
||||||
* and use or copy this data for any later usage.
|
* 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
|
* @brief Test if the column value is NULL
|
||||||
@ -424,10 +425,14 @@ private:
|
|||||||
*/
|
*/
|
||||||
void check(const int aRet);
|
void check(const int aRet);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::map<std::string, int> TColumnNames;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mQuery; //!< UTF-8 SQL Query
|
std::string mQuery; //!< UTF-8 SQL Query
|
||||||
Ptr mStmtPtr; //!< Shared Pointer to the prepared SQLite Statement Object
|
Ptr mStmtPtr; //!< Shared Pointer to the prepared SQLite Statement Object
|
||||||
int mColumnCount; //!< Number of columns in the result of the prepared statement
|
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 mbOk; //!< true when a row has been fetched with executeStep()
|
||||||
bool mbDone; //!< true when the last executeStep() had no more row to fetch
|
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
|
// Return a copy of the column data specified by its column name starting at 0
|
||||||
// (use the Column copy-constructor)
|
// (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)
|
if (false == mbOk)
|
||||||
{
|
{
|
||||||
@ -268,18 +268,28 @@ Column Statement::getColumn(const char* aName)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < mColumnCount; ++i) {
|
if (mColumnNames.empty())
|
||||||
if (sqlite3_column_name(mStmtPtr, i) == aName)
|
{
|
||||||
break;
|
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");
|
throw SQLite::Exception("Column index out of range");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Share the Statement Object handle with the new Column created
|
// Share the Statement Object handle with the new Column created
|
||||||
return Column(mStmtPtr, aIndex);
|
return Column(mStmtPtr, Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the column is NULL
|
// Test if the column is NULL
|
||||||
|
@ -77,3 +77,45 @@ TEST(Statement, invalid) {
|
|||||||
} // Close DB test.db3
|
} // Close DB test.db3
|
||||||
remove("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