Core/DBLayer:

- Declare the datatypes used to determine transaction element data (prepared statement/adhoc query string) on a generic level in SQLOperation.h
- Implement variable SQL element data for SQLQueryHolder class so it can execute both prepared statements and adhoc queries
- Make MySQLConnection::Query for adhoc queries return pointer to type instead of an autopointer, the autopointer is now applied on higher level code just like the function for querying prepared statements

--HG--
branch : trunk
This commit is contained in:
Machiavelli
2010-09-19 12:16:29 +02:00
parent a25ef43223
commit 0982719f5f
7 changed files with 151 additions and 70 deletions
@@ -199,7 +199,12 @@ class DatabaseWorkerPool
QueryResult Query(const char* sql)
{
return GetConnection()->Query(sql);
ResultSet* result = GetConnection()->Query(sql);
if (!result || !result->GetRowCount())
return QueryResult(NULL);
result->NextRow();
return QueryResult(result);
}
QueryResult PQuery(const char* sql, ...)
@@ -291,7 +296,7 @@ class DatabaseWorkerPool
PreparedQueryResult Query(PreparedStatement* stmt)
{
PreparedResultSet* ret = GetConnection()->Query(stmt);
if (!ret || !ret->num_rows)
if (!ret || !ret->GetRowCount())
return PreparedQueryResult(NULL);
ret->NextRow();
@@ -233,10 +233,10 @@ bool MySQLConnection::Execute(PreparedStatement* stmt)
}
}
QueryResult MySQLConnection::Query(const char* sql)
ResultSet* MySQLConnection::Query(const char* sql)
{
if (!sql)
return QueryResult(NULL);
return NULL;
MYSQL_RES *result = NULL;
MYSQL_FIELD *fields = NULL;
@@ -244,13 +244,9 @@ QueryResult MySQLConnection::Query(const char* sql)
uint32 fieldCount = 0;
if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
return QueryResult(NULL);
return NULL;
ResultSet *queryResult = new ResultSet(result, fields, rowCount, fieldCount);
queryResult->NextRow();
return QueryResult(queryResult);
return new ResultSet(result, fields, rowCount, fieldCount);
}
bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount)
+1 -1
View File
@@ -40,7 +40,7 @@ class MySQLConnection
public:
bool Execute(const char* sql);
bool Execute(PreparedStatement* stmt);
QueryResult Query(const char* sql);
ResultSet* Query(const char* sql);
PreparedResultSet* Query(PreparedStatement* stmt);
bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount);
+91 -24
View File
@@ -44,10 +44,14 @@ bool BasicStatementTask::Execute()
{
if (m_has_result)
{
m_result.set(
m_conn->Query(m_sql)
);
ResultSet* result = m_conn->Query(m_sql);
if (!result || !result->GetRowCount())
{
m_result.set(QueryResult(NULL));
return false;
}
result->NextRow();
m_result.set(QueryResult(result));
return true;
}
@@ -62,15 +66,15 @@ bool SQLQueryHolder::SetQuery(size_t index, const char *sql)
return false;
}
if (m_queries[index].first != NULL)
{
sLog.outError("Attempt assign query to holder index (%zu) where other query stored (Old: [%s] New: [%s])",
index, m_queries[index].first, sql);
return false;
}
/// not executed yet, just stored (it's not called a holder for nothing)
m_queries[index] = SQLResultPair(strdup(sql), QueryResult(NULL));
SQLElementData element;
element.type = SQL_ELEMENT_RAW;
element.element.query = strdup(sql);
SQLResultSetUnion result;
result.qresult = NULL;
m_queries[index] = SQLResultPair(element, result);
return true;
}
@@ -99,26 +103,62 @@ bool SQLQueryHolder::SetPQuery(size_t index, const char *format, ...)
QueryResult SQLQueryHolder::GetResult(size_t index)
{
// Don't call to this function if the index is of a prepared statement
if (index < m_queries.size())
{
/// the query strings are freed on the first GetResult or in the destructor
if (m_queries[index].first != NULL)
if (SQLElementData* data = &m_queries[index].first)
{
free((void*)(const_cast<char*>(m_queries[index].first)));
m_queries[index].first = NULL;
free((void*)(const_cast<char*>(data->element.query)));
data->element.query = NULL;
}
/// when you get a result aways remember to delete it!
return m_queries[index].second;
ResultSet* result = m_queries[index].second.qresult;
if (!result || !result->GetRowCount())
return QueryResult(NULL);
result->NextRow();
return QueryResult(result);
}
else
return QueryResult(NULL);
}
void SQLQueryHolder::SetResult(size_t index, QueryResult result)
PreparedQueryResult SQLQueryHolder::GetPreparedResult(size_t index)
{
// Don't call to this function if the index is of a prepared statement
if (index < m_queries.size())
{
/// the query strings are freed on the first GetResult or in the destructor
if (SQLElementData* data = &m_queries[index].first)
{
delete data->element.stmt;
data->element.stmt = NULL;
}
PreparedResultSet* result = m_queries[index].second.presult;
if (!result || !result->GetRowCount())
return PreparedQueryResult(NULL);
result->NextRow();
return PreparedQueryResult(result);
}
else
return PreparedQueryResult(NULL);
}
void SQLQueryHolder::SetResult(size_t index, ResultSet* result)
{
/// store the result in the holder
if (index < m_queries.size())
m_queries[index].second = result;
m_queries[index].second.qresult = result;
}
void SQLQueryHolder::SetPreparedResult(size_t index, PreparedResultSet* result)
{
/// store the result in the holder
if (index < m_queries.size())
m_queries[index].second.presult = result;
}
SQLQueryHolder::~SQLQueryHolder()
@@ -127,8 +167,18 @@ SQLQueryHolder::~SQLQueryHolder()
{
/// if the result was never used, free the resources
/// results used already (getresult called) are expected to be deleted
if (m_queries[i].first != NULL)
free((void*)(const_cast<char*>(m_queries[i].first)));
if (SQLElementData* data = &m_queries[i].first)
{
switch (data->type)
{
case SQL_ELEMENT_RAW:
free((void*)(const_cast<char*>(data->element.query)));
break;
case SQL_ELEMENT_PREPARED:
delete data->element.stmt;
break;
}
}
}
}
@@ -149,9 +199,26 @@ bool SQLQueryHolderTask::Execute()
for (size_t i = 0; i < queries.size(); i++)
{
/// execute all queries in the holder and pass the results
char const *sql = queries[i].first;
if (sql)
m_holder->SetResult(i, m_conn->Query(sql));
if (SQLElementData* data = &queries[i].first)
{
switch (data->type)
{
case SQL_ELEMENT_RAW:
{
char const *sql = data->element.query;
if (sql)
m_holder->SetResult(i, m_conn->Query(sql));
break;
}
case SQL_ELEMENT_PREPARED:
{
PreparedStatement* stmt = data->element.stmt;
if (stmt)
m_holder->SetPreparedResult(i, m_conn->Query(stmt));
break;
}
}
}
}
m_result.set(m_holder);
+36 -2
View File
@@ -25,6 +25,37 @@
#include "Common.h"
#include "Callback.h"
//- Forward declare (don't include header to prevent circular includes)
class PreparedStatement;
//- Union that holds element data
union SQLElementUnion
{
PreparedStatement* stmt;
const char* query;
};
//- Type specifier of our element data
enum SQLElementDataType
{
SQL_ELEMENT_RAW,
SQL_ELEMENT_PREPARED,
};
//- The element
struct SQLElementData
{
SQLElementUnion element;
SQLElementDataType type;
};
//- For ambigious resultsets
union SQLResultSetUnion
{
PreparedResultSet* presult;
ResultSet* qresult;
};
class MySQLConnection;
class SQLOperation : public ACE_Method_Request
@@ -65,16 +96,19 @@ class SQLQueryHolder
{
friend class SQLQueryHolderTask;
private:
typedef std::pair<const char*, QueryResult> SQLResultPair;
typedef std::pair<SQLElementData, SQLResultSetUnion> SQLResultPair;
std::vector<SQLResultPair> m_queries;
public:
SQLQueryHolder() {}
~SQLQueryHolder();
bool SetQuery(size_t index, const char *sql);
bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4);
bool SetPreparedQuery(size_t index, PreparedStatement* stmt);
void SetSize(size_t size);
QueryResult GetResult(size_t index);
void SetResult(size_t index, QueryResult result);
PreparedQueryResult GetPreparedResult(size_t index);
void SetResult(size_t index, ResultSet* result);
void SetPreparedResult(size_t index, PreparedResultSet* result);
};
typedef ACE_Future<SQLQueryHolder*> QueryResultHolderFuture;
+11 -11
View File
@@ -22,8 +22,8 @@
//- Append a raw ad-hoc query to the transaction
void Transaction::Append(const char* sql)
{
TransactionElementData data;
data.type = TRANSACTION_ELEMENT_RAW;
SQLElementData data;
data.type = SQL_ELEMENT_RAW;
data.element.query = strdup(sql);
m_queries.push(data);
}
@@ -42,8 +42,8 @@ void Transaction::PAppend(const char* sql, ...)
//- Append a prepared statement to the transaction
void Transaction::Append(PreparedStatement* stmt)
{
TransactionElementData data;
data.type = TRANSACTION_ELEMENT_PREPARED;
SQLElementData data;
data.type = SQL_ELEMENT_PREPARED;
data.element.stmt = stmt;
m_queries.push(data);
}
@@ -52,13 +52,13 @@ void Transaction::Cleanup()
{
while (!m_queries.empty())
{
TransactionElementData data = m_queries.front();
SQLElementData data = m_queries.front();
switch (data.type)
{
case TRANSACTION_ELEMENT_PREPARED:
case SQL_ELEMENT_PREPARED:
delete data.element.stmt;
break;
case TRANSACTION_ELEMENT_RAW:
case SQL_ELEMENT_RAW:
free((void*)(data.element.query));
break;
}
@@ -68,17 +68,17 @@ void Transaction::Cleanup()
bool TransactionTask::Execute()
{
std::queue<TransactionElementData> &queries = m_trans->m_queries;
std::queue<SQLElementData> &queries = m_trans->m_queries;
if (queries.empty())
return false;
m_conn->BeginTransaction();
while (!queries.empty())
{
TransactionElementData data = queries.front();
SQLElementData data = queries.front();
switch (data.type)
{
case TRANSACTION_ELEMENT_PREPARED:
case SQL_ELEMENT_PREPARED:
{
PreparedStatement* stmt = data.element.stmt;
ASSERT(stmt);
@@ -91,7 +91,7 @@ bool TransactionTask::Execute()
delete data.element.stmt;
}
break;
case TRANSACTION_ELEMENT_RAW:
case SQL_ELEMENT_RAW:
{
const char* sql = data.element.query;
ASSERT(sql);
+1 -22
View File
@@ -24,27 +24,6 @@
//- Forward declare (don't include header to prevent circular includes)
class PreparedStatement;
//- Union that holds element data
union TransactionElementUnion
{
PreparedStatement* stmt;
const char* query;
};
//- Type specifier of our element data
enum TransactionElementDataType
{
TRANSACTION_ELEMENT_RAW,
TRANSACTION_ELEMENT_PREPARED,
};
//- The transaction element
struct TransactionElementData
{
TransactionElementUnion element;
TransactionElementDataType type;
};
/*! Transactions, high level class. */
class Transaction
{
@@ -60,7 +39,7 @@ class Transaction
protected:
void Cleanup();
std::queue<TransactionElementData> m_queries;
std::queue<SQLElementData> m_queries;
private:
bool m_actioned;