1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace PhpMyAdmin\SqlParser\Tests\Utils; |
6
|
|
|
|
7
|
|
|
use PhpMyAdmin\SqlParser\Parser; |
8
|
|
|
use PhpMyAdmin\SqlParser\Tests\TestCase; |
9
|
|
|
use PhpMyAdmin\SqlParser\Utils\Query; |
10
|
|
|
use PhpMyAdmin\SqlParser\Utils\StatementFlags; |
11
|
|
|
use PhpMyAdmin\SqlParser\Utils\StatementType; |
12
|
|
|
use PHPUnit\Framework\Attributes\DataProvider; |
13
|
|
|
|
14
|
|
|
class QueryTest extends TestCase |
15
|
|
|
{ |
16
|
|
|
/** |
17
|
|
|
* @psalm-param non-empty-string $query |
18
|
|
|
* @psalm-param array<key-of<properties-of<StatementFlags>>, bool|StatementType|null> $expected |
19
|
|
|
*/ |
20
|
|
|
#[DataProvider('getFlagsProvider')] |
21
|
|
|
public function testGetFlags(string $query, array $expected): void |
22
|
|
|
{ |
23
|
|
|
$parser = new Parser($query); |
24
|
|
|
$flags = new StatementFlags(); |
25
|
|
|
foreach ($expected as $property => $expectedValue) { |
26
|
|
|
$flags->$property = $expectedValue; |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
$this->assertEquals($flags, Query::getFlags($parser->statements[0])); |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
/** @psalm-return list<array{non-empty-string, array<key-of<properties-of<StatementFlags>>, bool|StatementType|null>}> */ |
33
|
|
|
public static function getFlagsProvider(): array |
34
|
|
|
{ |
35
|
|
|
return [ |
36
|
|
|
[ |
37
|
|
|
'ALTER TABLE DROP col', |
38
|
|
|
[ |
39
|
|
|
'reload' => true, |
40
|
|
|
'queryType' => StatementType::Alter, |
41
|
|
|
], |
42
|
|
|
], |
43
|
|
|
[ |
44
|
|
|
'CALL test()', |
45
|
|
|
[ |
46
|
|
|
'isProcedure' => true, |
47
|
|
|
'queryType' => StatementType::Call, |
48
|
|
|
], |
49
|
|
|
], |
50
|
|
|
[ |
51
|
|
|
'CREATE TABLE tbl (id INT)', |
52
|
|
|
[ |
53
|
|
|
'reload' => true, |
54
|
|
|
'queryType' => StatementType::Create, |
55
|
|
|
], |
56
|
|
|
], |
57
|
|
|
[ |
58
|
|
|
'CHECK TABLE tbl', |
59
|
|
|
[ |
60
|
|
|
'isMaint' => true, |
61
|
|
|
'queryType' => StatementType::Check, |
62
|
|
|
], |
63
|
|
|
], |
64
|
|
|
[ |
65
|
|
|
'DELETE FROM tbl', |
66
|
|
|
[ |
67
|
|
|
'isAffected' => true, |
68
|
|
|
'isDelete' => true, |
69
|
|
|
'queryType' => StatementType::Delete, |
70
|
|
|
], |
71
|
|
|
], |
72
|
|
|
[ |
73
|
|
|
'DROP VIEW v', |
74
|
|
|
[ |
75
|
|
|
'reload' => true, |
76
|
|
|
'queryType' => StatementType::Drop, |
77
|
|
|
], |
78
|
|
|
], |
79
|
|
|
[ |
80
|
|
|
'DROP DATABASE db', |
81
|
|
|
[ |
82
|
|
|
'dropDatabase' => true, |
83
|
|
|
'reload' => true, |
84
|
|
|
'queryType' => StatementType::Drop, |
85
|
|
|
], |
86
|
|
|
], |
87
|
|
|
[ |
88
|
|
|
'EXPLAIN tbl', |
89
|
|
|
[ |
90
|
|
|
'isExplain' => true, |
91
|
|
|
'queryType' => StatementType::Explain, |
92
|
|
|
], |
93
|
|
|
], |
94
|
|
|
[ |
95
|
|
|
'LOAD DATA INFILE \'/tmp/test.txt\' INTO TABLE test', |
96
|
|
|
[ |
97
|
|
|
'isAffected' => true, |
98
|
|
|
'isInsert' => true, |
99
|
|
|
'queryType' => StatementType::Load, |
100
|
|
|
], |
101
|
|
|
], |
102
|
|
|
[ |
103
|
|
|
'INSERT INTO tbl VALUES (1)', |
104
|
|
|
[ |
105
|
|
|
'isAffected' => true, |
106
|
|
|
'isInsert' => true, |
107
|
|
|
'queryType' => StatementType::Insert, |
108
|
|
|
], |
109
|
|
|
], |
110
|
|
|
[ |
111
|
|
|
'REPLACE INTO tbl VALUES (2)', |
112
|
|
|
[ |
113
|
|
|
'isAffected' => true, |
114
|
|
|
'isReplace' => true, |
115
|
|
|
'isInsert' => true, |
116
|
|
|
'queryType' => StatementType::Replace, |
117
|
|
|
], |
118
|
|
|
], |
119
|
|
|
[ |
120
|
|
|
'SELECT 1', |
121
|
|
|
[ |
122
|
|
|
'isSelect' => true, |
123
|
|
|
'queryType' => StatementType::Select, |
124
|
|
|
], |
125
|
|
|
], |
126
|
|
|
[ |
127
|
|
|
'SELECT * FROM tbl', |
128
|
|
|
[ |
129
|
|
|
'isSelect' => true, |
130
|
|
|
'selectFrom' => true, |
131
|
|
|
'queryType' => StatementType::Select, |
132
|
|
|
], |
133
|
|
|
], |
134
|
|
|
[ |
135
|
|
|
'SELECT DISTINCT * FROM tbl LIMIT 0, 10 ORDER BY id', |
136
|
|
|
[ |
137
|
|
|
'distinct' => true, |
138
|
|
|
'isSelect' => true, |
139
|
|
|
'selectFrom' => true, |
140
|
|
|
'limit' => true, |
141
|
|
|
'order' => true, |
142
|
|
|
'queryType' => StatementType::Select, |
143
|
|
|
], |
144
|
|
|
], |
145
|
|
|
[ |
146
|
|
|
'SELECT * FROM actor GROUP BY actor_id', |
147
|
|
|
[ |
148
|
|
|
'isGroup' => true, |
149
|
|
|
'isSelect' => true, |
150
|
|
|
'selectFrom' => true, |
151
|
|
|
'group' => true, |
152
|
|
|
'queryType' => StatementType::Select, |
153
|
|
|
], |
154
|
|
|
], |
155
|
|
|
[ |
156
|
|
|
'SELECT col1, col2 FROM table1 PROCEDURE ANALYSE(10, 2000);', |
157
|
|
|
[ |
158
|
|
|
'isAnalyse' => true, |
159
|
|
|
'isSelect' => true, |
160
|
|
|
'selectFrom' => true, |
161
|
|
|
'queryType' => StatementType::Select, |
162
|
|
|
], |
163
|
|
|
], |
164
|
|
|
[ |
165
|
|
|
'SELECT * FROM tbl INTO OUTFILE "/tmp/export.txt"', |
166
|
|
|
[ |
167
|
|
|
'isExport' => true, |
168
|
|
|
'isSelect' => true, |
169
|
|
|
'selectFrom' => true, |
170
|
|
|
'queryType' => StatementType::Select, |
171
|
|
|
], |
172
|
|
|
], |
173
|
|
|
[ |
174
|
|
|
'SELECT COUNT(id), SUM(id) FROM tbl', |
175
|
|
|
[ |
176
|
|
|
'isCount' => true, |
177
|
|
|
'isFunc' => true, |
178
|
|
|
'isSelect' => true, |
179
|
|
|
'selectFrom' => true, |
180
|
|
|
'queryType' => StatementType::Select, |
181
|
|
|
], |
182
|
|
|
], |
183
|
|
|
[ |
184
|
|
|
'SELECT (SELECT "foo")', |
185
|
|
|
[ |
186
|
|
|
'isSelect' => true, |
187
|
|
|
'isSubQuery' => true, |
188
|
|
|
'queryType' => StatementType::Select, |
189
|
|
|
], |
190
|
|
|
], |
191
|
|
|
[ |
192
|
|
|
'SELECT * FROM customer HAVING store_id = 2;', |
193
|
|
|
[ |
194
|
|
|
'isSelect' => true, |
195
|
|
|
'selectFrom' => true, |
196
|
|
|
'isGroup' => true, |
197
|
|
|
'having' => true, |
198
|
|
|
'queryType' => StatementType::Select, |
199
|
|
|
], |
200
|
|
|
], |
201
|
|
|
[ |
202
|
|
|
'SELECT * FROM table1 INNER JOIN table2 ON table1.id=table2.id;', |
203
|
|
|
[ |
204
|
|
|
'isSelect' => true, |
205
|
|
|
'selectFrom' => true, |
206
|
|
|
'join' => true, |
207
|
|
|
'queryType' => StatementType::Select, |
208
|
|
|
], |
209
|
|
|
], |
210
|
|
|
[ |
211
|
|
|
'SHOW CREATE TABLE tbl', |
212
|
|
|
[ |
213
|
|
|
'isShow' => true, |
214
|
|
|
'queryType' => StatementType::Show, |
215
|
|
|
], |
216
|
|
|
], |
217
|
|
|
[ |
218
|
|
|
'UPDATE tbl SET id = 1', |
219
|
|
|
[ |
220
|
|
|
'isAffected' => true, |
221
|
|
|
'queryType' => StatementType::Update, |
222
|
|
|
], |
223
|
|
|
], |
224
|
|
|
[ |
225
|
|
|
'ANALYZE TABLE tbl', |
226
|
|
|
[ |
227
|
|
|
'isMaint' => true, |
228
|
|
|
'queryType' => StatementType::Analyze, |
229
|
|
|
], |
230
|
|
|
], |
231
|
|
|
[ |
232
|
|
|
'CHECKSUM TABLE tbl', |
233
|
|
|
[ |
234
|
|
|
'isMaint' => true, |
235
|
|
|
'queryType' => StatementType::Checksum, |
236
|
|
|
], |
237
|
|
|
], |
238
|
|
|
[ |
239
|
|
|
'OPTIMIZE TABLE tbl', |
240
|
|
|
[ |
241
|
|
|
'isMaint' => true, |
242
|
|
|
'queryType' => StatementType::Optimize, |
243
|
|
|
], |
244
|
|
|
], |
245
|
|
|
[ |
246
|
|
|
'REPAIR TABLE tbl', |
247
|
|
|
[ |
248
|
|
|
'isMaint' => true, |
249
|
|
|
'queryType' => StatementType::Repair, |
250
|
|
|
], |
251
|
|
|
], |
252
|
|
|
[ |
253
|
|
|
'(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) ' . |
254
|
|
|
'UNION ' . |
255
|
|
|
'(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);', |
256
|
|
|
[ |
257
|
|
|
'isSelect' => true, |
258
|
|
|
'selectFrom' => true, |
259
|
|
|
'limit' => true, |
260
|
|
|
'order' => true, |
261
|
|
|
'union' => true, |
262
|
|
|
'queryType' => StatementType::Select, |
263
|
|
|
], |
264
|
|
|
], |
265
|
|
|
[ |
266
|
|
|
'SELECT * FROM orders AS ord WHERE 1', |
267
|
|
|
[ |
268
|
|
|
'queryType' => StatementType::Select, |
269
|
|
|
'isSelect' => true, |
270
|
|
|
'selectFrom' => true, |
271
|
|
|
], |
272
|
|
|
], |
273
|
|
|
[ |
274
|
|
|
'SET NAMES \'latin\'', |
275
|
|
|
['queryType' => StatementType::Set], |
276
|
|
|
], |
277
|
|
|
]; |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
public function testGetFlagsWithEmptyString(): void |
281
|
|
|
{ |
282
|
|
|
$statementInfo = Query::getAll(''); |
283
|
|
|
self::assertEquals(new Parser(''), $statementInfo->parser); |
284
|
|
|
self::assertNull($statementInfo->statement); |
285
|
|
|
self::assertSame([], $statementInfo->selectTables); |
286
|
|
|
self::assertSame([], $statementInfo->selectExpressions); |
287
|
|
|
$flags = $statementInfo->flags; |
288
|
|
|
self::assertFalse($flags->distinct); |
289
|
|
|
self::assertFalse($flags->dropDatabase); |
290
|
|
|
self::assertFalse($flags->group); |
291
|
|
|
self::assertFalse($flags->having); |
292
|
|
|
self::assertFalse($flags->isAffected); |
293
|
|
|
self::assertFalse($flags->isAnalyse); |
294
|
|
|
self::assertFalse($flags->isCount); |
295
|
|
|
/** @psalm-suppress DeprecatedProperty */ |
296
|
|
|
self::assertFalse($flags->isDelete); |
|
|
|
|
297
|
|
|
/** @psalm-suppress DeprecatedProperty */ |
298
|
|
|
self::assertFalse($flags->isExplain); |
|
|
|
|
299
|
|
|
self::assertFalse($flags->isExport); |
300
|
|
|
self::assertFalse($flags->isFunc); |
301
|
|
|
self::assertFalse($flags->isGroup); |
302
|
|
|
self::assertFalse($flags->isInsert); |
303
|
|
|
self::assertFalse($flags->isMaint); |
304
|
|
|
self::assertFalse($flags->isProcedure); |
305
|
|
|
/** @psalm-suppress DeprecatedProperty */ |
306
|
|
|
self::assertFalse($flags->isReplace); |
|
|
|
|
307
|
|
|
/** @psalm-suppress DeprecatedProperty */ |
308
|
|
|
self::assertFalse($flags->isSelect); |
|
|
|
|
309
|
|
|
/** @psalm-suppress DeprecatedProperty */ |
310
|
|
|
self::assertFalse($flags->isShow); |
|
|
|
|
311
|
|
|
self::assertFalse($flags->isSubQuery); |
312
|
|
|
self::assertFalse($flags->join); |
313
|
|
|
self::assertFalse($flags->limit); |
314
|
|
|
self::assertFalse($flags->offset); |
315
|
|
|
self::assertFalse($flags->order); |
316
|
|
|
self::assertNull($flags->queryType); |
317
|
|
|
self::assertFalse($flags->reload); |
318
|
|
|
self::assertFalse($flags->selectFrom); |
319
|
|
|
self::assertFalse($flags->union); |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
public function testGetAll(): void |
323
|
|
|
{ |
324
|
|
|
$query = 'SELECT *, actor.actor_id, sakila2.film.* FROM sakila2.city, sakila2.film, actor'; |
325
|
|
|
$parser = new Parser($query); |
326
|
|
|
$statementInfo = Query::getAll($query); |
327
|
|
|
self::assertEquals($parser, $statementInfo->parser); |
328
|
|
|
self::assertEquals($parser->statements[0], $statementInfo->statement); |
329
|
|
|
self::assertEquals(Query::getFlags($parser->statements[0]), $statementInfo->flags); |
330
|
|
|
self::assertSame([['actor', null], ['film', 'sakila2']], $statementInfo->selectTables); |
331
|
|
|
self::assertSame(['*'], $statementInfo->selectExpressions); |
332
|
|
|
|
333
|
|
|
$query = 'SELECT * FROM sakila.actor, film'; |
334
|
|
|
$parser = new Parser($query); |
335
|
|
|
$statementInfo = Query::getAll($query); |
336
|
|
|
self::assertEquals($parser, $statementInfo->parser); |
337
|
|
|
self::assertEquals($parser->statements[0], $statementInfo->statement); |
338
|
|
|
self::assertEquals(Query::getFlags($parser->statements[0]), $statementInfo->flags); |
339
|
|
|
self::assertSame([['actor', 'sakila'], ['film', null]], $statementInfo->selectTables); |
340
|
|
|
self::assertSame(['*'], $statementInfo->selectExpressions); |
341
|
|
|
|
342
|
|
|
$query = 'SELECT a.actor_id FROM sakila.actor AS a, film'; |
343
|
|
|
$parser = new Parser($query); |
344
|
|
|
$statementInfo = Query::getAll($query); |
345
|
|
|
self::assertEquals($parser, $statementInfo->parser); |
346
|
|
|
self::assertEquals($parser->statements[0], $statementInfo->statement); |
347
|
|
|
self::assertEquals(Query::getFlags($parser->statements[0]), $statementInfo->flags); |
348
|
|
|
self::assertSame([['actor', 'sakila']], $statementInfo->selectTables); |
349
|
|
|
self::assertSame([], $statementInfo->selectExpressions); |
350
|
|
|
|
351
|
|
|
$query = 'SELECT CASE WHEN 2 IS NULL THEN "this is true" ELSE "this is false" END'; |
352
|
|
|
$parser = new Parser($query); |
353
|
|
|
$statementInfo = Query::getAll($query); |
354
|
|
|
self::assertEquals($parser, $statementInfo->parser); |
355
|
|
|
self::assertEquals($parser->statements[0], $statementInfo->statement); |
356
|
|
|
self::assertEquals(Query::getFlags($parser->statements[0]), $statementInfo->flags); |
357
|
|
|
self::assertSame([], $statementInfo->selectTables); |
358
|
|
|
self::assertSame( |
359
|
|
|
['CASE WHEN 2 IS NULL THEN "this is true" ELSE "this is false" END'], |
360
|
|
|
$statementInfo->selectExpressions, |
361
|
|
|
); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
/** @param string[] $expected */ |
365
|
|
|
#[DataProvider('getTablesProvider')] |
366
|
|
|
public function testGetTables(string $query, array $expected): void |
367
|
|
|
{ |
368
|
|
|
$parser = new Parser($query); |
369
|
|
|
$this->assertEquals( |
370
|
|
|
$expected, |
371
|
|
|
Query::getTables($parser->statements[0]), |
372
|
|
|
); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* @return array<int, array<int, string|string[]>> |
377
|
|
|
* @psalm-return list<array{string, string[]}> |
378
|
|
|
*/ |
379
|
|
|
public static function getTablesProvider(): array |
380
|
|
|
{ |
381
|
|
|
return [ |
382
|
|
|
[ |
383
|
|
|
'INSERT INTO tbl(`id`, `name`) VALUES (1, "Name")', |
384
|
|
|
['`tbl`'], |
385
|
|
|
], |
386
|
|
|
[ |
387
|
|
|
'INSERT INTO 0tbl(`id`, `name`) VALUES (1, "Name")', |
388
|
|
|
['`0tbl`'], |
389
|
|
|
], |
390
|
|
|
[ |
391
|
|
|
'UPDATE tbl SET id = 0', |
392
|
|
|
['`tbl`'], |
393
|
|
|
], |
394
|
|
|
[ |
395
|
|
|
'UPDATE 0tbl SET id = 0', |
396
|
|
|
['`0tbl`'], |
397
|
|
|
], |
398
|
|
|
[ |
399
|
|
|
'DELETE FROM tbl WHERE id < 10', |
400
|
|
|
['`tbl`'], |
401
|
|
|
], |
402
|
|
|
[ |
403
|
|
|
'DELETE FROM 0tbl WHERE id < 10', |
404
|
|
|
['`0tbl`'], |
405
|
|
|
], |
406
|
|
|
[ |
407
|
|
|
'TRUNCATE tbl', |
408
|
|
|
['`tbl`'], |
409
|
|
|
], |
410
|
|
|
[ |
411
|
|
|
'DROP VIEW v', |
412
|
|
|
[], |
413
|
|
|
], |
414
|
|
|
[ |
415
|
|
|
'DROP TABLE tbl1, tbl2', |
416
|
|
|
[ |
417
|
|
|
'`tbl1`', |
418
|
|
|
'`tbl2`', |
419
|
|
|
], |
420
|
|
|
], |
421
|
|
|
[ |
422
|
|
|
'RENAME TABLE a TO b, c TO d', |
423
|
|
|
[ |
424
|
|
|
'`a`', |
425
|
|
|
'`c`', |
426
|
|
|
], |
427
|
|
|
], |
428
|
|
|
]; |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
public function testGetClause(): void |
432
|
|
|
{ |
433
|
|
|
/* Assertion 1 */ |
434
|
|
|
$parser = new Parser( |
435
|
|
|
'SELECT c.city_id, c.country_id ' . |
436
|
|
|
'FROM `city` ' . |
437
|
|
|
'WHERE city_id < 1 /* test */' . |
438
|
|
|
'ORDER BY city_id ASC ' . |
439
|
|
|
'LIMIT 0, 1 ' . |
440
|
|
|
'INTO OUTFILE "/dev/null"', |
441
|
|
|
); |
442
|
|
|
$this->assertNotNull($parser->list); |
443
|
|
|
$this->assertEquals( |
444
|
|
|
'0, 1 INTO OUTFILE "/dev/null"', |
445
|
|
|
Query::getClause( |
446
|
|
|
$parser->statements[0], |
447
|
|
|
$parser->list, |
|
|
|
|
448
|
|
|
'LIMIT', |
449
|
|
|
0, |
450
|
|
|
), |
451
|
|
|
); |
452
|
|
|
// Assert it returns all clauses between FROM and LIMIT |
453
|
|
|
$this->assertEquals( |
454
|
|
|
'WHERE city_id < 1 ORDER BY city_id ASC', |
455
|
|
|
Query::getClause( |
456
|
|
|
$parser->statements[0], |
457
|
|
|
$parser->list, |
458
|
|
|
'FROM', |
459
|
|
|
'LIMIT', |
460
|
|
|
), |
461
|
|
|
); |
462
|
|
|
// Assert it returns all clauses between SELECT and LIMIT |
463
|
|
|
$this->assertEquals( |
464
|
|
|
'FROM `city` WHERE city_id < 1 ORDER BY city_id ASC', |
465
|
|
|
Query::getClause( |
466
|
|
|
$parser->statements[0], |
467
|
|
|
$parser->list, |
468
|
|
|
'LIMIT', |
469
|
|
|
'SELECT', |
470
|
|
|
), |
471
|
|
|
); |
472
|
|
|
|
473
|
|
|
/* Assertion 2 */ |
474
|
|
|
$parser = new Parser( |
475
|
|
|
'DELETE FROM `renewal` ' . |
476
|
|
|
'WHERE number = "1DB" AND actionDate <= CURRENT_DATE() ' . |
477
|
|
|
'ORDER BY id ASC ' . |
478
|
|
|
'LIMIT 1', |
479
|
|
|
); |
480
|
|
|
$this->assertNotNull($parser->list); |
481
|
|
|
$this->assertEquals( |
482
|
|
|
'number = "1DB" AND actionDate <= CURRENT_DATE()', |
483
|
|
|
Query::getClause( |
484
|
|
|
$parser->statements[0], |
485
|
|
|
$parser->list, |
486
|
|
|
'WHERE', |
487
|
|
|
), |
488
|
|
|
); |
489
|
|
|
$this->assertEquals( |
490
|
|
|
'1', |
491
|
|
|
Query::getClause( |
492
|
|
|
$parser->statements[0], |
493
|
|
|
$parser->list, |
494
|
|
|
'LIMIT', |
495
|
|
|
), |
496
|
|
|
); |
497
|
|
|
$this->assertEquals( |
498
|
|
|
'id ASC', |
499
|
|
|
Query::getClause( |
500
|
|
|
$parser->statements[0], |
501
|
|
|
$parser->list, |
502
|
|
|
'ORDER BY', |
503
|
|
|
), |
504
|
|
|
); |
505
|
|
|
|
506
|
|
|
/* Assertion 3 */ |
507
|
|
|
$parser = new Parser( |
508
|
|
|
'UPDATE `renewal` SET `some_column` = 1 ' . |
509
|
|
|
'WHERE number = "1DB" AND actionDate <= CURRENT_DATE() ' . |
510
|
|
|
'ORDER BY id ASC ' . |
511
|
|
|
'LIMIT 1', |
512
|
|
|
); |
513
|
|
|
$this->assertNotNull($parser->list); |
514
|
|
|
$this->assertEquals( |
515
|
|
|
'number = "1DB" AND actionDate <= CURRENT_DATE()', |
516
|
|
|
Query::getClause( |
517
|
|
|
$parser->statements[0], |
518
|
|
|
$parser->list, |
519
|
|
|
'WHERE', |
520
|
|
|
), |
521
|
|
|
); |
522
|
|
|
$this->assertEquals( |
523
|
|
|
'1', |
524
|
|
|
Query::getClause( |
525
|
|
|
$parser->statements[0], |
526
|
|
|
$parser->list, |
527
|
|
|
'LIMIT', |
528
|
|
|
), |
529
|
|
|
); |
530
|
|
|
$this->assertEquals( |
531
|
|
|
'id ASC', |
532
|
|
|
Query::getClause( |
533
|
|
|
$parser->statements[0], |
534
|
|
|
$parser->list, |
535
|
|
|
'ORDER BY', |
536
|
|
|
), |
537
|
|
|
); |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
public function testReplaceClause(): void |
541
|
|
|
{ |
542
|
|
|
$parser = new Parser('SELECT *, (SELECT 1) FROM film LIMIT 0, 10;'); |
543
|
|
|
$this->assertNotNull($parser->list); |
544
|
|
|
$this->assertEquals( |
545
|
|
|
'SELECT *, (SELECT 1) FROM film WHERE film_id > 0 LIMIT 0, 10', |
546
|
|
|
Query::replaceClause( |
547
|
|
|
$parser->statements[0], |
548
|
|
|
$parser->list, |
|
|
|
|
549
|
|
|
'WHERE film_id > 0', |
550
|
|
|
), |
551
|
|
|
); |
552
|
|
|
|
553
|
|
|
$parser = new Parser( |
554
|
|
|
'select supplier.city, supplier.id from supplier ' |
555
|
|
|
. 'union select customer.city, customer.id from customer', |
556
|
|
|
); |
557
|
|
|
$this->assertNotNull($parser->list); |
558
|
|
|
$this->assertEquals( |
559
|
|
|
'select supplier.city, supplier.id from supplier ' |
560
|
|
|
. 'union select customer.city, customer.id from customer' |
561
|
|
|
. ' ORDER BY city ', |
562
|
|
|
Query::replaceClause( |
563
|
|
|
$parser->statements[0], |
564
|
|
|
$parser->list, |
565
|
|
|
'ORDER BY city', |
566
|
|
|
), |
567
|
|
|
); |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
public function testReplaceClauseOnlyKeyword(): void |
571
|
|
|
{ |
572
|
|
|
$parser = new Parser('SELECT *, (SELECT 1) FROM film LIMIT 0, 10'); |
573
|
|
|
$this->assertNotNull($parser->list); |
574
|
|
|
$this->assertEquals( |
575
|
|
|
' SELECT SQL_CALC_FOUND_ROWS *, (SELECT 1) FROM film LIMIT 0, 10', |
576
|
|
|
Query::replaceClause( |
577
|
|
|
$parser->statements[0], |
578
|
|
|
$parser->list, |
|
|
|
|
579
|
|
|
'SELECT SQL_CALC_FOUND_ROWS', |
580
|
|
|
null, |
581
|
|
|
true, |
582
|
|
|
), |
583
|
|
|
); |
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
public function testReplaceNonExistingPart(): void |
587
|
|
|
{ |
588
|
|
|
$parser = new Parser('ALTER TABLE `sale_mast` OPTIMIZE PARTITION p3'); |
589
|
|
|
$this->assertNotNull($parser->list); |
590
|
|
|
$this->assertEquals( |
591
|
|
|
' ALTER TABLE `sale_mast` OPTIMIZE PARTITION p3', |
592
|
|
|
Query::replaceClause( |
593
|
|
|
$parser->statements[0], |
594
|
|
|
$parser->list, |
|
|
|
|
595
|
|
|
'ORDER BY', |
596
|
|
|
'', |
597
|
|
|
), |
598
|
|
|
); |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
public function testReplaceClauses(): void |
602
|
|
|
{ |
603
|
|
|
$parser = new Parser('SELECT *, (SELECT 1) FROM film LIMIT 0, 10;'); |
604
|
|
|
$this->assertNotNull($parser->list); |
605
|
|
|
$this->assertSame('', Query::replaceClauses($parser->statements[0], $parser->list, [])); |
|
|
|
|
606
|
|
|
$this->assertEquals( |
607
|
|
|
'SELECT *, (SELECT 1) FROM film WHERE film_id > 0 LIMIT 0, 10', |
608
|
|
|
Query::replaceClauses( |
609
|
|
|
$parser->statements[0], |
610
|
|
|
$parser->list, |
611
|
|
|
[ |
612
|
|
|
[ |
613
|
|
|
'WHERE', |
614
|
|
|
'WHERE film_id > 0', |
615
|
|
|
], |
616
|
|
|
], |
617
|
|
|
), |
618
|
|
|
); |
619
|
|
|
|
620
|
|
|
$parser = new Parser( |
621
|
|
|
'SELECT c.city_id, c.country_id ' . |
622
|
|
|
'INTO OUTFILE "/dev/null" ' . |
623
|
|
|
'FROM `city` ' . |
624
|
|
|
'WHERE city_id < 1 ' . |
625
|
|
|
'ORDER BY city_id ASC ' . |
626
|
|
|
'LIMIT 0, 1 ', |
627
|
|
|
); |
628
|
|
|
$this->assertNotNull($parser->list); |
629
|
|
|
$this->assertEquals( |
630
|
|
|
'SELECT c.city_id, c.country_id ' . |
631
|
|
|
'INTO OUTFILE "/dev/null" ' . |
632
|
|
|
'FROM city AS c ' . |
633
|
|
|
'ORDER BY city_id ASC ' . |
634
|
|
|
'LIMIT 0, 10 ', |
635
|
|
|
Query::replaceClauses( |
636
|
|
|
$parser->statements[0], |
637
|
|
|
$parser->list, |
638
|
|
|
[ |
639
|
|
|
[ |
640
|
|
|
'FROM', |
641
|
|
|
'FROM city AS c', |
642
|
|
|
], |
643
|
|
|
[ |
644
|
|
|
'WHERE', |
645
|
|
|
'', |
646
|
|
|
], |
647
|
|
|
[ |
648
|
|
|
'LIMIT', |
649
|
|
|
'LIMIT 0, 10', |
650
|
|
|
], |
651
|
|
|
], |
652
|
|
|
), |
653
|
|
|
); |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
public function testGetFirstStatement(): void |
657
|
|
|
{ |
658
|
|
|
$query = 'USE saki'; |
659
|
|
|
$delimiter = null; |
660
|
|
|
[$statement, $query, $delimiter] = Query::getFirstStatement($query, $delimiter); |
661
|
|
|
$this->assertNull($statement); |
662
|
|
|
$this->assertEquals('USE saki', $query); |
663
|
|
|
$this->assertNull($delimiter); |
664
|
|
|
|
665
|
|
|
$query = 'USE sakila; ' . |
666
|
|
|
'/*test comment*/' . |
667
|
|
|
'SELECT * FROM actor; ' . |
668
|
|
|
'DELIMITER $$ ' . |
669
|
|
|
'UPDATE actor SET last_name = "abc"$$' . |
670
|
|
|
'/*!SELECT * FROM actor WHERE last_name = "abc"*/$$'; |
671
|
|
|
$delimiter = null; |
672
|
|
|
|
673
|
|
|
[$statement, $query, $delimiter] = Query::getFirstStatement($query, $delimiter); |
674
|
|
|
$this->assertEquals('USE sakila;', $statement); |
675
|
|
|
|
676
|
|
|
[$statement, $query, $delimiter] = Query::getFirstStatement($query, $delimiter); |
677
|
|
|
$this->assertEquals('SELECT * FROM actor;', $statement); |
678
|
|
|
|
679
|
|
|
[$statement, $query, $delimiter] = Query::getFirstStatement($query, $delimiter); |
680
|
|
|
$this->assertEquals('DELIMITER $$', $statement); |
681
|
|
|
$this->assertEquals('$$', $delimiter); |
682
|
|
|
|
683
|
|
|
[$statement, $query, $delimiter] = Query::getFirstStatement($query, $delimiter); |
684
|
|
|
$this->assertEquals('UPDATE actor SET last_name = "abc"$$', $statement); |
685
|
|
|
|
686
|
|
|
[$statement, $query, $delimiter] = Query::getFirstStatement($query, $delimiter); |
687
|
|
|
$this->assertEquals('SELECT * FROM actor WHERE last_name = "abc"$$', $statement); |
688
|
|
|
$this->assertSame('', $query); |
689
|
|
|
$this->assertSame('$$', $delimiter); |
690
|
|
|
} |
691
|
|
|
} |
692
|
|
|
|
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.