200 lines
5.9 KiB
C++
200 lines
5.9 KiB
C++
/**
|
|
* @file Statement.cpp
|
|
* @ingroup CSQLite
|
|
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
|
|
*
|
|
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
|
*
|
|
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
|
* or copy at http://opensource.org/licenses/MIT)
|
|
*/
|
|
#include "pch.h"
|
|
#include "CSQLite/CSQLite.h"
|
|
|
|
#include <sqlite3.h>
|
|
|
|
|
|
// Compile and register the SQL query for the provided SQLite Database Connection
|
|
CSQLiteStatement::CSQLiteStatement(CSQLiteDB &aDatabase, const char* apQuery) :
|
|
mQuery(apQuery),
|
|
mStmtPtr(std::make_shared<_Statement>(aDatabase.mpSQLite, mQuery)), // prepare the SQL query, and ref count (needs Database friendship)
|
|
mColumnCount(0),
|
|
mbHasRow(false),
|
|
mbDone(false)
|
|
{
|
|
mColumnCount = sqlite3_column_count(*mStmtPtr);
|
|
}
|
|
|
|
// Compile and register the SQL query for the provided SQLite Database Connection
|
|
CSQLiteStatement::CSQLiteStatement(CSQLiteDB &aDatabase, const std::string& aQuery) :
|
|
mQuery(aQuery),
|
|
mStmtPtr(std::make_shared<_Statement>(aDatabase.mpSQLite, mQuery)), // prepare the SQL query, and ref count (needs Database friendship)
|
|
mColumnCount(0),
|
|
mbHasRow(false),
|
|
mbDone(false)
|
|
{
|
|
mColumnCount = sqlite3_column_count(*mStmtPtr);
|
|
}
|
|
|
|
CSQLiteStatement::CSQLiteStatement(CSQLiteStatement&& aStatement) noexcept :
|
|
mQuery(std::move(aStatement.mQuery)),
|
|
mStmtPtr(std::move(aStatement.mStmtPtr)),
|
|
mColumnCount(aStatement.mColumnCount),
|
|
mbHasRow(aStatement.mbHasRow),
|
|
mbDone(aStatement.mbDone)
|
|
{
|
|
aStatement.mColumnCount = 0;
|
|
aStatement.mbHasRow = false;
|
|
aStatement.mbDone = false;
|
|
}
|
|
|
|
// Finalize and unregister the SQL query from the SQLite Database Connection.
|
|
CSQLiteStatement::~CSQLiteStatement()
|
|
{
|
|
// the finalization will be done by the destructor of the last shared pointer
|
|
}
|
|
|
|
// Execute a step of the query to fetch one row of results
|
|
bool CSQLiteStatement::executeStep()
|
|
{
|
|
const int ret = tryExecuteStep();
|
|
if ((SQLITE_ROW != ret) && (SQLITE_DONE != ret)) // on row or no (more) row ready, else it's a problem
|
|
{
|
|
if (ret == sqlite3_errcode(*mStmtPtr))
|
|
{
|
|
throw CSQLiteException(*mStmtPtr, ret);
|
|
}
|
|
else
|
|
{
|
|
throw CSQLiteException("Statement needs to be reseted", ret);
|
|
}
|
|
}
|
|
|
|
return mbHasRow; // true only if one row is accessible by getColumn(N)
|
|
}
|
|
|
|
// Execute a one-step query with no expected result
|
|
int CSQLiteStatement::exec()
|
|
{
|
|
const int ret = tryExecuteStep();
|
|
if (SQLITE_DONE != ret) // the statement has finished executing successfully
|
|
{
|
|
if (SQLITE_ROW == ret)
|
|
{
|
|
throw CSQLiteException("exec() does not expect results. Use executeStep.");
|
|
}
|
|
else if (ret == sqlite3_errcode(*mStmtPtr))
|
|
{
|
|
throw CSQLiteException(*mStmtPtr, ret);
|
|
}
|
|
else
|
|
{
|
|
throw CSQLiteException("Statement needs to be reseted", ret);
|
|
}
|
|
}
|
|
|
|
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE)
|
|
return sqlite3_changes(*mStmtPtr);
|
|
}
|
|
|
|
int CSQLiteStatement::tryExecuteStep() noexcept
|
|
{
|
|
if (false == mbDone)
|
|
{
|
|
const int ret = sqlite3_step(*mStmtPtr);
|
|
if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
|
|
{
|
|
mbHasRow = true;
|
|
}
|
|
else if (SQLITE_DONE == ret) // no (more) row ready : the query has finished executing
|
|
{
|
|
mbHasRow = false;
|
|
mbDone = true;
|
|
}
|
|
else
|
|
{
|
|
mbHasRow = false;
|
|
mbDone = false;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
// Statement needs to be reseted !
|
|
return SQLITE_MISUSE;
|
|
}
|
|
}
|
|
|
|
// Return the named assigned to the specified result column (potentially aliased)
|
|
const char* CSQLiteStatement::getColumnName(const int aIndex) const
|
|
{
|
|
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* CSQLiteStatement::getColumnOriginName(const int aIndex) const
|
|
{
|
|
checkIndex(aIndex);
|
|
return sqlite3_column_origin_name(*mStmtPtr, aIndex);
|
|
}
|
|
#endif
|
|
|
|
// Return the index of the specified (potentially aliased) column name
|
|
int CSQLiteStatement::getColumnIndex(const char* apName) const
|
|
{
|
|
// Build the map of column index by name on first call
|
|
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())
|
|
{
|
|
std::string errStr = "Unknown column name:";
|
|
errStr += apName;
|
|
throw CSQLiteException(errStr);
|
|
}
|
|
|
|
return (*iIndex).second;
|
|
}
|
|
|
|
int CSQLiteStatement::getBindParameterCount() const noexcept
|
|
{
|
|
return sqlite3_bind_parameter_count(*mStmtPtr);
|
|
}
|
|
|
|
// Return the numeric result code for the most recent failed API call (if any).
|
|
int CSQLiteStatement::getErrorCode() const noexcept // nothrow
|
|
{
|
|
return sqlite3_errcode(*mStmtPtr);
|
|
}
|
|
|
|
// Return the extended numeric result code for the most recent failed API call (if any).
|
|
int CSQLiteStatement::getExtendedErrorCode() const noexcept // nothrow
|
|
{
|
|
return sqlite3_extended_errcode(*mStmtPtr);
|
|
}
|
|
|
|
// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
|
|
const char* CSQLiteStatement::getErrorMsg() const noexcept // nothrow
|
|
{
|
|
return sqlite3_errmsg(*mStmtPtr);
|
|
}
|
|
|
|
// Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.
|
|
std::string CSQLiteStatement::getExpandedSQL() {
|
|
char* expanded = sqlite3_expanded_sql(*mStmtPtr);
|
|
std::string expandedString(expanded);
|
|
sqlite3_free(expanded);
|
|
return expandedString;
|
|
}
|
|
|