From 3c6dc320308880bde4ef9eddd695db28a74aa0d9 Mon Sep 17 00:00:00 2001 From: Machiavelli Date: Fri, 24 Sep 2010 22:16:21 +0200 Subject: 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. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Still experimental and all that jazz, not recommended for production servers until feedback is given. --HG-- branch : trunk --- src/server/shared/Database/Field.h | 320 ++++++++++++++++++++++++++++++++----- 1 file changed, 276 insertions(+), 44 deletions(-) (limited to 'src/server/shared/Database/Field.h') 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 - * * Copyright (C) 2008-2010 Trinity * * 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 +#ifndef _FIELD_H +#define _FIELD_H + #include "Common.h" +#include "Log.h" + +#include 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(data.value); + return static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(atol((char*)data.value)); } - float GetFloat() const { return mValue ? static_cast(atof(mValue)) : 0.0f; } - bool GetBool() const { return mValue ? atoi(mValue) > 0 : false; } - int32 GetInt32() const { return mValue ? static_cast(atol(mValue)) : int32(0); } - uint8 GetUInt8() const { return mValue ? static_cast(atol(mValue)) : uint8(0); } - uint16 GetUInt16() const { return mValue ? static_cast(atol(mValue)) : uint16(0); } - int16 GetInt16() const { return mValue ? static_cast(atol(mValue)) : int16(0); } - uint32 GetUInt32() const { return mValue ? static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(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(data.value); + return static_cast(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(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 -- cgit v1.2.3