Failed Conditions
Push — drop-deprecated ( d77510...d983c4 )
by Michael
40:59 queued 38:23
created

testGetPositionalPlaceholderPositions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\ParameterType;
9
use Doctrine\DBAL\SQLParserUtils;
10
use Doctrine\DBAL\SQLParserUtilsException;
11
use Doctrine\Tests\DbalTestCase;
12
use ReflectionMethod;
13
14
/**
15
 * @group DBAL-78
16
 * @group DDC-1372
17
 */
18
class SQLParserUtilsTest extends DbalTestCase
19
{
20
    public function dataGetPlaceholderPositionalPositions()
21
    {
22
        return [
23
            // none
24
            ['SELECT * FROM Foo', []],
25
26
            // Positionals
27
            ['SELECT ?', [7]],
28
            ['SELECT * FROM Foo WHERE bar IN (?, ?, ?)', [32, 35, 38]],
29
            ['SELECT ? FROM ?', [7, 14]],
30
            ['SELECT "?" FROM foo', []],
31
            ["SELECT '?' FROM foo", []],
32
            ['SELECT `?` FROM foo', []], // Ticket DBAL-552
33
            ['SELECT [?] FROM foo', []],
34
            ["SELECT 'Doctrine\DBAL?' FROM foo", []], // Ticket DBAL-558
35
            ['SELECT "Doctrine\DBAL?" FROM foo', []], // Ticket DBAL-558
36
            ['SELECT `Doctrine\DBAL?` FROM foo', []], // Ticket DBAL-558
37
            ['SELECT [Doctrine\DBAL?] FROM foo', []], // Ticket DBAL-558
38
            ['SELECT "?" FROM foo WHERE bar = ?', [32]],
39
            ["SELECT '?' FROM foo WHERE bar = ?", [32]],
40
            ['SELECT `?` FROM foo WHERE bar = ?', [32]], // Ticket DBAL-552
41
            ['SELECT [?] FROM foo WHERE bar = ?', [32]],
42
            ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[?])', [56]], // Ticket GH-2295
43
            ["SELECT 'Doctrine\DBAL?' FROM foo WHERE bar = ?", [45]], // Ticket DBAL-558
44
            ['SELECT "Doctrine\DBAL?" FROM foo WHERE bar = ?', [45]], // Ticket DBAL-558
45
            ['SELECT `Doctrine\DBAL?` FROM foo WHERE bar = ?', [45]], // Ticket DBAL-558
46
            ['SELECT [Doctrine\DBAL?] FROM foo WHERE bar = ?', [45]], // Ticket DBAL-558
47
            ["SELECT * FROM FOO WHERE bar = 'it\\'s a trap? \\\\' OR bar = ?\nAND baz = \"\\\"quote\\\" me on it? \\\\\" OR baz = ?", [58, 104]],
48
            ['SELECT * FROM foo WHERE foo = ? AND bar = ?', [1 => 42, 0 => 30]], // explicit keys
49
50
        ];
51
    }
52
53
    public function dataGetPlaceholderNamedPositions()
