TrinityCore
Loading...
Searching...
No Matches
DBCDatabaseLoader.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "DBCDatabaseLoader.h"
19#include "Common.h"
20#include "DatabaseEnv.h"
21#include "Errors.h"
22#include "Log.h"
23#include "StringFormat.h"
24#include <sstream>
25
26DBCDatabaseLoader::DBCDatabaseLoader(char const* tableName, char const* dbFormatString, char const* primaryKey, char const* dbcFormatString, std::vector<char*>& stringPool)
27 : _sqlTableName(tableName), _formatString(dbFormatString), _indexName(primaryKey), _dbcFormat(dbcFormatString), _sqlIndexPos(0), _recordSize(0), _stringPool(stringPool)
28{
29 // Get sql index position
30 int32 indexPos = -1;
32 ASSERT(indexPos >= 0);
34
35 uint32 uIndexPos = uint32(indexPos);
36 char const* fmt = _formatString;
37 while (uIndexPos)
38 {
39 switch (*fmt)
40 {
41 case FT_SQL_PRESENT:
43 break;
44 case FT_SQL_ABSENT:
45 break;
46 default:
47 ABORT_MSG("Invalid DB format string for '%s'", tableName);
48 break;
49 }
50 --uIndexPos;
51 ++fmt;
52 }
53 ASSERT(*fmt == FT_SQL_PRESENT, "Index column not present in format string for '%s'", tableName);
54}
55
56static char const* nullStr = "";
57
58char* DBCDatabaseLoader::Load(uint32& records, char**& indexTable)
59{
60 std::string query = Trinity::StringFormat("SELECT * FROM {} ORDER BY {} DESC;", _sqlTableName, _indexName);
61
62 // no error if empty set
63 QueryResult result = WorldDatabase.Query(query.c_str());
64 if (!result)
65 return nullptr;
66
67 // Check if sql index pos is valid
68 if (int32(result->GetFieldCount() - 1) < _sqlIndexPos)
69 {
70 ABORT_MSG("Invalid index pos for dbc: '%s'", _sqlTableName);
71 return nullptr;
72 }
73
74 // Resize index table
75 // database query *MUST* contain ORDER BY `index_field` DESC clause
76 uint32 indexTableSize = std::max(records, (*result)[_sqlIndexPos].GetUInt32() + 1);
77 if (indexTableSize > records)
78 {
79 char** tmpIdxTable = new char*[indexTableSize];
80 memset(tmpIdxTable, 0, indexTableSize * sizeof(char*));
81 memcpy(tmpIdxTable, indexTable, records * sizeof(char*));
82 delete[] indexTable;
83 indexTable = tmpIdxTable;
84 }
85
86 std::unique_ptr<char[]> dataTable = std::make_unique<char[]>(result->GetRowCount() * _recordSize);
87 std::unique_ptr<uint32[]> newIndexes = std::make_unique<uint32[]>(result->GetRowCount());
88 uint32 newRecords = 0;
89
90 // Insert sql data into the data array
91 do
92 {
93 Field* fields = result->Fetch();
94
95 uint32 indexValue = fields[_sqlIndexPos].GetUInt32();
96
97 char* dataValue = indexTable[indexValue];
98 if (!dataValue)
99 {
100 newIndexes[newRecords] = indexValue;
101 dataValue = &dataTable[newRecords++ * _recordSize];
102 }
103 else
104 {
105 // Attempt to overwrite existing data
106 ABORT_MSG("Index %d already exists in dbc:'%s'", indexValue, _sqlTableName);
107 return nullptr;
108 }
109
110 uint32 dataOffset = 0;
111 uint32 sqlColumnNumber = 0;
112 char const* dbcFormat = _dbcFormat;
113 char const* sqlFormat = _formatString;
114 for (; (*dbcFormat || *sqlFormat); ++dbcFormat, ++sqlFormat)
115 {
116 if (!*dbcFormat || !*sqlFormat)
117 {
118 ABORT_MSG("DB and DBC format strings do not have the same length for '%s'", _sqlTableName);
119 return nullptr;
120 }
121 if (!*dbcFormat)
122 break;
123 switch (*sqlFormat)
124 {
125 case FT_SQL_PRESENT:
126 switch (*dbcFormat)
127 {
128 case FT_FLOAT:
129 *reinterpret_cast<float*>(&dataValue[dataOffset]) = fields[sqlColumnNumber].GetFloat();
130 dataOffset += sizeof(float);
131 break;
132 case FT_IND:
133 case FT_INT:
134 *reinterpret_cast<uint32*>(&dataValue[dataOffset]) = fields[sqlColumnNumber].GetUInt32();
135 dataOffset += sizeof(uint32);
136 break;
137 case FT_BYTE:
138 *reinterpret_cast<uint8*>(&dataValue[dataOffset]) = fields[sqlColumnNumber].GetUInt8();
139 dataOffset += sizeof(uint8);
140 break;
141 case FT_STRING:
142 *reinterpret_cast<char**>(&dataValue[dataOffset]) = CloneStringToPool(fields[sqlColumnNumber].GetString());
143 dataOffset += sizeof(char*);
144 break;
145 case FT_SORT:
146 break;
147 default:
148 ABORT_MSG("Unsupported data type '%c' marked present in table '%s'", *dbcFormat, _sqlTableName);
149 return nullptr;
150 }
151 ++sqlColumnNumber;
152 break;
153 case FT_SQL_ABSENT:
154 switch (*dbcFormat)
155 {
156 case FT_FLOAT:
157 *reinterpret_cast<float*>(&dataValue[dataOffset]) = 0.0f;
158 dataOffset += sizeof(float);
159 break;
160 case FT_IND:
161 case FT_INT:
162 *reinterpret_cast<uint32*>(&dataValue[dataOffset]) = uint32(0);
163 dataOffset += sizeof(uint32);
164 break;
165 case FT_BYTE:
166 *reinterpret_cast<uint8*>(&dataValue[dataOffset]) = uint8(0);
167 dataOffset += sizeof(uint8);
168 break;
169 case FT_STRING:
170 *reinterpret_cast<char**>(&dataValue[dataOffset]) = const_cast<char*>(nullStr);
171 dataOffset += sizeof(char*);
172 break;
173 }
174 break;
175 default:
176 ABORT_MSG("Invalid DB format string for '%s'", _sqlTableName);
177 return nullptr;
178 }
179 }
180 ASSERT(sqlColumnNumber == result->GetFieldCount(), "SQL format string does not match database for table: '%s'", _sqlTableName);
181 ASSERT(dataOffset == _recordSize);
182 } while (result->NextRow());
183
184 ASSERT(newRecords == result->GetRowCount());
185
186 // insert new records to index table
187 for (uint32 i = 0; i < newRecords; ++i)
188 indexTable[newIndexes[i]] = &dataTable[i * _recordSize];
189
190 records = indexTableSize;
191
192 return dataTable.release();
193}
194
195char* DBCDatabaseLoader::CloneStringToPool(std::string const& str)
196{
197 char* buf = new char[str.size() + 1];
198 memcpy(buf, str.c_str(), str.size() + 1);
199 _stringPool.push_back(buf);
200 return buf;
201}
static char const * nullStr
@ FT_IND
@ FT_FLOAT
@ FT_STRING
@ FT_SORT
@ FT_INT
@ FT_BYTE
@ FT_SQL_ABSENT
@ FT_SQL_PRESENT
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define ABORT_MSG
Definition Errors.h:75
#define ASSERT
Definition Errors.h:68
static uint32 GetFormatRecordSize(const char *format, int32 *index_pos=nullptr)
Class used to access individual fields of database query result.
Definition Field.h:92
uint32 GetUInt32() const
Definition Field.cpp:61
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
char * Load(uint32 &records, char **&indexTable)
char const * _formatString
std::vector< char * > & _stringPool
char * CloneStringToPool(std::string const &str)
char const * _dbcFormat
char const * _indexName
DBCDatabaseLoader(char const *dbTable, char const *dbFormatString, char const *index, char const *dbcFormatString, std::vector< char * > &stringPool)
char const * _sqlTableName