‪TYPO3CMS  11.5
PositionPlaceholderPreparedStatementTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Doctrine\DBAL\ParameterType;
21 use Doctrine\DBAL\Statement;
25 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
29 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
30 
31 class ‪PositionPlaceholderPreparedStatementTest extends FunctionalTestCase
32 {
33  protected function ‪setUp(): void
34  {
35  parent::setUp();
36  $this->withDatabaseSnapshot(function () {
37  $this->‪setUpDatabase();
38  });
39  }
40 
41  protected function ‪setUpDatabase(): void
42  {
43  $this->importCSVDataSet(__DIR__ . '/Fixtures/DataSet/queryBuilder_preparedStatement.csv');
44  }
45 
49  public function ‪canBeInstantiated(): void
50  {
51  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
52  ->getQueryBuilderForTable('pages');
53 
54  self::assertIsObject($queryBuilder);
55  self::assertInstanceOf(QueryBuilder::class, $queryBuilder);
56  }
57 
62  {
63  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
64  ->getQueryBuilderForTable('pages');
65  $queryBuilder->getRestrictions()
66  ->removeAll()
67  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
68 
69  $statement = $queryBuilder
70  ->select(...['*'])
71  ->from('pages')
72  ->where(
73  $queryBuilder->expr()->eq(
74  'pid',
75  $queryBuilder->createPositionalParameter(10, ParameterType::INTEGER)
76  )
77  )
78  ->orderBy('sorting', 'ASC')
79  // add deterministic sort order as last sorting information, which many dbms
80  // and version does it by itself, but not all.
81  ->addOrderBy('uid', 'ASC')
82  ->prepare();
83 
84  // first execution of prepared statement
85  $result1 = $statement->executeQuery();
86  $rows1 = $result1->fetchAllAssociative();
87  self::assertSame(2, count($rows1));
88  self::assertSame(11, (int)($rows1[0]['uid'] ?? 0));
89  self::assertSame(12, (int)($rows1[1]['uid'] ?? 0));
90 
91  // second execution of prepared statement with changed placeholder value
92  $statement->bindValue(1, 20, ParameterType::INTEGER);
93  $result2 = $statement->executeQuery();
94  $rows2 = $result2->fetchAllAssociative();
95  self::assertSame(2, count($rows2));
96  self::assertSame(21, (int)($rows2[0]['uid'] ?? 0));
97  self::assertSame(22, (int)($rows2[1]['uid'] ?? 0));
98  }
99 
104  {
105  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
106  ->getQueryBuilderForTable('pages');
107  $queryBuilder->getRestrictions()
108  ->removeAll()
109  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
110 
111  $statement = $queryBuilder
112  ->select(...['*'])
113  ->from('pages')
114  ->where(
115  $queryBuilder->expr()->eq(
116  'pid',
117  $queryBuilder->createPositionalParameter(10, ParameterType::INTEGER)
118  )
119  )
120  ->orderBy('sorting', 'ASC')
121  // add deterministic sort order as last sorting information, which many dbms
122  // and version does it by itself, but not all.
123  ->addOrderBy('uid', 'ASC')
124  ->prepare();
125 
126  // first execution of prepared statement
127  $result1 = $statement->executeQuery();
128  $rows1 = [];
129  while ($row = $result1->fetchAssociative()) {
130  $rows1[] = $row;
131  }
132 
133  self::assertSame(2, count($rows1));
134  self::assertSame(11, (int)($rows1[0]['uid'] ?? 0));
135  self::assertSame(12, (int)($rows1[1]['uid'] ?? 0));
136 
137  // second execution of prepared statement with changed placeholder value
138  $statement->bindValue(1, 20, ParameterType::INTEGER);
139  $result2 = $statement->executeQuery();
140  $rows2 = [];
141  while ($row = $result2->fetchAssociative()) {
142  $rows2[] = $row;
143  }
144  self::assertSame(2, count($rows2));
145  self::assertSame(21, (int)($rows2[0]['uid'] ?? 0));
146  self::assertSame(22, (int)($rows2[1]['uid'] ?? 0));
147  }
148 
153  {
154  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
155  ->getQueryBuilderForTable('pages');
156  $queryBuilder->getRestrictions()
157  ->removeAll()
158  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
159 
160  $statement = $queryBuilder
161  ->select(...['*'])
162  ->from('pages')
163  ->where(
164  $queryBuilder->expr()->eq(
165  'pid',
166  $queryBuilder->createPositionalParameter(10, ParameterType::INTEGER)
167  )
168  )
169  ->orderBy('sorting', 'ASC')
170  // add deterministic sort order as last sorting information, which many dbms
171  // and version does it by itself, but not all.
172  ->addOrderBy('uid', 'ASC')
173  ->prepare();
174 
175  // first execution of prepared statement
176  $statement->bindValue(1, 10, ParameterType::INTEGER);
177  $result1 = $statement->executeQuery();
178  self::assertSame(11, (int)($result1->fetchAssociative()['uid'] ?? 0));
179 
180  // second execution of prepared statement with changed placeholder value
181  $statement->bindValue(1, 20, ParameterType::INTEGER);
182  $result2 = $statement->executeQuery();
183  self::assertSame(21, (int)($result2->fetchAssociative()['uid'] ?? 0));
184  }
185 
190  {
191  $runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
192  $cacheIdentifier = 'prepared-statement-through-runtime-cache';
193  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
194  ->getQueryBuilderForTable('pages');
195  $queryBuilder->getRestrictions()
196  ->removeAll()
197  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
198 
199  $statement = $queryBuilder
200  ->select(...['*'])
201  ->from('pages')
202  ->where(
203  $queryBuilder->expr()->eq(
204  'pid',
205  $queryBuilder->createPositionalParameter(10, ParameterType::INTEGER)
206  )
207  )
208  ->orderBy('sorting', 'ASC')
209  // add deterministic sort order as last sorting information, which many dbms
210  // and version does it by itself, but not all.
211  ->addOrderBy('uid', 'ASC')
212  ->prepare();
213  $runtimeCache->set($cacheIdentifier, $statement);
214 
215  // first execution of prepared statement
216  $statement->bindValue(1, 10, ParameterType::INTEGER);
217  $result1 = $statement->executeQuery();
218  self::assertSame(11, (int)($result1->fetchAssociative()['uid'] ?? 0));
219  unset($result1);
220  unset($statement);
221 
222  // retrieve statement from runtime cache
223  $statement2 = $runtimeCache->get($cacheIdentifier);
224  self::assertInstanceOf(Statement::class, $statement2);
225 
226  // second execution of prepared statement with changed placeholder value
227  $statement2->bindValue(1, 20, ParameterType::INTEGER);
228  $result2 = $statement2->executeQuery();
229  self::assertSame(21, (int)($result2->fetchAssociative()['uid'] ?? 0));
230  }
231 
233  {
234  return [
235  'PARAM_INT_ARRAY' => [Connection::PARAM_INT_ARRAY, 'PARAM_INT_ARRAY', [10, 20]],
236  'PARAM_STR_ARRAY' => [Connection::PARAM_STR_ARRAY, 'PARAM_STR_ARRAY', [10, 20]],
237  ];
238  }
239 
244  public function ‪preparedStatementThrowsExceptionForInvalidParameterType(int $arrayParameterType, string $arrayParameterName, array $arrayValues): void
245  {
246  // expected exception
247  $this->expectExceptionObject(‪UnsupportedPreparedStatementParameterTypeException::new($arrayParameterName));
248 
249  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
250  ->getQueryBuilderForTable('pages');
251  $queryBuilder->getRestrictions()
252  ->removeAll()
253  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
254 
255  // prepare should result in exception, thus no forther execution with it
256  $queryBuilder
257  ->select(...['*'])
258  ->from('pages')
259  ->where(
260  $queryBuilder->expr()->in(
261  'pid',
262  $queryBuilder->createPositionalParameter($arrayValues, $arrayParameterType)
263  )
264  )
265  ->orderBy('sorting', 'ASC')
266  // add deterministic sort order as last sorting information, which many dbms
267  // and version does it by itself, but not all.
268  ->addOrderBy('uid', 'ASC')
269  ->prepare();
270  }
271 }
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\invalidParameterTypesForPreparedStatements
‪invalidParameterTypesForPreparedStatements()
Definition: PositionPlaceholderPreparedStatementTest.php:232
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\setUpDatabase
‪setUpDatabase()
Definition: PositionPlaceholderPreparedStatementTest.php:41
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\preparedStatementWithPositionPlaceholderAndBindValueWithWileLoopWorks
‪preparedStatementWithPositionPlaceholderAndBindValueWithWileLoopWorks()
Definition: PositionPlaceholderPreparedStatementTest.php:103
‪TYPO3\CMS\Core\Database\Query\UnsupportedPreparedStatementParameterTypeException
Definition: UnsupportedPreparedStatementParameterTypeException.php:21
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder
Definition: NamedPlaceholderPreparedStatementTest.php:18
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\preparedStatementThrowsExceptionForInvalidParameterType
‪preparedStatementThrowsExceptionForInvalidParameterType(int $arrayParameterType, string $arrayParameterName, array $arrayValues)
Definition: PositionPlaceholderPreparedStatementTest.php:244
‪TYPO3\CMS\Core\Database\Query\UnsupportedPreparedStatementParameterTypeException\new
‪static new(string $parameterType)
Definition: UnsupportedPreparedStatementParameterTypeException.php:22
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest
Definition: PositionPlaceholderPreparedStatementTest.php:32
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\preparedStatementWorksIfRetrievedThroughRuntimeCacheAndPriorResultSetNotFreedAfterIncompleteDataRetrieval
‪preparedStatementWorksIfRetrievedThroughRuntimeCacheAndPriorResultSetNotFreedAfterIncompleteDataRetrieval()
Definition: PositionPlaceholderPreparedStatementTest.php:189
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\preparedStatementWithPositionPlaceholderAndBindValueWorks
‪preparedStatementWithPositionPlaceholderAndBindValueWorks()
Definition: PositionPlaceholderPreparedStatementTest.php:61
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\setUp
‪setUp()
Definition: PositionPlaceholderPreparedStatementTest.php:33
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\canBeInstantiated
‪canBeInstantiated()
Definition: PositionPlaceholderPreparedStatementTest.php:49
‪TYPO3\CMS\Core\Tests\Functional\Database\Query\QueryBuilder\PositionPlaceholderPreparedStatementTest\preparedStatementWithoutRetrievingFullResultSetAndWithoutFreeingPriorResultSetWorks
‪preparedStatementWithoutRetrievingFullResultSetAndWithoutFreeingPriorResultSetWorks()
Definition: PositionPlaceholderPreparedStatementTest.php:152