[TASK] dbal: skip update suggestions for equivalent fields in Install Tool 55/40455/8
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Thu, 18 Jun 2015 19:55:00 +0000 (21:55 +0200)
committerAndreas Fernandez <typo3@scripting-base.de>
Mon, 20 Jul 2015 16:55:54 +0000 (18:55 +0200)
Make the Install Tool / Database Upgrade Wizard ignore database
alterations for functionally equivalent field types / indexes when
used with DBAL. This is required as some special MySQL native fields
like TINYTEXT, TINY- and MEDIUMINT have no matching types and will
get converted by ADOdb to a type that is able to store longer/bigger
values.

This patch makes the SqlSchemaMigrationService check with the DBAL
Driver which field type/index definition will be used and updates
the field type requested by the database compare to reflect the actual
field type for the DBMS.

Resolves: #67301
Releases: master
Change-Id: I7f28ab38b66a224344069c42744e75bf63e222e6
Reviewed-on: http://review.typo3.org/40455
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
typo3/sysext/dbal/Classes/Database/DatabaseConnection.php
typo3/sysext/dbal/Tests/Unit/Database/DatabaseConnectionPostgresqlTest.php
typo3/sysext/dbal/Tests/Unit/Database/DatabaseConnectionTest.php
typo3/sysext/install/Classes/Service/SqlSchemaMigrationService.php
typo3/sysext/install/Tests/Unit/Service/SqlSchemaMigrationServiceTest.php

index 2b4eae7..a51661c 100644 (file)
@@ -2041,6 +2041,73 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                return $this->dbmsSpecifics->getNativeFieldType($meta);
        }
 
+       /*********************************************
+        *
+        * SqlSchemaMigrationService helper functions
+        *
+        *********************************************/
+       /**
+        * Remove the index prefix length information from columns in an index definition.
+        * Partial indexes based on a prefix are not supported by all databases.
+        *
+        * @param string $indexSQL
+        * @return string
+        */
+       public function getEquivalentIndexDefinition($indexSQL) {
+               if ($this->dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::PARTIAL_STRING_INDEX) && (bool)$this->dbmsSpecifics->getSpecific(Specifics\AbstractSpecifics::PARTIAL_STRING_INDEX)) {
+                       return $indexSQL;
+               }
+
+               $strippedIndexSQL = preg_replace_callback(
+                       '/\A([^(]+)\((.*)\)\Z/',
+                       function($matches) {
+                               return $matches[1] . '(' . preg_replace('/\((\d+)\)/', '', $matches[2]) . ')';
+                       },
+                       $indexSQL
+               );
+
+               return $strippedIndexSQL === NULL ? $indexSQL : $strippedIndexSQL;
+       }
+
+       /**
+        * Convert the native MySQL Field type to the closest matching equivalent field type supported by the DBMS.
+        * INTEGER and TINYTEXT colums need to be further processed due to MySQL limitations / non-standard features.
+        *
+        * @param string $fieldSQL
+        * @return string
+        */
+       public function getEquivalentFieldDefinition($fieldSQL) {
+               if (!preg_match('/^([a-z0-9]+)(\(([^\)]+)\))?(.*)/', $fieldSQL, $components)) {
+                       return $fieldSQL;
+               }
+
+               $metaType = $this->dbmsSpecifics->getMetaFieldType($components[1]);
+               $replacementType = $this->dbmsSpecifics->getNativeFieldType($metaType);
+               $replacementLength = $components[2];
+               $replacementExtra = '';
+
+               // MySQL INT types support a display length that has no effect on the
+               // actual range of values that can be stored, normalize to the default
+               // display length returned by DBAL.
+               if (substr($metaType, 0, 1) === 'I') {
+                       $replacementLength = $this->dbmsSpecifics->getNativeFieldLength($replacementType, $components[3]);
+               }
+
+               // MySQL TINYTEXT is equivalent to VARCHAR(255) DEFAULT NULL. MySQL TEXT
+               // columns can not have a default value in contrast to VARCHAR, so the
+               // `default NULL` gets appended to avoid false-positive schema changes.
+               if ($components[1] === 'tinytext') {
+                       $replacementLength = '(255)';
+                       if (FALSE !== stripos($components[0], ' NOT NULL')) {
+                               $replacementExtra = ' default \'\'';
+                       } else {
+                               $replacementExtra = ' default NULL';
+                       }
+               }
+
+               return str_replace($components[1] . $components[2], strtolower($replacementType) . $replacementLength, $components[0]) . $replacementExtra;
+       }
+
        /**************************************
         *
         * SQL wrapper functions (Overriding parent methods)
index a4c905d..046eaf6 100644 (file)
@@ -221,4 +221,31 @@ class DatabaseConnectionPostgresqlTest extends AbstractTestCase {
                $expected = 'SELECT COUNT("title"), COUNT("pid") FROM "pages" GROUP BY "title" ORDER BY "title"';
                $this->assertEquals($expected, $this->cleanSql($result));
        }
+
+       /**
+        * @test
+        * @param string $fieldSQL
+        * @param string $expected
+        * @dataProvider equivalentFieldTypeDataProvider
+        * @see http://forge.typo3.org/issues/67301
+        */
+       public function suggestEquivalentFieldDefinitions($fieldSQL, $expected) {
+               $actual= $this->subject->getEquivalentFieldDefinition($fieldSQL);
+               $this->assertSame($expected, $actual);
+       }
+
+       /**
+        * @return array
+        */
+       public function equivalentFieldTypeDataProvider() {
+               return array(
+                       array('int(11) NOT NULL default \'0\'', 'int(11) NOT NULL default \'0\''),
+                       array('int(10) NOT NULL', 'int(11) NOT NULL'),
+                       array('tinyint(3)', 'smallint(6)'),
+                       array('bigint(20) NOT NULL', 'bigint(20) NOT NULL'),
+                       array('tinytext NOT NULL', 'varchar(255) NOT NULL default \'\''),
+                       array('tinytext', 'varchar(255) default NULL'),
+                       array('mediumtext', 'longtext')
+               );
+       }
 }
