Completed
Pull Request — 2.10 (#3843)
by Sergei
25:59 queued 22:24
created

SQLParserUtilsTest   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 482
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 6
eloc 263
c 2
b 0
f 0
dl 0
loc 482
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A testGetPlaceholderPositions() 0 4 1
A testExpandListParameters() 0 13 1
A dataQueryWithMissingParameters() 0 32 1
A testExceptionIsThrownForMissingParam() 0 6 1
B dataExpandListParameters() 0 309 1
B dataGetPlaceholderPositions() 0 73 1
1
<?php
2
3
namespace Doctrine\Tests\DBAL;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\ParameterType;
7
use Doctrine\DBAL\SQLParserUtils;
8
use Doctrine\DBAL\SQLParserUtilsException;
9
use Doctrine\Tests\DbalTestCase;
10
11
/**
12
 * @group DBAL-78
13
 * @group DDC-1372
14
 */
15
class SQLParserUtilsTest extends DbalTestCase
16
{
17
    /**
18
     * @return mixed[][]
19
     */
20
    public static function dataGetPlaceholderPositions() : iterable
21
    {
22
        return [
23
            // none
24
            ['SELECT * FROM Foo', true, []],
25
            ['SELECT * FROM Foo', false, []],
26
27
            // Positionals
28
            ['SELECT ?', true, [7]],
29
            ['SELECT * FROM Foo WHERE bar IN (?, ?, ?)', true, [32, 35, 38]],
30
            ['SELECT ? FROM ?', true, [7, 14]],
31
            ['SELECT "?" FROM foo', true, []],
32
            ["SELECT '?' FROM foo", true, []],
33
            ['SELECT `?` FROM foo', true, []], // Ticket DBAL-552
34
            ['SELECT [?] FROM foo', true, []],
35
            ["SELECT 'Doctrine\DBAL?' FROM foo", true, []], // Ticket DBAL-558
36
            ['SELECT "Doctrine\DBAL?" FROM foo', true, []], // Ticket DBAL-558
37
            ['SELECT `Doctrine\DBAL?` FROM foo', true, []], // Ticket DBAL-558
38
            ['SELECT [Doctrine\DBAL?] FROM foo', true, []], // Ticket DBAL-558
39
            ['SELECT "?" FROM foo WHERE bar = ?', true, [32]],
40
            ["SELECT '?' FROM foo WHERE bar = ?", true, [32]],
41
            ['SELECT `?` FROM foo WHERE bar = ?', true, [32]], // Ticket DBAL-552
42
            ['SELECT [?] FROM foo WHERE bar = ?', true, [32]],
43
            ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[?])', true, [56]], // Ticket GH-2295
44
            ["SELECT 'Doctrine\DBAL?' FROM foo WHERE bar = ?", true, [45]], // Ticket DBAL-558
45
            ['SELECT "Doctrine\DBAL?" FROM foo WHERE bar = ?', true, [45]], // Ticket DBAL-558
46
            ['SELECT `Doctrine\DBAL?` FROM foo WHERE bar = ?', true, [45]], // Ticket DBAL-558
47
            ['SELECT [Doctrine\DBAL?] FROM foo WHERE bar = ?', true, [45]], // Ticket DBAL-558
48
            ["SELECT * FROM FOO WHERE bar = 'it\\'s a trap? \\\\' OR bar = ?\nAND baz = \"\\\"quote\\\" me on it? \\\\\" OR baz = ?", true, [58, 104]],
49
            ['SELECT * FROM foo WHERE foo = ? AND bar = ?', true, [1 => 42, 0 => 30]], // explicit keys
50
51
            // named
52
            ['SELECT :foo FROM :bar', false, [7 => 'foo', 17 => 'bar']],
53
            ['SELECT * FROM Foo WHERE bar IN (:name1, :name2)', false, [32 => 'name1', 40 => 'name2']],
54
            ['SELECT ":foo" FROM Foo WHERE bar IN (:name1, :name2)', false, [37 => 'name1', 45 => 'name2']],
55
            ["SELECT ':foo' FROM Foo WHERE bar IN (:name1, :name2)", false, [37 => 'name1', 45 => 'name2']],
56
            ['SELECT :foo_id', false, [7 => 'foo_id']], // Ticket DBAL-231
57
            ['SELECT @rank := 1', false, []], // Ticket DBAL-398
58
            ['SELECT @rank := 1 AS rank, :foo AS foo FROM :bar', false, [27 => 'foo', 44 => 'bar']], // Ticket DBAL-398
59
            ['SELECT * FROM Foo WHERE bar > :start_date AND baz > :start_date', false, [30 => 'start_date', 52 => 'start_date']], // Ticket GH-113
60
            ['SELECT foo::date as date FROM Foo WHERE bar > :start_date AND baz > :start_date', false, [46 => 'start_date', 68 => 'start_date']], // Ticket GH-259
61
            ['SELECT `d.ns:col_name` FROM my_table d WHERE `d.date` >= :param1', false, [57 => 'param1']], // Ticket DBAL-552
62
            ['SELECT [d.ns:col_name] FROM my_table d WHERE [d.date] >= :param1', false, [57 => 'param1']], // Ticket DBAL-552
63
            ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[:foo])', false, [56 => 'foo']], // Ticket GH-2295
64
            ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, array[:foo])', false, [56 => 'foo']],
65
            ['SELECT table.field1, ARRAY[\'3\'] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']', false, [73 => 'foo']],
66
            ['SELECT table.field1, ARRAY[\'3\']::integer[] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']::integer[]', false, [84 => 'foo']],
67
            ['SELECT table.field1, ARRAY[:foo] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']', false, [27 => 'foo', 74 => 'bar']],
68
            ['SELECT table.field1, ARRAY[:foo]::integer[] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']::integer[]', false, [27 => 'foo', 85 => 'bar']],
69
            [
70
                <<<'SQLDATA'
71
SELECT * FROM foo WHERE 
72
bar = ':not_a_param1 ''":not_a_param2"'''
73
OR bar=:a_param1
74
OR bar=:a_param2||':not_a_param3'
75
OR bar=':not_a_param4 '':not_a_param5'' :not_a_param6'
76
OR bar=''
77
OR bar=:a_param3
78
SQLDATA
79
                ,
80
                false,
81
                [
82
                    74 => 'a_param1',
83
                    91 => 'a_param2',
84
                    190 => 'a_param3',
85
                ],
86
            ],
87
            ["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", false, [121 => 'condition_0', 174 => 'condition_1']],
88
            ['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', false, [121 => 'condition_0', 174 => 'condition_1']],
89
            ['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', false, [121 => 'condition_0', 174 => 'condition_1']],
90
            ['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', false, [121 => 'condition_0', 174 => 'condition_1']],
91
            ['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', false, [121 => 'condition_0', 174 => 'condition_1']],
92
            ["SELECT * FROM Foo WHERE (foo.bar LIKE :condition_0 ESCAPE '\') AND (foo.baz = :condition_1) AND (foo.bak LIKE :condition_2 ESCAPE '\')", false, [38 => 'condition_0', 78 => 'condition_1', 110 => 'condition_2']],
93
        ];
