Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpmyadmin/phpmyadmin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugues Peccatte <hugues.peccatte@gmail.com>2014-02-23 17:52:48 +0400
committerHugues Peccatte <hugues.peccatte@gmail.com>2014-02-23 17:52:48 +0400
commit8b84cf0d91669b4a359b2f20bb014a95d7b64013 (patch)
treec06a07397d770855df4eb869177b3371abc536d4
parentb7f5acff6b5c7bcc61cea2808a0bedc0bc317aa5 (diff)
Feature #569 Load/Save Query By Example
Implement possibility to save/load/delete a QBE on a DB. Signed-off-by: Hugues Peccatte <hugues.peccatte@gmail.com>
-rw-r--r--config.sample.inc.php3
-rw-r--r--db_qbe.php43
-rw-r--r--examples/config.manyhosts.inc.php1
-rw-r--r--examples/create_tables.sql84
-rw-r--r--examples/create_tables_drizzle.sql72
-rw-r--r--js/db_qbe.js55
-rw-r--r--libraries/DBQbe.class.php223
-rw-r--r--libraries/SavedSearches.php397
-rw-r--r--libraries/config.default.php9
-rw-r--r--libraries/config/setup.forms.php1
-rw-r--r--libraries/relation.lib.php8
-rw-r--r--test/libraries/PMA_relation_cleanup_test.php1
12 files changed, 796 insertions, 101 deletions
diff --git a/config.sample.inc.php b/config.sample.inc.php
index 83fe50cb96..2b3024d12d 100644
--- a/config.sample.inc.php
+++ b/config.sample.inc.php
@@ -60,6 +60,7 @@ $cfg['Servers'][$i]['AllowNoPassword'] = false;
// $cfg['Servers'][$i]['users'] = 'pma__users';
// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
+// $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
/* Contrib / Swekey authentication */
// $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf';
@@ -145,7 +146,7 @@ $cfg['SaveDir'] = '';
/**
* Should error reporting be enabled for JavaScript errors
*
- * default = 'ask'
+ * default = 'ask'
*/
//$cfg['SendErrorReports'] = 'ask';
diff --git a/db_qbe.php b/db_qbe.php
index e1ed199d1f..37845edbb4 100644
--- a/db_qbe.php
+++ b/db_qbe.php
@@ -19,6 +19,47 @@ $response = PMA_Response::getInstance();
// Gets the relation settings
$cfgRelation = PMA_getRelationsParam();
+$savedSearchList = array();
+$currentSearchId = null;
+if ($cfgRelation['savedsearcheswork']) {
+ include 'libraries/SavedSearches.php';
+ $header = $response->getHeader();
+ $scripts = $header->getScripts();
+ $scripts->addFile('db_qbe.js');
+
+ //Get saved search list.
+ $savedSearch = new PMA_SavedSearches($GLOBALS);
+ $savedSearch->setId($_REQUEST['searchId'])
+ ->setUsername($GLOBALS['cfg']['Server']['user'])
+ ->setDbname($_REQUEST['db'])
+ ->setSearchName($_REQUEST['searchName']);
+
+ //Criterias field is filled only when clicking on "Save search".
+ if (!empty($_REQUEST['action'])) {
+ if ('save' === $_REQUEST['action']) {
+ $saveResult = $savedSearch->setCriterias($_REQUEST)
+ ->save();
+ /*if (!$saveResult) {
+ $response->addHTML('raté');
+ exit();
+ }*/
+ } elseif ('delete' === $_REQUEST['action']) {
+ $deleteResult = $savedSearch->delete();
+ //After deletion, reset search.
+ $savedSearch = new PMA_SavedSearches($GLOBALS);
+ $savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
+ ->setDbname($_REQUEST['db']);
+ $_REQUEST = array();
+ } elseif ('load' === $_REQUEST['action']) {
+ $loadResult = $savedSearch->load();
+ }
+ //Else, it's an "update query"
+ }
+
+ $savedSearchList = $savedSearch->getList();
+ $currentSearchId = $savedSearch->getId();
+}
+
/**
* A query has been submitted -> (maybe) execute it
*/
@@ -52,7 +93,7 @@ if ($message_to_display) {
unset($message_to_display);
// create new qbe search instance
-$db_qbe = new PMA_DBQbe($GLOBALS['db']);
+$db_qbe = new PMA_DBQbe($GLOBALS['db'], $savedSearchList, $savedSearch);
/**
* Displays the Query by example form
diff --git a/examples/config.manyhosts.inc.php b/examples/config.manyhosts.inc.php
index b188aa8b86..bced1fca2c 100644
--- a/examples/config.manyhosts.inc.php
+++ b/examples/config.manyhosts.inc.php
@@ -47,4 +47,5 @@ foreach ($hosts as $host) {
$cfg['Servers'][$i]['users'] = 'pma__users';
$cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
$cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
+ $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
}
diff --git a/examples/create_tables.sql b/examples/create_tables.sql
index 0ac5654dc4..8ffbf5ef84 100644
--- a/examples/create_tables.sql
+++ b/examples/create_tables.sql
@@ -1,40 +1,40 @@
-- --------------------------------------------------------
-- SQL Commands to set up the pmadb as described in the documentation.
---
+--
-- This file is meant for use with MySQL 5 and above!
---
+--
-- This script expects the user pma to already be existing. If we would put a
-- line here to create him too many users might just use this script and end
-- up with having the same password for the controluser.
---
--- This user "pma" must be defined in config.inc.php (controluser/controlpass)
---
--- Please don't forget to set up the tablenames in config.inc.php
---
+--
+-- This user "pma" must be defined in config.inc.php (controluser/controlpass)
+--
+-- Please don't forget to set up the tablenames in config.inc.php
+--
-- --------------------------------------------------------
---
+--
-- Database : `phpmyadmin`
---
+--
CREATE DATABASE IF NOT EXISTS `phpmyadmin`
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
USE phpmyadmin;
-- --------------------------------------------------------
---
+--
-- Privileges
---
+--
-- (activate this statement if necessary)
-- GRANT SELECT, INSERT, DELETE, UPDATE ON `phpmyadmin`.* TO
-- 'pma'@localhost;
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__bookmark`
---
+--
CREATE TABLE IF NOT EXISTS `pma__bookmark` (
`id` int(11) NOT NULL auto_increment,
@@ -49,9 +49,9 @@ CREATE TABLE IF NOT EXISTS `pma__bookmark` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__column_info`
---
+--
CREATE TABLE IF NOT EXISTS `pma__column_info` (
`id` int(5) unsigned NOT NULL auto_increment,
@@ -70,9 +70,9 @@ CREATE TABLE IF NOT EXISTS `pma__column_info` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__history`
---
+--
CREATE TABLE IF NOT EXISTS `pma__history` (
`id` bigint(20) unsigned NOT NULL auto_increment,
@@ -89,9 +89,9 @@ CREATE TABLE IF NOT EXISTS `pma__history` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__pdf_pages`
---
+--
CREATE TABLE IF NOT EXISTS `pma__pdf_pages` (
`db_name` varchar(64) NOT NULL default '',
@@ -136,9 +136,9 @@ CREATE TABLE IF NOT EXISTS `pma__table_uiprefs` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__relation`
---
+--
CREATE TABLE IF NOT EXISTS `pma__relation` (
`master_db` varchar(64) NOT NULL default '',
@@ -155,9 +155,9 @@ CREATE TABLE IF NOT EXISTS `pma__relation` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__table_coords`
---
+--
CREATE TABLE IF NOT EXISTS `pma__table_coords` (
`db_name` varchar(64) NOT NULL default '',
@@ -172,9 +172,9 @@ CREATE TABLE IF NOT EXISTS `pma__table_coords` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__table_info`
---
+--
CREATE TABLE IF NOT EXISTS `pma__table_info` (
`db_name` varchar(64) NOT NULL default '',
@@ -187,9 +187,9 @@ CREATE TABLE IF NOT EXISTS `pma__table_info` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__designer_coords`
---
+--
CREATE TABLE IF NOT EXISTS `pma__designer_coords` (
`db_name` varchar(64) NOT NULL default '',
@@ -205,9 +205,9 @@ CREATE TABLE IF NOT EXISTS `pma__designer_coords` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__tracking`
---
+--
CREATE TABLE IF NOT EXISTS `pma__tracking` (
`db_name` varchar(64) NOT NULL,
@@ -250,7 +250,7 @@ CREATE TABLE IF NOT EXISTS `pma__users` (
`username` varchar(64) NOT NULL,
`usergroup` varchar(64) NOT NULL,
PRIMARY KEY (`username`,`usergroup`)
-)
+)
COMMENT='Users and their assignments to user groups'
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
@@ -265,10 +265,10 @@ CREATE TABLE IF NOT EXISTS `pma__usergroups` (
`tab` varchar(64) NOT NULL,
`allowed` enum('Y','N') NOT NULL DEFAULT 'N',
PRIMARY KEY (`usergroup`,`tab`,`allowed`)
-)
+)
COMMENT='User groups with configured menu items'
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
-
+
-- --------------------------------------------------------
--
@@ -282,6 +282,24 @@ CREATE TABLE IF NOT EXISTS `pma__navigationhiding` (
`db_name` varchar(64) NOT NULL,
`table_name` varchar(64) NOT NULL,
PRIMARY KEY (`username`,`item_name`,`item_type`,`db_name`,`table_name`)
-)
+)
COMMENT='Hidden items of navigation tree'
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `pma__savedsearches`
+--
+
+CREATE TABLE IF NOT EXISTS `pma__savedsearches` (
+ `id` int(5) unsigned NOT NULL auto_increment,
+ `username` varchar(64) NOT NULL default '',
+ `db_name` varchar(64) NOT NULL default '',
+ `search_name` varchar(64) NOT NULL default '',
+ `search_data` text NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `u_savedsearches_username_dbname` (`username`,`db_name`,`search_name`)
+)
+ COMMENT='Saved searches'
+ DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
diff --git a/examples/create_tables_drizzle.sql b/examples/create_tables_drizzle.sql
index 698a15949d..71318caf77 100644
--- a/examples/create_tables_drizzle.sql
+++ b/examples/create_tables_drizzle.sql
@@ -1,27 +1,27 @@
-- --------------------------------------------------------
-- SQL Commands to set up the pmadb as described in the documentation.
---
+--
-- This file is meant for use with Drizzle 2011.03.13 and above!
---
+--
-- This script expects that you take care of database permissions.
--
-- Please don't forget to set up the tablenames in config.inc.php
---
+--
-- --------------------------------------------------------
---
+--
-- Database : `phpmyadmin`
---
+--
CREATE DATABASE IF NOT EXISTS `phpmyadmin`
COLLATE utf8_bin;
USE phpmyadmin;
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__bookmark`
---
+--
CREATE TABLE IF NOT EXISTS `pma__bookmark` (
`id` int(11) NOT NULL auto_increment,
@@ -36,9 +36,9 @@ CREATE TABLE IF NOT EXISTS `pma__bookmark` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__column_info`
---
+--
CREATE TABLE IF NOT EXISTS `pma__column_info` (
`id` int(5) NOT NULL auto_increment,
@@ -57,9 +57,9 @@ CREATE TABLE IF NOT EXISTS `pma__column_info` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__history`
---
+--
CREATE TABLE IF NOT EXISTS `pma__history` (
`id` bigint(20) NOT NULL auto_increment,
@@ -76,9 +76,9 @@ CREATE TABLE IF NOT EXISTS `pma__history` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__pdf_pages`
---
+--
CREATE TABLE IF NOT EXISTS `pma__pdf_pages` (
`db_name` varchar(64) NOT NULL default '',
@@ -123,9 +123,9 @@ CREATE TABLE IF NOT EXISTS `pma__table_uiprefs` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__relation`
---
+--
CREATE TABLE IF NOT EXISTS `pma__relation` (
`master_db` varchar(64) NOT NULL default '',
@@ -142,9 +142,9 @@ CREATE TABLE IF NOT EXISTS `pma__relation` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__table_coords`
---
+--
CREATE TABLE IF NOT EXISTS `pma__table_coords` (
`db_name` varchar(64) NOT NULL default '',
@@ -159,9 +159,9 @@ CREATE TABLE IF NOT EXISTS `pma__table_coords` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__table_info`
---
+--
CREATE TABLE IF NOT EXISTS `pma__table_info` (
`db_name` varchar(64) NOT NULL default '',
@@ -174,9 +174,9 @@ CREATE TABLE IF NOT EXISTS `pma__table_info` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__designer_coords`
---
+--
CREATE TABLE IF NOT EXISTS `pma__designer_coords` (
`db_name` varchar(64) NOT NULL default '',
@@ -192,9 +192,9 @@ CREATE TABLE IF NOT EXISTS `pma__designer_coords` (
-- --------------------------------------------------------
---
+--
-- Table structure for table `pma__tracking`
---
+--
CREATE TABLE IF NOT EXISTS `pma__tracking` (
`db_name` varchar(64) NOT NULL,
@@ -236,7 +236,7 @@ CREATE TABLE IF NOT EXISTS `pma__users` (
`username` varchar(64) NOT NULL,
`usergroup` varchar(64) NOT NULL,
PRIMARY KEY (`username`,`usergroup`)
-)
+)
COMMENT='Users and their assignments to user groups'
COLLATE utf8_bin;
@@ -251,10 +251,10 @@ CREATE TABLE IF NOT EXISTS `pma__usergroups` (
`tab` varchar(64) NOT NULL,
`allowed` enum('Y','N') NOT NULL DEFAULT 'N',
PRIMARY KEY (`usergroup`,`tab`,`allowed`)
-)
+)
COMMENT='User groups with configured menu items'
COLLATE utf8_bin;
-
+
-- --------------------------------------------------------
--
@@ -268,6 +268,24 @@ CREATE TABLE IF NOT EXISTS `pma__navigationhiding` (
`db_name` varchar(64) NOT NULL,
`table_name` varchar(64) NOT NULL,
PRIMARY KEY (`username`,`item_name`,`item_type`,`db_name`,`table_name`)
-)
+)
COMMENT='Hidden items of navigation tree'
COLLATE utf8_bin;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `pma__savedsearches`
+--
+
+CREATE TABLE IF NOT EXISTS `pma__savedsearches` (
+ `id` int(5) unsigned NOT NULL auto_increment,
+ `username` varchar(64) NOT NULL default '',
+ `db_name` varchar(64) NOT NULL default '',
+ `search_name` varchar(64) NOT NULL default '',
+ `search_data` text NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `u_savedsearches_username_dbname` (`username`,`db_name`,`search_name`)
+)
+ COMMENT='Saved searches'
+ DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
diff --git a/js/db_qbe.js b/js/db_qbe.js
new file mode 100644
index 0000000000..0a37b79aba
--- /dev/null
+++ b/js/db_qbe.js
@@ -0,0 +1,55 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * @fileoverview function used in QBE for DB
+ * @name Database Operations
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ *
+ */
+
+/**
+ * Ajax event handlers here for db_qbe.php
+ *
+ * Actions Ajaxified here:
+ * Select saved search
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('db_qbe.js', function () {
+ $("#searchId").die('change');
+ $("#saveSearch").die('click');
+ $("#deleteSearch").die('click');
+});
+
+AJAX.registerOnload('db_qbe.js', function () {
+
+ /**
+ * Ajax event handlers for 'Select saved search'
+ */
+ $("#searchId").live('change', function (event) {
+ if ('' == $(this).val()) {
+ return false;
+ }
+
+ $('#action').val('load');
+ $('#formQBE').submit();
+ });
+
+ /**
+ * Ajax event handlers for 'Save search'
+ */
+ $("#saveSearch").live('click', function (event) {
+ $('#action').val('save');
+ });
+
+ /**
+ * Ajax event handlers for 'Delete search'
+ */
+ $("#deleteSearch").live('click', function (event) {
+ $('#action').val('delete');
+ });
+}); \ No newline at end of file
diff --git a/libraries/DBQbe.class.php b/libraries/DBQbe.class.php
index ccaad0bd88..dd7407d1e1 100644
--- a/libraries/DBQbe.class.php
+++ b/libraries/DBQbe.class.php
@@ -73,6 +73,13 @@ class PMA_DbQbe
*/
private $_criteriaRowInsert;
/**
+ * Whether to delete a row
+ *
+ * @access private
+ * @var array
+ */
+ private $_criteriaRowDelete;
+ /**
* Already set criteria values
*
* @access private
@@ -150,6 +157,13 @@ class PMA_DbQbe
*/
private $_curAndOrCol;
/**
+ * Current criteria AND/OR row relations
+ *
+ * @access private
+ * @var array
+ */
+ private $_curAndOrRow;
+ /**
* New column count in case of add/delete
*
* @access private
@@ -163,15 +177,64 @@ class PMA_DbQbe
* @var integer
*/
private $_new_row_count;
+ /**
+ * List of saved searches
+ *
+ * @access private
+ * @var array
+ */
+ private $_savedSearchList = null;
+ /**
+ * Current search
+ *
+ * @access private
+ * @var PMA_SavedSearches
+ */
+ private $_currentSearch = null;
/**
- * Public Constructor
+ * Initialize criterias
*
- * @param string $db Database name
+ * @return static
*/
- public function __construct($db)
+ private function _loadCriterias()
{
- $this->_db = $db;
+ if (null === $this->_currentSearch
+ || null === $this->_currentSearch->getCriterias()
+ ) {
+ return $this;
+ }
+
+ $criterias = $this->_currentSearch->getCriterias();
+ $_REQUEST = $criterias + $_REQUEST;
+
+ return $this;
+ }
+
+ /**
+ * Getter for current search
+ *
+ * @return PMA_SavedSearches
+ */
+ private function _getCurrentSearch()
+ {
+ return $this->_currentSearch;
+ }
+
+ /**
+ * Public Constructor
+ *
+ * @param string $dbname Database name
+ * @param array $savedSearchList List of saved searches
+ * @param PMA_SavedSearches $currentSearch Current search id
+ */
+ public function __construct(
+ $dbname, $savedSearchList = array(), $currentSearch = null
+ ) {
+ $this->_db = $dbname;
+ $this->_savedSearchList = $savedSearchList;
+ $this->_currentSearch = $currentSearch;
+ $this->_loadCriterias();
// Sets criteria parameters
$this->_setSearchParams();
$this->_setCriteriaTablesAndColumns();
@@ -184,26 +247,7 @@ class PMA_DbQbe
*/
private function _setSearchParams()
{
- // sets column count
- $criteriaColumnCount = PMA_ifSetOr(
- $_REQUEST['criteriaColumnCount'],
- 3,
- 'numeric'
- );
- $criteriaColumnAdd = PMA_ifSetOr(
- $_REQUEST['criteriaColumnAdd'],
- 0,
- 'numeric'
- );
- $this->_criteria_column_count = max(
- $criteriaColumnCount + $criteriaColumnAdd,
- 0
- );
-
- // sets row count
- $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric');
- $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric');
- $this->_criteria_row_count = max($rows + $criteriaRowAdd, 0);
+ $criteriaColumnCount = $this->_initializeCriteriasCount();
$this->_criteriaColumnInsert = PMA_ifSetOr(
$_REQUEST['criteriaColumnInsert'],
@@ -1130,20 +1174,10 @@ class PMA_DbQbe
$unique_columns = $indexes['unique'];
$index_columns = $indexes['index'];
- // now we want to find the best.
- if (isset($unique_columns) && count($unique_columns) > 0) {
- $candidate_columns = $unique_columns;
- $needsort = 1;
- } elseif (isset($index_columns) && count($index_columns) > 0) {
- $candidate_columns = $index_columns;
- $needsort = 1;
- } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) {
- $candidate_columns = $where_clause_columns;
- $needsort = 0;
- } else {
- $candidate_columns = $all_tables;
- $needsort = 0;
- }
+ list($candidate_columns, $needsort)
+ = $this->_getLeftJoinColumnCandidatesBest(
+ $all_tables, $where_clause_columns, $unique_columns, $index_columns
+ );
// If we came up with $unique_columns (very good) or $index_columns (still
// good) as $candidate_columns we want to check if we have any 'Y' there
@@ -1348,8 +1382,13 @@ class PMA_DbQbe
*/
public function getSelectionForm($cfgRelation)
{
- $html_output = '<form action="db_qbe.php" method="post">';
+ $html_output = '<form action="db_qbe.php" method="post" id="formQBE">';
$html_output .= '<fieldset>';
+
+ if ($GLOBALS['cfgRelation']['savedsearcheswork']) {
+ $html_output .= $this->_getSavedSearchesField();
+ }
+
$html_output .= '<table class="data" style="width: 100%;">';
// Get table's <tr> elements
$html_output .= $this->_getColumnNamesRow();
@@ -1397,5 +1436,111 @@ class PMA_DbQbe
$html_output .= '</form>';
return $html_output;
}
+
+ /**
+ * Get fields to display
+ *
+ * @return string
+ */
+ private function _getSavedSearchesField()
+ {
+ $html_output = __('Saved searches : ');
+ $html_output .= '<select name="searchId" id="searchId">';
+ $html_output .= '<option value="">New search</option>';
+
+ $currentSearch = $this->_getCurrentSearch();
+ $currentSearchId = null;
+ $currentSearchName = null;
+ if (null != $currentSearch) {
+ $currentSearchId = $currentSearch->getId();
+ $currentSearchName = $currentSearch->getSearchName();
+ }
+
+ foreach ($this->_savedSearchList as $id => $name) {
+ $html_output .= '<option value="' . htmlspecialchars($id)
+ . '" ' . (
+ $id == $currentSearchId
+ ? 'selected="selected" '
+ : ''
+ )
+ . '>'
+ . htmlspecialchars($name)
+ . '</option>';
+ }
+ $html_output .= '</select>';
+ $html_output .= '<input type="text" name="searchName" id="searchName" '
+ . 'value="' . $currentSearchName . '" />';
+ $html_output .= '<input type="hidden" name="action" id="action" value="" />';
+ $html_output .= '<input type="submit" name="saveSearch" id="saveSearch" '
+ . 'value="' . __('Save search') . '" />';
+ $html_output .= '<input type="submit" name="deleteSearch" id="deleteSearch" '
+ . 'value="' . __('Delete search') . '" />';
+
+ return $html_output;
+ }
+
+ /**
+ * Initialize _criteria_column_count
+ *
+ * @return int Previous number of columns
+ */
+ private function _initializeCriteriasCount()
+ {
+ // sets column count
+ $criteriaColumnCount = PMA_ifSetOr(
+ $_REQUEST['criteriaColumnCount'],
+ 3,
+ 'numeric'
+ );
+ $criteriaColumnAdd = PMA_ifSetOr(
+ $_REQUEST['criteriaColumnAdd'],
+ 0,
+ 'numeric'
+ );
+ $this->_criteria_column_count = max(
+ $criteriaColumnCount + $criteriaColumnAdd,
+ 0
+ );
+
+ // sets row count
+ $rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric');
+ $criteriaRowAdd = PMA_ifSetOr($_REQUEST['criteriaRowAdd'], 0, 'numeric');
+ $this->_criteria_row_count = max($rows + $criteriaRowAdd, 0);
+
+ return $criteriaColumnCount;
+ }
+
+ /**
+ * Get best
+ *
+ * @param array $all_tables All tables
+ * @param array $where_clause_columns Columns with where clause
+ * @param array $unique_columns Unique columns
+ * @param array $index_columns Indexed columns
+ *
+ * @return array
+ */
+ private function _getLeftJoinColumnCandidatesBest(
+ $all_tables, $where_clause_columns, $unique_columns, $index_columns
+ ) {
+ // now we want to find the best.
+ if (isset($unique_columns) && count($unique_columns) > 0) {
+ $candidate_columns = $unique_columns;
+ $needsort = 1;
+ return array($candidate_columns, $needsort);
+ } elseif (isset($index_columns) && count($index_columns) > 0) {
+ $candidate_columns = $index_columns;
+ $needsort = 1;
+ return array($candidate_columns, $needsort);
+ } elseif (isset($where_clause_columns) && count($where_clause_columns) > 0) {
+ $candidate_columns = $where_clause_columns;
+ $needsort = 0;
+ return array($candidate_columns, $needsort);
+ } else {
+ $candidate_columns = $all_tables;
+ $needsort = 0;
+ return array($candidate_columns, $needsort);
+ }
+ }
}
?>
diff --git a/libraries/SavedSearches.php b/libraries/SavedSearches.php
new file mode 100644
index 0000000000..63cca46f41
--- /dev/null
+++ b/libraries/SavedSearches.php
@@ -0,0 +1,397 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Saved searches managing
+ *
+ * @package PhpMyAdmin
+ */
+
+if (! defined('PHPMYADMIN')) {
+ exit;
+}
+
+/**
+ * Saved searches managing
+ *
+ * @package PhpMyAdmin
+ */
+class PMA_SavedSearches
+{
+ /**
+ * Global configuration
+ * @var array
+ */
+ private $_config = null;
+
+ /**
+ * Id
+ * @var int|null
+ */
+ private $_id = null;
+
+ /**
+ * Username
+ * @var string
+ */
+ private $_username = null;
+
+ /**
+ * DB name
+ * @var string
+ */
+ private $_dbname = null;
+
+ /**
+ * Saved search name
+ * @var string
+ */
+ private $_searchName = null;
+
+ /**
+ * Setter of id
+ *
+ * @param int|null $searchId Id of search
+ *
+ * @return static
+ */
+ public function setId($searchId)
+ {
+ $searchId = (int)$searchId;
+ if (empty($searchId)) {
+ $searchId = null;
+ }
+
+ $this->_id = $searchId;
+ return $this;
+ }
+
+ /**
+ * Getter of id
+ *
+ * @return int|null
+ */
+ public function getId()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * Setter of searchName
+ *
+ * @param string $searchName Saved search name
+ *
+ * @return static
+ */
+ public function setSearchName($searchName)
+ {
+ $this->_searchName = $searchName;
+ return $this;
+ }
+
+ /**
+ * Getter of searchName
+ *
+ * @return string
+ */
+ public function getSearchName()
+ {
+ return $this->_searchName;
+ }
+
+ /**
+ * Criterias
+ * @var array
+ */
+ private $_criterias = null;
+
+ /**
+ * Setter of config
+ *
+ * @param array $config Global configuration
+ *
+ * @return static
+ */
+ public function setConfig($config)
+ {
+ $this->_config = $config;
+ return $this;
+ }
+
+ /**
+ * Getter of config
+ *
+ * @return array
+ */
+ public function getConfig()
+ {
+ return $this->_config;
+ }
+
+ /**
+ * Setter for criterias
+ *
+ * @param array $criterias Criterias of saved searches
+ * @param bool $json Criterias are in JSON format
+ *
+ * @return static
+ */
+ public function setCriterias($criterias, $json = false)
+ {
+ if (true === $json) {
+ $this->_criterias = json_decode($criterias, true);
+ return $this;
+ }
+
+ $aListFieldsToGet = array(
+ 'criteriaColumn',
+ 'criteriaSort',
+ 'criteriaShow',
+ 'criteria',
+ 'criteriaAndOrRow',
+ 'criteriaAndOrColumn',
+ 'rows'
+ );
+
+ $data = array();
+
+ $data['criteriaColumnCount'] = count($criterias['criteriaColumn']);
+
+ foreach ($aListFieldsToGet as $field) {
+ $data[$field] = $criterias[$field];
+ }
+
+ for ($i = 0; $i <= $data['rows']; $i++) {
+ $data['Or' . $i] = $criterias['Or' . $i];
+ }
+
+ $this->_criterias = $data;
+ return $this;
+ }
+
+ /**
+ * Getter for criterias
+ *
+ * @return array
+ */
+ public function getCriterias()
+ {
+ return $this->_criterias;
+ }
+
+ /**
+ * Setter for username
+ *
+ * @param string $username Username
+ *
+ * @return static
+ */
+ public function setUsername($username)
+ {
+ $this->_username = $username;
+ return $this;
+ }
+
+ /**
+ * Getter for username
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ return $this->_username;
+ }
+
+ /**
+ * Setter for DB name
+ *
+ * @param string $dbname DB name
+ *
+ * @return static
+ */
+ public function setDbname($dbname)
+ {
+ $this->_dbname = $dbname;
+ return $this;
+ }
+
+ /**
+ * Getter for DB name
+ *
+ * @return string
+ */
+ public function getDbname()
+ {
+ return $this->_dbname;
+ }
+
+ /**
+ * Public constructor
+ *
+ * @param array $config Global configuration
+ */
+ public function __construct($config)
+ {
+ $this->setConfig($config);
+ }
+
+ /**
+ * Save the search
+ *
+ * @return boolean
+ */
+ public function save()
+ {
+ if (null == $this->getUsername()
+ || null == $this->getDbname()
+ || null == $this->getSearchName()
+ || null == $this->getCriterias()
+ ) {
+ PMA_Util::mysqlDie(__('Missing information to save the search.'));
+ }
+
+ $savedSearchesTbl
+ = PMA_Util::backquote($this->_config['cfgRelation']['db']) . "."
+ . PMA_Util::backquote($this->_config['cfgRelation']['savedsearches']);
+
+ //If it's an insert.
+ if (null === $this->getId()) {
+ $wheres = array(
+ "search_name = '" . PMA_Util::sqlAddSlashes($this->getSearchName())
+ . "'"
+ );
+ $existingSearches = $this->getList($wheres);
+
+ if (!empty($existingSearches)) {
+ PMA_Util::mysqlDie(__('An entry with this name already exists.'));
+ }
+
+ $sqlQuery = "INSERT INTO " . $savedSearchesTbl
+ . "(`username`, `db_name`, `search_name`, `search_data`)"
+ . " VALUES ("
+ . "'" . PMA_Util::sqlAddSlashes($this->getUsername()) . "',"
+ . "'" . PMA_Util::sqlAddSlashes($this->getDbname()) . "',"
+ . "'" . PMA_Util::sqlAddSlashes($this->getSearchName()) . "',"
+ . "'" . PMA_Util::sqlAddSlashes(json_encode($this->getCriterias()))
+ . "')";
+
+ $result = (bool)PMA_queryAsControlUser($sqlQuery);
+ if (!$result) {
+ return false;
+ }
+
+ $this->setId($GLOBALS['dbi']->insertId());
+
+ return true;
+ }
+
+ //Else, it's an update.
+ $wheres = array(
+ "id != " . $this->getId(),
+ "search_name = '" . PMA_Util::sqlAddSlashes($this->getSearchName()) . "'"
+ );
+ $existingSearches = $this->getList($wheres);
+
+ if (!empty($existingSearches)) {
+ PMA_Util::mysqlDie(__('An entry with this name already exists.'));
+ }
+
+ $sqlQuery = "UPDATE " . $savedSearchesTbl
+ . "SET `search_name` = '"
+ . PMA_Util::sqlAddSlashes($this->getSearchName()) . "', "
+ . "`search_data` = '"
+ . PMA_Util::sqlAddSlashes(json_encode($this->getCriterias())) . "' "
+ . "WHERE id = " . $this->getId();
+ return (bool)PMA_queryAsControlUser($sqlQuery);
+ }
+
+ /**
+ * Delete the search
+ *
+ * @return boolean
+ */
+ public function delete()
+ {
+ if (null == $this->getId()) {
+ PMA_Util::mysqlDie(__('Missing information to delete the search.'));
+ }
+
+ $savedSearchesTbl
+ = PMA_Util::backquote($this->_config['cfgRelation']['db']) . "."
+ . PMA_Util::backquote($this->_config['cfgRelation']['savedsearches']);
+
+ $sqlQuery = "DELETE FROM " . $savedSearchesTbl
+ . "WHERE id = '" . PMA_Util::sqlAddSlashes($this->getId()) . "'";
+
+ return (bool)PMA_queryAsControlUser($sqlQuery);
+ }
+
+ /**
+ * Load the current search from an id.
+ *
+ * @return bool Success
+ */
+ public function load()
+ {
+ if (null == $this->getId()) {
+ PMA_Util::mysqlDie(__('Missing information to load the search.'));
+ }
+
+ $savedSearchesTbl = PMA_Util::backquote($this->_config['cfgRelation']['db'])
+ . "."
+ . PMA_Util::backquote($this->_config['cfgRelation']['savedsearches']);
+ $sqlQuery = "SELECT id, search_name, search_data "
+ . "FROM " . $savedSearchesTbl . " "
+ . "WHERE id = '" . PMA_Util::sqlAddSlashes($this->getId()) . "' ";
+
+ $resList = PMA_queryAsControlUser($sqlQuery);
+
+ if (false === ($oneResult = $GLOBALS['dbi']->fetchArray($resList))) {
+ PMA_Util::mysqlDie(__('Error while loading the search.'));
+ }
+
+ $this->setSearchName($oneResult['search_name'])
+ ->setCriterias($oneResult['search_data'], true);
+
+ return true;
+ }
+
+ /**
+ * Get the list of saved search of a user on a DB
+ *
+ * @param array $wheres List of filters
+ *
+ * @return array|bool List of saved search or false on failure
+ */
+ public function getList(array $wheres = array())
+ {
+ if (null == $this->getUsername()
+ || null == $this->getDbname()
+ ) {
+ return false;
+ }
+
+ $savedSearchesTbl = PMA_Util::backquote($this->_config['cfgRelation']['db'])
+ . "."
+ . PMA_Util::backquote($this->_config['cfgRelation']['savedsearches']);
+ $sqlQuery = "SELECT id, search_name "
+ . "FROM " . $savedSearchesTbl . " "
+ . "WHERE "
+ . "username = '" . PMA_Util::sqlAddSlashes($this->getUsername()) . "' "
+ . "AND db_name = '" . PMA_Util::sqlAddSlashes($this->getDbname()) . "' ";
+
+ foreach ($wheres as $where) {
+ $sqlQuery .= "AND " . $where . " ";
+ }
+
+ $sqlQuery .= "order by search_name ASC ";
+
+ $resList = PMA_queryAsControlUser($sqlQuery);
+
+ $list = array();
+ while ($oneResult = $GLOBALS['dbi']->fetchArray($resList)) {
+ $list[$oneResult['id']] = $oneResult['search_name'];
+ }
+
+ return $list;
+ }
+} \ No newline at end of file
diff --git a/libraries/config.default.php b/libraries/config.default.php
index a4694bf9e8..d04abdaf44 100644
--- a/libraries/config.default.php
+++ b/libraries/config.default.php
@@ -466,6 +466,15 @@ $cfg['Servers'][$i]['usergroups'] = '';
$cfg['Servers'][$i]['navigationhiding'] = '';
/**
+ * table to store information about saved searches from query-by-example on a db
+ * - leave blank to disable saved searches feature
+ * SUGGESTED: 'pma__savedsearches'
+ *
+ * @global string $cfg['Servers'][$i]['savedsearches']
+ */
+$cfg['Servers'][$i]['savedsearches'] = '';
+
+/**
* Maximum number of records saved in $cfg['Servers'][$i]['table_uiprefs'] table.
*
* In case where tables in databases is modified (e.g. dropped or renamed),
diff --git a/libraries/config/setup.forms.php b/libraries/config/setup.forms.php
index 611c1480b8..e979966799 100644
--- a/libraries/config/setup.forms.php
+++ b/libraries/config/setup.forms.php
@@ -79,6 +79,7 @@ $forms['Servers']['Server_pmadb'] = array('Servers' => array(1 => array(
'table_coords' => 'pma__table_coords',
'pdf_pages' => 'pma__pdf_pages',
'designer_coords' => 'pma__designer_coords',
+ 'saved_searches' => 'pma__savedsearches',
'MaxTableUiprefs' => 100)));
$forms['Servers']['Server_tracking'] = array('Servers' => array(1 => array(
'tracking_version_auto_create',
diff --git a/libraries/relation.lib.php b/libraries/relation.lib.php
index 47f4bf7941..511337241d 100644
--- a/libraries/relation.lib.php
+++ b/libraries/relation.lib.php
@@ -395,6 +395,7 @@ function PMA_checkRelationsParam()
$cfgRelation['menuswork'] = false;
$cfgRelation['navwork'] = false;
$cfgRelation['allworks'] = false;
+ $cfgRelation['savedsearcheswork'] = false;
$cfgRelation['user'] = null;
$cfgRelation['db'] = null;
@@ -463,6 +464,8 @@ function PMA_checkRelationsParam()
$cfgRelation['usergroups'] = $curr_table[0];
} elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['navigationhiding']) {
$cfgRelation['navigationhiding'] = $curr_table[0];
+ } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['savedsearches']) {
+ $cfgRelation['savedsearches'] = $curr_table[0];
}
} // end while
$GLOBALS['dbi']->freeResult($tab_rs);
@@ -521,6 +524,10 @@ function PMA_checkRelationsParam()
$cfgRelation['navwork'] = true;
}
+ if (isset($cfgRelation['savedsearches'])) {
+ $cfgRelation['savedsearcheswork'] = true;
+ }
+
if ($cfgRelation['relwork'] && $cfgRelation['displaywork']
&& $cfgRelation['pdfwork'] && $cfgRelation['commwork']
&& $cfgRelation['mimework'] && $cfgRelation['historywork']
@@ -528,6 +535,7 @@ function PMA_checkRelationsParam()
&& $cfgRelation['trackingwork'] && $cfgRelation['userconfigwork']
&& $cfgRelation['bookmarkwork'] && $cfgRelation['designerwork']
&& $cfgRelation['menuswork'] && $cfgRelation['navwork']
+ && $cfgRelation['savedsearcheswork']
) {
$cfgRelation['allworks'] = true;
}
diff --git a/test/libraries/PMA_relation_cleanup_test.php b/test/libraries/PMA_relation_cleanup_test.php
index 97d1099bf0..9b59f366b3 100644
--- a/test/libraries/PMA_relation_cleanup_test.php
+++ b/test/libraries/PMA_relation_cleanup_test.php
@@ -52,6 +52,7 @@ class PMA_Relation_Cleanup_Test extends PHPUnit_Framework_TestCase
$GLOBALS['cfg']['Server']['users'] = 'users';
$GLOBALS['cfg']['Server']['usergroups'] = 'usergroups';
$GLOBALS['cfg']['Server']['navigationhiding'] = 'navigationhiding';
+ $GLOBALS['cfg']['Server']['savedsearches'] = 'savedsearches';
$this->redefineRelation();
}