54
    {
55
        return [
56
            // none
57
            ['SELECT * FROM Foo', []],
58
59
            // named
60
            ['SELECT :foo FROM :bar', [7 => 'foo', 17 => 'bar']],
61
            ['SELECT * FROM Foo WHERE bar IN (:name1, :name2)', [32 => 'name1', 40 => 'name2']],
62
            ['SELECT ":foo" FROM Foo WHERE bar IN (:name1, :name2)', [37 => 'name1', 45 => 'name2']],
63
            ["SELECT ':foo' FROM Foo WHERE bar IN (:name1, :name2)", [37 => 'name1', 45 => 'name2']],
64
            ['SELECT :foo_id', [7 => 'foo_id']], // Ticket DBAL-231
65
            ['SELECT @rank := 1', []], // Ticket DBAL-398
66
            ['SELECT @rank := 1 AS rank, :foo AS foo FROM :bar', [27 => 'foo', 44 => 'bar']], // Ticket DBAL-398
67
            ['SELECT * FROM Foo WHERE bar > :start_date AND baz > :start_date', [30 => 'start_date', 52 => 'start_date']], // Ticket GH-113
68
            ['SELECT foo::date as date FROM Foo WHERE bar > :start_date AND baz > :start_date', [46 => 'start_date', 68 => 'start_date']], // Ticket GH-259
69
            ['SELECT `d.ns:col_name` FROM my_table d WHERE `d.date` >= :param1', [57 => 'param1']], // Ticket DBAL-552
70
            ['SELECT [d.ns:col_name] FROM my_table d WHERE [d.date] >= :param1', [57 => 'param1']], // Ticket DBAL-552
71
            ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[:foo])', [56 => 'foo']], // Ticket GH-2295
72
            ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, array[:foo])', [56 => 'foo']],
73
            ['SELECT table.field1, ARRAY[\'3\'] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']', [73 => 'foo']],
74
            ['SELECT table.field1, ARRAY[\'3\']::integer[] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']::integer[]', [84 => 'foo']],
75
            ['SELECT table.field1, ARRAY[:foo] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']', [27 => 'foo', 74 => 'bar']],
76
            ['SELECT table.field1, ARRAY[:foo]::integer[] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']::integer[]', [27 => 'foo', 85 => 'bar']],
77
            [
78
                <<<'SQLDATA'
79
SELECT * FROM foo WHERE 
80
bar = ':not_a_param1 ''":not_a_param2"'''
81
OR bar=:a_param1
82
OR bar=:a_param2||':not_a_param3'
83
OR bar=':not_a_param4 '':not_a_param5'' :not_a_param6'
84
OR bar=''
85
OR bar=:a_param3
86
SQLDATA
87
                ,
88
                [
89
                    74 => 'a_param1',
90
                    91 => 'a_param2',
91
                    190 => 'a_param3',
92
                ],
93
            ],
94
            ["SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE '\\\\') AND (data.description LIKE :condition_1 ESCAPE '\\\\') ORDER BY id ASC", [121 => 'condition_0', 174 => 'condition_1']],
95
            ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE "\\\\") ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']],
96
            ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE \'\\\\\') ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']],
97
            ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE `\\\\`) AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']],
98
            ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE \'\\\\\') AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']],
99
100
        ];
101
    }
102
103
    /**
104
     * @dataProvider dataGetPlaceholderPositionalPositions
105
     */
106
    public function testGetPositionalPlaceholderPositions($query, $expectedParamPos)
107
    {
108
        $reflection = new ReflectionMethod(SQLParserUtils::class, 'getPositionalPlaceholderPositions');
109
        $reflection->setAccessible(true);
110
111
        self::assertEquals($expectedParamPos, $reflection->invoke(null, $query));
112
    }
113
114
    /**
115
     * @dataProvider dataGetPlaceholderNamedPositions
116
     */
117
    public function testGetNamedPlaceholderPositions($query, $expectedParamPos)
118
    {
119
        $reflection = new ReflectionMethod(SQLParserUtils::class, 'getNamedPlaceholderPositions');
120
        $reflection->setAccessible(true);
121
122
        self::assertEquals($expectedParamPos, $reflection->invoke(null, $query));
123
    }
124
125
    public function dataExpandListParameters()
126
    {
127
        return [
128
            // Positional: Very simple with one needle
129
            [
130
                'SELECT * FROM Foo WHERE foo IN (?)',
131
                [[1, 2, 3]],
132
                [Connection::PARAM_INT_ARRAY],
133
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?)',
134
                [1, 2, 3],
135
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
136
            ],
137
            // Positional: One non-list before d one after list-needle
138
            [
139
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?)',
140
                ['string', [1, 2, 3]],
141
                [ParameterType::STRING, Connection::PARAM_INT_ARRAY],
142
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)',
143
                ['string', 1, 2, 3],
