1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace PhpMyAdmin\Tests\Controllers\Database; |
6
|
|
|
|
7
|
|
|
use PhpMyAdmin\CheckUserPrivileges; |
8
|
|
|
use PhpMyAdmin\Controllers\Database\RoutinesController; |
9
|
|
|
use PhpMyAdmin\Database\Routines; |
|
|
|
|
10
|
|
|
use PhpMyAdmin\Http\ServerRequest; |
11
|
|
|
use PhpMyAdmin\Template; |
12
|
|
|
use PhpMyAdmin\Tests\AbstractTestCase; |
13
|
|
|
use PhpMyAdmin\Tests\Stubs\ResponseRenderer; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @covers \PhpMyAdmin\Controllers\Database\RoutinesController |
17
|
|
|
* @covers \PhpMyAdmin\Database\Routines |
18
|
|
|
*/ |
19
|
|
|
final class RoutinesControllerTest extends AbstractTestCase |
20
|
|
|
{ |
21
|
|
|
public function testWithRoutines(): void |
22
|
|
|
{ |
23
|
|
|
$GLOBALS['server'] = 2; |
24
|
|
|
$GLOBALS['text_dir'] = 'ltr'; |
25
|
|
|
$GLOBALS['PMA_PHP_SELF'] = 'index.php'; |
26
|
|
|
$GLOBALS['db'] = 'test_db'; |
27
|
|
|
$GLOBALS['cfg']['Server']['DisableIS'] = true; |
28
|
|
|
|
29
|
|
|
$dummyDbi = $this->createDbiDummy(); |
30
|
|
|
// phpcs:disable Generic.Files.LineLength.TooLong |
31
|
|
|
$dummyDbi->removeDefaultResults(); |
32
|
|
|
$dummyDbi->addSelectDb('test_db'); |
33
|
|
|
$dummyDbi->addResult('SELECT CURRENT_USER();', [['definer@localhost']], ['CURRENT_USER()']); |
34
|
|
|
$dummyDbi->addResult( |
35
|
|
|
'SHOW GRANTS', |
36
|
|
|
[['GRANT ALL PRIVILEGES ON *.* TO `definer`@`localhost`']], |
37
|
|
|
['Grants for definer@localhost'], |
38
|
|
|
); |
39
|
|
|
$dummyDbi->addResult( |
40
|
|
|
'SHOW FUNCTION STATUS WHERE `Db` = \'test_db\'', |
41
|
|
|
[['test_db', 'test_func', 'FUNCTION', 'definer@localhost']], |
42
|
|
|
['Db', 'Name', 'Type', 'Definer'], |
43
|
|
|
); |
44
|
|
|
$dummyDbi->addResult( |
45
|
|
|
'SHOW PROCEDURE STATUS WHERE `Db` = \'test_db\'', |
46
|
|
|
[['test_db', 'test_proc', 'PROCEDURE', 'definer@localhost']], |
47
|
|
|
['Db', 'Name', 'Type', 'Definer'], |
48
|
|
|
); |
49
|
|
|
$dummyDbi->addResult('SELECT @@lower_case_table_names', []); |
50
|
|
|
$dummyDbi->addResult( |
51
|
|
|
"SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA COLLATE utf8_bin='test_db' AND SPECIFIC_NAME='test_func'AND ROUTINE_TYPE='FUNCTION';", |
52
|
|
|
[['definer@localhost']], |
53
|
|
|
['DEFINER'], |
54
|
|
|
); |
55
|
|
|
$dummyDbi->addResult( |
56
|
|
|
"SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE='''definer''@''localhost''' AND PRIVILEGE_TYPE='CREATE ROUTINE'", |
57
|
|
|
[['CREATE ROUTINE']], |
58
|
|
|
['PRIVILEGE_TYPE'], |
59
|
|
|
); |
60
|
|
|
$dummyDbi->addResult( |
61
|
|
|
"SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE='''definer''@''localhost''' AND PRIVILEGE_TYPE='EXECUTE'", |
62
|
|
|
[['EXECUTE']], |
63
|
|
|
['PRIVILEGE_TYPE'], |
64
|
|
|
); |
65
|
|
|
$dummyDbi->addResult( |
66
|
|
|
'SHOW CREATE FUNCTION `test_db`.`test_func`', |
67
|
|
|
[['test_func', 'CREATE FUNCTION `test_func` (p INT) RETURNS int(11) BEGIN END']], |
68
|
|
|
['Function', 'Create Function'], |
69
|
|
|
); |
70
|
|
|
$dummyDbi->addResult( |
71
|
|
|
"SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA COLLATE utf8_bin='test_db' AND SPECIFIC_NAME='test_proc'AND ROUTINE_TYPE='PROCEDURE';", |
72
|
|
|
[['definer@localhost']], |
73
|
|
|
['DEFINER'], |
74
|
|
|
); |
75
|
|
|
$dummyDbi->addResult( |
76
|
|
|
"SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE='''definer''@''localhost''' AND PRIVILEGE_TYPE='CREATE ROUTINE'", |
77
|
|
|
[['CREATE ROUTINE']], |
78
|
|
|
['PRIVILEGE_TYPE'], |
79
|
|
|
); |
80
|
|
|
$dummyDbi->addResult( |
81
|
|
|
"SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE='''definer''@''localhost''' AND PRIVILEGE_TYPE='EXECUTE'", |
82
|
|
|
[['EXECUTE']], |
83
|
|
|
['PRIVILEGE_TYPE'], |
84
|
|
|
); |
85
|
|
|
$dummyDbi->addResult( |
86
|
|
|
'SHOW CREATE PROCEDURE `test_db`.`test_proc`', |
87
|
|
|
[['test_proc2', 'CREATE PROCEDURE `test_proc2` (p INT) BEGIN END']], |
88
|
|
|
['Procedure', 'Create Procedure'], |
89
|
|
|
); |
90
|
|
|
$dummyDbi->addResult( |
91
|
|
|
"SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE='''definer''@''localhost''' AND PRIVILEGE_TYPE='CREATE ROUTINE'", |
92
|
|
|
[['CREATE ROUTINE']], |
93
|
|
|
['PRIVILEGE_TYPE'], |
94
|
|
|
); |
95
|
|
|
// phpcs:enable |
96
|
|
|
|
97
|
|
|
$dbi = $this->createDatabaseInterface($dummyDbi); |
98
|
|
|
$GLOBALS['dbi'] = $dbi; |
99
|
|
|
$template = new Template(); |
100
|
|
|
$response = new ResponseRenderer(); |
101
|
|
|
|
102
|
|
|
(new RoutinesController( |
103
|
|
|
$response, |
104
|
|
|
$template, |
105
|
|
|
new CheckUserPrivileges($dbi), |
106
|
|
|
$dbi, |
107
|
|
|
new Routines($dbi, $template, $response), |
108
|
|
|
))($this->createStub(ServerRequest::class)); |
109
|
|
|
|
110
|
|
|
$actual = $response->getHTMLResult(); |
111
|
|
|
// phpcs:disable Generic.Files.LineLength.TooLong |
112
|
|
|
$expected = <<<'HTML' |
113
|
|
|
<div class="container-fluid my-3"> |
114
|
|
|
<h2> |
115
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Routines" alt="Routines" class="icon ic_b_routines"> Routines</span> |
116
|
|
|
<a href="index.php?route=/url&url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F5.7%2Fen%2Fstored-routines.html" target="mysql_doc"><img src="themes/dot.gif" title="Documentation" alt="Documentation" class="icon ic_b_help"></a> |
117
|
|
|
</h2> |
118
|
|
|
|
119
|
|
|
<div class="d-flex flex-wrap my-3"> <div> |
120
|
|
|
<div class="input-group"> |
121
|
|
|
<div class="input-group-text"> |
122
|
|
|
<div class="form-check mb-0"> |
123
|
|
|
<input class="form-check-input checkall_box" type="checkbox" value="" id="checkAllCheckbox" form="rteListForm"> |
124
|
|
|
<label class="form-check-label" for="checkAllCheckbox">Check all</label> |
125
|
|
|
</div> |
126
|
|
|
</div> |
127
|
|
|
<button class="btn btn-outline-secondary" id="bulkActionExportButton" type="submit" name="submit_mult" value="export" form="rteListForm" title="Export"> |
128
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Export" alt="Export" class="icon ic_b_export"> Export</span> |
129
|
|
|
</button> |
130
|
|
|
<button class="btn btn-outline-secondary" id="bulkActionDropButton" type="submit" name="submit_mult" value="drop" form="rteListForm" title="Drop"> |
131
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Drop" alt="Drop" class="icon ic_b_drop"> Drop</span> |
132
|
|
|
</button> |
133
|
|
|
</div> |
134
|
|
|
</div> |
135
|
|
|
|
136
|
|
|
<div class="ms-auto"> |
137
|
|
|
<div class="input-group"> |
138
|
|
|
<span class="input-group-text"><img src="themes/dot.gif" title="Search" alt="Search" class="icon ic_b_search"></span> |
139
|
|
|
<input class="form-control" name="filterText" type="text" id="filterText" value="" placeholder="Search" aria-label="Search"> |
140
|
|
|
</div> |
141
|
|
|
</div> |
142
|
|
|
<div class="ms-2"> |
143
|
|
|
<a class="ajax add_anchor btn btn-primary" href="index.php?route=/database/routines&db=test_db&table=&add_item=1&server=2&lang=en" role="button"> |
144
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Create new routine" alt="Create new routine" class="icon ic_b_routine_add"> Create new routine</span> |
145
|
|
|
</a> |
146
|
|
|
</div> |
147
|
|
|
</div> |
148
|
|
|
|
149
|
|
|
<form id="rteListForm" class="ajax" action="index.php?route=/database/routines&server=2&lang=en"> |
150
|
|
|
<input type="hidden" name="db" value="test_db"><input type="hidden" name="server" value="2"><input type="hidden" name="lang" value="en"><input type="hidden" name="token" value="token"> |
151
|
|
|
|
152
|
|
|
<div id="nothing2display" class="hide"> |
153
|
|
|
<div class="alert alert-primary" role="alert"> |
154
|
|
|
<img src="themes/dot.gif" title="" alt="" class="icon ic_s_notice"> There are no routines to display. |
155
|
|
|
</div> |
156
|
|
|
|
157
|
|
|
</div> |
158
|
|
|
|
159
|
|
|
<table id="routinesTable" class="table table-striped table-hover data w-auto"> |
160
|
|
|
<thead> |
161
|
|
|
<tr> |
162
|
|
|
<th></th> |
163
|
|
|
<th>Name</th> |
164
|
|
|
<th>Type</th> |
165
|
|
|
<th>Returns</th> |
166
|
|
|
<th colspan="4"></th> |
167
|
|
|
</tr> |
168
|
|
|
</thead> |
169
|
|
|
<tbody> |
170
|
|
|
<tr class="hide"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr data-filter-row="TEST_FUNC"> |
171
|
|
|
<td> |
172
|
|
|
<input type="checkbox" class="checkall" name="item_name[]" value="test_func"> |
173
|
|
|
</td> |
174
|
|
|
<td> |
175
|
|
|
<span class="drop_sql hide">DROP FUNCTION IF EXISTS `test_func`</span> |
176
|
|
|
<strong>test_func</strong> |
177
|
|
|
</td> |
178
|
|
|
<td>FUNCTION</td> |
179
|
|
|
<td dir="ltr"></td> |
180
|
|
|
<td> |
181
|
|
|
<a class="ajax edit_anchor" href="index.php?route=/database/routines&db=test_db&table=&edit_item=1&item_name=test_func&item_type=FUNCTION&server=2&lang=en"> |
182
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Edit" alt="Edit" class="icon ic_b_edit"> Edit</span> |
183
|
|
|
</a> |
184
|
|
|
</td> |
185
|
|
|
<td> |
186
|
|
|
<a class="ajax exec_anchor" href="index.php?route=/database/routines&db=test_db&table=&execute_dialog=1&item_name=test_func&item_type=FUNCTION&server=2&lang=en"> |
187
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Execute" alt="Execute" class="icon ic_b_nextpage"> Execute</span> |
188
|
|
|
</a> |
189
|
|
|
</td> |
190
|
|
|
<td> |
191
|
|
|
<a class="ajax export_anchor" href="index.php?route=/database/routines&db=test_db&table=&export_item=1&item_name=test_func&item_type=FUNCTION&server=2&lang=en"> |
192
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Export" alt="Export" class="icon ic_b_export"> Export</span> |
193
|
|
|
</a> |
194
|
|
|
</td> |
195
|
|
|
<td> |
196
|
|
|
<a href="index.php" data-post="route=/sql&server=2&lang=en&db=test_db&table=&sql_query=DROP+FUNCTION+IF+EXISTS+%60test_func%60&goto=index.php%3Froute%3D%2Fdatabase%2Froutines%26db%3Dtest_db%26server%3D2%26lang%3Den&server=2&lang=en" class="ajax drop_anchor"><span class="text-nowrap"><img src="themes/dot.gif" title="Drop" alt="Drop" class="icon ic_b_drop"> Drop</span></a> |
197
|
|
|
</td> |
198
|
|
|
</tr> |
199
|
|
|
<tr data-filter-row="TEST_PROC"> |
200
|
|
|
<td> |
201
|
|
|
<input type="checkbox" class="checkall" name="item_name[]" value="test_proc"> |
202
|
|
|
</td> |
203
|
|
|
<td> |
204
|
|
|
<span class="drop_sql hide">DROP PROCEDURE IF EXISTS `test_proc`</span> |
205
|
|
|
<strong>test_proc</strong> |
206
|
|
|
</td> |
207
|
|
|
<td>PROCEDURE</td> |
208
|
|
|
<td dir="ltr"></td> |
209
|
|
|
<td> |
210
|
|
|
<a class="ajax edit_anchor" href="index.php?route=/database/routines&db=test_db&table=&edit_item=1&item_name=test_proc&item_type=PROCEDURE&server=2&lang=en"> |
211
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Edit" alt="Edit" class="icon ic_b_edit"> Edit</span> |
212
|
|
|
</a> |
213
|
|
|
</td> |
214
|
|
|
<td> |
215
|
|
|
<a class="ajax exec_anchor" href="index.php?route=/database/routines&db=test_db&table=&execute_dialog=1&item_name=test_proc&item_type=PROCEDURE&server=2&lang=en"> |
216
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Execute" alt="Execute" class="icon ic_b_nextpage"> Execute</span> |
217
|
|
|
</a> |
218
|
|
|
</td> |
219
|
|
|
<td> |
220
|
|
|
<a class="ajax export_anchor" href="index.php?route=/database/routines&db=test_db&table=&export_item=1&item_name=test_proc&item_type=PROCEDURE&server=2&lang=en"> |
221
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Export" alt="Export" class="icon ic_b_export"> Export</span> |
222
|
|
|
</a> |
223
|
|
|
</td> |
224
|
|
|
<td> |
225
|
|
|
<a href="index.php" data-post="route=/sql&server=2&lang=en&db=test_db&table=&sql_query=DROP+PROCEDURE+IF+EXISTS+%60test_proc%60&goto=index.php%3Froute%3D%2Fdatabase%2Froutines%26db%3Dtest_db%26server%3D2%26lang%3Den&server=2&lang=en" class="ajax drop_anchor"><span class="text-nowrap"><img src="themes/dot.gif" title="Drop" alt="Drop" class="icon ic_b_drop"> Drop</span></a> |
226
|
|
|
</td> |
227
|
|
|
</tr> |
228
|
|
|
|
229
|
|
|
</tbody> |
230
|
|
|
</table> |
231
|
|
|
</form> |
232
|
|
|
</div> |
233
|
|
|
|
234
|
|
|
HTML; |
235
|
|
|
// phpcs:enable |
236
|
|
|
|
237
|
|
|
$this->assertSame($expected, $actual); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
public function testWithoutRoutines(): void |
241
|
|
|
{ |
242
|
|
|
$GLOBALS['server'] = 2; |
243
|
|
|
$GLOBALS['text_dir'] = 'ltr'; |
244
|
|
|
$GLOBALS['PMA_PHP_SELF'] = 'index.php'; |
245
|
|
|
$GLOBALS['db'] = 'test_db'; |
246
|
|
|
$GLOBALS['cfg']['Server']['DisableIS'] = true; |
247
|
|
|
|
248
|
|
|
$dummyDbi = $this->createDbiDummy(); |
249
|
|
|
// phpcs:disable Generic.Files.LineLength.TooLong |
250
|
|
|
$dummyDbi->removeDefaultResults(); |
251
|
|
|
$dummyDbi->addSelectDb('test_db'); |
252
|
|
|
$dummyDbi->addResult('SELECT CURRENT_USER();', [['definer@localhost']], ['CURRENT_USER()']); |
253
|
|
|
$dummyDbi->addResult( |
254
|
|
|
'SHOW GRANTS', |
255
|
|
|
[['GRANT ALL PRIVILEGES ON *.* TO `definer`@`localhost`']], |
256
|
|
|
['Grants for definer@localhost'], |
257
|
|
|
); |
258
|
|
|
$dummyDbi->addResult('SHOW FUNCTION STATUS WHERE `Db` = \'test_db\'', [], ['Db', 'Name', 'Type', 'Definer']); |
259
|
|
|
$dummyDbi->addResult('SHOW PROCEDURE STATUS WHERE `Db` = \'test_db\'', [], ['Db', 'Name', 'Type', 'Definer']); |
260
|
|
|
$dummyDbi->addResult( |
261
|
|
|
"SELECT `PRIVILEGE_TYPE` FROM `INFORMATION_SCHEMA`.`USER_PRIVILEGES` WHERE GRANTEE='''definer''@''localhost''' AND PRIVILEGE_TYPE='CREATE ROUTINE'", |
262
|
|
|
[['CREATE ROUTINE']], |
263
|
|
|
['PRIVILEGE_TYPE'], |
264
|
|
|
); |
265
|
|
|
// phpcs:enable |
266
|
|
|
|
267
|
|
|
$dbi = $this->createDatabaseInterface($dummyDbi); |
268
|
|
|
$GLOBALS['dbi'] = $dbi; |
269
|
|
|
$template = new Template(); |
270
|
|
|
$response = new ResponseRenderer(); |
271
|
|
|
|
272
|
|
|
(new RoutinesController( |
273
|
|
|
$response, |
274
|
|
|
$template, |
275
|
|
|
new CheckUserPrivileges($dbi), |
276
|
|
|
$dbi, |
277
|
|
|
new Routines($dbi, $template, $response), |
278
|
|
|
))($this->createStub(ServerRequest::class)); |
279
|
|
|
|
280
|
|
|
$actual = $response->getHTMLResult(); |
281
|
|
|
// phpcs:disable Generic.Files.LineLength.TooLong |
282
|
|
|
$expected = <<<'HTML' |
283
|
|
|
<div class="container-fluid my-3"> |
284
|
|
|
<h2> |
285
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Routines" alt="Routines" class="icon ic_b_routines"> Routines</span> |
286
|
|
|
<a href="index.php?route=/url&url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F5.7%2Fen%2Fstored-routines.html" target="mysql_doc"><img src="themes/dot.gif" title="Documentation" alt="Documentation" class="icon ic_b_help"></a> |
287
|
|
|
</h2> |
288
|
|
|
|
289
|
|
|
<div class="d-flex flex-wrap my-3"> |
290
|
|
|
<div> |
291
|
|
|
<a class="ajax add_anchor btn btn-primary" href="index.php?route=/database/routines&db=test_db&table=&add_item=1&server=2&lang=en" role="button"> |
292
|
|
|
<span class="text-nowrap"><img src="themes/dot.gif" title="Create new routine" alt="Create new routine" class="icon ic_b_routine_add"> Create new routine</span> |
293
|
|
|
</a> |
294
|
|
|
</div> |
295
|
|
|
</div> |
296
|
|
|
|
297
|
|
|
<form id="rteListForm" class="ajax" action="index.php?route=/database/routines&server=2&lang=en"> |
298
|
|
|
<input type="hidden" name="db" value="test_db"><input type="hidden" name="server" value="2"><input type="hidden" name="lang" value="en"><input type="hidden" name="token" value="token"> |
299
|
|
|
|
300
|
|
|
<div id="nothing2display"> |
301
|
|
|
<div class="alert alert-primary" role="alert"> |
302
|
|
|
<img src="themes/dot.gif" title="" alt="" class="icon ic_s_notice"> There are no routines to display. |
303
|
|
|
</div> |
304
|
|
|
|
305
|
|
|
</div> |
306
|
|
|
|
307
|
|
|
<table id="routinesTable" class="table table-striped table-hover hide data w-auto"> |
308
|
|
|
<thead> |
309
|
|
|
<tr> |
310
|
|
|
<th></th> |
311
|
|
|
<th>Name</th> |
312
|
|
|
<th>Type</th> |
313
|
|
|
<th>Returns</th> |
314
|
|
|
<th colspan="4"></th> |
315
|
|
|
</tr> |
316
|
|
|
</thead> |
317
|
|
|
<tbody> |
318
|
|
|
<tr class="hide"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr> |
319
|
|
|
</tbody> |
320
|
|
|
</table> |
321
|
|
|
</form> |
322
|
|
|
</div> |
323
|
|
|
|
324
|
|
|
HTML; |
325
|
|
|
// phpcs:enable |
326
|
|
|
|
327
|
|
|
$this->assertSame($expected, $actual); |
328
|
|
|
} |
329
|
|
|
} |
330
|
|
|
|
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths