DataAccessTest.php 35.2 KB
Newer Older
1 2
<?php

3 4
namespace Doctrine\Tests\DBAL\Functional;

Sergei Morozov's avatar
Sergei Morozov committed
5
use DateTime;
jeroendedauw's avatar
jeroendedauw committed
6
use Doctrine\DBAL\Connection;
7
use Doctrine\DBAL\DBALException;
Sergei Morozov's avatar
Sergei Morozov committed
8
use Doctrine\DBAL\Driver\Mysqli\Driver as MySQLiDriver;
9 10 11
use Doctrine\DBAL\Driver\OCI8\Driver as Oci8Driver;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver;
Sergei Morozov's avatar
Sergei Morozov committed
12
use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver;
13 14
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
15
use Doctrine\DBAL\Platforms\SqlitePlatform;
16
use Doctrine\DBAL\Platforms\TrimMode;
17
use Doctrine\DBAL\Schema\Table;
Sergei Morozov's avatar
Sergei Morozov committed
18
use Doctrine\DBAL\Statement;
19
use Doctrine\DBAL\Types\Types;
Sergei Morozov's avatar
Sergei Morozov committed
20
use Doctrine\Tests\DbalFunctionalTestCase;
21
use PDO;
22 23 24 25 26 27 28 29 30
use function array_change_key_case;
use function array_filter;
use function array_keys;
use function count;
use function date;
use function implode;
use function is_numeric;
use function json_encode;
use function property_exists;
Sergei Morozov's avatar
Sergei Morozov committed
31
use function sprintf;
32
use function strtotime;
Grégoire Paris's avatar
Grégoire Paris committed
33 34
use const CASE_LOWER;
use const PHP_EOL;
35

Sergei Morozov's avatar
Sergei Morozov committed
36
class DataAccessTest extends DbalFunctionalTestCase
37
{
Sergei Morozov's avatar
Sergei Morozov committed
38
    /** @var bool */
39
    private static $generated = false;
40

41
    protected function setUp() : void
42 43 44
    {
        parent::setUp();

Sergei Morozov's avatar
Sergei Morozov committed
45 46 47
        if (self::$generated !== false) {
            return;
        }
48

Sergei Morozov's avatar
Sergei Morozov committed
49 50 51 52 53
        $table = new Table('fetch_table');
        $table->addColumn('test_int', 'integer');
        $table->addColumn('test_string', 'string');
        $table->addColumn('test_datetime', 'datetime', ['notnull' => false]);
        $table->setPrimaryKey(['test_int']);
54

Sergei Morozov's avatar
Sergei Morozov committed
55
        $sm = $this->connection->getSchemaManager();
Sergei Morozov's avatar
Sergei Morozov committed
56 57
        $sm->createTable($table);

Sergei Morozov's avatar
Sergei Morozov committed
58
        $this->connection->insert('fetch_table', ['test_int' => 1, 'test_string' => 'foo', 'test_datetime' => '2010-01-01 10:10:10']);
Sergei Morozov's avatar
Sergei Morozov committed
59
        self::$generated = true;
60 61
    }

62
    public function testPrepareWithBindValue() : void
63
    {
Sergei Morozov's avatar
Sergei Morozov committed
64
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
65 66
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
67 68 69 70 71

        $stmt->bindValue(1, 1);
        $stmt->bindValue(2, 'foo');
        $stmt->execute();

72
        $row = $stmt->fetch(FetchMode::ASSOCIATIVE);
Sergei Morozov's avatar
Sergei Morozov committed
73 74
        $row = array_change_key_case($row, CASE_LOWER);
        self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row);
75 76
    }

77
    public function testPrepareWithBindParam() : void
78 79 80 81
    {
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
82
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
83 84
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
85 86 87 88 89

        $stmt->bindParam(1, $paramInt);
        $stmt->bindParam(2, $paramStr);
        $stmt->execute();

90
        $row = $stmt->fetch(FetchMode::ASSOCIATIVE);
Sergei Morozov's avatar
Sergei Morozov committed
91 92
        $row = array_change_key_case($row, CASE_LOWER);
        self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row);
93 94
    }

95
    public function testPrepareWithFetchAll() : void
96 97 98 99
    {
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
100
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
101 102
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
103 104 105 106 107

        $stmt->bindParam(1, $paramInt);
        $stmt->bindParam(2, $paramStr);
        $stmt->execute();

108
        $rows    = $stmt->fetchAll(FetchMode::ASSOCIATIVE);
Sergei Morozov's avatar
Sergei Morozov committed
109 110
        $rows[0] = array_change_key_case($rows[0], CASE_LOWER);
        self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $rows[0]);
111 112
    }

113 114 115
    /**
     * @group DBAL-228
     */
116
    public function testPrepareWithFetchAllBoth() : void
117 118 119 120
    {
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
121
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
122 123
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
124 125 126 127 128

        $stmt->bindParam(1, $paramInt);
        $stmt->bindParam(2, $paramStr);
        $stmt->execute();

129
        $rows    = $stmt->fetchAll(FetchMode::MIXED);
Sergei Morozov's avatar
Sergei Morozov committed
130 131
        $rows[0] = array_change_key_case($rows[0], CASE_LOWER);
        self::assertEquals(['test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'], $rows[0]);
132 133
    }

134
    public function testPrepareWithFetchColumn() : void
135 136 137 138
    {
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
139
        $sql  = 'SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
140 141
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
142 143 144 145 146 147

        $stmt->bindParam(1, $paramInt);
        $stmt->bindParam(2, $paramStr);
        $stmt->execute();

        $column = $stmt->fetchColumn();
148
        self::assertEquals(1, $column);
149 150
    }

151
    public function testPrepareWithIterator() : void
