Passed
Push — master ( 79c732...041d44 )
by Sergei
46:55 queued 43:06
created

testSqliteDateArithmeticWithDynamicInterval()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 15
nc 2
nop 0
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\FetchMode;
7
use Doctrine\DBAL\ParameterType;
8
use Doctrine\DBAL\Platforms\SqlitePlatform;
9
use Doctrine\DBAL\Platforms\TrimMode;
10
use Doctrine\DBAL\Schema\Table;
11
use Doctrine\DBAL\Types\Type;
12
use const CASE_LOWER;
13
use const PHP_EOL;
14
use function array_change_key_case;
15
use function array_filter;
16
use function array_keys;
17
use function count;
18
use function date;
19
use function implode;
20
use function is_numeric;
21
use function json_encode;
22
use function property_exists;
23
use function strtotime;
24
25
class DataAccessTest extends \Doctrine\Tests\DbalFunctionalTestCase
26
{
27
    /**
28
     * @var bool
29
     */
30
    static private $generated = false;
31
32
    protected function setUp()
33
    {
34
        parent::setUp();
35
36
        if (self::$generated === false) {
37
            /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
38
            $table = new \Doctrine\DBAL\Schema\Table("fetch_table");
39
            $table->addColumn('test_int', 'integer');
40
            $table->addColumn('test_string', 'string');
41
            $table->addColumn('test_datetime', 'datetime', array('notnull' => false));
42
            $table->setPrimaryKey(array('test_int'));
43
44
            $sm = $this->_conn->getSchemaManager();
45
            $sm->createTable($table);
46
47
            $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo', 'test_datetime' => '2010-01-01 10:10:10'));
48
            self::$generated = true;
49
        }
50
    }
51
52
    public function testPrepareWithBindValue()
53
    {
54
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
55
        $stmt = $this->_conn->prepare($sql);
56
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
57
58
        $stmt->bindValue(1, 1);
59
        $stmt->bindValue(2, 'foo');
60
        $stmt->execute();
61
62
        $row = $stmt->fetch(FetchMode::ASSOCIATIVE);
63
        $row = array_change_key_case($row, \CASE_LOWER);
64
        self::assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
65
    }
66
67
    public function testPrepareWithBindParam()
68
    {
69
        $paramInt = 1;
70
        $paramStr = 'foo';
71
72
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
73
        $stmt = $this->_conn->prepare($sql);
74
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
75
76
        $stmt->bindParam(1, $paramInt);
77
        $stmt->bindParam(2, $paramStr);
78
        $stmt->execute();
79
80
        $row = $stmt->fetch(FetchMode::ASSOCIATIVE);
81
        $row = array_change_key_case($row, \CASE_LOWER);
82
        self::assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
83
    }
84
85
    public function testPrepareWithFetchAll()
86
    {
87
        $paramInt = 1;
88
        $paramStr = 'foo';
89
90
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
91
        $stmt = $this->_conn->prepare($sql);
92
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
93
94
        $stmt->bindParam(1, $paramInt);
95
        $stmt->bindParam(2, $paramStr);
96
        $stmt->execute();
97
98
        $rows    = $stmt->fetchAll(FetchMode::ASSOCIATIVE);
99
        $rows[0] = array_change_key_case($rows[0], \CASE_LOWER);
100
        self::assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]);
101
    }
102
103
    /**
104
     * @group DBAL-228
105
     */
106
    public function testPrepareWithFetchAllBoth()
107
    {
108
        $paramInt = 1;
109
        $paramStr = 'foo';
110
111
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
112
        $stmt = $this->_conn->prepare($sql);
113
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
114
115
        $stmt->bindParam(1, $paramInt);
116
        $stmt->bindParam(2, $paramStr);
117
        $stmt->execute();
118
119
        $rows    = $stmt->fetchAll(FetchMode::MIXED);
120
        $rows[0] = array_change_key_case($rows[0], \CASE_LOWER);
121
        self::assertEquals(array('test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'), $rows[0]);
122
    }
123
124
    public function testPrepareWithFetchColumn()
125
    {
126
        $paramInt = 1;
127
        $paramStr = 'foo';
128
129
        $sql = "SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?";
130
        $stmt = $this->_conn->prepare($sql);
131
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
132
133
        $stmt->bindParam(1, $paramInt);
134
        $stmt->bindParam(2, $paramStr);
135
        $stmt->execute();
136
137
        $column = $stmt->fetchColumn();
138
        self::assertEquals(1, $column);
139
    }
140
141
    public function testPrepareWithIterator()
142
    {
143
        $paramInt = 1;
144
        $paramStr = 'foo';
145
146
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
147
        $stmt = $this->_conn->prepare($sql);
148
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
149
150
        $stmt->bindParam(1, $paramInt);
151
        $stmt->bindParam(2, $paramStr);
152
        $stmt->execute();
153
154
        $rows = array();
155
        $stmt->setFetchMode(FetchMode::ASSOCIATIVE);
156
        foreach ($stmt as $row) {
157
            $rows[] = array_change_key_case($row, \CASE_LOWER);
158
        }
159
160
        self::assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]);
