Failed Conditions
Pull Request — master (#3074)
by Sergei
31:20
created

LastInsertIdTest::createQueryInsertExecutor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Schema\Sequence;
7
use Doctrine\DBAL\Schema\Table;
8
use Doctrine\Tests\DbalFunctionalTestCase;
9
use Doctrine\Tests\TestUtil;
10
11
class LastInsertIdTest extends DbalFunctionalTestCase
12
{
13
    /** @var Connection */
14
    private $testConnection;
15
16
    protected function setUp()
17
    {
18
        parent::setUp();
19
20
        $this->testConnection = TestUtil::getConnection();
21
22
        $this->createTable('last_insert_id_table');
23
    }
24
25
    protected function tearDown()
26
    {
27
        $this->testConnection->close();
28
29
        if ($this->_conn->getDatabasePlatform()->getName() !== 'sqlite') {
30
            $this->_conn->getSchemaManager()->dropTable('last_insert_id_table');
31
        }
32
33
        parent::tearDown();
34
    }
35
36
    private function createTable($tableName)
37
    {
38
        $table = new Table($tableName);
39
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
40
        $table->addColumn('foo', 'integer', ['notnull' => false]);
41
        $table->setPrimaryKey(['id']);
42
43
        $connection = $this->_conn->getDatabasePlatform()->getName() === 'sqlite'
44
            ? $this->testConnection
45
            : $this->_conn;
46
47
        $connection->getSchemaManager()->createTable($table);
48
    }
49
50
    public function testLastInsertIdNoInsert()
51
    {
52
        $this->assertSame('0', $this->testConnection->lastInsertId());
53
    }
54
55
    public function testLastInsertIdExec()
56
    {
57
        $this->assertLastInsertId($this->createExecInsertExecutor());
58
    }
59
60
    public function testLastInsertIdPrepare()
61
    {
62
        $this->assertLastInsertId($this->createPrepareInsertExecutor());
63
    }
64
65
    public function testLastInsertIdQuery()
66
    {
67
        $this->assertLastInsertId($this->createQueryInsertExecutor());
68
    }
69
70
    private function assertLastInsertId(callable $insertExecutor)
71
    {
72
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
73
            $this->markTestSkipped('Test only works on platforms with identity columns.');
74
        }
75
76
        $insertExecutor();
77
78
        $this->assertSame('1', $this->testConnection->lastInsertId());
79
    }
80
81
    public function testLastInsertIdAfterUpdateExec()
82
    {
83
        $this->assertLastInsertIdAfterUpdate($this->createExecInsertExecutor());
84
    }
85
86
    public function testLastInsertIdAfterUpdatePrepare()
87
    {
88
        $this->assertLastInsertIdAfterUpdate($this->createPrepareInsertExecutor());
89
    }
90
91
    public function testLastInsertIdAfterUpdateQuery()
92
    {
93
        $this->assertLastInsertIdAfterUpdate($this->createQueryInsertExecutor());
94
    }
95
96
    private function assertLastInsertIdAfterUpdate(callable $insertExecutor)
97
    {
98
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
99
            $this->markTestSkipped('Test only works on platforms with identity columns.');
100
        }
101
102
        $insertExecutor();
103
        $this->testConnection->update('last_insert_id_table', ['foo' => 2], ['id' => 1]);
104
105
        $this->assertSame('1', $this->testConnection->lastInsertId());
106
    }
107
108
    public function testLastInsertIdAfterDeleteExec()
109
    {
110
        $this->assertLastInsertIdAfterDelete($this->createExecInsertExecutor());
111
    }
112
113
    public function testLastInsertIdAfterDeletePrepare()
114
    {
115
        $this->assertLastInsertIdAfterDelete($this->createPrepareInsertExecutor());
116
    }
117
118
    public function testLastInsertIdAfterDeleteQuery()
119
    {
120
        $this->assertLastInsertIdAfterDelete($this->createQueryInsertExecutor());
121
    }
122
123
    private function assertLastInsertIdAfterDelete(callable $insertExecutor)
124
    {
125
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
126
            $this->markTestSkipped('Test only works on platforms with identity columns.');
127
        }
128
129
        $insertExecutor();
130
        $this->testConnection->exec('DELETE FROM last_insert_id_table');
131
132
        $this->assertSame('1', $this->testConnection->lastInsertId());