152 153 154 155
    {
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
156
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
157 158
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
159 160 161 162 163

        $stmt->bindParam(1, $paramInt);
        $stmt->bindParam(2, $paramStr);
        $stmt->execute();

Sergei Morozov's avatar
Sergei Morozov committed
164
        $rows = [];
165
        $stmt->setFetchMode(FetchMode::ASSOCIATIVE);
166
        foreach ($stmt as $row) {
Sergei Morozov's avatar
Sergei Morozov committed
167
            $rows[] = array_change_key_case($row, CASE_LOWER);
168 169
        }

Sergei Morozov's avatar
Sergei Morozov committed
170
        self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $rows[0]);
171 172
    }

173
    public function testPrepareWithQuoted() : void
174
    {
Sergei Morozov's avatar
Sergei Morozov committed
175
        $table    = 'fetch_table';
176 177 178
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
179 180 181 182 183 184 185
        $stmt = $this->connection->prepare(sprintf(
            'SELECT test_int, test_string FROM %s WHERE test_int = %s AND test_string = %s',
            $this->connection->quoteIdentifier($table),
            $this->connection->quote($paramInt),
            $this->connection->quote($paramStr)
        ));
        self::assertInstanceOf(Statement::class, $stmt);
186 187
    }

188
    public function testPrepareWithExecuteParams() : void
189 190 191 192
    {
        $paramInt = 1;
        $paramStr = 'foo';

Sergei Morozov's avatar
Sergei Morozov committed
193
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
194 195
        $stmt = $this->connection->prepare($sql);
        self::assertInstanceOf(Statement::class, $stmt);
Sergei Morozov's avatar
Sergei Morozov committed
196
        $stmt->execute([$paramInt, $paramStr]);
197

198
        $row = $stmt->fetch(FetchMode::ASSOCIATIVE);
Gabriel Caruso's avatar
Gabriel Caruso committed
199
        self::assertNotFalse($row);
Sergei Morozov's avatar
Sergei Morozov committed
200 201
        $row = array_change_key_case($row, CASE_LOWER);
        self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row);
202 203
    }

204
    public function testFetchAll() : void
205
    {
Sergei Morozov's avatar
Sergei Morozov committed
206
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
207
        $data = $this->connection->fetchAll($sql, [1, 'foo']);
208

Gabriel Caruso's avatar
Gabriel Caruso committed
209
        self::assertCount(1, $data);
210 211

        $row = $data[0];
Gabriel Caruso's avatar
Gabriel Caruso committed
212
        self::assertCount(2, $row);
213

Sergei Morozov's avatar
Sergei Morozov committed
214
        $row = array_change_key_case($row, CASE_LOWER);
215 216
        self::assertEquals(1, $row['test_int']);
        self::assertEquals('foo', $row['test_string']);
217 218
    }

root's avatar
root committed
219 220 221
    /**
     * @group DBAL-209
     */
222
    public function testFetchAllWithTypes() : void
root's avatar
root committed
223 224
    {
        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
225
        $datetime       = new DateTime($datetimeString);
226

227
        $sql  = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
228 229 230 231 232
        $data = $this->connection->fetchAll(
            $sql,
            [1, $datetime],
            [ParameterType::STRING, Types::DATETIME_MUTABLE]
        );
root's avatar
root committed
233

Gabriel Caruso's avatar
Gabriel Caruso committed
234
        self::assertCount(1, $data);
root's avatar
root committed
235 236

        $row = $data[0];
Gabriel Caruso's avatar
Gabriel Caruso committed
237
        self::assertCount(2, $row);
root's avatar
root committed
238

Sergei Morozov's avatar
Sergei Morozov committed
239
        $row = array_change_key_case($row, CASE_LOWER);
240 241
        self::assertEquals(1, $row['test_int']);
        self::assertStringStartsWith($datetimeString, $row['test_datetime']);
root's avatar
root committed
242
    }
243

root's avatar
root committed
244 245 246
    /**
     * @group DBAL-209
     */
247
    public function testFetchAllWithMissingTypes() : void
root's avatar
root committed
248
    {
Sergei Morozov's avatar
Sergei Morozov committed
249 250
        if ($this->connection->getDriver() instanceof MySQLiDriver ||
            $this->connection->getDriver() instanceof SQLSrvDriver) {
Steve Müller's avatar
Steve Müller committed
251
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
252 253
        }

root's avatar
root committed
254
        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
255 256
        $datetime       = new DateTime($datetimeString);
        $sql            = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
257 258 259

        $this->expectException(DBALException::class);

Sergei Morozov's avatar
Sergei Morozov committed
260
        $this->connection->fetchAll($sql, [1, $datetime]);
root's avatar
root committed
261 262
    }

263
    public function testFetchBoth() : void
264
    {
265
        $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
266
        $row = $this->connection->executeQuery($sql, [1, 'foo'])->fetch(FetchMode::MIXED);
267

Gabriel Caruso's avatar
Gabriel Caruso committed
268
        self::assertNotFalse($row);
269

Sergei Morozov's avatar
Sergei Morozov committed
270
        $row = array_change_key_case($row, CASE_LOWER);
271

272 273 274 275
        self::assertEquals(1, $row['test_int']);
        self::assertEquals('foo', $row['test_string']);
        self::assertEquals(1, $row[0]);
        self::assertEquals('foo', $row[1]);
276 277
    }

278
    public function testFetchNoResult() : void