161
    }
162
163
    public function testPrepareWithQuoted()
164
    {
165
        $table = 'fetch_table';
166
        $paramInt = 1;
167
        $paramStr = 'foo';
168
169
        $sql = "SELECT test_int, test_string FROM " . $this->_conn->quoteIdentifier($table) . " ".
170
               "WHERE test_int = " . $this->_conn->quote($paramInt) . " AND test_string = " . $this->_conn->quote($paramStr);
171
        $stmt = $this->_conn->prepare($sql);
172
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
173
    }
174
175
    public function testPrepareWithExecuteParams()
176
    {
177
        $paramInt = 1;
178
        $paramStr = 'foo';
179
180
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
181
        $stmt = $this->_conn->prepare($sql);
182
        self::assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
183
        $stmt->execute(array($paramInt, $paramStr));
184
185
        $row = $stmt->fetch(FetchMode::ASSOCIATIVE);
186
        self::assertNotFalse($row);
187
        $row = array_change_key_case($row, \CASE_LOWER);
188
        self::assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
189
    }
190
191
    public function testFetchAll()
192
    {
193
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
194
        $data = $this->_conn->fetchAll($sql, array(1, 'foo'));
195
196
        self::assertCount(1, $data);
197
198
        $row = $data[0];
199
        self::assertCount(2, $row);
200
201
        $row = array_change_key_case($row, \CASE_LOWER);
202
        self::assertEquals(1, $row['test_int']);
203
        self::assertEquals('foo', $row['test_string']);
204
    }
205
206
    /**
207
     * @group DBAL-209
208
     */
209
    public function testFetchAllWithTypes()
210
    {
211
        $datetimeString = '2010-01-01 10:10:10';
212
        $datetime = new \DateTime($datetimeString);
213
214
        $sql  = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
215
        $data = $this->_conn->fetchAll($sql, [1, $datetime], [ParameterType::STRING, Type::DATETIME]);
216
217
        self::assertCount(1, $data);
218
219
        $row = $data[0];
220
        self::assertCount(2, $row);
221
222
        $row = array_change_key_case($row, \CASE_LOWER);
223
        self::assertEquals(1, $row['test_int']);
224
        self::assertStringStartsWith($datetimeString, $row['test_datetime']);
225
    }
226
227
    /**
228
     * @group DBAL-209
229
     * @expectedException \Doctrine\DBAL\DBALException
230
     */
231
    public function testFetchAllWithMissingTypes()
232
    {
233
        if ($this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\Mysqli\Driver ||
234
            $this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\SQLSrv\Driver) {
235
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
236
        }
237
238
        $datetimeString = '2010-01-01 10:10:10';
239
        $datetime = new \DateTime($datetimeString);
240
        $sql = "SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?";
241
        $data = $this->_conn->fetchAll($sql, array(1, $datetime));
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
242
    }
243
244
    public function testFetchBoth()
245
    {
246
        $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?';
247
        $row = $this->_conn->executeQuery($sql, [1, 'foo'])->fetch(FetchMode::MIXED);
248
249
        self::assertNotFalse($row);
250
251
        $row = array_change_key_case($row, \CASE_LOWER);
252
253
        self::assertEquals(1, $row['test_int']);
254
        self::assertEquals('foo', $row['test_string']);
255
        self::assertEquals(1, $row[0]);
256
        self::assertEquals('foo', $row[1]);
257
    }
258
259
    public function testFetchNoResult()
260
    {
261
        self::assertFalse(
262
            $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1])->fetch()
263
        );
264
    }
265
266
    public function testFetchAssoc()
267
    {
268
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
269
        $row = $this->_conn->fetchAssoc($sql, array(1, 'foo'));
270
271
        self::assertNotFalse($row);
272
273
        $row = array_change_key_case($row, \CASE_LOWER);
0 ignored issues
show
Bug introduced by
It seems like $row can also be of type boolean; however, parameter $input of array_change_key_case() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

273
        $row = array_change_key_case(/** @scrutinizer ignore-type */ $row, \CASE_LOWER);
Loading history...
274
275
        self::assertEquals(1, $row['test_int']);
276
        self::assertEquals('foo', $row['test_string']);
277
    }
278
279
    public function testFetchAssocWithTypes()
