Merge pull request #1235 from D-storm/FR-755

rfe-755: Export with table/column name changes
This commit is contained in:
Isaac Bennetch 2014-06-16 15:12:12 -04:00
commit 5765c05cfe
11 changed files with 794 additions and 96 deletions

View File

@ -15,6 +15,7 @@ phpMyAdmin - ChangeLog
+ rfe #1145 Preview SQL instead of executing it
+ rfe #759 Use aliases in SQL export for tables and columns
- bug #4450 Query is duplicated on Ctrl+Enter
+ rfe #755 Export with table/column name changes
4.2.4.0 (not yet released)
- bug #4449 Mediawiki export does not produce table header row; also fix related PHP warnings

View File

@ -126,6 +126,7 @@ if (!defined('TESTSUITE')) {
'sql_hex_for_binary',
'sql_utc_time',
'sql_drop_database',
'sql_views_as_tables',
'csv_separator',
'csv_enclosed',
'csv_escaped',
@ -147,7 +148,8 @@ if (!defined('TESTSUITE')) {
'latex_data_caption',
'latex_data_continued_caption',
'latex_data_label',
'latex_null'
'latex_null',
'aliases'
);
foreach ($post_params as $one_post_param) {
@ -241,6 +243,18 @@ if (!defined('TESTSUITE')) {
PMA_fatalError(__('Bad parameters!'));
}
// Merge SQL Query aliases with Export aliases from
// export page, Export page aliases are given more
// preference over SQL Query aliases.
if (!empty($_REQUEST['aliases'])) {
$aliases = PMA_mergeAliases(
PMA_SQP_getAliasesFromQuery($sql_query, $db),
$_REQUEST['aliases']
);
} else {
$aliases = PMA_SQP_getAliasesFromQuery($sql_query, $db);
}
/**
* Increase time limit for script execution and initializes some variables
*/
@ -370,12 +384,14 @@ if (!defined('TESTSUITE')) {
}
PMA_exportServer(
$db_select, $whatStrucOrData, $export_plugin, $crlf, $err_url,
$export_type, $do_relation, $do_comments, $do_mime, $do_dates
$export_type, $do_relation, $do_comments, $do_mime, $do_dates,
$aliases
);
} elseif ($export_type == 'database') {
PMA_exportDatabase(
$db, $tables, $whatStrucOrData, $export_plugin, $crlf, $err_url,
$export_type, $do_relation, $do_comments, $do_mime, $do_dates
$export_type, $do_relation, $do_comments, $do_mime, $do_dates,
$aliases
);
} else {
// We export just one table
@ -392,8 +408,7 @@ if (!defined('TESTSUITE')) {
PMA_exportTable(
$db, $table, $whatStrucOrData, $export_plugin, $crlf, $err_url,
$export_type, $do_relation, $do_comments, $do_mime, $do_dates,
$allrows, $limit_to, $limit_from, $sql_query,
PMA_SQP_getAliasesFromQuery($sql_query, $db)
$allrows, $limit_to, $limit_from, $sql_query, $aliases
);
}
if (! $export_plugin->exportFooter()) {

View File

@ -42,6 +42,9 @@ AJAX.registerTeardown('export.js', function () {
$("#plugins").unbind('change');
$("input[type='radio'][name='quick_or_custom']").unbind('change');
$("input[type='radio'][name='allrows']").unbind('change');
$('#btn_alias_config').off('click');
$('#db_alias_select').off('change');
$('.table_alias_select').off('change');
});
AJAX.registerOnload('export.js', function () {
@ -246,6 +249,73 @@ function check_time_out(time_limit)
}, time_limit * 1000);
}
/**
* Handler for Database/table alias select
*
* @param object event the event object
*
* @return void
*/
function aliasSelectHandler(event) {
var sel = event.data.sel;
var type = event.data.type;
var inputId = $(this).val();
var $label = $(this).next('label');
$('input#' + $label.attr('for')).addClass('hide');
$('input#' + inputId).removeClass('hide');
$label.attr('for', inputId);
//alert('#' + $label.attr('for'));
$('#alias_modal ' + sel + '[id$=' + type + ']:visible').addClass('hide');
$('#alias_modal ' + sel + '#' + inputId + type).removeClass('hide');
$("#alias_modal").dialog("option", "position", "center");
}
/**
* Handler for Alias dialog box
*
* @param object event the event object
*
* @return void
*/
function createAliasModal(event) {
event.preventDefault();
$('#alias_modal').dialog({
width: Math.min($(window).width() - 100, 700),
modal: true,
dialogClass: "alias-dialog",
buttons: {
'Reset All': function() {
$(this).find('input[type="text"]').val('');
},
'Reset': function() {
$(this).find('input[type="text"]:visible').val('');
},
'Save & Close': function() {
$(this).dialog("close");
$('#alias_modal').parent().appendTo($('form[name="dump"]'));
}
},
create: function() {
$(this).css('maxHeight', $(window).height() - 150);
$('.alias-dialog .ui-dialog-titlebar-close').remove();
},
close: function() {
var isEmpty = true;
$(this).find('input[type="text"]').each(function() {
// trim input fields on close
$(this).val($(this).val().trim());
// check if non empty field present
if ($(this).val()) {
isEmpty = false;
}
});
$('input#btn_alias_config').attr('checked', !isEmpty);
},
position: 'center'
});
}
AJAX.registerOnload('export.js', function () {
$("input[type='radio'][name='quick_or_custom']").change(toggle_quick_or_custom);
@ -278,4 +348,21 @@ AJAX.registerOnload('export.js', function () {
disable_dump_some_rows_sub_options();
}
});
// Open Alias Modal Dialog on click
$('#btn_alias_config').on('click', createAliasModal);
// Database alias select on change event
$('#db_alias_select').on(
'change',
{sel: 'span', type: '_tables'},
aliasSelectHandler
);
// Table alias select on change event
$('.table_alias_select').on(
'change',
{sel: 'table', type: '_cols'},
aliasSelectHandler
);
});

View File

@ -634,6 +634,10 @@ function PMA_getHtmlForExportOptionsOutput($export_type)
$html = '<div class="exportoptions" id="output">';
$html .= '<h3>' . __('Output:') . '</h3>';
$html .= '<ul id="ul_output">';
$html .= '<li><input type="checkbox" id="btn_alias_config"/>';
$html .= '<label for="btn_alias_config">';
$html .= __('Rename exported databases/tables/columns');
$html .= '</label></li>';
$html .= '<li>';
$html .= '<input type="radio" name="output_format" value="sendit" ';
$html .= 'id="radio_dump_asfile" ';
@ -707,9 +711,128 @@ function PMA_getHtmlForExportOptions(
$html .= PMA_getHtmlForExportOptionsQuickExport();
}
$html .= PMA_getHtmlForAliasModalDialog($db, $table);
$html .= PMA_getHtmlForExportOptionsOutput($export_type);
$html .= PMA_getHtmlForExportOptionsFormat($export_list);
return $html;
}
/**
* Prints Html For Alias Modal Dialog
*
* @param String $db Selected DB
* @param String $table Selected Table
*
* @return string
*/
function PMA_getHtmlForAliasModalDialog($db = '', $table = '')
{
// In case of server export, the following list of
// databases are not shown in the list.
$dbs_not_allowed = array(
'information_schema',
'performance_schema',
'mysql'
);
// Fetch Columns info
// Server export does not have db set.
$title = __('Rename exported databases/tables/columns');
if (empty($db)) {
$databases = $GLOBALS['dbi']->getColumnsFull(
null, null, null, $GLOBALS['userlink']
);
foreach ($dbs_not_allowed as $db) {
unset($databases[$db]);
}
// Database export does not have table set.
} elseif (empty($table)) {
$tables = $GLOBALS['dbi']->getColumnsFull(
$db, null, null, $GLOBALS['userlink']
);
$databases = array($db => $tables);
// Table export
} else {
$columns = $GLOBALS['dbi']->getColumnsFull(
$db, $table, null, $GLOBALS['userlink']
);
$databases = array(
$db => array(
$table => $columns
)
);
}
$html = '<div id="alias_modal" class="hide" title="' . $title . '">';
$db_html = '<label class="col-2">' . __('Select database') . ': '
. '</label><select id="db_alias_select">';
$table_html = '<label class="col-2">' . __('Select table') . ': </label>';
$first_db = true;
foreach ($databases as $db => $tables) {
$db = htmlspecialchars($db);
$name_attr = 'aliases[' . $db . '][alias]';
$id_attr = substr(md5($name_attr), 0, 12);
$class = 'hide';
if ($first_db) {
$first_db = false;
$class = '';
$db_input_html = '<label class="col-2" for="' . $id_attr . '">'
. __('New database name') . ': </label>';
}
$db_input_html .= '<input type="text" name="' . $name_attr . '" '
. 'placeholder="' . $db . ' alias" class="' . $class . '" '
. 'id="' . $id_attr . '"/>';
$db_html .= '<option value="' . $id_attr . '">' . $db . '</option>';
$table_html .= '<span id="' . $id_attr . '_tables" class="' . $class . '">';
$table_html .= '<select id="' . $id_attr . '_tables_select" '
. 'class="table_alias_select">';
$first_tbl = true;
$col_html = '';
foreach ($tables as $table => $columns) {
$table = htmlspecialchars($table);
$name_attr = 'aliases[' . $db . '][tables][' . $table . '][alias]';
$id_attr = substr(md5($name_attr), 0, 12);
$class = 'hide';
if ($first_tbl) {
$first_tbl = false;
$class = '';
$table_input_html = '<label class="col-2" for="' . $id_attr . '">'
. __('New table name') . ': </label>';
}
$table_input_html .= '<input type="text" '
. 'name="' . $name_attr . '" id="' . $id_attr . '" '
. 'placeholder="' . $table . ' alias" class="' . $class . '"/>';
$table_html .= '<option value="' . $id_attr . '">'
. $table . '</option>';
$col_html .= '<table id="' . $id_attr . '_cols" class="'
. $class . '" width="100%">';
$col_html .= '<thead><tr><th>' . __('Old column name') . '</th>'
. '<th>' . __('New column name') . '</th></tr></thead><tbody>';
$class = 'odd';
foreach ($columns as $column => $col_def) {
$column = htmlspecialchars($column);
$name_attr = 'aliases[' . $db . '][tables][' . $table
. '][columns][' . $column . ']';
$id_attr = substr(md5($name_attr), 0, 12);
$col_html .= '<tr class="' . $class . '">';
$col_html .= '<th><label for="' . $id_attr . '">' . $column
. '</label></th>';
$col_html .= '<td><input type="text" name="' . $name_attr . '" '
. 'id="' . $id_attr . '" placeholder="'
. $column . ' alias" /></td>';
$col_html .= '</tr>';
$class = $class === 'odd' ? 'even' : 'odd';
}
$col_html .= '</tbody></table>';
}
$table_html .= '</select>';
$table_html .= $table_input_html . '<hr/>' . $col_html . '</span>';
}
$db_html .= '</select>';
$html .= $db_html;
$html .= $db_input_html . '<hr/>';
$html .= $table_html;
$html .= '</div>';
return $html;
}
?>