279
    {
280
        self::assertFalse(
Sergei Morozov's avatar
Sergei Morozov committed
281
            $this->connection->executeQuery('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1])->fetch()
282
        );
283 284
    }

285
    public function testFetchAssoc() : void
286
    {
Sergei Morozov's avatar
Sergei Morozov committed
287
        $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
288
        $row = $this->connection->fetchAssoc($sql, [1, 'foo']);
289

Gabriel Caruso's avatar
Gabriel Caruso committed
290
        self::assertNotFalse($row);
291

Sergei Morozov's avatar
Sergei Morozov committed
292
        $row = array_change_key_case($row, CASE_LOWER);
293

294 295
        self::assertEquals(1, $row['test_int']);
        self::assertEquals('foo', $row['test_string']);
296 297
    }

298
    public function testFetchAssocWithTypes() : void
299 300
    {
        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
301
        $datetime       = new DateTime($datetimeString);
302

303
        $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
304 305 306 307 308
        $row = $this->connection->fetchAssoc(
            $sql,
            [1, $datetime],
            [ParameterType::STRING, Types::DATETIME_MUTABLE]
        );
309

Gabriel Caruso's avatar
Gabriel Caruso committed
310
        self::assertNotFalse($row);
311

Sergei Morozov's avatar
Sergei Morozov committed
312
        $row = array_change_key_case($row, CASE_LOWER);
313

314 315
        self::assertEquals(1, $row['test_int']);
        self::assertStringStartsWith($datetimeString, $row['test_datetime']);
316 317
    }

318
    public function testFetchAssocWithMissingTypes() : void
319
    {
Sergei Morozov's avatar
Sergei Morozov committed
320 321
        if ($this->connection->getDriver() instanceof MySQLiDriver ||
            $this->connection->getDriver() instanceof SQLSrvDriver) {
322 323 324 325
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
        }

        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
326 327
        $datetime       = new DateTime($datetimeString);
        $sql            = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
328 329 330

        $this->expectException(DBALException::class);

Sergei Morozov's avatar
Sergei Morozov committed
331
        $this->connection->fetchAssoc($sql, [1, $datetime]);
332 333
    }

334
    public function testFetchArray() : void
335
    {
Sergei Morozov's avatar
Sergei Morozov committed
336
        $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
337
        $row = $this->connection->fetchArray($sql, [1, 'foo']);
338

339 340
        self::assertEquals(1, $row[0]);
        self::assertEquals('foo', $row[1]);
341 342
    }

343
    public function testFetchArrayWithTypes() : void
344 345
    {
        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
346
        $datetime       = new DateTime($datetimeString);
347

348
        $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
349 350 351 352 353
        $row = $this->connection->fetchArray(
            $sql,
            [1, $datetime],
            [ParameterType::STRING, Types::DATETIME_MUTABLE]
        );
354

Gabriel Caruso's avatar
Gabriel Caruso committed
355
        self::assertNotFalse($row);
356

Sergei Morozov's avatar
Sergei Morozov committed
357
        $row = array_change_key_case($row, CASE_LOWER);
358

359 360
        self::assertEquals(1, $row[0]);
        self::assertStringStartsWith($datetimeString, $row[1]);
361 362
    }

363
    public function testFetchArrayWithMissingTypes() : void
364
    {
Sergei Morozov's avatar
Sergei Morozov committed
365 366
        if ($this->connection->getDriver() instanceof MySQLiDriver ||
            $this->connection->getDriver() instanceof SQLSrvDriver) {
367 368 369 370
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
        }

        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
371 372
        $datetime       = new DateTime($datetimeString);
        $sql            = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
373 374 375 376

        $this->expectException(DBALException::class);

        $this->connection->fetchArray($sql, [1, $datetime]);
377 378
    }

379
    public function testFetchColumn() : void
380
    {
Sergei Morozov's avatar
Sergei Morozov committed
381
        $sql     = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
382
        $testInt = $this->connection->fetchColumn($sql, [1, 'foo'], 0);
383

384
        self::assertEquals(1, $testInt);
385

Sergei Morozov's avatar
Sergei Morozov committed
386
        $sql        = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
387
        $testString = $this->connection->fetchColumn($sql, [1, 'foo'], 1);
388

389
        self::assertEquals('foo', $testString);
390
    }
391

392
    public function testFetchColumnWithTypes() : void
393 394
    {
        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
395
        $datetime       = new DateTime($datetimeString);
396

397
        $sql    = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
398 399 400 401 402 403
        $column = $this->connection->fetchColumn(
            $sql,
            [1, $datetime],
            1,
            [ParameterType::STRING, Types::DATETIME_MUTABLE]
        );
404

Gabriel Caruso's avatar
Gabriel Caruso committed
405
        self::assertNotFalse($column);
406

407
        self::assertStringStartsWith($datetimeString, $column);
408 409
    }

410
    public function testFetchColumnWithMissingTypes() : void
411
    {
Sergei Morozov's avatar
Sergei Morozov committed
412 413
        if ($this->connection->getDriver() instanceof MySQLiDriver ||
            $this->connection->getDriver() instanceof SQLSrvDriver) {
414 415 416 417
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
        }

        $datetimeString = '2010-01-01 10:10:10';
Sergei Morozov's avatar
Sergei Morozov committed
418 419
        $datetime       = new DateTime($datetimeString);
        $sql            = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
420 421 422 423

        $this->expectException(DBALException::class);

        $this->connection->fetchColumn($sql, [1, $datetime], 1);
424 425
    }

426 427 428
    /**
     * @group DDC-697
     */
429
    public function testExecuteQueryBindDateTimeType() : void
430
    {
Sergei Morozov's avatar
Sergei Morozov committed
431
        $sql  = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
Sergei Morozov's avatar
Sergei Morozov committed
432
        $stmt = $this->connection->executeQuery(
Sergei Morozov's avatar
Sergei Morozov committed
433 434
            $sql,
            [1 => new DateTime('2010-01-01 10:10:10')],
435
            [1 => Types::DATETIME_MUTABLE]
436 437
        );

438
        self::assertEquals(1, $stmt->fetchColumn());
439 440 441 442 443
    }

    /**
     * @group DDC-697
     */
444
    public function testExecuteUpdateBindDateTimeType() : void
445
    {
Sergei Morozov's avatar
Sergei Morozov committed
446
        $datetime = new DateTime('2010-02-02 20:20:20');
447

Sergei Morozov's avatar
Sergei Morozov committed
448
        $sql          = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)';
Sergei Morozov's avatar
Sergei Morozov committed
449
        $affectedRows = $this->connection->executeUpdate($sql, [
450 451 452 453 454 455
            1 => 50,
            2 => 'foo',
            3 => $datetime,
        ], [
            1 => ParameterType::INTEGER,
            2 => ParameterType::STRING,
456
            3 => Types::DATETIME_MUTABLE,
457
        ]);
458

459
        self::assertEquals(1, $affectedRows);
Sergei Morozov's avatar
Sergei Morozov committed
460
        self::assertEquals(1, $this->connection->executeQuery(
461
            'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?',
Sergei Morozov's avatar
Sergei Morozov committed
462
            [1 => $datetime],
463
            [1 => Types::DATETIME_MUTABLE]
464 465 466 467 468 469
        )->fetchColumn());
    }

    /**
     * @group DDC-697
     */