144
                [ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
145
            ],
146
            // Positional: One non-list after list-needle
147
            [
148
                'SELECT * FROM Foo WHERE bar IN (?) AND baz = ?',
149
                [[1, 2, 3], 'foo'],
150
                [Connection::PARAM_INT_ARRAY, ParameterType::STRING],
151
                'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?',
152
                [1, 2, 3, 'foo'],
153
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
154
            ],
155
            // Positional: One non-list before and one after list-needle
156
            [
157
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ?',
158
                [1, [1, 2, 3], 4],
159
                [ParameterType::INTEGER, Connection::PARAM_INT_ARRAY, ParameterType::INTEGER],
160
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?',
161
                [1, 1, 2, 3, 4],
162
                [
163
                    ParameterType::INTEGER,
164
                    ParameterType::INTEGER,
165
                    ParameterType::INTEGER,
166
                    ParameterType::INTEGER,
167
                    ParameterType::INTEGER,
168
                ],
169
            ],
170
            // Positional: Two lists
171
            [
172
                'SELECT * FROM Foo WHERE foo IN (?, ?)',
173
                [[1, 2, 3], [4, 5]],
174
                [Connection::PARAM_INT_ARRAY, Connection::PARAM_INT_ARRAY],
175
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)',
176
                [1, 2, 3, 4, 5],
177
                [
178
                    ParameterType::INTEGER,
179
                    ParameterType::INTEGER,
180
                    ParameterType::INTEGER,
181
                    ParameterType::INTEGER,
182
                    ParameterType::INTEGER,
183
                ],
184
            ],
185
            // Positional: Empty "integer" array DDC-1978
186
            [
187
                'SELECT * FROM Foo WHERE foo IN (?)',
188
                [[]],
189
                [Connection::PARAM_INT_ARRAY],
190
                'SELECT * FROM Foo WHERE foo IN (NULL)',
191
                [],
192
                [],
193
            ],
194
            // Positional: Empty "str" array DDC-1978
195
            [
196
                'SELECT * FROM Foo WHERE foo IN (?)',
197
                [[]],
198
                [Connection::PARAM_STR_ARRAY],
199
                'SELECT * FROM Foo WHERE foo IN (NULL)',
200
                [],
201
                [],
202
            ],
203
            // Positional: explicit keys for params and types
204
            [
205
                'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?',
206
                [1 => 'bar', 2 => 'baz', 0 => 1],
207
                [2 => ParameterType::STRING, 1 => ParameterType::STRING],
208
                'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?',
209
                [1 => 'bar', 0 => 1, 2 => 'baz'],
210
                [1 => ParameterType::STRING, 2 => ParameterType::STRING],
211
            ],
212
            // Positional: explicit keys for array params and array types
213
            [
214
                'SELECT * FROM Foo WHERE foo IN (?) AND bar IN (?) AND baz = ?',
215
                [1 => ['bar1', 'bar2'], 2 => true, 0 => [1, 2, 3]],
216
                [2 => ParameterType::BOOLEAN, 1 => Connection::PARAM_STR_ARRAY, 0 => Connection::PARAM_INT_ARRAY],
217
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND bar IN (?, ?) AND baz = ?',
218
                [1, 2, 3, 'bar1', 'bar2', true],
219
                [
220
                    ParameterType::INTEGER,
221
                    ParameterType::INTEGER,
222
                    ParameterType::INTEGER,
223
                    ParameterType::STRING,
224
                    ParameterType::STRING,
225
                    ParameterType::BOOLEAN,
226
                ],
227
            ],
228
            // Positional starts from 1: One non-list before and one after list-needle