View File

@ -457,12 +457,14 @@ function PMA_getHtmlForDisplayedExportHeader($export_type, $db, $table)
* @param string $do_comments whether to add comments
* @param string $do_mime whether to add MIME info
* @param string $do_dates whether to add dates
* @param array $aliases Alias information for db/table/column
*
* @return void
*/
function PMA_exportServer(
$db_select, $whatStrucOrData, $export_plugin, $crlf, $err_url,
$export_type, $do_relation, $do_comments, $do_mime, $do_dates
$export_type, $do_relation, $do_comments, $do_mime, $do_dates,
$aliases
) {
if (! empty($db_select)) {
$tmp_select = implode($db_select, '|');
@ -477,7 +479,7 @@ function PMA_exportServer(
PMA_exportDatabase(
$current_db, $tables, $whatStrucOrData, $export_plugin, $crlf,
$err_url, $export_type, $do_relation, $do_comments, $do_mime,
$do_dates
$do_dates, $aliases
);
}
} // end foreach database
@ -497,17 +499,21 @@ function PMA_exportServer(
* @param string $do_comments whether to add comments
* @param string $do_mime whether to add MIME info
* @param string $do_dates whether to add dates
* @param array $aliases Alias information for db/table/column
*
* @return void
*/
function PMA_exportDatabase(
$db, $tables, $whatStrucOrData, $export_plugin, $crlf, $err_url,
$export_type, $do_relation, $do_comments, $do_mime, $do_dates
$export_type, $do_relation, $do_comments, $do_mime, $do_dates,
$aliases
) {
if (! $export_plugin->exportDBHeader($db)) {
$db_alias = !empty($aliases[$db]['alias'])
? $aliases[$db]['alias'] : '';
if (! $export_plugin->exportDBHeader($db, $db_alias)) {
return;
}
if (! $export_plugin->exportDBCreate($db)) {
if (! $export_plugin->exportDBCreate($db, $db_alias)) {
return;
}
@ -515,7 +521,7 @@ function PMA_exportDatabase(
&& strpos($GLOBALS['sql_structure_or_data'], 'structure') !== false
&& isset($GLOBALS['sql_procedure_function'])
) {
$export_plugin->exportRoutines($db);
$export_plugin->exportRoutines($db, $aliases);
}
$views = array();
@ -537,9 +543,9 @@ function PMA_exportDatabase(
if (isset($GLOBALS['sql_create_view'])) {
if (! $export_plugin->exportStructure(
$db, $table, $crlf, $err_url,
'stand_in', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates
$db, $table, $crlf, $err_url, 'stand_in',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
break 1;
}
@ -566,9 +572,9 @@ function PMA_exportDatabase(
}
if (! $export_plugin->exportStructure(
$db, $table, $crlf, $err_url,
'create_table', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates
$db, $table, $crlf, $err_url, 'create_table',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
break 1;
}
@ -584,7 +590,7 @@ function PMA_exportDatabase(
$local_query = 'SELECT * FROM ' . PMA_Util::backquote($db)
. '.' . PMA_Util::backquote($table);
if (! $export_plugin->exportData(
$db, $table, $crlf, $err_url, $local_query
$db, $table, $crlf, $err_url, $local_query, $aliases
)) {
break 1;
}
@ -595,9 +601,9 @@ function PMA_exportDatabase(
|| $whatStrucOrData == 'structure_and_data')
) {
if (! $export_plugin->exportStructure(
$db, $table, $crlf, $err_url,
'triggers', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates
$db, $table, $crlf, $err_url, 'triggers',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
break 1;
}
@ -612,9 +618,9 @@ function PMA_exportDatabase(
|| $whatStrucOrData == 'structure_and_data'
) {
if (! $export_plugin->exportStructure(
$db, $view, $crlf, $err_url,
'create_view', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates
$db, $view, $crlf, $err_url, 'create_view',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
break 1;
}
@ -623,7 +629,7 @@ function PMA_exportDatabase(
}
if (! $export_plugin->exportDBFooter($db)) {
if (! $export_plugin->exportDBFooter($db, $db_alias)) {
return;
}
}
@ -655,7 +661,9 @@ function PMA_exportTable(
$export_type, $do_relation, $do_comments, $do_mime, $do_dates,
$allrows, $limit_to, $limit_from, $sql_query, $aliases
) {
if (! $export_plugin->exportDBHeader($db)) {
$db_alias = !empty($aliases[$db]['alias'])
? $aliases[$db]['alias'] : '';
if (! $export_plugin->exportDBHeader($db, $db_alias)) {
return;
}
if (isset($allrows)
@ -679,9 +687,9 @@ function PMA_exportTable(
if (isset($GLOBALS['sql_create_view'])) {
if (! $export_plugin->exportStructure(
$db, $table, $crlf, $err_url,
'create_view', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates
$db, $table, $crlf, $err_url, 'create_view',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
return;
}
@ -690,9 +698,9 @@ function PMA_exportTable(
} else if (isset($GLOBALS['sql_create_table'])) {
if (! $export_plugin->exportStructure(
$db, $table, $crlf, $err_url,
'create_table', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates, $aliases
$db, $table, $crlf, $err_url, 'create_table',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
return;
}
@ -731,14 +739,14 @@ function PMA_exportTable(
|| $whatStrucOrData == 'structure_and_data')
) {
if (! $export_plugin->exportStructure(
$db, $table, $crlf, $err_url,
'triggers', $export_type,
$do_relation, $do_comments, $do_mime, $do_dates, $aliases
$db, $table, $crlf, $err_url, 'triggers',
$export_type, $do_relation, $do_comments,
$do_mime, $do_dates, $aliases
)) {
return;
}
}
if (! $export_plugin->exportDBFooter($db)) {
if (! $export_plugin->exportDBFooter($db, $db_alias)) {
return;
}
}
@ -764,4 +772,58 @@ function PMA_showExportPage($export_type)
}
exit();
}
/**
* Merge two alias arrays, if array1 and array2 have
* conflicting alias then array2 value is used if it
* is non empty otherwise array1 value.
*
* @param array $aliases1 first array of aliases
* @param array $aliases2 second array of aliases
*
* @return array resultant merged aliases info
*/
function PMA_mergeAliases($aliases1, $aliases2)
{
// First do a recursive array merge
// on aliases arrays.
$aliases = array_merge_recursive($aliases1, $aliases2);
// Now, resolve conflicts in aliases, if any
foreach ($aliases as $db_name => $db) {
// If alias key is an array then
// it is a merge conflict.
if (isset($db['alias']) && is_array($db['alias'])) {
$val1 = $db['alias'][0];
$val2 = $db['alias'][1];
// Use aliases2 alias if non empty
$aliases[$db_name]['alias']
= empty($val2) ? $val1 : $val2;
}
if (!isset($db['tables'])) {
continue;
}
foreach ($db['tables'] as $tbl_name => $tbl) {
if (isset($tbl['alias']) && is_array($tbl['alias'])) {
$val1 = $tbl['alias'][0];
$val2 = $tbl['alias'][1];
// Use aliases2 alias if non empty
$aliases[$db_name]['tables'][$tbl_name]['alias']
= empty($val2) ? $val1 : $val2;
}
if (!isset($tbl['columns'])) {
continue;
}
foreach ($tbl['columns'] as $col => $col_as) {
if (isset($col_as) && is_array($col_as)) {
$val1 = $col_as[0];
$val2 = $col_as[1];
// Use aliases2 alias if non empty
$aliases[$db_name]['tables'][$tbl_name]['columns'][$col]
= empty($val2) ? $val1 : $val2;
}
};
};
}
return $aliases;
}
?>

View File

@ -475,14 +475,18 @@ class ExportSql extends ExportPlugin
/**
* Exports routines (procedures and functions)
*
* @param string $db Database
* @param string $db Database
* @param array $aliases Aliases of db/table/columns
*
* @return bool Whether it succeeded
*/
public function exportRoutines($db)
public function exportRoutines($db, $aliases = array())
{
global $crlf;
$db_alias = $db;
$this->initAlias($aliases, $db_alias);
$text = '';
$delimiter = '$$';
@ -500,17 +504,31 @@ class ExportSql extends ExportPlugin
$this->_exportComment()
. $this->_exportComment(__('Procedures'))
. $this->_exportComment();
$used_alias = false;
$proc_query = '';
foreach ($procedure_names as $procedure_name) {
if (! empty($GLOBALS['sql_drop_table'])) {
$text .= 'DROP PROCEDURE IF EXISTS '
$proc_query .= 'DROP PROCEDURE IF EXISTS '
. PMA_Util::backquote($procedure_name)
. $delimiter . $crlf;
}
$text .= $GLOBALS['dbi']
->getDefinition($db, 'PROCEDURE', $procedure_name)
. $delimiter . $crlf . $crlf;
$create_query = $GLOBALS['dbi']
->getDefinition($db, 'PROCEDURE', $procedure_name);
$create_query = $this->replaceWithAliases(
$create_query, $aliases, $db, '', $flag
);
// One warning per database
if ($flag) {
$used_alias = true;
}
$proc_query .= $create_query . $delimiter . $crlf . $crlf;
}
if ($used_alias) {
$text .= $this->_exportComment(__('It appears your database uses procedures;'))
. $this->_exportComment(__('alias export may not work reliably in all cases.'))
. $this->_exportComment();
}
$text .= $proc_query;
}
if ($function_names) {
@ -518,17 +536,31 @@ class ExportSql extends ExportPlugin
$this->_exportComment()
. $this->_exportComment(__('Functions'))
. $this->_exportComment();
$used_alias = false;
$function_query = '';
foreach ($function_names as $function_name) {
if (! empty($GLOBALS['sql_drop_table'])) {
$text .= 'DROP FUNCTION IF EXISTS '
$function_query .= 'DROP FUNCTION IF EXISTS '
. PMA_Util::backquote($function_name)
. $delimiter . $crlf;
}
$text .= $GLOBALS['dbi']
->getDefinition($db, 'FUNCTION', $function_name)
. $delimiter . $crlf . $crlf;
$create_query = $GLOBALS['dbi']
->getDefinition($db, 'FUNCTION', $function_name);
$create_query = $this->replaceWithAliases(
$create_query, $aliases, $db, '', $flag
);
// One warning per database
if ($flag) {
$used_alias = true;
}
$function_query .= $create_query . $delimiter . $crlf . $crlf;
}
if ($used_alias) {
$text .= $this->_exportComment(__('It appears your database uses functions;'))
. $this->_exportComment(__('alias export may not work reliably in all cases.'))
. $this->_exportComment();
}
$text .= $function_query;
}
if ($procedure_names || $function_names) {
@ -760,7 +792,7 @@ class ExportSql extends ExportPlugin
$create_query = 'CREATE DATABASE IF NOT EXISTS '
. (isset($GLOBALS['sql_backquotes'])
? PMA_Util::backquoteCompat($db_alias, $compat) : $db_alias);
$collation = PMA_getDbCollation($db_alias);
$collation = PMA_getDbCollation($db);
if (PMA_DRIZZLE) {
$create_query .= ' COLLATE ' . $collation;
} else {
@ -903,18 +935,22 @@ class ExportSql extends ExportPlugin
/**
* Returns a stand-in CREATE definition to resolve view dependencies
*
* @param string $db the database name
* @param string $view the view name
* @param string $crlf the end of line sequence
* @param string $db the database name
* @param string $view the view name
* @param string $crlf the end of line sequence
* @param array $aliases Aliases of db/table/columns
*
* @return string resulting definition
*/
public function getTableDefStandIn($db, $view, $crlf)
public function getTableDefStandIn($db, $view, $crlf, $aliases = array())
{
$db_alias = $db;
$view_alias = $view;
$this->initAlias($aliases, $db_alias, $view_alias);
$create_query = '';
if (! empty($GLOBALS['sql_drop_table'])) {
$create_query .= 'DROP VIEW IF EXISTS '
. PMA_Util::backquote($view)
. PMA_Util::backquote($view_alias)
. ';' . $crlf;
}
@ -925,14 +961,18 @@ class ExportSql extends ExportPlugin
) {
$create_query .= 'IF NOT EXISTS ';
}
$create_query .= PMA_Util::backquote($view) . ' (' . $crlf;
$create_query .= PMA_Util::backquote($view_alias) . ' (' . $crlf;
$tmp = array();
$columns = $GLOBALS['dbi']->getColumnsFull($db, $view);
foreach ($columns as $column_name => $definition) {
$tmp[] = PMA_Util::backquote($column_name) . ' ' .
$col_alias = $column_name;
if (!empty($aliases[$db]['tables'][$view]['columns'][$col_alias])) {
$col_alias = $aliases[$db]['tables'][$view]['columns'][$col_alias];
}
$tmp[] = PMA_Util::backquote($col_alias) . ' ' .
$definition['Type'] . $crlf;
}
$create_query .= implode(',', $tmp) . ');';
$create_query .= implode(',', $tmp) . ');' . $crlf;
return($create_query);
}
@ -944,6 +984,7 @@ class ExportSql extends ExportPlugin
* @param string $crlf the end of line sequence
* @param bool $add_semicolon whether to add semicolon and end-of-line at
* the end
* @param array $aliases Aliases of db/table/columns
*
* @return string resulting schema
*/
@ -951,24 +992,32 @@ class ExportSql extends ExportPlugin
$db,
$view,
$crlf,
$add_semicolon = true
$add_semicolon = true,
$aliases = array()
) {
$db_alias = $db;
$view_alias = $view;
$this->initAlias($aliases, $db_alias, $view_alias);
$create_query = "CREATE TABLE";
if (isset($GLOBALS['sql_if_not_exists'])) {
$create_query .= " IF NOT EXISTS ";
}
$create_query .= PMA_Util::backquote($view) . "(" . $crlf;
$create_query .= PMA_Util::backquote($view_alias) . "(" . $crlf;
$columns = $GLOBALS['dbi']->getColumns($db, $view, null, true);
$firstCol = true;
foreach ($columns as $column) {
$col_alias = $column['Field'];
if (!empty($aliases[$db]['tables'][$view]['columns'][$col_alias])) {
$col_alias = $aliases[$db]['tables'][$view]['columns'][$col_alias];
}
$extracted_columnspec = PMA_Util::extractColumnSpec($column['Type']);
if (! $firstCol) {
$create_query .= "," . $crlf;
}
$create_query .= " " . PMA_Util::backquote($column['Field']);
$create_query .= " " . PMA_Util::backquote($col_alias);
$create_query .= " " . $column['Type'];
if ($extracted_columnspec['can_contain_collation']
&& ! empty($column['Collation'])
@ -1173,6 +1222,7 @@ class ExportSql extends ExportPlugin
return $this->_exportComment(__('in use') . '(' . $tmp_error . ')');
}
$warning = '';
if ($result != false && ($row = $GLOBALS['dbi']->fetchRow($result))) {
$create_query = $row[1];
unset($row);
@ -1202,8 +1252,19 @@ class ExportSql extends ExportPlugin
}
// substitute aliases in create query
$create_query = $this->replaceWithAliases(
$create_query, $aliases, $db, $table
$create_query, $aliases, $db, $table, $flag
);
// One warning per view
if ($flag && $view) {
$warning = $this->_exportComment()
. $this->_exportComment(
__('It appears your database uses views;')
)
. $this->_exportComment(
__('alias export may not work reliably in all cases.')
)
. $this->_exportComment();
}
// Should we use IF NOT EXISTS?
if (isset($GLOBALS['sql_if_not_exists'])) {
$create_query = preg_replace(
@ -1505,7 +1566,7 @@ class ExportSql extends ExportPlugin
$schema_create .= ($compat != 'MSSQL') ? $auto_increment : '';
$GLOBALS['dbi']->freeResult($result);
return $schema_create . ($add_semicolon ? ';' . $crlf : '');
return $warning . $schema_create . ($add_semicolon ? ';' . $crlf : '');
} // end of the 'getTableDef()' function
/**
@ -1698,16 +1759,33 @@ class ExportSql extends ExportPlugin
__('Triggers') . ' ' . $formatted_table_name
)
. $this->_exportComment();
$used_alias = false;
$trigger_query = '';
foreach ($triggers as $trigger) {
if (! empty($GLOBALS['sql_drop_table'])) {
$dump .= $trigger['drop'] . ';' . $crlf;
$trigger_query .= $trigger['drop'] . ';' . $crlf;
}
$dump .= 'DELIMITER ' . $delimiter . $crlf;
$dump .= $this->replaceWithAliases(
$trigger['create'], $aliases, $db, $table
$trigger_query .= 'DELIMITER ' . $delimiter . $crlf;
$trigger_query .= $this->replaceWithAliases(
$trigger['create'], $aliases, $db, $table, $flag
);
$dump .= 'DELIMITER ;' . $crlf;
if ($flag) {
$used_alias = true;
}
$trigger_query .= 'DELIMITER ;' . $crlf;
}
// One warning per table.
if ($used_alias) {
$dump .= $this->_exportComment(
__('It appears your table uses triggers;')
)
. $this->_exportComment(
__('alias export may not work reliably in all cases.')
)
. $this->_exportComment();
}
$dump .= $trigger_query;
}
break;
case 'create_view':
@ -1722,10 +1800,11 @@ class ExportSql extends ExportPlugin
// delete the stand-in table previously created (if any)
if ($export_type != 'table') {
$dump .= 'DROP TABLE IF EXISTS '
. PMA_Util::backquote($table) . ';' . $crlf;
. PMA_Util::backquote($table_alias) . ';' . $crlf;
}
$dump .= $this->getTableDef(
$db, $table, $crlf, $error_url, $dates, true, true
$db, $table, $crlf, $error_url, $dates,
true, true, true, $aliases
);
} else {
$dump .=
@ -1739,10 +1818,10 @@ class ExportSql extends ExportPlugin
// delete the stand-in table previously created (if any)
if ($export_type != 'table') {
$dump .= 'DROP TABLE IF EXISTS '
. PMA_Util::backquote($table) . ';' . $crlf;
. PMA_Util::backquote($table_alias) . ';' . $crlf;
}
$dump .= $this->_getTableDefForView(
$db, $table, $crlf, true
$db, $table, $crlf, true, $aliases
);
}
break;
@ -1753,7 +1832,7 @@ class ExportSql extends ExportPlugin
)
. $this->_exportComment();
// export a stand-in definition to resolve view dependencies
$dump .= $this->getTableDefStandIn($db, $table, $crlf);
$dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases);
} // end switch
// this one is built by getTableDef() to use in table copy/move
@ -1837,8 +1916,12 @@ class ExportSql extends ExportPlugin
$field_set = array();
for ($j = 0; $j < $fields_cnt; $j++) {
$col_as = $fields_meta[$j]->name;
if (!empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
}
$field_set[$j] = PMA_Util::backquoteCompat(
$fields_meta[$j]->name,
$col_as,
$compat,
$sql_backquotes
);
@ -2235,11 +2318,14 @@ class ExportSql extends ExportPlugin
* @param array $aliases Alias information for db/table/column
* @param string $db the database name
* @param string $table the tablename
* @param string &$flag the flag denoting whether any replacement was done
*
* @return string query replaced with aliases
*/
public function replaceWithAliases($sql_query, $aliases, $db, $table)
{
public function replaceWithAliases(
$sql_query, $aliases, $db, $table = '', &$flag = null
) {
$flag = false;
// Return original sql query if no aliases are provided.
if (!is_array($aliases) || empty($aliases) || empty($sql_query)) {
return $sql_query;
@ -2249,7 +2335,10 @@ class ExportSql extends ExportPlugin
);
$supported_query_ons = array(
'TABLE' => true,
'TRIGGER' => true
'VIEW' => true,
'TRIGGER' => true,
'FUNCTION' => true,
'PROCEDURE' => true
);
$identifier_types = array(
'alpha_identifier',
@ -2276,8 +2365,15 @@ class ExportSql extends ExportPlugin
for ($i = 0; $i < $size && !$query_end; $i++) {
$type = $tokens[$i]['type'];
$data = $tokens[$i]['data'];
$data_next = isset($tokens[$i+1]['data'])
? $tokens[$i+1]['data'] : '';
$data_prev = ($i > 0) ? $tokens[$i-1]['data'] : '';
$d_unq = PMA_Util::unQuote($data);
$d_unq_next = PMA_Util::unQuote($data_next);
$d_unq_prev = PMA_Util::unQuote($data_prev);
$d_upper = strtoupper($d_unq);
$d_upper_next = strtoupper($d_unq_next);
$d_upper_prev = strtoupper($d_unq_prev);
$pos = $tokens[$i]['pos'] + $offset;
if ($type === 'alpha_reservedWord') {
if ($query_type === ''
@ -2295,13 +2391,14 @@ class ExportSql extends ExportPlugin
// replace create table name
if (!$in_create_table_fields
&& in_array($type, $identifier_types)
&& isset($aliases[$db]['tables'][$table]['alias'])
&& !empty($aliases[$db]['tables'][$table]['alias'])
) {
$sql_query = $this->substituteAlias(
$sql_query, $data,
$aliases[$db]['tables'][$table]['alias'],
$pos, $offset
);
$flag = true;
} elseif ($type === 'punct_bracket_open_round') {
// CREATE TABLE fields started
if (!$in_create_table_fields) {
@ -2330,15 +2427,24 @@ class ExportSql extends ExportPlugin
) {
$table = $d_unq;
$ref_table_seen = true;
if (!empty($aliases[$db]['tables'][$table]['alias'])) {
$sql_query = $this->substituteAlias(
$sql_query, $data,
$aliases[$db]['tables'][$table]['alias'],
$pos, $offset
);
$flag = true;
}
// Replace column names
} elseif (in_array($type, $identifier_types)
&& isset($aliases[$db]['tables'][$table]['columns'][$d_unq])
&& !empty($aliases[$db]['tables'][$table]['columns'][$d_unq])
) {
$sql_query = $this->substituteAlias(
$sql_query, $data,
$aliases[$db]['tables'][$table]['columns'][$d_unq],
$pos, $offset
);
$flag = true;
}
// CREATE TRIGGER - Alias replacement
} elseif ($query_type === 'CREATE' && $query_on === 'TRIGGER') {
@ -2349,7 +2455,7 @@ class ExportSql extends ExportPlugin
$on_seen = true;
} elseif ($on_seen && in_array($type, $identifier_types)) {
if (!$ref_table_seen
&& isset($aliases[$db]['tables'][$d_unq]['alias'])
&& !empty($aliases[$db]['tables'][$d_unq]['alias'])
) {
$ref_table_seen = true;
$sql_query = $this->substituteAlias(
@ -2357,25 +2463,49 @@ class ExportSql extends ExportPlugin
$aliases[$db]['tables'][$d_unq]['alias'],
$pos, $offset
);
$flag = true;
} else {
// search for identifiers
// search for identifier alias
$alias = $this->getAlias($aliases, $d_unq);
if (!empty($alias)) {
$sql_query = $this->substituteAlias(
$sql_query, $data, $alias, $pos, $offset
);
$flag = true;
}
}
}
// CREATE PROCEDURE|FUNCTION|VIEW - Alias replacement
} elseif ($query_type === 'CREATE'
&& ($query_on === 'FUNCTION'
|| $query_on === 'PROCEDURE'
|| $query_on === 'VIEW')
) {
// LANGUAGE SQL | (READS|MODIFIES) SQL DATA
// characteristics are skipped
if ($type === 'alpha_identifier'
&& (($d_upper === 'LANGUAGE' && $d_upper_next === 'SQL')
|| ($d_upper === 'DATA' && $d_upper_prev === 'SQL'))
) {
continue;
// No need to process further in case of VIEW
// when 'WITH' keyword has been detected
} elseif ($query_on === 'VIEW'
&& $type === 'alpha_reservedWord' && $d_upper === 'WITH'
) {
$query_end = true;
} elseif (in_array($type, $identifier_types)) {
// search for identifier alias
$alias = $this->getAlias($aliases, $d_unq);
if (!empty($alias)) {
$sql_query = $this->substituteAlias(
$sql_query, $data, $alias, $pos, $offset
);
$flag = true;
};
}
}
}
if ($query_type === 'CREATE' && $query_on === 'TRIGGER') {
$warning = $this->_exportComment()
. $this->_exportComment(__('It appears your table uses triggers;'))
. $this->_exportComment(__('alias export may not work reliably in all cases.'))
. $this->_exportComment();
PMA_exportOutputHandler($warning);
}
return $sql_query;
}
@ -2418,10 +2548,10 @@ class ExportSql extends ExportPlugin
*/
public function initAlias($aliases, &$db, &$table = null)
{
if (isset($aliases[$db]['tables'][$table]['alias'])) {
if (!empty($aliases[$db]['tables'][$table]['alias'])) {
$table = $aliases[$db]['tables'][$table]['alias'];
}
if (isset($aliases[$db]['alias'])) {
if (!empty($aliases[$db]['alias'])) {
$db = $aliases[$db]['alias'];
}
}
@ -2431,27 +2561,35 @@ class ExportSql extends ExportPlugin
*
* @param array $aliases Alias information for db/table/column
* @param string $id the identifier to be searched
* @param string $type db/tbl/col or any combination of them
* representing what to be searched
*
* @return string alias of the identifier if found or ''
*/
public function getAlias($aliases, $id)
public function getAlias($aliases, $id, $type = 'dbtblcol')
{
// search each database
foreach ($aliases as $db_key => $db) {
// check if id is database and has alias
if ($db_key === $id && !empty($db['alias'])) {
if (stristr($type, 'db') !== false
&& $db_key === $id && !empty($db['alias'])
) {
return $db['alias'];
}
// search each of its tables
foreach ($db['tables'] as $table_key => $table) {
// check if id is table and has alias
if ($table_key === $id && !empty($table['alias'])) {
if (stristr($type, 'tbl') !== false
&& $table_key === $id && !empty($table['alias'])
) {
return $table['alias'];
}
// search each of its columns
foreach ($table['columns'] as $col_key => $col) {
// check if id is column
if ($col_key === $id) {
if (stristr($type, 'col') !== false
&& $col_key === $id && !empty($col)
) {
return $col;
}
}

View File

@ -494,6 +494,7 @@ $PMA_SQPdata_reserved_word = array (
'INDEXES',
'INFILE',
'INNER',
'INOUT',
'INSERT',
'INSERT_ID',
'INSERT_METHOD',
@ -541,6 +542,7 @@ $PMA_SQPdata_reserved_word = array (
'MINUTE_SECOND',
'MIN_ROWS',
'MODE',
'MODIFIES',
'MODIFY',
'MONTH',
'MRG_MYISAM',
@ -559,6 +561,7 @@ $PMA_SQPdata_reserved_word = array (
'OPTIONALLY',
'OR',
'ORDER',
'OUT',
'OUTER',
'OUTFILE',
'PACK_KEYS',
@ -581,6 +584,7 @@ $PMA_SQPdata_reserved_word = array (
'RAID_TYPE',
'RANGE', // 5.1
'READ',
'READS',
'READ_ONLY', // 5.1
'READ_WRITE', // 5.1
'REFERENCES',

View File

@ -143,6 +143,23 @@ class PMA_DisplayExport_Test extends PHPUnit_Framework_TestCase
$single_table = "single_table";
PMA_Table::$cache[$db][$table]['ENGINE'] = "MERGE";
$columns_info = array(
'test_column1' => array(
'COLUMN_NAME' => 'test_column1'
),
'test_column2' => array(
'COLUMN_NAME' => 'test_column2'
)
);
$dbi = $this->getMockBuilder('PMA_DatabaseInterface')
->disableOriginalConstructor()
->getMock();
$dbi->expects($this->any())->method('getColumnsFull')
->will($this->returnValue($columns_info));
$GLOBALS['dbi'] = $dbi;
/* Scan for plugins */
$export_list = PMA_getPlugins(
"export",
@ -217,7 +234,34 @@ class PMA_DisplayExport_Test extends PHPUnit_Framework_TestCase
$html
);
//validate 5: PMA_getHtmlForExportOptionsOutput
//validate 5: PMA_getHtmlForAliasModalDialog
$this->assertContains(
'<div id="alias_modal" class="hide" title="'
. 'Rename exported databases/tables/columns">',
$html
);
$this->assertContains(
'Select database',
$html
);
$this->assertContains(
'Select table',
$html
);
$this->assertContains(
'New database name',
$html
);
$this->assertContains(
'New table name',
$html
);
$this->assertContains(
'test_column',
$html
);
//validate 6: PMA_getHtmlForExportOptionsOutput
$this->assertContains(
'<div class="exportoptions" id="output">',
$html
@ -227,7 +271,7 @@ class PMA_DisplayExport_Test extends PHPUnit_Framework_TestCase
$html
);
//validate 6: PMA_getHtmlForExportOptionsFormat
//validate 7: PMA_getHtmlForExportOptionsFormat
$this->assertContains(
'<div class="exportoptions" id="format">',
$html
@ -237,4 +281,72 @@ class PMA_DisplayExport_Test extends PHPUnit_Framework_TestCase
$html
);
}
/**
* Test for PMA_getHtmlForAliasModalDialog
*
* @return void
*/
public function testPMAGetHtmlForAliasModalDialog()
{
$columns_info = array(
'test\'_db' => array(
'test_<b>table' => array(
'co"l1' => array(
'COLUMN_NAME' => 'co"l1'
),
'col<2' => array(
'COLUMN_NAME' => 'col<2'
)
)
)
);
$dbi = $this->getMockBuilder('PMA_DatabaseInterface')
->disableOriginalConstructor()
->getMock();
$dbi->expects($this->any())->method('getColumnsFull')
->will($this->returnValue($columns_info));
$GLOBALS['dbi'] = $dbi;
$html = PMA_getHtmlForAliasModalDialog();
$this->assertContains(
'<div id="alias_modal" class="hide" title="'
. 'Rename exported databases/tables/columns">',
$html
);
$this->assertContains(
'test\'_db',
$html
);
$this->assertContains(
'test_&lt;b&gt;table',
$html
);
$this->assertContains(
'col&lt;2',
$html
);
$this->assertContains(
'co&quot;l1',
$html
);
$this->assertContains(
'<hr/>',
$html
);
$name_attr = 'aliases[test\'_db][tables][test_&lt;b&gt;table][alias]';
$id_attr = substr(md5($name_attr), 0, 12);
$this->assertContains(
'<input type="text" name="' . $name_attr . '" '
. 'id="' . $id_attr . '" placeholder="'
. 'test_&lt;b&gt;table alias" class=""/>',
$html
);
}
}

View File

@ -0,0 +1,110 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* tests for export.lib.php
*
* @package PhpMyAdmin-test
*/
/*
* Include to test.
*/
require_once 'libraries/export.lib.php';
/**
* class PMA_DisplayExport_Test
*
* this class is for testing export.lib.php functions
*
* @package PhpMyAdmin-test
* @group large
*/
class PMA_Export_Test extends PHPUnit_Framework_TestCase
{
/**
* Test for setUp
*
* @return void
*/
public function setUp()
{
}
/**
* Test for PMA_mergeAliases
*
* @return void
*/
public function testPMAMergeAliases()
{
$aliases1 = array(
'test_db' => array(
'alias' => 'aliastest',
'tables' => array(
'foo' => array(
'alias' => 'foobar',
'columns' => array(
'bar' => 'foo',
'baz' => 'barbaz'
)
),
'bar' => array(
'alias' => 'foobaz',
'columns' => array(
'a' => 'a_alias',
'b' => 'b'
)
)
)
)
);
$aliases2 = array(
'test_db' => array(
'alias' => 'test',
'tables' => array(
'foo' => array(
'columns' => array(
'bar' => 'foobar'
)
),
'baz' => array(
'columns' => array(
'a' => 'x'
)
)
)
)
);
$expected = array(
'test_db' => array(
'alias' => 'test',
'tables' => array(
'foo' => array(
'alias' => 'foobar',
'columns' => array(
'bar' => 'foobar',
'baz' => 'barbaz'
)
),
'bar' => array(
'alias' => 'foobaz',
'columns' => array(
'a' => 'a_alias',
'b' => 'b'
)
),
'baz' => array(
'columns' => array(
'a' => 'x'
)
)
)
)
);
$actual = PMA_mergeAliases($aliases1, $aliases2);
$this->assertEquals($expected, $actual);
}
}

View File

@ -2670,3 +2670,26 @@ table.show_create {
table.show_create td {
border-right: 1px solid #bbb;
}
#alias_modal table th {
vertical-align: middle;
padding-left: 1em;
}
#alias_modal label.col-2 {
min-width: 20%;
display: inline-block;
}
#alias_modal select {
width: 25%;
margin-right: 2em;
}
#alias_modal label {
font-weight: bold;
}
.ui-dialog {
position: fixed;
}

View File

@ -2966,3 +2966,26 @@ table.show_create {
table.show_create td {
border-right: 1px solid #bbb;
}
#alias_modal table th {
vertical-align: middle;
padding-left: 1em;
}
#alias_modal label.col-2 {
min-width: 20%;
display: inline-block;
}
#alias_modal select {
width: 25%;
margin-right: 2em;
}
#alias_modal label {
font-weight: bold;
}
.ui-dialog {
position: fixed;
}