Test Failed
Pull Request — master (#2765)
by Marco
04:16
created

assertLastInsertIdInsertAfterTransactionRollback()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 19
Ratio 100 %

Importance

Changes 0
Metric Value
dl 19
loc 19
c 0
b 0
f 0
rs 9.4285
cc 3
eloc 11
nc 4
nop 1
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional;
4
5
use Doctrine\DBAL\Schema\Sequence;
6
use Doctrine\DBAL\Schema\Table;
7
use Doctrine\Tests\TestUtil;
8
9
class LastInsertIdTest extends \Doctrine\Tests\DbalFunctionalTestCase
10
{
11
    /**
12
     * @var \Doctrine\DBAL\Connection
13
     */
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
        if ($this->_conn->getDatabasePlatform()->getName() !== 'sqlite') {
29
            $this->_conn->getSchemaManager()->dropTable('last_insert_id_table');
30
        }
31
32
        return parent::tearDown();
33
    }
34
35
    private function createTable($tableName)
36
    {
37
        $table = new Table($tableName);
38
        $table->addColumn('id', 'integer', array('autoincrement' => true));
39
        $table->addColumn('foo', 'integer', array('notnull' => false));
40
        $table->setPrimaryKey(array('id'));
41
42
        $connection = $this->_conn->getDatabasePlatform()->getName() === 'sqlite'
43
            ? $this->testConnection
44
            : $this->_conn;
45
46
        $connection->getSchemaManager()->createTable($table);
47
    }
48
49
    public function testLastInsertIdNoInsert()
50
    {
51
        $this->assertSame('0', $this->testConnection->lastInsertId());
52
    }
53
54
    public function testLastInsertIdExec()
55
    {
56
        $this->assertLastInsertId($this->createExecInsertExecutor());
57
    }
58
59
    public function testLastInsertIdPrepare()
60
    {
61
        $this->assertLastInsertId($this->createPrepareInsertExecutor());
62
    }
63
64
    public function testLastInsertIdQuery()
65
    {
66
        $this->assertLastInsertId($this->createQueryInsertExecutor());
67
    }
68
69 View Code Duplication
    private function assertLastInsertId(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
70
    {
71
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
72
            $this->markTestSkipped('Test only works on platforms with identity columns.');
73
        }
74
75
        $insertExecutor();
76
77
        $this->assertSame('1', $this->testConnection->lastInsertId());
78
    }
79
80
    public function testLastInsertIdAfterUpdateExec()
81
    {
82
        $this->assertLastInsertIdAfterUpdate($this->createExecInsertExecutor());
83
    }
84
85
    public function testLastInsertIdAfterUpdatePrepare()
86
    {
87
        $this->assertLastInsertIdAfterUpdate($this->createPrepareInsertExecutor());
88
    }
89
90
    public function testLastInsertIdAfterUpdateQuery()
91
    {
92
        $this->assertLastInsertIdAfterUpdate($this->createQueryInsertExecutor());
93
    }
94
95
    private function assertLastInsertIdAfterUpdate(callable $insertExecutor)
96
    {
97
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
98
            $this->markTestSkipped('Test only works on platforms with identity columns.');
99
        }
100
101
        $insertExecutor();
102
        $this->testConnection->update('last_insert_id_table', array('foo' => 2), array('id' => 1));
103
104
        $this->assertSame('1', $this->testConnection->lastInsertId());
105
    }
106
107
    public function testLastInsertIdAfterDeleteExec()
108
    {
109
        $this->assertLastInsertIdAfterDelete($this->createExecInsertExecutor());
110
    }
111
112
    public function testLastInsertIdAfterDeletePrepare()
113
    {
114
        $this->assertLastInsertIdAfterDelete($this->createPrepareInsertExecutor());
115
    }
116
117
    public function testLastInsertIdAfterDeleteQuery()
118
    {
119
        $this->assertLastInsertIdAfterDelete($this->createQueryInsertExecutor());
120
    }
121
122 View Code Duplication
    private function assertLastInsertIdAfterDelete(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123
    {
124
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
125
            $this->markTestSkipped('Test only works on platforms with identity columns.');
126
        }
127
128
        $insertExecutor();
129
        $this->testConnection->exec('DELETE FROM last_insert_id_table');
130
131
        $this->assertSame('1', $this->testConnection->lastInsertId());
132
    }