229
            [
230
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ? AND foo IN (?)',
231
                [1 => 1, 2 => [1, 2, 3], 3 => 4, 4 => [5, 6]],
232
                [
233
                    1 => ParameterType::INTEGER,
234
                    2 => Connection::PARAM_INT_ARRAY,
235
                    3 => ParameterType::INTEGER,
236
                    4 => Connection::PARAM_INT_ARRAY,
237
                ],
238
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ? AND foo IN (?, ?)',
239
                [1, 1, 2, 3, 4, 5, 6],
240
                [
241
                    ParameterType::INTEGER,
242
                    ParameterType::INTEGER,
243
                    ParameterType::INTEGER,
244
                    ParameterType::INTEGER,
245
                    ParameterType::INTEGER,
246
                    ParameterType::INTEGER,
247
                    ParameterType::INTEGER,
248
                ],
249
            ],
250
            //  Named parameters : Very simple with param int
251
            [
252
                'SELECT * FROM Foo WHERE foo = :foo',
253
                ['foo' => 1],
254
                ['foo' => ParameterType::INTEGER],
255
                'SELECT * FROM Foo WHERE foo = ?',
256
                [1],
257
                [ParameterType::INTEGER],
258
            ],
259
260
             //  Named parameters : Very simple with param int and string
261
            [
262
                'SELECT * FROM Foo WHERE foo = :foo AND bar = :bar',
263
                ['bar' => 'Some String','foo' => 1],
264
                ['foo' => ParameterType::INTEGER, 'bar' => ParameterType::STRING],
265
                'SELECT * FROM Foo WHERE foo = ? AND bar = ?',
266
                [1,'Some String'],
267
                [ParameterType::INTEGER, ParameterType::STRING],
268
            ],
269
            //  Named parameters : Very simple with one needle
270
            [
271
                'SELECT * FROM Foo WHERE foo IN (:foo)',
272
                ['foo' => [1, 2, 3]],
273
                ['foo' => Connection::PARAM_INT_ARRAY],
274
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?)',
275
                [1, 2, 3],
276
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
277
            ],
278
            // Named parameters: One non-list before d one after list-needle
279
            [
280
                'SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar)',
281
                ['foo' => 'string', 'bar' => [1, 2, 3]],
282
                ['foo' => ParameterType::STRING, 'bar' => Connection::PARAM_INT_ARRAY],
283
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)',
284
                ['string', 1, 2, 3],
285
                [ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
286
            ],
287
            // Named parameters: One non-list after list-needle
288
            [
289
                'SELECT * FROM Foo WHERE bar IN (:bar) AND baz = :baz',
290
                ['bar' => [1, 2, 3], 'baz' => 'foo'],
291
                ['bar' => Connection::PARAM_INT_ARRAY, 'baz' => ParameterType::STRING],
292
                'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?',
293
                [1, 2, 3, 'foo'],
294
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
295
            ],
296
            // Named parameters: One non-list before and one after list-needle
297
            [
298
                'SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar) AND baz = :baz',
299
                ['bar' => [1, 2, 3],'foo' => 1, 'baz' => 4],
300
                ['bar' => Connection::PARAM_INT_ARRAY, 'foo' => ParameterType::INTEGER, 'baz' => ParameterType::INTEGER],
301
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?',
302
                [1, 1, 2, 3, 4],
303
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
304
            ],
305
            // Named parameters: Two lists
306
            [
307
                'SELECT * FROM Foo WHERE foo IN (:a, :b)',
308
                ['b' => [4, 5],'a' => [1, 2, 3]],
309
                ['a' => Connection::PARAM_INT_ARRAY, 'b' => Connection::PARAM_INT_ARRAY],
310
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)',
311
                [1, 2, 3, 4, 5],
312
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
313
            ],
314
            //  Named parameters : With the same name arg type string
315
            [
316
                'SELECT * FROM Foo WHERE foo <> :arg AND bar = :arg',
317
                ['arg' => 'Some String'],
318
                ['arg' => ParameterType::STRING],
319
                'SELECT * FROM Foo WHERE foo <> ? AND bar = ?',
320
                ['Some String','Some String'],
321
                [ParameterType::STRING,ParameterType::STRING],
322
            ],
