抛弃GdCpp*.dll/pdb历史重新建库。libhv和Sqlite的dll保留
This commit is contained in:
23
source/CSQLite/CSQLiteColumn.cpp
Normal file
23
source/CSQLite/CSQLiteColumn.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file CSQLiteColumn.cpp
|
||||
* @ingroup CSQLite
|
||||
* @brief Encapsulation of a Column in a row of the result pointed by the prepared SQLite::Statement.
|
||||
*
|
||||
* 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/CSQLiteColumn.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// Standard std::ostream inserter
|
||||
std::ostream& operator<<(std::ostream& aStream, const CSQLiteColumn& aColumn)
|
||||
{
|
||||
aStream.write(aColumn.getText(), aColumn.getBytes());
|
||||
return aStream;
|
||||
}
|
||||
105
source/CSQLite/CSQLiteDB.cpp
Normal file
105
source/CSQLite/CSQLiteDB.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "pch.h"
|
||||
#include "CSQLite/CSQLite.h"
|
||||
#include "aLog.h"
|
||||
|
||||
int CSQLiteDB::open(const char* apFilename, const int aFlags) noexcept
|
||||
{
|
||||
mFilename = apFilename;
|
||||
dbErrCode = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, nullptr);
|
||||
if (SQLITE_OK != dbErrCode)
|
||||
{
|
||||
dbErrMsg = sqlite3_errmsg(mpSQLite);
|
||||
sqlite3_close(mpSQLite); // close is required even in case of error on opening
|
||||
mpSQLite = nullptr;
|
||||
}
|
||||
return dbErrCode;
|
||||
}
|
||||
|
||||
int CSQLiteDB::open(const std::string &apFilename, const int aFlags) noexcept
|
||||
{
|
||||
mFilename = apFilename;
|
||||
dbErrCode = sqlite3_open_v2(apFilename.c_str(), &mpSQLite, aFlags, nullptr);
|
||||
if (SQLITE_OK != dbErrCode)
|
||||
{
|
||||
dbErrMsg = sqlite3_errmsg(mpSQLite);
|
||||
sqlite3_close(mpSQLite); // close is required even in case of error on opening
|
||||
mpSQLite = nullptr;
|
||||
}
|
||||
return dbErrCode;
|
||||
}
|
||||
|
||||
int CSQLiteDB::openInRam(const char* apFilename)
|
||||
{
|
||||
UNUSED(apFilename);
|
||||
return dbErrCode;
|
||||
|
||||
}
|
||||
|
||||
int CSQLiteDB::close()
|
||||
{
|
||||
if(bInTransaction)
|
||||
{
|
||||
// 没有主动Commit,就Rollback();
|
||||
Rollback();
|
||||
}
|
||||
bInTransaction = false;
|
||||
int ret =0;
|
||||
if(mpSQLite){
|
||||
ret = sqlite3_close(mpSQLite);
|
||||
|
||||
if(SQLITE_OK != ret){
|
||||
switch (ret) {
|
||||
case SQLITE_MISUSE:
|
||||
alog->error("CSQLiteDB::close(): Library used incorrectly {}, {}", ret, mFilename);
|
||||
break;
|
||||
case SQLITE_BUSY:
|
||||
alog->error("CSQLiteDB::close(): database is locked {}, {}", ret, mFilename);
|
||||
break;
|
||||
default:
|
||||
alog->error("CSQLiteDB::close(): database close error {}, {}", ret, mFilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mpSQLite = nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
|
||||
*
|
||||
* This is useful in multithreaded program to handle case where a table is locked for writting by a thread.
|
||||
* Any other thread cannot access the table and will receive a SQLITE_BUSY error:
|
||||
* setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error.
|
||||
* Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;".
|
||||
* Default busy timeout is 0ms.
|
||||
*
|
||||
* @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void CSQLiteDB::setBusyTimeout(const int aBusyTimeoutMs)
|
||||
{
|
||||
const int ret = sqlite3_busy_timeout(mpSQLite, aBusyTimeoutMs);
|
||||
check(ret);
|
||||
}
|
||||
|
||||
// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
|
||||
int CSQLiteDB::exec(const char* apQueries)
|
||||
{
|
||||
const int ret = sqlite3_exec(mpSQLite, apQueries, nullptr, nullptr, nullptr);
|
||||
check(ret);
|
||||
|
||||
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only)
|
||||
return sqlite3_changes(mpSQLite);
|
||||
}
|
||||
|
||||
// Shortcut to test if a table exists.
|
||||
bool CSQLiteDB::tableExists(const char* apTableName)
|
||||
{
|
||||
CSQLiteStatement query(*this, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?");
|
||||
query.bind(1, apTableName);
|
||||
(void)query.executeStep(); // Cannot return false, as the above query always return a result
|
||||
return (1 == query.getColumn(0).getInt());
|
||||
}
|
||||
199
source/CSQLite/CSQLiteStatement.cpp
Normal file
199
source/CSQLite/CSQLiteStatement.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
59
source/CSQLite/CSQLiteTransaction.cpp
Normal file
59
source/CSQLite/CSQLiteTransaction.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file CSQLiteTransaction.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief A CSQLiteTransaction is way to group multiple SQL statements into an atomic secured operation.
|
||||
*
|
||||
* Copyright (c) 2012-2013 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/CSQLiteTransaction.h"
|
||||
|
||||
#include "CSQLite/CSQLiteDB.h"
|
||||
|
||||
// Begins the SQLite CSQLiteTransaction
|
||||
CSQLiteTransaction::CSQLiteTransaction(CSQLiteDB & aDatabase, bool startnow) :
|
||||
mDatabase(aDatabase),
|
||||
mbCommited(false)
|
||||
{
|
||||
if(startnow)
|
||||
{
|
||||
mDatabase.exec("BEGIN");
|
||||
mbCommited = false;
|
||||
}else{
|
||||
mbCommited = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Safely rollback the CSQLiteTransaction if it has not been committed.
|
||||
CSQLiteTransaction::~CSQLiteTransaction()
|
||||
{
|
||||
if (false == mbCommited)
|
||||
{
|
||||
try
|
||||
{
|
||||
mDatabase.exec("ROLLBACK");
|
||||
}
|
||||
catch (CSQLiteException&)
|
||||
{
|
||||
// Never throw an exception in a destructor: error if already rollbacked, but no harm is caused by this.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit the CSQLiteTransaction.
|
||||
void CSQLiteTransaction::commit()
|
||||
{
|
||||
if (false == mbCommited)
|
||||
{
|
||||
mDatabase.exec("COMMIT");
|
||||
mbCommited = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CSQLiteException("CSQLiteTransaction already commited.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user