280
    {
281
        $datetimeString = '2010-01-01 10:10:10';
282
        $datetime = new \DateTime($datetimeString);
283
284
        $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
285
        $row = $this->_conn->fetchAssoc($sql, [1, $datetime], [ParameterType::STRING, Type::DATETIME]);
286
287
        self::assertNotFalse($row);
288
289
        $row = array_change_key_case($row, \CASE_LOWER);
0 ignored issues
show
Bug introduced by
It seems like $row can also be of type boolean; however, parameter $input of array_change_key_case() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

289
        $row = array_change_key_case(/** @scrutinizer ignore-type */ $row, \CASE_LOWER);
Loading history...
290
291
        self::assertEquals(1, $row['test_int']);
292
        self::assertStringStartsWith($datetimeString, $row['test_datetime']);
293
    }
294
295
    /**
296
     * @expectedException \Doctrine\DBAL\DBALException
297
     */
298
    public function testFetchAssocWithMissingTypes()
299
    {
300
        if ($this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\Mysqli\Driver ||
301
            $this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\SQLSrv\Driver) {
302
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
303
        }
304
305
        $datetimeString = '2010-01-01 10:10:10';
306
        $datetime = new \DateTime($datetimeString);
307
        $sql = "SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?";
308
        $row = $this->_conn->fetchAssoc($sql, array(1, $datetime));
0 ignored issues
show
Unused Code introduced by
The assignment to $row is dead and can be removed.
Loading history...
309
    }
310
311
    public function testFetchArray()
312
    {
313
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
314
        $row = $this->_conn->fetchArray($sql, array(1, 'foo'));
315
316
        self::assertEquals(1, $row[0]);
317
        self::assertEquals('foo', $row[1]);
318
    }
319
320
    public function testFetchArrayWithTypes()
321
    {
322
        $datetimeString = '2010-01-01 10:10:10';
323
        $datetime = new \DateTime($datetimeString);
324
325
        $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
326
        $row = $this->_conn->fetchArray($sql, [1, $datetime], [ParameterType::STRING, Type::DATETIME]);
327
328
        self::assertNotFalse($row);
329
330
        $row = array_change_key_case($row, \CASE_LOWER);
0 ignored issues
show
Bug introduced by
It seems like $row can also be of type boolean; however, parameter $input of array_change_key_case() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

330
        $row = array_change_key_case(/** @scrutinizer ignore-type */ $row, \CASE_LOWER);
Loading history...
331
332
        self::assertEquals(1, $row[0]);
333
        self::assertStringStartsWith($datetimeString, $row[1]);
334
    }
335
336
    /**
337
     * @expectedException \Doctrine\DBAL\DBALException
338
     */
339
    public function testFetchArrayWithMissingTypes()
340
    {
341
        if ($this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\Mysqli\Driver ||
342
            $this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\SQLSrv\Driver) {
343
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
344
        }
345
346
        $datetimeString = '2010-01-01 10:10:10';
347
        $datetime = new \DateTime($datetimeString);
348
        $sql = "SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?";
349
        $row = $this->_conn->fetchArray($sql, array(1, $datetime));
0 ignored issues
show
Unused Code introduced by
The assignment to $row is dead and can be removed.
Loading history...
350
    }
351
352
    public function testFetchColumn()
353
    {
354
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
355
        $testInt = $this->_conn->fetchColumn($sql, array(1, 'foo'), 0);
356
357
        self::assertEquals(1, $testInt);
358
359
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
360
        $testString = $this->_conn->fetchColumn($sql, array(1, 'foo'), 1);
361
362
        self::assertEquals('foo', $testString);
363
    }
364
365
    public function testFetchColumnWithTypes()
366
    {
367
        $datetimeString = '2010-01-01 10:10:10';
368
        $datetime = new \DateTime($datetimeString);
369
370
        $sql    = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?';
371
        $column = $this->_conn->fetchColumn($sql, [1, $datetime], 1, [ParameterType::STRING, Type::DATETIME]);
372
373
        self::assertNotFalse($column);
374
375
        self::assertStringStartsWith($datetimeString, $column);
0 ignored issues
show
Bug introduced by
It seems like $column can also be of type boolean; however, parameter $string of PHPUnit\Framework\Assert::assertStringStartsWith() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

375
        self::assertStringStartsWith($datetimeString, /** @scrutinizer ignore-type */ $column);
Loading history...
376
    }
377
378
    /**
379
     * @expectedException \Doctrine\DBAL\DBALException
380
     */
381
    public function testFetchColumnWithMissingTypes()
382
    {
383
        if ($this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\Mysqli\Driver ||
384
            $this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\SQLSrv\Driver) {
385
            $this->markTestSkipped('mysqli and sqlsrv actually supports this');
386
        }
387
388
        $datetimeString = '2010-01-01 10:10:10';
389
        $datetime = new \DateTime($datetimeString);
390
        $sql = "SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?";
391
        $column = $this->_conn->fetchColumn($sql, array(1, $datetime), 1);
0 ignored issues
show
Unused Code introduced by
The assignment to $column is dead and can be removed.
Loading history...
392
    }
393
394
    /**
395
     * @group DDC-697
396
     */