323
             //  Named parameters : With the same name arg
324
            [
325
                'SELECT * FROM Foo WHERE foo IN (:arg) AND NOT bar IN (:arg)',
326
                ['arg' => [1, 2, 3]],
327
                ['arg' => Connection::PARAM_INT_ARRAY],
328
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND NOT bar IN (?, ?, ?)',
329
                [1, 2, 3, 1, 2, 3],
330
                [ParameterType::INTEGER,ParameterType::INTEGER, ParameterType::INTEGER,ParameterType::INTEGER,ParameterType::INTEGER, ParameterType::INTEGER],
331
            ],
332
333
             //  Named parameters : Same name, other name in between DBAL-299
334
            [
335
                'SELECT * FROM Foo WHERE (:foo = 2) AND (:bar = 3) AND (:foo = 2)',
336
                ['foo' => 2,'bar' => 3],
337
                ['foo' => ParameterType::INTEGER,'bar' => ParameterType::INTEGER],
338
                'SELECT * FROM Foo WHERE (? = 2) AND (? = 3) AND (? = 2)',
339
                [2, 3, 2],
340
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
341
            ],
342
             //  Named parameters : Empty "integer" array DDC-1978
343
            [
344
                'SELECT * FROM Foo WHERE foo IN (:foo)',
345
                ['foo' => []],
346
                ['foo' => Connection::PARAM_INT_ARRAY],
347
                'SELECT * FROM Foo WHERE foo IN (NULL)',
348
                [],
349
                [],
350
            ],
351
             //  Named parameters : Two empty "str" array DDC-1978
352
            [
353
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar IN (:bar)',
354
                ['foo' => [], 'bar' => []],
355
                ['foo' => Connection::PARAM_STR_ARRAY, 'bar' => Connection::PARAM_STR_ARRAY],
356
                'SELECT * FROM Foo WHERE foo IN (NULL) OR bar IN (NULL)',
357
                [],
358
                [],
359
            ],
360
            [
361
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar OR baz = :baz',
362
                ['foo' => [1, 2], 'bar' => 'bar', 'baz' => 'baz'],
363
                ['foo' => Connection::PARAM_INT_ARRAY, 'baz' => 'string'],
364
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ? OR baz = ?',
365
                [1, 2, 'bar', 'baz'],
366
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING, 'string'],
367
            ],
368
            [
369
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar',
370
                ['foo' => [1, 2], 'bar' => 'bar'],
371
                ['foo' => Connection::PARAM_INT_ARRAY],
372
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
373
                [1, 2, 'bar'],
374
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
375
            ],
376
            // Params/types with colons
377
            [
378
                'SELECT * FROM Foo WHERE foo = :foo OR bar = :bar',
379
                [':foo' => 'foo', ':bar' => 'bar'],
380
                [':foo' => ParameterType::INTEGER],
381
                'SELECT * FROM Foo WHERE foo = ? OR bar = ?',
382
                ['foo', 'bar'],
383
                [ParameterType::INTEGER, ParameterType::STRING],
384
            ],
385
            [
386
                'SELECT * FROM Foo WHERE foo = :foo OR bar = :bar',
387
                [':foo' => 'foo', ':bar' => 'bar'],
388
                [':foo' => ParameterType::INTEGER, 'bar' => ParameterType::INTEGER],
389
                'SELECT * FROM Foo WHERE foo = ? OR bar = ?',
390
                ['foo', 'bar'],
391
                [ParameterType::INTEGER, ParameterType::INTEGER],
392
            ],
393
            [
394
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar',
395
                [':foo' => [1, 2], ':bar' => 'bar'],
396
                ['foo' => Connection::PARAM_INT_ARRAY],
397
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
398
                [1, 2, 'bar'],
399
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
400
            ],
