From 10745bb39275a6f5ac7c62c063fa6433dfc8854b Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 20 Aug 2019 16:42:00 +0200 Subject: [PATCH 01/16] #15363 - substr can return false Signed-off-by: William Desportes --- libraries/classes/InsertEdit.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index 1282b3e44a..454109cf21 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -2078,7 +2078,8 @@ class InsertEdit } elseif ($trueType == 'binary' || $trueType == 'varbinary') { $special_chars = bin2hex($column['Default']); } elseif ('text' === substr($trueType, -4)) { - $special_chars = stripcslashes(substr($column['Default'], 1, -1)); + $textDefault = substr($column['Default'], 1, -1); + $special_chars = stripcslashes($textDefault !== false ? $textDefault : $column['Default']); } else { $special_chars = htmlspecialchars($column['Default']); } From da9d907ad1b17c31d293bff56f10fdaca52672c1 Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Tue, 20 Aug 2019 19:32:42 +0200 Subject: [PATCH 02/16] Fix #15446 Tables added from other databases are not collapsing in the designer section The events to link all buttons to collapse tables were initialized at page loading. But when a new table was added, the event wasn't declared for this one. With this commit, the event is now also declared on table addition. Signed-off-by: Hugues Peccatte --- js/designer/move.js | 86 ++++++++++--------- .../database/designer/database_tables.twig | 4 +- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/js/designer/move.js b/js/designer/move.js index 3fb8cd3cb7..94845a3ce6 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -564,18 +564,7 @@ function Add_Other_db_tables () { $new_table_dom = $(data.message); $new_table_dom.find('a').first().remove(); $('#container-form').append($new_table_dom); - $('.designer_tab').on('click','.tab_field_2,.tab_field_3,.tab_field', function () { - var params = ($(this).attr('click_field_param')).split(','); - Click_field(params[3], params[0], params[1], params[2]); - }); - $('.designer_tab').on('click', '.select_all_store_col', function () { - var params = ($(this).attr('store_column_param')).split(','); - store_column(params[0], params[1], params[2]); - }); - $('.designer_tab').on('click', '.small_tab_pref_click_opt', function () { - var params = ($(this).attr('Click_option_param')).split(','); - Click_option(params[0], params[1], params[2]); - }); + enableTableEvents(null, $new_table_dom); }); $(this).dialog('close'); }; @@ -1913,6 +1902,44 @@ function add_object () { $('#ab').accordion('refresh'); } +function enablePageContentEvents() { + $('#page_content').off('mousedown', MouseDown); + $('#page_content').off('mouseup', MouseUp); + $('#page_content').off('mousemove', MouseMove); + $('#page_content').on('mousedown', MouseDown); + $('#page_content').on('mouseup', MouseUp); + $('#page_content').on('mousemove', MouseMove); +} + +/** + * This function enables the events on table items. + * It helps to enable them on page loading and when a table is added on the fly. + */ +function enableTableEvents(index, element) { + $(element).on('click', '.select_all_1', function () { + Select_all($(this).attr('designer_url_table_name'), $(this).attr('designer_out_owner')); + }); + $(element).on('click', '.small_tab,.small_tab2', function () { + Small_tab($(this).attr('table_name'), 1); + }); + $(element).on('click', '.small_tab_pref_1', function () { + Start_tab_upd($(this).attr('table_name_small')); + }); + $(element).on('click', '.select_all_store_col', function () { + var params = ($(this).attr('store_column_param')).split(','); + store_column(params[0], params[1], params[2]); + }); + $(element).on('click', '.small_tab_pref_click_opt', function () { + var params = ($(this).attr('Click_option_param')).split(','); + Click_option(params[0], params[1], params[2]); + }); + $(element).on('click', '.tab_field_2,.tab_field_3,.tab_field', function () { + var params = ($(this).attr('click_field_param')).split(','); + Click_field(params[3], params[0], params[1], params[2]); + }); + enablePageContentEvents(); +} + AJAX.registerTeardown('designer/move.js', function () { $('#side_menu').off('mouseenter mouseleave'); $('#key_Show_left_menu').off('click'); @@ -2073,15 +2100,9 @@ AJAX.registerOnload('designer/move.js', function () { $('#id_scroll_tab').find('tr').on('click', '.designer_Tabs2,.designer_Tabs', function () { Select_tab($(this).attr('designer_url_table_name')); }); - $('.designer_tab').on('click', '.select_all_1', function () { - Select_all($(this).attr('designer_url_table_name'), $(this).attr('designer_out_owner')); - }); - $('.designer_tab').on('click', '.small_tab,.small_tab2', function () { - Small_tab($(this).attr('table_name'), 1); - }); - $('.designer_tab').on('click', '.small_tab_pref_1', function () { - Start_tab_upd($(this).attr('table_name_small')); - }); + + $('.designer_tab').each(enableTableEvents); + $('.tab_zag_noquery').mouseover(function () { Table_onover($(this).attr('table_name'),0, $(this).attr('query_set')); }); @@ -2094,18 +2115,7 @@ AJAX.registerOnload('designer/move.js', function () { $('.tab_zag_query').mouseout(function () { Table_onover($(this).attr('table_name'),1, 1); }); - $('.designer_tab').on('click','.tab_field_2,.tab_field_3,.tab_field', function () { - var params = ($(this).attr('click_field_param')).split(','); - Click_field(params[3], params[0], params[1], params[2]); - }); - $('.designer_tab').on('click', '.select_all_store_col', function () { - var params = ($(this).attr('store_column_param')).split(','); - store_column(params[0], params[1], params[2]); - }); - $('.designer_tab').on('click', '.small_tab_pref_click_opt', function () { - var params = ($(this).attr('Click_option_param')).split(','); - Click_option(params[0], params[1], params[2]); - }); + $('input#del_button').click(function () { Upd_relation(); }); @@ -2125,13 +2135,5 @@ AJAX.registerOnload('designer/move.js', function () { $('input#cancel_new_rel_panel').click(function () { document.getElementById('layer_new_relation').style.display = 'none'; }); - $('#page_content').on('mousedown', function(e) { - MouseDown(e); - }); - $('#page_content').on('mouseup', function(e) { - MouseUp(e); - }); - $('#page_content').on('mousemove', function(e) { - MouseMove(e); - }); + enablePageContentEvents(); }); diff --git a/templates/database/designer/database_tables.twig b/templates/database/designer/database_tables.twig index 64a63a8058..8d4505eed7 100644 --- a/templates/database/designer/database_tables.twig +++ b/templates/database/designer/database_tables.twig @@ -30,9 +30,7 @@ - {{ tab_pos[t_n] is not defined or tab_pos[t_n]['V'] is not empty ? 'v' : '>' }} - + table_name="{{ t_n_url|url_encode }}">{{ tab_pos[t_n] is not defined or tab_pos[t_n]['V'] is not empty ? 'v' : '>' }} Date: Tue, 20 Aug 2019 20:57:20 +0200 Subject: [PATCH 03/16] Fix wrong id on table When a table is added on the fly, the id was always built based on the first table of the targetted DB, not based on the selected table. Signed-off-by: Hugues Peccatte --- db_designer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/db_designer.php b/db_designer.php index 60ae358fd2..6d15395bbe 100644 --- a/db_designer.php +++ b/db_designer.php @@ -38,6 +38,7 @@ if (isset($_POST['dialog'])) { $req_key = array_search($required, $GLOBALS['designer']['TABLE_NAME']); $GLOBALS['designer']['TABLE_NAME'] = array($GLOBALS['designer']['TABLE_NAME'][$req_key]); + $GLOBALS['designer_url']['TABLE_NAME'] = array($GLOBALS['designer_url']['TABLE_NAME'][$req_key]); $GLOBALS['designer_url']['TABLE_NAME_SMALL'] = array($GLOBALS['designer_url']['TABLE_NAME_SMALL'][$req_key]); $GLOBALS['designer']['TABLE_NAME_SMALL'] = array($GLOBALS['designer']['TABLE_NAME_SMALL'][$req_key]); $GLOBALS['designer_out']['TABLE_NAME_SMALL'] = array($GLOBALS['designer_out']['TABLE_NAME_SMALL'][$req_key]); From 14ba5a1b248791c71ad9e621330d4b4f361722bd Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Tue, 20 Aug 2019 22:23:35 +0200 Subject: [PATCH 04/16] Retrieve DB instead of relying on current one When adding a table to the designer, it is useful to know the DB of this table to be able to jump to its structure. Signed-off-by: Hugues Peccatte --- js/designer/move.js | 7 ++++--- libraries/classes/Database/Designer.php | 1 + templates/database/designer/database_tables.twig | 1 + templates/database/designer/table_list.twig | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/js/designer/move.js b/js/designer/move.js index 94845a3ce6..5dcea4c9b2 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -1284,7 +1284,8 @@ function Start_table_new () { PMA_commonActions.refreshMain('tbl_create.php'); } -function Start_tab_upd (table) { +function Start_tab_upd (db, table) { + PMA_commonParams.set('db', db); PMA_commonParams.set('table', table); PMA_commonActions.refreshMain('tbl_structure.php'); } @@ -1923,7 +1924,7 @@ function enableTableEvents(index, element) { Small_tab($(this).attr('table_name'), 1); }); $(element).on('click', '.small_tab_pref_1', function () { - Start_tab_upd($(this).attr('table_name_small')); + Start_tab_upd($(this).attr('db'), $(this).attr('table_name_small')); }); $(element).on('click', '.select_all_store_col', function () { var params = ($(this).attr('store_column_param')).split(','); @@ -2092,7 +2093,7 @@ AJAX.registerOnload('designer/move.js', function () { return false; }); $('.scroll_tab_struct').click(function () { - Start_tab_upd($(this).attr('table_name')); + Start_tab_upd($(this).attr('db'), $(this).attr('table_name')); }); $('.scroll_tab_checkbox').click(function () { VisibleTab(this,$(this).val()); diff --git a/libraries/classes/Database/Designer.php b/libraries/classes/Database/Designer.php index 875125a488..b135f9b3ed 100644 --- a/libraries/classes/Database/Designer.php +++ b/libraries/classes/Database/Designer.php @@ -293,6 +293,7 @@ class Designer public function getHtmlTableList(array $tab_pos, $display_page) { return Template::get('database/designer/table_list')->render([ + 'db' => $GLOBALS['db'], 'tab_pos' => $tab_pos, 'display_page' => $display_page, 'theme' => $GLOBALS['PMA_Theme'], diff --git a/templates/database/designer/database_tables.twig b/templates/database/designer/database_tables.twig index 8d4505eed7..32e816f141 100644 --- a/templates/database/designer/database_tables.twig +++ b/templates/database/designer/database_tables.twig @@ -32,6 +32,7 @@ id="id_hide_tbody_{{ t_n_url|url_encode }}" table_name="{{ t_n_url|url_encode }}">{{ tab_pos[t_n] is not defined or tab_pos[t_n]['V'] is not empty ? 'v' : '>' }} diff --git a/templates/database/designer/table_list.twig b/templates/database/designer/table_list.twig index 5fca2873c7..c69b0382ff 100644 --- a/templates/database/designer/table_list.twig +++ b/templates/database/designer/table_list.twig @@ -25,6 +25,7 @@ width="1px" class="L_butt2_1"> From c23bec2dee77f4b9af19f04f58d78db7cc75f5c4 Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Tue, 20 Aug 2019 22:34:06 +0200 Subject: [PATCH 05/16] Be sure to use local variable Signed-off-by: Hugues Peccatte --- js/designer/move.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/designer/move.js b/js/designer/move.js index 5dcea4c9b2..166b0673df 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -561,7 +561,7 @@ function Add_Other_db_tables () { 'table' : table, 'server': PMA_commonParams.get('server') }, function (data) { - $new_table_dom = $(data.message); + var $new_table_dom = $(data.message); $new_table_dom.find('a').first().remove(); $('#container-form').append($new_table_dom); enableTableEvents(null, $new_table_dom); From de57539fb71beacba54b18283893ca3cba6f01cf Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 00:01:17 +0200 Subject: [PATCH 06/16] Build "tables list" in JS This will allow to have the list generation in only one place, as the tables can now be added on the fly. So JS also needs to add items to this list. Signed-off-by: Hugues Peccatte --- db_designer.php | 2 +- js/designer/move.js | 53 +++++++++++++++++---- js/messages.php | 4 ++ libraries/classes/Database/Designer.php | 11 +---- templates/database/designer/table_list.twig | 35 +------------- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/db_designer.php b/db_designer.php index 6d15395bbe..5aca11080a 100644 --- a/db_designer.php +++ b/db_designer.php @@ -188,7 +188,7 @@ $response->addHTML( ); $response->addHTML($databaseDesigner->getHtmlCanvas()); -$response->addHTML($databaseDesigner->getHtmlTableList($tab_pos, $display_page)); +$response->addHTML($databaseDesigner->getHtmlTableList()); $response->addHTML( $databaseDesigner->getDatabaseTables( diff --git a/js/designer/move.js b/js/designer/move.js index 166b0673df..d0655c80fb 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -549,6 +549,48 @@ function Toggle_fullscreen () { saveValueInConfig('full_screen', value_sent); } +function addTableToTablesList(index, table_dom) { + var db = $(table_dom).find('.small_tab_pref').attr('db'); + var table = $(table_dom).find('.small_tab_pref').attr('table_name_small'); + var db_encoded = encodeURI(db); + var table_encoded = encodeURI(table); + var $new_table_line = $('' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + db + '.' + table + '' + + ''); + $('#id_scroll_tab table').first().append($new_table_line); + $($new_table_line).find('.scroll_tab_struct').click(function () { + Start_tab_upd(db, table); + }); + $($new_table_line).on('click', '.designer_Tabs2,.designer_Tabs', function () { + Select_tab($(this).attr('designer_url_table_name')); + }); + $($new_table_line).find('.scroll_tab_checkbox').click(function () { + VisibleTab(this,$(this).val()); + }); + var $tables_counter = $('#tables_counter'); + $tables_counter.text(parseInt($tables_counter.text(), 10) + 1); +} + function Add_Other_db_tables () { var button_options = {}; button_options[PMA_messages.strGo] = function () { @@ -565,6 +607,7 @@ function Add_Other_db_tables () { $new_table_dom.find('a').first().remove(); $('#container-form').append($new_table_dom); enableTableEvents(null, $new_table_dom); + addTableToTablesList(null, $new_table_dom); }); $(this).dialog('close'); }; @@ -2092,17 +2135,9 @@ AJAX.registerOnload('designer/move.js', function () { No_have_constr(this); return false; }); - $('.scroll_tab_struct').click(function () { - Start_tab_upd($(this).attr('db'), $(this).attr('table_name')); - }); - $('.scroll_tab_checkbox').click(function () { - VisibleTab(this,$(this).val()); - }); - $('#id_scroll_tab').find('tr').on('click', '.designer_Tabs2,.designer_Tabs', function () { - Select_tab($(this).attr('designer_url_table_name')); - }); $('.designer_tab').each(enableTableEvents); + $('.designer_tab').each(addTableToTablesList); $('.tab_zag_noquery').mouseover(function () { Table_onover($(this).attr('table_name'),0, $(this).attr('query_set')); diff --git a/js/messages.php b/js/messages.php index 2bf1822cb9..193e1a1f59 100644 --- a/js/messages.php +++ b/js/messages.php @@ -751,6 +751,10 @@ $js_messages['strStrong'] = __('Strong'); $js_messages['strU2FTimeout'] = __('Timed out waiting for security key activation.'); $js_messages['strU2FError'] = __('Failed security key activation (%s).'); +/* DB Designer */ +$js_messages['strHide'] = __('Hide'); +$js_messages['strStructure'] = __('Structure'); + echo "var PMA_messages = new Array();\n"; foreach ($js_messages as $name => $js_message) { Sanitize::printJsValue("PMA_messages['" . $name . "']", $js_message); diff --git a/libraries/classes/Database/Designer.php b/libraries/classes/Database/Designer.php index b135f9b3ed..dc4456a6d1 100644 --- a/libraries/classes/Database/Designer.php +++ b/libraries/classes/Database/Designer.php @@ -285,22 +285,13 @@ class Designer /** * Return HTML for the table list * - * @param array $tab_pos table positions - * @param int $display_page page number of the selected page - * * @return string html */ - public function getHtmlTableList(array $tab_pos, $display_page) + public function getHtmlTableList() { return Template::get('database/designer/table_list')->render([ - 'db' => $GLOBALS['db'], - 'tab_pos' => $tab_pos, - 'display_page' => $display_page, 'theme' => $GLOBALS['PMA_Theme'], 'table_names' => $GLOBALS['designer']['TABLE_NAME'], - 'table_names_url' => $GLOBALS['designer_url']['TABLE_NAME'], - 'table_names_small_url' => $GLOBALS['designer_url']['TABLE_NAME_SMALL'], - 'table_names_out' => $GLOBALS['designer_out']['TABLE_NAME'], ]); } diff --git a/templates/database/designer/table_list.twig b/templates/database/designer/table_list.twig index c69b0382ff..4534d55a50 100644 --- a/templates/database/designer/table_list.twig +++ b/templates/database/designer/table_list.twig @@ -18,42 +18,11 @@
- - {% for i in 0..table_names|length - 1 %} - - - - - - {% endfor %} -
- - - - - {{ table_names_out[i]|raw }} -
+
{# end id_scroll_tab #}
- {% trans 'Number of tables:' %} {{ table_names|length }} + {% trans 'Number of tables:' %} 0
From ac340e29b6c53c4722789650c9500891c6b1f5e8 Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 00:20:13 +0200 Subject: [PATCH 07/16] Add missing overlay on added tables Signed-off-by: Hugues Peccatte --- js/designer/move.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/js/designer/move.js b/js/designer/move.js index d0655c80fb..5d3719822a 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -1981,6 +1981,20 @@ function enableTableEvents(index, element) { var params = ($(this).attr('click_field_param')).split(','); Click_field(params[3], params[0], params[1], params[2]); }); + + $(element).find('.tab_zag_noquery').mouseover(function () { + Table_onover($(this).attr('table_name'),0, $(this).attr('query_set')); + }); + $(element).find('.tab_zag_noquery').mouseout(function () { + Table_onover($(this).attr('table_name'),1, $(this).attr('query_set')); + }); + $(element).find('.tab_zag_query').mouseover(function () { + Table_onover($(this).attr('table_name'),0, 1); + }); + $(element).find('.tab_zag_query').mouseout(function () { + Table_onover($(this).attr('table_name'),1, 1); + }); + enablePageContentEvents(); } @@ -2139,19 +2153,6 @@ AJAX.registerOnload('designer/move.js', function () { $('.designer_tab').each(enableTableEvents); $('.designer_tab').each(addTableToTablesList); - $('.tab_zag_noquery').mouseover(function () { - Table_onover($(this).attr('table_name'),0, $(this).attr('query_set')); - }); - $('.tab_zag_noquery').mouseout(function () { - Table_onover($(this).attr('table_name'),1, $(this).attr('query_set')); - }); - $('.tab_zag_query').mouseover(function () { - Table_onover($(this).attr('table_name'),0, 1); - }); - $('.tab_zag_query').mouseout(function () { - Table_onover($(this).attr('table_name'),1, 1); - }); - $('input#del_button').click(function () { Upd_relation(); }); From b13c05edfa5effe098516ca6db4b84b3d9ea8693 Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 00:44:28 +0200 Subject: [PATCH 08/16] Toggling global collapse of tables now relies on tables items instead of j_tabs Signed-off-by: Hugues Peccatte --- js/designer/move.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/js/designer/move.js b/js/designer/move.js index 5d3719822a..ef1fb9c041 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -1341,20 +1341,20 @@ function Small_tab_all (id_this) { var value_sent = ''; if (icon.alt === 'v') { - for (key in j_tabs) { - if (document.getElementById('id_hide_tbody_' + key).innerHTML === 'v') { - Small_tab(key, 0); + $('.designer_tab .small_tab,.small_tab2').each(function(index, element) { + if ($(element).text() === 'v') { + Small_tab($(element).attr('table_name'), 0); } - } + }); icon.alt = '>'; icon.src = icon.dataset.right; value_sent = 'v'; } else { - for (key in j_tabs) { - if (document.getElementById('id_hide_tbody_' + key).innerHTML !== 'v') { - Small_tab(key, 0); + $('.designer_tab .small_tab,.small_tab2').each(function(index, element) { + if ($(element).text() !== 'v') { + Small_tab($(element).attr('table_name'), 0); } - } + }); icon.alt = 'v'; icon.src = icon.dataset.down; value_sent = '>'; @@ -1367,9 +1367,9 @@ function Small_tab_all (id_this) { // invert max/min all tables function Small_tab_invert () { - for (var key in j_tabs) { - Small_tab(key, 0); - } + $('.designer_tab .small_tab,.small_tab2').each(function(index, element) { + Small_tab($(element).attr('table_name'), 0); + }); Re_load(); } From fce235c7bcc49793f2914a00790e573f3c8d5386 Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 08:27:32 +0200 Subject: [PATCH 09/16] Remove variable that is unused anymore Signed-off-by: Hugues Peccatte --- js/designer/move.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/designer/move.js b/js/designer/move.js index ef1fb9c041..c2ae24869c 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -1337,7 +1337,6 @@ function Start_tab_upd (db, table) { // max/min all tables function Small_tab_all (id_this) { var icon = id_this.children[0]; - var key; var value_sent = ''; if (icon.alt === 'v') { From 3aa7a35daebd2b1f816ac97ffe3822af032bc0f2 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Wed, 21 Aug 2019 19:09:57 +0200 Subject: [PATCH 10/16] #15363 - substr can return false on tbl_definition_form Signed-off-by: William Desportes --- libraries/tbl_columns_definition_form.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/tbl_columns_definition_form.inc.php b/libraries/tbl_columns_definition_form.inc.php index eacfa5a995..e83be4dc2c 100644 --- a/libraries/tbl_columns_definition_form.inc.php +++ b/libraries/tbl_columns_definition_form.inc.php @@ -265,7 +265,8 @@ for ($columnNumber = 0; $columnNumber < $num_fields; $columnNumber++) { $columnMeta['DefaultType'] = 'USER_DEFINED'; if ('text' === substr($columnMeta['Type'], -4)) { - $columnMeta['Default'] = stripcslashes(substr($columnMeta['Default'], 1, -1)); + $textDefault = substr($columnMeta['Default'], 1, -1); + $columnMeta['Default'] = stripcslashes($textDefault !== false ? $textDefault : $columnMeta['Default']); } $columnMeta['DefaultValue'] = $columnMeta['Default']; From 67c94b17fd04ec4ba22b4f8e5dcf9d3e3ab94eec Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 21:32:32 +0200 Subject: [PATCH 11/16] Designer export fails when a table name contains special chars Signed-off-by: Hugues Peccatte --- js/designer/move.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/designer/move.js b/js/designer/move.js index 3fb8cd3cb7..eb2394c81c 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -662,10 +662,10 @@ function Get_url_pos (forceString) { var poststr = ''; var argsep = PMA_commonParams.get('arg_separator'); for (var key in j_tabs) { - poststr += argsep + 't_x[' + key + ']=' + parseInt(document.getElementById(key).style.left, 10); - poststr += argsep + 't_y[' + key + ']=' + parseInt(document.getElementById(key).style.top, 10); - poststr += argsep + 't_v[' + key + ']=' + (document.getElementById('id_tbody_' + key).style.display === 'none' ? 0 : 1); - poststr += argsep + 't_h[' + key + ']=' + (document.getElementById('check_vis_' + key).checked ? 1 : 0); + poststr += argsep + 't_x[' + decodeURIComponent(key) + ']=' + parseInt(document.getElementById(key).style.left, 10); + poststr += argsep + 't_y[' + decodeURIComponent(key) + ']=' + parseInt(document.getElementById(key).style.top, 10); + poststr += argsep + 't_v[' + decodeURIComponent(key) + ']=' + (document.getElementById('id_tbody_' + key).style.display === 'none' ? 0 : 1); + poststr += argsep + 't_h[' + decodeURIComponent(key) + ']=' + (document.getElementById('check_vis_' + key).checked ? 1 : 0); } return poststr; } else { From b37b479da03b02cab23ce039ecb299496afa6b6d Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 23:05:15 +0200 Subject: [PATCH 12/16] Display an error when trying to import in designer a table that's already imported Signed-off-by: Hugues Peccatte --- js/designer/move.js | 12 ++++++++++++ js/messages.php | 3 +++ 2 files changed, 15 insertions(+) diff --git a/js/designer/move.js b/js/designer/move.js index 3fb8cd3cb7..b37d03fdda 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -554,6 +554,18 @@ function Add_Other_db_tables () { button_options[PMA_messages.strGo] = function () { var db = $('#add_table_from').val(); var table = $('#add_table').val(); + + //Check if table already imported or not. + var $table = $('[id="' + encodeURIComponent(db) + '.' + encodeURIComponent(table) + '"]'); + if ($table.length !== 0) { + PMA_ajaxShowMessage( + PMA_sprintf(PMA_messages.strTableAlreadyExists, db + '.' + table), + undefined, + 'error' + ); + return; + } + $.post('db_designer.php', { 'ajax_request' : true, 'dialog' : 'add_table', diff --git a/js/messages.php b/js/messages.php index 2bf1822cb9..6e4383d7ff 100644 --- a/js/messages.php +++ b/js/messages.php @@ -751,6 +751,9 @@ $js_messages['strStrong'] = __('Strong'); $js_messages['strU2FTimeout'] = __('Timed out waiting for security key activation.'); $js_messages['strU2FError'] = __('Failed security key activation (%s).'); +/* Designer */ +$js_messages['strTableAlreadyExists'] = __('Table %s already exists!'); + echo "var PMA_messages = new Array();\n"; foreach ($js_messages as $name => $js_message) { Sanitize::printJsValue("PMA_messages['" . $name . "']", $js_message); From 5c7eb38a81712679c354d13cc9355e27db2eba21 Mon Sep 17 00:00:00 2001 From: Hugues Peccatte Date: Wed, 21 Aug 2019 16:37:31 +0200 Subject: [PATCH 13/16] Fix url encoding of table names Signed-off-by: Hugues Peccatte --- js/designer/move.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/designer/move.js b/js/designer/move.js index c2ae24869c..05aca59785 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -552,8 +552,8 @@ function Toggle_fullscreen () { function addTableToTablesList(index, table_dom) { var db = $(table_dom).find('.small_tab_pref').attr('db'); var table = $(table_dom).find('.small_tab_pref').attr('table_name_small'); - var db_encoded = encodeURI(db); - var table_encoded = encodeURI(table); + var db_encoded = encodeURIComponent(db); + var table_encoded = encodeURIComponent(table); var $new_table_line = $('' + ' Date: Thu, 22 Aug 2019 10:05:13 +0200 Subject: [PATCH 14/16] Update js/messages.php add context for translators Co-Authored-By: William Desportes Signed-off-by: Hugues Peccatte --- js/messages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/messages.php b/js/messages.php index 6e4383d7ff..72bff5f107 100644 --- a/js/messages.php +++ b/js/messages.php @@ -752,7 +752,7 @@ $js_messages['strU2FTimeout'] = __('Timed out waiting for security key activatio $js_messages['strU2FError'] = __('Failed security key activation (%s).'); /* Designer */ -$js_messages['strTableAlreadyExists'] = __('Table %s already exists!'); +$js_messages['strTableAlreadyExists'] = _pgettext('The table already exists in the designer and can not be added once more.', 'Table %s already exists!'); echo "var PMA_messages = new Array();\n"; foreach ($js_messages as $name => $js_message) { From a23f2ba51a93af0c5eedf91646aa9e04b9bc3a12 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Thu, 22 Aug 2019 18:35:10 +0200 Subject: [PATCH 15/16] Fix some bugs with strange table and database names - Fix export - Fix split on . to have db and table - Replace some $_REQUEST occurences - Add translations to "add tables from another database" : "None" > strNone - Refactor the ugly code that used globals to use an object "DesignerTable" - Fix save a new added table - Fix delete page items - Fix more bugs Fixes: #15446 Fixes: #13370 Fixes: #14945 Closes: #15438 Signed-off-by: William Desportes --- db_designer.php | 64 +++--- js/designer/move.js | 62 +++--- libraries/classes/Database/Designer.php | 25 ++- .../classes/Database/Designer/Common.php | 185 ++++++++---------- .../Database/Designer/DesignerTable.php | 88 +++++++++ libraries/classes/Export.php | 4 +- .../Plugins/Schema/ExportRelationSchema.php | 12 +- .../classes/Plugins/Schema/TableStats.php | 14 +- schema_export.php | 4 +- .../database/designer/database_tables.twig | 69 +++---- 10 files changed, 313 insertions(+), 214 deletions(-) create mode 100644 libraries/classes/Database/Designer/DesignerTable.php diff --git a/db_designer.php b/db_designer.php index 5aca11080a..e26f4b47a5 100644 --- a/db_designer.php +++ b/db_designer.php @@ -19,33 +19,25 @@ $designerCommon = new Common(); if (isset($_POST['dialog'])) { if ($_POST['dialog'] == 'edit') { - $html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'editPage'); + $html = $databaseDesigner->getHtmlForEditOrDeletePages($_POST['db'], 'editPage'); } elseif ($_POST['dialog'] == 'delete') { - $html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'deletePage'); + $html = $databaseDesigner->getHtmlForEditOrDeletePages($_POST['db'], 'deletePage'); } elseif ($_POST['dialog'] == 'save_as') { - $html = $databaseDesigner->getHtmlForPageSaveAs($GLOBALS['db']); + $html = $databaseDesigner->getHtmlForPageSaveAs($_POST['db']); } elseif ($_POST['dialog'] == 'export') { $html = $databaseDesigner->getHtmlForSchemaExport( - $GLOBALS['db'], $_POST['selected_page'] + $_POST['db'], $_POST['selected_page'] ); } elseif ($_POST['dialog'] == 'add_table') { - $script_display_field = $designerCommon->getTablesInfo(); - $required = $GLOBALS['db'] . '.' . $GLOBALS['table']; - $tab_column = $designerCommon->getColumnsInfo(); - $tables_all_keys = $designerCommon->getAllKeys(); - $tables_pk_or_unique_keys = $designerCommon->getPkOrUniqueKeys(); - - $req_key = array_search($required, $GLOBALS['designer']['TABLE_NAME']); - - $GLOBALS['designer']['TABLE_NAME'] = array($GLOBALS['designer']['TABLE_NAME'][$req_key]); - $GLOBALS['designer_url']['TABLE_NAME'] = array($GLOBALS['designer_url']['TABLE_NAME'][$req_key]); - $GLOBALS['designer_url']['TABLE_NAME_SMALL'] = array($GLOBALS['designer_url']['TABLE_NAME_SMALL'][$req_key]); - $GLOBALS['designer']['TABLE_NAME_SMALL'] = array($GLOBALS['designer']['TABLE_NAME_SMALL'][$req_key]); - $GLOBALS['designer_out']['TABLE_NAME_SMALL'] = array($GLOBALS['designer_out']['TABLE_NAME_SMALL'][$req_key]); - $GLOBALS['designer']['TABLE_TYPE'] = array($GLOBALS['designer_url']['TABLE_TYPE'][$req_key]); - $GLOBALS['designer_out']['OWNER'] = array($GLOBALS['designer_out']['OWNER'][$req_key]); + // Pass the db and table to the getTablesInfo so we only have the table we asked for + $script_display_field = $designerCommon->getTablesInfo($_POST['db'], $_POST['table']); + $tab_column = $designerCommon->getColumnsInfo($script_display_field); + $tables_all_keys = $designerCommon->getAllKeys($script_display_field); + $tables_pk_or_unique_keys = $designerCommon->getPkOrUniqueKeys($script_display_field); $html = $databaseDesigner->getDatabaseTables( + $_POST['db'], + $script_display_field, array(), -1, $tab_column, $tables_all_keys, $tables_pk_or_unique_keys ); @@ -66,7 +58,7 @@ if (isset($_POST['operation'])) { if ($_POST['save_page'] == 'same') { $page = $_POST['selected_page']; } else { // new - $page = $designerCommon->createNewPage($_POST['selected_value'], $GLOBALS['db']); + $page = $designerCommon->createNewPage($_POST['selected_value'], $_POST['db']); $response->addJSON('id', $page); } $success = $designerCommon->saveTablePositions($page); @@ -110,11 +102,6 @@ if (isset($_POST['operation'])) { require 'libraries/db_common.inc.php'; $script_display_field = $designerCommon->getTablesInfo(); -$tab_column = $designerCommon->getColumnsInfo(); -$script_tables = $designerCommon->getScriptTabs(); -$tables_pk_or_unique_keys = $designerCommon->getPkOrUniqueKeys(); -$tables_all_keys = $designerCommon->getAllKeys(); -$classes_side_menu = $databaseDesigner->returnClassNamesFromMenuButtons(); $display_page = -1; $selected_page = null; @@ -132,7 +119,30 @@ if ($display_page != -1) { $selected_page = $designerCommon->getPageName($display_page); } $tab_pos = $designerCommon->getTablePositions($display_page); -$script_contr = $designerCommon->getScriptContr(); + +$fullTableNames = []; + +foreach($script_display_field as $designerTable) { + $fullTableNames[] = $designerTable->getDbTableString(); +} + +foreach($tab_pos as $position) { + if (! in_array($position['dbName'] . '.' . $position['tableName'], $fullTableNames)) { + foreach($designerCommon->getTablesInfo($position['dbName'], $position['tableName']) as $designerTable) { + $script_display_field[] = $designerTable; + } + } +} + + +$tab_column = $designerCommon->getColumnsInfo($script_display_field); +$script_tables = $designerCommon->getScriptTabs($script_display_field); +$tables_pk_or_unique_keys = $designerCommon->getPkOrUniqueKeys($script_display_field); +$tables_all_keys = $designerCommon->getAllKeys($script_display_field); +$classes_side_menu = $databaseDesigner->returnClassNamesFromMenuButtons(); + + +$script_contr = $designerCommon->getScriptContr($script_display_field); $params = array('lang' => $GLOBALS['lang']); if (isset($_GET['db'])) { @@ -192,6 +202,8 @@ $response->addHTML($databaseDesigner->getHtmlTableList()); $response->addHTML( $databaseDesigner->getDatabaseTables( + $_GET['db'], + $script_display_field, $tab_pos, $display_page, $tab_column, $tables_all_keys, $tables_pk_or_unique_keys ) diff --git a/js/designer/move.js b/js/designer/move.js index 572718b477..d6b5bbbafc 100644 --- a/js/designer/move.js +++ b/js/designer/move.js @@ -549,25 +549,25 @@ function Toggle_fullscreen () { saveValueInConfig('full_screen', value_sent); } -function addTableToTablesList(index, table_dom) { +function addTableToTablesList (index, table_dom) { var db = $(table_dom).find('.small_tab_pref').attr('db'); - var table = $(table_dom).find('.small_tab_pref').attr('table_name_small'); - var db_encoded = encodeURIComponent(db); - var table_encoded = encodeURIComponent(table); + var table = $(table_dom).find('.small_tab_pref').attr('table_name'); + var db_encoded = $(table_dom).find('.small_tab_pref').attr('db_url'); + var table_encoded = $(table_dom).find('.small_tab_pref').attr('table_name_url'); var $new_table_line = $('' + ' ' + ' ' + ' ' + ' ' + ' '); - $select_db.append(''); + $select_db.append(''); var $select_table = $(''); - $select_table.append(''); + $select_table.append(''); $.post('sql.php', { 'ajax_request' : true, @@ -670,7 +673,11 @@ function Add_Other_db_tables () { 'server': PMA_commonParams.get('server') }, function (data) { $select_table.html(''); - $(data.message).find('table.table_results.data.ajax').find('td.data').each(function () { + var rows = $(data.message).find('table.table_results.data.ajax').find('td.data'); + if (rows.length === 0) { + $select_table.append(''); + } + rows.each(function () { var val = $(this)[0].innerHTML; $select_table.append(''); }); @@ -705,11 +712,15 @@ function Get_url_pos (forceString) { if (designer_tables_enabled || forceString) { var poststr = ''; var argsep = PMA_commonParams.get('arg_separator'); + var i = 1; for (var key in j_tabs) { - poststr += argsep + 't_x[' + decodeURIComponent(key) + ']=' + parseInt(document.getElementById(key).style.left, 10); - poststr += argsep + 't_y[' + decodeURIComponent(key) + ']=' + parseInt(document.getElementById(key).style.top, 10); - poststr += argsep + 't_v[' + decodeURIComponent(key) + ']=' + (document.getElementById('id_tbody_' + key).style.display === 'none' ? 0 : 1); - poststr += argsep + 't_h[' + decodeURIComponent(key) + ']=' + (document.getElementById('check_vis_' + key).checked ? 1 : 0); + poststr += argsep + 't_x[' + i + ']=' + parseInt(document.getElementById(key).style.left, 10); + poststr += argsep + 't_y[' + i + ']=' + parseInt(document.getElementById(key).style.top, 10); + poststr += argsep + 't_v[' + i + ']=' + (document.getElementById('id_tbody_' + key).style.display === 'none' ? 0 : 1); + poststr += argsep + 't_h[' + i + ']=' + (document.getElementById('check_vis_' + key).checked ? 1 : 0); + poststr += argsep + 't_db[' + i + ']=' + $(document.getElementById(key)).attr('db_url'); + poststr += argsep + 't_tbl[' + i + ']=' + $(document.getElementById(key)).attr('table_name_url'); + i++; } return poststr; } else { @@ -718,7 +729,10 @@ function Get_url_pos (forceString) { if (document.getElementById('check_vis_' + key).checked) { var x = parseInt(document.getElementById(key).style.left, 10); var y = parseInt(document.getElementById(key).style.top, 10); - var tbCoords = new TableCoordinate(db, key.split('.')[1], -1, x, y); + var tbCoords = new TableCoordinate( + $(document.getElementById(key)).attr('db_url'), + $(document.getElementById(key)).attr('table_name_url'), + -1, x, y); coords.push(tbCoords); } } @@ -729,8 +743,8 @@ function Get_url_pos (forceString) { function Save2 (callback) { if (designer_tables_enabled) { var argsep = PMA_commonParams.get('arg_separator'); - var poststr = argsep + 'operation=savePage' + argsep + 'save_page=same' + argsep + 'ajax_request=true'; - poststr += argsep + 'server=' + server + argsep + 'db=' + db + argsep + 'selected_page=' + selected_page; + var poststr = 'operation=savePage' + argsep + 'save_page=same' + argsep + 'ajax_request=true'; + poststr += argsep + 'server=' + server + argsep + 'db=' + encodeURIComponent(db) + argsep + 'selected_page=' + selected_page; poststr += Get_url_pos(); var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest); @@ -1176,7 +1190,7 @@ function Load_page (page) { if (page !== null) { param_page = argsep + 'page=' + page; } - $('') + $('') .appendTo($('#page_content')) .click(); } else { diff --git a/libraries/classes/Database/Designer.php b/libraries/classes/Database/Designer.php index dc4456a6d1..fdb29610f2 100644 --- a/libraries/classes/Database/Designer.php +++ b/libraries/classes/Database/Designer.php @@ -291,22 +291,25 @@ class Designer { return Template::get('database/designer/table_list')->render([ 'theme' => $GLOBALS['PMA_Theme'], - 'table_names' => $GLOBALS['designer']['TABLE_NAME'], ]); } /** * Get HTML to display tables on designer page * - * @param array $tab_pos tables positions - * @param int $display_page page number of the selected page - * @param array $tab_column table column info - * @param array $tables_all_keys all indices - * @param array $tables_pk_or_unique_keys unique or primary indices + * @param string $db The database name from the request + * @param array $designerTables The designer tables + * @param array $tab_pos tables positions + * @param int $display_page page number of the selected page + * @param array $tab_column table column info + * @param array $tables_all_keys all indices + * @param array $tables_pk_or_unique_keys unique or primary indices * * @return string html */ public function getDatabaseTables( + $db, + array $designerTables, array $tab_pos, $display_page, array $tab_column, @@ -315,20 +318,14 @@ class Designer ) { return Template::get('database/designer/database_tables')->render([ 'db' => $GLOBALS['db'], - 'get_db' => $_GET['db'], + 'get_db' => $db, 'has_query' => isset($_REQUEST['query']), 'tab_pos' => $tab_pos, 'display_page' => $display_page, 'tab_column' => $tab_column, 'tables_all_keys' => $tables_all_keys, 'tables_pk_or_unique_keys' => $tables_pk_or_unique_keys, - 'table_names' => $GLOBALS['designer']['TABLE_NAME'], - 'table_names_url' => $GLOBALS['designer_url']['TABLE_NAME'], - 'table_names_small' => $GLOBALS['designer']['TABLE_NAME_SMALL'], - 'table_names_small_url' => $GLOBALS['designer_url']['TABLE_NAME_SMALL'], - 'table_names_small_out' => $GLOBALS['designer_out']['TABLE_NAME_SMALL'], - 'table_types' => $GLOBALS['designer']['TABLE_TYPE'], - 'owner_out' => $GLOBALS['designer_out']['OWNER'], + 'tables' => $designerTables, 'theme' => $GLOBALS['PMA_Theme'], ]); } diff --git a/libraries/classes/Database/Designer/Common.php b/libraries/classes/Database/Designer/Common.php index fd938202dc..3121648aab 100644 --- a/libraries/classes/Database/Designer/Common.php +++ b/libraries/classes/Database/Designer/Common.php @@ -12,6 +12,7 @@ use PhpMyAdmin\Index; use PhpMyAdmin\Relation; use PhpMyAdmin\Table; use PhpMyAdmin\Util; +use PhpMyAdmin\Database\Designer\DesignerTable; /** * Common functions for Designer @@ -34,109 +35,84 @@ class Common } /** - * Retrieves table info and stores it in $GLOBALS['designer'] + * Retrieves table info and returns it * - * @return array with table info + * @param string $db (optional) Filter only a DB ($table is required if you use $db) + * @param string $table (optional) Filter only a table ($db is now required) + * @return DesignerTable[] with table info */ - public function getTablesInfo() + public function getTablesInfo($db = null, $table = null) { - $retval = array(); - - $GLOBALS['designer']['TABLE_NAME'] = array();// that foreach no error - $GLOBALS['designer']['OWNER'] = array(); - $GLOBALS['designer']['TABLE_NAME_SMALL'] = array(); - $GLOBALS['designer']['TABLE_TYPE'] = array(); - - $GLOBALS['designer_url']['TABLE_NAME'] = array(); - $GLOBALS['designer_url']['OWNER'] = array(); - $GLOBALS['designer_url']['TABLE_NAME_SMALL'] = array(); - - $GLOBALS['designer_out']['TABLE_NAME'] = array(); - $GLOBALS['designer_out']['OWNER'] = array(); - $GLOBALS['designer_out']['TABLE_NAME_SMALL'] = array(); - $tables = $GLOBALS['dbi']->getTablesFull($GLOBALS['db']); + $designerTables = array(); + $db = ($db === null) ? $GLOBALS['db'] : $db; // seems to be needed later - $GLOBALS['dbi']->selectDb($GLOBALS['db']); - $i = 0; - foreach ($tables as $one_table) { - $GLOBALS['designer']['TABLE_NAME'][$i] - = $GLOBALS['db'] . "." . $one_table['TABLE_NAME']; - $GLOBALS['designer']['OWNER'][$i] = $GLOBALS['db']; - $GLOBALS['designer']['TABLE_NAME_SMALL'][$i] = htmlspecialchars( - $one_table['TABLE_NAME'], ENT_QUOTES - ); - - $GLOBALS['designer_url']['TABLE_NAME'][$i] - = $GLOBALS['db'] . "." . $one_table['TABLE_NAME']; - $GLOBALS['designer_url']['OWNER'][$i] = $GLOBALS['db']; - $GLOBALS['designer_url']['TABLE_NAME_SMALL'][$i] - = $one_table['TABLE_NAME']; - - $GLOBALS['designer_out']['TABLE_NAME'][$i] = htmlspecialchars( - $GLOBALS['db'] . "." . $one_table['TABLE_NAME'], ENT_QUOTES - ); - $GLOBALS['designer_out']['OWNER'][$i] = htmlspecialchars( - $GLOBALS['db'], ENT_QUOTES - ); - $GLOBALS['designer_out']['TABLE_NAME_SMALL'][$i] = htmlspecialchars( - $one_table['TABLE_NAME'], ENT_QUOTES - ); - - $GLOBALS['designer']['TABLE_TYPE'][$i] = mb_strtoupper( - $one_table['ENGINE'] - ); - - $DF = $this->relation->getDisplayField($GLOBALS['db'], $one_table['TABLE_NAME']); - if ($DF != '') { - $DF = rawurlencode((string)$DF); - $retval[rawurlencode($GLOBALS['designer_url']["TABLE_NAME_SMALL"][$i])] = $DF; - } - - $i++; + $GLOBALS['dbi']->selectDb($db); + if ($db === null && $table === null) { + $tables = $GLOBALS['dbi']->getTablesFull($db); + } else { + $tables = $GLOBALS['dbi']->getTablesFull($db, $table); } - return $retval; + + foreach ($tables as $one_table) { + $DF = $this->relation->getDisplayField($db, $one_table['TABLE_NAME']); + $DF = ($DF !== '') ? $DF : null; + $designerTables[] = new DesignerTable( + $db, + $one_table['TABLE_NAME'], + $one_table['ENGINE'], + $DF + ); + } + + return $designerTables; } /** * Retrieves table column info * - * @return array table column nfo + * @param DesignerTable[] $designerTables The designer tables + * @return array table column nfo */ - public function getColumnsInfo() + public function getColumnsInfo($designerTables) { - $GLOBALS['dbi']->selectDb($GLOBALS['db']); - $tab_column = array(); - for ($i = 0, $cnt = count($GLOBALS['designer']["TABLE_NAME"]); $i < $cnt; $i++) { - $fields_rs = $GLOBALS['dbi']->query( + //$GLOBALS['dbi']->selectDb($GLOBALS['db']); + $tabColumn = array(); + + foreach($designerTables as $designerTable) { + $fieldsRs = $GLOBALS['dbi']->query( $GLOBALS['dbi']->getColumnsSql( - $GLOBALS['db'], - $GLOBALS['designer_url']["TABLE_NAME_SMALL"][$i], + $designerTable->getDatabaseName(), + $designerTable->getTableName(), null, true ), DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_STORE ); - $tbl_name_i = $GLOBALS['designer']['TABLE_NAME'][$i]; $j = 0; - while ($row = $GLOBALS['dbi']->fetchAssoc($fields_rs)) { - $tab_column[$tbl_name_i]['COLUMN_ID'][$j] = $j; - $tab_column[$tbl_name_i]['COLUMN_NAME'][$j] = $row['Field']; - $tab_column[$tbl_name_i]['TYPE'][$j] = $row['Type']; - $tab_column[$tbl_name_i]['NULLABLE'][$j] = $row['Null']; + while ($row = $GLOBALS['dbi']->fetchAssoc($fieldsRs)) { + if (! isset($tabColumn[$designerTable->getDbTableString()])) { + $tabColumn[$designerTable->getDbTableString()] = []; + } + $tabColumn[$designerTable->getDbTableString()]['COLUMN_ID'][$j] = $j; + $tabColumn[$designerTable->getDbTableString()]['COLUMN_NAME'][$j] = $row['Field']; + $tabColumn[$designerTable->getDbTableString()]['TYPE'][$j] = $row['Type']; + $tabColumn[$designerTable->getDbTableString()]['NULLABLE'][$j] = $row['Null']; $j++; } } - return $tab_column; + + return $tabColumn; } /** * Returns JavaScript code for initializing vars * + * @param DesignerTable[] $designerTables The designer tables * @return string JavaScript code */ - public function getScriptContr() + public function getScriptContr($designerTables) { $GLOBALS['dbi']->selectDb($GLOBALS['db']); $con = array(); @@ -183,6 +159,11 @@ class Common } } + $tableDbNames = []; + foreach($designerTables as $designerTable) { + $tableDbNames[] = $designerTable->getDbTableString(); + } + $ti = 0; $retval = array(); for ($i = 0, $cnt = count($con["C_NAME"]); $i < $cnt; $i++) { @@ -190,9 +171,7 @@ class Common $dtn_i = $con['DTN'][$i]; $retval[$ti] = array(); $retval[$ti][$c_name_i] = array(); - if (in_array(rawurldecode($dtn_i), $GLOBALS['designer_url']["TABLE_NAME"]) - && in_array(rawurldecode($con['STN'][$i]), $GLOBALS['designer_url']["TABLE_NAME"]) - ) { + if (in_array($dtn_i, $tableDbNames) && in_array($con['STN'][$i], $tableDbNames)) { $retval[$ti][$c_name_i][$dtn_i] = array(); $retval[$ti][$c_name_i][$dtn_i][$con['DCN'][$i]] = array( 0 => $con['STN'][$i], @@ -207,34 +186,36 @@ class Common /** * Returns UNIQUE and PRIMARY indices * + * @param DesignerTable[] $designerTables The designer tables * @return array unique or primary indices */ - public function getPkOrUniqueKeys() + public function getPkOrUniqueKeys($designerTables) { - return $this->getAllKeys(true); + return $this->getAllKeys($designerTables, true); } /** * Returns all indices * + * @param DesignerTable[] $designerTables The designer tables * @param bool $unique_only whether to include only unique ones * * @return array indices */ - public function getAllKeys($unique_only = false) + public function getAllKeys($designerTables, $unique_only = false) { $keys = array(); - foreach ($GLOBALS['designer']['TABLE_NAME_SMALL'] as $I => $table) { - $schema = $GLOBALS['designer']['OWNER'][$I]; + foreach ($designerTables as $designerTable) { + $schema = $designerTable->getDatabaseName(); // for now, take into account only the first index segment - foreach (Index::getFromTable($table, $schema) as $index) { + foreach (Index::getFromTable($designerTable->getTableName(), $schema) as $index) { if ($unique_only && ! $index->isUnique()) { continue; } $columns = $index->getColumns(); foreach ($columns as $column_name => $dummy) { - $keys[$schema . '.' . $table . '.' . $column_name] = 1; + $keys[$schema . '.' . $designerTable->getTableName() . '.' . $column_name] = 1; } } } @@ -242,25 +223,24 @@ class Common } /** - * Return script to create j_tab and h_tab arrays + * Return j_tab and h_tab arrays * - * @return string + * @param DesignerTable[] $designerTables The designer tables + * @return array */ - public function getScriptTabs() + public function getScriptTabs($designerTables) { $retval = array( 'j_tabs' => array(), 'h_tabs' => array() ); - for ($i = 0, $cnt = count($GLOBALS['designer']['TABLE_NAME']); $i < $cnt; $i++) { - $j = 0; - if (Util::isForeignKeySupported($GLOBALS['designer']['TABLE_TYPE'][$i])) { - $j = 1; - } - $retval['j_tabs'][\rawurlencode($GLOBALS['designer_url']['TABLE_NAME'][$i])] = $j; - $retval['h_tabs'][\rawurlencode($GLOBALS['designer_url']['TABLE_NAME'][$i])] = 1; + foreach($designerTables as $designerTable) { + $key = rawurlencode($designerTable->getDbTableString()); + $retval['j_tabs'][$key] = $designerTable->supportsForeignkeys() ? 1 : 0; + $retval['h_tabs'][$key] = 1; } + return $retval; } @@ -280,6 +260,7 @@ class Common $query = " SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, + `db_name` as `dbName`, `table_name` as `tableName`, `x` AS `X`, `y` AS `Y`, 1 AS `V`, @@ -465,6 +446,10 @@ class Common */ public function saveTablePositions($pg) { + $pageId = $GLOBALS['dbi']->escapeString($pg); + + $db = $GLOBALS['dbi']->escapeString($_POST['db']); + $cfgRelation = $this->relation->getRelationsParam(); if (! $cfgRelation['pdfwork']) { return false; @@ -475,10 +460,7 @@ class Common . "." . Util::backquote( $GLOBALS['cfgRelation']['table_coords'] ) - . " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($_REQUEST['db']) - . "'" - . " AND `pdf_page_number` = '" . $GLOBALS['dbi']->escapeString($pg) - . "'"; + . " WHERE `pdf_page_number` = '" . $pageId . "'"; $res = $this->relation->queryAsControlUser( $query, @@ -490,8 +472,9 @@ class Common return (boolean)$res; } - foreach ($_REQUEST['t_h'] as $key => $value) { - list($DB, $TAB) = explode(".", $key); + foreach ($_POST['t_h'] as $key => $value) { + $DB = $_POST['t_db'][$key]; + $TAB = $_POST['t_tbl'][$key]; if (!$value) { continue; } @@ -503,9 +486,9 @@ class Common . " VALUES (" . "'" . $GLOBALS['dbi']->escapeString($DB) . "', " . "'" . $GLOBALS['dbi']->escapeString($TAB) . "', " - . "'" . $GLOBALS['dbi']->escapeString($pg) . "', " - . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['t_x'][$key]) . "', " - . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['t_y'][$key]) . "')"; + . "'" . $pageId . "', " + . "'" . $GLOBALS['dbi']->escapeString($_POST['t_x'][$key]) . "', " + . "'" . $GLOBALS['dbi']->escapeString($_POST['t_y'][$key]) . "')"; $res = $this->relation->queryAsControlUser( $query, true, DatabaseInterface::QUERY_STORE diff --git a/libraries/classes/Database/Designer/DesignerTable.php b/libraries/classes/Database/Designer/DesignerTable.php new file mode 100644 index 0000000000..bfdd48f04e --- /dev/null +++ b/libraries/classes/Database/Designer/DesignerTable.php @@ -0,0 +1,88 @@ +databaseName = $databaseName; + $this->tableName = $tableName; + $this->tableEngine = $tableEngine; + $this->displayField = $displayField; + } + + /** + * The table engine supports or not foreign keys + * + * @return bool + */ + public function supportsForeignkeys() { + return Util::isForeignKeySupported($this->tableEngine); + } + + /** + * Get the database name + * + * @return string + */ + public function getDatabaseName() { + return $this->databaseName; + } + + /** + * Get the table name + * + * @return string + */ + public function getTableName() { + return $this->tableName; + } + + /** + * Get the table engine + * + * @return string + */ + public function getTableEngine() { + return $this->tableEngine; + } + + /** + * Get the db and table speparated with a dot + * + * @return string + */ + public function getDbTableString() { + return $this->databaseName . '.' . $this->tableName; + } +} diff --git a/libraries/classes/Export.php b/libraries/classes/Export.php index 421ba1cd76..e4d028b224 100644 --- a/libraries/classes/Export.php +++ b/libraries/classes/Export.php @@ -1095,7 +1095,7 @@ class Export Core::fatalError(__('Bad type!')); } - $GLOBALS['dbi']->selectDb($GLOBALS['db']); - $export_plugin->exportSchema($GLOBALS['db']); + $GLOBALS['dbi']->selectDb($_POST['db']); + $export_plugin->exportSchema($_POST['db']); } } diff --git a/libraries/classes/Plugins/Schema/ExportRelationSchema.php b/libraries/classes/Plugins/Schema/ExportRelationSchema.php index dc0b36d910..ca9ca561ac 100644 --- a/libraries/classes/Plugins/Schema/ExportRelationSchema.php +++ b/libraries/classes/Plugins/Schema/ExportRelationSchema.php @@ -245,14 +245,12 @@ class ExportRelationSchema */ protected function getTablesFromRequest() { - $tables = array(); - $dbLength = mb_strlen($this->db); - foreach ($_REQUEST['t_h'] as $key => $value) { - if ($value) { - $tables[] = mb_substr($key, $dbLength + 1); + $tables = []; + if (isset($_POST['t_tbl'])) { + foreach($_POST['t_tbl'] as $table) { + $tables[] = rawurldecode($table); } } - return $tables; } @@ -301,7 +299,7 @@ class ExportRelationSchema echo ' ' , $error_message , "\n"; echo '

' , "\n"; echo '' , __('Back') , ''; echo "\n"; exit; diff --git a/libraries/classes/Plugins/Schema/TableStats.php b/libraries/classes/Plugins/Schema/TableStats.php index 0dc3db8663..420618de07 100644 --- a/libraries/classes/Plugins/Schema/TableStats.php +++ b/libraries/classes/Plugins/Schema/TableStats.php @@ -130,11 +130,15 @@ abstract class TableStats */ protected function loadCoordinates() { - foreach ($_REQUEST['t_h'] as $key => $value) { - if ($this->db . '.' . $this->tableName == $key) { - $this->x = (double) $_REQUEST['t_x'][$key]; - $this->y = (double) $_REQUEST['t_y'][$key]; - break; + if (isset($_POST['t_h'])) { + foreach ($_POST['t_h'] as $key => $value) { + $db = rawurldecode($_POST['t_db'][$key]); + $tbl = rawurldecode($_POST['t_tbl'][$key]); + if ($this->db . '.' . $this->tableName === $db . '.' . $tbl) { + $this->x = (double) $_POST['t_x'][$key]; + $this->y = (double) $_POST['t_y'][$key]; + break; + } } } } diff --git a/schema_export.php b/schema_export.php index d25657e8c2..9fe93f68f9 100644 --- a/schema_export.php +++ b/schema_export.php @@ -22,7 +22,7 @@ require_once 'libraries/common.inc.php'; $relation = new Relation(); $cfgRelation = $relation->getRelationsParam(); -if (! isset($_REQUEST['export_type'])) { +if (! isset($_POST['export_type'])) { Util::checkParameters(array('export_type')); } @@ -30,4 +30,4 @@ if (! isset($_REQUEST['export_type'])) { * Include the appropriate Schema Class depending on $export_type * default is PDF */ -Export::processExportSchema($_REQUEST['export_type']); +Export::processExportSchema($_POST['export_type']); diff --git a/templates/database/designer/database_tables.twig b/templates/database/designer/database_tables.twig index 32e816f141..7ba0a1f351 100644 --- a/templates/database/designer/database_tables.twig +++ b/templates/database/designer/database_tables.twig @@ -1,11 +1,14 @@ -{% for t_n in table_names %} +{% for designerTable in tables %} {% set i = loop.index0 %} - {% set t_n_url = table_names_url[i] %} - - - - - + + + +
+ designer_url_table_name="{{ t_n_url }}" + designer_out_owner="{{ designerTable.getDatabaseName() }}"> {% endif %} + id="id_hide_tbody_{{ t_n_url }}" + table_name="{{ t_n_url }}">{{ tab_pos[t_n] is not defined or tab_pos[t_n]['V'] is not empty ? 'v' : '>' }} - {% if has_query %} {% endif %} - - {% set display_field = Relation_getDisplayField(get_db, table_names_small[i]) %} + {% set display_field = Relation_getDisplayField(get_db, t_n) %} {% for j in 0..tab_column[t_n]['COLUMN_ID']|length - 1 %} {% set tmp_column = t_n ~ '.' ~ tab_column[t_n]['COLUMN_NAME'][j] %} {% set click_field_param = [ - table_names_small_url[i], + t_n, tab_column[t_n]['COLUMN_NAME'][j]|url_encode ] %} - {% if not Util_isForeignKeySupported(table_types[i]) %} + {% if not designerTable.supportsForeignkeys() %} {% set click_field_param = click_field_param|merge([tables_pk_or_unique_keys[tmp_column] is defined ? 1 : 0]) %} {% else %} {# if foreign keys are supported, it's not necessary that the @@ -71,23 +74,23 @@ {% set click_field_param = click_field_param|merge([tables_all_keys[tmp_column] is defined ? 1 : 0]) %} {% endif %} {% set click_field_param = click_field_param|merge([db]) %} - {% if has_query %} {% endif %} - {% endif %} From 9c5195d438f85fab78c79f280276e3f184a0116a Mon Sep 17 00:00:00 2001 From: William Desportes Date: Fri, 23 Aug 2019 01:07:12 +0200 Subject: [PATCH 16/16] Fix Unit tests broken by a23f2ba51a93af0c5e Signed-off-by: William Desportes --- test/classes/Database/Designer/CommonTest.php | 1 + test/classes/Plugins/Schema/DiaRelationSchemaTest.php | 2 ++ test/classes/Plugins/Schema/EpsRelationSchemaTest.php | 2 ++ test/classes/Plugins/Schema/PdfRelationSchemaTest.php | 2 ++ test/classes/Plugins/Schema/SvgRelationSchemaTest.php | 2 ++ 5 files changed, 9 insertions(+) diff --git a/test/classes/Database/Designer/CommonTest.php b/test/classes/Database/Designer/CommonTest.php index abbcaa5f05..b7c3d3614a 100644 --- a/test/classes/Database/Designer/CommonTest.php +++ b/test/classes/Database/Designer/CommonTest.php @@ -65,6 +65,7 @@ class CommonTest extends TestCase ->with( " SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, + `db_name` as `dbName`, `table_name` as `tableName`, `x` AS `X`, `y` AS `Y`, 1 AS `V`, diff --git a/test/classes/Plugins/Schema/DiaRelationSchemaTest.php b/test/classes/Plugins/Schema/DiaRelationSchemaTest.php index 5c08609280..942d24f97a 100644 --- a/test/classes/Plugins/Schema/DiaRelationSchemaTest.php +++ b/test/classes/Plugins/Schema/DiaRelationSchemaTest.php @@ -39,6 +39,8 @@ class DiaRelationSchemaTest extends PmaTestCase $_REQUEST['t_h'] = array('information_schema.files' => 1); $_REQUEST['t_x'] = array('information_schema.files' => 0); $_REQUEST['t_y'] = array('information_schema.files' => 0); + $_POST['t_db'] = array('information_schema'); + $_POST['t_tbl'] = array('files'); $GLOBALS['server'] = 1; $GLOBALS['db'] = 'information_schema'; diff --git a/test/classes/Plugins/Schema/EpsRelationSchemaTest.php b/test/classes/Plugins/Schema/EpsRelationSchemaTest.php index b9aea56d85..c63b2f2390 100644 --- a/test/classes/Plugins/Schema/EpsRelationSchemaTest.php +++ b/test/classes/Plugins/Schema/EpsRelationSchemaTest.php @@ -40,6 +40,8 @@ class EpsRelationSchemaTest extends PmaTestCase $_REQUEST['t_h'] = array('information_schema.files' => 1); $_REQUEST['t_x'] = array('information_schema.files' => 0); $_REQUEST['t_y'] = array('information_schema.files' => 0); + $_POST['t_db'] = array('information_schema'); + $_POST['t_tbl'] = array('files'); $GLOBALS['server'] = 1; $GLOBALS['db'] = 'information_schema'; diff --git a/test/classes/Plugins/Schema/PdfRelationSchemaTest.php b/test/classes/Plugins/Schema/PdfRelationSchemaTest.php index 65bcf901d2..03951a4e05 100644 --- a/test/classes/Plugins/Schema/PdfRelationSchemaTest.php +++ b/test/classes/Plugins/Schema/PdfRelationSchemaTest.php @@ -43,6 +43,8 @@ class PdfRelationSchemaTest extends PmaTestCase $_REQUEST['t_h'] = array('information_schema.files' => 1); $_REQUEST['t_x'] = array('information_schema.files' => 0); $_REQUEST['t_y'] = array('information_schema.files' => 0); + $_POST['t_db'] = array('information_schema'); + $_POST['t_tbl'] = array('files'); $GLOBALS['server'] = 1; $GLOBALS['db'] = 'information_schema'; diff --git a/test/classes/Plugins/Schema/SvgRelationSchemaTest.php b/test/classes/Plugins/Schema/SvgRelationSchemaTest.php index 11dc2256e9..37351c029e 100644 --- a/test/classes/Plugins/Schema/SvgRelationSchemaTest.php +++ b/test/classes/Plugins/Schema/SvgRelationSchemaTest.php @@ -39,6 +39,8 @@ class SvgRelationSchemaTest extends PmaTestCase $_REQUEST['t_h'] = array('information_schema.files' => 1); $_REQUEST['t_x'] = array('information_schema.files' => 0); $_REQUEST['t_y'] = array('information_schema.files' => 0); + $_POST['t_db'] = array('information_schema'); + $_POST['t_tbl'] = array('files'); $GLOBALS['server'] = 1; $GLOBALS['db'] = 'information_schema';
{{ tab_pos[t_n] is not defined or tab_pos[t_n]['V'] is not empty ? 'v' : '>' }} + db="{{ designerTable.getDatabaseName() }}" + db_url="{{ designerTable.getDatabaseName()|escape('url') }}" + table_name="{{ designerTable.getTableName() }}" + table_name_url="{{ designerTable.getTableName()|escape('url') }}"> - - {{ owner_out[i]|raw }} - - {{ table_names_small_out[i]|raw }} + {{ designerTable.getDatabaseName() }} + {{ designerTable.getTableName()|raw }} + id="id_zag_{{ t_n_url }}_2" + table_name="{{ t_n_url }}">