diff --git a/lib/ddl/sql_generator.php b/lib/ddl/sql_generator.php index 0555bf36988..dc6e1b7e40a 100644 --- a/lib/ddl/sql_generator.php +++ b/lib/ddl/sql_generator.php @@ -1086,40 +1086,19 @@ abstract class sql_generator { $name .= substr(trim($field),0,3); } // Prepend the prefix - $name = $this->prefix . $name; + $name = trim($this->prefix . $name); - $name = substr(trim($name), 0, $this->names_max_length - 1 - strlen($suffix)); //Max names_max_length - - // Add the suffix - $namewithsuffix = $name; - if ($suffix) { - $namewithsuffix = $namewithsuffix . '_' . $suffix; - } + // Make sure name does not exceed the maximum name length and add suffix. + $maxlengthwithoutsuffix = $this->names_max_length - strlen($suffix) - ($suffix ? 1 : 0); + $namewithsuffix = substr($name, 0, $maxlengthwithoutsuffix) . ($suffix ? ('_' . $suffix) : ''); // If the calculated name is in the cache, or if we detect it by introspecting the DB let's modify if - if (in_array($namewithsuffix, $used_names) || $this->isNameInUse($namewithsuffix, $suffix, $tablename)) { - $counter = 2; - // If have free space, we add 2 - if (strlen($namewithsuffix) < $this->names_max_length) { - $newname = $name . $counter; - // Else replace the last char by 2 - } else { - $newname = substr($name, 0, strlen($name)-1) . $counter; - } - $newnamewithsuffix = $newname; - if ($suffix) { - $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix; - } + $counter = 1; + while (in_array($namewithsuffix, $used_names) || $this->isNameInUse($namewithsuffix, $suffix, $tablename)) { // Now iterate until not used name is found, incrementing the counter - while (in_array($newnamewithsuffix, $used_names) || $this->isNameInUse($newnamewithsuffix, $suffix, $tablename)) { - $counter++; - $newname = substr($name, 0, strlen($newname)-1) . $counter; - $newnamewithsuffix = $newname; - if ($suffix) { - $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix; - } - } - $namewithsuffix = $newnamewithsuffix; + $counter++; + $namewithsuffix = substr($name, 0, $maxlengthwithoutsuffix - strlen($counter)) . + $counter . ($suffix ? ('_' . $suffix) : ''); } // Add the name to the cache diff --git a/lib/ddl/tests/ddl_test.php b/lib/ddl/tests/ddl_test.php index c712880fa2d..7644a2319a1 100644 --- a/lib/ddl/tests/ddl_test.php +++ b/lib/ddl/tests/ddl_test.php @@ -1889,6 +1889,59 @@ class core_ddl_testcase extends database_driver_testcase { } } + public function test_object_name() { + $gen = $this->tdb->get_manager()->generator; + + // This will form short object name and max length should not be exceeded. + $table = 'tablename'; + $fields = 'id'; + $suffix = 'pk'; + for ($i=0; $i<12; $i++) { + $this->assertLessThanOrEqual($gen->names_max_length, + strlen($gen->getNameForObject($table, $fields, $suffix)), + 'Generated object name is too long. $i = '.$i); + } + + // This will form too long object name always and it must be trimmed to exactly 30 chars. + $table = 'aaaa_bbbb_cccc_dddd_eeee_ffff_gggg'; + $fields = 'aaaaa,bbbbb,ccccc,ddddd'; + $suffix = 'idx'; + for ($i=0; $i<12; $i++) { + $this->assertEquals($gen->names_max_length, + strlen($gen->getNameForObject($table, $fields, $suffix)), + 'Generated object name is too long. $i = '.$i); + } + + // Same test without suffix. + $table = 'bbbb_cccc_dddd_eeee_ffff_gggg_hhhh'; + $fields = 'aaaaa,bbbbb,ccccc,ddddd'; + $suffix = ''; + for ($i=0; $i<12; $i++) { + $this->assertEquals($gen->names_max_length, + strlen($gen->getNameForObject($table, $fields, $suffix)), + 'Generated object name is too long. $i = '.$i); + } + + // This must only trim name when counter is 10 or more. + $table = 'cccc_dddd_eeee_ffff_gggg_hhhh_iiii'; + $fields = 'id'; + $suffix = 'idx'; + // Since we don't know how long prefix is, loop to generate tablename that gives exactly maxlengh-1 length. + // Skip this test if prefix is too long. + while (strlen($table) && strlen($gen->prefix.preg_replace('/_/','',$table).'_id_'.$suffix) >= $gen->names_max_length) { + $table = rtrim(substr($table, 0, strlen($table) - 1), '_'); + } + if (strlen($table)) { + $this->assertEquals($gen->names_max_length - 1, + strlen($gen->getNameForObject($table, $fields, $suffix))); + for ($i=0; $i<12; $i++) { + $this->assertEquals($gen->names_max_length, + strlen($gen->getNameForObject($table, $fields, $suffix)), + 'Generated object name is too long. $i = '.$i); + } + } + } + // Following methods are not supported == Do not test. /* public function testRenameIndex() {