397
    public function testExecuteQueryBindDateTimeType()
398
    {
399
        $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
400
        $stmt = $this->_conn->executeQuery($sql,
401
            array(1 => new \DateTime('2010-01-01 10:10:10')),
402
            array(1 => Type::DATETIME)
403
        );
404
405
        self::assertEquals(1, $stmt->fetchColumn());
406
    }
407
408
    /**
409
     * @group DDC-697
410
     */
411
    public function testExecuteUpdateBindDateTimeType()
412
    {
413
        $datetime = new \DateTime('2010-02-02 20:20:20');
414
415
        $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)';
416
        $affectedRows = $this->_conn->executeUpdate($sql, [
417
            1 => 50,
418
            2 => 'foo',
419
            3 => $datetime,
420
        ], [
421
            1 => ParameterType::INTEGER,
422
            2 => ParameterType::STRING,
423
            3 => Type::DATETIME,
424
        ]);
425
426
        self::assertEquals(1, $affectedRows);
427
        self::assertEquals(1, $this->_conn->executeQuery(
428
            'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?',
429
            array(1 => $datetime),
430
            array(1 => Type::DATETIME)
431
        )->fetchColumn());
432
    }
433
434
    /**
435
     * @group DDC-697
436
     */
437
    public function testPrepareQueryBindValueDateTimeType()
438
    {
439
        $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
440
        $stmt = $this->_conn->prepare($sql);
441
        $stmt->bindValue(1, new \DateTime('2010-01-01 10:10:10'), Type::DATETIME);
442
        $stmt->execute();
443
444
        self::assertEquals(1, $stmt->fetchColumn());
445
    }
446
447
    /**
448
     * @group DBAL-78
449
     */
450
    public function testNativeArrayListSupport()
451
    {
452
        for ($i = 100; $i < 110; $i++) {
453
            $this->_conn->insert('fetch_table', array('test_int' => $i, 'test_string' => 'foo' . $i, 'test_datetime' => '2010-01-01 10:10:10'));
454
        }
455
456
        $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_int IN (?)',
457
            array(array(100, 101, 102, 103, 104)), array(Connection::PARAM_INT_ARRAY));
458
459
        $data = $stmt->fetchAll(FetchMode::NUMERIC);
460
        self::assertCount(5, $data);
461
        self::assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
462
463
        $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_string IN (?)',
464
            array(array('foo100', 'foo101', 'foo102', 'foo103', 'foo104')), array(Connection::PARAM_STR_ARRAY));
465
466
        $data = $stmt->fetchAll(FetchMode::NUMERIC);
467
        self::assertCount(5, $data);
468
        self::assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
469
    }
470
471
    /**
472
     * @dataProvider getTrimExpressionData
473
     */
474
    public function testTrimExpression($value, $position, $char, $expectedResult)
475
    {
476
        $sql = 'SELECT ' .
477
            $this->_conn->getDatabasePlatform()->getTrimExpression($value, $position, $char) . ' AS trimmed ' .
478
            'FROM fetch_table';
479
480
        $row = $this->_conn->fetchAssoc($sql);
481
        $row = array_change_key_case($row, CASE_LOWER);
0 ignored issues
show
Bug introduced by
It seems like $row can also be of type boolean; however, parameter $input of array_change_key_case() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

481
        $row = array_change_key_case(/** @scrutinizer ignore-type */ $row, CASE_LOWER);
Loading history...
482
483
        self::assertEquals($expectedResult, $row['trimmed']);
484
    }
485
486
    public function getTrimExpressionData()
