3 declare(strict_types
=1);
5 namespace PhpMyAdmin\Tests\Table
;
8 use PhpMyAdmin\ConfigStorage\Relation
;
9 use PhpMyAdmin\ConfigStorage\RelationParameters
;
10 use PhpMyAdmin\Current
;
11 use PhpMyAdmin\Dbal\ConnectionType
;
12 use PhpMyAdmin\Dbal\DatabaseInterface
;
13 use PhpMyAdmin\ListDatabase
;
14 use PhpMyAdmin\Query\Cache
;
15 use PhpMyAdmin\SqlParser\Context
;
16 use PhpMyAdmin\Table\MoveMode
;
17 use PhpMyAdmin\Table\MoveScope
;
18 use PhpMyAdmin\Table\Table
;
19 use PhpMyAdmin\Table\TableMover
;
20 use PhpMyAdmin\Table\UiProperty
;
21 use PhpMyAdmin\Tests\AbstractTestCase
;
22 use PhpMyAdmin\Tests\FieldHelper
;
23 use PhpMyAdmin\Tests\Stubs\DbiDummy
;
24 use PhpMyAdmin\Tests\Stubs\DummyResult
;
25 use PHPUnit\Framework\Attributes\CoversClass
;
26 use PHPUnit\Framework\Attributes\DataProvider
;
27 use PHPUnit\Framework\MockObject\MockObject
;
28 use ReflectionProperty
;
30 use const MYSQLI_TYPE_STRING
;
32 #[CoversClass(Table::class)]
33 class TableTest
extends AbstractTestCase
35 private DatabaseInterface
&MockObject
$mockedDbi;
38 * Configures environment
40 protected function setUp(): void
45 * SET these to avoid undefined index error
47 $config = Config
::getInstance();
48 $config->selectedServer
['DisableIS'] = false;
49 $config->settings
['MaxExactCount'] = 100;
50 $config->settings
['MaxExactCountViews'] = 100;
51 $config->selectedServer
['pmadb'] = 'pmadb';
52 $config->selectedServer
['table_uiprefs'] = 'pma__table_uiprefs';
54 $sqlIsViewTrue = 'SELECT 1'
55 . ' FROM information_schema.VIEWS'
56 . ' WHERE TABLE_SCHEMA = \'PMA\''
57 . ' AND TABLE_NAME = \'PMA_BookMark\'';
59 $sqlIsViewFalse = 'SELECT 1'
60 . ' FROM information_schema.VIEWS'
61 . ' WHERE TABLE_SCHEMA = \'PMA\''
62 . ' AND TABLE_NAME = \'PMA_BookMark_2\'';
64 $sqlIsUpdatableViewTrue = 'SELECT 1'
65 . ' FROM information_schema.VIEWS'
66 . ' WHERE TABLE_SCHEMA = \'PMA\''
67 . ' AND TABLE_NAME = \'PMA_BookMark\''
68 . ' AND IS_UPDATABLE = \'YES\'';
70 $sqlIsUpdatableViewFalse = 'SELECT 1'
71 . ' FROM information_schema.VIEWS'
72 . ' WHERE TABLE_SCHEMA = \'PMA\''
73 . ' AND TABLE_NAME = \'PMA_BookMark_2\''
74 . ' AND IS_UPDATABLE = \'YES\'';
76 $sqlAnalyzeStructureTrue = 'SELECT COLUMN_NAME, DATA_TYPE'
77 . ' FROM information_schema.COLUMNS'
78 . ' WHERE TABLE_SCHEMA = \'PMA\''
79 . ' AND TABLE_NAME = \'PMA_BookMark\'';
81 $sqlCopyData = 'SELECT 1'
82 . ' FROM information_schema.VIEWS'
83 . ' WHERE TABLE_SCHEMA = \'PMA_new\''
84 . ' AND TABLE_NAME = \'PMA_BookMark_new\'';
86 $getUniqueColumnsSql = 'SHOW INDEXES FROM `PMA`.`PMA_BookMark`';
88 $fetchResultSimple = [
90 $sqlAnalyzeStructureTrue,
92 [['COLUMN_NAME' => 'COLUMN_NAME', 'DATA_TYPE' => 'DATA_TYPE']],
95 'SHOW COLUMNS FROM `PMA`.`PMA_BookMark`',
99 'Field' => 'COLUMN_NAME1',
107 'Field' => 'COLUMN_NAME2',
112 'Extra' => 'STORED GENERATED',
117 'SHOW TRIGGERS FROM `PMA` LIKE \'PMA_BookMark\';',
118 ConnectionType
::User
,
121 'Trigger' => 'name1',
123 'Table' => 'PMA_BookMark',
125 'Statement' => 'BEGIN END',
126 'Definer' => 'test_user@localhost',
129 'Trigger' => 'name2',
131 'Table' => 'PMA_BookMark',
133 'Statement' => 'BEGIN END',
134 'Definer' => 'test_user@localhost',
137 'Trigger' => 'name3',
139 'Table' => 'PMA_BookMark',
141 'Statement' => 'BEGIN END',
142 'Definer' => 'test_user@localhost',
147 'SHOW TRIGGERS FROM `PMA` LIKE \'PMA_.BookMark\';',
148 ConnectionType
::User
,
151 'Trigger' => 'name1',
153 'Table' => 'PMA_.BookMark',
155 'Statement' => 'BEGIN END',
156 'Definer' => 'test_user@localhost',
159 'Trigger' => 'name2',
161 'Table' => 'PMA_.BookMark',
163 'Statement' => 'BEGIN END',
164 'Definer' => 'test_user@localhost',
167 'Trigger' => 'name3',
169 'Table' => 'PMA_.BookMark',
171 'Statement' => 'BEGIN END',
172 'Definer' => 'test_user@localhost',
177 'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, '
178 . 'ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER FROM '
179 . "information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA COLLATE utf8_bin= 'PMA' "
180 . "AND EVENT_OBJECT_TABLE COLLATE utf8_bin = 'PMA_BookMark';",
181 ConnectionType
::User
,
187 'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, '
188 . 'ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER FROM '
189 . "information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA COLLATE utf8_bin= 'aa' "
190 . "AND EVENT_OBJECT_TABLE COLLATE utf8_bin = 'ad';",
191 ConnectionType
::User
,
197 'SHOW COLUMNS FROM `aa`.`ad`',
198 ConnectionType
::User
,
205 $getUniqueColumnsSql . ' WHERE (Non_unique = 0)',
208 ConnectionType
::User
,
209 [['index1'], ['index3'], ['index5']],
212 $getUniqueColumnsSql,
215 ConnectionType
::User
,
216 ['column1', 'column3', 'column5', 'ACCESSIBLE', 'ADD', 'ALL'],
219 'SHOW COLUMNS FROM `PMA`.`PMA_BookMark`',
222 ConnectionType
::User
,
223 ['column1', 'column3', 'column5', 'ACCESSIBLE', 'ADD', 'ALL'],
228 [$sqlIsViewTrue, 0, ConnectionType
::User
, 'PMA_BookMark'],
229 [$sqlCopyData, 0, ConnectionType
::User
, false],
230 [$sqlIsViewFalse, 0, ConnectionType
::User
, false],
231 [$sqlIsUpdatableViewTrue, 0, ConnectionType
::User
, 'PMA_BookMark'],
232 [$sqlIsUpdatableViewFalse, 0, ConnectionType
::User
, false],
234 "SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = 'aa' AND TABLE_NAME = 'ad'",
236 ConnectionType
::User
,
240 "SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = 'bb' AND TABLE_NAME = 'ad'",
242 ConnectionType
::User
,
247 $resultStub = $this->createMock(DummyResult
::class);
249 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
250 ->disableOriginalConstructor()
253 $databaseList = self
::createStub(ListDatabase
::class);
254 $databaseList->method('exists')->willReturn(true);
255 $dbi->expects(self
::any())->method('getDatabaseList')->willReturn($databaseList);
257 $dbi->expects(self
::any())->method('fetchResult')
258 ->willReturnMap($fetchResult);
260 $dbi->expects(self
::any())->method('fetchResultSimple')
261 ->willReturnMap($fetchResultSimple);
263 $dbi->expects(self
::any())->method('fetchValue')
264 ->willReturnMap($fetchValue);
266 $cache = new Cache();
267 $dbi->expects(self
::any())->method('getCache')
268 ->willReturn($cache);
270 $dbi->expects(self
::any())->method('getColumnNames')
275 ConnectionType
::User
,
276 ['column1', 'column3', 'column5', 'ACCESSIBLE', 'ADD', 'ALL'],
281 $databaseName = 'PMA';
282 $databases[$databaseName]['SCHEMA_TABLES'] = 1;
283 $databases[$databaseName]['SCHEMA_TABLE_ROWS'] = 3;
284 $databases[$databaseName]['SCHEMA_DATA_LENGTH'] = 5;
285 $databases[$databaseName]['SCHEMA_MAX_DATA_LENGTH'] = 10;
286 $databases[$databaseName]['SCHEMA_INDEX_LENGTH'] = 10;
287 $databases[$databaseName]['SCHEMA_LENGTH'] = 10;
289 $dbi->expects(self
::any())->method('getTablesFull')
290 ->willReturn($databases);
292 $dbi->expects(self
::any())->method('query')
293 ->willReturn($resultStub);
295 $dbi->expects(self
::any())->method('insertId')
298 $resultStub->expects(self
::any())->method('fetchAssoc')
301 $value = ['Auto_increment' => 'Auto_increment'];
302 $dbi->expects(self
::any())->method('fetchSingleRow')
303 ->willReturn($value);
305 $resultStub->expects(self
::any())->method('fetchRow')
308 $dbi->expects(self
::any())->method('quoteString')
309 ->willReturnCallback(static fn (string $string): string => "'" . $string . "'");
311 DatabaseInterface
::$instance = $dbi;
312 $this->mockedDbi
= $dbi;
315 protected function tearDown(): void
319 DatabaseInterface
::$instance = null;
323 * Test for constructor
325 public function testConstruct(): void
327 $table = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
330 $table->__toString(),
342 $table->getFullName(),
347 * Test getName & getDbName
349 public function testGetName(): void
351 $table = new Table('table1', 'pma_test', $this->mockedDbi
);
358 $table->getName(true),
366 $table->getDbName(true),
371 * Test getLastError & getLastMessage
373 public function testGetLastErrorAndMessage(): void
375 $table = new Table('table1', 'pma_test', $this->mockedDbi
);
376 $table->errors
[] = 'error1';
377 $table->errors
[] = 'error2';
378 $table->errors
[] = 'error3';
380 $table->messages
[] = 'messages1';
381 $table->messages
[] = 'messages2';
382 $table->messages
[] = 'messages3';
386 $table->getLastError(),
390 $table->getLastMessage(),
396 $table->getLastError(),
399 $table->messages
= [];
402 $table->getLastMessage(),
407 * Test name validation
409 * @param string $name name to test
410 * @param bool $result expected result
411 * @param bool $isBackquoted is backquoted
413 #[DataProvider('dataValidateName')]
414 public function testValidateName(string $name, bool $result, bool $isBackquoted = false): void
418 Table
::isValidName($name, $isBackquoted),
422 /** @return array<array{0: string, 1: bool, 2?: bool}> */
423 public static function dataValidateName(): array
431 [' te st', true, true],
434 ['test ', false, true],
435 ['te.st ', false, true],
442 public function testIsView(): void
444 $table = new Table('', '', $this->mockedDbi
);
449 //validate that it is the same as DBI fetchResult
450 $table = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
455 $table = new Table('PMA_BookMark_2', 'PMA', $this->mockedDbi
);
462 * Test for generateFieldSpec
464 public function testGenerateFieldSpec(): void
470 $attribute = 'PMA_attribute';
471 $collation = 'PMA_collation';
473 $defaultType = 'USER_DEFINED';
474 $defaultValue = '12';
475 $extra = 'AUTO_INCREMENT';
476 $comment = 'PMA_comment';
481 $query = Table
::generateFieldSpec(
497 '`PMA_name` BIT(12) PMA_attribute NULL DEFAULT b\'10\' AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
503 $query = Table
::generateFieldSpec(
519 '`PMA_name` DOUBLE(12) PMA_attribute NULL DEFAULT \'12\' AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
525 $query = Table
::generateFieldSpec(
541 '`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT TRUE AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
545 //$default_type is NULL
546 $defaultType = 'NULL';
547 $query = Table
::generateFieldSpec(
563 '`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT NULL AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
567 //$default_type is CURRENT_TIMESTAMP
568 $defaultType = 'CURRENT_TIMESTAMP';
569 $query = Table
::generateFieldSpec(
585 '`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT CURRENT_TIMESTAMP '
586 . "AUTO_INCREMENT COMMENT 'PMA_comment' FIRST",
590 //$default_type is current_timestamp()
591 $defaultType = 'current_timestamp()';
592 $query = Table
::generateFieldSpec(
608 '`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT current_timestamp() '
609 . "AUTO_INCREMENT COMMENT 'PMA_comment' FIRST",
613 // $type is 'TIMESTAMP(3), $default_type is CURRENT_TIMESTAMP(3)
617 $defaultType = 'CURRENT_TIMESTAMP';
618 $query = Table
::generateFieldSpec(
634 '`PMA_name` TIMESTAMP(3) PMA_attribute NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT \'PMA_comment\' FIRST',
641 $defaultType = 'USER_DEFINED';
642 $defaultValue = '\'0000-00-00 00:00:00\'';
643 $query = Table
::generateFieldSpec(
659 '`PMA_name` TIMESTAMP PMA_attribute NULL DEFAULT \'0000-00-00 00:00:00\' COMMENT \'PMA_comment\' FIRST',
666 $defaultType = 'USER_DEFINED';
667 $defaultValue = '\'0000-00-00 00:00:00.0\'';
668 $query = Table
::generateFieldSpec(
684 '`PMA_name` TIMESTAMP PMA_attribute NULL DEFAULT \'0000-00-00 00:00:00.0\' COMMENT \'PMA_comment\' FIRST',
691 $defaultType = 'USER_DEFINED';
692 $defaultValue = '\'0000-00-00 00:00:00.000000\'';
693 $query = Table
::generateFieldSpec(
709 '`PMA_name` TIMESTAMP PMA_attribute NULL DEFAULT \'0000-00-00 00:00:00.000000\' '
710 . "COMMENT 'PMA_comment' FIRST",
714 //$default_type is UUID
716 $defaultType = 'UUID';
718 $query = Table
::generateFieldSpec(
733 self
::assertSame('`PMA_name` UUID PMA_attribute NULL DEFAULT uuid()', $query);
735 //$default_type is uuid()
737 $defaultType = 'uuid()';
739 $query = Table
::generateFieldSpec(
754 self
::assertSame('`PMA_name` UUID PMA_attribute NULL DEFAULT uuid()', $query);
756 //$default_type is NONE
758 $defaultType = 'NONE';
759 $extra = 'INCREMENT';
761 $query = Table
::generateFieldSpec(
776 self
::assertSame('`PMA_name` BOOLEAN PMA_attribute NULL INCREMENT COMMENT \'PMA_comment\' FIRST', $query);
778 $defaultType = 'NONE';
780 $query = Table
::generateFieldSpec(
797 self
::assertSame('`ids` INT(11) PMA_attribute NULL AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST', $query);
799 $defaultType = 'NONE';
801 $query = Table
::generateFieldSpec(
818 // Add primary key for AUTO_INCREMENT if missing
820 '`ids` INT(11) PMA_attribute NULL AUTO_INCREMENT '
821 . "COMMENT 'PMA_comment' FIRST, ADD PRIMARY KEY (`ids`)",
825 $defaultType = 'NONE';
827 $query = Table
::generateFieldSpec(
845 self
::assertSame('`id` INT(11) PMA_attribute NULL DEF COMMENT \'PMA_comment\' FIRST', $query);
847 $defaultType = 'NONE';
849 $query = Table
::generateFieldSpec(
867 self
::assertSame('`ids` INT(11) PMA_attribute NULL DEF COMMENT \'PMA_comment\' FIRST', $query);
869 $defaultType = 'NONE';
871 $query = Table
::generateFieldSpec(
888 // Add it beaucause it is missing
890 '`ids` INT(11) PMA_attribute NULL DEF COMMENT \'PMA_comment\' FIRST, ADD PRIMARY KEY (`ids`)',
894 $defaultType = 'NONE';
896 $query = Table
::generateFieldSpec(
913 // Do not add PK since it is not a AUTO_INCREMENT
915 '`ids` INT(11) PMA_attribute AS (1) VIRTUAL NULL USER_DEFINED COMMENT \'PMA_comment\' FIRST',
921 * Test for duplicateInfo
923 public function testDuplicateInfo(): void
925 $getFields = ['filed0', 'field6'];
926 $whereFields = ['field2', 'filed5'];
927 $newFields = ['field3', 'filed4'];
929 $relationParameters = RelationParameters
::fromArray([
932 'relation' => 'relation',
934 (new ReflectionProperty(Relation
::class, 'cache'))->setValue(null, $relationParameters);
936 $object = new TableMover($this->mockedDbi
, new Relation($this->mockedDbi
));
937 $ret = $object->duplicateInfo('relwork', 'relation', $getFields, $whereFields, $newFields);
938 self
::assertSame(-1, $ret);
942 * Test for isUpdatableView
944 public function testIsUpdatableView(): void
946 $table = new Table('', '', $this->mockedDbi
);
948 $table->isUpdatableView(),
951 //validate that it is the same as DBI fetchResult
952 $table = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
954 $table->isUpdatableView(),
957 $table = new Table('PMA_BookMark_2', 'PMA', $this->mockedDbi
);
959 $table->isUpdatableView(),
964 * Test for isMerge -- when there's no ENGINE info cached
966 public function testIsMergeCase1(): void
968 $tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
970 $tableObj->isMerge(),
975 * Test for isMerge -- when ENGINE info is MERGE
977 public function testIsMergeCase2(): void
979 $this->mockedDbi
->getCache()->cacheTableValue('PMA', 'PMA_BookMark', 'ENGINE', 'MERGE');
981 $tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
983 $tableObj->isMerge(),
988 * Test for isMerge -- when ENGINE info is MRG_MYISAM
990 public function testIsMergeCase3(): void
992 $this->mockedDbi
->getCache()->cacheTableValue('PMA', 'PMA_BookMark', 'ENGINE', 'MRG_MYISAM');
994 $tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
996 $tableObj->isMerge(),
1001 * Test for Table::isMerge -- when ENGINE info is ISDB
1003 public function testIsMergeCase4(): void
1005 $tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi
);
1007 $tableObj->isMerge(),
1012 * Test for generateAlter
1014 public function testGenerateAlter(): void
1018 $newcol = 'new_name';
1021 $attribute = 'new_name';
1022 $collation = 'charset1';
1024 $defaultType = 'USER_DEFINED';
1025 $defaultValue = 'VARCHAR';
1026 $extra = 'AUTO_INCREMENT';
1027 $comment = 'PMA comment';
1030 $moveTo = 'new_name';
1032 $result = Table
::generateAlter(
1049 $expect = '`name` `new_name` VARCHAR(2) new_name CHARACTER SET '
1050 . "charset1 NULL DEFAULT 'VARCHAR' "
1051 . "AUTO_INCREMENT COMMENT 'PMA comment' AFTER `new_name`";
1053 self
::assertSame($expect, $result);
1059 public function testRename(): void
1061 Config
::getInstance()->selectedServer
['DisableIS'] = true;
1063 $table = 'PMA_BookMark';
1066 $this->mockedDbi
->expects(self
::any())->method('tryQuery')->willReturn($this->createMock(DummyResult
::class));
1068 $table = new Table($table, $db, $this->mockedDbi
);
1070 //rename to same name
1071 $tableNew = 'PMA_BookMark';
1072 $result = $table->rename($tableNew);
1073 self
::assertTrue($result);
1076 //space in table name
1077 $tableNew = 'PMA_BookMark ';
1078 $result = $table->rename($tableNew);
1079 self
::assertFalse($result);
1082 $result = $table->rename($tableNew);
1083 self
::assertFalse($result);
1085 $tableNew = 'PMA_.BookMark';
1086 $result = $table->rename($tableNew);
1087 self
::assertTrue($result);
1091 'Table PMA_BookMark has been renamed to PMA_.BookMark.',
1092 $table->getLastMessage(),
1095 $tableNew = 'PMA_BookMark_new';
1097 $result = $table->rename($tableNew, $dbNew);
1098 self
::assertTrue($result);
1101 'Table PMA_.BookMark has been renamed to PMA_BookMark_new.',
1102 $table->getLastMessage(),
1107 * Test for getUniqueColumns
1109 public function testGetUniqueColumns(): void
1111 $table = 'PMA_BookMark';
1114 $table = new Table($table, $db, $this->mockedDbi
);
1115 $return = $table->getUniqueColumns();
1116 $expect = ['`PMA`.`PMA_BookMark`.`index1`', '`PMA`.`PMA_BookMark`.`index3`', '`PMA`.`PMA_BookMark`.`index5`'];
1117 self
::assertSame($expect, $return);
1121 * Test for getIndexedColumns
1123 public function testGetIndexedColumns(): void
1125 $table = 'PMA_BookMark';
1128 $table = new Table($table, $db, $this->mockedDbi
);
1129 $return = $table->getIndexedColumns();
1131 '`PMA`.`PMA_BookMark`.`column1`',
1132 '`PMA`.`PMA_BookMark`.`column3`',
1133 '`PMA`.`PMA_BookMark`.`column5`',
1134 '`PMA`.`PMA_BookMark`.`ACCESSIBLE`',
1135 '`PMA`.`PMA_BookMark`.`ADD`',
1136 '`PMA`.`PMA_BookMark`.`ALL`',
1138 self
::assertSame($expect, $return);
1142 * Test for getColumnsMeta
1144 public function testGetColumnsMeta(): void
1146 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
1147 ->disableOriginalConstructor()
1150 $resultStub = $this->createMock(DummyResult
::class);
1152 $dbi->expects(self
::once())
1153 ->method('tryQuery')
1154 ->with('SELECT * FROM `db`.`table` LIMIT 1')
1155 ->willReturn($resultStub);
1157 $dummyFieldMetadata = FieldHelper
::fromArray(['type' => MYSQLI_TYPE_STRING
]);
1159 $dbi->expects(self
::once())
1160 ->method('getFieldsMeta')
1162 ->willReturn([$dummyFieldMetadata]);
1164 DatabaseInterface
::$instance = $dbi;
1166 $tableObj = new Table('table', 'db', $dbi);
1169 $tableObj->getColumnsMeta(),
1170 [$dummyFieldMetadata],
1175 * Tests for getSQLToCreateForeignKey() method.
1177 public function testGetSQLToCreateForeignKey(): void
1179 $table = 'PMA_table';
1180 $field = ['PMA_field1', 'PMA_field2'];
1181 $foreignDb = 'foreignDb';
1182 $foreignTable = 'foreignTable';
1183 $foreignField = ['foreignField1', 'foreignField2'];
1185 $tableObj = new Table('PMA_table', 'db', $this->mockedDbi
);
1187 $sql = $this->callFunction(
1190 'getSQLToCreateForeignKey',
1191 [$table, $field, $foreignDb, $foreignTable, $foreignField],
1193 $sqlExcepted = 'ALTER TABLE `PMA_table` ADD '
1194 . 'FOREIGN KEY (`PMA_field1`, `PMA_field2`) REFERENCES '
1195 . '`foreignDb`.`foreignTable`(`foreignField1`, `foreignField2`);';
1196 self
::assertSame($sqlExcepted, $sql);
1198 // Exclude db name when relations are made between table in the same db
1199 $sql = $this->callFunction(
1202 'getSQLToCreateForeignKey',
1203 [$table, $field, 'db', $foreignTable, $foreignField],
1205 $sqlExcepted = 'ALTER TABLE `PMA_table` ADD '
1206 . 'FOREIGN KEY (`PMA_field1`, `PMA_field2`) REFERENCES '
1207 . '`foreignTable`(`foreignField1`, `foreignField2`);';
1208 self
::assertSame($sqlExcepted, $sql);
1212 * Test for getColumns
1214 public function testGetColumns(): void
1217 $table = 'PMA_BookMark';
1220 $table = new Table($table, $db, $this->mockedDbi
);
1221 $return = $table->getColumns();
1223 '`PMA`.`PMA_BookMark`.`column1`',
1224 '`PMA`.`PMA_BookMark`.`column3`',
1225 '`PMA`.`PMA_BookMark`.`column5`',
1226 '`PMA`.`PMA_BookMark`.`ACCESSIBLE`',
1227 '`PMA`.`PMA_BookMark`.`ADD`',
1228 '`PMA`.`PMA_BookMark`.`ALL`',
1230 self
::assertSame($expect, $return);
1234 * Test for checkIfMinRecordsExist
1236 public function testCheckIfMinRecordsExist(): void
1238 $oldDbi = $this->mockedDbi
;
1240 $resultStub = $this->createMock(DummyResult
::class);
1242 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
1243 ->disableOriginalConstructor()
1245 $dbi->expects(self
::any())
1246 ->method('tryQuery')
1247 ->willReturn($resultStub);
1248 $resultStub->expects(self
::any())
1250 ->willReturn(0, 10, 200);
1251 $dbi->expects(self
::any())
1252 ->method('fetchResult')
1255 [], // No Uniques found
1256 ['`one_ind`', '`sec_ind`'],
1257 [], // No Uniques found
1258 [], // No Indexed found
1261 DatabaseInterface
::$instance = $dbi;
1263 $table = 'PMA_BookMark';
1265 $tableObj = new Table($table, $db, $dbi);
1267 // Case 1 : Check if table is non-empty
1268 $return = $tableObj->checkIfMinRecordsExist();
1269 self
::assertTrue($return);
1271 // Case 2 : Check if table contains at least 100
1272 $return = $tableObj->checkIfMinRecordsExist(100);
1273 self
::assertFalse($return);
1275 // Case 3 : Check if table contains at least 100
1276 $return = $tableObj->checkIfMinRecordsExist(100);
1277 self
::assertTrue($return);
1279 DatabaseInterface
::$instance = $oldDbi;
1283 * Test for Table::countRecords
1285 public function testCountRecords(): void
1287 $resultStub = $this->createMock(DummyResult
::class);
1288 $resultStub->expects(self
::any())
1292 $dbi = clone $this->mockedDbi
;
1293 $dbi->expects(self
::any())->method('tryQuery')
1294 ->willReturn($resultStub);
1296 $table = 'PMA_BookMark';
1298 $tableObj = new Table($table, $db, $dbi);
1302 $tableObj->countRecords(true),
1307 * Test for setUiProp
1309 public function testSetUiProp(): void
1311 $tableName = 'PMA_BookMark';
1314 $table = new Table($tableName, $db, $this->mockedDbi
);
1316 $property = UiProperty
::ColumnOrder
;
1317 $value = 'UiProp_value';
1318 $tableCreateTime = null;
1319 $table->setUiProp($property, $value, $tableCreateTime);
1321 //set UI prop successfully
1322 self
::assertSame($value, $table->uiprefs
[$property->value
]);
1325 $table->removeUiProp($property);
1326 $isDefineProperty = isset($table->uiprefs
[$property->value
]);
1327 self
::assertFalse($isDefineProperty);
1329 //getUiProp after removeUiProp
1330 $isDefineProperty = $table->getUiProp($property);
1331 self
::assertFalse($isDefineProperty);
1337 public function testMoveCopy(): void
1339 $sourceTable = 'PMA_BookMark';
1341 $targetTable = 'PMA_BookMark_new';
1342 $targetDb = 'PMA_new';
1345 [$targetDb, $targetTable, new Table($targetTable, $targetDb, $this->mockedDbi
)],
1346 ['aa', 'ad', new Table('ad', 'aa', $this->mockedDbi
)],
1349 $this->mockedDbi
->expects(self
::any())->method('getTable')
1350 ->willReturnMap($getTableMap);
1352 $object = new TableMover($this->mockedDbi
, new Relation($this->mockedDbi
));
1354 $return = $object->moveCopy(
1360 MoveMode
::SingleTable
,
1365 self
::assertTrue($return);
1366 $sqlQuery = 'INSERT INTO `PMA_new`.`PMA_BookMark_new`(`COLUMN_NAME1`)'
1367 . ' SELECT `COLUMN_NAME1` FROM '
1368 . '`PMA`.`PMA_BookMark`';
1369 self
::assertStringContainsString($sqlQuery, Current
::$sqlQuery);
1370 $sqlQuery = 'DROP VIEW `PMA`.`PMA_BookMark`';
1371 self
::assertStringContainsString($sqlQuery, Current
::$sqlQuery);
1373 $return = $object->moveCopy(
1378 MoveScope
::DataOnly
,
1379 MoveMode
::SingleTable
,
1384 self
::assertTrue($return);
1385 $sqlQuery = 'INSERT INTO `PMA_new`.`PMA_BookMark_new`(`COLUMN_NAME1`)'
1386 . ' SELECT `COLUMN_NAME1` FROM '
1387 . '`PMA`.`PMA_BookMark`';
1388 self
::assertStringContainsString($sqlQuery, Current
::$sqlQuery);
1389 $sqlQuery = 'DROP VIEW `PMA`.`PMA_BookMark`';
1390 self
::assertStringNotContainsString($sqlQuery, Current
::$sqlQuery);
1392 // Renaming DB with a view bug
1393 $resultStub = $this->createMock(DummyResult
::class);
1394 $this->mockedDbi
->expects(self
::any())->method('tryQuery')
1397 'SHOW CREATE TABLE `aa`.`ad`',
1398 ConnectionType
::User
,
1404 'SHOW TABLE STATUS FROM `aa` WHERE Name = \'ad\'',
1405 ConnectionType
::User
,
1410 ['USE `aa`', ConnectionType
::User
, false, true, $resultStub],
1412 'RENAME TABLE `PMA`.`PMA_BookMark` TO `PMA`.`PMA_.BookMark`;',
1413 ConnectionType
::User
,
1419 'RENAME TABLE `aa`.`ad` TO `bb`.`ad`;',
1420 ConnectionType
::User
,
1426 $resultStub->expects(self
::any())
1427 ->method('fetchRow')
1430 'CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost`' .
1431 ' SQL SECURITY DEFINER VIEW `ad` AS select `aa`.`bb`.`ac` AS `ac` from `bb`',
1433 'utf8mb4_unicode_ci',
1436 Current
::$sqlQuery = '';
1437 $return = $object->moveCopy('aa', 'ad', 'bb', 'ad', MoveScope
::Move
, MoveMode
::WholeDatabase
, true);
1438 self
::assertTrue($return);
1439 self
::assertStringContainsString('DROP TABLE IF EXISTS `bb`.`ad`;', Current
::$sqlQuery);
1440 self
::assertStringContainsString(
1441 'CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost`' .
1442 ' SQL SECURITY DEFINER VIEW `bb`.`ad` AS SELECT `bb`.`ac` AS `ac` FROM `bb` ;',
1445 self
::assertStringContainsString('DROP VIEW `aa`.`ad`;', Current
::$sqlQuery);
1449 * Test for getStorageEngine
1451 public function testGetStorageEngine(): void
1453 $targetTable = 'table1';
1454 $targetDb = 'pma_test';
1455 $extension = new DbiDummy();
1456 $dbi = DatabaseInterface
::getInstanceForTest($extension);
1457 $tblObject = new Table($targetTable, $targetDb, $dbi);
1458 $tblObject->getStatusInfo(null);
1459 $expect = 'DBIDUMMY';
1460 $tblStorageEngine = $dbi->getTable($targetDb, $targetTable)->getStorageEngine();
1461 self
::assertSame($expect, $tblStorageEngine);
1465 * Test for getComment
1467 public function testGetComment(): void
1469 $targetTable = 'table1';
1470 $targetDb = 'pma_test';
1471 $extension = new DbiDummy();
1472 $dbi = DatabaseInterface
::getInstanceForTest($extension);
1473 $tblObject = new Table($targetTable, $targetDb, $dbi);
1474 $tblObject->getStatusInfo(null);
1475 $expect = 'Test comment for "table1" in \'pma_test\'';
1476 $showComment = $dbi->getTable($targetDb, $targetTable)->getComment();
1477 self
::assertSame($expect, $showComment);
1481 * Test for getCollation
1483 public function testGetCollation(): void
1485 $targetTable = 'table1';
1486 $targetDb = 'pma_test';
1487 $extension = new DbiDummy();
1488 $dbi = DatabaseInterface
::getInstanceForTest($extension);
1489 $tblObject = new Table($targetTable, $targetDb, $dbi);
1490 $tblObject->getStatusInfo(null);
1491 $expect = 'utf8mb4_general_ci';
1492 $tblCollation = $dbi->getTable($targetDb, $targetTable)->getCollation();
1493 self
::assertSame($expect, $tblCollation);
1497 * Test for getRowFormat
1499 public function testGetRowFormat(): void
1501 $targetTable = 'table1';
1502 $targetDb = 'pma_test';
1503 $extension = new DbiDummy();
1504 $dbi = DatabaseInterface
::getInstanceForTest($extension);
1505 $tblObject = new Table($targetTable, $targetDb, $dbi);
1506 $tblObject->getStatusInfo(null);
1507 $expect = 'Redundant';
1508 $rowFormat = $dbi->getTable($targetDb, $targetTable)->getRowFormat();
1509 self
::assertSame($expect, $rowFormat);
1513 * Test for getAutoIncrement
1515 public function testGetAutoIncrement(): void
1517 $targetTable = 'table1';
1518 $targetDb = 'pma_test';
1519 $extension = new DbiDummy();
1520 $dbi = DatabaseInterface
::getInstanceForTest($extension);
1521 $tblObject = new Table($targetTable, $targetDb, $dbi);
1522 $tblObject->getStatusInfo(null);
1524 $autoIncrement = $dbi->getTable($targetDb, $targetTable)->getAutoIncrement();
1525 self
::assertSame($expect, $autoIncrement);
1529 * Test for getCreateOptions
1531 public function testGetCreateOptions(): void
1533 $targetTable = 'table1';
1534 $targetDb = 'pma_test';
1535 $extension = new DbiDummy();
1536 $dbi = DatabaseInterface
::getInstanceForTest($extension);
1537 $tblObject = new Table($targetTable, $targetDb, $dbi);
1538 $tblObject->getStatusInfo(null);
1539 $expect = ['pack_keys' => 'DEFAULT', 'row_format' => 'REDUNDANT'];
1540 $createOptions = $dbi->getTable($targetDb, $targetTable)->getCreateOptions();
1541 self
::assertEquals($expect, $createOptions);