94
    }
95
96
    /**
97
     * @param int[] $expectedParamPos
98
     *
99
     * @dataProvider dataGetPlaceholderPositions
100
     */
101
    public function testGetPlaceholderPositions(string $query, bool $isPositional, array $expectedParamPos) : void
102
    {
103
        $actualParamPos = SQLParserUtils::getPlaceholderPositions($query, $isPositional);
1 ignored issue
show
Deprecated Code introduced by
The function Doctrine\DBAL\SQLParserU...tPlaceholderPositions() has been deprecated: Will be removed as internal implementation detail. ( Ignorable by Annotation )

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

103
        $actualParamPos = /** @scrutinizer ignore-deprecated */ SQLParserUtils::getPlaceholderPositions($query, $isPositional);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
104
        self::assertEquals($expectedParamPos, $actualParamPos);
105
    }
106
107
    /**
108
     * @return mixed[][]
109
     */
110
    public static function dataExpandListParameters() : iterable
111
    {
112
        return [
113
            // Positional: Very simple with one needle
114
            [
115
                'SELECT * FROM Foo WHERE foo IN (?)',
116
                [[1, 2, 3]],
117
                [Connection::PARAM_INT_ARRAY],
118
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?)',
119
                [1, 2, 3],
120
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
121
            ],
122
            // Positional: One non-list before d one after list-needle
123
            [
124
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?)',
125
                ['string', [1, 2, 3]],
126
                [ParameterType::STRING, Connection::PARAM_INT_ARRAY],
127
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)',
128
                ['string', 1, 2, 3],