index c34b4fb..fb7e9a1 100644 (file)
@@ -284,4 +284,28 @@ class DatabaseConnectionTest extends AbstractTestCase {
                $this->assertEquals($expectedParameterValues, $parameters);
        }
 
+       ///////////////////////////////////////
+       // Tests concerning indexes
+       ///////////////////////////////////////
+       /**
+        * @test
+        * @param string $indexSQL
+        * @param string $expected
+        * @dataProvider equivalentIndexDefinitionDataProvider
+        */
+       public function equivalentIndexDefinitionRemovesLengthInformation($indexSQL, $expected) {
+               $result = $this->subject->getEquivalentIndexDefinition($indexSQL);
+               $this->assertSame($expected, $result);
+       }
+
+       /**
+        * @return array
+        */
+       public function equivalentIndexDefinitionDataProvider() {
+               return array(
+                       array('KEY (foo,bar(199))', 'KEY (foo,bar)'),
+                       array('KEY (foo(199), bar)', 'KEY (foo, bar)'),
+                       array('KEY (foo(199),bar(199))', 'KEY (foo,bar)'),
+               );
+       }
 }
index 3879708..035a1b5 100644 (file)
@@ -93,7 +93,7 @@ class SqlSchemaMigrationService {
                                                        // Note: Keywords "DEFAULT CHARSET" and "CHARSET" are the same, so "DEFAULT" can just be ignored
                                                        $charset = $tcharset[2];
                                                } else {
-                                                       $charset = $GLOBALS['TYPO3_DB']->default_charset;
+                                                       $charset = $this->getDatabaseConnection()->default_charset;
                                                }
                                                $total[$table]['extra']['COLLATE'] = $this->getCollationForCharset($charset);
                                        }
