1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Doctrine\Tests\DBAL\Query; |
4
|
|
|
|
5
|
|
|
use Doctrine\DBAL\Query\BulkInsertQuery; |
6
|
|
|
use Doctrine\Tests\DBAL\Mocks\MockPlatform; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* @group DBAL-218 |
10
|
|
|
*/ |
11
|
|
|
class BulkInsertQueryTest extends \Doctrine\Tests\DbalTestCase |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* @var \Doctrine\DBAL\Connection|\PHPUnit_Framework_MockObject_MockObject |
15
|
|
|
*/ |
16
|
|
|
protected $connection; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* {@inheritdoc} |
20
|
|
|
*/ |
21
|
|
|
protected function setUp() |
22
|
|
|
{ |
23
|
|
|
$this->connection = $this->getMockBuilder('Doctrine\DBAL\Connection') |
24
|
|
|
->disableOriginalConstructor() |
25
|
|
|
->getMock(); |
26
|
|
|
|
27
|
|
|
$this->connection->expects($this->any()) |
28
|
|
|
->method('getDatabasePlatform') |
29
|
|
|
->will($this->returnValue(new MockPlatform())); |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @expectedException \LogicException |
34
|
|
|
* @expectedExceptionMessage You need to add at least one set of values before generating the SQL. |
35
|
|
|
*/ |
36
|
|
|
public function testGetSQLWithoutSpecifiedValuesThrowsException() |
37
|
|
|
{ |
38
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
39
|
|
|
|
40
|
|
|
$query->getSQL(); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
public function testEmptyInsertWithoutColumnSpecification() |
44
|
|
|
{ |
45
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
46
|
|
|
|
47
|
|
|
$query->addValues(array()); |
48
|
|
|
|
49
|
|
|
$this->assertSame("INSERT INTO foo VALUES ()", $query->getSQL()); |
50
|
|
|
$this->assertSame(array(), $query->getParameters()); |
51
|
|
|
$this->assertSame(array(), $query->getParameterTypes()); |
52
|
|
|
|
53
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
54
|
|
|
|
55
|
|
|
$query->addValues(array(), array(\PDO::PARAM_BOOL)); |
56
|
|
|
|
57
|
|
|
$this->assertSame("INSERT INTO foo VALUES ()", $query->getSQL()); |
58
|
|
|
$this->assertSame(array(), $query->getParameters()); |
59
|
|
|
$this->assertSame(array(), $query->getParameterTypes()); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
public function testSingleInsertWithoutColumnSpecification() |
63
|
|
|
{ |
64
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
65
|
|
|
|
66
|
|
|
$query->addValues(array('bar', 'baz', 'named' => 'bloo')); |
67
|
|
|
|
68
|
|
|
$this->assertSame("INSERT INTO foo VALUES (?, ?, ?)", $query->getSQL()); |
69
|
|
|
$this->assertSame(array('bar', 'baz', 'bloo'), $query->getParameters()); |
70
|
|
|
$this->assertSame(array(null, null, null), $query->getParameterTypes()); |
71
|
|
|
|
72
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
73
|
|
|
|
74
|
|
|
$query->addValues( |
75
|
|
|
array('bar', 'baz', 'named' => 'bloo'), |
76
|
|
|
array('named' => \PDO::PARAM_BOOL, null, \PDO::PARAM_INT) |
77
|
|
|
); |
78
|
|
|
|
79
|
|
|
$this->assertSame("INSERT INTO foo VALUES (?, ?, ?)", $query->getSQL()); |
80
|
|
|
$this->assertSame(array('bar', 'baz', 'bloo'), $query->getParameters()); |
81
|
|
|
$this->assertSame(array(null, \PDO::PARAM_INT, \PDO::PARAM_BOOL), $query->getParameterTypes()); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
public function testMultiInsertWithoutColumnSpecification() |
85
|
|
|
{ |
86
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
87
|
|
|
|
88
|
|
|
$query->addValues(array()); |
89
|
|
|
$query->addValues(array('bar', 'baz')); |
90
|
|
|
$query->addValues(array('bar', 'baz', 'bloo')); |
91
|
|
|
$query->addValues(array('bar', 'baz', 'named' => 'bloo')); |
92
|
|
|
|
93
|
|
|
$this->assertSame("INSERT INTO foo VALUES (), (?, ?), (?, ?, ?), (?, ?, ?)", $query->getSQL()); |
94
|
|
|
$this->assertSame(array('bar', 'baz', 'bar', 'baz', 'bloo', 'bar', 'baz', 'bloo'), $query->getParameters()); |
95
|
|
|
$this->assertSame(array(null, null, null, null, null, null, null, null), $query->getParameterTypes()); |
96
|
|
|
|
97
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
98
|
|
|
|
99
|
|
|
$query->addValues(array(), array(\PDO::PARAM_INT)); |
100
|
|
|
$query->addValues(array('bar', 'baz'), array(1 => \PDO::PARAM_BOOL)); |
101
|
|
|
$query->addValues(array('bar', 'baz', 'bloo'), array(\PDO::PARAM_INT, null, \PDO::PARAM_BOOL)); |
102
|
|
|
$query->addValues( |
103
|
|
|
array('bar', 'baz', 'named' => 'bloo'), |
104
|
|
|
array('named' => \PDO::PARAM_INT, null, \PDO::PARAM_BOOL) |
105
|
|
|
); |
106
|
|
|
|
107
|
|
|
$this->assertSame("INSERT INTO foo VALUES (), (?, ?), (?, ?, ?), (?, ?, ?)", $query->getSQL()); |
108
|
|
|
$this->assertSame(array('bar', 'baz', 'bar', 'baz', 'bloo', 'bar', 'baz', 'bloo'), $query->getParameters()); |
109
|
|
|
$this->assertSame( |
110
|
|
|
array(null, \PDO::PARAM_BOOL, \PDO::PARAM_INT, null, \PDO::PARAM_BOOL, null, \PDO::PARAM_BOOL, \PDO::PARAM_INT), |
111
|
|
|
$query->getParameterTypes() |
112
|
|
|
); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
public function testSingleInsertWithColumnSpecificationAndPositionalTypeValues() |
116
|
|
|
{ |
117
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
118
|
|
|
|
119
|
|
|
$query->addValues(array('bar', 'baz')); |
120
|
|
|
|
121
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?)", $query->getSQL()); |
122
|
|
|
$this->assertSame(array('bar', 'baz'), $query->getParameters()); |
123
|
|
|
$this->assertSame(array(null, null), $query->getParameterTypes()); |
124
|
|
|
|
125
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
126
|
|
|
|
127
|
|
|
$query->addValues(array('bar', 'baz'), array(1 => \PDO::PARAM_BOOL)); |
128
|
|
|
|
129
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?)", $query->getSQL()); |
130
|
|
|
$this->assertSame(array('bar', 'baz'), $query->getParameters()); |
131
|
|
|
$this->assertSame(array(null, \PDO::PARAM_BOOL), $query->getParameterTypes()); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
View Code Duplication |
public function testSingleInsertWithColumnSpecificationAndNamedTypeValues() |
|
|
|
|
135
|
|
|
{ |
136
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
137
|
|
|
|
138
|
|
|
$query->addValues(array('baz' => 'baz', 'bar' => 'bar')); |
139
|
|
|
|
140
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?)", $query->getSQL()); |
141
|
|
|
$this->assertSame(array('bar', 'baz'), $query->getParameters()); |
142
|
|
|
$this->assertSame(array(null, null), $query->getParameterTypes()); |
143
|
|
|
|
144
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
145
|
|
|
|
146
|
|
|
$query->addValues(array('baz' => 'baz', 'bar' => 'bar'), array(null, \PDO::PARAM_INT)); |
147
|
|
|
|
148
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?)", $query->getSQL()); |
149
|
|
|
$this->assertSame(array('bar', 'baz'), $query->getParameters()); |
150
|
|
|
$this->assertSame(array(null, \PDO::PARAM_INT), $query->getParameterTypes()); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
View Code Duplication |
public function testSingleInsertWithColumnSpecificationAndMixedTypeValues() |
|
|
|
|
154
|
|
|
{ |
155
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
156
|
|
|
|
157
|
|
|
$query->addValues(array(1 => 'baz', 'bar' => 'bar')); |
158
|
|
|
|
159
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?)", $query->getSQL()); |
160
|
|
|
$this->assertSame(array('bar', 'baz'), $query->getParameters()); |
161
|
|
|
$this->assertSame(array(null, null), $query->getParameterTypes()); |
162
|
|
|
|
163
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
164
|
|
|
|
165
|
|
|
$query->addValues(array(1 => 'baz', 'bar' => 'bar'), array(\PDO::PARAM_INT, \PDO::PARAM_BOOL)); |
166
|
|
|
|
167
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?)", $query->getSQL()); |
168
|
|
|
$this->assertSame(array('bar', 'baz'), $query->getParameters()); |
169
|
|
|
$this->assertSame(array(\PDO::PARAM_INT, \PDO::PARAM_BOOL), $query->getParameterTypes()); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
public function testMultiInsertWithColumnSpecification() |
173
|
|
|
{ |
174
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
175
|
|
|
|
176
|
|
|
$query->addValues(array('bar', 'baz')); |
177
|
|
|
$query->addValues(array(1 => 'baz', 'bar' => 'bar')); |
178
|
|
|
$query->addValues(array('bar', 'baz' => 'baz')); |
179
|
|
|
$query->addValues(array('bar' => 'bar', 'baz' => 'baz')); |
180
|
|
|
|
181
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?), (?, ?), (?, ?), (?, ?)", $query->getSQL()); |
182
|
|
|
$this->assertSame(array('bar', 'baz', 'bar', 'baz', 'bar', 'baz', 'bar', 'baz'), $query->getParameters()); |
183
|
|
|
$this->assertSame(array(null, null, null, null, null, null, null, null), $query->getParameterTypes()); |
184
|
|
|
|
185
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
186
|
|
|
|
187
|
|
|
$query->addValues(array('bar', 'baz'), array('baz' => \PDO::PARAM_BOOL, 'bar' => \PDO::PARAM_INT)); |
188
|
|
|
$query->addValues(array(1 => 'baz', 'bar' => 'bar'), array(1 => \PDO::PARAM_BOOL, 'bar' => \PDO::PARAM_INT)); |
189
|
|
|
$query->addValues(array('bar', 'baz' => 'baz'), array(null, null)); |
190
|
|
|
$query->addValues( |
191
|
|
|
array('bar' => 'bar', 'baz' => 'baz'), |
192
|
|
|
array('bar' => \PDO::PARAM_INT, 'baz' => \PDO::PARAM_BOOL) |
193
|
|
|
); |
194
|
|
|
|
195
|
|
|
$this->assertSame("INSERT INTO foo (bar, baz) VALUES (?, ?), (?, ?), (?, ?), (?, ?)", $query->getSQL()); |
196
|
|
|
$this->assertSame(array('bar', 'baz', 'bar', 'baz', 'bar', 'baz', 'bar', 'baz'), $query->getParameters()); |
197
|
|
|
$this->assertSame( |
198
|
|
|
array(\PDO::PARAM_INT, \PDO::PARAM_BOOL, \PDO::PARAM_INT, \PDO::PARAM_BOOL, null, null, \PDO::PARAM_INT, \PDO::PARAM_BOOL), |
199
|
|
|
$query->getParameterTypes() |
200
|
|
|
); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* @expectedException \InvalidArgumentException |
205
|
|
|
* @expectedExceptionMessage No value specified for column bar (index 0). |
206
|
|
|
*/ |
207
|
|
|
public function testEmptyInsertWithColumnSpecificationThrowsException() |
208
|
|
|
{ |
209
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
210
|
|
|
|
211
|
|
|
$query->addValues(array()); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* @expectedException \InvalidArgumentException |
216
|
|
|
* @expectedExceptionMessage Multiple values specified for column baz (index 1). |
217
|
|
|
*/ |
218
|
|
|
public function testInsertWithColumnSpecificationAndMultipleValuesForColumnThrowsException() |
219
|
|
|
{ |
220
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
221
|
|
|
|
222
|
|
|
$query->addValues(array('bar', 'baz', 'baz' => 666)); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* @expectedException \InvalidArgumentException |
227
|
|
|
* @expectedExceptionMessage Multiple types specified for column baz (index 1). |
228
|
|
|
*/ |
229
|
|
|
public function testInsertWithColumnSpecificationAndMultipleTypesForColumnThrowsException() |
230
|
|
|
{ |
231
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', array('bar', 'baz')); |
232
|
|
|
|
233
|
|
|
$query->addValues(array('bar', 'baz'), array(\PDO::PARAM_INT, \PDO::PARAM_INT, 'baz' => \PDO::PARAM_STR)); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
public function testExecuteWithMaxInsertRowsPerStatementExceededThrowsException() |
237
|
|
|
{ |
238
|
|
|
$this->connection->expects($this->any()) |
|
|
|
|
239
|
|
|
->method('isTransactionActive') |
240
|
|
|
->will($this->returnValue(false)); |
241
|
|
|
|
242
|
|
|
$platform = $this->connection->getDatabasePlatform(); |
|
|
|
|
243
|
|
|
$insertMaxRows = $platform->getInsertMaxRows(); |
244
|
|
|
|
245
|
|
|
$this->expectException( |
246
|
|
|
'\Doctrine\DBAL\Query\QueryException', |
247
|
|
|
sprintf( |
|
|
|
|
248
|
|
|
'You can only insert %d rows in a single INSERT statement with platform "%s".', |
249
|
|
|
$insertMaxRows, |
250
|
|
|
$platform->getName() |
251
|
|
|
) |
252
|
|
|
); |
253
|
|
|
|
254
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo'); |
255
|
|
|
|
256
|
|
|
for ($i = 0; $i <= $insertMaxRows; $i++) { |
257
|
|
|
$query->addValues(array()); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
$query->execute(); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* testAllValuesInserted |
265
|
|
|
* |
266
|
|
|
* @return void |
267
|
|
|
*/ |
268
|
|
|
public function testAllValuesInserted() |
269
|
|
|
{ |
270
|
|
|
$platform = $this->connection->getDatabasePlatform(); |
|
|
|
|
271
|
|
|
$insertMaxRows = $platform->getInsertMaxRows(); |
272
|
|
|
|
273
|
|
|
$this->connection->expects($this->any()) |
|
|
|
|
274
|
|
|
->method('isTransactionActive') |
275
|
|
|
->will($this->returnValue(true)); |
276
|
|
|
|
277
|
|
|
$actualTypes = []; |
278
|
|
|
$actualParameters = []; |
279
|
|
|
|
280
|
|
|
$this->connection->expects($this->exactly(5)) |
281
|
|
|
->method('executeUpdate') |
282
|
|
|
->will($this->returnCallback( |
283
|
|
|
function (string $sql, array $parameters, array $types) use (&$actualParameters, &$actualTypes) { |
284
|
|
|
$valueSet = []; |
285
|
|
|
$parameterCount = count($parameters); |
286
|
|
|
for ($i = 0; $i < $parameterCount; $i++) { |
287
|
|
|
$valueSet[] = "\\(\\?\\)"; |
288
|
|
|
} |
289
|
|
|
$sqlRegExp = "INSERT\\s+INTO\\s+foo\\s+\\(id\\)\s+VALUES\\s+" . implode("\\s*,\\s*", $valueSet); |
290
|
|
|
|
291
|
|
|
self::assertRegExp("/$sqlRegExp/", $sql, 'Incorrect sql received'); |
292
|
|
|
$actualParameters = array_merge($actualParameters, $parameters); |
293
|
|
|
$actualTypes = array_merge($actualTypes, $types); |
294
|
|
|
|
295
|
|
|
return $parameterCount; |
296
|
|
|
} |
297
|
|
|
) |
298
|
|
|
); |
299
|
|
|
|
300
|
|
|
$query = new BulkInsertQuery($this->connection, 'foo', ['id']); |
301
|
|
|
|
302
|
|
|
$numberOfRows = 4*$insertMaxRows + (int) ceil($insertMaxRows / 2); |
303
|
|
|
for ($i = 0; $i < $numberOfRows; $i++) { |
304
|
|
|
$query->addValues(array('id' => $i), array('id' => 'type' . $i)); |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
$inserted = $query->execute(); |
308
|
|
|
$this->assertSame($numberOfRows, $inserted, 'Unexpected number of inserted rows returned'); |
309
|
|
|
|
310
|
|
|
$this->assertSame($query->getParameters(), $actualParameters, 'Incorrect parameters were passed into the query'); |
311
|
|
|
$this->assertSame($query->getParameterTypes(), $actualTypes, 'Incorrect types were passed into the query'); |
312
|
|
|
} |
313
|
|
|
} |
314
|
|
|
|
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.