From 32cb648073f28184679fb656ed7acfae3b3351ef Mon Sep 17 00:00:00 2001 From: Thomas Hohn <thomas@hohn.dk> Date: Fri, 24 Feb 2017 08:26:56 +0100 Subject: [PATCH] [BUGFIX] DB Check causes PHP warnings and errors In DatabaseIntegrityCheck the method selectNonEmptyRecordsWithFkeys also needs to take the BLOB into account or else it will fail with a PHP warning. Furthermore the returned tableColumns list may contain quoted fields names if the field name can be interpreted as a keyword for the used connection platform. This patch ensures the correct column information is received before further processing is started. Additionally the "Record Statics" module is fixed by checking for an empty TCA table field which invokes an exception. Resolves: #79347 Resolves: #79991 Resolves: #79992 Releases: master Change-Id: Ie455abd2da90d7dabc773ec345b5c8a87b0b5836 Reviewed-on: https://review.typo3.org/51813 Reviewed-by: Christer V <cvi@systime.dk> Tested-by: Christer V <cvi@systime.dk> Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Claus Due <claus@phpmind.net> Reviewed-by: Nicole Cordes <typo3@cordes.co> Tested-by: Nicole Cordes <typo3@cordes.co> Reviewed-by: Markus Klein <markus.klein@typo3.org> Reviewed-by: Anders Kostending <aha@systime.dk> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> --- .../Query/Expression/ExpressionBuilder.php | 12 +++++++++ .../Integrity/DatabaseIntegrityCheck.php | 26 ++++++++++++++++--- .../Expression/ExpressionBuilderTest.php | 17 ++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php b/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php index ad5cf5bdb840..692dd25b795a 100644 --- a/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php +++ b/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php @@ -437,6 +437,18 @@ class ExpressionBuilder return $this->calculation('COUNT', $fieldName, $alias); } + /** + * Creates a LENGTH expression for the given field/alias. + * + * @param string $fieldName + * @param string|null $alias + * @return string + */ + public function length(string $fieldName, string $alias = null): string + { + return $this->calculation('LENGTH', $fieldName, $alias); + } + /** * Create a SQL aggregate function. * diff --git a/typo3/sysext/core/Classes/Integrity/DatabaseIntegrityCheck.php b/typo3/sysext/core/Classes/Integrity/DatabaseIntegrityCheck.php index 82be6f70cbb6..34eb270763e8 100644 --- a/typo3/sysext/core/Classes/Integrity/DatabaseIntegrityCheck.php +++ b/typo3/sysext/core/Classes/Integrity/DatabaseIntegrityCheck.php @@ -18,6 +18,7 @@ use Doctrine\DBAL\Types\Type; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder; use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; use TYPO3\CMS\Core\Database\RelationHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -227,7 +228,11 @@ class DatabaseIntegrityCheck } $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions()->removeAll(); - $queryResult = $queryBuilder->select('uid', 'pid', $GLOBALS['TCA'][$table]['ctrl']['label']) + $selectFields = ['uid', 'pid']; + if (!empty($GLOBALS['TCA'][$table]['ctrl']['label'])) { + $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['label']; + } + $queryResult = $queryBuilder->select(...$selectFields) ->from($table) ->where( $queryBuilder->expr()->notIn( @@ -422,7 +427,8 @@ class DatabaseIntegrityCheck $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); foreach ($fkey_arrays as $table => $field_list) { if ($GLOBALS['TCA'][$table] && trim($field_list)) { - $schemaManager = $connectionPool->getConnectionForTable($table)->getSchemaManager(); + $connection = $connectionPool->getConnectionForTable($table); + $schemaManager = $connection->getSchemaManager(); $tableColumns = $schemaManager->listTableColumns($table); $queryBuilder = $connectionPool->getQueryBuilderForTable($table); @@ -433,9 +439,13 @@ class DatabaseIntegrityCheck $queryBuilder->select('uid') ->from($table); $whereClause = []; + foreach ($fields as $fieldName) { // The array index of $tableColumns is the lowercased column name! - $fieldType = $tableColumns[strtolower($fieldName)]->getType()->getName(); + // It is quoted for keywords + $column = $tableColumns[strtolower($fieldName)] + ?? $tableColumns[$connection->quoteIdentifier(strtolower($fieldName))]; + $fieldType = $column->getType()->getName(); if (in_array( $fieldType, [Type::BIGINT, Type::INTEGER, Type::SMALLINT, Type::DECIMAL, Type::FLOAT], @@ -456,6 +466,16 @@ class DatabaseIntegrityCheck $queryBuilder->createNamedParameter('', \PDO::PARAM_STR) ) ); + } elseif (in_array($fieldType, [Type::BLOB], true)) { + $whereClause[] = $queryBuilder->expr()->andX( + $queryBuilder->expr()->isNotNull($fieldName), + $queryBuilder->expr() + ->comparison( + $queryBuilder->expr()->length($fieldName), + ExpressionBuilder::GT, + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ); } } $queryResult = $queryBuilder->orWhere(...$whereClause)->execute(); diff --git a/typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php b/typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php index 30798ba895e9..4926d90b5db0 100644 --- a/typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php +++ b/typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php @@ -488,6 +488,23 @@ class ExpressionBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCa ); } + /** + * @test + */ + public function lengthQuotesIdentifier() + { + $this->connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($args) { + $platform = new MockPlatform(); + return $platform->quoteIdentifier($args[0]); + }); + + $this->assertSame('LENGTH("tableName"."fieldName")', $this->subject->length('tableName.fieldName')); + $this->assertSame( + 'LENGTH("tableName"."fieldName") AS "anAlias"', + $this->subject->length('tableName.fieldName', 'anAlias') + ); + } + /** * @test */ -- GitLab