void DB2DatabaseLoader::LoadStrings(uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool) { PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(_loadInfo->Statement + 1)); stmt->setString(0, localeNames[locale]); PreparedQueryResult result = HotfixDatabase.Query(stmt); if (!result) return; std::size_t stringFields = _loadInfo->GetStringFieldCount(true); if (result->GetFieldCount() != stringFields + 1 /*ID*/) return; uint32 fieldCount = _loadInfo->Meta->FieldCount; uint32 recordSize = _loadInfo->Meta->GetRecordSize(); do { Field* fields = result->Fetch(); uint32 offset = 0; uint32 stringFieldNumInRecord = 0; uint32 indexValue = fields[0].GetUInt32(); if (indexValue >= records) continue; // Attempt to overwrite existing data if (char* dataValue = indexTable[indexValue]) { uint32 fieldIndex = 0; if (!_loadInfo->Meta->HasIndexFieldInData()) { offset += 4; ++fieldIndex; } for (uint32 x = 0; x < fieldCount; ++x) { for (uint32 z = 0; z < _loadInfo->Meta->ArraySizes[x]; ++z) { switch (_loadInfo->TypesString[fieldIndex]) { case FT_FLOAT: case FT_INT: offset += 4; break; case FT_BYTE: offset += 1; break; case FT_SHORT: offset += 2; break; case FT_STRING: { // fill only not filled entries LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]); if (db2str->Str[locale] == nullStr) if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString())) stringPool.push_back(str); ++stringFieldNumInRecord; offset += sizeof(LocalizedString*); break; } case FT_STRING_NOT_LOCALIZED: offset += sizeof(char*); break; default: ASSERT(false, "Unknown format character '%c' found in %s meta", _loadInfo->Meta->Types[x], _storageName.c_str()); break; } ++fieldIndex; } } ASSERT(offset == recordSize); } else TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u locale %s!", _storageName.c_str(), indexValue, localeNames[locale]); } while (result->NextRow()); return; }
char* DB2DatabaseLoader::Load(uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool) { // Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(_loadInfo->Statement)); if (!result) return nullptr; if (_loadInfo->Meta->GetDbFieldCount() != result->GetFieldCount()) return nullptr; // get struct size and index pos uint32 indexField = _loadInfo->Meta->GetDbIndexField(); uint32 recordSize = _loadInfo->Meta->GetRecordSize(); // we store flat holders pool as single memory block std::size_t stringFields = _loadInfo->GetStringFieldCount(false); std::size_t localizedStringFields = _loadInfo->GetStringFieldCount(true); // each string field at load have array of string for each locale std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); if (stringFields) { std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); stringHolders = new char[stringHoldersPoolSize]; // DB2 strings expected to have at least empty string for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) ((char const**)stringHolders)[i] = nullStr; } else stringHolders = nullptr; // Resize index table // database query *MUST* contain ORDER BY `index_field` DESC clause uint32 indexTableSize = (*result)[indexField].GetUInt32() + 1; if (indexTableSize < records) indexTableSize = records; if (indexTableSize > records) { char** tmpIdxTable = new char*[indexTableSize]; memset(tmpIdxTable, 0, indexTableSize * sizeof(char*)); memcpy(tmpIdxTable, indexTable, records * sizeof(char*)); delete[] indexTable; indexTable = tmpIdxTable; } char* tempDataTable = new char[result->GetRowCount() * recordSize]; uint32* newIndexes = new uint32[result->GetRowCount()]; uint32 rec = 0; uint32 newRecords = 0; do { Field* fields = result->Fetch(); uint32 offset = 0; uint32 stringFieldOffset = 0; uint32 indexValue = fields[indexField].GetUInt32(); // Attempt to overwrite existing data char* dataValue = indexTable[indexValue]; if (!dataValue) { newIndexes[newRecords] = indexValue; dataValue = &tempDataTable[newRecords++ * recordSize]; } uint32 f = 0; if (!_loadInfo->Meta->HasIndexFieldInData()) { *((uint32*)(&dataValue[offset])) = indexValue; offset += 4; ++f; } for (uint32 x = 0; x < _loadInfo->Meta->FieldCount; ++x) { for (uint32 z = 0; z < _loadInfo->Meta->ArraySizes[x]; ++z) { switch (_loadInfo->TypesString[f]) { case FT_FLOAT: *((float*)(&dataValue[offset])) = fields[f].GetFloat(); offset += 4; break; case FT_INT: *((int32*)(&dataValue[offset])) = fields[f].GetInt32(); offset += 4; break; case FT_BYTE: *((int8*)(&dataValue[offset])) = fields[f].GetInt8(); offset += 1; break; case FT_SHORT: *((int16*)(&dataValue[offset])) = fields[f].GetInt16(); offset += 2; break; case FT_STRING: { LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); ASSERT(*slot); // Value in database in main table field must be for enUS locale if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString())) stringPool.push_back(str); stringFieldOffset += sizeof(LocalizedString); offset += sizeof(char*); break; } case FT_STRING_NOT_LOCALIZED: { char const** slot = (char const**)(&dataValue[offset]); *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); ASSERT(*slot); // Value in database in main table field must be for enUS locale if (char* str = AddString(slot, fields[f].GetString())) stringPool.push_back(str); stringFieldOffset += sizeof(char*); offset += sizeof(char*); break; } default: ASSERT(false, "Unknown format character '%c' found in %s meta", _loadInfo->Meta->Types[x], _storageName.c_str()); break; } ++f; } } ASSERT(offset == recordSize); ++rec; } while (result->NextRow()); if (!newRecords) { delete[] tempDataTable; delete[] newIndexes; return nullptr; } // Compact new data table to only contain new records not previously loaded from file char* dataTable = new char[newRecords * recordSize]; memcpy(dataTable, tempDataTable, newRecords * recordSize); // insert new records to index table for (uint32 i = 0; i < newRecords; ++i) indexTable[newIndexes[i]] = &dataTable[i * recordSize]; delete[] tempDataTable; delete[] newIndexes; records = indexTableSize; return dataTable; }
void DB2DatabaseLoader::LoadStrings(const char* format, uint32 preparedStatement, uint32 locale, char**& indexTable, std::list<char*>& stringPool) { PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement); stmt->setString(0, localeNames[locale]); PreparedQueryResult result = HotfixDatabase.Query(stmt); if (!result) return; size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format); if (result->GetFieldCount() != stringFields + 1 /*ID*/) return; uint32 const fieldCount = strlen(format); int32 indexField; uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField); ASSERT(indexField >= 0, "DB2Storage must be indexed to load localized strings"); do { Field* fields = result->Fetch(); uint32 offset = 0; uint32 stringFieldNumInRecord = 0; uint32 indexValue = fields[0].GetUInt32(); // Attempt to overwrite existing data if (char* dataValue = indexTable[indexValue]) { for (uint32 x = 0; x < fieldCount; x++) { switch (format[x]) { case FT_FLOAT: case FT_IND: case FT_INT: offset += 4; break; case FT_BYTE: offset += 1; break; case FT_STRING: { // fill only not filled entries LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]); if (db2str->Str[locale] == nullStr) if (char* str = AddLocaleString(db2str, locale, fields[1 + stringFieldNumInRecord].GetString())) stringPool.push_back(str); ++stringFieldNumInRecord; offset += sizeof(char*); break; } } } ASSERT(offset == recordSize); } else TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u!", _storageName.c_str(), indexValue); } while (result->NextRow()); return; }
static bool HandleBanListHelper(PreparedQueryResult result, ChatHandler* handler) { handler->PSendSysMessage(LANG_BANLIST_MATCHINGACCOUNT); // Chat short output if (handler->GetSession()) { do { Field* fields = result->Fetch(); uint32 accountid = fields[0].GetUInt32(); QueryResult banResult = LoginDatabase.PQuery("SELECT account.username FROM account, account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id", accountid); if (banResult) { Field* fields2 = banResult->Fetch(); handler->PSendSysMessage("%s", fields2[0].GetCString()); } } while (result->NextRow()); } // Console wide output else { handler->SendSysMessage(LANG_BANLIST_ACCOUNTS); handler->SendSysMessage(" ==============================================================================="); handler->SendSysMessage(LANG_BANLIST_ACCOUNTS_HEADER); do { handler->SendSysMessage("-------------------------------------------------------------------------------"); Field* fields = result->Fetch(); uint32 accountId = fields[0].GetUInt32(); std::string accountName; // "account" case, name can be get in same query if (result->GetFieldCount() > 1) accountName = fields[1].GetString(); // "character" case, name need extract from another DB else AccountMgr::GetName(accountId, accountName); // No SQL injection. id is uint32. QueryResult banInfo = LoginDatabase.PQuery("SELECT bandate, unbandate, bannedby, banreason FROM account_banned WHERE id = %u ORDER BY unbandate", accountId); if (banInfo) { Field* fields2 = banInfo->Fetch(); do { time_t timeBan = time_t(fields2[0].GetUInt32()); tm tmBan; ACE_OS::localtime_r(&timeBan, &tmBan); if (fields2[0].GetUInt32() == fields2[1].GetUInt32()) { handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|", accountName.c_str(), tmBan.tm_year%100, tmBan.tm_mon+1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min, fields2[2].GetCString(), fields2[3].GetCString()); } else { time_t timeUnban = time_t(fields2[1].GetUInt32()); tm tmUnban; ACE_OS::localtime_r(&timeUnban, &tmUnban); handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", accountName.c_str(), tmBan.tm_year%100, tmBan.tm_mon+1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min, tmUnban.tm_year%100, tmUnban.tm_mon+1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min, fields2[2].GetCString(), fields2[3].GetCString()); } } while (banInfo->NextRow()); } } while (result->NextRow()); handler->SendSysMessage(" ==============================================================================="); } return true; }
char* DB2DatabaseLoader::Load(const char* format, uint32 preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list<char*>& stringPool) { // Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(preparedStatement)); if (!result) return nullptr; uint32 const fieldCount = strlen(format); if (fieldCount != result->GetFieldCount()) return nullptr; // get struct size and index pos int32 indexField; uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField); // we store flat holders pool as single memory block size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format); // each string field at load have array of string for each locale size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; if (stringFields) { size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); stringHolders = new char[stringHoldersPoolSize]; // DB2 strings expected to have at least empty string for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) ((char const**)stringHolders)[i] = nullStr; } else stringHolders = nullptr; // Resize index table // database query *MUST* contain ORDER BY `index_field` DESC clause uint32 indexTableSize; if (indexField >= 0) { indexTableSize = (*result)[indexField].GetUInt32() + 1; if (indexTableSize < records) indexTableSize = records; } else indexTableSize = records + result->GetRowCount(); if (indexTableSize > records) { char** tmpIdxTable = new char*[indexTableSize]; memset(tmpIdxTable, 0, indexTableSize * sizeof(char*)); memcpy(tmpIdxTable, indexTable, records * sizeof(char*)); delete[] indexTable; indexTable = tmpIdxTable; } char* tempDataTable = new char[result->GetRowCount() * recordSize]; uint32* newIndexes = new uint32[result->GetRowCount()]; uint32 rec = 0; uint32 newRecords = 0; do { Field* fields = result->Fetch(); uint32 offset = 0; uint32 stringFieldNumInRecord = 0; uint32 indexValue; if (indexField >= 0) indexValue = fields[indexField].GetUInt32(); else indexValue = records + rec; // Attempt to overwrite existing data char* dataValue = indexTable[indexValue]; if (!dataValue) { newIndexes[newRecords] = indexValue; dataValue = &tempDataTable[newRecords++ * recordSize]; } for (uint32 f = 0; f < fieldCount; f++) { switch (format[f]) { case FT_FLOAT: *((float*)(&dataValue[offset])) = fields[f].GetFloat(); offset += 4; break; case FT_IND: case FT_INT: *((int32*)(&dataValue[offset])) = fields[f].GetInt32(); offset += 4; break; case FT_BYTE: *((int8*)(&dataValue[offset])) = fields[f].GetInt8(); offset += 1; break; case FT_STRING: { LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringHolderSize * stringFieldNumInRecord]); ASSERT(*slot); // Value in database in main table field must be for enUS locale if (char* str = AddLocaleString(*slot, LOCALE_enUS, fields[f].GetString())) stringPool.push_back(str); ++stringFieldNumInRecord; offset += sizeof(char*); break; } } } ASSERT(offset == recordSize); ++rec; } while (result->NextRow()); if (!newRecords) { delete[] tempDataTable; delete[] newIndexes; return nullptr; } // Compact new data table to only contain new records not previously loaded from file char* dataTable = new char[newRecords * recordSize]; memcpy(dataTable, tempDataTable, newRecords * recordSize); // insert new records to index table for (uint32 i = 0; i < newRecords; ++i) indexTable[newIndexes[i]] = &dataTable[i * recordSize]; delete[] tempDataTable; delete[] newIndexes; records = indexTableSize; return dataTable; }