487
    {
488
        return array(
489
            ['test_string', TrimMode::UNSPECIFIED, false, 'foo'],
490
            ['test_string', TrimMode::LEADING, false, 'foo'],
491
            ['test_string', TrimMode::TRAILING, false, 'foo'],
492
            ['test_string', TrimMode::BOTH, false, 'foo'],
493
            ['test_string', TrimMode::UNSPECIFIED, "'f'", 'oo'],
494
            ['test_string', TrimMode::UNSPECIFIED, "'o'", 'f'],
495
            ['test_string', TrimMode::UNSPECIFIED, "'.'", 'foo'],
496
            ['test_string', TrimMode::LEADING, "'f'", 'oo'],
497
            ['test_string', TrimMode::LEADING, "'o'", 'foo'],
498
            ['test_string', TrimMode::LEADING, "'.'", 'foo'],
499
            ['test_string', TrimMode::TRAILING, "'f'", 'foo'],
500
            ['test_string', TrimMode::TRAILING, "'o'", 'f'],
501
            ['test_string', TrimMode::TRAILING, "'.'", 'foo'],
502
            ['test_string', TrimMode::BOTH, "'f'", 'oo'],
503
            ['test_string', TrimMode::BOTH, "'o'", 'f'],
504
            ['test_string', TrimMode::BOTH, "'.'", 'foo'],
505
            ["' foo '", TrimMode::UNSPECIFIED, false, 'foo'],
506
            ["' foo '", TrimMode::LEADING, false, 'foo '],
507
            ["' foo '", TrimMode::TRAILING, false, ' foo'],
508
            ["' foo '", TrimMode::BOTH, false, 'foo'],
509
            ["' foo '", TrimMode::UNSPECIFIED, "'f'", ' foo '],
510
            ["' foo '", TrimMode::UNSPECIFIED, "'o'", ' foo '],
511
            ["' foo '", TrimMode::UNSPECIFIED, "'.'", ' foo '],
512
            ["' foo '", TrimMode::UNSPECIFIED, "' '", 'foo'],
513
            ["' foo '", TrimMode::LEADING, "'f'", ' foo '],
514
            ["' foo '", TrimMode::LEADING, "'o'", ' foo '],
515
            ["' foo '", TrimMode::LEADING, "'.'", ' foo '],
516
            ["' foo '", TrimMode::LEADING, "' '", 'foo '],
517
            ["' foo '", TrimMode::TRAILING, "'f'", ' foo '],
518
            ["' foo '", TrimMode::TRAILING, "'o'", ' foo '],
519
            ["' foo '", TrimMode::TRAILING, "'.'", ' foo '],
520
            ["' foo '", TrimMode::TRAILING, "' '", ' foo'],
521
            ["' foo '", TrimMode::BOTH, "'f'", ' foo '],
522
            ["' foo '", TrimMode::BOTH, "'o'", ' foo '],
523
            ["' foo '", TrimMode::BOTH, "'.'", ' foo '],
524
            ["' foo '", TrimMode::BOTH, "' '", 'foo'],
525
        );
526
    }
527
528
    /**
529
     * @group DDC-1014
530
     */
531
    public function testDateArithmetics()
532
    {
533
        $p = $this->_conn->getDatabasePlatform();
534
        $sql = 'SELECT ';
535
        $sql .= $p->getDateAddSecondsExpression('test_datetime', 1) .' AS add_seconds, ';
536
        $sql .= $p->getDateSubSecondsExpression('test_datetime', 1) .' AS sub_seconds, ';
537
        $sql .= $p->getDateAddMinutesExpression('test_datetime', 5) .' AS add_minutes, ';
538
        $sql .= $p->getDateSubMinutesExpression('test_datetime', 5) .' AS sub_minutes, ';
539
        $sql .= $p->getDateAddHourExpression('test_datetime', 3) .' AS add_hour, ';
540
        $sql .= $p->getDateSubHourExpression('test_datetime', 3) .' AS sub_hour, ';
541
        $sql .= $p->getDateAddDaysExpression('test_datetime', 10) .' AS add_days, ';
542
        $sql .= $p->getDateSubDaysExpression('test_datetime', 10) .' AS sub_days, ';
543
        $sql .= $p->getDateAddWeeksExpression('test_datetime', 1) .' AS add_weeks, ';
544
        $sql .= $p->getDateSubWeeksExpression('test_datetime', 1) .' AS sub_weeks, ';
545
        $sql .= $p->getDateAddMonthExpression('test_datetime', 2) .' AS add_month, ';
546
        $sql .= $p->getDateSubMonthExpression('test_datetime', 2) .' AS sub_month, ';
547
        $sql .= $p->getDateAddQuartersExpression('test_datetime', 3) .' AS add_quarters, ';
548
        $sql .= $p->getDateSubQuartersExpression('test_datetime', 3) .' AS sub_quarters, ';
549
        $sql .= $p->getDateAddYearsExpression('test_datetime', 6) .' AS add_years, ';
550
        $sql .= $p->getDateSubYearsExpression('test_datetime', 6) .' AS sub_years ';
551
        $sql .= 'FROM fetch_table';
552
553
        $row = $this->_conn->fetchAssoc($sql);
554
        $row = array_change_key_case($row, CASE_LOWER);
555
556
        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");
557
        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");
558
        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");
559
        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");
560
        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");
561
        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");
562
        self::assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), "Adding date should end up on 2010-01-11");
563
        self::assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), "Subtracting date should end up on 2009-12-22");
564
        self::assertEquals('2010-01-08', date('Y-m-d', strtotime($row['add_weeks'])), "Adding week should end up on 2010-01-08");
565
        self::assertEquals('2009-12-25', date('Y-m-d', strtotime($row['sub_weeks'])), "Subtracting week should end up on 2009-12-25");
566
        self::assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), "Adding month should end up on 2010-03-01");
567
        self::assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), "Subtracting month should end up on 2009-11-01");
568
        self::assertEquals('2010-10-01', date('Y-m-d', strtotime($row['add_quarters'])), "Adding quarters should end up on 2010-04-01");