129
                [ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
130
            ],
131
            // Positional: One non-list after list-needle
132
            [
133
                'SELECT * FROM Foo WHERE bar IN (?) AND baz = ?',
134
                [[1, 2, 3], 'foo'],
135
                [Connection::PARAM_INT_ARRAY, ParameterType::STRING],
136
                'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?',
137
                [1, 2, 3, 'foo'],
138
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
139
            ],
140
            // Positional: One non-list before and one after list-needle
141
            [
142
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ?',
143
                [1, [1, 2, 3], 4],
144
                [ParameterType::INTEGER, Connection::PARAM_INT_ARRAY, ParameterType::INTEGER],
145
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?',
146
                [1, 1, 2, 3, 4],
147
                [
148
                    ParameterType::INTEGER,
149
                    ParameterType::INTEGER,
150
                    ParameterType::INTEGER,
151
                    ParameterType::INTEGER,
152
                    ParameterType::INTEGER,
153
                ],
154
            ],
155
            // Positional: Two lists
156
            [
157
                'SELECT * FROM Foo WHERE foo IN (?, ?)',
158
                [[1, 2, 3], [4, 5]],
159
                [Connection::PARAM_INT_ARRAY, Connection::PARAM_INT_ARRAY],
160
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)',
161
                [1, 2, 3, 4, 5],
162
                [
163
                    ParameterType::INTEGER,
164
                    ParameterType::INTEGER,
165
                    ParameterType::INTEGER,
166
                    ParameterType::INTEGER,
167
                    ParameterType::INTEGER,
168
                ],
169
            ],
170
            // Positional: Empty "integer" array DDC-1978
171
            [
172
                'SELECT * FROM Foo WHERE foo IN (?)',
173
                [[]],
174
                [Connection::PARAM_INT_ARRAY],
175
                'SELECT * FROM Foo WHERE foo IN (NULL)',
176
                [],
177
                [],
178
            ],
179
            // Positional: Empty "str" array DDC-1978
180
            [
181
                'SELECT * FROM Foo WHERE foo IN (?)',
182
                [[]],
183
                [Connection::PARAM_STR_ARRAY],
184
                'SELECT * FROM Foo WHERE foo IN (NULL)',
185
                [],
186
                [],
187
            ],
188
            // Positional: explicit keys for params and types
189
            [
190
                'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?',
191
                [1 => 'bar', 2 => 'baz', 0 => 1],
192
                [2 => ParameterType::STRING, 1 => ParameterType::STRING],
193
                'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?',
194
                [1 => 'bar', 0 => 1, 2 => 'baz'],
195
                [1 => ParameterType::STRING, 2 => ParameterType::STRING],
196
            ],
197
            // Positional: explicit keys for array params and array types
198
            [
199
                'SELECT * FROM Foo WHERE foo IN (?) AND bar IN (?) AND baz = ?',
200
                [1 => ['bar1', 'bar2'], 2 => true, 0 => [1, 2, 3]],
201
                [2 => ParameterType::BOOLEAN, 1 => Connection::PARAM_STR_ARRAY, 0 => Connection::PARAM_INT_ARRAY],
202
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND bar IN (?, ?) AND baz = ?',
203
                [1, 2, 3, 'bar1', 'bar2', true],
204
                [
205
                    ParameterType::INTEGER,
206
                    ParameterType::INTEGER,
207
                    ParameterType::INTEGER,
208
                    ParameterType::STRING,
209
                    ParameterType::STRING,
210
                    ParameterType::BOOLEAN,
211
                ],
212
            ],
213
            // Positional starts from 1: One non-list before and one after list-needle
