Completed
Pull Request — master (#3641)
by Roeland
60:53
created

SQLParserUtilsTest::dataGetPlaceholderPositions()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 73
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 55
c 3
b 0
f 0
dl 0
loc 73
rs 8.9818
cc 1
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    /**
98
     * @param int[] $expectedParamPos
99
     *
100
     * @dataProvider dataGetPlaceholderPositions
101
     */
102
    public function testGetPlaceholderPositions(string $query, bool $isPositional, array $expectedParamPos) : void
103
    {
104
        $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

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