569
        self::assertEquals('2009-04-01', date('Y-m-d', strtotime($row['sub_quarters'])), "Subtracting quarters should end up on 2009-10-01");
570
        self::assertEquals('2016-01-01', date('Y-m-d', strtotime($row['add_years'])), "Adding years should end up on 2016-01-01");
571
        self::assertEquals('2004-01-01', date('Y-m-d', strtotime($row['sub_years'])), "Subtracting years should end up on 2004-01-01");
572
    }
573
574
    public function testSqliteDateArithmeticWithDynamicInterval()
575
    {
576
        $platform = $this->_conn->getDatabasePlatform();
577
578
        if (! $platform instanceof SqlitePlatform) {
579
            $this->markTestSkipped('test is for sqlite only');
580
        }
581
582
        $table = new Table('fetch_table_date_math');
583
        $table->addColumn('test_date', 'date');
584
        $table->addColumn('test_days', 'integer');
585
        $table->setPrimaryKey(['test_date']);
586
587
        /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
588
        $sm = $this->_conn->getSchemaManager();
589
        $sm->createTable($table);
590
591
        $this->_conn->insert('fetch_table_date_math', ['test_date' => '2010-01-01', 'test_days' => 10]);
592
        $this->_conn->insert('fetch_table_date_math', ['test_date' => '2010-06-01', 'test_days' => 20]);
593
594
        $sql  = 'SELECT COUNT(*) FROM fetch_table_date_math WHERE ';
595
        $sql .= $platform->getDateSubDaysExpression('test_date', 'test_days') . " < '2010-05-12'";
0 ignored issues
show
Bug introduced by
'test_days' of type string is incompatible with the type integer expected by parameter $days of Doctrine\DBAL\Platforms\...DateSubDaysExpression(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

595
        $sql .= $platform->getDateSubDaysExpression('test_date', /** @scrutinizer ignore-type */ 'test_days') . " < '2010-05-12'";
Loading history...
596
597
        $rowCount = $this->_conn->fetchColumn($sql, [], 0);
598
599
        $this->assertEquals(1, $rowCount);
600
    }
601
602
    public function testLocateExpression()
603
    {
604
        $platform = $this->_conn->getDatabasePlatform();
605
606
        $sql = 'SELECT ';
607
        $sql .= $platform->getLocateExpression('test_string', "'oo'") .' AS locate1, ';
608
        $sql .= $platform->getLocateExpression('test_string', "'foo'") .' AS locate2, ';
609
        $sql .= $platform->getLocateExpression('test_string', "'bar'") .' AS locate3, ';
610
        $sql .= $platform->getLocateExpression('test_string', 'test_string') .' AS locate4, ';
611
        $sql .= $platform->getLocateExpression("'foo'", 'test_string') .' AS locate5, ';
612
        $sql .= $platform->getLocateExpression("'barfoobaz'", 'test_string') .' AS locate6, ';
613
        $sql .= $platform->getLocateExpression("'bar'", 'test_string') .' AS locate7, ';
614
        $sql .= $platform->getLocateExpression('test_string', "'oo'", 2) .' AS locate8, ';
615
        $sql .= $platform->getLocateExpression('test_string', "'oo'", 3) .' AS locate9 ';
616
        $sql .= 'FROM fetch_table';
617
618
        $row = $this->_conn->fetchAssoc($sql);
619
        $row = array_change_key_case($row, CASE_LOWER);
620
621
        self::assertEquals(2, $row['locate1']);
622
        self::assertEquals(1, $row['locate2']);
623
        self::assertEquals(0, $row['locate3']);
624
        self::assertEquals(1, $row['locate4']);
625
        self::assertEquals(1, $row['locate5']);
626
        self::assertEquals(4, $row['locate6']);
627
        self::assertEquals(0, $row['locate7']);
628
        self::assertEquals(2, $row['locate8']);
629
        self::assertEquals(0, $row['locate9']);
630
    }
631
632
    public function testQuoteSQLInjection()
633
    {
634
        $sql = "SELECT * FROM fetch_table WHERE test_string = " . $this->_conn->quote("bar' OR '1'='1");
635
        $rows = $this->_conn->fetchAll($sql);
636
637
        self::assertCount(0, $rows, "no result should be returned, otherwise SQL injection is possible");
638
    }
639
640
    /**
641
     * @group DDC-1213
642
     */
643
    public function testBitComparisonExpressionSupport()
644
    {
645
        $this->_conn->exec('DELETE FROM fetch_table');
646
        $platform = $this->_conn->getDatabasePlatform();
647
        $bitmap   = array();
648
649
        for ($i = 2; $i < 9; $i = $i + 2) {
650
            $bitmap[$i] = array(
651
                'bit_or'    => ($i | 2),
652
                'bit_and'   => ($i & 2)
653
            );
654
            $this->_conn->insert('fetch_table', array(
655
                'test_int'      => $i,
656
                'test_string'   => json_encode($bitmap[$i]),
657
                'test_datetime' => '2010-01-01 10:10:10'
658
            ));
659
        }
660
661
        $sql[]  = 'SELECT ';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$sql was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sql = array(); before regardless.
Loading history...
662
        $sql[]  = 'test_int, ';
663
        $sql[]  = 'test_string, ';
664
        $sql[]  = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, ';
665
        $sql[]  = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and ';
666
        $sql[]  = 'FROM fetch_table';
667
668
        $stmt = $this->_conn->executeQuery(implode(PHP_EOL, $sql));
669
        $data = $stmt->fetchAll(FetchMode::ASSOCIATIVE);
670
671
672
        self::assertCount(4, $data);
673
        self::assertEquals(count($bitmap), count($data));
674
        foreach ($data as $row) {
675
            $row = array_change_key_case($row, CASE_LOWER);
676
677
            self::assertArrayHasKey('test_int', $row);
678
679
            $id = $row['test_int'];
680
681
            self::assertArrayHasKey($id, $bitmap);
682
            self::assertArrayHasKey($id, $bitmap);
683
684
            self::assertArrayHasKey('bit_or', $row);
685
            self::assertArrayHasKey('bit_and', $row);
686
687
            self::assertEquals($row['bit_or'], $bitmap[$id]['bit_or']);
688
            self::assertEquals($row['bit_and'], $bitmap[$id]['bit_and']);
689
        }
690
    }
691
692
    public function testSetDefaultFetchMode()
693
    {
694
        $stmt = $this->_conn->query("SELECT * FROM fetch_table");
695
        $stmt->setFetchMode(FetchMode::NUMERIC);
696
697
        $row = array_keys($stmt->fetch());
698
        self::assertCount(0, array_filter($row, function($v) { return ! is_numeric($v); }), "should be no non-numerical elements in the result.");
699
    }
700
701
    /**
702
     * @group DBAL-1091
703
     */
704
    public function testFetchAllStyleObject()
705
    {
706
        $this->setupFixture();
707
708
        $sql = 'SELECT test_int, test_string, test_datetime FROM fetch_table';
709
        $stmt = $this->_conn->prepare($sql);
710
711
        $stmt->execute();
712
713
        $results = $stmt->fetchAll(FetchMode::STANDARD_OBJECT);
714
715
        self::assertCount(1, $results);
716
        self::assertInstanceOf('stdClass', $results[0]);
717
718
        self::assertEquals(
719
            1,
720
            property_exists($results[0], 'test_int') ? $results[0]->test_int : $results[0]->TEST_INT
721
        );
722
        self::assertEquals(
723
            'foo',
724
            property_exists($results[0], 'test_string') ? $results[0]->test_string : $results[0]->TEST_STRING
725
        );
726
        self::assertStringStartsWith(
727
            '2010-01-01 10:10:10',
728
            property_exists($results[0], 'test_datetime') ? $results[0]->test_datetime : $results[0]->TEST_DATETIME
729
        );
730
    }
731
732
    /**
733
     * @group DBAL-196
734
     */
735
    public function testFetchAllSupportFetchClass()
736
    {
737
        $this->skipOci8AndMysqli();
738
        $this->setupFixture();
739
740
        $sql    = "SELECT test_int, test_string, test_datetime FROM fetch_table";
741
        $stmt   = $this->_conn->prepare($sql);
742
        $stmt->execute();
743
744
        $results = $stmt->fetchAll(
745
            FetchMode::CUSTOM_OBJECT,
746
            __NAMESPACE__.'\\MyFetchClass'
747
        );
748
749
        self::assertCount(1, $results);
750
        self::assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
751
752
        self::assertEquals(1, $results[0]->test_int);
753
        self::assertEquals('foo', $results[0]->test_string);
754
        self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
755
    }
756
757
    /**
758
     * @group DBAL-241
759
     */
760
    public function testFetchAllStyleColumn()
761
    {
762
        $sql = "DELETE FROM fetch_table";
763
        $this->_conn->executeUpdate($sql);
764
765
        $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo'));
766
        $this->_conn->insert('fetch_table', array('test_int' => 10, 'test_string' => 'foo'));
767
768
        $sql = "SELECT test_int FROM fetch_table";
769
        $rows = $this->_conn->query($sql)->fetchAll(FetchMode::COLUMN);
770
771
        self::assertEquals(array(1, 10), $rows);
772
    }
773
774
    /**
775
     * @group DBAL-214
776
     */
777
    public function testSetFetchModeClassFetchAll()
778
    {
779
        $this->skipOci8AndMysqli();
780
        $this->setupFixture();
781
782
        $sql = "SELECT * FROM fetch_table";
783
        $stmt = $this->_conn->query($sql);
784
        $stmt->setFetchMode(FetchMode::CUSTOM_OBJECT, __NAMESPACE__ . '\\MyFetchClass');
785
786
        $results = $stmt->fetchAll();
787
788
        self::assertCount(1, $results);
789
        self::assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
790
791
        self::assertEquals(1, $results[0]->test_int);
792
        self::assertEquals('foo', $results[0]->test_string);
793
        self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
794
    }
795
796
    /**
797
     * @group DBAL-214
798
     */
799
    public function testSetFetchModeClassFetch()
800
    {
801
        $this->skipOci8AndMysqli();
802
        $this->setupFixture();
803
804
        $sql = "SELECT * FROM fetch_table";
805
        $stmt = $this->_conn->query($sql);
806
        $stmt->setFetchMode(FetchMode::CUSTOM_OBJECT, __NAMESPACE__ . '\\MyFetchClass');
807
808
        $results = array();
809
        while ($row = $stmt->fetch()) {
810
            $results[] = $row;
811
        }
812
813
        self::assertCount(1, $results);
814
        self::assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
815
816
        self::assertEquals(1, $results[0]->test_int);
817
        self::assertEquals('foo', $results[0]->test_string);
818
        self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
819
    }
820
821
    /**
822
     * @group DBAL-257
823
     */
824
    public function testEmptyFetchColumnReturnsFalse()
825
    {
826
        $this->_conn->beginTransaction();
827
        $this->_conn->exec('DELETE FROM fetch_table');
828
        self::assertFalse($this->_conn->fetchColumn('SELECT test_int FROM fetch_table'));
829
        self::assertFalse($this->_conn->query('SELECT test_int FROM fetch_table')->fetchColumn());
830
        $this->_conn->rollBack();
831
    }
832
833
    /**
834
     * @group DBAL-339
835
     */
836
    public function testSetFetchModeOnDbalStatement()
837
    {
838
        $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
839
        $stmt = $this->_conn->executeQuery($sql, array(1, "foo"));
840
        $stmt->setFetchMode(FetchMode::NUMERIC);
841
842
        $row = $stmt->fetch();
843
844
        self::assertArrayHasKey(0, $row);
845
        self::assertArrayHasKey(1, $row);
846
        self::assertFalse($stmt->fetch());
847
    }
848
849
    /**
850
     * @group DBAL-435
851
     */
852
    public function testEmptyParameters()
853
    {
854
        $sql = "SELECT * FROM fetch_table WHERE test_int IN (?)";
855
        $stmt = $this->_conn->executeQuery($sql, array(array()), array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY));
856
        $rows = $stmt->fetchAll();
857
858
        self::assertEquals(array(), $rows);
859
    }