214
            [
215
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ? AND foo IN (?)',
216
                [1 => 1, 2 => [1, 2, 3], 3 => 4, 4 => [5, 6]],
217
                [
218
                    1 => ParameterType::INTEGER,
219
                    2 => Connection::PARAM_INT_ARRAY,
220
                    3 => ParameterType::INTEGER,
221
                    4 => Connection::PARAM_INT_ARRAY,
222
                ],
223
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ? AND foo IN (?, ?)',
224
                [1, 1, 2, 3, 4, 5, 6],
225
                [
226
                    ParameterType::INTEGER,
227
                    ParameterType::INTEGER,
228
                    ParameterType::INTEGER,
229
                    ParameterType::INTEGER,
230
                    ParameterType::INTEGER,
231
                    ParameterType::INTEGER,
232
                    ParameterType::INTEGER,
233
                ],
234
            ],
235
            //  Named parameters : Very simple with param int
236
            [
237
                'SELECT * FROM Foo WHERE foo = :foo',
238
                ['foo' => 1],
239
                ['foo' => ParameterType::INTEGER],
240
                'SELECT * FROM Foo WHERE foo = ?',
241
                [1],
242
                [ParameterType::INTEGER],
243
            ],
244
245
             //  Named parameters : Very simple with param int and string
246
            [
247
                'SELECT * FROM Foo WHERE foo = :foo AND bar = :bar',
248
                ['bar' => 'Some String','foo' => 1],
249
                ['foo' => ParameterType::INTEGER, 'bar' => ParameterType::STRING],
250
                'SELECT * FROM Foo WHERE foo = ? AND bar = ?',
251
                [1,'Some String'],
252
                [ParameterType::INTEGER, ParameterType::STRING],
253
            ],
254
            //  Named parameters : Very simple with one needle
255
            [
256
                'SELECT * FROM Foo WHERE foo IN (:foo)',
257
                ['foo' => [1, 2, 3]],
258
                ['foo' => Connection::PARAM_INT_ARRAY],
259
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?)',
260
                [1, 2, 3],
261
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
262
            ],
263
            // Named parameters: One non-list before d one after list-needle
264
            [
265
                'SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar)',
266
                ['foo' => 'string', 'bar' => [1, 2, 3]],
267
                ['foo' => ParameterType::STRING, 'bar' => Connection::PARAM_INT_ARRAY],
268
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)',
269
                ['string', 1, 2, 3],
270
                [ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
271
            ],
272
            // Named parameters: One non-list after list-needle
273
            [
274
                'SELECT * FROM Foo WHERE bar IN (:bar) AND baz = :baz',
275
                ['bar' => [1, 2, 3], 'baz' => 'foo'],
276
                ['bar' => Connection::PARAM_INT_ARRAY, 'baz' => ParameterType::STRING],
277
                'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?',
278
                [1, 2, 3, 'foo'],
279
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
280
            ],
281
            // Named parameters: One non-list before and one after list-needle
282
            [
283
                'SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar) AND baz = :baz',
284
                ['bar' => [1, 2, 3],'foo' => 1, 'baz' => 4],
285
                ['bar' => Connection::PARAM_INT_ARRAY, 'foo' => ParameterType::INTEGER, 'baz' => ParameterType::INTEGER],
286
                'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?',
287
                [1, 1, 2, 3, 4],
288
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
289
            ],
290
            // Named parameters: Two lists
291
            [
292
                'SELECT * FROM Foo WHERE foo IN (:a, :b)',
293
                ['b' => [4, 5],'a' => [1, 2, 3]],
294
                ['a' => Connection::PARAM_INT_ARRAY, 'b' => Connection::PARAM_INT_ARRAY],
295
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)',
296
                [1, 2, 3, 4, 5],
297
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
298
            ],
299
            //  Named parameters : With the same name arg type string
300
            [
301
                'SELECT * FROM Foo WHERE foo <> :arg AND bar = :arg',
302
                ['arg' => 'Some String'],
303
                ['arg' => ParameterType::STRING],
304
                'SELECT * FROM Foo WHERE foo <> ? AND bar = ?',
305
                ['Some String','Some String'],
306
                [ParameterType::STRING,ParameterType::STRING],
307
            ],