133
134
    public function testLastInsertIdAfterTruncateExec()
135
    {
136
        $this->assertLastInsertIdAfterTruncate($this->createExecInsertExecutor());
137
    }
138
139
    public function testLastInsertIdAfterTruncatePrepare()
140
    {
141
        $this->assertLastInsertIdAfterTruncate($this->createPrepareInsertExecutor());
142
    }
143
144
    public function testLastInsertIdAfterTruncateQuery()
145
    {
146
        $this->assertLastInsertIdAfterTruncate($this->createQueryInsertExecutor());
147
    }
148
149 View Code Duplication
    private function assertLastInsertIdAfterTruncate(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
    {
151
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
152
            $this->markTestSkipped('Test only works on platforms with identity columns.');
153
        }
154
155
        $insertExecutor();
156
        $truncateTableSql = $this->testConnection->getDatabasePlatform()->getTruncateTableSQL('last_insert_id_table');
157
        $this->testConnection->exec($truncateTableSql);
158
159
        $this->assertSame('1', $this->testConnection->lastInsertId());
160
    }
161
162
    public function testLastInsertIdAfterDropTableExec()
163
    {
164
        $this->assertLastInsertIdAfterDropTable($this->createExecInsertExecutor());
165
    }
166
167
    public function testLastInsertIdAfterDropTablePrepare()
168
    {
169
        $this->assertLastInsertIdAfterDropTable($this->createPrepareInsertExecutor());
170
    }
171
172
    public function testLastInsertIdAfterDropTableQuery()
173
    {
174
        $this->assertLastInsertIdAfterDropTable($this->createQueryInsertExecutor());
175
    }
176
177 View Code Duplication
    private function assertLastInsertIdAfterDropTable(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
178
    {
179
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
180
            $this->markTestSkipped('Test only works on platforms with identity columns.');
181
        }
182
183
        $this->createTable('last_insert_id_table_tmp');
184
185
        $insertExecutor();
186
        $this->testConnection->getSchemaManager()->dropTable('last_insert_id_table_tmp');
187
188
        $this->assertSame('1', $this->testConnection->lastInsertId());
189
    }
190
191
    public function testLastInsertIdAfterSelectExec()
192
    {
193
        $this->assertLastInsertIdAfterSelect($this->createExecInsertExecutor());
194
    }
195
196
    public function testLastInsertIdAfterSelectPrepare()
197
    {
198
        $this->assertLastInsertIdAfterSelect($this->createPrepareInsertExecutor());
199
    }
200
201
    public function testLastInsertIdAfterSelectQuery()
202
    {
203
        $this->assertLastInsertIdAfterSelect($this->createQueryInsertExecutor());
204
    }
205
206 View Code Duplication
    private function assertLastInsertIdAfterSelect(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
207
    {
208
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
209
            $this->markTestSkipped('Test only works on platforms with identity columns.');
210
        }
211
212
        $insertExecutor();
213
        $this->testConnection->executeQuery('SELECT 1 FROM last_insert_id_table');
214
215
        $this->assertSame('1', $this->testConnection->lastInsertId());
216
    }
217
218
    public function testLastInsertIdInTransactionExec()
219
    {
220
        $this->assertLastInsertIdInTransaction($this->createExecInsertExecutor());
221
    }
222
223
    public function testLastInsertIdInTransactionPrepare()
224
    {
225
        $this->assertLastInsertIdInTransaction($this->createPrepareInsertExecutor());
226
    }
227
228
    public function testLastInsertIdInTransactionQuery()
229
    {
230
        $this->assertLastInsertIdInTransaction($this->createQueryInsertExecutor());
231
    }
232
233 View Code Duplication
    public function assertLastInsertIdInTransaction(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
    {
235
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
236
            $this->markTestSkipped('Test only works on platforms with identity columns.');
237
        }
238
239
        $this->testConnection->beginTransaction();
240
        $insertExecutor();
241
        $this->assertSame('1', $this->testConnection->lastInsertId());
242
        $this->testConnection->rollBack();
243
    }
244
245
    public function testLastInsertIdAfterTransactionCommitExec()
246
    {
247
        $this->assertLastInsertIdAfterTransactionCommit($this->createExecInsertExecutor());
248
    }