401
            [
402
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar',
403
                ['foo' => [1, 2], 'bar' => 'bar'],
404
                [':foo' => Connection::PARAM_INT_ARRAY],
405
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
406
                [1, 2, 'bar'],
407
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
408
            ],
409
            // DBAL-522 - null valued parameters are not considered
410
            [
411
                'INSERT INTO Foo (foo, bar) values (:foo, :bar)',
412
                ['foo' => 1, 'bar' => null],
413
                [':foo' => ParameterType::INTEGER, ':bar' => ParameterType::NULL],
414
                'INSERT INTO Foo (foo, bar) values (?, ?)',
415
                [1, null],
416
                [ParameterType::INTEGER, ParameterType::NULL],
417
            ],
418
            [
419
                'INSERT INTO Foo (foo, bar) values (?, ?)',
420
                [1, null],
421
                [ParameterType::INTEGER, ParameterType::NULL],
422
                'INSERT INTO Foo (foo, bar) values (?, ?)',
423
                [1, null],
424
                [ParameterType::INTEGER, ParameterType::NULL],
425
            ],
426
            // DBAL-1205 - Escaped single quotes SQL- and C-Style
427
            [
428
                "SELECT * FROM Foo WHERE foo = :foo||''':not_a_param''\\'' OR bar = ''':not_a_param''\\'':bar",
429
                [':foo' => 1, ':bar' => 2],
430
                [':foo' => ParameterType::INTEGER, 'bar' => ParameterType::INTEGER],
431
                'SELECT * FROM Foo WHERE foo = ?||\'\'\':not_a_param\'\'\\\'\' OR bar = \'\'\':not_a_param\'\'\\\'\'?',
432
                [1, 2],
433
                [ParameterType::INTEGER, ParameterType::INTEGER],
434
            ],
435
        ];
436
    }
437
438
    /**
439
     * @dataProvider dataExpandListParameters
440
     */
441
    public function testExpandListParameters($q, $p, $t, $expectedQuery, $expectedParams, $expectedTypes)
442
    {
443
        [$query, $params, $types] = SQLParserUtils::expandListParameters($q, $p, $t);
444
445
        self::assertEquals($expectedQuery, $query, 'Query was not rewritten correctly.');
446
        self::assertEquals($expectedParams, $params, 'Params dont match');
447
        self::assertEquals($expectedTypes, $types, 'Types dont match');
448
    }
449
450
    public function dataQueryWithMissingParameters()
451
    {
452
        return [
453
            [
454
                'SELECT * FROM foo WHERE bar = :param',
455
                ['other' => 'val'],
456
                [],
457
            ],
458
            [
459
                'SELECT * FROM foo WHERE bar = :param',
460
                [],
461
                [],
462
            ],
463
            [
464
                'SELECT * FROM foo WHERE bar = :param',
465
                [],
466
                ['param' => Connection::PARAM_INT_ARRAY],
467
            ],
468
            [
469
                'SELECT * FROM foo WHERE bar = :param',
470
                [],
471
                [':param' => Connection::PARAM_INT_ARRAY],
472
            ],
473
            [
474
                'SELECT * FROM foo WHERE bar = :param',
475
                [],
476
                ['bar' => Connection::PARAM_INT_ARRAY],
477
            ],
478
            [
479
                'SELECT * FROM foo WHERE bar = :param',
480
                ['bar' => 'value'],
481
                ['bar' => Connection::PARAM_INT_ARRAY],
482
            ],
483
        ];
484
    }
485
486
    /**
487
     * @dataProvider dataQueryWithMissingParameters
488
     */
489
    public function testExceptionIsThrownForMissingParam($query, $params, $types = [])
490
    {
491
        $this->expectException(SQLParserUtilsException::class);
492
        $this->expectExceptionMessage('Value for :param not found in params array. Params array key should be "param"');
493
494
        SQLParserUtils::expandListParameters($query, $params, $types);
495
    }
496
}
497