470
    public function testPrepareQueryBindValueDateTimeType() : void
471
    {
Sergei Morozov's avatar
Sergei Morozov committed
472
        $sql  = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
Sergei Morozov's avatar
Sergei Morozov committed
473
        $stmt = $this->connection->prepare($sql);
474
        $stmt->bindValue(1, new DateTime('2010-01-01 10:10:10'), Types::DATETIME_MUTABLE);
475 476
        $stmt->execute();

477
        self::assertEquals(1, $stmt->fetchColumn());
478
    }
479

480 481 482
    /**
     * @group DBAL-78
     */
483
    public function testNativeArrayListSupport() : void
484 485
    {
        for ($i = 100; $i < 110; $i++) {
Sergei Morozov's avatar
Sergei Morozov committed
486
            $this->connection->insert('fetch_table', ['test_int' => $i, 'test_string' => 'foo' . $i, 'test_datetime' => '2010-01-01 10:10:10']);
487
        }
488

Sergei Morozov's avatar
Sergei Morozov committed
489
        $stmt = $this->connection->executeQuery(
Sergei Morozov's avatar
Sergei Morozov committed
490 491 492 493
            'SELECT test_int FROM fetch_table WHERE test_int IN (?)',
            [[100, 101, 102, 103, 104]],
            [Connection::PARAM_INT_ARRAY]
        );
494

495
        $data = $stmt->fetchAll(FetchMode::NUMERIC);
Gabriel Caruso's avatar
Gabriel Caruso committed
496
        self::assertCount(5, $data);
Sergei Morozov's avatar
Sergei Morozov committed
497
        self::assertEquals([[100], [101], [102], [103], [104]], $data);
498

Sergei Morozov's avatar
Sergei Morozov committed
499
        $stmt = $this->connection->executeQuery(
Sergei Morozov's avatar
Sergei Morozov committed
500 501 502 503
            'SELECT test_int FROM fetch_table WHERE test_string IN (?)',
            [['foo100', 'foo101', 'foo102', 'foo103', 'foo104']],
            [Connection::PARAM_STR_ARRAY]
        );
504

505
        $data = $stmt->fetchAll(FetchMode::NUMERIC);
Gabriel Caruso's avatar
Gabriel Caruso committed
506
        self::assertCount(5, $data);
Sergei Morozov's avatar
Sergei Morozov committed
507
        self::assertEquals([[100], [101], [102], [103], [104]], $data);
508
    }
509

510
    /**
511 512
     * @param string|false $char
     *
513 514
     * @dataProvider getTrimExpressionData
     */
515
    public function testTrimExpression(string $value, int $position, $char, string $expectedResult) : void
516 517
    {
        $sql = 'SELECT ' .
Sergei Morozov's avatar
Sergei Morozov committed
518
            $this->connection->getDatabasePlatform()->getTrimExpression($value, $position, $char) . ' AS trimmed ' .
519 520
            'FROM fetch_table';

Sergei Morozov's avatar
Sergei Morozov committed
521
        $row = $this->connection->fetchAssoc($sql);
522 523
        $row = array_change_key_case($row, CASE_LOWER);

524
        self::assertEquals($expectedResult, $row['trimmed']);
525 526
    }

527 528 529 530
    /**
     * @return array<int, array<int, mixed>>
     */
    public static function getTrimExpressionData() : iterable
531
    {
Sergei Morozov's avatar
Sergei Morozov committed
532
        return [
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
            ['test_string', TrimMode::UNSPECIFIED, false, 'foo'],
            ['test_string', TrimMode::LEADING, false, 'foo'],
            ['test_string', TrimMode::TRAILING, false, 'foo'],
            ['test_string', TrimMode::BOTH, false, 'foo'],
            ['test_string', TrimMode::UNSPECIFIED, "'f'", 'oo'],
            ['test_string', TrimMode::UNSPECIFIED, "'o'", 'f'],
            ['test_string', TrimMode::UNSPECIFIED, "'.'", 'foo'],
            ['test_string', TrimMode::LEADING, "'f'", 'oo'],
            ['test_string', TrimMode::LEADING, "'o'", 'foo'],
            ['test_string', TrimMode::LEADING, "'.'", 'foo'],
            ['test_string', TrimMode::TRAILING, "'f'", 'foo'],
            ['test_string', TrimMode::TRAILING, "'o'", 'f'],
            ['test_string', TrimMode::TRAILING, "'.'", 'foo'],
            ['test_string', TrimMode::BOTH, "'f'", 'oo'],
            ['test_string', TrimMode::BOTH, "'o'", 'f'],
            ['test_string', TrimMode::BOTH, "'.'", 'foo'],
            ["' foo '", TrimMode::UNSPECIFIED, false, 'foo'],
            ["' foo '", TrimMode::LEADING, false, 'foo '],
            ["' foo '", TrimMode::TRAILING, false, ' foo'],
            ["' foo '", TrimMode::BOTH, false, 'foo'],
            ["' foo '", TrimMode::UNSPECIFIED, "'f'", ' foo '],
            ["' foo '", TrimMode::UNSPECIFIED, "'o'", ' foo '],
            ["' foo '", TrimMode::UNSPECIFIED, "'.'", ' foo '],
            ["' foo '", TrimMode::UNSPECIFIED, "' '", 'foo'],
            ["' foo '", TrimMode::LEADING, "'f'", ' foo '],
            ["' foo '", TrimMode::LEADING, "'o'", ' foo '],
            ["' foo '", TrimMode::LEADING, "'.'", ' foo '],
            ["' foo '", TrimMode::LEADING, "' '", 'foo '],
            ["' foo '", TrimMode::TRAILING, "'f'", ' foo '],
            ["' foo '", TrimMode::TRAILING, "'o'", ' foo '],
            ["' foo '", TrimMode::TRAILING, "'.'", ' foo '],
            ["' foo '", TrimMode::TRAILING, "' '", ' foo'],
            ["' foo '", TrimMode::BOTH, "'f'", ' foo '],
            ["' foo '", TrimMode::BOTH, "'o'", ' foo '],
            ["' foo '", TrimMode::BOTH, "'.'", ' foo '],
            ["' foo '", TrimMode::BOTH, "' '", 'foo'],
Sergei Morozov's avatar
Sergei Morozov committed
569
        ];
570 571
    }

