* All apps: improved speed when searching with (many) custom-fields

This commit is contained in:
Ralf Becker 2019-02-18 19:03:29 +01:00
parent 23ceb00380
commit 5086e6cca3
4 changed files with 37 additions and 43 deletions

View File

@ -272,10 +272,6 @@ class Storage
// remove some columns, absolutly not necessary to search in sql // remove some columns, absolutly not necessary to search in sql
$this->columns_to_search = array_diff(array_values($this->somain->db_cols),$this->sql_cols_not_to_search); $this->columns_to_search = array_diff(array_values($this->somain->db_cols),$this->sql_cols_not_to_search);
if ($this->customfields) // add custom fields, if configured
{
$this->columns_to_search[] = Sql::EXTRA_TABLE.'.'.Sql::EXTRA_VALUE;
}
} }
if ($this->user) if ($this->user)
{ {

View File

@ -406,6 +406,34 @@ class Storage extends Storage\Base
return $this->total; return $this->total;
} }
/**
* Return criteria array for a given search pattern
*
* Reimplemented to handle search in custom-fields by ORing with a sub-query
* returning all auto-ids of custom-fields matching the search-criteria
*
* @param string $_pattern search pattern incl. * or ? as wildcard, if no wildcards used we append and prepend one!
* @param string &$wildcard ='' on return wildcard char to use, if pattern does not already contain wildcards!
* @param string &$op ='AND' on return boolean operation to use, if pattern does not start with ! we use OR else AND
* @param string $extra_col =null extra column to search
* @param array $search_cols =array() List of columns to search. If not provided, all columns in $this->db_cols will be considered
* @return array or column => value pairs
*/
public function search2criteria($_pattern,&$wildcard='',&$op='AND',$extra_col=null, $search_cols = array())
{
$pattern = $wildcard.$_pattern.$wildcard;
$criteria = parent::search2criteria($_pattern, $wildcard, $op, $extra_col, $search_cols);
$criteria[0] = '('.$criteria[0].' OR '.
$this->table_name.'.'.$this->autoinc_id.' IN (SELECT '.$this->autoinc_id.
' FROM '.$this->extra_table.' WHERE '.$this->extra_value.' '.
$this->db->capabilities[Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.
$GLOBALS['egw']->db->quote($pattern).'))';
return $criteria;
}
/** /**
* searches db for rows matching searchcriteria * searches db for rows matching searchcriteria
* *
@ -440,10 +468,12 @@ class Storage extends Storage\Base
{ {
$only_keys = $this->table_name.'.*'; $only_keys = $this->table_name.'.*';
} }
// if string given as criteria --> search in all (or $this->columns_to_search) columns including custom fields $extra_join_added = $join && strpos($join, $this->extra_join) !== false;
if ($criteria && is_string($criteria)) if ($criteria && is_string($criteria))
{ {
$criteria = $this->search2criteria($criteria,$wildcard,$op); $extra_join_added = true; // we have NOT added the join, as we use a sub-query and therefore not need it
$criteria = $this->search2criteria($criteria, $wildcard, $op);
} }
if ($criteria && is_array($criteria)) if ($criteria && is_array($criteria))
{ {
@ -471,7 +501,6 @@ class Storage extends Storage\Base
unset($criteria[$this->autoinc_id]); unset($criteria[$this->autoinc_id]);
} }
// replace ambiguous column with (an exact match of) table_name.column // replace ambiguous column with (an exact match of) table_name.column
$extra_join_added = $join && strpos($join, $this->extra_join) !== false;
foreach($criteria as $name => $val) foreach($criteria as $name => $val)
{ {
// only add extra_join, if we really need it // only add extra_join, if we really need it
@ -711,24 +740,6 @@ class Storage extends Storage\Base
return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
} }
/**
* Get a default list of columns to search
*
* Reimplemented to search custom fields by default.
*
* @return array of column names
*/
protected function get_default_search_columns()
{
$cols = parent::get_default_search_columns();
if ($this->customfields && !isset($this->columns_to_search))
{
$cols[] = $this->extra_table.'.'.$this->extra_value;
}
//error_log(__METHOD__."() this->columns_to_search=".array2string($this->columns_to_search).' returning '.array2string($cols));
return $cols;
}
/** /**
* Function to test if $field is a custom field: check for the prefix * Function to test if $field is a custom field: check for the prefix
* *

View File

@ -761,17 +761,8 @@ class calendar_so
{ {
$columns = array('cal_title','cal_description','cal_location'); $columns = array('cal_title','cal_description','cal_location');
$wildcard = $op = null; $wildcard = '%'; $op = null;
if(!is_null($params['cfs'])) $so_sql = new Api\Storage('calendar', $this->cal_table, $this->extra_table, '', 'cal_extra_name', 'cal_extra_value', 'cal_id', $this->db);
{
$custom = Api\Storage\Customfields::get('calendar');
if($custom)
{
$columns[] = 'cal_extra_value';
$join .= " LEFT JOIN {$this->extra_table} ON {$this->extra_table}.cal_id = {$this->cal_table}.cal_id ";
}
}
$so_sql = new Api\Storage\Base('calendar', $this->cal_table, $this->db);
$where = $so_sql->search2criteria($params['query'], $wildcard, $op, null, $columns); $where = $so_sql->search2criteria($params['query'], $wildcard, $op, null, $columns);
// Searching - restrict private to own or private grant // Searching - restrict private to own or private grant

View File

@ -904,20 +904,16 @@ class infolog_so
if ($query['query']) $query['search'] = $query['query']; // allow both names if ($query['query']) $query['search'] = $query['query']; // allow both names
if ($query['search']) // we search in _from, _subject, _des and _extra_value for $query if ($query['search']) // we search in _from, _subject, _des and _extra_value for $query
{ {
$columns = array('info_from','info_location','info_subject','info_extra_value'); $columns = array('info_from','info_location','info_subject');
// at the moment MaxDB 7.5 cant cast nor search text columns, it's suppost to change in 7.6 // at the moment MaxDB 7.5 cant cast nor search text columns, it's suppost to change in 7.6
if ($this->db->capabilities['like_on_text']) $columns[] = 'info_des'; if ($this->db->capabilities['like_on_text']) $columns[] = 'info_des';
$wildcard = $op = null; $wildcard = '%'; $op = null;
$so_sql = new Api\Storage\Base('infolog', $this->info_table, $this->db); $so_sql = new Api\Storage('infolog', $this->info_table, $this->extra_table, '', 'info_extra_name', 'info_extra_value', 'info_id', $this->db);
$so_sql->table_name = 'main'; $so_sql->table_name = 'main';
$search = $so_sql->search2criteria($query['search'], $wildcard, $op, null, $columns); $search = $so_sql->search2criteria($query['search'], $wildcard, $op, null, $columns);
$sql_query = 'AND ('.(is_numeric($query['search']) ? 'main.info_id='.(int)$query['search'].' OR ' : ''). $sql_query = 'AND ('.(is_numeric($query['search']) ? 'main.info_id='.(int)$query['search'].' OR ' : '').
implode($op, $search) .')'; implode($op, $search) .')';
$join = ($cfcolfilter>0 ? '':'LEFT')." JOIN $this->extra_table ON main.info_id=$this->extra_table.info_id ";
// mssql and others cant use DISTICT if text columns (info_des) are involved
$distinct = $this->db->capabilities['distinct_on_text'] ? 'DISTINCT' : '';
} }
$join .= " LEFT JOIN $this->users_table ON main.info_id=$this->users_table.info_id"; $join .= " LEFT JOIN $this->users_table ON main.info_id=$this->users_table.info_id";
if (strpos($query['filter'], '+deleted') === false) if (strpos($query['filter'], '+deleted') === false)