308
             //  Named parameters : With the same name arg
309
            [
310
                'SELECT * FROM Foo WHERE foo IN (:arg) AND NOT bar IN (:arg)',
311
                ['arg' => [1, 2, 3]],
312
                ['arg' => Connection::PARAM_INT_ARRAY],
313
                'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND NOT bar IN (?, ?, ?)',
314
                [1, 2, 3, 1, 2, 3],
315
                [ParameterType::INTEGER,ParameterType::INTEGER, ParameterType::INTEGER,ParameterType::INTEGER,ParameterType::INTEGER, ParameterType::INTEGER],
316
            ],
317
318
             //  Named parameters : Same name, other name in between DBAL-299
319
            [
320
                'SELECT * FROM Foo WHERE (:foo = 2) AND (:bar = 3) AND (:foo = 2)',
321
                ['foo' => 2,'bar' => 3],
322
                ['foo' => ParameterType::INTEGER,'bar' => ParameterType::INTEGER],
323
                'SELECT * FROM Foo WHERE (? = 2) AND (? = 3) AND (? = 2)',
324
                [2, 3, 2],
325
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER],
326
            ],
327
             //  Named parameters : Empty "integer" array DDC-1978
328
            [
329
                'SELECT * FROM Foo WHERE foo IN (:foo)',
330
                ['foo' => []],
331
                ['foo' => Connection::PARAM_INT_ARRAY],
332
                'SELECT * FROM Foo WHERE foo IN (NULL)',
333
                [],
334
                [],
335
            ],
336
             //  Named parameters : Two empty "str" array DDC-1978
337
            [
338
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar IN (:bar)',
339
                ['foo' => [], 'bar' => []],
340
                ['foo' => Connection::PARAM_STR_ARRAY, 'bar' => Connection::PARAM_STR_ARRAY],
341
                'SELECT * FROM Foo WHERE foo IN (NULL) OR bar IN (NULL)',
342
                [],
343
                [],
344
            ],
345
            [
346
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar OR baz = :baz',
347
                ['foo' => [1, 2], 'bar' => 'bar', 'baz' => 'baz'],
348
                ['foo' => Connection::PARAM_INT_ARRAY, 'baz' => 'string'],
349
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ? OR baz = ?',
350
                [1, 2, 'bar', 'baz'],
351
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING, 'string'],
352
            ],
353
            [
354
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar',
355
                ['foo' => [1, 2], 'bar' => 'bar'],
356
                ['foo' => Connection::PARAM_INT_ARRAY],
357
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
358
                [1, 2, 'bar'],
359
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
360
            ],
361
            // Params/types with colons
362
            [
363
                'SELECT * FROM Foo WHERE foo = :foo OR bar = :bar',
364
                [':foo' => 'foo', ':bar' => 'bar'],
365
                [':foo' => ParameterType::INTEGER],
366
                'SELECT * FROM Foo WHERE foo = ? OR bar = ?',
367
                ['foo', 'bar'],
368
                [ParameterType::INTEGER, ParameterType::STRING],
369
            ],
370
            [
371
                'SELECT * FROM Foo WHERE foo = :foo OR bar = :bar',
372
                [':foo' => 'foo', ':bar' => 'bar'],
373
                [':foo' => ParameterType::INTEGER, 'bar' => ParameterType::INTEGER],
374
                'SELECT * FROM Foo WHERE foo = ? OR bar = ?',
375
                ['foo', 'bar'],
376
                [ParameterType::INTEGER, ParameterType::INTEGER],
377
            ],
378
            [
379
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar',
380
                [':foo' => [1, 2], ':bar' => 'bar'],
381
                ['foo' => Connection::PARAM_INT_ARRAY],
382
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
383
                [1, 2, 'bar'],
384
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
385
            ],
386
            [
387
                'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar',
388
                ['foo' => [1, 2], 'bar' => 'bar'],
389
                [':foo' => Connection::PARAM_INT_ARRAY],
390
                'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
391
                [1, 2, 'bar'],
392
                [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING],
393
            ],
