From 7616ec25fcfb5dadf6d7e7dadaf7584aef08814f Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Fri, 16 Jan 2026 01:29:04 +0100 Subject: [PATCH] DB/Search * add more indizes to large tables for cols used in lookups * drop multi-column indizes on spell as they are not utilized by mysql * add and use fulltext indizes for names of items, spells, quests, creatures & objects could add more, but is it really necessary? * limitations - still need a solution for race/class/spellFamily masks cols that are used as such - fulltext indizes in boolean mode cant partial match the end of a word. reverse name cols and search and match back to front like that..? blows up db size even more though (+trike* : "stormstrike" => +ekirt* : "ekirtsmrots") --- includes/components/dbtypelist.class.php | 7 +- includes/components/filter.class.php | 45 ++++++++- includes/components/search.class.php | 92 +++++++++++------ includes/dbtypes/creature.class.php | 15 +-- includes/dbtypes/gameobject.class.php | 2 +- includes/dbtypes/item.class.php | 2 +- includes/dbtypes/quest.class.php | 15 +-- includes/dbtypes/spell.class.php | 15 +-- setup/sql/01-db_structure.sql | 116 +++++++++++++++++++--- setup/sql/02-db_initial_data.sql | 2 +- setup/sql/updates/1768556688_01.sql | 120 +++++++++++++++++++++++ setup/tools/dbc.class.php | 16 ++- setup/tools/dbc/12340.ini | 4 +- 13 files changed, 373 insertions(+), 78 deletions(-) create mode 100644 setup/sql/updates/1768556688_01.sql diff --git a/includes/components/dbtypelist.class.php b/includes/components/dbtypelist.class.php index ec51e07f..f2aaa4d7 100644 --- a/includes/components/dbtypelist.class.php +++ b/includes/components/dbtypelist.class.php @@ -35,6 +35,7 @@ abstract class DBTypeList * null - operator defaults to: IS [NULL] * operator: modifies/overrides default * ! - negated default value (NOT LIKE; <>; NOT IN) + * MATCH - creates fulltext search ('value' must be array; column must have fulltext index) * condition as str * defines linking (AND || OR) * condition as int @@ -50,12 +51,13 @@ abstract class DBTypeList * ['flags2', 0xF, '&'], * ] * [['mask', 0x3, '&'], 0], + * ['nameField', ['+contains*', '-excludes'], 'MATCH], * ['joinedTbl.field', NULL] // NULL must be explicitly specified "['joinedTbl.field']" would be skipped as erroneous definition (only really usefull when left-joining) * 'OR', * 5 * ) * results in - * WHERE ((`id` = 45) OR (`name` NOT LIKE "test%") OR ((`flags` & 255) AND (`flags2` & 15)) OR ((`mask` & 3) = 0)) OR (`joinedTbl`.`field` IS NULL) LIMIT 5 + * WHERE ((`id` = 45) OR (`name` NOT LIKE "test%") OR ((`flags` & 255) AND (`flags2` & 15)) OR ((`mask` & 3) = 0)) OR (MATCH(`nameField`) AGAINST("+contains* -excludes" IN BOOLEAN MODE)) OR (`joinedTbl`.`field` IS NULL) LIMIT 5 */ public function __construct(array $conditions = [], array $miscData = []) { @@ -167,6 +169,9 @@ abstract class DBTypeList if (is_array($c[1]) && !empty($c[1])) { + if (($c[2] ?? '') === 'MATCH') + return 'MATCH('.$field.') AGAINST(\''.implode(' ', $c[1]).'\' IN BOOLEAN MODE)'; + array_walk($c[1], fn(&$x) => $x = Util::checkNumeric($x) ? $x : DB::Aowow()->escape($x)); $op = (isset($c[2]) && $c[2] == '!') ? 'NOT IN' : 'IN'; diff --git a/includes/components/filter.class.php b/includes/components/filter.class.php index d9f6fefd..0fa11740 100644 --- a/includes/components/filter.class.php +++ b/includes/components/filter.class.php @@ -555,7 +555,7 @@ abstract class Filter return false; } - protected function transformToken(string $string, bool $exact) : string + protected function transformToken(string $string, string $outPH) : string { // escape manually entered _; entering % should be prohibited $string = str_replace('_', '\\_', $string); @@ -563,7 +563,7 @@ abstract class Filter // now replace search wildcards with sql wildcards $string = strtr($string, self::$wCards); - return sprintf($exact ? '%s' : '%%%s%%', $string); + return sprintf($outPH, $string); } protected function tokenizeString(array $fields, string $string = '', bool $exact = false, bool $shortStr = false) : array @@ -579,9 +579,9 @@ abstract class Filter foreach ($parts as $p) { if ($p[0] == '-' && (mb_strlen($p) > 3 || $shortStr)) - $sub[] = [$f, $this->transformToken(mb_substr($p, 1), $exact), '!']; + $sub[] = [$f, $this->transformToken(mb_substr($p, 1), $exact ? '%s' : '%%%s%%'), '!']; else if ($p[0] != '-' && (mb_strlen($p) > 2 || $shortStr)) - $sub[] = [$f, $this->transformToken($p, $exact)]; + $sub[] = [$f, $this->transformToken($p, $exact ? '%s' : '%%%s%%')]; } // single cnd? @@ -609,6 +609,43 @@ abstract class Filter return $qry; } + protected function buildMatchLookup(array $fields, string $string = '', bool $exact = false, bool $shortStr = false) : array + { + if (!$string && $this->values['na']) + $string = $this->values['na']; + + $string = preg_replace('/[^[:alpha:] \d_-]/iu', ' ', $string); + if (!$string) + return []; + + $sub = []; + $parts = $exact ? [$string] : array_filter(explode(' ', $string)); + foreach ($parts as $p) + { + if ($p[0] == '-' && (mb_strlen($p) > 3 || $shortStr)) + $sub[] = $this->transformToken($p, '%s*'); + else if ($p[0] != '-' && (mb_strlen($p) > 2 || $shortStr)) + $sub[] = $this->transformToken($p, '+%s*'); + } + + $qry = []; + foreach ($fields as $f) + $qry[] = [$f, $sub, 'MATCH']; + + // single cnd? + if (!$qry) + { + trigger_error('Filter::tokenizeString - could not tokenize string: '.$string, E_USER_NOTICE); + $this->error = true; + } + else if (count($qry) > 1) + array_unshift($qry, 'OR'); + else + $qry = $qry[0]; + + return $qry; + } + protected function int2Op(mixed &$op) : bool { $op = match ($op) { diff --git a/includes/components/search.class.php b/includes/components/search.class.php index 474252ee..bdeaa4e6 100644 --- a/includes/components/search.class.php +++ b/includes/components/search.class.php @@ -131,7 +131,7 @@ class Search } } - private function createLookup(array $fields = []) : array + private function createLikeLookup(array $fields = []) : array { if ($this->idSearch && $this->included) return ['id', $this->included]; @@ -171,6 +171,36 @@ class Search return $qry; } + private function createMatchLookup(array $fields = []) : array + { + if ($this->idSearch && $this->included) + return ['id', $this->included]; + + if (!$this->included) + return []; + + // default to name-field + if (!$fields) + $fields[] = 'name_loc'.Lang::getLocale()->value; + + $match = array_merge( + array_map(fn($x) => '+'.preg_replace('/[^[:alpha:] \d_-]/iu', ' ', $x).'*', $this->included), + array_map(fn($x) => '-'.preg_replace('/[^[:alpha:] \d_-]/iu', ' ', $x).'*', $this->excluded) + ); + + $qry = []; + foreach ($fields as $f) + $qry[] = [$f, $match, 'MATCH']; + + // single cnd? + if (count($qry) > 1) + array_unshift($qry, 'OR'); + else + $qry = $qry[0]; + + return $qry; + } + public function canPerform() : bool { // has valid search terms or weights and selected modules @@ -206,7 +236,7 @@ class Search private function _searchCharClass() : ?array // 0 Classes: $moduleMask & 0x00000001 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $classes = new CharClassList($cnd, ['calcTotal' => true]); $data = $classes->getListviewData(); @@ -245,7 +275,7 @@ class Search private function _searchCharRace() : ?array // 1 Races: $moduleMask & 0x00000002 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $races = new CharRaceList($cnd, ['calcTotal' => true]); $data = $races->getListviewData(); @@ -284,7 +314,7 @@ class Search private function _searchTitle() : ?array // 2 Titles: $moduleMask & 0x00000004 { - $cnd = array_merge($this->cndBase, [$this->createLookup(['male_loc'.Lang::getLocale()->value, 'female_loc'.Lang::getLocale()->value])]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup(['male_loc'.Lang::getLocale()->value, 'female_loc'.Lang::getLocale()->value])]); $titles = new TitleList($cnd, ['calcTotal' => true]); $data = $titles->getListviewData(); @@ -326,8 +356,8 @@ class Search $cnd = array_merge($this->cndBase, array( array( 'OR', - $this->createLookup(['h.name_loc'.Lang::getLocale()->value]), - ['AND', $this->createLookup(['e.description']), ['e.holidayId', 0]] + $this->createLikeLookup(['h.name_loc'.Lang::getLocale()->value]), + ['AND', $this->createLikeLookup(['e.description']), ['e.holidayId', 0]] ) )); $wEvents = new WorldEventList($cnd, ['calcTotal' => true]); @@ -368,7 +398,7 @@ class Search private function _searchCurrency() : ?array // 4 Currencies $moduleMask & 0x0000010 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $money = new CurrencyList($cnd, ['calcTotal' => true]); $data = $money->getListviewData(); @@ -407,7 +437,7 @@ class Search private function _searchItemset(array &$shared) : ?array// 5 Itemsets $moduleMask & 0x0000020 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $sets = new ItemsetList($cnd, ['calcTotal' => true]); $data = $sets->getListviewData(); @@ -464,7 +494,7 @@ class Search private function _searchItem(array &$shared) : ?array // 6 Items $moduleMask & 0x0000040 { $miscData = ['calcTotal' => true]; - $lookup = $this->createLookup(); + $lookup = $this->createMatchLookup(); if ($this->moduleMask & self::TYPE_JSON) { @@ -544,11 +574,11 @@ class Search private function _searchAbility() : ?array // 7 Abilities (Player + Pet) $moduleMask & 0x0000080 { - $cnd = array_merge($this->cndBase, array( // hmm, inclued classMounts..? + $cnd = array_merge($this->cndBase, array( // hmm, inclued classMounts..? ['s.typeCat', [7, -2, -3, -4]], [['s.cuFlags', (SPELL_CU_TRIGGERED | SPELL_CU_TALENT), '&'], 0], [['s.attributes0', 0x80, '&'], 0], - $this->createLookup() + $this->createMatchLookup() )); $abilities = new SpellList($cnd, ['calcTotal' => true]); @@ -610,7 +640,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', [-7, -2]], - $this->createLookup() + $this->createMatchLookup() )); $talents = new SpellList($cnd, ['calcTotal' => true]); @@ -669,7 +699,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', -13], - $this->createLookup() + $this->createMatchLookup() )); $glyphs = new SpellList($cnd, ['calcTotal' => true]); @@ -723,7 +753,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', -11], - $this->createLookup() + $this->createMatchLookup() )); $prof = new SpellList($cnd, ['calcTotal' => true]); @@ -777,7 +807,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', [9, 11]], - $this->createLookup() + $this->createMatchLookup() )); $prof = new SpellList($cnd, ['calcTotal' => true]); @@ -831,7 +861,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', -6], - $this->createLookup() + $this->createMatchLookup() )); $vPets = new SpellList($cnd, ['calcTotal' => true]); @@ -885,7 +915,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', -5], - $this->createLookup() + $this->createMatchLookup() )); $mounts = new SpellList($cnd, ['calcTotal' => true]); @@ -939,7 +969,7 @@ class Search $cnd = array_merge($this->cndBase, array( [['flagsExtra', 0x80], 0], // exclude trigger creatures [['cuFlags', NPC_CU_DIFFICULTY_DUMMY, '&'], 0], // exclude difficulty entries - $this->createLookup() + $this->createMatchLookup() )); $npcs = new CreatureList($cnd, ['calcTotal' => true]); @@ -991,7 +1021,7 @@ class Search { $cnd = array_merge($this->cndBase, array( [['flags', CUSTOM_UNAVAILABLE | CUSTOM_DISABLED, '&'], 0], - $this->createLookup() + $this->createMatchLookup() )); $quests = new QuestList($cnd, ['calcTotal' => true]); @@ -1040,7 +1070,7 @@ class Search { $cnd = array_merge($this->cndBase, array( [['flags', ACHIEVEMENT_FLAG_COUNTER, '&'], 0], // not a statistic - $this->createLookup() + $this->createLikeLookup() )); $acvs = new AchievementList($cnd, ['calcTotal' => true]); @@ -1092,7 +1122,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['flags', ACHIEVEMENT_FLAG_COUNTER, '&'], // is a statistic - $this->createLookup() + $this->createLikeLookup() )); $stats = new AchievementList($cnd, ['calcTotal' => true]); @@ -1145,7 +1175,7 @@ class Search private function _searchZone() : ?array // 18 Zones $moduleMask & 0x0040000 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $zones = new ZoneList($cnd, ['calcTotal' => true]); $data = $zones->getListviewData(); @@ -1188,7 +1218,7 @@ class Search private function _searchObject() : ?array // 19 Objects $moduleMask & 0x0080000 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createMatchLookup()]); $objects = new GameObjectList($cnd, ['calcTotal' => true]); $data = $objects->getListviewData(); @@ -1231,7 +1261,7 @@ class Search private function _searchFaction() : ?array // 20 Factions $moduleMask & 0x0100000 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $factions = new FactionList($cnd, ['calcTotal' => true]); $data = $factions->getListviewData(); @@ -1267,7 +1297,7 @@ class Search private function _searchSkill() : ?array // 21 Skills $moduleMask & 0x0200000 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $skills = new SkillList($cnd, ['calcTotal' => true]); $data = $skills->getListviewData(); @@ -1306,7 +1336,7 @@ class Search private function _searchPet() : ?array // 22 Pets $moduleMask & 0x0400000 { - $cnd = array_merge($this->cndBase, [$this->createLookup()]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup()]); $pets = new PetList($cnd, ['calcTotal' => true]); $data = $pets->getListviewData(); @@ -1350,7 +1380,7 @@ class Search { $cnd = array_merge($this->cndBase, array( ['s.typeCat', -8], - $this->createLookup() + $this->createMatchLookup() )); $npcAbilities = new SpellList($cnd, ['calcTotal' => true]); @@ -1411,7 +1441,7 @@ class Search ['s.cuFlags', SPELL_CU_TRIGGERED, '&'], ['s.attributes0', 0x80, '&'] ], - $this->createLookup() + $this->createMatchLookup() )); $misc = new SpellList($cnd, ['calcTotal' => true]); @@ -1463,7 +1493,7 @@ class Search private function _searchEmote() : ?array // 25 Emotes $moduleMask & 0x2000000 { - $cnd = array_merge($this->cndBase, [$this->createLookup(['cmd', 'meToExt_loc'.Lang::getLocale()->value, 'meToNone_loc'.Lang::getLocale()->value, 'extToMe_loc'.Lang::getLocale()->value, 'extToExt_loc'.Lang::getLocale()->value, 'extToNone_loc'.Lang::getLocale()->value])]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup(['cmd', 'meToExt_loc'.Lang::getLocale()->value, 'meToNone_loc'.Lang::getLocale()->value, 'extToMe_loc'.Lang::getLocale()->value, 'extToExt_loc'.Lang::getLocale()->value, 'extToNone_loc'.Lang::getLocale()->value])]); $emote = new EmoteList($cnd, ['calcTotal' => true]); $data = $emote->getListviewData(); @@ -1504,7 +1534,7 @@ class Search private function _searchEnchantment() : ?array // 26 Enchantments $moduleMask & 0x4000000 { - $cnd = array_merge($this->cndBase, [$this->createLookup(['name_loc'.Lang::getLocale()->value])]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup(['name_loc'.Lang::getLocale()->value])]); $enchantment = new EnchantmentList($cnd, ['calcTotal' => true]); $data = $enchantment->getListviewData(); @@ -1551,7 +1581,7 @@ class Search private function _searchSound() : ?array // 27 Sounds $moduleMask & 0x8000000 { - $cnd = array_merge($this->cndBase, [$this->createLookup(['name'])]); + $cnd = array_merge($this->cndBase, [$this->createLikeLookup(['name'])]); $sounds = new SoundList($cnd, ['calcTotal' => true]); $data = $sounds->getListviewData(); diff --git a/includes/dbtypes/creature.class.php b/includes/dbtypes/creature.class.php index f7267887..f6a871b9 100644 --- a/includes/dbtypes/creature.class.php +++ b/includes/dbtypes/creature.class.php @@ -364,14 +364,17 @@ class CreatureListFilter extends Filter // name [str] if ($_v['na']) { - $_ = []; if ($_v['ex'] == 'on') - $_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value, 'subname_loc'.Lang::getLocale()->value]); - else - $_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value]); + if ($_ = $this->tokenizeString(['subname_loc'.Lang::getLocale()->value])) + $parts[] = $_; - if ($_) - $parts[] = $_; + if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value])) + { + if ($parts) + $parts = ['OR', $_, ...$parts]; + else + $parts[] = $_; + } } // pet family [list] diff --git a/includes/dbtypes/gameobject.class.php b/includes/dbtypes/gameobject.class.php index 1fdba3d0..2e8c7198 100644 --- a/includes/dbtypes/gameobject.class.php +++ b/includes/dbtypes/gameobject.class.php @@ -178,7 +178,7 @@ class GameObjectListFilter extends Filter // name if ($_v['na']) - if ($_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value])) + if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value])) $parts[] = $_; return $parts; diff --git a/includes/dbtypes/item.class.php b/includes/dbtypes/item.class.php index f0aa9c01..76854110 100644 --- a/includes/dbtypes/item.class.php +++ b/includes/dbtypes/item.class.php @@ -2098,7 +2098,7 @@ class ItemListFilter extends Filter // name if ($_v['na']) - if ($_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value])) + if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value])) $parts[] = $_; // usable-by (not excluded by requiredClass && armor or weapons match mask from ?_classes) diff --git a/includes/dbtypes/quest.class.php b/includes/dbtypes/quest.class.php index 9008d7e5..1f39c2d1 100644 --- a/includes/dbtypes/quest.class.php +++ b/includes/dbtypes/quest.class.php @@ -506,14 +506,17 @@ class QuestListFilter extends Filter // name if ($_v['na']) { - $_ = []; if ($_v['ex'] == 'on') - $_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value, 'objectives_loc'.Lang::getLocale()->value, 'details_loc'.Lang::getLocale()->value]); - else - $_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value]); + if ($_ = $this->tokenizeString(['objectives_loc'.Lang::getLocale()->value, 'details_loc'.Lang::getLocale()->value])) + $parts[] = $_; - if ($_) - $parts[] = $_; + if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value])) + { + if ($parts) + $parts[0][] = $_; + else + $parts[] = $_; + } } // level min diff --git a/includes/dbtypes/spell.class.php b/includes/dbtypes/spell.class.php index 6ee9b373..7a4de8e4 100644 --- a/includes/dbtypes/spell.class.php +++ b/includes/dbtypes/spell.class.php @@ -2551,14 +2551,17 @@ class SpellListFilter extends Filter //string (extended) if ($_v['na']) { - $_ = []; if ($_v['ex'] == 'on') - $_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value, 'buff_loc'.Lang::getLocale()->value, 'description_loc'.Lang::getLocale()->value]); - else - $_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value]); + if ($_ = $this->tokenizeString(['buff_loc'.Lang::getLocale()->value, 'description_loc'.Lang::getLocale()->value])) + $parts[] = $_; - if ($_) - $parts[] = $_; + if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value])) + { + if ($parts) + $parts[0][] = $_; + else + $parts[] = $_; + } } // spellLevel min todo (low): talentSpells (typeCat -2) commonly have spellLevel 1 (and talentLevel >1) -> query is inaccurate diff --git a/setup/sql/01-db_structure.sql b/setup/sql/01-db_structure.sql index e57e99e0..b9d4fba1 100644 --- a/setup/sql/01-db_structure.sql +++ b/setup/sql/01-db_structure.sql @@ -570,13 +570,28 @@ CREATE TABLE `aowow_creature` ( `ScriptOrAI` varchar(64) DEFAULT NULL, `StringId` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`), - KEY `idx_name` (`name_loc0`), KEY `difficultyEntry1` (`difficultyEntry1`), KEY `difficultyEntry2` (`difficultyEntry2`), KEY `difficultyEntry3` (`difficultyEntry3`), KEY `idx_loot` (`lootId`), KEY `idx_pickpocketloot` (`pickpocketLootId`), - KEY `idx_skinloot` (`skinLootId`) + KEY `idx_skinloot` (`skinLootId`), + KEY `idx_trainer` (`trainerType`), + KEY `idx_trainerrequirement` (`trainerRequirement`), + FULLTEXT `idx_name0` (`name_loc0`), + FULLTEXT `idx_name2` (`name_loc2`), + FULLTEXT `idx_name3` (`name_loc3`), + FULLTEXT `idx_name4` (`name_loc4`), + FULLTEXT `idx_name6` (`name_loc6`), + FULLTEXT `idx_name8` (`name_loc8`), + KEY `idx_spell1` (`spell1`), + KEY `idx_spell2` (`spell2`), + KEY `idx_spell3` (`spell3`), + KEY `idx_spell4` (`spell4`), + KEY `idx_spell5` (`spell5`), + KEY `idx_spell6` (`spell6`), + KEY `idx_spell7` (`spell7`), + KEY `idx_spell8` (`spell8`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1440,13 +1455,28 @@ CREATE TABLE `aowow_items` ( `unsheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT 0, `flagsCustom` int(10) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`id`), - KEY `idx_name` (`name_loc0`), KEY `items_index` (`class`), KEY `idx_model` (`displayId`), KEY `idx_faction` (`requiredFaction`), KEY `iconId` (`iconId`), - KEY `spellId1` (`spellId1`), - KEY `spellId2` (`spellId2`) + KEY `idx_spell1` (`spellId1`), + KEY `idx_spell2` (`spellId2`), + KEY `idx_spell3` (`spellId3`), + KEY `idx_spell4` (`spellId4`), + KEY `idx_spell5` (`spellId5`), + KEY `idx_trigger1` (`spellTrigger1`), + KEY `idx_trigger2` (`spellTrigger2`), + KEY `idx_trigger3` (`spellTrigger3`), + KEY `idx_trigger4` (`spellTrigger4`), + KEY `idx_trigger5` (`spellTrigger5`), + KEY `idx_reqskill` (`requiredSkill`), + FULLTEXT `idx_name0` (`name_loc0`), + FULLTEXT `idx_name2` (`name_loc2`), + FULLTEXT `idx_name3` (`name_loc3`), + FULLTEXT `idx_name4` (`name_loc4`), + FULLTEXT `idx_name6` (`name_loc6`), + FULLTEXT `idx_name8` (`name_loc8`), + KEY `idx_itemset` (`itemset`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1631,7 +1661,16 @@ CREATE TABLE `aowow_objects` ( `ScriptOrAI` varchar(64) DEFAULT NULL, `StringId` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`), - KEY `idx_name` (`name_loc0`) + KEY `idx_onusespell` (`onUseSpell`), + KEY `idx_onsuccessspell` (`onSuccessSpell`), + KEY `idx_auraspell` (`auraSpell`), + KEY `idx_triggeredspell` (`triggeredSpell`), + FULLTEXT `idx_name0` (`name_loc0`), + FULLTEXT `idx_name2` (`name_loc2`), + FULLTEXT `idx_name3` (`name_loc3`), + FULLTEXT `idx_name4` (`name_loc4`), + FULLTEXT `idx_name6` (`name_loc6`), + FULLTEXT `idx_name8` (`name_loc8`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -2134,12 +2173,12 @@ CREATE TABLE `aowow_quests` ( `rewardFactionValue3` mediumint(9) NOT NULL DEFAULT 0, `rewardFactionValue4` mediumint(9) NOT NULL DEFAULT 0, `rewardFactionValue5` mediumint(9) NOT NULL DEFAULT 0, - `name_loc0` text DEFAULT NULL, - `name_loc2` text DEFAULT NULL, - `name_loc3` text DEFAULT NULL, - `name_loc4` text DEFAULT NULL, - `name_loc6` text DEFAULT NULL, - `name_loc8` text DEFAULT NULL, + `name_loc0` varchar(100) DEFAULT NULL, + `name_loc2` varchar(100) DEFAULT NULL, + `name_loc3` varchar(100) DEFAULT NULL, + `name_loc4` varchar(100) DEFAULT NULL, + `name_loc6` varchar(100) DEFAULT NULL, + `name_loc8` varchar(100) DEFAULT NULL, `objectives_loc0` text DEFAULT NULL, `objectives_loc2` text DEFAULT NULL, `objectives_loc3` text DEFAULT NULL, @@ -2229,7 +2268,39 @@ CREATE TABLE `aowow_quests` ( `objectiveText4_loc6` text DEFAULT NULL, `objectiveText4_loc8` text DEFAULT NULL, PRIMARY KEY (`id`), - KEY `nextQuestIdChain` (`nextQuestIdChain`) + KEY `nextQuestIdChain` (`nextQuestIdChain`), + FULLTEXT `idx_name0` (`name_loc0`), + FULLTEXT `idx_name2` (`name_loc2`), + FULLTEXT `idx_name3` (`name_loc3`), + FULLTEXT `idx_name4` (`name_loc4`), + FULLTEXT `idx_name6` (`name_loc6`), + FULLTEXT `idx_name8` (`name_loc8`), + KEY `idx_sourcespell` (`sourceSpellId`), + KEY `idx_rewardspell` (`rewardSpell`), + KEY `idx_rewardcastspell` (`rewardSpellCast`), + KEY `idx_classmask` (`reqRaceMask`), + KEY `idx_racemask` (`reqClassMask`), + KEY `idx_questsort` (`questSortId`), + KEY `idx_rewarditem1` (`rewardChoiceItemId1`), + KEY `idx_rewarditem2` (`rewardChoiceItemId2`), + KEY `idx_rewarditem3` (`rewardChoiceItemId3`), + KEY `idx_rewarditem4` (`rewardChoiceItemId4`), + KEY `idx_rewarditem5` (`rewardChoiceItemId5`), + KEY `idx_rewarditem6` (`rewardChoiceItemId6`), + KEY `idx_rewardfaction1` (`rewardFactionId1`), + KEY `idx_rewardfaction2` (`rewardFactionId2`), + KEY `idx_rewardfaction3` (`rewardFactionId3`), + KEY `idx_rewardfaction4` (`rewardFactionId4`), + KEY `idx_rewardfaction5` (`rewardFactionId5`), + KEY `idx_choiceitem1` (`rewardItemId1`), + KEY `idx_choiceitem2` (`rewardItemId2`), + KEY `idx_choiceitem3` (`rewardItemId3`), + KEY `idx_choiceitem4` (`rewardItemId4`), + KEY `idx_requirement1` (`reqNpcOrGo1`), + KEY `idx_requirement2` (`reqNpcOrGo2`), + KEY `idx_requirement3` (`reqNpcOrGo3`), + KEY `idx_requirement4` (`reqNpcOrGo4`), + KEY `idx_event` (`eventId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -2787,8 +2858,6 @@ CREATE TABLE `aowow_spell` ( PRIMARY KEY (`id`), KEY `category` (`typeCat`), KEY `spell` (`id`) USING BTREE, - KEY `effects` (`effect1Id`,`effect2Id`,`effect3Id`), - KEY `items` (`effect1CreateItemId`,`effect2CreateItemId`,`effect3CreateItemId`), KEY `iconId` (`iconId`), KEY `reagent1` (`reagent1`), KEY `reagent2` (`reagent2`), @@ -2806,7 +2875,22 @@ CREATE TABLE `aowow_spell` ( KEY `effect3Id` (`effect3Id`), KEY `effect1AuraId` (`effect1AuraId`), KEY `effect2AuraId` (`effect2AuraId`), - KEY `effect3AuraId` (`effect3AuraId`) + KEY `effect3AuraId` (`effect3AuraId`), + KEY `idx_skill1` (`skillLine1`), + KEY `idx_skill2` (`skillLine2OrMask`), + FULLTEXT `idx_name0` (`name_loc0`), + FULLTEXT `idx_name2` (`name_loc2`), + FULLTEXT `idx_name3` (`name_loc3`), + FULLTEXT `idx_name4` (`name_loc4`), + FULLTEXT `idx_name6` (`name_loc6`), + FULLTEXT `idx_name8` (`name_loc8`), + KEY `idx_spellfamily` (`spellFamilyId`), + KEY `idx_miscvalue1` (`effect1MiscValue`), + KEY `idx_miscvalue2` (`effect2MiscValue`), + KEY `idx_miscvalue3` (`effect3MiscValue`), + KEY `idx_triggerspell1` (`effect1TriggerSpell`), + KEY `idx_triggerspell2` (`effect2TriggerSpell`), + KEY `idx_triggerspell3` (`effect3TriggerSpell`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/setup/sql/02-db_initial_data.sql b/setup/sql/02-db_initial_data.sql index b679437b..addd6536 100644 --- a/setup/sql/02-db_initial_data.sql +++ b/setup/sql/02-db_initial_data.sql @@ -71,7 +71,7 @@ UNLOCK TABLES; LOCK TABLES `aowow_dbversion` WRITE; /*!40000 ALTER TABLE `aowow_dbversion` DISABLE KEYS */; -INSERT INTO `aowow_dbversion` VALUES (1768517244,0,NULL,NULL); +INSERT INTO `aowow_dbversion` VALUES (1768556689,0,NULL,NULL); /*!40000 ALTER TABLE `aowow_dbversion` ENABLE KEYS */; UNLOCK TABLES; diff --git a/setup/sql/updates/1768556688_01.sql b/setup/sql/updates/1768556688_01.sql new file mode 100644 index 00000000..b1e65dfb --- /dev/null +++ b/setup/sql/updates/1768556688_01.sql @@ -0,0 +1,120 @@ +ALTER TABLE `aowow_spell` + DROP INDEX `items`, + DROP INDEX `effects`, + ADD INDEX `idx_skill1` (`skillLine1`), + ADD INDEX `idx_skill2` (`skillLine2OrMask`), + ADD FULLTEXT `idx_name0` (`name_loc0`), + ADD FULLTEXT `idx_name2` (`name_loc2`), + ADD FULLTEXT `idx_name3` (`name_loc3`), + ADD FULLTEXT `idx_name4` (`name_loc4`), + ADD FULLTEXT `idx_name6` (`name_loc6`), + ADD FULLTEXT `idx_name8` (`name_loc8`), + ADD INDEX `idx_spellfamily` (`spellFamilyId`), + ADD INDEX `idx_miscvalue1` (`effect1MiscValue`), + ADD INDEX `idx_miscvalue2` (`effect2MiscValue`), + ADD INDEX `idx_miscvalue3` (`effect3MiscValue`), + ADD INDEX `idx_triggerspell1` (`effect1TriggerSpell`), + ADD INDEX `idx_triggerspell2` (`effect2TriggerSpell`), + ADD INDEX `idx_triggerspell3` (`effect3TriggerSpell`) +; + +ALTER TABLE `aowow_quests` + MODIFY COLUMN `name_loc0` varchar(100) DEFAULT NULL, + MODIFY COLUMN `name_loc2` varchar(100) DEFAULT NULL, + MODIFY COLUMN `name_loc3` varchar(100) DEFAULT NULL, + MODIFY COLUMN `name_loc4` varchar(100) DEFAULT NULL, + MODIFY COLUMN `name_loc6` varchar(100) DEFAULT NULL, + MODIFY COLUMN `name_loc8` varchar(100) DEFAULT NULL, + ADD FULLTEXT `idx_name0` (`name_loc0`), + ADD FULLTEXT `idx_name2` (`name_loc2`), + ADD FULLTEXT `idx_name3` (`name_loc3`), + ADD FULLTEXT `idx_name4` (`name_loc4`), + ADD FULLTEXT `idx_name6` (`name_loc6`), + ADD FULLTEXT `idx_name8` (`name_loc8`), + ADD INDEX `idx_sourcespell` (`sourceSpellId`), + ADD INDEX `idx_rewardspell` (`rewardSpell`), + ADD INDEX `idx_rewardcastspell` (`rewardSpellCast`), + ADD INDEX `idx_classmask` (`reqRaceMask`), + ADD INDEX `idx_racemask` (`reqClassMask`), + ADD INDEX `idx_questsort` (`questSortId`), + ADD INDEX `idx_rewarditem1` (`rewardChoiceItemId1`), + ADD INDEX `idx_rewarditem2` (`rewardChoiceItemId2`), + ADD INDEX `idx_rewarditem3` (`rewardChoiceItemId3`), + ADD INDEX `idx_rewarditem4` (`rewardChoiceItemId4`), + ADD INDEX `idx_rewarditem5` (`rewardChoiceItemId5`), + ADD INDEX `idx_rewarditem6` (`rewardChoiceItemId6`), + ADD INDEX `idx_rewardfaction1` (`rewardFactionId1`), + ADD INDEX `idx_rewardfaction2` (`rewardFactionId2`), + ADD INDEX `idx_rewardfaction3` (`rewardFactionId3`), + ADD INDEX `idx_rewardfaction4` (`rewardFactionId4`), + ADD INDEX `idx_rewardfaction5` (`rewardFactionId5`), + ADD INDEX `idx_choiceitem1` (`rewardItemId1`), + ADD INDEX `idx_choiceitem2` (`rewardItemId2`), + ADD INDEX `idx_choiceitem3` (`rewardItemId3`), + ADD INDEX `idx_choiceitem4` (`rewardItemId4`), + ADD INDEX `idx_requirement1` (`reqNpcOrGo1`), + ADD INDEX `idx_requirement2` (`reqNpcOrGo2`), + ADD INDEX `idx_requirement3` (`reqNpcOrGo3`), + ADD INDEX `idx_requirement4` (`reqNpcOrGo4`), + ADD INDEX `idx_event` (`eventId`) +; + +ALTER TABLE `aowow_creature` + DROP INDEX `idx_name`, + ADD INDEX `idx_trainer` (`trainerType`), + ADD INDEX `idx_trainerrequirement` (`trainerRequirement`), + ADD FULLTEXT `idx_name0` (`name_loc0`), + ADD FULLTEXT `idx_name2` (`name_loc2`), + ADD FULLTEXT `idx_name3` (`name_loc3`), + ADD FULLTEXT `idx_name4` (`name_loc4`), + ADD FULLTEXT `idx_name6` (`name_loc6`), + ADD FULLTEXT `idx_name8` (`name_loc8`), + ADD INDEX `idx_spell1` (`spell1`), + ADD INDEX `idx_spell2` (`spell2`), + ADD INDEX `idx_spell3` (`spell3`), + ADD INDEX `idx_spell4` (`spell4`), + ADD INDEX `idx_spell5` (`spell5`), + ADD INDEX `idx_spell6` (`spell6`), + ADD INDEX `idx_spell7` (`spell7`), + ADD INDEX `idx_spell8` (`spell8`) +; + +ALTER TABLE `aowow_items` + DROP INDEX `spellId1`, + DROP INDEX `spellId2`, + DROP INDEX `idx_name`, + ADD INDEX `idx_spell1` (`spellId1`), + ADD INDEX `idx_spell2` (`spellId2`), + ADD INDEX `idx_spell3` (`spellId3`), + ADD INDEX `idx_spell4` (`spellId4`), + ADD INDEX `idx_spell5` (`spellId5`), + ADD INDEX `idx_trigger1` (`spellTrigger1`), + ADD INDEX `idx_trigger2` (`spellTrigger2`), + ADD INDEX `idx_trigger3` (`spellTrigger3`), + ADD INDEX `idx_trigger4` (`spellTrigger4`), + ADD INDEX `idx_trigger5` (`spellTrigger5`), + ADD INDEX `idx_reqskill` (`requiredSkill`), + ADD FULLTEXT `idx_name0` (`name_loc0`), + ADD FULLTEXT `idx_name2` (`name_loc2`), + ADD FULLTEXT `idx_name3` (`name_loc3`), + ADD FULLTEXT `idx_name4` (`name_loc4`), + ADD FULLTEXT `idx_name6` (`name_loc6`), + ADD FULLTEXT `idx_name8` (`name_loc8`), + ADD INDEX `idx_itemset` (`itemset`) +; + +ALTER TABLE `aowow_objects` + DROP INDEX `idx_name`, + ADD INDEX `idx_onusespell` (`onUseSpell`), + ADD INDEX `idx_onsuccessspell` (`onSuccessSpell`), + ADD INDEX `idx_auraspell` (`auraSpell`), + ADD INDEX `idx_triggeredspell` (`triggeredSpell`), + ADD FULLTEXT `idx_name0` (`name_loc0`), + ADD FULLTEXT `idx_name2` (`name_loc2`), + ADD FULLTEXT `idx_name3` (`name_loc3`), + ADD FULLTEXT `idx_name4` (`name_loc4`), + ADD FULLTEXT `idx_name6` (`name_loc6`), + ADD FULLTEXT `idx_name8` (`name_loc8`) +; + +UPDATE `aowow_dbversion` SET `sql` = CONCAT(IFNULL(`sql`, ''), ' achievementcriteria'); diff --git a/setup/tools/dbc.class.php b/setup/tools/dbc.class.php index fd72555b..db687f68 100644 --- a/setup/tools/dbc.class.php +++ b/setup/tools/dbc.class.php @@ -60,10 +60,12 @@ class DBC 'S' => 'V', // S - string block index, 4 bytes - localized; autofill 'f' => 'f', // f - float, 4 bytes (rounded to 4 digits after comma) 'i' => 'l', // i - signed int, 4 bytes + 'I' => 'l', // I - signed int, 4 bytes, sql index 'u' => 'V', // u - unsigned int, 4 bytes + 'U' => 'V', // U - unsigned int, 4 bytes, sql index 'b' => 'C', // b - unsigned char, 1 byte 'd' => 'x4', // d - ordered by this field, not included in array - 'n' => 'V' // n - int, 4 bytes, ordered by this field + 'n' => 'V' // n - unsigned int, 4 bytes, sql primary key ); public const DEFAULT_WOW_BUILD = '12340'; @@ -284,8 +286,9 @@ class DBC if ($this->error) return; - $pKey = ''; - $query = 'CREATE '.($this->tempTable ? 'TEMPORARY' : '').' TABLE `'.$this->tableName.'` ('; + $pKey = ''; + $query = 'CREATE '.($this->tempTable ? 'TEMPORARY' : '').' TABLE `'.$this->tableName.'` ('; + $indizes = []; if ($this->isGameTable) { @@ -312,10 +315,14 @@ class DBC case 'b': $query .= '`'.$name.'` TINYINT UNSIGNED NOT NULL, '; break; + case 'I': + $indizes[] = $name; case 'i': case 'n': $query .= '`'.$name.'` INT SIGNED NOT NULL, '; break; + case 'U': + $indizes[] = $name; case 'u': $query .= '`'.$name.'` INT UNSIGNED NOT NULL, '; break; @@ -327,6 +334,9 @@ class DBC $pKey = $name; } + foreach ($indizes as $i) + $query .= 'KEY `idx_'.$i.'` (`'.$i.'`), '; + if ($pKey) $query .= 'PRIMARY KEY (`'.$pKey.'`) '; else diff --git a/setup/tools/dbc/12340.ini b/setup/tools/dbc/12340.ini index 0d59bbda..f2b66696 100644 --- a/setup/tools/dbc/12340.ini +++ b/setup/tools/dbc/12340.ini @@ -39,8 +39,8 @@ UNUSED3 = x [achievement_criteria] id = n refAchievementId = i -type = i -value1 = i +type = I +value1 = I value2 = i value3 = i value4 = i