From a4ec309d2df474f807b5cb44e7f01740325248d3 Mon Sep 17 00:00:00 2001 From: Christian Kuhn <lolli@schwarzbu.ch> Date: Tue, 6 Jun 2017 17:57:15 +0200 Subject: [PATCH] [BUGFIX] mssql: ExpressionBuilder inSet() support mssql does not support FIND_IN_SET(). The patch adds a solution based on LIKE. Since the query fiddling in this area is a bit tricky, this area is now supported by a bunch of functional tests. A postgres bug those new functional tests reveal is fixed along the way. Change-Id: I5e94ad8df7a37a680b457eff1b5b16a0c14dba39 Resolves: #81488 Releases: master, 8.7 Reviewed-on: https://review.typo3.org/53141 Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de> Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de> Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Markus Klein <markus.klein@typo3.org> Tested-by: Markus Klein <markus.klein@typo3.org> --- .../Query/Expression/ExpressionBuilder.php | 32 +- .../DataSet/TestExpressionBuilderInSet.csv | 42 ++ .../test_expressionbuilder/ext_emconf.php | 22 + .../test_expressionbuilder/ext_tables.sql | 13 + .../Expression/ExpressionBuilderTest.php | 399 ++++++++++++++++++ .../Expression/ExpressionBuilderTest.php | 46 ++ .../Generic/Storage/Typo3DbQueryParser.php | 2 +- 7 files changed, 548 insertions(+), 8 deletions(-) create mode 100644 typo3/sysext/core/Tests/Functional/Database/Fixtures/DataSet/TestExpressionBuilderInSet.csv create mode 100644 typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_emconf.php create mode 100644 typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_tables.sql create mode 100644 typo3/sysext/core/Tests/Functional/Database/Query/Expression/ExpressionBuilderTest.php diff --git a/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php b/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php index ba8335925df1..f0fd694d4718 100644 --- a/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php +++ b/typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php @@ -270,7 +270,7 @@ class ExpressionBuilder /** * Returns a comparison that can find a value in a list field (CSV). * - * @param string $fieldName The fieldname. Will be quoted according to database platform automatically. + * @param string $fieldName The field name. Will be quoted according to database platform automatically. * @param string $value Argument to be used in FIND_IN_SET() comparison. No automatic quoting/escaping is done. * @param bool $isColumn Set when the value to compare is a column on a table to activate casting * @return string @@ -297,7 +297,7 @@ class ExpressionBuilder case 'postgresql': case 'pdo_postgresql': return $this->comparison( - $isColumn ? $value . '::text' : $value, + $isColumn ? $value . '::text' : $this->literal($this->unquoteLiteral((string)$value)), self::EQ, sprintf( 'ANY(string_to_array(%s, %s))', @@ -315,11 +315,29 @@ class ExpressionBuilder break; case 'sqlsrv': case 'pdo_sqlsrv': - throw new \RuntimeException( - 'FIND_IN_SET support for database platform "SQLServer" not yet implemented.', - 1459696681 - ); - break; + case 'mssql': + // See unit and functional tests for details + if ($isColumn) { + $expression = $this->orX( + $this->eq($fieldName, $value), + $this->like($fieldName, $value . ' + \',%\''), + $this->like($fieldName, '\'%,\' + ' . $value), + $this->like($fieldName, '\'%,\' + ' . $value . ' + \',%\'') + ); + } else { + $likeEscapedValue = str_replace( + ['[', '%'], + ['[[]', '[%]'], + $this->unquoteLiteral($value) + ); + $expression = $this->orX( + $this->eq($fieldName, $this->literal($this->unquoteLiteral((string)$value))), + $this->like($fieldName, $this->literal($likeEscapedValue . ',%')), + $this->like($fieldName, $this->literal('%,' . $likeEscapedValue)), + $this->like($fieldName, $this->literal('%,' . $likeEscapedValue . ',%')) + ); + } + return (string)$expression; case 'sqlite': case 'sqlite3': case 'pdo_sqlite': diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/DataSet/TestExpressionBuilderInSet.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/DataSet/TestExpressionBuilderInSet.csv new file mode 100644 index 000000000000..26f44dc3dc5f --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/DataSet/TestExpressionBuilderInSet.csv @@ -0,0 +1,42 @@ +"tx_expressionbuildertest" +,"uid","pid","aField","aCsvField" +,1,0,"match","match" +,2,0,"match","match,nomatch" +,3,0,"match","nomatch,match" +,4,0,"match","nomatch1,match,nomatch2" +,5,0,"match","nomatch" +,6,0,"2","2" +,7,0,"2","2,3" +,8,0,"2","1,2" +,9,0,"2","1,2,3" +,10,0,"2","4" +,11,0,"wild%card","wild%card" +,12,0,"wild%card","wild%card,nowild%card" +,13,0,"wild%card","nowild%card,wild%card" +,14,0,"wild%card","nowild%card1,wild%card,nowild%card2" +,15,0,"wild%card","nowild%card" +,16,0,"kokolores","wild[card" +,17,0,"kokolores","wild[card,nowild[card" +,18,0,"kokolores","nowild[card,wild[card" +,19,0,"kokolores","nowild[card1,wild[card,nowild[card2" +,20,0,"kokolores","nowild[card" +,21,0,"kokolores","wild]card" +,22,0,"kokolores","wild]card,nowild]card" +,23,0,"kokolores","nowild]card,wild]card" +,24,0,"kokolores","nowild]card1,wild]card,nowild]card2" +,25,0,"kokolores","nowild]card" +,26,0,"kokolores","wild[]card" +,27,0,"kokolores","wild[]card,nowild[]card" +,28,0,"kokolores","nowild[]card,wild[]card" +,29,0,"kokolores","nowild[]card1,wild[]card,nowild[]card2" +,30,0,"kokolores","nowild[]card" +,31,0,"kokolores","wild[foo]card" +,32,0,"kokolores","wild[foo]card,nowild[foo]card" +,33,0,"kokolores","nowild[foo]card,wild[foo]card" +,34,0,"kokolores","nowild[foo]card1,wild[foo]card,nowild[foo]card2" +,35,0,"kokolores","nowild[foo]card" +,36,0,"kokolores","wild[%]card" +,37,0,"kokolores","wild[%]card,nowild[%]card" +,38,0,"kokolores","nowild[%]card,wild[%]card" +,39,0,"kokolores","nowild[%]card1,wild[%]card,nowild[%]card2" +,40,0,"kokolores","nowild[%]card" \ No newline at end of file diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_emconf.php b/typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_emconf.php new file mode 100644 index 000000000000..efbc737910de --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_emconf.php @@ -0,0 +1,22 @@ +<?php +$EM_CONF[$_EXTKEY] = [ + 'title' => 'ExpressionBuilder Test', + 'description' => 'ExpressionBuilder Test', + 'category' => 'example', + 'version' => '0.0.1', + 'state' => 'beta', + 'uploadfolder' => 0, + 'createDirs' => '', + 'clearcacheonload' => 0, + 'author' => 'Christian Kuhn', + 'author_email' => 'lolli@schwarzu.ch', + 'constraints' => [ + 'depends' => [ + 'typo3' => '8.7.0-0.0.0', + ], + 'conflicts' => [ + ], + 'suggests' => [ + ], + ], +]; diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_tables.sql b/typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_tables.sql new file mode 100644 index 000000000000..73b94ca38a1a --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder/ext_tables.sql @@ -0,0 +1,13 @@ +# +# Table structure for table 'tx_expressionbuildertest' +# +CREATE TABLE tx_expressionbuildertest ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + + aField text, + aCsvField text, + + PRIMARY KEY (uid), + KEY parent (pid) +); diff --git a/typo3/sysext/core/Tests/Functional/Database/Query/Expression/ExpressionBuilderTest.php b/typo3/sysext/core/Tests/Functional/Database/Query/Expression/ExpressionBuilderTest.php new file mode 100644 index 000000000000..92579879b8de --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Database/Query/Expression/ExpressionBuilderTest.php @@ -0,0 +1,399 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Core\Tests\Functional\Database\Query\Expression; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; + +/** + * Test case + */ +class ExpressionBuilderTest extends FunctionalTestCase +{ + /** + * @var array Extension comes with table setup to test inSet() methods of ExpressionBuilder + */ + protected $testExtensionsToLoad = [ + 'typo3/sysext/core/Tests/Functional/Database/Fixtures/Extensions/test_expressionbuilder', + ]; + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsWithColumn() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->quoteIdentifier('aField'), true) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 1, + 'aCsvField' => 'match', + ], + 1 => [ + 'uid' => 2, + 'aCsvField' => 'match,nomatch', + ], + 2 => [ + 'uid' => 3, + 'aCsvField' => 'nomatch,match', + ], + 3 => [ + 'uid' => 4, + 'aCsvField' => 'nomatch1,match,nomatch2', + ], + // uid 5 missing here! + 4 => [ + 'uid' => 6, + 'aCsvField' => '2', + ], + 5 => [ + 'uid' => 7, + 'aCsvField' => '2,3', + ], + 6 => [ + 'uid' => 8, + 'aCsvField' => '1,2', + ], + 7 => [ + 'uid' => 9, + 'aCsvField' => '1,2,3', + ], + // uid 10 missing here! + 8 => [ + 'uid' => 11, + 'aCsvField' => 'wild%card', + ], + 9 => [ + 'uid' => 12, + 'aCsvField' => 'wild%card,nowild%card', + ], + 10 => [ + 'uid' => 13, + 'aCsvField' => 'nowild%card,wild%card', + ], + 11 => [ + 'uid' => 14, + 'aCsvField' => 'nowild%card1,wild%card,nowild%card2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSets() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('match')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 1, + 'aCsvField' => 'match', + ], + 1 => [ + 'uid' => 2, + 'aCsvField' => 'match,nomatch', + ], + 2 => [ + 'uid' => 3, + 'aCsvField' => 'nomatch,match', + ], + 3 => [ + 'uid' => 4, + 'aCsvField' => 'nomatch1,match,nomatch2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsWithInts() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', (string)2) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 6, + 'aCsvField' => '2', + ], + 1 => [ + 'uid' => 7, + 'aCsvField' => '2,3', + ], + 2 => [ + 'uid' => 8, + 'aCsvField' => '1,2', + ], + 3 => [ + 'uid' => 9, + 'aCsvField' => '1,2,3', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsIfValueContainsLikeWildcard() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('wild%card')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 11, + 'aCsvField' => 'wild%card', + ], + 1 => [ + 'uid' => 12, + 'aCsvField' => 'wild%card,nowild%card', + ], + 2 => [ + 'uid' => 13, + 'aCsvField' => 'nowild%card,wild%card', + ], + 3 => [ + 'uid' => 14, + 'aCsvField' => 'nowild%card1,wild%card,nowild%card2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsIfValueContainsBracket() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('wild[card')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 16, + 'aCsvField' => 'wild[card', + ], + 1 => [ + 'uid' => 17, + 'aCsvField' => 'wild[card,nowild[card', + ], + 2 => [ + 'uid' => 18, + 'aCsvField' => 'nowild[card,wild[card', + ], + 3 => [ + 'uid' => 19, + 'aCsvField' => 'nowild[card1,wild[card,nowild[card2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsIfValueContainsClosingBracket() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('wild]card')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 21, + 'aCsvField' => 'wild]card', + ], + 1 => [ + 'uid' => 22, + 'aCsvField' => 'wild]card,nowild]card', + ], + 2 => [ + 'uid' => 23, + 'aCsvField' => 'nowild]card,wild]card', + ], + 3 => [ + 'uid' => 24, + 'aCsvField' => 'nowild]card1,wild]card,nowild]card2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsIfValueContainsOpeningAndClosingBracket() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('wild[]card')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 26, + 'aCsvField' => 'wild[]card', + ], + 1 => [ + 'uid' => 27, + 'aCsvField' => 'wild[]card,nowild[]card', + ], + 2 => [ + 'uid' => 28, + 'aCsvField' => 'nowild[]card,wild[]card', + ], + 3 => [ + 'uid' => 29, + 'aCsvField' => 'nowild[]card1,wild[]card,nowild[]card2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsIfValueContainsBracketsAroundWord() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('wild[foo]card')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 31, + 'aCsvField' => 'wild[foo]card', + ], + 1 => [ + 'uid' => 32, + 'aCsvField' => 'wild[foo]card,nowild[foo]card', + ], + 2 => [ + 'uid' => 33, + 'aCsvField' => 'nowild[foo]card,wild[foo]card', + ], + 3 => [ + 'uid' => 34, + 'aCsvField' => 'nowild[foo]card1,wild[foo]card,nowild[foo]card2', + ], + ]; + $this->assertEquals($expected, $result); + } + + /** + * @test + */ + public function inSetReturnsExpectedDataSetsIfValueContainsBracketsAroundLikeWildcard() + { + $this->importCSVDataSet(__DIR__ . '/../../Fixtures/DataSet/TestExpressionBuilderInSet.csv'); + $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_expressionbuildertest'); + $result = $queryBuilder + ->select('uid', 'aCsvField') + ->from('tx_expressionbuildertest') + ->where( + $queryBuilder->expr()->inSet('aCsvField', $queryBuilder->expr()->literal('wild[%]card')) + ) + ->orderBy('uid') + ->execute() + ->fetchAll(); + $expected = [ + 0 => [ + 'uid' => 36, + 'aCsvField' => 'wild[%]card', + ], + 1 => [ + 'uid' => 37, + 'aCsvField' => 'wild[%]card,nowild[%]card', + ], + 2 => [ + 'uid' => 38, + 'aCsvField' => 'nowild[%]card,wild[%]card', + ], + 3 => [ + 'uid' => 39, + 'aCsvField' => 'nowild[%]card1,wild[%]card,nowild[%]card2', + ], + ]; + $this->assertEquals($expected, $result); + } +} 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 11961722b62c..57bc5d98c109 100644 --- a/typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php +++ b/typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php @@ -230,6 +230,26 @@ class ExpressionBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCa $this->assertSame('aField NOT IN (1, 2, 3)', $result); } + /** + * @test + */ + public function inSetThrowsExceptionWithEmptyValue() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(1459696089); + $this->subject->inSet('aField', ''); + } + + /** + * @test + */ + public function inSetThrowsExceptionWithInvalidValue() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(1459696090); + $this->subject->inSet('aField', 'an,Invalid,Value'); + } + /** * @test */ @@ -256,8 +276,10 @@ class ExpressionBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCa { $databasePlatform = $this->prophesize(MockPlatform::class); $databasePlatform->getName()->willReturn('postgresql'); + $databasePlatform->getStringLiteralQuoteCharacter()->willReturn('"'); $this->connectionProphet->quote(',', Argument::cetera())->shouldBeCalled()->willReturn("','"); + $this->connectionProphet->quote("'1'", null)->shouldBeCalled()->willReturn("'1'"); $this->connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($args) { return '"' . $args[0] . '"'; }); @@ -368,6 +390,30 @@ class ExpressionBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCa $this->subject->inSet('aField', ':dcValue1'); } + /** + * @test + */ + public function inSetForMssql() + { + $databasePlatform = $this->prophesize(MockPlatform::class); + $databasePlatform->getName()->willReturn('mssql'); + $databasePlatform->getStringLiteralQuoteCharacter()->willReturn('\''); + + $this->connectionProphet->quote('1', null)->shouldBeCalled()->willReturn("'1'"); + $this->connectionProphet->quote('1,%', null)->shouldBeCalled()->willReturn("'1,%'"); + $this->connectionProphet->quote('%,1', null)->shouldBeCalled()->willReturn("'%,1'"); + $this->connectionProphet->quote('%,1,%', null)->shouldBeCalled()->willReturn("'%,1,%'"); + $this->connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($args) { + return '[' . $args[0] . ']'; + }); + + $this->connectionProphet->getDatabasePlatform()->willReturn($databasePlatform->reveal()); + + $result = $this->subject->inSet('aField', "'1'"); + + $this->assertSame("([aField] = '1') OR ([aField] LIKE '1,%') OR ([aField] LIKE '%,1') OR ([aField] LIKE '%,1,%')", $result); + } + /** * @test */ diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php index eb3d8faea56d..079362763e7a 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php @@ -364,7 +364,7 @@ class Typo3DbQueryParser } else { return $this->queryBuilder->expr()->inSet( $tableName . '.' . $columnName, - $this->queryBuilder->createNamedParameter($value) + $this->queryBuilder->quote($value) ); } } else { -- GitLab