572 573 574
    /**
     * @group DDC-1014
     */
575
    public function testDateArithmetics() : void
576
    {
Sergei Morozov's avatar
Sergei Morozov committed
577
        $p    = $this->connection->getDatabasePlatform();
Sergei Morozov's avatar
Sergei Morozov committed
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
        $sql  = 'SELECT ';
        $sql .= $p->getDateAddSecondsExpression('test_datetime', 1) . ' AS add_seconds, ';
        $sql .= $p->getDateSubSecondsExpression('test_datetime', 1) . ' AS sub_seconds, ';
        $sql .= $p->getDateAddMinutesExpression('test_datetime', 5) . ' AS add_minutes, ';
        $sql .= $p->getDateSubMinutesExpression('test_datetime', 5) . ' AS sub_minutes, ';
        $sql .= $p->getDateAddHourExpression('test_datetime', 3) . ' AS add_hour, ';
        $sql .= $p->getDateSubHourExpression('test_datetime', 3) . ' AS sub_hour, ';
        $sql .= $p->getDateAddDaysExpression('test_datetime', 10) . ' AS add_days, ';
        $sql .= $p->getDateSubDaysExpression('test_datetime', 10) . ' AS sub_days, ';
        $sql .= $p->getDateAddWeeksExpression('test_datetime', 1) . ' AS add_weeks, ';
        $sql .= $p->getDateSubWeeksExpression('test_datetime', 1) . ' AS sub_weeks, ';
        $sql .= $p->getDateAddMonthExpression('test_datetime', 2) . ' AS add_month, ';
        $sql .= $p->getDateSubMonthExpression('test_datetime', 2) . ' AS sub_month, ';
        $sql .= $p->getDateAddQuartersExpression('test_datetime', 3) . ' AS add_quarters, ';
        $sql .= $p->getDateSubQuartersExpression('test_datetime', 3) . ' AS sub_quarters, ';
        $sql .= $p->getDateAddYearsExpression('test_datetime', 6) . ' AS add_years, ';
        $sql .= $p->getDateSubYearsExpression('test_datetime', 6) . ' AS sub_years ';
595 596
        $sql .= 'FROM fetch_table';

Sergei Morozov's avatar
Sergei Morozov committed
597
        $row = $this->connection->fetchAssoc($sql);
598
        $row = array_change_key_case($row, CASE_LOWER);
599

Sergei Morozov's avatar
Sergei Morozov committed
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
        self::assertEquals('2010-01-01 10:10:11', date('Y-m-d H:i:s', strtotime($row['add_seconds'])), 'Adding second should end up on 2010-01-01 10:10:11');
        self::assertEquals('2010-01-01 10:10:09', date('Y-m-d H:i:s', strtotime($row['sub_seconds'])), 'Subtracting second should end up on 2010-01-01 10:10:09');
        self::assertEquals('2010-01-01 10:15:10', date('Y-m-d H:i:s', strtotime($row['add_minutes'])), 'Adding minutes should end up on 2010-01-01 10:15:10');
        self::assertEquals('2010-01-01 10:05:10', date('Y-m-d H:i:s', strtotime($row['sub_minutes'])), 'Subtracting minutes should end up on 2010-01-01 10:05:10');
        self::assertEquals('2010-01-01 13:10', date('Y-m-d H:i', strtotime($row['add_hour'])), 'Adding date should end up on 2010-01-01 13:10');
        self::assertEquals('2010-01-01 07:10', date('Y-m-d H:i', strtotime($row['sub_hour'])), 'Subtracting date should end up on 2010-01-01 07:10');
        self::assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), 'Adding date should end up on 2010-01-11');
        self::assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), 'Subtracting date should end up on 2009-12-22');
        self::assertEquals('2010-01-08', date('Y-m-d', strtotime($row['add_weeks'])), 'Adding week should end up on 2010-01-08');
        self::assertEquals('2009-12-25', date('Y-m-d', strtotime($row['sub_weeks'])), 'Subtracting week should end up on 2009-12-25');
        self::assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), 'Adding month should end up on 2010-03-01');
        self::assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), 'Subtracting month should end up on 2009-11-01');
        self::assertEquals('2010-10-01', date('Y-m-d', strtotime($row['add_quarters'])), 'Adding quarters should end up on 2010-04-01');
        self::assertEquals('2009-04-01', date('Y-m-d', strtotime($row['sub_quarters'])), 'Subtracting quarters should end up on 2009-10-01');
        self::assertEquals('2016-01-01', date('Y-m-d', strtotime($row['add_years'])), 'Adding years should end up on 2016-01-01');
        self::assertEquals('2004-01-01', date('Y-m-d', strtotime($row['sub_years'])), 'Subtracting years should end up on 2004-01-01');
616
    }
617

618
    public function testSqliteDateArithmeticWithDynamicInterval() : void