860
861
    /**
862
     * @group DBAL-1028
863
     */
864
    public function testFetchColumnNullValue()
865
    {
866
        $this->_conn->executeUpdate(
867
            'INSERT INTO fetch_table (test_int, test_string) VALUES (?, ?)',
868
            array(2, 'foo')
869
        );
870
871
        self::assertNull(
872
            $this->_conn->fetchColumn('SELECT test_datetime FROM fetch_table WHERE test_int = ?', array(2))
873
        );
874
    }
875
876
    /**
877
     * @group DBAL-1028
878
     */
879
    public function testFetchColumnNonExistingIndex()
880
    {
881
        if ($this->_conn->getDriver()->getName() === 'pdo_sqlsrv') {
882
            $this->markTestSkipped(
883
                'Test does not work for pdo_sqlsrv driver as it throws a fatal error for a non-existing column index.'
884
            );
885
        }
886
887
        self::assertNull(
888
            $this->_conn->fetchColumn('SELECT test_int FROM fetch_table WHERE test_int = ?', array(1), 1)
889
        );
890
    }
891
892
    /**
893
     * @group DBAL-1028
894
     */
895
    public function testFetchColumnNoResult()
896
    {
897
        self::assertFalse(
898
            $this->_conn->fetchColumn('SELECT test_int FROM fetch_table WHERE test_int = ?', array(-1))
899
        );
900
    }
901
902
    private function setupFixture()
903
    {
904
        $this->_conn->exec('DELETE FROM fetch_table');
905
        $this->_conn->insert('fetch_table', array(
906
            'test_int'      => 1,
907
            'test_string'   => 'foo',
908
            'test_datetime' => '2010-01-01 10:10:10'
909
        ));
910
    }
911
912
    private function skipOci8AndMysqli()
913
    {
914
        if (isset($GLOBALS['db_type']) && $GLOBALS['db_type'] == "oci8")  {
915
            $this->markTestSkipped("Not supported by OCI8");
916
        }
917
        if ('mysqli' == $this->_conn->getDriver()->getName()) {
918
            $this->markTestSkipped('Mysqli driver dont support this feature.');
919
        }
920
    }
921
}
922
923
class MyFetchClass
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
924
{
925
    public $test_int, $test_string, $test_datetime;
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
926
}
927