133
    }
134
135
    public function testLastInsertIdAfterTruncateExec()
136
    {
137
        $this->assertLastInsertIdAfterTruncate($this->createExecInsertExecutor());
138
    }
139
140
    public function testLastInsertIdAfterTruncatePrepare()
141
    {
142
        $this->assertLastInsertIdAfterTruncate($this->createPrepareInsertExecutor());
143
    }
144
145
    public function testLastInsertIdAfterTruncateQuery()
146
    {
147
        $this->assertLastInsertIdAfterTruncate($this->createQueryInsertExecutor());
148
    }
149
150
    private function assertLastInsertIdAfterTruncate(callable $insertExecutor)
151
    {
152
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
153
            $this->markTestSkipped('Test only works on platforms with identity columns.');
154
        }
155
156
        $insertExecutor();
157
        $truncateTableSql = $this->testConnection->getDatabasePlatform()->getTruncateTableSQL('last_insert_id_table');
158
        $this->testConnection->exec($truncateTableSql);
159
160
        $this->assertSame('1', $this->testConnection->lastInsertId());
161
    }
162
163
    public function testLastInsertIdAfterDropTableExec()
164
    {
165
        $this->assertLastInsertIdAfterDropTable($this->createExecInsertExecutor());
166
    }
167
168
    public function testLastInsertIdAfterDropTablePrepare()
169
    {
170
        $this->assertLastInsertIdAfterDropTable($this->createPrepareInsertExecutor());
171
    }
172
173
    public function testLastInsertIdAfterDropTableQuery()
174
    {
175
        $this->assertLastInsertIdAfterDropTable($this->createQueryInsertExecutor());
176
    }
177
178
    private function assertLastInsertIdAfterDropTable(callable $insertExecutor)
179
    {
180
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
181
            $this->markTestSkipped('Test only works on platforms with identity columns.');
182
        }
183
184
        $this->createTable('last_insert_id_table_tmp');
185
186
        $insertExecutor();
187
        $this->testConnection->getSchemaManager()->dropTable('last_insert_id_table_tmp');
188
189
        $this->assertSame('1', $this->testConnection->lastInsertId());
190
    }
191
192
    public function testLastInsertIdAfterSelectExec()
193
    {
194
        $this->assertLastInsertIdAfterSelect($this->createExecInsertExecutor());
195
    }
196
197
    public function testLastInsertIdAfterSelectPrepare()
198
    {
199
        $this->assertLastInsertIdAfterSelect($this->createPrepareInsertExecutor());
200
    }
201
202
    public function testLastInsertIdAfterSelectQuery()
203
    {
204
        $this->assertLastInsertIdAfterSelect($this->createQueryInsertExecutor());
205
    }
206
207
    private function assertLastInsertIdAfterSelect(callable $insertExecutor)
208
    {
209
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
210
            $this->markTestSkipped('Test only works on platforms with identity columns.');
211
        }
212
213
        $insertExecutor();
214
        $this->testConnection->executeQuery('SELECT 1 FROM last_insert_id_table');
215
216
        $this->assertSame('1', $this->testConnection->lastInsertId());
217
    }
218
219
    public function testLastInsertIdInTransactionExec()
220
    {
221
        $this->assertLastInsertIdInTransaction($this->createExecInsertExecutor());
222
    }
223
224
    public function testLastInsertIdInTransactionPrepare()
225
    {
226
        $this->assertLastInsertIdInTransaction($this->createPrepareInsertExecutor());
227
    }
228
229
    public function testLastInsertIdInTransactionQuery()
230
    {
231
        $this->assertLastInsertIdInTransaction($this->createQueryInsertExecutor());
232
    }
233
234
    public function assertLastInsertIdInTransaction(callable $insertExecutor)
235
    {
236
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
237
            $this->markTestSkipped('Test only works on platforms with identity columns.');
238
        }
239
240
        $this->testConnection->beginTransaction();
241
        $insertExecutor();
242
        $this->assertSame('1', $this->testConnection->lastInsertId());
243
        $this->testConnection->rollBack();
244
    }
245
246
    public function testLastInsertIdAfterTransactionCommitExec()
247
    {
248
        $this->assertLastInsertIdAfterTransactionCommit($this->createExecInsertExecutor());
249
    }
250
251
    public function testLastInsertIdAfterTransactionCommitPrepare()