619
    {
Sergei Morozov's avatar
Sergei Morozov committed
620
        $platform = $this->connection->getDatabasePlatform();
621 622 623 624 625 626 627 628 629 630

        if (! $platform instanceof SqlitePlatform) {
            $this->markTestSkipped('test is for sqlite only');
        }

        $table = new Table('fetch_table_date_math');
        $table->addColumn('test_date', 'date');
        $table->addColumn('test_days', 'integer');
        $table->setPrimaryKey(['test_date']);

Sergei Morozov's avatar
Sergei Morozov committed
631
        $sm = $this->connection->getSchemaManager();
632 633
        $sm->createTable($table);

Sergei Morozov's avatar
Sergei Morozov committed
634 635
        $this->connection->insert('fetch_table_date_math', ['test_date' => '2010-01-01', 'test_days' => 10]);
        $this->connection->insert('fetch_table_date_math', ['test_date' => '2010-06-01', 'test_days' => 20]);
636 637 638 639

        $sql  = 'SELECT COUNT(*) FROM fetch_table_date_math WHERE ';
        $sql .= $platform->getDateSubDaysExpression('test_date', 'test_days') . " < '2010-05-12'";

Sergei Morozov's avatar
Sergei Morozov committed
640
        $rowCount = $this->connection->fetchColumn($sql, [], 0);
641 642 643 644

        $this->assertEquals(1, $rowCount);
    }

645
    public function testLocateExpression() : void
646
    {
Sergei Morozov's avatar
Sergei Morozov committed
647
        $platform = $this->connection->getDatabasePlatform();
648

Sergei Morozov's avatar
Sergei Morozov committed
649 650 651 652 653 654 655 656 657 658
        $sql  = 'SELECT ';
        $sql .= $platform->getLocateExpression('test_string', "'oo'") . ' AS locate1, ';
        $sql .= $platform->getLocateExpression('test_string', "'foo'") . ' AS locate2, ';
        $sql .= $platform->getLocateExpression('test_string', "'bar'") . ' AS locate3, ';
        $sql .= $platform->getLocateExpression('test_string', 'test_string') . ' AS locate4, ';
        $sql .= $platform->getLocateExpression("'foo'", 'test_string') . ' AS locate5, ';
        $sql .= $platform->getLocateExpression("'barfoobaz'", 'test_string') . ' AS locate6, ';
        $sql .= $platform->getLocateExpression("'bar'", 'test_string') . ' AS locate7, ';
        $sql .= $platform->getLocateExpression('test_string', "'oo'", 2) . ' AS locate8, ';
        $sql .= $platform->getLocateExpression('test_string', "'oo'", 3) . ' AS locate9 ';
659 660
        $sql .= 'FROM fetch_table';

Sergei Morozov's avatar
Sergei Morozov committed
661
        $row = $this->connection->fetchAssoc($sql);
662 663
        $row = array_change_key_case($row, CASE_LOWER);

664 665 666 667 668 669 670 671 672
        self::assertEquals(2, $row['locate1']);
        self::assertEquals(1, $row['locate2']);
        self::assertEquals(0, $row['locate3']);
        self::assertEquals(1, $row['locate4']);
        self::assertEquals(1, $row['locate5']);
        self::assertEquals(4, $row['locate6']);
        self::assertEquals(0, $row['locate7']);
        self::assertEquals(2, $row['locate8']);
        self::assertEquals(0, $row['locate9']);
673 674
    }

675
    public function testQuoteSQLInjection() : void
676
    {
Sergei Morozov's avatar
Sergei Morozov committed
677 678
        $sql  = 'SELECT * FROM fetch_table WHERE test_string = ' . $this->connection->quote("bar' OR '1'='1");
        $rows = $this->connection->fetchAll($sql);
679

Sergei Morozov's avatar
Sergei Morozov committed
680
        self::assertCount(0, $rows, 'no result should be returned, otherwise SQL injection is possible');
681
    }
682

Fabio B. Silva's avatar
Fabio B. Silva committed
683 684 685
    /**
     * @group DDC-1213
     */
686
    public function testBitComparisonExpressionSupport() : void
Fabio B. Silva's avatar
Fabio B. Silva committed
687
    {
Sergei Morozov's avatar
Sergei Morozov committed
688 689
        $this->connection->exec('DELETE FROM fetch_table');
        $platform = $this->connection->getDatabasePlatform();
Sergei Morozov's avatar
Sergei Morozov committed
690
        $bitmap   = [];
691

Sergei Morozov's avatar
Sergei Morozov committed
692 693
        for ($i = 2; $i < 9; $i += 2) {
            $bitmap[$i] = [
Fabio B. Silva's avatar
Fabio B. Silva committed
694
                'bit_or'    => ($i | 2),
Sergei Morozov's avatar
Sergei Morozov committed
695 696
                'bit_and'   => ($i & 2),
            ];
Sergei Morozov's avatar
Sergei Morozov committed
697
            $this->connection->insert('fetch_table', [
698
                'test_int'      => $i,
Fabio B. Silva's avatar
Fabio B. Silva committed
699
                'test_string'   => json_encode($bitmap[$i]),
Sergei Morozov's avatar
Sergei Morozov committed
700 701
                'test_datetime' => '2010-01-01 10:10:10',
            ]);
Fabio B. Silva's avatar
Fabio B. Silva committed
702
        }
703

Sergei Morozov's avatar
Sergei Morozov committed
704 705 706 707 708 709
        $sql[] = 'SELECT ';
        $sql[] = 'test_int, ';
        $sql[] = 'test_string, ';
        $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, ';
        $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and ';
        $sql[] = 'FROM fetch_table';
Fabio B. Silva's avatar
Fabio B. Silva committed
710

Sergei Morozov's avatar
Sergei Morozov committed
711
        $stmt = $this->connection->executeQuery(implode(PHP_EOL, $sql));
712
        $data = $stmt->fetchAll(FetchMode::ASSOCIATIVE);
713

Gabriel Caruso's avatar
Gabriel Caruso committed
714
        self::assertCount(4, $data);
715
        self::assertEquals(count($bitmap), count($data));
Fabio B. Silva's avatar
Fabio B. Silva committed
716
        foreach ($data as $row) {
717 718
            $row = array_change_key_case($row, CASE_LOWER);

719
            self::assertArrayHasKey('test_int', $row);
720

Fabio B. Silva's avatar
Fabio B. Silva committed
721
            $id = $row['test_int'];
722

723 724
            self::assertArrayHasKey($id, $bitmap);
            self::assertArrayHasKey($id, $bitmap);
725

726 727
            self::assertArrayHasKey('bit_or', $row);
            self::assertArrayHasKey('bit_and', $row);
728

729 730
            self::assertEquals($row['bit_or'], $bitmap[$id]['bit_or']);
            self::assertEquals($row['bit_and'], $bitmap[$id]['bit_and']);
Fabio B. Silva's avatar
Fabio B. Silva committed
731 732
        }
    }
