[FOLLOWUP][TASK] Implement DBAL inSet() for SQLite 49/50149/3
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Sun, 9 Oct 2016 16:26:48 +0000 (09:26 -0700)
committerWouter Wolters <typo3@wouterwolters.nl>
Sun, 9 Oct 2016 17:15:15 +0000 (19:15 +0200)
Add an exception if named parameters are used with inSet() on SQLite,
add tests to verify the behaviors for named parameters and values that
contain the actual quote character.

Change-Id: Iac2e40d13f921d7e6dcfaeb2c86a9eedc4d8351e
Resolves: #78045
Releases: master
Reviewed-on: https://review.typo3.org/50149
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
typo3/sysext/core/Classes/Database/Query/Expression/ExpressionBuilder.php
typo3/sysext/core/Tests/Unit/Database/Query/Expression/ExpressionBuilderTest.php

index 52ba984..ee1fac7 100644 (file)
@@ -320,6 +320,13 @@ class ExpressionBuilder
             case 'sqlite':
             case 'sqlite3':
             case 'pdo_sqlite':
+                if (strpos($value, ':') === 0 || $value === '?') {
+                    throw new \InvalidArgumentException(
+                        'ExpressionBuilder::inSet() for SQLite can not be used with placeholder arguments.',
+                        1476029421
+                    );
+                }
+
                 return $this->comparison(
                     implode('||', [
                         $this->literal(','),
@@ -475,8 +482,12 @@ class ExpressionBuilder
             ->getDatabasePlatform()
             ->getStringLiteralQuoteCharacter();
 
-        $unquotedValue = trim($value, $quoteChar);
+        $isQuoted = strpos($value, $quoteChar) === 0 && strpos(strrev($value), $quoteChar) === 0;
+
+        if ($isQuoted) {
+            return str_replace($quoteChar . $quoteChar, $quoteChar, substr($value, 1, -1));
+        }
 
-        return str_replace($quoteChar . $quoteChar, $quoteChar, $unquotedValue);
+        return $value;
     }
 }
index c2e30fd..7044391 100644 (file)
@@ -293,6 +293,64 @@ class ExpressionBuilderTest extends UnitTestCase
 
         $this->assertSame('\',\'||"aField"||\',\' LIKE \'%,1,%\'', $result);
     }
+
+    /**
+     * @test
+     */
+    public function inSetForSQLiteWithQuoteCharactersInValue()
+    {
+        $databasePlatform = $this->prophesize(MockPlatform::class);
+        $databasePlatform->getName()->willReturn('sqlite');
+        $databasePlatform->getStringLiteralQuoteCharacter()->willReturn("'");
+
+        $this->connectionProphet->quote(',', Argument::cetera())->shouldBeCalled()->willReturn("','");
+        $this->connectionProphet->quote('%,\'Some\'Value,%', Argument::cetera())->shouldBeCalled()
+            ->willReturn("'%,''Some''Value,%'");
+        $this->connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($args) {
+            return '"' . $args[0] . '"';
+        });
+
+        $this->connectionProphet->getDatabasePlatform()->willReturn($databasePlatform->reveal());
+
+        $result = $this->subject->inSet('aField', "'''Some''Value'");
+
+        $this->assertSame('\',\'||"aField"||\',\' LIKE \'%,\'\'Some\'\'Value,%\'', $result);
+    }
+
+    /**
+     * @test
+     */
+    public function inSetForSQLiteThrowsExceptionOnPositionalPlaceholder()
+    {
+        $databasePlatform = $this->prophesize(MockPlatform::class);
+        $databasePlatform->getName()->willReturn('sqlite');
+        $databasePlatform->getStringLiteralQuoteCharacter()->willReturn("'");
+
+        $this->connectionProphet->getDatabasePlatform()->willReturn($databasePlatform->reveal());
+
+        $this->expectException('InvalidArgumentException');
+        $this->expectExceptionCode(1476029421);
+
+        $this->subject->inSet('aField', '?');
+    }
+
+    /**
+     * @test
+     */
+    public function inSetForSQLiteThrowsExceptionOnNamedPlaceholder()
+    {
+        $databasePlatform = $this->prophesize(MockPlatform::class);
+        $databasePlatform->getName()->willReturn('sqlite');
+        $databasePlatform->getStringLiteralQuoteCharacter()->willReturn("'");
+
+        $this->connectionProphet->getDatabasePlatform()->willReturn($databasePlatform->reveal());
+
+        $this->expectException('InvalidArgumentException');
+        $this->expectExceptionCode(1476029421);
+
+        $this->subject->inSet('aField', ':dcValue1');
+    }
+
     /**
      * @test
      */