diff --git a/typo3/sysext/core/Classes/Database/Query/QueryBuilder.php b/typo3/sysext/core/Classes/Database/Query/QueryBuilder.php index c6f6218b6d3a55002b9371223f40b7af9bae897c..576ec2c3b7372a53646c4e37575a21c7466b138f 100644 --- a/typo3/sysext/core/Classes/Database/Query/QueryBuilder.php +++ b/typo3/sysext/core/Classes/Database/Query/QueryBuilder.php @@ -923,18 +923,32 @@ class QueryBuilder * @param array $input * * @return array + * @throws \InvalidArgumentException */ public function quoteIdentifiersForSelect(array $input): array { - // The SQL * operator must not be quoted. As it can only occur either by itself - // or preceded by a tablename (tablename.*) check if the last character of a select - // expression is the * and quote only prepended table name. In all other cases the - // full expression is being quoted. foreach ($input as &$select) { - if (substr($select, -2) === '.*') { - $select = $this->quoteIdentifier(substr($select, 0, -2)) . '.*'; - } elseif ($select !== '*') { - $select = $this->quoteIdentifier($select); + list($fieldName, $alias, $suffix) = GeneralUtility::trimExplode(' AS ', $select, 3); + if (!empty($suffix)) { + throw new \InvalidArgumentException( + 'QueryBuilder::quoteIdentifiersForSelect() could not parse the input "' . $input . '"', + 1461170686 + ); + } + + // The SQL * operator must not be quoted. As it can only occur either by itself + // or preceded by a tablename (tablename.*) check if the last character of a select + // expression is the * and quote only prepended table name. In all other cases the + // full expression is being quoted. + if (substr($fieldName, -2) === '.*') { + $select = $this->quoteIdentifier(substr($fieldName, 0, -2)) . '.*'; + } elseif ($fieldName !== '*') { + $select = $this->quoteIdentifier($fieldName); + } + + // Quote the alias for the current fieldName, if given + if (!empty($alias)) { + $select .= ' AS ' . $this->quoteIdentifier($alias); } } return $input; diff --git a/typo3/sysext/core/Tests/Unit/Database/Query/QueryBuilderTest.php b/typo3/sysext/core/Tests/Unit/Database/Query/QueryBuilderTest.php index 35a547d0de0850786eaee2dc11c44a57428e8175..03c8e4aab8dd2434dc1175cabc1830e9f7c4b51a 100644 --- a/typo3/sysext/core/Tests/Unit/Database/Query/QueryBuilderTest.php +++ b/typo3/sysext/core/Tests/Unit/Database/Query/QueryBuilderTest.php @@ -279,6 +279,75 @@ class QueryBuilderTest extends UnitTestCase $this->subject->select('aField', 'anotherField'); } + public function quoteIdentifiersForSelectDataProvider() + { + return [ + 'fieldName' => [ + 'fieldName', + '"fieldName"', + ], + 'tableName.fieldName' => [ + 'tableName.fieldName', + '"tableName"."fieldName"', + ], + 'tableName.*' => [ + 'tableName.*', + '"tableName".*', + ], + '*' => [ + '*', + '*', + ], + 'fieldName AS anotherFieldName' => [ + 'fieldName AS anotherFieldName', + '"fieldName" AS "anotherFieldName"', + ], + 'tableName.fieldName AS anotherFieldName' => [ + 'tableName.fieldName AS anotherFieldName', + '"tableName"."fieldName" AS "anotherFieldName"', + ], + 'tableName.fieldName AS anotherTable.anotherFieldName' => [ + 'tableName.fieldName AS anotherTable.anotherFieldName', + '"tableName"."fieldName" AS "anotherTable"."anotherFieldName"', + ], + ]; + } + + /** + * @test + * @dataProvider quoteIdentifiersForSelectDataProvider + * @param string $identifier + * @param string $expectedResult + */ + public function quoteIdentifiersForSelect($identifier, $expectedResult) + { + $this->connection->quoteIdentifier(Argument::cetera())->will( + function ($args) { + $platform = new MockPlatform(); + + return $platform->quoteIdentifier($args[0]); + } + ); + + $this->assertSame([$expectedResult], $this->subject->quoteIdentifiersForSelect([$identifier])); + } + + /** + * @test + * @expectedException \InvalidArgumentException + */ + public function quoteIdentifiersForSelectWithInvalidAlias() + { + $this->connection->quoteIdentifier(Argument::cetera())->will( + function ($args) { + $platform = new MockPlatform(); + + return $platform->quoteIdentifier($args[0]); + } + ); + $this->subject->quoteIdentifiersForSelect(['aField AS anotherField,someField AS someThing']); + } + /** * @test */