diff --git a/tbl_relation.php b/tbl_relation.php index 0ece707bf0..638e8c680f 100644 --- a/tbl_relation.php +++ b/tbl_relation.php @@ -143,13 +143,14 @@ if (isset($destination) && $cfgRelation['relwork']) { // u p d a t e s f o r f o r e i g n k e y s // (for now, one index name only; we keep the definitions if the // foreign db is not the same) -// I use $sql_query to be able to display directly the query via -// getMessage() if (isset($_REQUEST['destination_foreign'])) { $display_query = ''; $seen_error = false; + $shown_error = false; foreach ($_REQUEST['destination_foreign'] as $master_field_md5 => $foreign_string) { + $create = false; + $drop = false; // Map the fieldname's md5 back to it's real name $master_field = $multi_edit_columns_name[$master_field_md5]; @@ -157,85 +158,66 @@ if (isset($_REQUEST['destination_foreign'])) { if (! empty($foreign_string)) { list($foreign_db, $foreign_table, $foreign_field) = PMA_backquoteSplit($foreign_string); - - if ( isset($existrel_foreign[$master_field]) - && ( PMA_Util::backquote($existrel_foreign[$master_field]['foreign_db']) != $foreign_db + if (! isset($existrel_foreign[$master_field])) { + // no key defined for this field + $create = true; + } elseif (PMA_Util::backquote($existrel_foreign[$master_field]['foreign_db']) != $foreign_db || PMA_Util::backquote($existrel_foreign[$master_field]['foreign_table']) != $foreign_table || PMA_Util::backquote($existrel_foreign[$master_field]['foreign_field']) != $foreign_field || $_REQUEST['constraint_name'][$master_field_md5] != $existrel_foreign[$master_field]['constraint'] || ($_REQUEST['on_delete'][$master_field_md5] != (! empty($existrel_foreign[$master_field]['on_delete']) ? $existrel_foreign[$master_field]['on_delete'] : 'RESTRICT')) - || ($_REQUEST['on_update'][$master_field_md5] != (! empty($existrel_foreign[$master_field]['on_update']) ? $existrel_foreign[$master_field]['on_update'] : 'RESTRICT'))) + || ($_REQUEST['on_update'][$master_field_md5] != (! empty($existrel_foreign[$master_field]['on_update']) ? $existrel_foreign[$master_field]['on_update'] : 'RESTRICT')) ) { // another foreign key is already defined for this field - // or - // an option has been changed for ON DELETE or ON UPDATE - // remove existing key - $sql_query_drop = 'ALTER TABLE ' . PMA_Util::backquote($table) - . ' DROP FOREIGN KEY ' - . PMA_Util::backquote( - $existrel_foreign[$master_field]['constraint'] - ); - $sql_query_drop .= ';'; - $display_query .= $sql_query_drop . "\n"; - } // end if... - - // The next few lines are repeated below, so they - // could be put in an include file - // Note: I tried to enclose the db and table name with - // backquotes but MySQL 4.0.16 did not like the syntax - // (for example: `base2`.`table1`) - $sql_query = 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD '; - // if user entered a constraint name - if (! empty($_REQUEST['constraint_name'][$master_field_md5])) { - $sql_query .= ' CONSTRAINT ' . PMA_Util::backquote( - $_REQUEST['constraint_name'][$master_field_md5] - ); - } - $sql_query .= ' FOREIGN KEY (' - . PMA_Util::backquote($master_field) . ')' - . ' REFERENCES ' . $foreign_db . '.' . $foreign_table - . '(' . $foreign_field . ')'; - if (! empty($_REQUEST['on_delete'][$master_field_md5])) { - $sql_query .= ' ON DELETE ' - . $options_array[$_REQUEST['on_delete'][$master_field_md5]]; - } - if (! empty($_REQUEST['on_update'][$master_field_md5])) { - $sql_query .= ' ON UPDATE ' - . $options_array[$_REQUEST['on_update'][$master_field_md5]]; - } - $sql_query .= ';'; - $display_query .= $sql_query . "\n"; - + // or an option has been changed for ON DELETE or ON UPDATE + $drop = true; + $create = true; + } // end if... else.... } elseif (isset($existrel_foreign[$master_field])) { - $sql_query = 'ALTER TABLE ' . PMA_Util::backquote($table) - . ' DROP FOREIGN KEY ' - . PMA_Util::backquote( - $existrel_foreign[$master_field]['constraint'] - ); - $sql_query .= ';'; - $display_query .= $sql_query . "\n"; + $drop = true; } // end if... else.... - if (! empty($sql_query)) { - if (! empty($sql_query_drop)) { - PMA_DBI_try_query($sql_query_drop); - $tmp_error_drop = PMA_DBI_getError(); + $tmp_error_drop = false; + if ($drop) { + $drop_query = PMA_getSQLToDropForeignKey( + $table, $existrel_foreign[$master_field]['constraint'] + ); + $display_query .= $drop_query . "\n"; + PMA_DBI_try_query($drop_query); + $tmp_error_drop = PMA_DBI_getError(); + + if (! empty($tmp_error_drop)) { + $seen_error = true; + continue; } - PMA_DBI_try_query($sql_query); - $tmp_error = PMA_DBI_getError(); - if (! empty($tmp_error)) { + } + $tmp_error_create = false; + if ($create) { + $create_query = PMA_getSQLToCreateForeignKey( + $table, $master_field, $foreign_db, $foreign_table, $foreign_field, + $_REQUEST['constraint_name'][$master_field_md5], + $options_array[$_REQUEST['on_delete'][$master_field_md5]], + $options_array[$_REQUEST['on_update'][$master_field_md5]] + ); + + $display_query .= $create_query . "\n"; + PMA_DBI_try_query($create_query); + $tmp_error_create = PMA_DBI_getError(); + if (! empty($tmp_error_create)) { $seen_error = true; } - if (substr($tmp_error, 1, 4) == '1216' - || substr($tmp_error, 1, 4) == '1452' + if (substr($tmp_error_create, 1, 4) == '1216' + || substr($tmp_error_create, 1, 4) == '1452' ) { - PMA_Util::mysqlDie($tmp_error, $sql_query, false, '', false); + PMA_Util::mysqlDie( + $tmp_error_create, $create_query, false, '', false + ); $html_output .= PMA_Util::showMySQLDocu( 'manual_Table_types', 'InnoDB_foreign_key_constraints' ) . "\n"; } - if (substr($tmp_error, 1, 4) == '1005') { + if (substr($tmp_error_create, 1, 4) == '1005') { $message = PMA_Message::error( __('Error creating foreign key on %1$s (check data types)') ); @@ -244,46 +226,34 @@ if (isset($_REQUEST['destination_foreign'])) { $html_output .= PMA_Util::showMySQLDocu( 'manual_Table_types', 'InnoDB_foreign_key_constraints' ) . "\n"; + $shown_error = true; } - if (! empty($tmp_error) && empty($tmp_error_drop)) { - // constraint might be dropped without creation of a new one + // this is an alteration and the old constraint has been dropped + // without creation of a new one + if ($drop && $create && empty($tmp_error_drop) + && ! empty($tmp_error_create) + ) { // a rollback may be better here - $sql_query_recreate = 'ALTER TABLE ' . PMA_Util::backquote($table) - . ' ADD ' - . ' CONSTRAINT ' . PMA_Util::backquote( - $existrel_foreign[$master_field]['constraint'] - ) - . ' FOREIGN KEY (' . PMA_Util::backquote($master_field) . ')' - . ' REFERENCES ' . PMA_Util::backquote( - $existrel_foreign[$master_field]['foreign_db'] - ) - . '.' . PMA_Util::backquote( - $existrel_foreign[$master_field]['foreign_table'] - ) - . '(' . PMA_Util::backquote( - $existrel_foreign[$master_field]['foreign_field'] - ) - . ')'; - if (! empty($existrel_foreign[$master_field]['on_delete'])) { - $sql_query_recreate .= ' ON DELETE ' - . $existrel_foreign[$master_field]['on_delete']; - } - if (! empty($existrel_foreign[$master_field]['on_update'])) { - $sql_query_recreate .= ' ON UPDATE ' - . $existrel_foreign[$master_field]['on_update']; - } - $sql_query_recreate .= ';'; + $sql_query_recreate = '# Restoring the dropped constraint...' . "\n"; + $sql_query_recreate .= PMA_getSQLToCreateForeignKey( + $table, $master_field, + PMA_Util::backquote($existrel_foreign[$master_field]['foreign_db']), + PMA_Util::backquote($existrel_foreign[$master_field]['foreign_table']), + PMA_Util::backquote($existrel_foreign[$master_field]['foreign_field']), + $existrel_foreign[$master_field]['constraint'], + $options_array[$existrel_foreign[$master_field]['on_delete']], + $options_array[$existrel_foreign[$master_field]['on_update']] + ); + $display_query .= $sql_query_recreate . "\n"; PMA_DBI_try_query($sql_query_recreate); - unset($sql_query_recreate); } - unset($tmp_error); - unset($tmp_error_drop); - $sql_query = ''; } } // end foreach if (!empty($display_query)) { if ($seen_error) { - $html_output .= PMA_Util::getMessage(__('Error'), null, 'error'); + if (! $shown_error) { + $html_output .= PMA_Util::getMessage(__('Error'), null, 'error'); + } } else { $html_output .= PMA_Util::getMessage( __('Your SQL query has been executed successfully'), @@ -406,17 +376,17 @@ if ($cfgRelation['relwork'] $columns = PMA_DBI_get_columns($db, $table); if (count($columns) > 0) { - + foreach ($columns as $row) { $save_row[] = $row; } - + $saved_row_cnt = count($save_row); $html_output .= '
' . '' . __('Relations'). '' . '' . ''; - + if ($cfgRelation['relwork']) { $html_output .= ''; } - + if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) { // this does not have to be translated, it's part of the MySQL syntax $html_output .= '
' . __('Column') . '' . __('Internal relation'); if (PMA_Util::isForeignKeySupported($tbl_storage_engine)) { @@ -429,7 +399,7 @@ if (count($columns) > 0) { } $html_output .= '' . __('Foreign key constraint') @@ -638,7 +608,7 @@ function PMA_generateDropdown( $html_output .= '>' . htmlspecialchars($one_label) . '' . "\n"; } $html_output .= '' . "\n"; - + return $html_output; } @@ -674,4 +644,56 @@ function PMA_backquoteSplit($text) } return($elements); } + +/** + * Returns the DROP query for a foreign key constraint + * + * @param string $table table of the foreign key + * @param string $fk foreign key name + * + * @return string DROP query for the foreign key constraint + */ +function PMA_getSQLToDropForeignKey($table, $fk) +{ + return 'ALTER TABLE ' . PMA_Util::backquote($table) + . ' DROP FOREIGN KEY ' . PMA_Util::backquote($fk) . ';'; +} + +/** + * Returns the SQL query for foreign key constraint creation + * + * @param string $table table name + * @param string $field field name + * @param string $foreignDb back-quoted foreign database name + * @param string $foreignTable back-quoted foreign table name + * @param string $foreignField back-quoted foreign field name + * @param string $name name of the constraint + * @param string $onDelete on delete action + * @param string $onUpdate on update action + * + * @return string SQL query for foreign key constraint creation + */ +function PMA_getSQLToCreateForeignKey($table, $field, $foreignDb, $foreignTable, + $foreignField, $name = null, $onDelete = null, $onUpdate = null +) { + $sql_query = 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD '; + // if user entered a constraint name + if (! empty($name)) { + $sql_query .= ' CONSTRAINT ' . PMA_Util::backquote($name); + } + + $sql_query .= ' FOREIGN KEY (' . PMA_Util::backquote($field) . ')' + . ' REFERENCES ' . $foreignDb . '.' . $foreignTable + . '(' . $foreignField . ')'; + + if (! empty($onDelete)) { + $sql_query .= ' ON DELETE ' . $onDelete; + } + if (! empty($onUpdate)) { + $sql_query .= ' ON UPDATE ' . $onUpdate; + } + $sql_query .= ';'; + + return $sql_query; +} ?>