733

734
    public function testSetDefaultFetchMode() : void
735
    {
Sergei Morozov's avatar
Sergei Morozov committed
736
        $stmt = $this->connection->query('SELECT * FROM fetch_table');
737
        $stmt->setFetchMode(FetchMode::NUMERIC);
738 739

        $row = array_keys($stmt->fetch());
Sergei Morozov's avatar
Sergei Morozov committed
740 741 742
        self::assertCount(0, array_filter($row, static function ($v) {
            return ! is_numeric($v);
        }), 'should be no non-numerical elements in the result.');
743
    }
Fabio B. Silva's avatar
Fabio B. Silva committed
744

745 746 747
    /**
     * @group DBAL-1091
     */
748
    public function testFetchAllStyleObject() : void
749 750 751
    {
        $this->setupFixture();

Sergei Morozov's avatar
Sergei Morozov committed
752
        $sql  = 'SELECT test_int, test_string, test_datetime FROM fetch_table';
Sergei Morozov's avatar
Sergei Morozov committed
753
        $stmt = $this->connection->prepare($sql);
754 755 756

        $stmt->execute();

757
        $results = $stmt->fetchAll(FetchMode::STANDARD_OBJECT);
758

759 760
        self::assertCount(1, $results);
        self::assertInstanceOf('stdClass', $results[0]);
761

762
        self::assertEquals(
763 764 765
            1,
            property_exists($results[0], 'test_int') ? $results[0]->test_int : $results[0]->TEST_INT
        );
766
        self::assertEquals(
767 768 769
            'foo',
            property_exists($results[0], 'test_string') ? $results[0]->test_string : $results[0]->TEST_STRING
        );
770
        self::assertStringStartsWith(
771 772 773 774 775
            '2010-01-01 10:10:10',
            property_exists($results[0], 'test_datetime') ? $results[0]->test_datetime : $results[0]->TEST_DATETIME
        );
    }

Fabio B. Silva's avatar
Fabio B. Silva committed
776 777 778
    /**
     * @group DBAL-196
     */
779
    public function testFetchAllSupportFetchClass() : void
Fabio B. Silva's avatar
Fabio B. Silva committed
780
    {
781
        $this->beforeFetchClassTest();
782
        $this->setupFixture();
Fabio B. Silva's avatar
Fabio B. Silva committed
783

Sergei Morozov's avatar
Sergei Morozov committed
784
        $sql  = 'SELECT test_int, test_string, test_datetime FROM fetch_table';
Sergei Morozov's avatar
Sergei Morozov committed
785
        $stmt = $this->connection->prepare($sql);
Fabio B. Silva's avatar
Fabio B. Silva committed
786 787 788
        $stmt->execute();

        $results = $stmt->fetchAll(
789
            FetchMode::CUSTOM_OBJECT,
Sergei Morozov's avatar
Sergei Morozov committed
790
            MyFetchClass::class
Fabio B. Silva's avatar
Fabio B. Silva committed
791 792
        );

Gabriel Caruso's avatar
Gabriel Caruso committed
793
        self::assertCount(1, $results);
Sergei Morozov's avatar
Sergei Morozov committed
794
        self::assertInstanceOf(MyFetchClass::class, $results[0]);
Benjamin Eberlei's avatar
Benjamin Eberlei committed
795

796 797 798
        self::assertEquals(1, $results[0]->test_int);
        self::assertEquals('foo', $results[0]->test_string);
        self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
Fabio B. Silva's avatar
Fabio B. Silva committed
799
    }
800 801 802 803

    /**
     * @group DBAL-241
     */
804
    public function testFetchAllStyleColumn() : void
805
    {
Sergei Morozov's avatar
Sergei Morozov committed
806
        $sql = 'DELETE FROM fetch_table';
Sergei Morozov's avatar
Sergei Morozov committed
807
        $this->connection->executeUpdate($sql);
808

Sergei Morozov's avatar
Sergei Morozov committed
809 810
        $this->connection->insert('fetch_table', ['test_int' => 1, 'test_string' => 'foo']);
        $this->connection->insert('fetch_table', ['test_int' => 10, 'test_string' => 'foo']);
811

Sergei Morozov's avatar
Sergei Morozov committed
812
        $sql  = 'SELECT test_int FROM fetch_table';
Sergei Morozov's avatar
Sergei Morozov committed
813
        $rows = $this->connection->query($sql)->fetchAll(FetchMode::COLUMN);
814

Sergei Morozov's avatar
Sergei Morozov committed
815
        self::assertEquals([1, 10], $rows);
816
    }
817 818 819 820

    /**
     * @group DBAL-214
     */
821
    public function testSetFetchModeClassFetchAll() : void
822
    {
823
        $this->beforeFetchClassTest();
824 825
        $this->setupFixture();

Sergei Morozov's avatar
Sergei Morozov committed
826
        $sql  = 'SELECT * FROM fetch_table';
Sergei Morozov's avatar
Sergei Morozov committed
827 828
        $stmt = $this->connection->query($sql);
        $stmt->setFetchMode(FetchMode::CUSTOM_OBJECT, MyFetchClass::class);
829 830 831

        $results = $stmt->fetchAll();

Gabriel Caruso's avatar
Gabriel Caruso committed
832
        self::assertCount(1, $results);
Sergei Morozov's avatar
Sergei Morozov committed
833
        self::assertInstanceOf(MyFetchClass::class, $results[0]);
834

835 836 837
        self::assertEquals(1, $results[0]->test_int);
        self::assertEquals('foo', $results[0]->test_string);
        self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
838 839 840 841 842
    }

    /**
     * @group DBAL-214
     */