@@ -153,8 +153,9 @@ class SqlSchemaMigrationService {
        public function getCollationForCharset($charset) {
                // Load character sets, if not cached already
                if (empty($this->character_sets)) {
-                       if (method_exists($GLOBALS['TYPO3_DB'], 'admin_get_charsets')) {
-                               $this->character_sets = $GLOBALS['TYPO3_DB']->admin_get_charsets();
+                       $databaseConnection = $this->getDatabaseConnection();
+                       if (method_exists($databaseConnection, 'admin_get_charsets')) {
+                               $this->character_sets = $databaseConnection->admin_get_charsets();
                        } else {
                                // Add empty element to avoid that the check will be repeated
                                $this->character_sets[$charset] = array();
@@ -176,17 +177,18 @@ class SqlSchemaMigrationService {
                $total = array();
                $tempKeys = array();
                $tempKeysPrefix = array();
-               $GLOBALS['TYPO3_DB']->connectDB();
-               echo $GLOBALS['TYPO3_DB']->sql_error();
-               $tables = $GLOBALS['TYPO3_DB']->admin_get_tables();
+               $databaseConnection = $this->getDatabaseConnection();
+               $databaseConnection->connectDB();
+               echo $databaseConnection->sql_error();
+               $tables = $databaseConnection->admin_get_tables();
                foreach ($tables as $tableName => $tableStatus) {
                        // Fields
-                       $fieldInformation = $GLOBALS['TYPO3_DB']->admin_get_fields($tableName);
+                       $fieldInformation = $databaseConnection->admin_get_fields($tableName);
                        foreach ($fieldInformation as $fN => $fieldRow) {
                                $total[$tableName]['fields'][$fN] = $this->assembleFieldDefinition($fieldRow);
                        }
                        // Keys
-                       $keyInformation = $GLOBALS['TYPO3_DB']->admin_get_keys($tableName);
+                       $keyInformation = $databaseConnection->admin_get_keys($tableName);
                        foreach ($keyInformation as $keyRow) {
                                $keyName = $keyRow['Key_name'];
                                $colName = $keyRow['Column_name'];
@@ -284,10 +286,24 @@ class SqlSchemaMigrationService {
                                                                                        $fieldC
                                                                                );
 
-                                                                               // Ignore nonstandard MySQL numeric field attributes UNSIGNED and ZEROFILL
-                                                                               if ($this->isDbalEnabled() && preg_match('/^(TINYINT|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT|REAL|DOUBLE|FLOAT|DECIMAL|NUMERIC)\([^\)]+\)\s+(UNSIGNED|ZEROFILL)/i', $fieldC)) {
-                                                                                       $fieldC = str_ireplace(array(' UNSIGNED', ' ZEROFILL'), '', $fieldC);
-                                                                                       $FDcomp[$table][$theKey][$fieldN] = str_ireplace(array(' UNSIGNED', ' ZEROFILL'), '', $FDcomp[$table][$theKey][$fieldN]);
+                                                                               if ($this->isDbalEnabled()) {
+                                                                                       // Ignore nonstandard MySQL numeric field attributes UNSIGNED and ZEROFILL
+                                                                                       if (preg_match('/^(TINYINT|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT|REAL|DOUBLE|FLOAT|DECIMAL|NUMERIC)\([^\)]+\)\s+(UNSIGNED|ZEROFILL)/i', $fieldC)) {
+                                                                                               $fieldC = str_ireplace(array(' UNSIGNED', ' ZEROFILL'), '', $fieldC);
+                                                                                               $FDcomp[$table][$theKey][$fieldN] = str_ireplace(array(' UNSIGNED', ' ZEROFILL'), '', $FDcomp[$table][$theKey][$fieldN]);
+                                                                                       }
+
+                                                                                       // Replace field and index definitions with functionally equivalent statements
+                                                                                       if ($fieldC !== $FDcomp[$table][$theKey][$fieldN]) {
+                                                                                               switch($theKey) {
+                                                                                                       case 'fields':
+                                                                                                               $fieldC = $this->getDatabaseConnection()->getEquivalentFieldDefinition($fieldC);
+                                                                                                               break;
+                                                                                                       case 'keys':
+                                                                                                               $fieldC = $this->getDatabaseConnection()->getEquivalentIndexDefinition($fieldC);
+                                                                                                               break;
+                                                                                               }
+                                                                                       }
                                                                                }
                                                                                if ($ignoreNotNullWhenComparing) {
                                                                                        $fieldC = str_replace(' NOT NULL', '', $fieldC);
@@ -446,7 +462,7 @@ class SqlSchemaMigrationService {
                                                                $statements['drop_table'][md5($statement)] = $statement;
                                                        }
                                                        // Count
-                                                       $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $table);
+                                                       $count = $this->getDatabaseConnection()->exec_SELECTcountRows('*', $table);
                                                        $statements['tables_count'][md5($statement)] = $count ? 'Records in table: ' . $count : '';
                                                } else {
                                                        $statement = 'CREATE TABLE ' . $table . ' (
@@ -610,13 +626,14 @@ class SqlSchemaMigrationService {
        public function performUpdateQueries($arr, $keyArr) {
                $result = array();
                if (is_array($arr)) {
+                       $databaseConnection = $this->getDatabaseConnection();
                        foreach ($arr as $key => $string) {
                                if (isset($keyArr[$key]) && $keyArr[$key]) {
-                                       $res = $GLOBALS['TYPO3_DB']->admin_query($string);
+                                       $res = $databaseConnection->admin_query($string);
                                        if ($res === FALSE) {
-                                               $result[$key] = $GLOBALS['TYPO3_DB']->sql_error();
+                                               $result[$key] = $databaseConnection->sql_error();
                                        } elseif (is_resource($res) || is_a($res, '\\mysqli_result')) {
-                                               $GLOBALS['TYPO3_DB']->sql_free_result($res);
+                                               $databaseConnection->sql_free_result($res);
                                        }
                                }
                        }
@@ -635,7 +652,7 @@ class SqlSchemaMigrationService {
         * @see \TYPO3\CMS\Core\Database\DatabaseConnection::admin_get_tables()
         */
        public function getListOfTables() {
-               $whichTables = $GLOBALS['TYPO3_DB']->admin_get_tables(TYPO3_db);
+               $whichTables = $this->getDatabaseConnection()->admin_get_tables(TYPO3_db);
                foreach ($whichTables as $key => &$value) {
                        $value = $key;
                }
@@ -652,4 +669,11 @@ class SqlSchemaMigrationService {
                return \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('dbal');
        }
 
+       /**
+        * @return \TYPO3\CMS\Core\Database\DatabaseConnection|\TYPO3\CMS\Dbal\Database\DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+
 }
index 5485925..e79e3b8 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Install\Tests\Unit\Service;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Service\SqlSchemaMigrationService;
 
 /**
@@ -22,10 +23,40 @@ use TYPO3\CMS\Install\Service\SqlSchemaMigrationService;
 class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
 
        /**
+        * Get a SchemaService instance with mocked DBAL enable database connection, DBAL not enabled
+        *
+        * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
+        */
+       protected function getSqlSchemaMigrationService() {
+               /** @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $databaseConnection */
+               $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled'), array(), '', FALSE);
+               $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(FALSE));
+
+               return $subject;
+       }
+
+       /**
+        * Get a SchemaService instance with mocked DBAL enable database connection, DBAL enabled
+        *
+        * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
+        */
+       protected function getDbalEnabledSqlSchemaMigrationService() {
+               /** @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $databaseConnection */
+               $databaseConnection = $this->getAccessibleMock(\TYPO3\CMS\Dbal\Database\DatabaseConnection::class, array('dummy'), array(), '', FALSE);
+               $databaseConnection->_set('dbmsSpecifics', GeneralUtility::makeInstance(\TYPO3\CMS\Dbal\Database\Specifics\PostgresSpecifics::class));
+
+               $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled', 'getDatabaseConnection'), array(), '', FALSE);
+               $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(TRUE));
+               $subject->expects($this->any())->method('getDatabaseConnection')->will($this->returnValue($databaseConnection));
+
+               return $subject;
+       }
+
+       /**
         * @test
         */
        public function getFieldDefinitionsFileContentHandlesMultipleWhitespacesInFieldDefinitions() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                // Multiple whitespaces and tabs in field definition
                $inputString = 'CREATE table atable (' . LF . 'aFieldName   int(11)' . TAB . TAB . TAB . 'unsigned   DEFAULT \'0\'' . LF . ');';
                $result = $subject->getFieldDefinitions_fileContent($inputString);
@@ -49,7 +80,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraFindsChangedFields() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -93,7 +124,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraFindsChangedFieldsIncludingNull() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -137,7 +168,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraFindsChangedFieldsIgnoreNotNull() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -183,7 +214,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraIgnoresCaseDifference() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -216,7 +247,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraIgnoresCaseDifferenceButKeepsCaseInSetIntact() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -248,7 +279,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraDoesNotLowercaseReservedWordsForTheComparison() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -280,7 +311,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraFindsNewSpatialKeys() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -316,7 +347,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function checkColumnDefinitionIfCommentIsSupplied() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $fieldDefinition = $subject->assembleFieldDefinition(
                        array(
                                'Field' => 'uid',
@@ -340,7 +371,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function checkColumnDefinitionIfNoCommentIsSupplied() {
-               $subject = new SqlSchemaMigrationService();
+               $subject = $this->getSqlSchemaMigrationService();
                $fieldDefinition = $subject->assembleFieldDefinition(
                        array(
                                'Field' => 'uid',
@@ -363,8 +394,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraIncludesEngineIfMySQLIsUsed() {
-               $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled'), array(), '', FALSE);
-               $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(FALSE));
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -402,8 +432,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraExcludesEngineIfDbalIsUsed() {
-               $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled'), array(), '', FALSE);
-               $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(TRUE));
+               $subject = $this->getDbalEnabledSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -439,8 +468,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraIncludesUnsignedAttributeIfMySQLIsUsed() {
-               $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled'), array(), '', FALSE);
-               $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(FALSE));
+               $subject = $this->getSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -490,8 +518,7 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function getDatabaseExtraExcludesUnsignedAttributeIfDbalIsUsed() {
-               $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled'), array(), '', FALSE);
-               $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(TRUE));
+               $subject = $this->getDbalEnabledSqlSchemaMigrationService();
                $differenceArray = $subject->getDatabaseExtra(
                        array(
                                'tx_foo' => array(
@@ -524,4 +551,80 @@ class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                        )
                );
        }
+
+       /**
+        * @test
+        */
+       public function getDatabaseExtraIgnoresIndexPrefixLengthIfDbalIsUsed() {
+               $subject = $this->getDbalEnabledSqlSchemaMigrationService();
+               $differenceArray = $subject->getDatabaseExtra(
+                       array(
+                               'tx_foo' => array(
+                                       'keys' => array(
+                                               'foo' => 'KEY foo (foo(199))'
+                                       )
+                               )
+                       ),
+                       array(
+                               'tx_foo' => array(
+                                       'keys' => array(
+                                               'foo' => 'KEY foo (foo)'
+                                       )
+                               )
+                       )
+               );
+
+               $this->assertSame(
+                       $differenceArray,
+                       array(
+                               'extra' => array(),
+                               'diff' => array(),
+                               'diff_currentValues' => NULL,
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function getDatabaseExtraComparesIndexPrefixLengthIfMySQLIsUsed() {
+               $subject = $this->getSqlSchemaMigrationService();
+               $differenceArray = $subject->getDatabaseExtra(
+                       array(
+                               'tx_foo' => array(
+                                       'keys' => array(
+                                               'foo' => 'KEY foo (foo(199))'
+                                       )
+                               )
+                       ),
+                       array(
+                               'tx_foo' => array(
+                                       'keys' => array(
+                                               'foo' => 'KEY foo (foo)'
+                                       )
+                               )
+                       )
+               );
+
+               $this->assertSame(
+                       $differenceArray,
+                       array(
+                               'extra' => array(),
+                               'diff' => array(
+                                       'tx_foo' => array(
+                                               'keys' => array(
+                                                       'foo' => 'KEY foo (foo(199))'
+                                               )
+                                       )
+                               ),
+                               'diff_currentValues' => array(
+                                       'tx_foo' => array(
+                                               'keys' => array(
+                                                       'foo' => 'KEY foo (foo)'
+                                               )
+                                       )
+                               )
+                       )
+               );
+       }
 }