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/Field.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/Field.h')
-rw-r--r-- | src/server/shared/Database/Field.h | 320 |
1 files changed, 276 insertions, 44 deletions
diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h index 2885d9eff8b..0870f1c8562 100644 --- a/src/server/shared/Database/Field.h +++ b/src/server/shared/Database/Field.h @@ -1,6 +1,4 @@ /* - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> * * This program is free software; you can redistribute it and/or modify @@ -18,74 +16,308 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#if !defined(FIELD_H) -#define FIELD_H -#include <iostream> +#ifndef _FIELD_H +#define _FIELD_H + #include "Common.h" +#include "Log.h" + +#include <mysql.h> class Field { + friend class ResultSet; + friend class PreparedResultSet; + public: + + bool GetBool() const // Wrapper, actually gets integer + { + return GetUInt8() == 1 ? true : false; + } - enum DataTypes + uint8 GetUInt8() const { - DB_TYPE_UNKNOWN = 0x00, - DB_TYPE_STRING = 0x01, - DB_TYPE_INTEGER = 0x02, - DB_TYPE_FLOAT = 0x03, - DB_TYPE_BOOL = 0x04 - }; + if (!data.value) + return 0; - Field(); - Field(Field &f); - Field(const char *value, enum DataTypes type); + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetUInt8() on non-numeric field."); + return 0; + } + #endif + if (data.raw) + return *reinterpret_cast<uint8*>(data.value); + return static_cast<uint8>(atol((char*)data.value)); + } - ~Field(); + int8 GetInt8() const + { + if (!data.value) + return 0; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GeInt8() on non-numeric field."); + return 0; + } + #endif + if (data.raw) + return *reinterpret_cast<int8*>(data.value); + return static_cast<int8>(atol((char*)data.value)); + } + + uint16 GetUInt16() const + { + if (!data.value) + return 0; - enum DataTypes GetType() const { return mType; } + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetUInt16() on non-numeric field."); + return 0; + } + #endif + if (data.raw) + return *reinterpret_cast<uint16*>(data.value); + return static_cast<uint16>(atol((char*)data.value)); + } - const char *GetString() const { return mValue; } - std::string GetCppString() const + int16 GetInt16() const { - return mValue ? mValue : ""; // std::string s = 0 have undefine result in C++ + if (!data.value) + return 0; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetInt16() on non-numeric field."); + return 0; + } + #endif + if (data.raw) + return *reinterpret_cast<int16*>(data.value); + return static_cast<int16>(atol((char*)data.value)); } - float GetFloat() const { return mValue ? static_cast<float>(atof(mValue)) : 0.0f; } - bool GetBool() const { return mValue ? atoi(mValue) > 0 : false; } - int32 GetInt32() const { return mValue ? static_cast<int32>(atol(mValue)) : int32(0); } - uint8 GetUInt8() const { return mValue ? static_cast<uint8>(atol(mValue)) : uint8(0); } - uint16 GetUInt16() const { return mValue ? static_cast<uint16>(atol(mValue)) : uint16(0); } - int16 GetInt16() const { return mValue ? static_cast<int16>(atol(mValue)) : int16(0); } - uint32 GetUInt32() const { return mValue ? static_cast<uint32>(atol(mValue)) : uint32(0); } - uint64 GetUInt64() const + + uint32 GetUInt32() const { - if(mValue) + if (!data.value) + return 0; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) { - uint64 value; - sscanf(mValue,UI64FMTD,&value); - return value; + sLog.outSQLDriver("Error: GetUInt32() on non-numeric field."); + return 0; } - else + #endif + if (data.raw) + return *reinterpret_cast<uint32*>(data.value); + return static_cast<uint32>(atol((char*)data.value)); + } + + int32 GetInt32() const + { + if (!data.value) + return 0; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetInt32() on non-numeric field."); return 0; + } + #endif + if (data.raw) + return *reinterpret_cast<int32*>(data.value); + return static_cast<int32>(atol((char*)data.value)); } - uint64 GetInt64() const + + uint64 GetUInt64() const { - if(mValue) + if (!data.value) + return 0; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) { - int64 value; - sscanf(mValue,SI64FMTD,&value); - return value; + sLog.outSQLDriver("Error: GetUInt64() on non-numeric field."); + return 0; } - else + #endif + if (data.raw) + return *reinterpret_cast<uint64*>(data.value); + return static_cast<uint64>(atol((char*)data.value)); + } + + int64 GetInt64() const + { + if (!data.value) + return 0; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetInt64() on non-numeric field."); return 0; + } + #endif + if (data.raw) + return *reinterpret_cast<int64*>(data.value); + return static_cast<int64>(atol((char*)data.value)); + } + + float GetFloat() const + { + if (!data.value) + return 0.0f; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetFloat() on non-numeric field."); + return 0.0f; + } + #endif + if (data.raw) + return *reinterpret_cast<float*>(data.value); + return static_cast<float>(atof((char*)data.value)); + } + + double GetDouble() const + { + if (!data.value) + return 0.0f; + + #ifdef TRINITY_DEBUG + if (!IsNumeric()) + { + sLog.outSQLDriver("Error: GetDouble() on non-numeric field."); + return 0.0f; + } + #endif + if (data.raw) + return *reinterpret_cast<double*>(data.value); + return static_cast<double>(atof((char*)data.value)); + } + + const char* GetCString() const + { + if (!data.value) + return NULL; + + #ifdef TRINITY_DEBUG + if (IsNumeric()) + { + sLog.outSQLDriver("Error: GetCString() on numeric field."); + return NULL; + } + #endif + return static_cast<const char*>(data.value); + } + + std::string GetString() const + { + if (!data.value) + return ""; + + if (data.raw) + { + const char* string = GetCString(); + if (!string) + string = ""; + return std::string(string, data.length); + } + return std::string((char*)data.value); + } + + protected: + Field(); + ~Field(); + + struct + { + enum_field_types type; // Field type + void* value; // Actual data in memory + bool raw; // Raw bytes? (Prepared statement or adhoc) + uint32 length; // Length (prepared strings only) + } data; + + void SetByteValue(void* newValue, const size_t newSize, enum_field_types newType, uint32 length); + void SetStructuredValue(char* newValue, enum_field_types newType, const size_t newSize); + + void CleanUp() + { + delete[] (data.value); + data.value = NULL; } - void SetType(enum DataTypes type) { mType = type; } + static 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; - void SetValue(const char *value); + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return 64; - private: - char *mValue; - enum DataTypes mType; + case MYSQL_TYPE_GEOMETRY: + /* + Following types are not sent over the wire: + MYSQL_TYPE_ENUM: + MYSQL_TYPE_SET: + */ + default: + sLog.outSQLDriver("SQL::SizeForType(): invalid field type %u", uint32(field->type)); + return 0; + } + } + + bool IsNumeric() const + { + return (data.type == MYSQL_TYPE_TINY || + data.type == MYSQL_TYPE_SHORT || + data.type == MYSQL_TYPE_INT24 || + data.type == MYSQL_TYPE_LONG || + data.type == MYSQL_TYPE_FLOAT || + data.type == MYSQL_TYPE_DOUBLE || + data.type == MYSQL_TYPE_LONGLONG ); + } }; + #endif |