diff options
author | Machiavelli <none@none> | 2010-09-24 22:16:21 +0200 |
---|---|---|
committer | Machiavelli <none@none> | 2010-09-24 22:16:21 +0200 |
commit | 3c6dc320308880bde4ef9eddd695db28a74aa0d9 (patch) | |
tree | f209e6c487e436fc1cd978487dddf3604ce2b594 /src/server/shared/Database/QueryResult.h | |
parent | b46b498141cc167163c6112e8e2bfa32fec2d7dc (diff) |
Core/DBLayer:
- Rewrite Field class to be able to store both binary prepared statement data and data from adhoc query resultsets
- Buffer the data of prepared statements using ResultSet and Field classes and let go of mysql c api structures after PreparedResultSet constructor. Fixes a race condition and thus a possible crash/data corruption (issue pointed out to Derex, basic suggestion by raczman)
- Conform PreparedResultSet and ResultSet to the same design standards, and using Field class as data buffer class for both
* NOTE: This means the fetching methods are uniform again, using ¨Field* fields = result->Fetch();¨ and access to elements trough fields[x].
* NOTE: for access to the correct row in prepared statements, ¨Field* fields = result->Fetch();¨ must ALWAYS be called inside the do { }while(result->NextRow()) loop.
* NOTE: This means that Field::GetString() returns std::string object and Field::GetCString() returns const char* pointer.
Still experimental and all that jazz, not recommended for production servers until feedback is given.
--HG--
branch : trunk
Diffstat (limited to 'src/server/shared/Database/QueryResult.h')
-rwxr-xr-x | src/server/shared/Database/QueryResult.h | 197 |
1 files changed, 37 insertions, 160 deletions
diff --git a/src/server/shared/Database/QueryResult.h b/src/server/shared/Database/QueryResult.h index 22cd8bbf19e..aa088b5f121 100755 --- a/src/server/shared/Database/QueryResult.h +++ b/src/server/shared/Database/QueryResult.h @@ -39,193 +39,70 @@ class ResultSet ~ResultSet(); bool NextRow(); - - Field *Fetch() const { return mCurrentRow; } - - const Field & operator [] (int index) const { return mCurrentRow[index]; } - - uint32 GetFieldCount() const { return mFieldCount; } - uint64 GetRowCount() const { return mRowCount; } + uint64 GetRowCount() const { return m_rowCount; } + uint32 GetFieldCount() const { return m_fieldCount; } + + Field *Fetch() const { return m_currentRow; } + const Field & operator [] (uint32 index) const + { + ASSERT(index < m_rowCount); + return m_currentRow[index]; + } protected: - Field *mCurrentRow; - uint32 mFieldCount; - uint64 mRowCount; + Field *m_currentRow; + uint64 m_rowCount; + uint32 m_fieldCount; private: - enum Field::DataTypes ConvertNativeType(enum_field_types mysqlType) const; - void EndQuery(); - MYSQL_RES *mResult; - + void CleanUp(); + MYSQL_RES *m_result; + MYSQL_FIELD *m_fields; }; typedef ACE_Refcounted_Auto_Ptr<ResultSet, ACE_Null_Mutex> QueryResult; -typedef std::vector<std::string> QueryFieldNames; - -class QueryNamedResult +class PreparedResultSet { public: - explicit QueryNamedResult(ResultSet* query, QueryFieldNames const& names) : mQuery(query), mFieldNames(names) {} - ~QueryNamedResult() { delete mQuery; } - - // compatible interface with ResultSet - bool NextRow() { return mQuery->NextRow(); } - Field *Fetch() const { return mQuery->Fetch(); } - uint32 GetFieldCount() const { return mQuery->GetFieldCount(); } - uint64 GetRowCount() const { return mQuery->GetRowCount(); } - Field const& operator[] (int index) const { return (*mQuery)[index]; } + PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount); + ~PreparedResultSet(); - // named access - Field const& operator[] (const std::string &name) const { return mQuery->Fetch()[GetField_idx(name)]; } - QueryFieldNames const& GetFieldNames() const { return mFieldNames; } + bool NextRow(); + uint64 GetRowCount() const { return m_rowCount; } + uint32 GetFieldCount() const { return m_fieldCount; } - uint32 GetField_idx(const std::string &name) const + Field* Fetch() const { - for (size_t idx = 0; idx < mFieldNames.size(); ++idx) - { - if(mFieldNames[idx] == name) - return idx; - } - ASSERT(false && "unknown field name"); - return uint32(-1); + ASSERT(m_rowPosition < m_rowCount); + return m_rows[m_rowPosition]; } - protected: - ResultSet *mQuery; - QueryFieldNames mFieldNames; -}; - -class ResultBind -{ - friend class PreparedResultSet; - public: - - ResultBind(MYSQL_STMT* stmt) : m_rBind(NULL), m_stmt(stmt), m_res(NULL), m_isNull(NULL), m_length(NULL), m_fieldCount(0) {} - - ~ResultBind() + const Field & operator [] (uint32 index) const { - CleanUp(); // Clean up buffer + ASSERT(m_rowPosition < m_rowCount); + ASSERT(index < m_fieldCount); + return m_rows[m_rowPosition][index]; } - void BindResult(uint64& num_rows); - protected: + uint64 m_rowCount; + uint64 m_rowPosition; + std::vector<Field*> m_rows; + uint32 m_fieldCount; + + private: MYSQL_BIND* m_rBind; MYSQL_STMT* m_stmt; MYSQL_RES* m_res; - void FreeBindBuffer(); - bool IsValidIndex(uint32 index) { return index < m_fieldCount; } - - private: - - void CleanUp(); - - size_t SizeForType(MYSQL_FIELD* field) - { - switch (field->type) - { - case MYSQL_TYPE_NULL: - return 0; - case MYSQL_TYPE_TINY: - return 1; - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_SHORT: - return 2; - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_FLOAT: - return 4; - case MYSQL_TYPE_DOUBLE: - case MYSQL_TYPE_LONGLONG: - case MYSQL_TYPE_BIT: - return 8; - - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - return sizeof(MYSQL_TIME); - - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_VAR_STRING: - return field->max_length + 1; - - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - return 64; - - case MYSQL_TYPE_GEOMETRY: - /* - Following types are not sent over the wire: - MYSQL_TYPE_ENUM: - MYSQL_TYPE_SET: - */ - default: - sLog.outSQLDriver("ResultBind::SizeForType(): invalid field type %u", uint32(field->type)); - return 0; - } - } - my_bool* m_isNull; unsigned long* m_length; - uint32 m_fieldCount; -}; -class PreparedResultSet -{ - template<class T> friend class DatabaseWorkerPool; - public: - PreparedResultSet(MYSQL_STMT* stmt) - { - num_rows = 0; - row_position = 0; - rbind = new ResultBind(stmt); - rbind->BindResult(num_rows); - } - ~PreparedResultSet() - { - delete rbind; - } - - operator bool() { return num_rows > 0; } - - bool GetBool(uint32 index); - uint8 GetUInt8(uint32 index); - int8 GetInt8(uint32 index); - uint16 GetUInt16(uint32 index); - int16 GetInt16(uint32 index); - uint32 GetUInt32(uint32 index); - int32 GetInt32(uint32 index); - uint64 GetUInt64(uint32 index); - int64 GetInt64(uint32 index); - float GetFloat(uint32 index); - std::string GetString(uint32 index); - const char* GetCString(uint32 index); - - bool NextRow(); - uint64 GetRowCount() const { return num_rows; } - - private: - bool CheckFieldIndex(uint32 index) const - { - if (!rbind->IsValidIndex(index)) - return false; - - if (rbind->m_isNull[index]) - return false; - - return true; - } + void FreeBindBuffer(); + void CleanUp(); + bool _NextRow(); - ResultBind* rbind; - uint64 row_position; - uint64 num_rows; }; typedef ACE_Refcounted_Auto_Ptr<PreparedResultSet, ACE_Null_Mutex> PreparedQueryResult; |