setTheme(); $GLOBALS['server'] = 0; $GLOBALS['db'] = 'db'; $GLOBALS['table'] = 'table'; $GLOBALS['PMA_PHP_SELF'] = 'index.php'; $this->object = new DisplayResults($this->dbi, 'as', '', 0, '', ''); $GLOBALS['text_dir'] = 'ltr'; $GLOBALS['cfg']['Server']['DisableIS'] = false; $_SESSION[' HMAC_secret '] = 'test'; } /** * Tears down the fixture, for example, closes a network connection. * This method is called after a test is executed. */ protected function tearDown(): void { parent::tearDown(); unset($this->object); } /** * Test for isSelect function */ public function testisSelect(): void { $parser = new Parser('SELECT * FROM pma'); $this->assertTrue( $this->callFunction( $this->object, DisplayResults::class, 'isSelect', [ [ 'statement' => $parser->statements[0], 'select_from' => true, ], ] ) ); } public function testGetClassForDateTimeRelatedFieldsCase1(): void { $this->assertEquals( 'datetimefield', $this->callFunction( $this->object, DisplayResults::class, 'getClassForDateTimeRelatedFields', [new FieldMetadata(MYSQLI_TYPE_TIMESTAMP, 0, (object) [])] ) ); } public function testGetClassForDateTimeRelatedFieldsCase2(): void { $this->assertEquals( 'datefield', $this->callFunction( $this->object, DisplayResults::class, 'getClassForDateTimeRelatedFields', [new FieldMetadata(MYSQLI_TYPE_DATE, 0, (object) [])] ) ); } public function testGetClassForDateTimeRelatedFieldsCase3(): void { $this->assertEquals( 'text', $this->callFunction( $this->object, DisplayResults::class, 'getClassForDateTimeRelatedFields', [new FieldMetadata(MYSQLI_TYPE_STRING, 0, (object) [])] ) ); } /** * Test for getOffsets - case 1 */ public function testGetOffsetsCase1(): void { $_SESSION['tmpval']['max_rows'] = DisplayResults::ALL_ROWS; $this->assertEquals( [ 0, 0, ], $this->callFunction( $this->object, DisplayResults::class, 'getOffsets', [] ) ); } /** * Test for getOffsets - case 2 */ public function testGetOffsetsCase2(): void { $_SESSION['tmpval']['max_rows'] = 5; $_SESSION['tmpval']['pos'] = 4; $this->assertEquals( [ 9, 0, ], $this->callFunction( $this->object, DisplayResults::class, 'getOffsets', [] ) ); } /** * Data provider for testGetSpecialLinkUrl * * @return array parameters and output */ public function dataProviderForTestGetSpecialLinkUrl(): array { return [ [ 'information_schema', 'routines', 'circumference', [ 'routine_name' => 'circumference', 'routine_schema' => 'data', 'routine_type' => 'FUNCTION', ], 'routine_name', 'index.php?route=/database/routines&item_name=circumference&db=data' . '&item_type=FUNCTION&server=0&lang=en', ], [ 'information_schema', 'routines', 'area', [ 'routine_name' => 'area', 'routine_schema' => 'data', 'routine_type' => 'PROCEDURE', ], 'routine_name', 'index.php?route=/database/routines&item_name=area&db=data&item_type=PROCEDURE&server=0&lang=en', ], ]; } /** * Test getSpecialLinkUrl * * @param string $db the database name * @param string $table the table name * @param string $column_value column value * @param array $row_info information about row * @param string $field_name column name * @param string $output output of getSpecialLinkUrl * * @dataProvider dataProviderForTestGetSpecialLinkUrl */ public function testGetSpecialLinkUrl( string $db, string $table, string $column_value, array $row_info, string $field_name, string $output ): void { $specialSchemaLinks = [ 'information_schema' => [ 'routines' => [ 'routine_name' => [ 'link_param' => 'item_name', 'link_dependancy_params' => [ 0 => [ 'param_info' => 'db', 'column_name' => 'routine_schema', ], 1 => [ 'param_info' => 'item_type', 'column_name' => 'routine_type', ], ], 'default_page' => 'index.php?route=/database/routines', ], ], 'columns' => [ 'column_name' => [ 'link_param' => 'table_schema', 'link_dependancy_params' => [ 0 => [ 'param_info' => 'db', 'column_name' => 'table_schema', ], 1 => [ 'param_info' => 'db2', 'column_name' => 'table_schema', ], ], 'default_page' => 'index.php', ], ], ], ]; $this->assertEquals( $output, $this->callFunction( $this->object, DisplayResults::class, 'getSpecialLinkUrl', [ $specialSchemaLinks[$db][$table][$field_name], $column_value, $row_info, ] ) ); } /** * Data provider for testGetRowInfoForSpecialLinks * * @return array parameters and output */ public function dataProviderForTestGetRowInfoForSpecialLinks(): array { $column_names = [ 'host', 'db', 'user', 'select_privilages', ]; $fields_mata = []; foreach ($column_names as $column_name) { $field_meta = new stdClass(); $field_meta->orgname = $column_name; $fields_mata[] = $field_meta; } return [ [ $fields_mata, count($fields_mata), [ 0 => 'localhost', 1 => 'phpmyadmin', 2 => 'pmauser', 3 => 'Y', ], [ 0 => '0', 1 => '3', 2 => '1', 3 => '2', ], [ 'host' => 'localhost', 'select_privilages' => 'Y', 'db' => 'phpmyadmin', 'user' => 'pmauser', ], ], ]; } /** * Test getRowInfoForSpecialLinks * * @param FieldMetadata[] $fields_meta meta information about fields * @param int $fields_count number of fields * @param array $row current row data * @param array $col_order the column order * @param array $output output of getRowInfoForSpecialLinks * * @dataProvider dataProviderForTestGetRowInfoForSpecialLinks */ public function testGetRowInfoForSpecialLinks( array $fields_meta, int $fields_count, array $row, array $col_order, array $output ): void { $this->object->properties['fields_meta'] = $fields_meta; $this->object->properties['fields_cnt'] = $fields_count; $this->assertEquals( $output, $this->callFunction( $this->object, DisplayResults::class, 'getRowInfoForSpecialLinks', [ $row, $col_order, ] ) ); } /** * Data provider for testSetHighlightedColumnGlobalField * * @return array parameters and output */ public function dataProviderForTestSetHighlightedColumnGlobalField(): array { $parser = new Parser('SELECT * FROM db_name WHERE `db_name`.`tbl`.id > 0 AND `id` < 10'); return [ [ ['statement' => $parser->statements[0]], [ 'db_name' => 'true', 'tbl' => 'true', 'id' => 'true', ], ], ]; } /** * Test setHighlightedColumnGlobalField * * @param array $analyzed_sql the analyzed query * @param array $output setting value of setHighlightedColumnGlobalField * * @dataProvider dataProviderForTestSetHighlightedColumnGlobalField */ public function testSetHighlightedColumnGlobalField(array $analyzed_sql, array $output): void { $this->callFunction( $this->object, DisplayResults::class, 'setHighlightedColumnGlobalField', [$analyzed_sql] ); $this->assertEquals($output, $this->object->properties['highlight_columns']); } /** * Data provider for testGetPartialText * * @return array parameters and output */ public function dataProviderForTestGetPartialText(): array { return [ [ 'P', 10, 'foo', [ false, 'foo', 3, ], ], [ 'P', 1, 'foo', [ true, 'f...', 3, ], ], [ 'F', 10, 'foo', [ false, 'foo', 3, ], ], [ 'F', 1, 'foo', [ false, 'foo', 3, ], ], ]; } /** * Test getPartialText * * @param string $pftext Partial or Full text * @param int $limitChars Partial or Full text * @param string $str the string to be tested * @param array $output return value of getPartialText * * @dataProvider dataProviderForTestGetPartialText */ public function testGetPartialText(string $pftext, int $limitChars, string $str, array $output): void { $_SESSION['tmpval']['pftext'] = $pftext; $GLOBALS['cfg']['LimitChars'] = $limitChars; $this->assertEquals( $output, $this->callFunction( $this->object, DisplayResults::class, 'getPartialText', [$str] ) ); } /** * @return mixed[][] * @psalm-return array{array{ * bool, * bool, * string, * string|null, * TransformationsPlugin|null, * array|object, * object, * array, * bool|null, * string * }} */ public function dataProviderForTestHandleNonPrintableContents(): array { $transformation_plugin = new Text_Plain_Link(); $meta = new FieldMetadata(MYSQLI_TYPE_BLOB, 0, (object) ['orgtable' => 'bar']); $url_params = [ 'db' => 'foo', 'table' => 'bar', 'where_clause' => 'where_clause', ]; return [ [ true, true, 'BLOB', '1001', null, [], $meta, $url_params, null, 'class="disableAjax">1001', ], [ true, true, 'BLOB', hex2bin('123456'), null, [], $meta, $url_params, null, 'class="disableAjax">0x123456', ], [ true, false, 'BLOB', '1001', null, [], $meta, $url_params, null, 'class="disableAjax">[BLOB - 4 B]', ], [ false, false, 'BINARY', '1001', $transformation_plugin, [], $meta, $url_params, null, '1001', ], [ false, true, 'GEOMETRY', null, null, [], $meta, $url_params, null, '[GEOMETRY - NULL]', ], ]; } /** * @param bool $display_binary show binary contents? * @param bool $display_blob show blob contents? * @param string $category BLOB|BINARY|GEOMETRY * @param string|null $content the binary content * @param array|object $transform_options transformation parameters * @param object $meta the meta-information about the field * @param array $url_params parameters that should go to the download link * @param bool|null $is_truncated the result is truncated or not * @param string $output the output of this function * * @dataProvider dataProviderForTestHandleNonPrintableContents */ public function testHandleNonPrintableContents( bool $display_binary, bool $display_blob, string $category, ?string $content, ?TransformationsPlugin $transformation_plugin, $transform_options, object $meta, array $url_params, ?bool $is_truncated, string $output ): void { $_SESSION['tmpval']['display_binary'] = $display_binary; $_SESSION['tmpval']['display_blob'] = $display_blob; $GLOBALS['cfg']['LimitChars'] = 50; $this->assertStringContainsString( $output, $this->callFunction( $this->object, DisplayResults::class, 'handleNonPrintableContents', [ $category, $content, $transformation_plugin, $transform_options, $meta, $url_params, &$is_truncated, ] ) ); } /** * @return mixed[][] * @psalm-return array{array{ * string, * string|null, * string, * object, * array, * array, * bool, * TransformationsPlugin|null, * array, * array, * string * }} */ public function dataProviderForTestGetDataCellForNonNumericColumns(): array { $transformation_plugin = new Text_Plain_Link(); $transformation_plugin_external = new Text_Plain_External(); $meta = new stdClass(); $meta->db = 'foo'; $meta->table = 'tbl'; $meta->orgtable = 'tbl'; $meta->name = 'tblob'; $meta->orgname = 'tblob'; $meta->charsetnr = 63; $meta = new FieldMetadata(MYSQLI_TYPE_BLOB, 0, $meta); $meta2 = new stdClass(); $meta2->db = 'foo'; $meta2->table = 'tbl'; $meta2->orgtable = 'tbl'; $meta2->name = 'varchar'; $meta2->orgname = 'varchar'; $meta2 = new FieldMetadata(MYSQLI_TYPE_STRING, 0, $meta2); $meta3 = new stdClass(); $meta3->db = 'foo'; $meta3->table = 'tbl'; $meta3->orgtable = 'tbl'; $meta3->name = 'datetime'; $meta3->orgname = 'datetime'; $meta3 = new FieldMetadata(MYSQLI_TYPE_DATETIME, 0, $meta3); $url_params = [ 'db' => 'foo', 'table' => 'tbl', 'where_clause' => 'where_clause', ]; return [ [ 'all', '1001', 'grid_edit', $meta, [], $url_params, false, null, ['https://www.example.com/'], [], 'class="disableAjax">[BLOB - 4 B]' . '' . "\n", ], [ 'noblob', '1001', 'grid_edit', $meta, [], $url_params, false, $transformation_plugin, [], [], '' . '1001' . '' . "\n", ], [ 'noblob', null, 'grid_edit', $meta2, [], $url_params, false, $transformation_plugin, [], [], '' . "\n" . ' NULL' . "\n" . '' . "\n", ], [ 'all', 'foo bar baz', 'grid_edit', $meta2, [], $url_params, false, null, [], [], 'foo bar baz' . "\n", ], [ 'all', 'foo bar baz', 'grid_edit', $meta2, [], $url_params, false, $transformation_plugin_external, [], [], 'foo bar baz' . "\n", ], [ 'all', '2020-09-20 16:35:00', 'grid_edit', $meta3, [], $url_params, false, null, [], [], '2020-09-20 16:35:00' . "\n", ], ]; } /** * @param string $protectBinary all|blob|noblob|no * @param string|null $column the relevant column in data row * @param string $class the html class for column * @param object $meta the meta-information about the field * @param array $map the list of relations * @param array $_url_params the parameters for generate url * @param bool $condition_field the column should highlighted or not * @param array $transform_options the transformation parameters * @param array $analyzed_sql_results the analyzed query * @param string $output the output of this function * * @dataProvider dataProviderForTestGetDataCellForNonNumericColumns */ public function testGetDataCellForNonNumericColumns( string $protectBinary, ?string $column, string $class, object $meta, array $map, array $_url_params, bool $condition_field, ?TransformationsPlugin $transformation_plugin, array $transform_options, array $analyzed_sql_results, string $output ): void { $_SESSION['tmpval']['display_binary'] = true; $_SESSION['tmpval']['display_blob'] = false; $_SESSION['tmpval']['relational_display'] = false; $GLOBALS['cfg']['LimitChars'] = 50; $GLOBALS['cfg']['ProtectBinary'] = $protectBinary; $this->assertStringContainsString( $output, $this->callFunction( $this->object, DisplayResults::class, 'getDataCellForNonNumericColumns', [ $column, $class, $meta, $map, $_url_params, $condition_field, $transformation_plugin, $transform_options, $analyzed_sql_results, ] ) ); } /** * Simple output transformation test * * It mocks data needed to display two transformations and asserts * they are rendered. */ public function testOutputTransformations(): void { // Fake relation settings $_SESSION['tmpval']['relational_display'] = 'K'; $_SESSION['relation'] = []; $_SESSION['relation'][$GLOBALS['server']] = RelationParameters::fromArray([ 'db' => 'db', 'mimework' => true, 'column_info' => 'column_info', ])->toArray(); $GLOBALS['cfg']['BrowseMIME'] = true; // Basic data $query = 'SELECT 1'; $this->object->properties['db'] = 'db'; $this->object->properties['fields_cnt'] = 2; // Field meta information $meta = new stdClass(); $meta->db = 'db'; $meta->table = 'table'; $meta->orgtable = 'table'; $meta->name = '1'; $meta->orgname = '1'; $meta->blob = false; $meta2 = new stdClass(); $meta2->db = 'db'; $meta2->table = 'table'; $meta2->orgtable = 'table'; $meta2->name = '2'; $meta2->orgname = '2'; $meta2->blob = false; $fields_meta = [ new FieldMetadata(MYSQLI_TYPE_LONG, MYSQLI_NUM_FLAG | MYSQLI_NOT_NULL_FLAG, $meta), new FieldMetadata(MYSQLI_TYPE_LONG, MYSQLI_NUM_FLAG | MYSQLI_NOT_NULL_FLAG, $meta2), ]; $this->object->properties['fields_meta'] = $fields_meta; $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); // MIME transformations $dbi->expects($this->exactly(1)) ->method('fetchResult') ->willReturn( [ 'db.table.1' => [ 'mimetype' => '', 'transformation' => 'output/text_plain_dateformat.php', ], 'db.table.2' => [ 'mimetype' => '', 'transformation' => 'output/text_plain_bool2text.php', ], ] ); $GLOBALS['dbi'] = $dbi; $transformations = new Transformations(); $this->object->properties['mime_map'] = $transformations->getMime('db', 'table'); // Actually invoke tested method $output = $this->callFunction( $this->object, DisplayResults::class, 'getRowValues', [ [ 3600, true, ], 0, false, [], 'disabled', false, $query, Query::getAll($query), ] ); // Dateformat $this->assertStringContainsString('Jan 01, 1970 at 01:00 AM', $output); // Bool2Text $this->assertStringContainsString('>T<', $output); } public function dataProviderGetSortOrderHiddenInputs(): array { // SQL to add the column // SQL to remove the column // The URL params // The column name return [ [ '', '', ['sql_query' => ''], 'colname', '', ], [ 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC, `gis_all`.`name` ASC', 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`name` ASC', ['sql_query' => 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC, `gis_all`.`name` ASC'], 'shape', '', ], [ 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC, `gis_all`.`name` ASC', 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC', ['sql_query' => 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC, `gis_all`.`name` ASC'], 'name', '', ], [ 'SELECT * FROM `gis_all`', 'SELECT * FROM `gis_all`', ['sql_query' => 'SELECT * FROM `gis_all`'], 'name', '', ], [ 'SELECT * FROM `gd_cities` ORDER BY `gd_cities`.`region_slug` DESC, ' . '`gd_cities`.`country_slug` ASC, `gd_cities`.`city_id` ASC, `gd_cities`.`city` ASC', 'SELECT * FROM `gd_cities` ORDER BY `gd_cities`.`region_slug` DESC, ' . '`gd_cities`.`country_slug` ASC, `gd_cities`.`city_id` ASC, `gd_cities`.`city` ASC', [ 'sql_query' => 'SELECT * FROM `gd_cities` ORDER BY `gd_cities`.`region_slug` DESC, ' . '`gd_cities`.`country_slug` ASC, `gd_cities`.`city_id` ASC, `gd_cities`.`city` ASC', ], '', '', ], [ 'SELECT * FROM `gd_cities` ORDER BY `gd_cities`.`region_slug` DESC, ' . '`gd_cities`.`country_slug` ASC, `gd_cities`.`city_id` ASC, `gd_cities`.`city` ASC', 'SELECT * FROM `gd_cities` ORDER BY `gd_cities`.`country_slug` ASC, `gd_cities`.`city_id`' . ' ASC, `gd_cities`.`city` ASC', [ 'sql_query' => 'SELECT * FROM `gd_cities` ORDER BY `gd_cities`.`region_slug` DESC, ' . '`gd_cities`.`country_slug` ASC, `gd_cities`.`city_id` ASC, `gd_cities`.`city` ASC', ], 'region_slug', '', ], [ 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC', 'SELECT * FROM `gis_all`', ['sql_query' => 'SELECT * FROM `gis_all` ORDER BY `gis_all`.`shape` DESC'], 'shape', '&discard_remembered_sort=1', ], ]; } /** * @dataProvider dataProviderGetSortOrderHiddenInputs */ public function testGetSortOrderHiddenInputs( string $sqlAdd, string $sqlRemove, array $urlParams, string $colName, string $urlParamsRemove ): void { $output = $this->callFunction( $this->object, DisplayResults::class, 'getSortOrderHiddenInputs', [ $urlParams, $colName, ] ); $out = urldecode(htmlspecialchars_decode($output)); $this->assertStringContainsString( 'name="url-remove-order" value="index.php?route=/sql&sql_query=' . $sqlRemove, $out, 'The remove query should be found' ); $this->assertStringContainsString( 'name="url-add-order" value="index.php?route=/sql&sql_query=' . $sqlAdd, $out, 'The add query should be found' ); $firstLine = explode("\n", $out)[0] ?? ''; $this->assertStringContainsString( 'url-remove-order', $firstLine, 'The first line should contain url-remove-order input' ); $this->assertStringNotContainsString( 'url-add-order', $firstLine, 'The first line should contain NOT url-add-order input' ); $this->assertStringContainsString($urlParamsRemove, $firstLine, 'The first line should contain the URL params'); } /** * @see https://github.com/phpmyadmin/phpmyadmin/issues/16836 */ public function testBuildValueDisplayNoTrainlingSpaces(): void { $output = $this->callFunction( $this->object, DisplayResults::class, 'buildValueDisplay', [ 'my_class', false, ' special value ', ] ); $this->assertSame(' special value ' . "\n", $output); $output = $this->callFunction( $this->object, DisplayResults::class, 'buildValueDisplay', [ 'my_class', false, '0x11e6ac0cfb1e8bf3bf48b827ebdafb0b', ] ); $this->assertSame('0x11e6ac0cfb1e8bf3bf48b827ebdafb0b' . "\n", $output); $output = $this->callFunction( $this->object, DisplayResults::class, 'buildValueDisplay', [ 'my_class', true,// condition mode '0x11e6ac0cfb1e8bf3bf48b827ebdafb0b', ] ); $this->assertSame( '0x11e6ac0cfb1e8bf3bf48b827ebdafb0b' . "\n", $output ); } /** * @dataProvider providerSetConfigParamsForDisplayTable */ public function testSetConfigParamsForDisplayTable( array $session, array $get, array $post, array $request, array $expected ): void { $_SESSION = $session; $_GET = $get; $_POST = $post; $_REQUEST = $request; $db = 'test_db'; $table = 'test_table'; $query = 'SELECT * FROM `test_db`.`test_table`;'; $object = new DisplayResults($this->dbi, $db, $table, 1, '', $query); $object->setConfigParamsForDisplayTable(); $this->assertArrayHasKey('tmpval', $_SESSION); $this->assertIsArray($_SESSION['tmpval']); $this->assertSame($expected, $_SESSION['tmpval']); } public function providerSetConfigParamsForDisplayTable(): array { $cfg = ['RelationalDisplay' => DisplayResults::RELATIONAL_KEY, 'MaxRows' => 25, 'RepeatCells' => 100]; return [ 'default values' => [ [], [], [], [], [ 'query' => [ '27b1330f2076ef45d236f20839a92831' => [ 'sql' => 'SELECT * FROM `test_db`.`test_table`;', 'repeat_cells' => $cfg['RepeatCells'], 'max_rows' => $cfg['MaxRows'], 'pos' => 0, 'pftext' => DisplayResults::DISPLAY_PARTIAL_TEXT, 'relational_display' => $cfg['RelationalDisplay'], 'geoOption' => DisplayResults::GEOMETRY_DISP_GEOM, 'display_binary' => true, ], ], 'pftext' => DisplayResults::DISPLAY_PARTIAL_TEXT, 'relational_display' => $cfg['RelationalDisplay'], 'geoOption' => DisplayResults::GEOMETRY_DISP_GEOM, 'display_binary' => true, 'display_blob' => false, 'hide_transformation' => false, 'pos' => 0, 'max_rows' => $cfg['MaxRows'], 'repeat_cells' => $cfg['RepeatCells'], ], ], 'cached values' => [ [ 'tmpval' => [ 'query' => [ '27b1330f2076ef45d236f20839a92831' => [ 'sql' => 'SELECT * FROM `test_db`.`test_table`;', 'repeat_cells' => 90, 'max_rows' => 26, 'pos' => 1, 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKB, 'display_binary' => false, ], 'a' => [], 'b' => [], 'c' => [], 'd' => [], 'e' => [], 'f' => [], 'g' => [], 'h' => [], 'i' => [], 'j' => [], ], ], ], [], [], [], [ 'query' => [ 'b' => [], 'c' => [], 'd' => [], 'e' => [], 'f' => [], 'g' => [], 'h' => [], 'i' => [], 'j' => [], '27b1330f2076ef45d236f20839a92831' => [ 'sql' => 'SELECT * FROM `test_db`.`test_table`;', 'repeat_cells' => 90, 'max_rows' => 26, 'pos' => 1, 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKB, 'display_binary' => true, ], ], 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKB, 'display_binary' => true, 'display_blob' => false, 'hide_transformation' => false, 'pos' => 1, 'max_rows' => 26, 'repeat_cells' => 90, ], ], 'default and request values' => [ [], ['session_max_rows' => '27'], ['session_max_rows' => '28'], [ 'pos' => '2', 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKT, 'display_binary' => '0', 'display_blob' => '0', 'hide_transformation' => '0', ], [ 'query' => [ '27b1330f2076ef45d236f20839a92831' => [ 'sql' => 'SELECT * FROM `test_db`.`test_table`;', 'repeat_cells' => $cfg['RepeatCells'], 'max_rows' => 27, 'pos' => 2, 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKT, 'display_binary' => true, 'display_blob' => true, 'hide_transformation' => true, ], ], 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKT, 'display_binary' => true, 'display_blob' => true, 'hide_transformation' => true, 'pos' => 2, 'max_rows' => 27, 'repeat_cells' => $cfg['RepeatCells'], ], ], 'cached and request values' => [ [ 'tmpval' => [ 'query' => [ '27b1330f2076ef45d236f20839a92831' => [ 'sql' => 'SELECT * FROM `test_db`.`test_table`;', 'repeat_cells' => $cfg['RepeatCells'], 'max_rows' => $cfg['MaxRows'], 'pos' => 0, 'pftext' => DisplayResults::DISPLAY_FULL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_DISPLAY_COLUMN, 'geoOption' => DisplayResults::GEOMETRY_DISP_GEOM, 'display_binary' => true, ], 'a' => [], 'b' => [], 'c' => [], 'd' => [], 'e' => [], 'f' => [], 'g' => [], 'h' => [], 'i' => [], ], ], ], [], ['session_max_rows' => DisplayResults::ALL_ROWS], [ 'pos' => 'NaN', 'pftext' => DisplayResults::DISPLAY_PARTIAL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_KEY, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKB, 'display_options_form' => '0', ], [ 'query' => [ 'a' => [], 'b' => [], 'c' => [], 'd' => [], 'e' => [], 'f' => [], 'g' => [], 'h' => [], 'i' => [], '27b1330f2076ef45d236f20839a92831' => [ 'sql' => 'SELECT * FROM `test_db`.`test_table`;', 'repeat_cells' => $cfg['RepeatCells'], 'max_rows' => DisplayResults::ALL_ROWS, 'pos' => 0, 'pftext' => DisplayResults::DISPLAY_PARTIAL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_KEY, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKB, ], ], 'pftext' => DisplayResults::DISPLAY_PARTIAL_TEXT, 'relational_display' => DisplayResults::RELATIONAL_KEY, 'geoOption' => DisplayResults::GEOMETRY_DISP_WKB, 'display_binary' => false, 'display_blob' => false, 'hide_transformation' => false, 'pos' => 0, 'max_rows' => DisplayResults::ALL_ROWS, 'repeat_cells' => $cfg['RepeatCells'], ], ], ]; } public function testGetTable(): void { $GLOBALS['cfg']['Server']['DisableIS'] = true; $GLOBALS['db'] = 'test_db'; $GLOBALS['table'] = 'test_table'; $query = 'SELECT * FROM `test_db`.`test_table`;'; $object = new DisplayResults($this->dbi, $GLOBALS['db'], $GLOBALS['table'], 1, '', $query); $object->properties['unique_id'] = 1234567890; [$analyzedSqlResults] = ParseAnalyze::sqlQuery($query, $GLOBALS['db']); $fieldsMeta = [ new FieldMetadata( MYSQLI_TYPE_DECIMAL, MYSQLI_PRI_KEY_FLAG | MYSQLI_NUM_FLAG | MYSQLI_NOT_NULL_FLAG, (object) ['name' => 'id'] ), new FieldMetadata(MYSQLI_TYPE_STRING, MYSQLI_NOT_NULL_FLAG, (object) ['name' => 'name']), new FieldMetadata(MYSQLI_TYPE_DATETIME, MYSQLI_NOT_NULL_FLAG, (object) ['name' => 'datetimefield']), ]; $object->setProperties( 3, $fieldsMeta, $analyzedSqlResults['is_count'], $analyzedSqlResults['is_export'], $analyzedSqlResults['is_func'], $analyzedSqlResults['is_analyse'], 3, count($fieldsMeta), 1.234, 'ltr', $analyzedSqlResults['is_maint'], $analyzedSqlResults['is_explain'], $analyzedSqlResults['is_show'], null, null, true, false ); $_SESSION = ['tmpval' => [], ' PMA_token ' => 'token']; $_SESSION['tmpval']['geoOption'] = ''; $_SESSION['tmpval']['hide_transformation'] = ''; $_SESSION['tmpval']['display_blob'] = ''; $_SESSION['tmpval']['display_binary'] = ''; $_SESSION['tmpval']['relational_display'] = ''; $_SESSION['tmpval']['possible_as_geometry'] = ''; $_SESSION['tmpval']['pftext'] = ''; $_SESSION['tmpval']['max_rows'] = 25; $_SESSION['tmpval']['pos'] = 0; $_SESSION['tmpval']['repeat_cells'] = 0; $_SESSION['tmpval']['query']['27b1330f2076ef45d236f20839a92831']['max_rows'] = 25; $dtResult = $this->dbi->tryQuery($query); $displayParts = DisplayParts::fromArray([ 'hasEditLink' => true, 'deleteLink' => DisplayParts::DELETE_ROW, 'hasSortLink' => true, 'hasNavigationBar' => true, 'hasBookmarkForm' => true, 'hasTextButton' => false, 'hasPrintLink' => true, ]); $this->assertNotFalse($dtResult); $actual = $object->getTable($dtResult, $displayParts, $analyzedSqlResults); $template = new Template(); $tableHeadersForColumns = $template->render('display/results/table_headers_for_columns', [ 'is_sortable' => true, 'columns' => [ [ 'column_name' => 'id', 'order_link' => 'id' . '' . '' . "\n" . '', 'comments' => '', 'is_browse_pointer_enabled' => true, 'is_browse_marker_enabled' => true, 'is_column_hidden' => false, 'is_column_numeric' => true, ], [ 'column_name' => 'name', 'order_link' => 'name' . '' . '' . "\n" . '', 'comments' => '', 'is_browse_pointer_enabled' => true, 'is_browse_marker_enabled' => true, 'is_column_hidden' => false, 'is_column_numeric' => false, ], [ 'column_name' => 'datetimefield', 'order_link' => 'datetimefield' . '' . '' . "\n" . '', 'comments' => '', 'is_browse_pointer_enabled' => true, 'is_browse_marker_enabled' => true, 'is_column_hidden' => false, 'is_column_numeric' => false, ], ], ]); $tableTemplate = $template->render('display/results/table', [ 'sql_query_message' => Generator::getMessage( Message::success('Showing rows 0 - 2 (3 total, Query took 1.2340 seconds.)'), $query, 'success' ), 'navigation' => [ 'page_selector' => '', 'number_total_page' => 1, 'has_show_all' => true, 'hidden_fields' => [ 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'server' => 1, 'sql_query' => $query, 'is_browse_distinct' => false, 'goto' => '', ], 'session_max_rows' => 'all', 'is_showing_all' => false, 'max_rows' => 25, 'pos' => 0, 'sort_by_key' => [ 'hidden_fields' => [ 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'server' => 1, 'sort_by_key' => '1', 'session_max_rows' => 25, ], 'options' => [ [ 'value' => 'SELECT * FROM `test_db`.`test_table` ORDER BY `id` ASC', 'content' => 'PRIMARY (ASC)', 'is_selected' => false, ], [ 'value' => 'SELECT * FROM `test_db`.`test_table` ORDER BY `id` DESC', 'content' => 'PRIMARY (DESC)', 'is_selected' => false, ], [ 'value' => 'SELECT * FROM `test_db`.`test_table` ', 'content' => 'None', 'is_selected' => true, ], ], ], 'is_last_page' => true, ], 'headers' => [ 'column_order' => [ 'order' => false, 'visibility' => false, 'is_view' => false, 'table_create_time' => '', ], 'options' => '$optionsBlock', 'has_bulk_actions_form' => false, 'button' => '' . "\n", 'table_headers_for_columns' => $tableHeadersForColumns, 'column_at_right_side' => "\n" . '', ], 'body' => '1' . "\n" . 'abcd' . "\n" . '2011-01-20 02:00:02' . "\n" . '' . "\n" . '2' . "\n" . 'foo' . "\n" . '2010-01-20 02:00:02' . "\n" . '' . "\n" . '3' . "\n" . 'Abcd' . "\n" . '2012-01-20 02:00:02' . "\n" . '' . "\n", 'bulk_links' => [], 'operations' => [ 'has_procedure' => false, 'has_geometry' => false, 'has_print_link' => true, 'has_export_link' => true, 'url_params' => [ 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'printview' => '1', 'sql_query' => $query, 'single_table' => 'true', 'unlim_num_rows' => 3, ], ], 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'unique_id' => 1234567890, 'sql_query' => $query, 'goto' => '', 'unlim_num_rows' => 3, 'displaywork' => false, 'relwork' => false, 'save_cells_at_once' => false, 'default_sliders_state' => 'closed', 'text_dir' => 'ltr', ]); $this->assertEquals($tableTemplate, $actual); } public function testGetTable2(): void { $GLOBALS['cfg']['Server']['DisableIS'] = true; $GLOBALS['db'] = 'test_db'; $GLOBALS['table'] = 'test_table'; $query = 'SELECT COUNT(*) AS `Rows`, `name` FROM `test_table` GROUP BY `name` ORDER BY `name`'; $object = new DisplayResults($this->dbi, $GLOBALS['db'], $GLOBALS['table'], 1, '', $query); $object->properties['unique_id'] = 1234567890; [$analyzedSqlResults] = ParseAnalyze::sqlQuery($query, $GLOBALS['db']); $fieldsMeta = [ new FieldMetadata( MYSQLI_TYPE_LONG, MYSQLI_NUM_FLAG | MYSQLI_NOT_NULL_FLAG, (object) ['name' => 'Rows'] ), new FieldMetadata(MYSQLI_TYPE_STRING, MYSQLI_NOT_NULL_FLAG, (object) ['name' => 'name']), ]; $this->dummyDbi->addResult($query, [['2', 'abcd'], ['1', 'foo']], ['Rows', 'name'], $fieldsMeta); $object->setProperties( 2, $fieldsMeta, $analyzedSqlResults['is_count'], $analyzedSqlResults['is_export'], $analyzedSqlResults['is_func'], $analyzedSqlResults['is_analyse'], 2, count($fieldsMeta), 1.234, 'ltr', $analyzedSqlResults['is_maint'], $analyzedSqlResults['is_explain'], $analyzedSqlResults['is_show'], null, null, true, true ); $_SESSION = ['tmpval' => [], ' PMA_token ' => 'token']; $_SESSION['tmpval']['geoOption'] = ''; $_SESSION['tmpval']['hide_transformation'] = false; $_SESSION['tmpval']['display_blob'] = ''; $_SESSION['tmpval']['display_binary'] = ''; $_SESSION['tmpval']['relational_display'] = ''; $_SESSION['tmpval']['possible_as_geometry'] = ''; $_SESSION['tmpval']['pftext'] = ''; $_SESSION['tmpval']['max_rows'] = 25; $_SESSION['tmpval']['pos'] = 0; $_SESSION['tmpval']['repeat_cells'] = 0; $_SESSION['tmpval']['query']['f2a8e80312ca180031ad773b573adbe1']['max_rows'] = 25; $dtResult = $this->dbi->tryQuery($query); $displayParts = DisplayParts::fromArray([ 'hasEditLink' => false, 'deleteLink' => DisplayParts::NO_DELETE, 'hasSortLink' => true, 'hasNavigationBar' => true, 'hasBookmarkForm' => true, 'hasTextButton' => false, 'hasPrintLink' => true, ]); $this->assertNotFalse($dtResult); $actual = $object->getTable($dtResult, $displayParts, $analyzedSqlResults); $template = new Template(); $tableHeadersForColumns = $template->render('display/results/table_headers_for_columns', [ 'is_sortable' => true, 'columns' => [ [ 'column_name' => 'Rows', 'order_link' => 'Rows' . "\n" . '', 'comments' => '', 'is_browse_pointer_enabled' => true, 'is_browse_marker_enabled' => true, 'is_column_hidden' => false, 'is_column_numeric' => true, ], [ 'column_name' => 'name', 'order_link' => 'name Ascending Descending 1' . "\n" . '', 'comments' => '', 'is_browse_pointer_enabled' => true, 'is_browse_marker_enabled' => true, 'is_column_hidden' => false, 'is_column_numeric' => false, ], ], ]); $tableTemplate = $template->render('display/results/table', [ 'sql_query_message' => Generator::getMessage( Message::success('Showing rows 0 - 1 (2 total, Query took 1.2340 seconds.)'), $query, 'success' ), 'navigation' => [ 'page_selector' => '', 'number_total_page' => 1, 'has_show_all' => true, 'hidden_fields' => [ 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'server' => 1, 'sql_query' => $query, 'is_browse_distinct' => true, 'goto' => '', ], 'session_max_rows' => 'all', 'is_showing_all' => false, 'max_rows' => 25, 'pos' => 0, 'sort_by_key' => [], 'is_last_page' => true, ], 'headers' => [ 'column_order' => [], 'options' => '$optionsBlock', 'has_bulk_actions_form' => false, 'button' => '' . "\n", 'table_headers_for_columns' => $tableHeadersForColumns, 'column_at_right_side' => "\n" . '', ], 'body' => '2' . "\n" . 'abcd' . "\n" . '' . "\n" . '1' . "\n" . 'foo' . "\n" . '' . "\n", 'bulk_links' => [], 'operations' => [ 'has_procedure' => false, 'has_geometry' => false, 'has_print_link' => true, 'has_export_link' => true, 'url_params' => [ 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'printview' => '1', 'sql_query' => $query, 'single_table' => 'true', 'unlim_num_rows' => 2, ], ], 'db' => $GLOBALS['db'], 'table' => $GLOBALS['table'], 'unique_id' => 1234567890, 'sql_query' => $query, 'goto' => '', 'unlim_num_rows' => 2, 'displaywork' => false, 'relwork' => false, 'save_cells_at_once' => false, 'default_sliders_state' => 'closed', 'text_dir' => 'ltr', ]); $this->assertEquals($tableTemplate, $actual); } }