From 714ab04d5135136e32fc08c19e191eadeeb6e343 Mon Sep 17 00:00:00 2001 From: Madhura Jayaratne Date: Wed, 17 Jun 2015 11:47:22 +0530 Subject: [PATCH] bug #4795 Query builder: missing joint for the intermediary table Signed-off-by: Madhura Jayaratne --- ChangeLog | 1 + libraries/DBQbe.class.php | 67 +++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index d38c43db3c..db042d2ec5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -58,6 +58,7 @@ phpMyAdmin - ChangeLog + rfe #1594 Use plain English descriptors instead of script names for icon link destinations + rfe #1541 Disable foreign key checks for some operations - bug #4957 "With selected" links doesn't work in table browse +- bug #4795 Query builder: missing joint for the intermediary table 4.4.10.0 (not yet released) - bug #4950 Issues in database selection for replication diff --git a/libraries/DBQbe.class.php b/libraries/DBQbe.class.php index 43a6808347..480d166872 100644 --- a/libraries/DBQbe.class.php +++ b/libraries/DBQbe.class.php @@ -1575,7 +1575,6 @@ class PMA_DbQbe */ private function _getJoinForFromClause($searchTables, $searchColumns) { - // $relations[master_table][foreign_table] => clause $relations = array(); @@ -1603,13 +1602,68 @@ class PMA_DbQbe $finalized[$master] = ''; } // Fill the $finalized array with JOIN clauses for each table - $this->_fillJoinClauses($finalized, $relations); + $this->_fillJoinClauses($finalized, $relations, $searchTables); + + // JOIN clause + $join = ''; // Tables that can not be combined with the table cluster // that includes master table $unfinalized = array_diff($searchTables, array_keys($finalized)); - // Add these tables as cartesian product before joined tables - $join = implode(', ', array_map('PMA_Util::backquote', $unfinalized)); + if (count($unfinalized) > 0) { + + // We need to look for intermediary tables to JOIN unfinalized tables + // Heuristic to chose intermediary tables is to look for tables + // having relationships with unfinalized tables + foreach ($unfinalized as $oneTable) { + + $references = PMA_getChildReferences($this->_db, $oneTable); + foreach ($references as $column => $columnReferences) { + foreach ($columnReferences as $reference) { + + // Only from this schema + if ($reference['table_schema'] == $this->_db) { + $table = $reference['table_name']; + + $this->_loadRelationsForTable($relations, $table); + + // Make copies + $tempFinalized = $finalized; + $tempSearchTables = $searchTables; + $tempSearchTables[] = $table; + + $this->_fillJoinClauses( + $tempFinalized, $relations, $tempSearchTables + ); + + $tempUnfinalized = array_diff( + $tempSearchTables, array_keys($tempFinalized) + ); + + // Take greedy approach, if the unfinalized count + // drops we keep the new tables + if (count($tempUnfinalized) < count($unfinalized)) { + $finalized = $tempFinalized; + $searchTables = $tempSearchTables; + } + + if (count($tempUnfinalized) == 0) { + break 3; + } + } + } + } + } + + $unfinalized = array_diff($searchTables, array_keys($finalized)); + // If there are still unfinalized tables + if (count($unfinalized) > 0) { + // Add these tables as cartesian product before joined tables + $join .= implode( + ', ', array_map('PMA_Util::backquote', $unfinalized) + ); + } + } $first = true; // Add joined tables @@ -1679,11 +1733,12 @@ class PMA_DbQbe * * @return void */ - private function _fillJoinClauses(&$finalized, $relations) + private function _fillJoinClauses(&$finalized, $relations, $searchTables) { while (true) { $added = false; - foreach ($relations as $masterTable => $foreignData) { + foreach ($searchTables as $masterTable) { + $foreignData = $relations[$masterTable]; foreach ($foreignData as $foreignTable => $clause) { if (! isset($finalized[$masterTable]) && isset($finalized[$foreignTable])