252
    {
253
        $this->assertLastInsertIdAfterTransactionCommit($this->createPrepareInsertExecutor());
254
    }
255
256
    public function testLastInsertIdAfterTransactionCommitQuery()
257
    {
258
        $this->assertLastInsertIdAfterTransactionCommit($this->createQueryInsertExecutor());
259
    }
260
261
    private function assertLastInsertIdAfterTransactionCommit(callable $insertExecutor)
262
    {
263
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
264
            $this->markTestSkipped('Test only works on platforms with identity columns.');
265
        }
266
267
        $this->testConnection->beginTransaction();
268
        $insertExecutor();
269
        $this->testConnection->commit();
270
271
        $this->assertSame('1', $this->testConnection->lastInsertId());
272
    }
273
274
    public function testLastInsertIdAfterTransactionRollbackExec()
275
    {
276
        $this->assertLastInsertIdAfterTransactionRollback($this->createExecInsertExecutor());
277
    }
278
279
    public function testLastInsertIdAfterTransactionRollbackPrepare()
280
    {
281
        $this->assertLastInsertIdAfterTransactionRollback($this->createPrepareInsertExecutor());
282
    }
283
284
    public function testLastInsertIdAfterTransactionRollbackQuery()
285
    {
286
        $this->assertLastInsertIdAfterTransactionRollback($this->createQueryInsertExecutor());
287
    }
288
289
    private function assertLastInsertIdAfterTransactionRollback(callable $insertExecutor)
290
    {
291
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
292
            $this->markTestSkipped('Test only works on platforms with identity columns.');
293
        }
294
295
        $this->testConnection->beginTransaction();
296
        $insertExecutor();
297
        $this->testConnection->rollBack();
298
299
        $this->assertSame('1', $this->testConnection->lastInsertId());
300
    }
301
302
    public function testLastInsertIdInsertAfterTransactionRollbackExec()
303
    {
304
        $this->assertLastInsertIdInsertAfterTransactionRollback($this->createExecInsertExecutor());
305
    }
306
307
    public function testLastInsertIdInsertAfterTransactionRollbackPrepare()
308
    {
309
        $this->assertLastInsertIdInsertAfterTransactionRollback($this->createPrepareInsertExecutor());
310
    }
311
312
    public function testLastInsertIdInsertAfterTransactionRollbackQuery()
313
    {
314
        $this->assertLastInsertIdInsertAfterTransactionRollback($this->createQueryInsertExecutor());
315
    }
316
317
    private function assertLastInsertIdInsertAfterTransactionRollback(callable $insertExecutor)
318
    {
319
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
320
            $this->markTestSkipped('Test only works on platforms with identity columns.');
321
        }
322
323
        $this->testConnection->beginTransaction();
324
        $insertExecutor();
325
        $this->testConnection->rollBack();
326
        $insertExecutor();
327
328
        $expected = $this->testConnection->getDatabasePlatform()->getName() === 'sqlite'
329
            // SQLite has a different transaction concept, that reuses rolled back IDs
330
            // See: http://sqlite.1065341.n5.nabble.com/Autoincrement-with-rollback-td79154.html
331
            ? '1'
332
            : '2';
333
334
        $this->assertSame($expected, $this->testConnection->lastInsertId());
335
    }
336
337
    public function testLastInsertIdReusePreparedStatementPrepare()
338
    {
339
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
340
            $this->markTestSkipped('Test only works on platforms with identity columns.');
341
        }
342
343
        $statement = $this->testConnection->prepare('INSERT INTO last_insert_id_table (foo) VALUES (1)');
344
345
        $statement->execute();
346
        $statement->execute();
347
348
        $this->assertSame('2', $this->testConnection->lastInsertId());
349
    }
350
351
    public function testLastInsertIdReusePreparedStatementQuery()
352
    {
353
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
354
            $this->markTestSkipped('Test only works on platforms with identity columns.');
355
        }
356
357
        $statement = $this->testConnection->query('INSERT INTO last_insert_id_table (foo) VALUES (1)');
358
359
        $statement->execute();
360
361
        $this->assertSame('2', $this->testConnection->lastInsertId());
362
    }
363
364
    public function testLastInsertIdConnectionScope()
