diff --git a/ChangeLog b/ChangeLog
index 79f42064e8..0f80ac7b1a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,7 +20,9 @@ phpMyAdmin - ChangeLog
- bug #3962 Proper escaping of JSON export
+ rfe #1328 Optional ReCAPTCHA support
+ rfe #1434 Improvements to the table browsing navigation bar
-+ rfe #1405 Find and Replacing column wise
++ rfe #1233 and rfe #1283 Improvements to Relation View interface
++ rfe #175 Allow cross-database relations
++ rfe #487 and rfe #1405 Find and Replacing column wise
4.0.5.0 (not yet released)
- bug #3977 Not detected configuration storage
diff --git a/doc/faq.rst b/doc/faq.rst
index 824ccb340d..4194d6ef93 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -881,8 +881,7 @@ TableSeparator or disabling that feature.
3.6 What is currently not supported in phpMyAdmin about InnoDB?
---------------------------------------------------------------
-In Relation view, being able to choose a table in another database, or
-having more than one index column in the foreign key. In Query-by-
+In Relation view, having more than one index column in the foreign key. In Query-by-
example (Query), automatic generation of the query LEFT JOIN from the
foreign table.
@@ -1378,7 +1377,7 @@ look for the word "upload" in this document.
---------------------------------------------------------
Here is an example with the tables persons, towns and countries, all
-located in the database mydb. If you don't have a ``pma__relation``
+located in the database "mydb". If you don't have a ``pma__relation``
table, create it as explained in the configuration section. Then
create the example tables:
@@ -1416,8 +1415,10 @@ create the example tables:
To setup appropriate links and display information:
* on table "REL\_persons" click Structure, then Relation view
-* in Links, for "town\_code" choose "REL\_towns->code"
-* in Links, for "country\_code" choose "REL\_countries->country\_code"
+* for "town\_code", choose from dropdowns, "mydb", "REL\_towns", "code"
+ for foreign database, table and column respectively
+* for "country\_code", choose from dropdowns, "mydb", "REL\_countries",
+ "country\_code" for foreign database, table and column respectively
* on table "REL\_towns" click Structure, then Relation view
* in "Choose column to display", choose "description"
* repeat the two previous steps for table "REL\_countries"
diff --git a/js/tbl_relation.js b/js/tbl_relation.js
index 7d72a1e872..2925096ceb 100644
--- a/js/tbl_relation.js
+++ b/js/tbl_relation.js
@@ -5,30 +5,123 @@
*/
function show_hide_clauses($thisDropdown)
{
- // here, one span contains the label and the clause dropdown
- // and we have one span for ON DELETE and one for ON UPDATE
- //
- if ($thisDropdown.val() !== '') {
- $thisDropdown.parent().nextAll('span').show();
- } else {
+ if ($thisDropdown.val() == '') {
$thisDropdown.parent().nextAll('span').hide();
+ } else {
+ if ($thisDropdown.is('select[name^="destination_foreign_column"]')) {
+ $thisDropdown.parent().nextAll('span').show();
+ }
}
}
+/**
+ * Retrieves and populates dropdowns to the left based on the selected value
+ *
+ * @param $dropdown the dropdown whose value got changed
+ */
+function getDropdownValues($dropdown) {
+ var foreignDb = null, foreignTable = null;
+ var $tableDd, $columnDd;
+ var foreign = '';
+ // if the changed dropdown is for foreign key constraints
+ if ($dropdown.is('select[name^="destination_foreign"]')) {
+ $tableDd = $dropdown.parent().find('select[name^="destination_foreign_table"]');
+ $columnDd = $dropdown.parent().find('select[name^="destination_foreign_column"]');
+ foreign = '_foreign';
+ } else { // internal relations
+ $tableDd = $dropdown.parent().find('select[name^="destination_table"]');
+ $columnDd = $dropdown.parent().find('select[name^="destination_column"]');
+ }
+
+ // if the changed dropdown is a database selector
+ if ($dropdown.is('select[name^="destination' + foreign + '_db"]')) {
+ foreignDb = $dropdown.val();
+ // if no database is selected empty table and column dropdowns
+ if (foreignDb == '') {
+ setDropdownValues($tableDd, []);
+ setDropdownValues($columnDd, []);
+ return;
+ }
+ } else { // if a table selector
+ foreignDb = $dropdown.parent()
+ .find('select[name^="destination' + foreign + '_db"]').val();
+ foreignTable = $dropdown.val();
+ // if no table is selected empty the column dropdown
+ if (foreignTable == '') {
+ setDropdownValues($columnDd, []);
+ return;
+ }
+ }
+ var $msgbox = PMA_ajaxShowMessage();
+ var $form = $dropdown.parents('form');
+ var url = 'tbl_relation.php?getDropdownValues=true&ajax_request=true'
+ + '&token=' + $form.find('input[name="token"]').val()
+ + '&db=' + $form.find('input[name="db"]').val()
+ + '&table=' + $form.find('input[name="table"]').val()
+ + '&foreign=' + (foreign != '')
+ + '&foreignDb=' + encodeURIComponent(foreignDb)
+ + (foreignTable !== null ?
+ '&foreignTable=' + encodeURIComponent(foreignTable) : ''
+ );
+ $.ajax({
+ url: url,
+ datatype: 'json',
+ success: function(data) {
+ PMA_ajaxRemoveMessage($msgbox);
+ if (data.success) {
+ // if the changed dropdown is a database selector
+ if (foreignTable == null) {
+ // set values for table and column dropdowns
+ setDropdownValues($tableDd, data.tables);
+ setDropdownValues($columnDd, []);
+ } else { // if a table selector
+ // set values for the column dropdown
+ setDropdownValues($columnDd, data.columns);
+ }
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+}
+
+function setDropdownValues($dropdown, values) {
+ $dropdown.empty();
+ var optionsAsString = '';
+ // add an empty string to the beginning for empty selection
+ values.unshift('');
+ $.each(values, function() {
+ optionsAsString += "";
+ })
+ $dropdown.append($(optionsAsString));
+}
+
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('tbl_relation.js', function () {
- $('select.referenced_column_dropdown').unbind('change');
+ $('select[name^="destination_foreign"]').unbind('change');
+ $('select[name^="destination_db"],'
+ + ' select[name^="destination_table"],'
+ + ' select[name^="destination_foreign_db"],'
+ + ' select[name^="destination_foreign_table"]').unbind('change');
});
AJAX.registerOnload('tbl_relation.js', function () {
// initial display
- $('select.referenced_column_dropdown').each(function (index, one_dropdown) {
+ $('select[name^="destination_foreign_column"]').each(function (index, one_dropdown) {
show_hide_clauses($(one_dropdown));
});
// change
- $('select.referenced_column_dropdown').change(function () {
+ $('select[name^="destination_foreign"]').change(function () {
show_hide_clauses($(this));
});
+
+ $('select[name^="destination_db"],'
+ + ' select[name^="destination_table"],'
+ + ' select[name^="destination_foreign_db"],'
+ + ' select[name^="destination_foreign_table"]')
+ .change(function() {
+ getDropdownValues($(this));
+ });
});
diff --git a/libraries/Table.class.php b/libraries/Table.class.php
index 1f85d52b10..ef145efdba 100644
--- a/libraries/Table.class.php
+++ b/libraries/Table.class.php
@@ -1314,10 +1314,11 @@ class PMA_Table
* - UNIQUE(x,y) // NONE
*
* @param bool $backquoted whether to quote name with backticks ``
+ * @param bool $fullName whether to include full name of the table as a prefix
*
* @return array
*/
- public function getUniqueColumns($backquoted = true)
+ public function getUniqueColumns($backquoted = true, $fullName = true)
{
$sql = $GLOBALS['dbi']->getTableIndexesSql(
$this->getDbName(),
@@ -1335,7 +1336,7 @@ class PMA_Table
if (count($index) > 1) {
continue;
}
- $return[] = $this->getFullName($backquoted) . '.'
+ $return[] = ($fullName ? $this->getFullName($backquoted) . '.' : '')
. ($backquoted ? PMA_Util::backquote($index[0]) : $index[0]);
}
diff --git a/libraries/operations.lib.php b/libraries/operations.lib.php
index 97a11a28da..d0e4262aab 100644
--- a/libraries/operations.lib.php
+++ b/libraries/operations.lib.php
@@ -1427,8 +1427,8 @@ function PMA_getHtmlForReferentialIntegrityCheck($foreign, $url_params)
. ''
- . $master . ' -> ' . $arr['foreign_table'] . '.'
- . $arr['foreign_field']
+ . $master . ' -> ' . $arr['foreign_db'] . '.'
+ . $arr['foreign_table'] . '.' . $arr['foreign_field']
. '' . "\n";
} // foreach $foreign
$html_output .= '';
diff --git a/libraries/pmd_common.php b/libraries/pmd_common.php
index 49ea3b6540..284c7fcc92 100644
--- a/libraries/pmd_common.php
+++ b/libraries/pmd_common.php
@@ -263,4 +263,18 @@ function get_tab_pos()
);
return count($tab_pos) ? $tab_pos : null;
}
+
+/**
+ * Prepares XML output for js/pmd/ajax.js to display a message
+ *
+ */
+function PMD_return_upd($b, $ret)
+{
+ // not sure where this was defined...
+ global $K;
+
+ header("Content-Type: text/xml; charset=utf-8");
+ header("Cache-Control: no-cache");
+ die('