249
250
    public function testLastInsertIdAfterTransactionCommitPrepare()
251
    {
252
        $this->assertLastInsertIdAfterTransactionCommit($this->createPrepareInsertExecutor());
253
    }
254
255
    public function testLastInsertIdAfterTransactionCommitQuery()
256
    {
257
        $this->assertLastInsertIdAfterTransactionCommit($this->createQueryInsertExecutor());
258
    }
259
260 View Code Duplication
    private function assertLastInsertIdAfterTransactionCommit(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
261
    {
262
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
263
            $this->markTestSkipped('Test only works on platforms with identity columns.');
264
        }
265
266
        $this->testConnection->beginTransaction();
267
        $insertExecutor();
268
        $this->testConnection->commit();
269
270
        $this->assertSame('1', $this->testConnection->lastInsertId());
271
    }
272
273
    public function testLastInsertIdAfterTransactionRollbackExec()
274
    {
275
        $this->assertLastInsertIdAfterTransactionRollback($this->createExecInsertExecutor());
276
    }
277
278
    public function testLastInsertIdAfterTransactionRollbackPrepare()
279
    {
280
        $this->assertLastInsertIdAfterTransactionRollback($this->createPrepareInsertExecutor());
281
    }
282
283
    public function testLastInsertIdAfterTransactionRollbackQuery()
284
    {
285
        $this->assertLastInsertIdAfterTransactionRollback($this->createQueryInsertExecutor());
286
    }
287
288 View Code Duplication
    private function assertLastInsertIdAfterTransactionRollback(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
    {
290
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
291
            $this->markTestSkipped('Test only works on platforms with identity columns.');
292
        }
293
294
        $this->testConnection->beginTransaction();
295
        $insertExecutor();
296
        $this->testConnection->rollBack();
297
298
        $this->assertSame('1', $this->testConnection->lastInsertId());
299
    }
300
301
    public function testLastInsertIdInsertAfterTransactionRollbackExec()
302
    {
303
        $this->assertLastInsertIdInsertAfterTransactionRollback($this->createExecInsertExecutor());
304
    }
305
306
    public function testLastInsertIdInsertAfterTransactionRollbackPrepare()
307
    {
308
        $this->assertLastInsertIdInsertAfterTransactionRollback($this->createPrepareInsertExecutor());
309
    }
310
311
    public function testLastInsertIdInsertAfterTransactionRollbackQuery()
312
    {
313
        $this->assertLastInsertIdInsertAfterTransactionRollback($this->createQueryInsertExecutor());
314
    }
315
316 View Code Duplication
    private function assertLastInsertIdInsertAfterTransactionRollback(callable $insertExecutor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
317
    {
318
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
319
            $this->markTestSkipped('Test only works on platforms with identity columns.');
320
        }
321
322
        $this->testConnection->beginTransaction();
323
        $insertExecutor();
324
        $this->testConnection->rollBack();
325
        $insertExecutor();
326
327
        $expected = $this->testConnection->getDatabasePlatform()->getName() === 'sqlite'
328
            // SQLite has a different transaction concept, that reuses rolled back IDs
329
            // See: http://sqlite.1065341.n5.nabble.com/Autoincrement-with-rollback-td79154.html
330
            ? '1'
331
            : '2';
332
333
        $this->assertSame($expected, $this->testConnection->lastInsertId());
334
    }
335
336 View Code Duplication
    public function testLastInsertIdReusePreparedStatementPrepare()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
337
    {
338
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
339
            $this->markTestSkipped('Test only works on platforms with identity columns.');
340
        }
341
342
        $statement = $this->testConnection->prepare('INSERT INTO last_insert_id_table (foo) VALUES (1)');
343
344
        $statement->execute();
345
        $statement->execute();
346
347
        $this->assertSame('2', $this->testConnection->lastInsertId());
348
    }
349
350 View Code Duplication
    public function testLastInsertIdReusePreparedStatementQuery()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
351
    {
352
        if (! $this->_conn->getDatabasePlatform()->supportsIdentityColumns()) {
353
            $this->markTestSkipped('Test only works on platforms with identity columns.');
354
        }
355
356
        $statement = $this->testConnection->query('INSERT INTO last_insert_id_table (foo) VALUES (1)');
357
358
        $statement->execute();
359
360
        $this->assertSame('2', $this->testConnection->lastInsertId());
361
    }