365
    {
366
        $platform = $this->_conn->getDatabasePlatform();
367
368
        if ($platform->getName() === 'sqlite') {
369
            $this->markTestSkipped('Test does not work on sqlite as connections do not share memory.');
370
        }
371
372
        if (! $platform->supportsIdentityColumns()) {
373
            $this->markTestSkipped('Test only works on platforms with identity columns.');
374
        }
375
376
        $connection1 = TestUtil::getConnection();
377
        $connection2 = TestUtil::getConnection();
378
379
        $connection1->insert('last_insert_id_table', ['foo' => 1]);
380
381
        $this->assertNotSame('1', $connection2->lastInsertId());
382
383
        $connection2->insert('last_insert_id_table', ['foo' => 2]);
384
385
        $this->assertSame('1', $connection1->lastInsertId());
386
        $this->assertSame('2', $connection2->lastInsertId());
387
388
        $connection1->close();
389
        $connection2->close();
390
    }
391
392
    public function testLastInsertIdSequence()
393
    {
394
        if (! $this->_conn->getDatabasePlatform()->supportsSequences()) {
395
            $this->markTestSkipped('Test only works on platforms with sequences.');
396
        }
397
398
        $sequence = new Sequence('last_insert_id_seq');
399
400
        $this->_conn->getSchemaManager()->createSequence($sequence);
401
402
        $nextSequenceValueSql = $this->_conn->getDatabasePlatform()->getSequenceNextValSQL('last_insert_id_seq');
403
        $nextSequenceValue    = $this->_conn->fetchColumn($nextSequenceValueSql);
404
        $lastInsertId         = $this->_conn->lastInsertId('last_insert_id_seq');
405
406
        $this->assertEquals($lastInsertId, $nextSequenceValue);
407
    }
408
409
    public function testLastInsertIdSequenceEmulatedIdentityColumnExec()
410
    {
411
        $this->assertLastInsertIdSequenceEmulatedIdentityColumn($this->createExecInsertExecutor());
412
    }
413
414
    public function testLastInsertIdSequenceEmulatedIdentityColumnPrepare()
415
    {
416
        $this->assertLastInsertIdSequenceEmulatedIdentityColumn($this->createPrepareInsertExecutor());
417
    }
418
419
    public function testLastInsertIdSequenceEmulatedIdentityColumnQuery()
420
    {
421
        $this->assertLastInsertIdSequenceEmulatedIdentityColumn($this->createQueryInsertExecutor());
422
    }
423
424
    private function assertLastInsertIdSequenceEmulatedIdentityColumn(callable $insertExecutor)
425
    {
426
        $platform = $this->_conn->getDatabasePlatform();
427
428
        if ($platform->supportsIdentityColumns() || ! $platform->usesSequenceEmulatedIdentityColumns()) {
429
            $this->markTestSkipped('Test only works on platforms that emulates identity columns through sequences.');
430
        }
431
432
        $sequenceName = $platform->getIdentitySequenceName('last_insert_id_table', 'id');
433
434
        $this->assertSame('0', $this->_conn->lastInsertId($sequenceName));
435
436
        $insertExecutor();
437
438
        $this->assertSame('1', $this->_conn->lastInsertId($sequenceName));
439
    }
440
441
    private function createExecInsertExecutor()
442
    {
443
        return function () {
444
            $this->testConnection->getWrappedConnection()->exec('INSERT INTO last_insert_id_table (foo) VALUES (1)');
445
        };
446
    }
447
448
    private function createPrepareInsertExecutor()
449
    {
450
        return function () {
451
            $stmt = $this->testConnection->getWrappedConnection()->prepare(
452
                'INSERT INTO last_insert_id_table (foo) VALUES (?)'
453
            );
454
455
            $stmt->execute([1]);
456
        };
457
    }
458
459
    private function createQueryInsertExecutor()
460
    {
461
        return function () {
462
            $this->testConnection->getWrappedConnection()->query('INSERT INTO last_insert_id_table (foo) VALUES (1)');
0 ignored issues
show
Unused Code introduced by
The call to Doctrine\DBAL\Driver\Connection::query() has too many arguments starting with 'INSERT INTO last_insert...table (foo) VALUES (1)'. ( Ignorable by Annotation )

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

462
            $this->testConnection->getWrappedConnection()->/** @scrutinizer ignore-call */ query('INSERT INTO last_insert_id_table (foo) VALUES (1)');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
463
        };
464
    }
465
}
466