394
            // DBAL-522 - null valued parameters are not considered
395
            [
396
                'INSERT INTO Foo (foo, bar) values (:foo, :bar)',
397
                ['foo' => 1, 'bar' => null],
398
                [':foo' => ParameterType::INTEGER, ':bar' => ParameterType::NULL],
399
                'INSERT INTO Foo (foo, bar) values (?, ?)',
400
                [1, null],
401
                [ParameterType::INTEGER, ParameterType::NULL],
402
            ],
403
            [
404
                'INSERT INTO Foo (foo, bar) values (?, ?)',
405
                [1, null],
406
                [ParameterType::INTEGER, ParameterType::NULL],
407
                'INSERT INTO Foo (foo, bar) values (?, ?)',
408
                [1, null],
409
                [ParameterType::INTEGER, ParameterType::NULL],
410
            ],
411
            // DBAL-1205 - Escaped single quotes SQL- and C-Style
412
            [
413
                "SELECT * FROM Foo WHERE foo = :foo||''':not_a_param''\\'' OR bar = ''':not_a_param''\\'':bar",
414
                [':foo' => 1, ':bar' => 2],
415
                [':foo' => ParameterType::INTEGER, 'bar' => ParameterType::INTEGER],
416
                'SELECT * FROM Foo WHERE foo = ?||\'\'\':not_a_param\'\'\\\'\' OR bar = \'\'\':not_a_param\'\'\\\'\'?',
417
                [1, 2],
418
                [ParameterType::INTEGER, ParameterType::INTEGER],
419
            ],
420
        ];
421
    }
422
423
    /**
424
     * @param mixed[] $params
425
     * @param mixed[] $types
426
     * @param mixed[] $expectedParams
427
     * @param mixed[] $expectedTypes
428
     *
429
     * @dataProvider dataExpandListParameters
430
     */
431
    public function testExpandListParameters(
432
        string $query,
433
        array $params,
434
        array $types,
435
        string $expectedQuery,
436
        array $expectedParams,
437
        array $expectedTypes
438
    ) : void {
439
        [$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types);
440
441
        self::assertEquals($expectedQuery, $query, 'Query was not rewritten correctly.');
442
        self::assertEquals($expectedParams, $params, 'Params dont match');
443
        self::assertEquals($expectedTypes, $types, 'Types dont match');
444
    }
445
446
    /**
447
     * @return mixed[][]
448
     */
449
    public static function dataQueryWithMissingParameters() : iterable
450
    {
451
        return [
452
            [
453
                'SELECT * FROM foo WHERE bar = :param',
454
                ['other' => 'val'],
455
                [],
456
            ],
457
            [
458
                'SELECT * FROM foo WHERE bar = :param',
459
                [],
460
                [],
461
            ],
462
            [
463
                'SELECT * FROM foo WHERE bar = :param',
464
                [],
465
                ['param' => Connection::PARAM_INT_ARRAY],
466
            ],
467
            [
468
                'SELECT * FROM foo WHERE bar = :param',
469
                [],
470
                [':param' => Connection::PARAM_INT_ARRAY],
471
            ],
472
            [
473
                'SELECT * FROM foo WHERE bar = :param',
474
                [],
475
                ['bar' => Connection::PARAM_INT_ARRAY],
476
            ],
477
            [
478
                'SELECT * FROM foo WHERE bar = :param',
479
                ['bar' => 'value'],
480
                ['bar' => Connection::PARAM_INT_ARRAY],
481
            ],
482
        ];
483
    }
484
485
    /**
486
     * @param mixed[] $params
487
     * @param mixed[] $types
488
     *
489
     * @dataProvider dataQueryWithMissingParameters
490
     */
491
    public function testExceptionIsThrownForMissingParam(string $query, array $params, array $types = []) : void
492
    {
493
        $this->expectException(SQLParserUtilsException::class);
494
        $this->expectExceptionMessage('Value for :param not found in params array. Params array key should be "param"');
495
496
        SQLParserUtils::expandListParameters($query, $params, $types);
497
    }
498
}
499