362
363
    public function testLastInsertIdConnectionScope()
364
    {
365
        $platform = $this->_conn->getDatabasePlatform();
366
367
        if ($platform->getName() === 'sqlite') {
368
            $this->markTestSkipped('Test does not work on sqlite as connections do not share memory.');
369
        }
370
371
        if (! $platform->supportsIdentityColumns()) {
372
            $this->markTestSkipped('Test only works on platforms with identity columns.');
373
        }
374
375
        $connection1 = TestUtil::getConnection();
376
        $connection2 = TestUtil::getConnection();
377
378
        $connection1->insert('last_insert_id_table', array('foo' => 1));
379
380
        $this->assertNotSame('1', $connection2->lastInsertId());
381
382
        $connection2->insert('last_insert_id_table', array('foo' => 2));
383
384
        $this->assertSame('1', $connection1->lastInsertId());
385
        $this->assertSame('2', $connection2->lastInsertId());
386
387
        $connection1->close();
388
        $connection2->close();
389
    }
390
391
    public function testLastInsertIdSequence()
392
    {
393
        if (! $this->_conn->getDatabasePlatform()->supportsSequences()) {
394
            $this->markTestSkipped('Test only works on platforms with sequences.');
395
        }
396
397
        $sequence = new Sequence('last_insert_id_seq');
398
399
        $this->_conn->getSchemaManager()->createSequence($sequence);
400
401
        $nextSequenceValueSql = $this->_conn->getDatabasePlatform()->getSequenceNextValSQL('last_insert_id_seq');
402
        $nextSequenceValue = $this->_conn->fetchColumn($nextSequenceValueSql);
403
        $lastInsertId = $this->_conn->lastInsertId('last_insert_id_seq');
404
405
        $this->assertEquals($lastInsertId, $nextSequenceValue);
406
    }
407
408
    public function testLastInsertIdSequenceEmulatedIdentityColumnExec()
409
    {
410
        $this->assertLastInsertIdSequenceEmulatedIdentityColumn($this->createExecInsertExecutor());
411
    }
412
413
    public function testLastInsertIdSequenceEmulatedIdentityColumnPrepare()
414
    {
415
        $this->assertLastInsertIdSequenceEmulatedIdentityColumn($this->createPrepareInsertExecutor());
416
    }
417
418
    public function testLastInsertIdSequenceEmulatedIdentityColumnQuery()
419
    {
420
        $this->assertLastInsertIdSequenceEmulatedIdentityColumn($this->createQueryInsertExecutor());
421
    }
422
423
    private function assertLastInsertIdSequenceEmulatedIdentityColumn(callable $insertExecutor)
424
    {
425
        $platform = $this->_conn->getDatabasePlatform();
426
427
        if ($platform->supportsIdentityColumns() || ! $platform->usesSequenceEmulatedIdentityColumns()) {
428
            $this->markTestSkipped('Test only works on platforms that emulates identity columns through sequences.');
429
        }
430
431
        $sequenceName = $platform->getIdentitySequenceName('last_insert_id_table', 'id');
432
433
        $this->assertSame('0', $this->_conn->lastInsertId($sequenceName));
434
435
        $insertExecutor();
436
437
        $this->assertSame('1', $this->_conn->lastInsertId($sequenceName));
438
    }
439
440
    private function createExecInsertExecutor()
441
    {
442
        return function () {
443
            $this->testConnection->getWrappedConnection()->exec('INSERT INTO last_insert_id_table (foo) VALUES (1)');
444
        };
445
    }
446
447
    private function createPrepareInsertExecutor()
448
    {
449
        return function () {
450
            $stmt = $this->testConnection->getWrappedConnection()->prepare(
451
                'INSERT INTO last_insert_id_table (foo) VALUES (?)'
452
            );
453
454
            $stmt->execute(array(1));
455
        };
456
    }
457
458
    private function createQueryInsertExecutor()
459
    {
460
        return function () {
461
            $this->testConnection->getWrappedConnection()->query('INSERT INTO last_insert_id_table (foo) VALUES (1)');
0 ignored issues
show
Unused Code introduced by
The call to Connection::query() has too many arguments starting with 'INSERT INTO last_insert...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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

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