843
    public function testSetFetchModeClassFetch() : void
844
    {
845
        $this->beforeFetchClassTest();
846 847
        $this->setupFixture();

Sergei Morozov's avatar
Sergei Morozov committed
848
        $sql  = 'SELECT * FROM fetch_table';
Sergei Morozov's avatar
Sergei Morozov committed
849 850
        $stmt = $this->connection->query($sql);
        $stmt->setFetchMode(FetchMode::CUSTOM_OBJECT, MyFetchClass::class);
851

Sergei Morozov's avatar
Sergei Morozov committed
852
        $results = [];
853 854 855 856
        while ($row = $stmt->fetch()) {
            $results[] = $row;
        }

Gabriel Caruso's avatar
Gabriel Caruso committed
857
        self::assertCount(1, $results);
Sergei Morozov's avatar
Sergei Morozov committed
858
        self::assertInstanceOf(MyFetchClass::class, $results[0]);
859

860 861 862
        self::assertEquals(1, $results[0]->test_int);
        self::assertEquals('foo', $results[0]->test_string);
        self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
863 864
    }

865 866 867
    /**
     * @group DBAL-257
     */
868
    public function testEmptyFetchColumnReturnsFalse() : void
869
    {
Sergei Morozov's avatar
Sergei Morozov committed
870 871 872 873 874
        $this->connection->beginTransaction();
        $this->connection->exec('DELETE FROM fetch_table');
        self::assertFalse($this->connection->fetchColumn('SELECT test_int FROM fetch_table'));
        self::assertFalse($this->connection->query('SELECT test_int FROM fetch_table')->fetchColumn());
        $this->connection->rollBack();
875 876
    }

877 878 879
    /**
     * @group DBAL-339
     */
880
    public function testSetFetchModeOnDbalStatement() : void
881
    {
Sergei Morozov's avatar
Sergei Morozov committed
882
        $sql  = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
Sergei Morozov's avatar
Sergei Morozov committed
883
        $stmt = $this->connection->executeQuery($sql, [1, 'foo']);
884
        $stmt->setFetchMode(FetchMode::NUMERIC);
885

Luís Cobucci's avatar
Luís Cobucci committed
886 887 888 889 890
        $row = $stmt->fetch();

        self::assertArrayHasKey(0, $row);
        self::assertArrayHasKey(1, $row);
        self::assertFalse($stmt->fetch());
891 892
    }

893 894 895
    /**
     * @group DBAL-435
     */
896
    public function testEmptyParameters() : void
897
    {
Sergei Morozov's avatar
Sergei Morozov committed
898
        $sql  = 'SELECT * FROM fetch_table WHERE test_int IN (?)';
Sergei Morozov's avatar
Sergei Morozov committed
899
        $stmt = $this->connection->executeQuery($sql, [[]], [Connection::PARAM_INT_ARRAY]);
900 901
        $rows = $stmt->fetchAll();

Sergei Morozov's avatar
Sergei Morozov committed
902
        self::assertEquals([], $rows);
903 904
    }

905 906 907
    /**
     * @group DBAL-1028
     */
908
    public function testFetchColumnNullValue() : void
909
    {
Sergei Morozov's avatar
Sergei Morozov committed
910
        $this->connection->executeUpdate(
911
            'INSERT INTO fetch_table (test_int, test_string) VALUES (?, ?)',
Sergei Morozov's avatar
Sergei Morozov committed
912
            [2, 'foo']
913 914
        );

915
        self::assertNull(
Sergei Morozov's avatar
Sergei Morozov committed
916
            $this->connection->fetchColumn('SELECT test_datetime FROM fetch_table WHERE test_int = ?', [2])
917 918 919 920 921 922
        );
    }

    /**
     * @group DBAL-1028
     */
923
    public function testFetchColumnNoResult() : void
924
    {
925
        self::assertFalse(
Sergei Morozov's avatar
Sergei Morozov committed
926
            $this->connection->fetchColumn('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1])
927 928 929
        );
    }

930
    private function setupFixture() : void
931
    {
Sergei Morozov's avatar
Sergei Morozov committed
932 933
        $this->connection->exec('DELETE FROM fetch_table');
        $this->connection->insert('fetch_table', [
934 935
            'test_int'      => 1,
            'test_string'   => 'foo',
Sergei Morozov's avatar
Sergei Morozov committed
936 937
            'test_datetime' => '2010-01-01 10:10:10',
        ]);
938 939
    }

940
    private function beforeFetchClassTest() : void
941
    {
942 943 944
        $driver = $this->connection->getDriver();

        if ($driver instanceof Oci8Driver) {
Sergei Morozov's avatar
Sergei Morozov committed
945
            $this->markTestSkipped('Not supported by OCI8');
946
        }
947 948 949 950 951 952

        if ($driver instanceof MySQLiDriver) {
            $this->markTestSkipped('Mysqli driver dont support this feature.');
        }

        if (! $driver instanceof PDOOracleDriver) {
Sergei Morozov's avatar
Sergei Morozov committed
953
            return;
954
        }
Sergei Morozov's avatar
Sergei Morozov committed
955

956
        $connection = $this->connection->getWrappedConnection();
957
        self::assertInstanceOf(PDOConnection::class, $connection);
958
        $connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
959
    }
Fabio B. Silva's avatar
Fabio B. Silva committed
960 961 962 963
}

class MyFetchClass
{
Sergei Morozov's avatar
Sergei Morozov committed
964 965 966 967 968 969 970 971
    /** @var int */
    public $test_int;

    /** @var string */
    public $test_string;

    /** @var string */
    public $test_datetime;
972
}