1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace PhpMyAdmin\Tests\Plugins\Export; |
6
|
|
|
|
7
|
|
|
use PhpMyAdmin\ColumnFull; |
8
|
|
|
use PhpMyAdmin\Config; |
9
|
|
|
use PhpMyAdmin\ConfigStorage\Relation; |
10
|
|
|
use PhpMyAdmin\ConfigStorage\RelationParameters; |
11
|
|
|
use PhpMyAdmin\Current; |
12
|
|
|
use PhpMyAdmin\DatabaseInterface; |
13
|
|
|
use PhpMyAdmin\Dbal\ConnectionType; |
14
|
|
|
use PhpMyAdmin\Export\Export; |
15
|
|
|
use PhpMyAdmin\Plugins\Export\ExportSql; |
16
|
|
|
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; |
17
|
|
|
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; |
18
|
|
|
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertySubgroup; |
19
|
|
|
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem; |
20
|
|
|
use PhpMyAdmin\Properties\Options\Items\MessageOnlyPropertyItem; |
21
|
|
|
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem; |
22
|
|
|
use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem; |
23
|
|
|
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem; |
24
|
|
|
use PhpMyAdmin\Properties\Options\OptionsPropertyGroup; |
25
|
|
|
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties; |
26
|
|
|
use PhpMyAdmin\Table\Table; |
27
|
|
|
use PhpMyAdmin\Tests\AbstractTestCase; |
28
|
|
|
use PhpMyAdmin\Tests\FieldHelper; |
29
|
|
|
use PhpMyAdmin\Tests\Stubs\DummyResult; |
30
|
|
|
use PhpMyAdmin\Transformations; |
31
|
|
|
use PHPUnit\Framework\Attributes\CoversClass; |
32
|
|
|
use PHPUnit\Framework\Attributes\Medium; |
33
|
|
|
use ReflectionMethod; |
34
|
|
|
use ReflectionProperty; |
35
|
|
|
|
36
|
|
|
use function ob_get_clean; |
37
|
|
|
use function ob_start; |
38
|
|
|
|
39
|
|
|
use const MYSQLI_NUM_FLAG; |
40
|
|
|
use const MYSQLI_PRI_KEY_FLAG; |
41
|
|
|
use const MYSQLI_TYPE_BLOB; |
42
|
|
|
use const MYSQLI_TYPE_FLOAT; |
43
|
|
|
use const MYSQLI_TYPE_LONG; |
44
|
|
|
use const MYSQLI_TYPE_STRING; |
45
|
|
|
use const MYSQLI_UNIQUE_KEY_FLAG; |
46
|
|
|
|
47
|
|
|
#[CoversClass(ExportSql::class)] |
48
|
|
|
#[Medium] |
49
|
|
|
class ExportSqlTest extends AbstractTestCase |
50
|
|
|
{ |
51
|
|
|
protected ExportSql $object; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Configures global environment. |
55
|
|
|
*/ |
56
|
|
|
protected function setUp(): void |
57
|
|
|
{ |
58
|
|
|
parent::setUp(); |
59
|
|
|
|
60
|
|
|
$dbi = $this->createDatabaseInterface(); |
61
|
|
|
DatabaseInterface::$instance = $dbi; |
62
|
|
|
Current::$database = ''; |
63
|
|
|
Current::$table = ''; |
64
|
|
|
$GLOBALS['lang'] = 'en'; |
65
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = true; |
|
|
|
|
66
|
|
|
$GLOBALS['output_kanji_conversion'] = false; |
67
|
|
|
$GLOBALS['buffer_needed'] = false; |
68
|
|
|
$GLOBALS['asfile'] = false; |
69
|
|
|
$GLOBALS['save_on_server'] = false; |
70
|
|
|
$GLOBALS['plugin_param'] = []; |
71
|
|
|
$GLOBALS['plugin_param']['export_type'] = 'table'; |
72
|
|
|
$GLOBALS['plugin_param']['single_table'] = false; |
73
|
|
|
|
74
|
|
|
$this->object = new ExportSql( |
75
|
|
|
new Relation($dbi), |
76
|
|
|
new Export($dbi), |
77
|
|
|
new Transformations(), |
78
|
|
|
); |
79
|
|
|
$this->object->useSqlBackquotes(false); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* tearDown for test cases |
84
|
|
|
*/ |
85
|
|
|
protected function tearDown(): void |
86
|
|
|
{ |
87
|
|
|
parent::tearDown(); |
88
|
|
|
|
89
|
|
|
DatabaseInterface::$instance = null; |
90
|
|
|
unset($this->object); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
public function testSetPropertiesWithHideSql(): void |
94
|
|
|
{ |
95
|
|
|
// test with hide structure and hide sql as true |
96
|
|
|
$GLOBALS['plugin_param']['export_type'] = 'table'; |
97
|
|
|
$GLOBALS['plugin_param']['single_table'] = false; |
98
|
|
|
|
99
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'setProperties'); |
100
|
|
|
$properties = $method->invoke($this->object, null); |
101
|
|
|
|
102
|
|
|
self::assertInstanceOf(ExportPluginProperties::class, $properties); |
103
|
|
|
self::assertSame('SQL', $properties->getText()); |
104
|
|
|
self::assertNull($properties->getOptions()); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
public function testSetProperties(): void |
108
|
|
|
{ |
109
|
|
|
// test with hide structure and hide sql as false |
110
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
111
|
|
|
->disableOriginalConstructor() |
112
|
|
|
->getMock(); |
113
|
|
|
|
114
|
|
|
$dbi->expects(self::once()) |
115
|
|
|
->method('getCompatibilities') |
116
|
|
|
->willReturn(['v1', 'v2']); |
117
|
|
|
|
118
|
|
|
DatabaseInterface::$instance = $dbi; |
119
|
|
|
$GLOBALS['plugin_param']['export_type'] = 'server'; |
120
|
|
|
$GLOBALS['plugin_param']['single_table'] = false; |
121
|
|
|
|
122
|
|
|
$relationParameters = RelationParameters::fromArray([ |
123
|
|
|
'db' => 'db', |
124
|
|
|
'relation' => 'relation', |
125
|
|
|
'column_info' => 'column_info', |
126
|
|
|
'relwork' => true, |
127
|
|
|
'mimework' => true, |
128
|
|
|
]); |
129
|
|
|
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters); |
130
|
|
|
|
131
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'setProperties'); |
132
|
|
|
$properties = $method->invoke($this->object, null); |
133
|
|
|
|
134
|
|
|
self::assertInstanceOf(ExportPluginProperties::class, $properties); |
135
|
|
|
self::assertSame('SQL', $properties->getText()); |
136
|
|
|
|
137
|
|
|
$options = $properties->getOptions(); |
138
|
|
|
|
139
|
|
|
self::assertInstanceOf(OptionsPropertyRootGroup::class, $options); |
140
|
|
|
|
141
|
|
|
$generalOptionsArray = $options->getProperties(); |
142
|
|
|
|
143
|
|
|
$generalOptions = $generalOptionsArray->current(); |
144
|
|
|
$generalOptionsArray->next(); |
145
|
|
|
|
146
|
|
|
self::assertInstanceOf(OptionsPropertyMainGroup::class, $generalOptions); |
147
|
|
|
|
148
|
|
|
$properties = $generalOptions->getProperties(); |
149
|
|
|
|
150
|
|
|
$property = $properties->current(); |
151
|
|
|
$properties->next(); |
152
|
|
|
|
153
|
|
|
self::assertInstanceOf(OptionsPropertySubgroup::class, $property); |
154
|
|
|
|
155
|
|
|
self::assertInstanceOf( |
156
|
|
|
BoolPropertyItem::class, |
157
|
|
|
$property->getSubgroupHeader(), |
158
|
|
|
); |
159
|
|
|
|
160
|
|
|
$leaves = $property->getProperties(); |
161
|
|
|
|
162
|
|
|
$leaf = $leaves->current(); |
163
|
|
|
$leaves->next(); |
164
|
|
|
self::assertInstanceOf(TextPropertyItem::class, $leaf); |
165
|
|
|
|
166
|
|
|
$leaf = $leaves->current(); |
167
|
|
|
$leaves->next(); |
168
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
169
|
|
|
|
170
|
|
|
$leaf = $leaves->current(); |
171
|
|
|
$leaves->next(); |
172
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
173
|
|
|
|
174
|
|
|
$leaf = $leaves->current(); |
175
|
|
|
$leaves->next(); |
176
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
177
|
|
|
|
178
|
|
|
$property = $properties->current(); |
179
|
|
|
$properties->next(); |
180
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $property); |
181
|
|
|
|
182
|
|
|
$property = $properties->current(); |
183
|
|
|
$properties->next(); |
184
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $property); |
185
|
|
|
|
186
|
|
|
$property = $properties->current(); |
187
|
|
|
$properties->next(); |
188
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $property); |
189
|
|
|
|
190
|
|
|
$property = $properties->current(); |
191
|
|
|
$properties->next(); |
192
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $property); |
193
|
|
|
|
194
|
|
|
$property = $properties->current(); |
195
|
|
|
$properties->next(); |
196
|
|
|
self::assertInstanceOf(SelectPropertyItem::class, $property); |
197
|
|
|
|
198
|
|
|
self::assertSame( |
199
|
|
|
['v1' => 'v1', 'v2' => 'v2'], |
200
|
|
|
$property->getValues(), |
201
|
|
|
); |
202
|
|
|
|
203
|
|
|
$property = $properties->current(); |
204
|
|
|
self::assertInstanceOf(OptionsPropertySubgroup::class, $property); |
205
|
|
|
|
206
|
|
|
self::assertInstanceOf( |
207
|
|
|
RadioPropertyItem::class, |
208
|
|
|
$property->getSubgroupHeader(), |
209
|
|
|
); |
210
|
|
|
|
211
|
|
|
$structureOptions = $generalOptionsArray->current(); |
212
|
|
|
$generalOptionsArray->next(); |
213
|
|
|
|
214
|
|
|
self::assertInstanceOf(OptionsPropertyMainGroup::class, $structureOptions); |
215
|
|
|
|
216
|
|
|
$properties = $structureOptions->getProperties(); |
217
|
|
|
|
218
|
|
|
$property = $properties->current(); |
219
|
|
|
$properties->next(); |
220
|
|
|
|
221
|
|
|
self::assertInstanceOf(OptionsPropertySubgroup::class, $property); |
222
|
|
|
|
223
|
|
|
self::assertInstanceOf( |
224
|
|
|
MessageOnlyPropertyItem::class, |
225
|
|
|
$property->getSubgroupHeader(), |
226
|
|
|
); |
227
|
|
|
|
228
|
|
|
$leaves = $property->getProperties(); |
229
|
|
|
|
230
|
|
|
$leaf = $leaves->current(); |
231
|
|
|
$leaves->next(); |
232
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
233
|
|
|
|
234
|
|
|
$leaf = $leaves->current(); |
235
|
|
|
$leaves->next(); |
236
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
237
|
|
|
|
238
|
|
|
self::assertSame( |
239
|
|
|
'Add <code>DROP TABLE / VIEW / PROCEDURE / FUNCTION / EVENT</code><code> / TRIGGER</code> statement', |
240
|
|
|
$leaf->getText(), |
241
|
|
|
); |
242
|
|
|
|
243
|
|
|
$leaf = $leaves->current(); |
244
|
|
|
$leaves->next(); |
245
|
|
|
self::assertInstanceOf(OptionsPropertySubgroup::class, $leaf); |
246
|
|
|
|
247
|
|
|
self::assertCount( |
248
|
|
|
2, |
249
|
|
|
$leaf->getProperties(), |
250
|
|
|
); |
251
|
|
|
|
252
|
|
|
self::assertInstanceOf( |
253
|
|
|
BoolPropertyItem::class, |
254
|
|
|
$leaf->getSubgroupHeader(), |
255
|
|
|
); |
256
|
|
|
|
257
|
|
|
$leaf = $leaves->current(); |
258
|
|
|
$leaves->next(); |
259
|
|
|
self::assertInstanceOf(OptionsPropertySubgroup::class, $leaf); |
260
|
|
|
|
261
|
|
|
self::assertCount( |
262
|
|
|
3, |
263
|
|
|
$leaf->getProperties(), |
264
|
|
|
); |
265
|
|
|
|
266
|
|
|
self::assertInstanceOf( |
267
|
|
|
BoolPropertyItem::class, |
268
|
|
|
$leaf->getSubgroupHeader(), |
269
|
|
|
); |
270
|
|
|
|
271
|
|
|
$leaf = $leaves->current(); |
272
|
|
|
$leaves->next(); |
273
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
274
|
|
|
|
275
|
|
|
$leaf = $leaves->current(); |
276
|
|
|
$leaves->next(); |
277
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $leaf); |
278
|
|
|
|
279
|
|
|
$property = $properties->current(); |
280
|
|
|
self::assertInstanceOf(BoolPropertyItem::class, $property); |
281
|
|
|
|
282
|
|
|
$dataOptions = $generalOptionsArray->current(); |
283
|
|
|
self::assertInstanceOf(OptionsPropertyMainGroup::class, $dataOptions); |
284
|
|
|
|
285
|
|
|
$properties = $dataOptions->getProperties(); |
286
|
|
|
|
287
|
|
|
self::assertCount(7, $properties); |
288
|
|
|
|
289
|
|
|
$properties->next(); |
|
|
|
|
290
|
|
|
|
291
|
|
|
$property = $properties->current(); |
|
|
|
|
292
|
|
|
self::assertInstanceOf(OptionsPropertyGroup::class, $property); |
293
|
|
|
|
294
|
|
|
self::assertCount( |
295
|
|
|
2, |
296
|
|
|
$property->getProperties(), |
297
|
|
|
); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
public function testExportRoutines(): void |
301
|
|
|
{ |
302
|
|
|
$GLOBALS['sql_drop_table'] = true; |
303
|
|
|
|
304
|
|
|
$this->expectOutputString( |
305
|
|
|
"\n" . 'DELIMITER $$' . "\n" . 'DROP PROCEDURE IF EXISTS `test_proc1`$$' . "\n" . 'CREATE PROCEDURE' |
306
|
|
|
. ' `test_proc1` (`p` INT) BEGIN END$$' . "\n\n" . 'DROP PROCEDURE IF EXISTS' |
307
|
|
|
. ' `test_proc2`$$' . "\n" . 'CREATE PROCEDURE `test_proc2` (`p` INT) BEGIN END$$' . "\n\n" . 'DROP' |
308
|
|
|
. ' FUNCTION IF EXISTS `test_func`$$' . "\n" . 'CREATE FUNCTION' |
309
|
|
|
. ' `test_func` (`p` INT) RETURNS INT(11) BEGIN END$$' . "\n\n" . 'DELIMITER ;' . "\n", |
310
|
|
|
); |
311
|
|
|
|
312
|
|
|
$this->object->exportRoutines('test_db'); |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
public function testExportComment(): void |
316
|
|
|
{ |
317
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'exportComment'); |
318
|
|
|
|
319
|
|
|
$GLOBALS['sql_include_comments'] = true; |
320
|
|
|
|
321
|
|
|
self::assertSame( |
322
|
|
|
'--' . "\n", |
323
|
|
|
$method->invoke($this->object, ''), |
324
|
|
|
); |
325
|
|
|
|
326
|
|
|
self::assertSame( |
327
|
|
|
'-- Comment' . "\n", |
328
|
|
|
$method->invoke($this->object, 'Comment'), |
329
|
|
|
); |
330
|
|
|
|
331
|
|
|
$GLOBALS['sql_include_comments'] = false; |
332
|
|
|
|
333
|
|
|
self::assertSame( |
334
|
|
|
'', |
335
|
|
|
$method->invoke($this->object, 'Comment'), |
336
|
|
|
); |
337
|
|
|
|
338
|
|
|
unset($GLOBALS['sql_include_comments']); |
339
|
|
|
|
340
|
|
|
self::assertSame( |
341
|
|
|
'', |
342
|
|
|
$method->invoke($this->object, 'Comment'), |
343
|
|
|
); |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
public function testPossibleCRLF(): void |
347
|
|
|
{ |
348
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'possibleCRLF'); |
349
|
|
|
|
350
|
|
|
$GLOBALS['sql_include_comments'] = true; |
351
|
|
|
|
352
|
|
|
self::assertSame( |
353
|
|
|
"\n", |
354
|
|
|
$method->invoke($this->object, ''), |
355
|
|
|
); |
356
|
|
|
|
357
|
|
|
self::assertSame( |
358
|
|
|
"\n", |
359
|
|
|
$method->invoke($this->object, 'Comment'), |
360
|
|
|
); |
361
|
|
|
|
362
|
|
|
$GLOBALS['sql_include_comments'] = false; |
363
|
|
|
|
364
|
|
|
self::assertSame( |
365
|
|
|
'', |
366
|
|
|
$method->invoke($this->object, 'Comment'), |
367
|
|
|
); |
368
|
|
|
|
369
|
|
|
unset($GLOBALS['sql_include_comments']); |
370
|
|
|
|
371
|
|
|
self::assertSame( |
372
|
|
|
'', |
373
|
|
|
$method->invoke($this->object, 'Comment'), |
374
|
|
|
); |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
public function testExportFooter(): void |
378
|
|
|
{ |
379
|
|
|
$GLOBALS['sql_disable_fk'] = true; |
380
|
|
|
$GLOBALS['sql_use_transaction'] = true; |
381
|
|
|
$GLOBALS['charset'] = 'utf-8'; |
382
|
|
|
$GLOBALS['sql_utc_time'] = true; |
383
|
|
|
$GLOBALS['old_tz'] = 'GMT'; |
384
|
|
|
$GLOBALS['asfile'] = 'yes'; |
385
|
|
|
$GLOBALS['output_charset_conversion'] = 'utf-8'; |
386
|
|
|
|
387
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
388
|
|
|
->disableOriginalConstructor() |
389
|
|
|
->getMock(); |
390
|
|
|
|
391
|
|
|
$dbi->expects(self::once()) |
392
|
|
|
->method('query') |
393
|
|
|
->with('SET time_zone = "GMT"'); |
394
|
|
|
|
395
|
|
|
DatabaseInterface::$instance = $dbi; |
396
|
|
|
|
397
|
|
|
$this->expectOutputString('SET FOREIGN_KEY_CHECKS=1;' . "\n" . 'COMMIT;' . "\n"); |
398
|
|
|
|
399
|
|
|
self::assertTrue( |
400
|
|
|
$this->object->exportFooter(), |
401
|
|
|
); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
public function testExportHeader(): void |
405
|
|
|
{ |
406
|
|
|
$GLOBALS['sql_compatibility'] = 'NONE'; |
407
|
|
|
$config = Config::getInstance(); |
|
|
|
|
408
|
|
|
$config->selectedServer['host'] = 'localhost'; |
409
|
|
|
$config->selectedServer['port'] = 80; |
410
|
|
|
$GLOBALS['sql_disable_fk'] = true; |
411
|
|
|
$GLOBALS['sql_use_transaction'] = true; |
412
|
|
|
$GLOBALS['sql_utc_time'] = true; |
413
|
|
|
$GLOBALS['old_tz'] = 'GMT'; |
414
|
|
|
$GLOBALS['asfile'] = 'yes'; |
415
|
|
|
$GLOBALS['output_charset_conversion'] = 'utf-8'; |
416
|
|
|
$GLOBALS['sql_header_comment'] = "h1C\nh2C"; |
417
|
|
|
$GLOBALS['sql_use_transaction'] = true; |
418
|
|
|
$GLOBALS['sql_include_comments'] = true; |
419
|
|
|
$GLOBALS['charset'] = 'utf-8'; |
420
|
|
|
|
421
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
422
|
|
|
->disableOriginalConstructor() |
423
|
|
|
->getMock(); |
424
|
|
|
|
425
|
|
|
$dbi->expects(self::once()) |
426
|
|
|
->method('tryQuery') |
427
|
|
|
->with('SET SQL_MODE=""'); |
428
|
|
|
|
429
|
|
|
$dbi->expects(self::once()) |
430
|
|
|
->method('fetchValue') |
431
|
|
|
->with('SELECT @@session.time_zone') |
432
|
|
|
->willReturn('old_tz'); |
433
|
|
|
|
434
|
|
|
$dbi->expects(self::once()) |
435
|
|
|
->method('query') |
436
|
|
|
->with('SET time_zone = "+00:00"'); |
437
|
|
|
|
438
|
|
|
DatabaseInterface::$instance = $dbi; |
439
|
|
|
|
440
|
|
|
ob_start(); |
441
|
|
|
self::assertTrue( |
442
|
|
|
$this->object->exportHeader(), |
443
|
|
|
); |
444
|
|
|
$result = ob_get_clean(); |
445
|
|
|
|
446
|
|
|
self::assertIsString($result); |
447
|
|
|
|
448
|
|
|
self::assertStringContainsString('h1C', $result); |
449
|
|
|
|
450
|
|
|
self::assertStringContainsString('h2C', $result); |
451
|
|
|
|
452
|
|
|
self::assertStringContainsString("SET FOREIGN_KEY_CHECKS=0;\n", $result); |
453
|
|
|
|
454
|
|
|
self::assertStringContainsString('40101 SET', $result); |
455
|
|
|
|
456
|
|
|
self::assertStringContainsString( |
457
|
|
|
"SET FOREIGN_KEY_CHECKS=0;\n" . |
458
|
|
|
"SET SQL_MODE = \"NO_AUTO_VALUE_ON_ZERO\";\n" . |
459
|
|
|
"START TRANSACTION;\n" . |
460
|
|
|
"SET time_zone = \"+00:00\";\n", |
461
|
|
|
$result, |
462
|
|
|
); |
463
|
|
|
} |
464
|
|
|
|
465
|
|
|
public function testExportDBCreate(): void |
466
|
|
|
{ |
467
|
|
|
$GLOBALS['sql_compatibility'] = 'NONE'; |
468
|
|
|
$GLOBALS['sql_drop_database'] = true; |
469
|
|
|
$GLOBALS['sql_create_database'] = true; |
470
|
|
|
$GLOBALS['sql_create_table'] = true; |
471
|
|
|
$GLOBALS['sql_create_view'] = true; |
472
|
|
|
|
473
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
474
|
|
|
->disableOriginalConstructor() |
475
|
|
|
->getMock(); |
476
|
|
|
|
477
|
|
|
$dbi->expects(self::once()) |
478
|
|
|
->method('getDbCollation') |
479
|
|
|
->with('db') |
480
|
|
|
->willReturn('utf8_general_ci'); |
481
|
|
|
|
482
|
|
|
DatabaseInterface::$instance = $dbi; |
483
|
|
|
|
484
|
|
|
$this->object->useSqlBackquotes(true); |
485
|
|
|
|
486
|
|
|
ob_start(); |
487
|
|
|
self::assertTrue( |
488
|
|
|
$this->object->exportDBCreate('db', 'database'), |
489
|
|
|
); |
490
|
|
|
$result = ob_get_clean(); |
491
|
|
|
|
492
|
|
|
self::assertIsString($result); |
493
|
|
|
|
494
|
|
|
self::assertStringContainsString("DROP DATABASE IF EXISTS `db`;\n", $result); |
495
|
|
|
|
496
|
|
|
self::assertStringContainsString( |
497
|
|
|
'CREATE DATABASE IF NOT EXISTS `db` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;', |
498
|
|
|
$result, |
499
|
|
|
); |
500
|
|
|
|
501
|
|
|
self::assertStringContainsString('USE `db`;', $result); |
502
|
|
|
|
503
|
|
|
// case2: no backquotes |
504
|
|
|
unset($GLOBALS['sql_compatibility']); |
505
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = true; |
|
|
|
|
506
|
|
|
|
507
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
508
|
|
|
->disableOriginalConstructor() |
509
|
|
|
->getMock(); |
510
|
|
|
|
511
|
|
|
$dbi->expects(self::once()) |
512
|
|
|
->method('getDbCollation') |
513
|
|
|
->with('db') |
514
|
|
|
->willReturn('testcollation'); |
515
|
|
|
|
516
|
|
|
DatabaseInterface::$instance = $dbi; |
517
|
|
|
|
518
|
|
|
$this->object->useSqlBackquotes(false); |
519
|
|
|
|
520
|
|
|
ob_start(); |
521
|
|
|
self::assertTrue( |
522
|
|
|
$this->object->exportDBCreate('db', 'database'), |
523
|
|
|
); |
524
|
|
|
$result = ob_get_clean(); |
525
|
|
|
|
526
|
|
|
self::assertIsString($result); |
527
|
|
|
|
528
|
|
|
self::assertStringContainsString("DROP DATABASE IF EXISTS db;\n", $result); |
529
|
|
|
|
530
|
|
|
self::assertStringContainsString( |
531
|
|
|
'CREATE DATABASE IF NOT EXISTS db DEFAULT CHARACTER SET testcollation;', |
532
|
|
|
$result, |
533
|
|
|
); |
534
|
|
|
|
535
|
|
|
self::assertStringContainsString('USE db;', $result); |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
public function testExportDBHeader(): void |
539
|
|
|
{ |
540
|
|
|
$GLOBALS['sql_compatibility'] = 'MSSQL'; |
541
|
|
|
$GLOBALS['sql_include_comments'] = true; |
542
|
|
|
|
543
|
|
|
$this->object->useSqlBackquotes(true); |
544
|
|
|
|
545
|
|
|
ob_start(); |
546
|
|
|
self::assertTrue( |
547
|
|
|
$this->object->exportDBHeader('testDB'), |
548
|
|
|
); |
549
|
|
|
$result = ob_get_clean(); |
550
|
|
|
|
551
|
|
|
self::assertIsString($result); |
552
|
|
|
|
553
|
|
|
self::assertStringContainsString('"testDB"', $result); |
554
|
|
|
|
555
|
|
|
// case 2 |
556
|
|
|
unset($GLOBALS['sql_compatibility']); |
557
|
|
|
|
558
|
|
|
$this->object->useSqlBackquotes(false); |
559
|
|
|
|
560
|
|
|
ob_start(); |
561
|
|
|
self::assertTrue( |
562
|
|
|
$this->object->exportDBHeader('testDB'), |
563
|
|
|
); |
564
|
|
|
$result = ob_get_clean(); |
565
|
|
|
|
566
|
|
|
self::assertIsString($result); |
567
|
|
|
|
568
|
|
|
self::assertStringContainsString('testDB', $result); |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
public function testExportEvents(): void |
572
|
|
|
{ |
573
|
|
|
$GLOBALS['sql_structure_or_data'] = 'structure'; |
574
|
|
|
$GLOBALS['sql_procedure_function'] = true; |
575
|
|
|
|
576
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
577
|
|
|
->disableOriginalConstructor() |
578
|
|
|
->getMock(); |
579
|
|
|
|
580
|
|
|
$dbi->expects(self::once()) |
581
|
|
|
->method('fetchResult') |
582
|
|
|
->with('SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'db\'') |
583
|
|
|
->willReturn(['f1', 'f2']); |
584
|
|
|
|
585
|
|
|
$dbi->expects(self::exactly(2)) |
586
|
|
|
->method('fetchValue') |
587
|
|
|
->willReturnMap([ |
588
|
|
|
['SHOW CREATE EVENT `db`.`f1`', 'Create Event', ConnectionType::User, 'f1event'], |
589
|
|
|
['SHOW CREATE EVENT `db`.`f2`', 'Create Event', ConnectionType::User, 'f2event'], |
590
|
|
|
]); |
591
|
|
|
$dbi->expects(self::any())->method('quoteString') |
592
|
|
|
->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); |
593
|
|
|
|
594
|
|
|
DatabaseInterface::$instance = $dbi; |
595
|
|
|
|
596
|
|
|
ob_start(); |
597
|
|
|
self::assertTrue( |
598
|
|
|
$this->object->exportEvents('db'), |
599
|
|
|
); |
600
|
|
|
$result = ob_get_clean(); |
601
|
|
|
|
602
|
|
|
self::assertIsString($result); |
603
|
|
|
|
604
|
|
|
self::assertStringContainsString("DELIMITER $$\n", $result); |
605
|
|
|
|
606
|
|
|
self::assertStringContainsString("DELIMITER ;\n", $result); |
607
|
|
|
|
608
|
|
|
self::assertStringContainsString("f1event$$\n", $result); |
609
|
|
|
|
610
|
|
|
self::assertStringContainsString("f2event$$\n", $result); |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
public function testExportDBFooter(): void |
614
|
|
|
{ |
615
|
|
|
$this->object->sqlConstraints = 'SqlConstraints'; |
616
|
|
|
$GLOBALS['sql_structure_or_data'] = 'structure'; |
617
|
|
|
$GLOBALS['sql_procedure_function'] = true; |
618
|
|
|
|
619
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
620
|
|
|
->disableOriginalConstructor() |
621
|
|
|
->getMock(); |
622
|
|
|
|
623
|
|
|
DatabaseInterface::$instance = $dbi; |
624
|
|
|
|
625
|
|
|
ob_start(); |
626
|
|
|
self::assertTrue( |
627
|
|
|
$this->object->exportDBFooter('db'), |
628
|
|
|
); |
629
|
|
|
$result = ob_get_clean(); |
630
|
|
|
|
631
|
|
|
self::assertSame('SqlConstraints', $result); |
632
|
|
|
} |
633
|
|
|
|
634
|
|
|
public function testGetTableDefStandIn(): void |
635
|
|
|
{ |
636
|
|
|
$GLOBALS['sql_drop_table'] = true; |
637
|
|
|
$GLOBALS['sql_if_not_exists'] = true; |
638
|
|
|
|
639
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
640
|
|
|
->disableOriginalConstructor() |
641
|
|
|
->getMock(); |
642
|
|
|
|
643
|
|
|
$dbi->expects(self::once()) |
644
|
|
|
->method('getColumnsFull') |
645
|
|
|
->with('db', 'view') |
646
|
|
|
->willReturn(['cname' => ['Type' => 'int']]); |
647
|
|
|
|
648
|
|
|
DatabaseInterface::$instance = $dbi; |
649
|
|
|
|
650
|
|
|
$result = $this->object->getTableDefStandIn('db', 'view'); |
651
|
|
|
|
652
|
|
|
self::assertStringContainsString('DROP VIEW IF EXISTS `view`;', $result); |
653
|
|
|
|
654
|
|
|
self::assertStringContainsString( |
655
|
|
|
'CREATE TABLE IF NOT EXISTS `view` (' . "\n" . '`cname` int' . "\n" . ');' . "\n", |
656
|
|
|
$result, |
657
|
|
|
); |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
public function testGetTableDefForView(): void |
661
|
|
|
{ |
662
|
|
|
$GLOBALS['sql_drop_table'] = true; |
663
|
|
|
$GLOBALS['sql_if_not_exists'] = true; |
664
|
|
|
|
665
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
666
|
|
|
->disableOriginalConstructor() |
667
|
|
|
->getMock(); |
668
|
|
|
$dbi->expects(self::any())->method('quoteString') |
669
|
|
|
->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); |
670
|
|
|
|
671
|
|
|
$dbi->expects(self::any()) |
672
|
|
|
->method('getColumns') |
673
|
|
|
->with('db', 'view') |
674
|
|
|
->willReturn([ |
675
|
|
|
new ColumnFull( |
676
|
|
|
'fname', |
677
|
|
|
'char', |
678
|
|
|
'utf-8', |
679
|
|
|
false, |
680
|
|
|
'', |
681
|
|
|
'a', |
682
|
|
|
'', |
683
|
|
|
'', |
684
|
|
|
'cmt', |
685
|
|
|
), |
686
|
|
|
]); |
687
|
|
|
|
688
|
|
|
DatabaseInterface::$instance = $dbi; |
689
|
|
|
$GLOBALS['sql_compatibility'] = 'MSSQL'; |
690
|
|
|
|
691
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'getTableDefForView'); |
692
|
|
|
$result = $method->invoke($this->object, 'db', 'view'); |
693
|
|
|
|
694
|
|
|
self::assertSame( |
695
|
|
|
"CREATE TABLE `view`(\n" . |
696
|
|
|
" `fname` char COLLATE utf-8 NOT NULL DEFAULT 'a' COMMENT 'cmt'\n" . |
697
|
|
|
");\n", |
698
|
|
|
$result, |
699
|
|
|
); |
700
|
|
|
|
701
|
|
|
// case 2 |
702
|
|
|
unset($GLOBALS['sql_compatibility']); |
703
|
|
|
|
704
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
705
|
|
|
->disableOriginalConstructor() |
706
|
|
|
->getMock(); |
707
|
|
|
$dbi->expects(self::any())->method('quoteString') |
708
|
|
|
->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); |
709
|
|
|
|
710
|
|
|
$dbi->expects(self::any()) |
711
|
|
|
->method('getColumns') |
712
|
|
|
->with('db', 'view') |
713
|
|
|
->willReturn([ |
714
|
|
|
new ColumnFull( |
715
|
|
|
'fname', |
716
|
|
|
'char', |
717
|
|
|
'utf-8', |
718
|
|
|
true, |
719
|
|
|
'', |
720
|
|
|
null, |
721
|
|
|
'', |
722
|
|
|
'', |
723
|
|
|
'cmt', |
724
|
|
|
), |
725
|
|
|
]); |
726
|
|
|
DatabaseInterface::$instance = $dbi; |
727
|
|
|
|
728
|
|
|
$result = $method->invoke($this->object, 'db', 'view'); |
729
|
|
|
|
730
|
|
|
self::assertSame( |
731
|
|
|
"CREATE TABLE IF NOT EXISTS `view`(\n" . |
732
|
|
|
" `fname` char COLLATE utf-8 DEFAULT NULL COMMENT 'cmt'\n" . |
733
|
|
|
");\n", |
734
|
|
|
$result, |
735
|
|
|
); |
736
|
|
|
} |
737
|
|
|
|
738
|
|
|
public function testGetTableDef(): void |
739
|
|
|
{ |
740
|
|
|
$GLOBALS['sql_compatibility'] = 'MSSQL'; |
741
|
|
|
$GLOBALS['sql_auto_increment'] = true; |
742
|
|
|
$GLOBALS['sql_drop_table'] = true; |
743
|
|
|
$GLOBALS['sql_if_not_exists'] = true; |
744
|
|
|
$GLOBALS['sql_include_comments'] = true; |
745
|
|
|
$this->object->sqlConstraints = null; |
746
|
|
|
|
747
|
|
|
if (isset($GLOBALS['no_constraints_comments'])) { |
748
|
|
|
unset($GLOBALS['no_constraints_comments']); |
749
|
|
|
} |
750
|
|
|
|
751
|
|
|
$createTableStatement = <<<'SQL' |
752
|
|
|
CREATE TABLE `table` ( |
753
|
|
|
`payment_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, |
754
|
|
|
`customer_id` smallint(5) unsigned NOT NULL, |
755
|
|
|
`staff_id` tinyint(3) unsigned NOT NULL, |
756
|
|
|
`rental_id` int(11) DEFAULT NULL, |
757
|
|
|
`amount` decimal(5,2) NOT NULL, |
758
|
|
|
`payment_date` datetime NOT NULL, |
759
|
|
|
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
760
|
|
|
PRIMARY KEY (`payment_id`), |
761
|
|
|
KEY `idx_fk_staff_id` (`staff_id`), |
762
|
|
|
KEY `idx_fk_customer_id` (`customer_id`), |
763
|
|
|
KEY `fk_payment_rental` (`rental_id`), |
764
|
|
|
CONSTRAINT `fk_payment_customer` |
765
|
|
|
FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`) ON UPDATE CASCADE, |
766
|
|
|
CONSTRAINT `fk_payment_rental` |
767
|
|
|
FOREIGN KEY (`rental_id`) REFERENCES `rental` (`rental_id`) ON DELETE SET NULL ON UPDATE CASCADE, |
768
|
|
|
CONSTRAINT `fk_payment_staff` |
769
|
|
|
FOREIGN KEY (`staff_id`) REFERENCES `staff` (`staff_id`) ON UPDATE CASCADE |
770
|
|
|
) ENGINE=InnoDB AUTO_INCREMENT=16050 DEFAULT CHARSET=utf8 |
771
|
|
|
SQL; |
772
|
|
|
$isViewQuery = 'SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = \'db\' AND TABLE_NAME = \'table\''; |
773
|
|
|
|
774
|
|
|
$dbiDummy = $this->createDbiDummy(); |
775
|
|
|
// phpcs:disable Generic.Files.LineLength.TooLong |
776
|
|
|
$dbiDummy->addResult( |
777
|
|
|
'SHOW TABLE STATUS FROM `db` WHERE Name = \'table\'', |
778
|
|
|
[['table', 'InnoDB', '10', 'Dynamic', '3', '5461', '16384', '0', '0', '0', '1', '2000-01-01 10:00:00', '2000-01-02 12:00:00', '2000-01-02 13:00:00', 'utf8mb4_general_ci', null, '', '', '0', 'N']], |
779
|
|
|
['Name', 'Engine', 'Version', 'Row_format', 'Rows', 'Avg_row_length', 'Data_length', 'Max_data_length', 'Index_length', 'Data_free', 'Auto_increment', 'Create_time', 'Update_time', 'Check_time', 'Collation', 'Checksum', 'Create_options', 'Comment', 'Max_index_length', 'Temporary'], |
780
|
|
|
); |
781
|
|
|
// phpcs:enable |
782
|
|
|
$dbiDummy->addResult($isViewQuery, []); |
783
|
|
|
$dbiDummy->addResult($isViewQuery, []); |
784
|
|
|
$dbiDummy->addResult('USE `db`', true); |
785
|
|
|
$dbiDummy->addResult( |
786
|
|
|
'SHOW CREATE TABLE `db`.`table`', |
787
|
|
|
[['table', $createTableStatement]], |
788
|
|
|
['Table', 'Create Table'], |
789
|
|
|
); |
790
|
|
|
|
791
|
|
|
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy); |
792
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = false; |
|
|
|
|
793
|
|
|
|
794
|
|
|
$this->object->useSqlBackquotes(true); |
795
|
|
|
|
796
|
|
|
$result = $this->object->getTableDef('db', 'table', true, true, false); |
797
|
|
|
|
798
|
|
|
$dbiDummy->assertAllQueriesConsumed(); |
799
|
|
|
self::assertStringContainsString('-- Creation: Jan 01, 2000 at 10:00 AM', $result); |
800
|
|
|
self::assertStringContainsString('-- Last update: Jan 02, 2000 at 12:00 PM', $result); |
801
|
|
|
self::assertStringContainsString('-- Last check: Jan 02, 2000 at 01:00 PM', $result); |
802
|
|
|
self::assertStringContainsString('DROP TABLE IF EXISTS `table`;', $result); |
803
|
|
|
self::assertStringContainsString('CREATE TABLE `table`', $result); |
804
|
|
|
self::assertIsString($this->object->sqlConstraints); |
805
|
|
|
self::assertStringContainsString('-- Constraints for dumped tables', $this->object->sqlConstraints); |
|
|
|
|
806
|
|
|
self::assertStringContainsString('-- Constraints for table "table"', $this->object->sqlConstraints); |
807
|
|
|
self::assertStringContainsString('ALTER TABLE "table"', $this->object->sqlConstraints); |
808
|
|
|
self::assertStringContainsString('ADD CONSTRAINT', $this->object->sqlConstraints); |
809
|
|
|
self::assertStringContainsString('ALTER TABLE "table"', $this->object->sqlConstraintsQuery); |
810
|
|
|
self::assertStringContainsString('ADD CONSTRAINT', $this->object->sqlConstraintsQuery); |
811
|
|
|
self::assertStringContainsString('ALTER TABLE "table"', $GLOBALS['sql_drop_foreign_keys']); |
812
|
|
|
self::assertStringContainsString('DROP FOREIGN KEY', $GLOBALS['sql_drop_foreign_keys']); |
813
|
|
|
} |
814
|
|
|
|
815
|
|
|
public function testGetTableDefWithError(): void |
816
|
|
|
{ |
817
|
|
|
$GLOBALS['sql_compatibility'] = ''; |
818
|
|
|
$GLOBALS['sql_auto_increment'] = true; |
819
|
|
|
$GLOBALS['sql_drop_table'] = true; |
820
|
|
|
$GLOBALS['sql_if_not_exists'] = true; |
821
|
|
|
$GLOBALS['sql_include_comments'] = true; |
822
|
|
|
|
823
|
|
|
$this->object->sqlConstraints = null; |
824
|
|
|
|
825
|
|
|
if (isset($GLOBALS['no_constraints_comments'])) { |
826
|
|
|
unset($GLOBALS['no_constraints_comments']); |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
$isViewQuery = 'SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = \'db\' AND TABLE_NAME = \'table\''; |
830
|
|
|
|
831
|
|
|
$dbiDummy = $this->createDbiDummy(); |
832
|
|
|
$dbiDummy->addResult('SHOW TABLE STATUS FROM `db` WHERE Name = \'table\'', []); |
833
|
|
|
$dbiDummy->addResult($isViewQuery, []); |
834
|
|
|
$dbiDummy->addResult($isViewQuery, []); |
835
|
|
|
$dbiDummy->addResult('USE `db`', true); |
836
|
|
|
$dbiDummy->addResult('SHOW CREATE TABLE `db`.`table`', []); |
837
|
|
|
$dbiDummy->addErrorCode('error occurred'); |
838
|
|
|
|
839
|
|
|
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy); |
840
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = false; |
|
|
|
|
841
|
|
|
|
842
|
|
|
$this->object->useSqlBackquotes(false); |
843
|
|
|
|
844
|
|
|
$result = $this->object->getTableDef('db', 'table', true, true, false); |
845
|
|
|
|
846
|
|
|
$dbiDummy->assertAllQueriesConsumed(); |
847
|
|
|
$dbiDummy->assertAllErrorCodesConsumed(); |
848
|
|
|
self::assertStringContainsString('-- Error reading structure for table db.table: error occurred', $result); |
849
|
|
|
} |
850
|
|
|
|
851
|
|
|
public function testGetTableComments(): void |
852
|
|
|
{ |
853
|
|
|
$relationParameters = RelationParameters::fromArray([ |
854
|
|
|
'relwork' => true, |
855
|
|
|
'commwork' => true, |
856
|
|
|
'mimework' => true, |
857
|
|
|
'db' => 'database', |
858
|
|
|
'relation' => 'rel', |
859
|
|
|
'column_info' => 'col', |
860
|
|
|
]); |
861
|
|
|
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters); |
862
|
|
|
$GLOBALS['sql_include_comments'] = true; |
863
|
|
|
|
864
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
865
|
|
|
->disableOriginalConstructor() |
866
|
|
|
->getMock(); |
867
|
|
|
|
868
|
|
|
$dbi->expects(self::exactly(2)) |
869
|
|
|
->method('fetchResult') |
870
|
|
|
->willReturn( |
871
|
|
|
['foo' => ['foreign_table' => 'ftable', 'foreign_field' => 'ffield']], |
872
|
|
|
['fieldname' => ['values' => 'test-', 'transformation' => 'testfoo', 'mimetype' => 'test<']], |
873
|
|
|
); |
874
|
|
|
|
875
|
|
|
DatabaseInterface::$instance = $dbi; |
876
|
|
|
$this->object->relation = new Relation($dbi); |
877
|
|
|
|
878
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'getTableComments'); |
879
|
|
|
$result = $method->invoke($this->object, 'db', '', true, true); |
880
|
|
|
|
881
|
|
|
self::assertStringContainsString( |
882
|
|
|
'-- MEDIA TYPES FOR TABLE :' . "\n" |
883
|
|
|
. '-- fieldname' . "\n" |
884
|
|
|
. '-- Test<', |
885
|
|
|
$result, |
886
|
|
|
); |
887
|
|
|
|
888
|
|
|
self::assertStringContainsString( |
889
|
|
|
'-- RELATIONSHIPS FOR TABLE :' . "\n" |
890
|
|
|
. '-- foo' . "\n" |
891
|
|
|
. '-- ftable -> ffield', |
892
|
|
|
$result, |
893
|
|
|
); |
894
|
|
|
} |
895
|
|
|
|
896
|
|
|
public function testExportStructure(): void |
897
|
|
|
{ |
898
|
|
|
$GLOBALS['sql_compatibility'] = 'MSSQL'; |
899
|
|
|
$GLOBALS['sql_include_comments'] = true; |
900
|
|
|
|
901
|
|
|
$this->object->useSqlBackquotes(true); |
902
|
|
|
|
903
|
|
|
// case 1 |
904
|
|
|
ob_start(); |
905
|
|
|
self::assertTrue( |
906
|
|
|
$this->object->exportStructure( |
907
|
|
|
'test_db', |
908
|
|
|
'test_table', |
909
|
|
|
'create_table', |
910
|
|
|
'test', |
911
|
|
|
), |
912
|
|
|
); |
913
|
|
|
$result = ob_get_clean(); |
914
|
|
|
|
915
|
|
|
self::assertIsString($result); |
916
|
|
|
self::assertStringContainsString('-- Table structure for table "test_table"', $result); |
917
|
|
|
self::assertStringContainsString('CREATE TABLE `test_table`', $result); |
918
|
|
|
|
919
|
|
|
// case 2 |
920
|
|
|
unset($GLOBALS['sql_compatibility']); |
921
|
|
|
|
922
|
|
|
$GLOBALS['sql_create_trigger'] = true; |
923
|
|
|
$GLOBALS['sql_drop_table'] = true; |
924
|
|
|
|
925
|
|
|
$this->object->useSqlBackquotes(false); |
926
|
|
|
|
927
|
|
|
ob_start(); |
928
|
|
|
self::assertTrue( |
929
|
|
|
$this->object->exportStructure( |
930
|
|
|
'test_db', |
931
|
|
|
'test_table', |
932
|
|
|
'triggers', |
933
|
|
|
'test', |
934
|
|
|
), |
935
|
|
|
); |
936
|
|
|
$result = ob_get_clean(); |
937
|
|
|
|
938
|
|
|
self::assertIsString($result); |
939
|
|
|
self::assertStringContainsString('-- Triggers test_table', $result); |
940
|
|
|
self::assertStringContainsString( |
941
|
|
|
"CREATE TRIGGER `test_trigger` AFTER INSERT ON `test_table` FOR EACH ROW BEGIN END\n$$", |
942
|
|
|
$result, |
943
|
|
|
); |
944
|
|
|
|
945
|
|
|
unset($GLOBALS['sql_create_trigger']); |
946
|
|
|
unset($GLOBALS['sql_drop_table']); |
947
|
|
|
|
948
|
|
|
// case 3 |
949
|
|
|
$GLOBALS['sql_views_as_tables'] = false; |
950
|
|
|
|
951
|
|
|
$this->object->useSqlBackquotes(false); |
952
|
|
|
|
953
|
|
|
ob_start(); |
954
|
|
|
self::assertTrue( |
955
|
|
|
$this->object->exportStructure( |
956
|
|
|
'test_db', |
957
|
|
|
'test_table', |
958
|
|
|
'create_view', |
959
|
|
|
'test', |
960
|
|
|
), |
961
|
|
|
); |
962
|
|
|
$result = ob_get_clean(); |
963
|
|
|
|
964
|
|
|
$sqlViews = (new ReflectionProperty(ExportSql::class, 'sqlViews'))->getValue($this->object); |
965
|
|
|
|
966
|
|
|
self::assertEquals('', $result); |
967
|
|
|
self::assertIsString($sqlViews); |
968
|
|
|
self::assertStringContainsString('-- Structure for view test_table', $sqlViews); |
969
|
|
|
self::assertStringContainsString('DROP TABLE IF EXISTS `test_table`;', $sqlViews); |
970
|
|
|
self::assertStringContainsString('CREATE TABLE `test_table`', $sqlViews); |
971
|
|
|
|
972
|
|
|
// case 4 |
973
|
|
|
$GLOBALS['sql_views_as_tables'] = true; |
974
|
|
|
unset($GLOBALS['sql_if_not_exists']); |
975
|
|
|
|
976
|
|
|
ob_start(); |
977
|
|
|
self::assertTrue( |
978
|
|
|
$this->object->exportStructure( |
979
|
|
|
'test_db', |
980
|
|
|
'test_table', |
981
|
|
|
'create_view', |
982
|
|
|
'test', |
983
|
|
|
), |
984
|
|
|
); |
985
|
|
|
$result = ob_get_clean(); |
986
|
|
|
|
987
|
|
|
self::assertIsString($result); |
988
|
|
|
self::assertStringContainsString('-- Structure for view test_table exported as a table', $result); |
989
|
|
|
self::assertStringContainsString('DROP TABLE IF EXISTS `test_table`;', $result); |
990
|
|
|
self::assertStringContainsString('CREATE TABLE`test_table`', $result); |
991
|
|
|
|
992
|
|
|
// case 5 |
993
|
|
|
ob_start(); |
994
|
|
|
self::assertTrue( |
995
|
|
|
$this->object->exportStructure( |
996
|
|
|
'test_db', |
997
|
|
|
'test_table', |
998
|
|
|
'stand_in', |
999
|
|
|
'test', |
1000
|
|
|
), |
1001
|
|
|
); |
1002
|
|
|
$result = ob_get_clean(); |
1003
|
|
|
|
1004
|
|
|
self::assertIsString($result); |
1005
|
|
|
self::assertStringContainsString('-- Stand-in structure for view test_table', $result); |
1006
|
|
|
self::assertStringContainsString('CREATE TABLE `test_table`', $result); |
1007
|
|
|
} |
1008
|
|
|
|
1009
|
|
|
public function testExportData(): void |
1010
|
|
|
{ |
1011
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
1012
|
|
|
->disableOriginalConstructor() |
1013
|
|
|
->getMock(); |
1014
|
|
|
|
1015
|
|
|
$fields = [ |
1016
|
|
|
FieldHelper::fromArray([ |
1017
|
|
|
'type' => MYSQLI_TYPE_LONG, |
1018
|
|
|
'name' => 'name', |
1019
|
|
|
'length' => 2, |
1020
|
|
|
]), |
1021
|
|
|
FieldHelper::fromArray([ |
1022
|
|
|
'type' => -1, |
1023
|
|
|
'flags' => MYSQLI_NUM_FLAG, |
1024
|
|
|
'name' => 'name', |
1025
|
|
|
'length' => 2, |
1026
|
|
|
]), |
1027
|
|
|
FieldHelper::fromArray([ |
1028
|
|
|
'type' => MYSQLI_TYPE_STRING, |
1029
|
|
|
'name' => 'name', |
1030
|
|
|
'length' => 2, |
1031
|
|
|
'charsetnr' => 63, |
1032
|
|
|
]), |
1033
|
|
|
FieldHelper::fromArray([ |
1034
|
|
|
'type' => MYSQLI_TYPE_STRING, |
1035
|
|
|
'name' => 'name', |
1036
|
|
|
'length' => 2, |
1037
|
|
|
'charsetnr' => 63, |
1038
|
|
|
]), |
1039
|
|
|
FieldHelper::fromArray([ |
1040
|
|
|
'type' => MYSQLI_TYPE_BLOB, |
1041
|
|
|
'name' => 'name', |
1042
|
|
|
'length' => 2, |
1043
|
|
|
'charsetnr' => 63, |
1044
|
|
|
]), |
1045
|
|
|
]; |
1046
|
|
|
|
1047
|
|
|
$resultStub = self::createMock(DummyResult::class); |
|
|
|
|
1048
|
|
|
|
1049
|
|
|
$dbi->expects(self::once()) |
1050
|
|
|
->method('getFieldsMeta') |
1051
|
|
|
->with($resultStub) |
1052
|
|
|
->willReturn($fields); |
1053
|
|
|
|
1054
|
|
|
$dbi->expects(self::once()) |
1055
|
|
|
->method('tryQuery') |
1056
|
|
|
->with('SELECT a FROM b WHERE 1', ConnectionType::User, DatabaseInterface::QUERY_UNBUFFERED) |
1057
|
|
|
->willReturn($resultStub); |
1058
|
|
|
|
1059
|
|
|
$resultStub->expects(self::once()) |
1060
|
|
|
->method('numFields') |
1061
|
|
|
->willReturn(5); |
1062
|
|
|
|
1063
|
|
|
$resultStub->expects(self::exactly(2)) |
1064
|
|
|
->method('fetchRow') |
1065
|
|
|
->willReturn([null, 'test', '10', '6', "\x00\x0a\x0d\x1a"], []); |
1066
|
|
|
$dbi->expects(self::any())->method('quoteString') |
1067
|
|
|
->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); |
1068
|
|
|
|
1069
|
|
|
$tableObj = $this->getMockBuilder(Table::class) |
1070
|
|
|
->disableOriginalConstructor() |
1071
|
|
|
->getMock(); |
1072
|
|
|
$tableObj->expects(self::once()) |
1073
|
|
|
->method('isMerge') |
1074
|
|
|
->willReturn(false); |
1075
|
|
|
$tableObj->expects(self::once()) |
1076
|
|
|
->method('isView') |
1077
|
|
|
->willReturn(false); |
1078
|
|
|
|
1079
|
|
|
$dbi->expects(self::any()) |
1080
|
|
|
->method('getTable') |
1081
|
|
|
->willReturn($tableObj); |
1082
|
|
|
|
1083
|
|
|
DatabaseInterface::$instance = $dbi; |
1084
|
|
|
$GLOBALS['sql_compatibility'] = 'MSSQL'; |
1085
|
|
|
$GLOBALS['sql_max_query_size'] = 50000; |
1086
|
|
|
$GLOBALS['sql_views_as_tables'] = true; |
1087
|
|
|
$GLOBALS['sql_type'] = 'INSERT'; |
1088
|
|
|
$GLOBALS['sql_delayed'] = ' DELAYED'; |
1089
|
|
|
$GLOBALS['sql_ignore'] = true; |
1090
|
|
|
$GLOBALS['sql_truncate'] = true; |
1091
|
|
|
$GLOBALS['sql_insert_syntax'] = 'both'; |
1092
|
|
|
$GLOBALS['sql_hex_for_binary'] = true; |
1093
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = false; |
|
|
|
|
1094
|
|
|
|
1095
|
|
|
$this->object->useSqlBackquotes(true); |
1096
|
|
|
|
1097
|
|
|
ob_start(); |
1098
|
|
|
$this->object->exportData('db', 'table', 'example.com/err', 'SELECT a FROM b WHERE 1'); |
1099
|
|
|
$result = ob_get_clean(); |
1100
|
|
|
|
1101
|
|
|
self::assertIsString($result); |
1102
|
|
|
|
1103
|
|
|
self::assertStringContainsString('TRUNCATE TABLE "table";', $result); |
1104
|
|
|
|
1105
|
|
|
self::assertStringContainsString('SET IDENTITY_INSERT "table" ON ;', $result); |
1106
|
|
|
|
1107
|
|
|
self::assertStringContainsString( |
1108
|
|
|
'INSERT DELAYED IGNORE INTO "table" ("name", ' . |
1109
|
|
|
'"name", "name", "name", ' . |
1110
|
|
|
'"name") VALUES', |
1111
|
|
|
$result, |
1112
|
|
|
); |
1113
|
|
|
|
1114
|
|
|
self::assertStringContainsString('(NULL, \'test\', 0x3130, 0x36, 0x000a0d1a);', $result); |
1115
|
|
|
|
1116
|
|
|
self::assertStringContainsString('SET IDENTITY_INSERT "table" OFF;', $result); |
1117
|
|
|
} |
1118
|
|
|
|
1119
|
|
|
public function testExportDataWithUpdate(): void |
1120
|
|
|
{ |
1121
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
1122
|
|
|
->disableOriginalConstructor() |
1123
|
|
|
->getMock(); |
1124
|
|
|
|
1125
|
|
|
$fields = [ |
1126
|
|
|
FieldHelper::fromArray([ |
1127
|
|
|
'type' => MYSQLI_TYPE_FLOAT, |
1128
|
|
|
'flags' => MYSQLI_PRI_KEY_FLAG, |
1129
|
|
|
'name' => 'name', |
1130
|
|
|
'orgname' => 'pma', |
1131
|
|
|
'table' => 'tbl', |
1132
|
|
|
'orgtable' => 'tbl', |
1133
|
|
|
'length' => 2, |
1134
|
|
|
]), |
1135
|
|
|
FieldHelper::fromArray([ |
1136
|
|
|
'type' => MYSQLI_TYPE_FLOAT, |
1137
|
|
|
'flags' => MYSQLI_UNIQUE_KEY_FLAG, |
1138
|
|
|
'name' => 'name', |
1139
|
|
|
'orgname' => 'pma', |
1140
|
|
|
'table' => 'tbl', |
1141
|
|
|
'orgtable' => 'tbl', |
1142
|
|
|
'length' => 2, |
1143
|
|
|
]), |
1144
|
|
|
]; |
1145
|
|
|
|
1146
|
|
|
$resultStub = self::createMock(DummyResult::class); |
|
|
|
|
1147
|
|
|
|
1148
|
|
|
$dbi->expects(self::once()) |
1149
|
|
|
->method('getFieldsMeta') |
1150
|
|
|
->with($resultStub) |
1151
|
|
|
->willReturn($fields); |
1152
|
|
|
|
1153
|
|
|
$dbi->expects(self::once()) |
1154
|
|
|
->method('tryQuery') |
1155
|
|
|
->with('SELECT a FROM b WHERE 1', ConnectionType::User, DatabaseInterface::QUERY_UNBUFFERED) |
1156
|
|
|
->willReturn($resultStub); |
1157
|
|
|
|
1158
|
|
|
$resultStub->expects(self::once()) |
1159
|
|
|
->method('numFields') |
1160
|
|
|
->willReturn(2); |
1161
|
|
|
|
1162
|
|
|
$resultStub->expects(self::exactly(2)) |
1163
|
|
|
->method('fetchRow') |
1164
|
|
|
->willReturn([null, null], []); |
1165
|
|
|
|
1166
|
|
|
$tableObj = $this->getMockBuilder(Table::class) |
1167
|
|
|
->disableOriginalConstructor() |
1168
|
|
|
->getMock(); |
1169
|
|
|
$tableObj->expects(self::once()) |
1170
|
|
|
->method('isMerge') |
1171
|
|
|
->willReturn(false); |
1172
|
|
|
$tableObj->expects(self::once()) |
1173
|
|
|
->method('isView') |
1174
|
|
|
->willReturn(false); |
1175
|
|
|
|
1176
|
|
|
$dbi->expects(self::any()) |
1177
|
|
|
->method('getTable') |
1178
|
|
|
->willReturn($tableObj); |
1179
|
|
|
|
1180
|
|
|
DatabaseInterface::$instance = $dbi; |
1181
|
|
|
$GLOBALS['sql_compatibility'] = 'MSSQL'; |
1182
|
|
|
$GLOBALS['sql_views_as_tables'] = true; |
1183
|
|
|
$GLOBALS['sql_type'] = 'UPDATE'; |
1184
|
|
|
$GLOBALS['sql_delayed'] = ' DELAYED'; |
1185
|
|
|
$GLOBALS['sql_ignore'] = true; |
1186
|
|
|
$GLOBALS['sql_truncate'] = true; |
1187
|
|
|
$GLOBALS['sql_insert_syntax'] = 'both'; |
1188
|
|
|
$GLOBALS['sql_hex_for_binary'] = true; |
1189
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = false; |
|
|
|
|
1190
|
|
|
|
1191
|
|
|
$this->object->useSqlBackquotes(true); |
1192
|
|
|
|
1193
|
|
|
ob_start(); |
1194
|
|
|
$this->object->exportData('db', 'table', 'example.com/err', 'SELECT a FROM b WHERE 1'); |
1195
|
|
|
$result = ob_get_clean(); |
1196
|
|
|
|
1197
|
|
|
self::assertIsString($result); |
1198
|
|
|
|
1199
|
|
|
self::assertStringContainsString( |
1200
|
|
|
'UPDATE IGNORE "table" SET "name" = NULL,' . |
1201
|
|
|
'"name" = NULL WHERE CONCAT(`tbl`.`pma`) IS NULL;', |
1202
|
|
|
$result, |
1203
|
|
|
); |
1204
|
|
|
} |
1205
|
|
|
|
1206
|
|
|
public function testExportDataWithIsView(): void |
1207
|
|
|
{ |
1208
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
1209
|
|
|
->disableOriginalConstructor() |
1210
|
|
|
->getMock(); |
1211
|
|
|
|
1212
|
|
|
$tableObj = $this->getMockBuilder(Table::class) |
1213
|
|
|
->disableOriginalConstructor() |
1214
|
|
|
->getMock(); |
1215
|
|
|
$tableObj->expects(self::once()) |
1216
|
|
|
->method('isMerge') |
1217
|
|
|
->willReturn(false); |
1218
|
|
|
$tableObj->expects(self::once()) |
1219
|
|
|
->method('isView') |
1220
|
|
|
->willReturn(true); |
1221
|
|
|
|
1222
|
|
|
$dbi->expects(self::any()) |
1223
|
|
|
->method('getTable') |
1224
|
|
|
->willReturn($tableObj); |
1225
|
|
|
|
1226
|
|
|
DatabaseInterface::$instance = $dbi; |
1227
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = false; |
|
|
|
|
1228
|
|
|
$GLOBALS['sql_views_as_tables'] = false; |
1229
|
|
|
$GLOBALS['sql_include_comments'] = true; |
1230
|
|
|
$oldVal = $GLOBALS['sql_compatibility'] ?? ''; |
1231
|
|
|
$GLOBALS['sql_compatibility'] = 'NONE'; |
1232
|
|
|
|
1233
|
|
|
$this->object->useSqlBackquotes(true); |
1234
|
|
|
|
1235
|
|
|
ob_start(); |
1236
|
|
|
self::assertTrue( |
1237
|
|
|
$this->object->exportData('db', 'tbl', 'err.com', 'SELECT'), |
1238
|
|
|
); |
1239
|
|
|
$result = ob_get_clean(); |
1240
|
|
|
|
1241
|
|
|
self::assertIsString($result); |
1242
|
|
|
|
1243
|
|
|
self::assertStringContainsString("-- VIEW `tbl`\n", $result); |
1244
|
|
|
|
1245
|
|
|
self::assertStringContainsString("-- Data: None\n", $result); |
1246
|
|
|
|
1247
|
|
|
// reset |
1248
|
|
|
$GLOBALS['sql_compatibility'] = $oldVal; |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
public function testExportDataWithError(): void |
1252
|
|
|
{ |
1253
|
|
|
$dbi = $this->getMockBuilder(DatabaseInterface::class) |
1254
|
|
|
->disableOriginalConstructor() |
1255
|
|
|
->getMock(); |
1256
|
|
|
|
1257
|
|
|
$dbi->expects(self::once()) |
1258
|
|
|
->method('getError') |
1259
|
|
|
->willReturn('err'); |
1260
|
|
|
|
1261
|
|
|
$tableObj = $this->getMockBuilder(Table::class) |
1262
|
|
|
->disableOriginalConstructor() |
1263
|
|
|
->getMock(); |
1264
|
|
|
$tableObj->expects(self::once()) |
1265
|
|
|
->method('isMerge') |
1266
|
|
|
->willReturn(false); |
1267
|
|
|
$tableObj->expects(self::once()) |
1268
|
|
|
->method('isView') |
1269
|
|
|
->willReturn(false); |
1270
|
|
|
|
1271
|
|
|
$dbi->expects(self::any()) |
1272
|
|
|
->method('getTable') |
1273
|
|
|
->willReturn($tableObj); |
1274
|
|
|
|
1275
|
|
|
DatabaseInterface::$instance = $dbi; |
1276
|
|
|
Config::getInstance()->selectedServer['DisableIS'] = false; |
|
|
|
|
1277
|
|
|
$GLOBALS['sql_views_as_tables'] = true; |
1278
|
|
|
$GLOBALS['sql_include_comments'] = true; |
1279
|
|
|
|
1280
|
|
|
ob_start(); |
1281
|
|
|
self::assertTrue( |
1282
|
|
|
$this->object->exportData('db', 'table', 'err.com', 'SELECT'), |
1283
|
|
|
); |
1284
|
|
|
$result = ob_get_clean(); |
1285
|
|
|
|
1286
|
|
|
self::assertIsString($result); |
1287
|
|
|
|
1288
|
|
|
self::assertStringContainsString('-- Error reading data for table db.table: err', $result); |
1289
|
|
|
} |
1290
|
|
|
|
1291
|
|
|
public function testMakeCreateTableMSSQLCompatible(): void |
1292
|
|
|
{ |
1293
|
|
|
$query = "CREATE TABLE IF NOT EXISTS (\" date DEFAULT NULL,\n" |
1294
|
|
|
. "\" date DEFAULT NULL\n\" date NOT NULL,\n\" date NOT NULL\n," |
1295
|
|
|
. " \" date NOT NULL DEFAULT 'asd'," |
1296
|
|
|
. " ) unsigned NOT NULL\n, ) unsigned NOT NULL,\n" |
1297
|
|
|
. " ) unsigned DEFAULT NULL\n, ) unsigned DEFAULT NULL,\n" |
1298
|
|
|
. " ) unsigned NOT NULL DEFAULT 'dsa',\n" |
1299
|
|
|
. " \" int(10) DEFAULT NULL,\n" |
1300
|
|
|
. " \" tinyint(0) DEFAULT NULL\n" |
1301
|
|
|
. " \" smallint(10) NOT NULL,\n" |
1302
|
|
|
. " \" bigint(0) NOT NULL\n" |
1303
|
|
|
. " \" bigint(0) NOT NULL DEFAULT '12'\n" |
1304
|
|
|
. " \" float(22,2,) DEFAULT NULL,\n" |
1305
|
|
|
. " \" double DEFAULT NULL\n" |
1306
|
|
|
. " \" float(22,2,) NOT NULL,\n" |
1307
|
|
|
. " \" double NOT NULL\n" |
1308
|
|
|
. " \" double NOT NULL DEFAULT '213'\n"; |
1309
|
|
|
|
1310
|
|
|
$method = new ReflectionMethod(ExportSql::class, 'makeCreateTableMSSQLCompatible'); |
1311
|
|
|
$result = $method->invoke($this->object, $query); |
1312
|
|
|
|
1313
|
|
|
self::assertSame( |
1314
|
|
|
"CREATE TABLE (\" datetime DEFAULT NULL,\n" . |
1315
|
|
|
"\" datetime DEFAULT NULL\n" . |
1316
|
|
|
"\" datetime NOT NULL,\n" . |
1317
|
|
|
"\" datetime NOT NULL\n" . |
1318
|
|
|
", \" datetime NOT NULL DEFAULT 'asd', ) NOT NULL\n" . |
1319
|
|
|
", ) NOT NULL,\n" . |
1320
|
|
|
" ) DEFAULT NULL\n" . |
1321
|
|
|
", ) DEFAULT NULL,\n" . |
1322
|
|
|
" ) NOT NULL DEFAULT 'dsa',\n" . |
1323
|
|
|
" \" int DEFAULT NULL,\n" . |
1324
|
|
|
" \" tinyint DEFAULT NULL\n" . |
1325
|
|
|
" \" smallint NOT NULL,\n" . |
1326
|
|
|
" \" bigint NOT NULL\n" . |
1327
|
|
|
" \" bigint NOT NULL DEFAULT '12'\n" . |
1328
|
|
|
" \" float DEFAULT NULL,\n" . |
1329
|
|
|
" \" float DEFAULT NULL\n" . |
1330
|
|
|
" \" float NOT NULL,\n" . |
1331
|
|
|
" \" float NOT NULL\n" . |
1332
|
|
|
" \" float NOT NULL DEFAULT '213'\n", |
1333
|
|
|
$result, |
1334
|
|
|
); |
1335
|
|
|
} |
1336
|
|
|
|
1337
|
|
|
public function testInitAlias(): void |
1338
|
|
|
{ |
1339
|
|
|
$aliases = [ |
1340
|
|
|
'a' => [ |
1341
|
|
|
'alias' => 'aliastest', |
1342
|
|
|
'tables' => ['foo' => ['alias' => 'qwerty'], 'bar' => ['alias' => 'f']], |
1343
|
|
|
], |
1344
|
|
|
]; |
1345
|
|
|
$db = 'a'; |
1346
|
|
|
$table = null; |
1347
|
|
|
|
1348
|
|
|
$this->object->initAlias($aliases, $db, $table); |
1349
|
|
|
self::assertSame('aliastest', $db); |
1350
|
|
|
self::assertNull($table); |
1351
|
|
|
|
1352
|
|
|
$db = 'foo'; |
1353
|
|
|
$table = 'qwerty'; |
1354
|
|
|
|
1355
|
|
|
$this->object->initAlias($aliases, $db, $table); |
1356
|
|
|
self::assertSame('foo', $db); |
1357
|
|
|
self::assertSame('qwerty', $table); |
1358
|
|
|
|
1359
|
|
|
$db = 'a'; |
1360
|
|
|
$table = 'foo'; |
1361
|
|
|
|
1362
|
|
|
$this->object->initAlias($aliases, $db, $table); |
1363
|
|
|
self::assertSame('aliastest', $db); |
1364
|
|
|
self::assertSame('qwerty', $table); |
1365
|
|
|
} |
1366
|
|
|
|
1367
|
|
|
public function testGetAlias(): void |
1368
|
|
|
{ |
1369
|
|
|
$aliases = [ |
1370
|
|
|
'a' => [ |
1371
|
|
|
'alias' => 'aliastest', |
1372
|
|
|
'tables' => [ |
1373
|
|
|
'foo' => ['alias' => 'qwerty', 'columns' => ['baz' => 'p', 'pqr' => 'pphymdain']], |
1374
|
|
|
'bar' => ['alias' => 'f', 'columns' => ['xy' => 'n']], |
1375
|
|
|
], |
1376
|
|
|
], |
1377
|
|
|
]; |
1378
|
|
|
|
1379
|
|
|
self::assertSame( |
1380
|
|
|
'f', |
1381
|
|
|
$this->object->getAlias($aliases, 'bar'), |
1382
|
|
|
); |
1383
|
|
|
|
1384
|
|
|
self::assertSame( |
1385
|
|
|
'aliastest', |
1386
|
|
|
$this->object->getAlias($aliases, 'a'), |
1387
|
|
|
); |
1388
|
|
|
|
1389
|
|
|
self::assertSame( |
1390
|
|
|
'pphymdain', |
1391
|
|
|
$this->object->getAlias($aliases, 'pqr'), |
1392
|
|
|
); |
1393
|
|
|
|
1394
|
|
|
self::assertSame( |
1395
|
|
|
'', |
1396
|
|
|
$this->object->getAlias($aliases, 'abc'), |
1397
|
|
|
); |
1398
|
|
|
} |
1399
|
|
|
|
1400
|
|
|
public function testReplaceWithAlias(): void |
1401
|
|
|
{ |
1402
|
|
|
$aliases = [ |
1403
|
|
|
'a' => [ |
1404
|
|
|
'alias' => 'aliastest', |
1405
|
|
|
'tables' => [ |
1406
|
|
|
'foo' => ['alias' => 'bartest', 'columns' => ['baz' => 'p', 'pqr' => 'pphymdain']], |
1407
|
|
|
'bar' => ['alias' => 'f', 'columns' => ['xy' => 'n']], |
1408
|
|
|
], |
1409
|
|
|
], |
1410
|
|
|
]; |
1411
|
|
|
|
1412
|
|
|
$db = 'a'; |
1413
|
|
|
$sqlQuery = "CREATE TABLE IF NOT EXISTS foo (\n" |
1414
|
|
|
. "baz tinyint(3) unsigned NOT NULL COMMENT 'Primary Key',\n" |
1415
|
|
|
. 'xyz varchar(255) COLLATE latin1_general_ci NOT NULL ' |
1416
|
|
|
. "COMMENT 'xyz',\n" |
1417
|
|
|
. 'pqr varchar(10) COLLATE latin1_general_ci NOT NULL ' |
1418
|
|
|
. "COMMENT 'pqr',\n" |
1419
|
|
|
. 'CONSTRAINT fk_om_dept FOREIGN KEY (baz) ' |
1420
|
|
|
. "REFERENCES dept_master (baz)\n" |
1421
|
|
|
. ') ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=' |
1422
|
|
|
. "latin1_general_ci COMMENT='List' AUTO_INCREMENT=5"; |
1423
|
|
|
$result = $this->object->replaceWithAliases(null, $sqlQuery, $aliases, $db); |
1424
|
|
|
|
1425
|
|
|
self::assertSame( |
1426
|
|
|
"CREATE TABLE IF NOT EXISTS `bartest` (\n" . |
1427
|
|
|
" `p` tinyint(3) UNSIGNED NOT NULL COMMENT 'Primary Key',\n" . |
1428
|
|
|
" `xyz` varchar(255) COLLATE latin1_general_ci NOT NULL COMMENT 'xyz',\n" . |
1429
|
|
|
" `pphymdain` varchar(10) COLLATE latin1_general_ci NOT NULL COMMENT 'pqr',\n" . |
1430
|
|
|
" CONSTRAINT `fk_om_dept` FOREIGN KEY (`p`) REFERENCES dept_master (`baz`)\n" . |
1431
|
|
|
") ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci COMMENT='List'", |
1432
|
|
|
$result, |
1433
|
|
|
); |
1434
|
|
|
|
1435
|
|
|
$result = $this->object->replaceWithAliases(null, $sqlQuery, [], ''); |
1436
|
|
|
|
1437
|
|
|
self::assertSame( |
1438
|
|
|
"CREATE TABLE IF NOT EXISTS foo (\n" . |
1439
|
|
|
" `baz` tinyint(3) UNSIGNED NOT NULL COMMENT 'Primary Key',\n" . |
1440
|
|
|
" `xyz` varchar(255) COLLATE latin1_general_ci NOT NULL COMMENT 'xyz',\n" . |
1441
|
|
|
" `pqr` varchar(10) COLLATE latin1_general_ci NOT NULL COMMENT 'pqr',\n" . |
1442
|
|
|
" CONSTRAINT `fk_om_dept` FOREIGN KEY (`baz`) REFERENCES dept_master (`baz`)\n" . |
1443
|
|
|
") ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci COMMENT='List'", |
1444
|
|
|
$result, |
1445
|
|
|
); |
1446
|
|
|
|
1447
|
|
|
$sqlQuery = 'CREATE TRIGGER `BEFORE_bar_INSERT` ' |
1448
|
|
|
. 'BEFORE INSERT ON `bar` ' |
1449
|
|
|
. 'FOR EACH ROW BEGIN ' |
1450
|
|
|
. 'SET @cnt=(SELECT count(*) FROM bar WHERE ' |
1451
|
|
|
. 'xy=NEW.xy AND id=NEW.id AND ' |
1452
|
|
|
. 'abc=NEW.xy LIMIT 1); ' |
1453
|
|
|
. 'IF @cnt<>0 THEN ' |
1454
|
|
|
. 'SET NEW.xy=1; ' |
1455
|
|
|
. 'END IF; END'; |
1456
|
|
|
$result = $this->object->replaceWithAliases('$$', $sqlQuery, $aliases, $db); |
1457
|
|
|
|
1458
|
|
|
self::assertSame( |
1459
|
|
|
'CREATE TRIGGER `BEFORE_bar_INSERT` BEFORE INSERT ON `f` FOR EACH ROW BEGIN ' . |
1460
|
|
|
'SET @cnt=(SELECT count(*) FROM `f` WHERE `n`=NEW.`n` AND id=NEW.id AND abc=NEW.`n` LIMIT 1); ' . |
1461
|
|
|
'IF @cnt<>0 THEN ' . |
1462
|
|
|
'SET NEW.`n`=1; ' . |
1463
|
|
|
'END IF; ' . |
1464
|
|
|
'END', |
1465
|
|
|
$result, |
1466
|
|
|
); |
1467
|
|
|
|
1468
|
|
|
$sqlQuery = <<<'SQL' |
1469
|
|
|
CREATE FUNCTION `HTML_UnEncode`(`x` TEXT CHARSET utf8) RETURNS text CHARSET utf8 |
1470
|
|
|
BEGIN |
1471
|
|
|
|
1472
|
|
|
DECLARE TextString TEXT ; |
1473
|
|
|
SET TextString = x ; |
1474
|
|
|
|
1475
|
|
|
#quotation mark |
1476
|
|
|
IF INSTR( x , '"' ) |
1477
|
|
|
THEN SET TextString = REPLACE(TextString, '"','"') ; |
1478
|
|
|
END IF ; |
1479
|
|
|
|
1480
|
|
|
#apostrophe |
1481
|
|
|
IF INSTR( x , ''' ) |
1482
|
|
|
THEN SET TextString = REPLACE(TextString, ''','"') ; |
1483
|
|
|
END IF ; |
1484
|
|
|
|
1485
|
|
|
RETURN TextString ; |
1486
|
|
|
|
1487
|
|
|
END |
1488
|
|
|
SQL; |
1489
|
|
|
|
1490
|
|
|
$result = $this->object->replaceWithAliases('$$', $sqlQuery, $aliases, $db); |
1491
|
|
|
|
1492
|
|
|
$expectedQuery = <<<'SQL' |
1493
|
|
|
CREATE FUNCTION `HTML_UnEncode` (`x` TEXT CHARSET utf8) RETURNS TEXT CHARSET utf8 BEGIN |
1494
|
|
|
|
1495
|
|
|
DECLARE TextString TEXT ; |
1496
|
|
|
SET TextString = x ; |
1497
|
|
|
|
1498
|
|
|
#quotation mark |
1499
|
|
|
IF INSTR( x , '"' ) |
1500
|
|
|
THEN SET TextString = REPLACE(TextString, '"','"') ; |
1501
|
|
|
END IF ; |
1502
|
|
|
|
1503
|
|
|
#apostrophe |
1504
|
|
|
IF INSTR( x , ''' ) |
1505
|
|
|
THEN SET TextString = REPLACE(TextString, ''','"') ; |
1506
|
|
|
END IF ; |
1507
|
|
|
|
1508
|
|
|
RETURN TextString ; |
1509
|
|
|
|
1510
|
|
|
END |
1511
|
|
|
SQL; |
1512
|
|
|
|
1513
|
|
|
self::assertSame($expectedQuery, $result); |
1514
|
|
|
} |
1515
|
|
|
} |
1516
|
|
|
|
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.