diff options
Diffstat (limited to 'phpBB/phpbb/search/fulltext_postgres.php')
| -rw-r--r-- | phpBB/phpbb/search/fulltext_postgres.php | 271 | 
1 files changed, 209 insertions, 62 deletions
| diff --git a/phpBB/phpbb/search/fulltext_postgres.php b/phpBB/phpbb/search/fulltext_postgres.php index 063bf52a19..42425cbc6b 100644 --- a/phpBB/phpbb/search/fulltext_postgres.php +++ b/phpBB/phpbb/search/fulltext_postgres.php @@ -1,18 +1,20 @@  <?php  /**  * -* @package search -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file.  *  */  namespace phpbb\search;  /** -* fulltext_postgres  * Fulltext search for PostgreSQL -* @package search  */  class fulltext_postgres extends \phpbb\search\base  { @@ -29,18 +31,6 @@ class fulltext_postgres extends \phpbb\search\base  	protected $split_words = array();  	/** -	 * True if PostgreSQL version supports tsearch -	 * @var boolean -	 */ -	protected $tsearch_usable = false; - -	/** -	 * Stores the PostgreSQL version -	 * @var string -	 */ -	protected $version; - -	/**  	 * Stores the tsearch query  	 * @var string  	 */ @@ -61,11 +51,17 @@ class fulltext_postgres extends \phpbb\search\base  	/**  	 * Database connection -	 * @var \phpbb\db\driver\driver +	 * @var \phpbb\db\driver\driver_interface  	 */  	protected $db;  	/** +	 * phpBB event dispatcher object +	 * @var \phpbb\event\dispatcher_interface +	 */ +	protected $phpbb_dispatcher; + +	/**  	 * User object  	 * @var \phpbb\user  	 */ @@ -96,25 +92,23 @@ class fulltext_postgres extends \phpbb\search\base  	 * Creates a new \phpbb\search\fulltext_postgres, which is used as a search backend  	 *  	 * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false +	 * @param string $phpbb_root_path Relative path to phpBB root +	 * @param string $phpEx PHP file extension +	 * @param \phpbb\auth\auth $auth Auth object +	 * @param \phpbb\config\config $config Config object +	 * @param \phpbb\db\driver\driver_interface Database object +	 * @param \phpbb\user $user User object +	 * @param \phpbb\event\dispatcher_interface	$phpbb_dispatcher	Event dispatcher object  	 */ -	public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user) +	public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher)  	{  		$this->config = $config;  		$this->db = $db; +		$this->phpbb_dispatcher = $phpbb_dispatcher;  		$this->user = $user;  		$this->word_length = array('min' => $this->config['fulltext_postgres_min_word_len'], 'max' => $this->config['fulltext_postgres_max_word_len']); -		if ($this->db->sql_layer == 'postgres') -		{ -			$pgsql_version = explode(',', substr($this->db->sql_server_info(), 10)); -			$this->version = trim($pgsql_version[0]); -			if (version_compare($this->version, '8.3', '>=')) -			{ -				$this->tsearch_usable = true; -			} -		} -  		/**  		 * Load the UTF tools  		 */ @@ -183,16 +177,11 @@ class fulltext_postgres extends \phpbb\search\base  	*/  	public function init()  	{ -		if ($this->db->sql_layer != 'postgres') +		if ($this->db->get_sql_layer() != 'postgres')  		{  			return $this->user->lang['FULLTEXT_POSTGRES_INCOMPATIBLE_DATABASE'];  		} -		if (!$this->tsearch_usable) -		{ -			return $this->user->lang['FULLTEXT_POSTGRES_TS_NOT_USABLE']; -		} -  		return false;  	} @@ -261,12 +250,12 @@ class fulltext_postgres extends \phpbb\search\base  					$this->search_query .= $word . ' ';  					$this->tsearch_query .= '&' . substr($word, 1) . ' ';  				} -				elseif (strpos($word, '-') === 0) +				else if (strpos($word, '-') === 0)  				{  					$this->search_query .= $word . ' ';  					$this->tsearch_query .= '&!' . substr($word, 1) . ' ';  				} -				elseif (strpos($word, '|') === 0) +				else if (strpos($word, '|') === 0)  				{  					$this->search_query .= $word . ' ';  					$this->tsearch_query .= '|' . substr($word, 1) . ' '; @@ -352,7 +341,7 @@ class fulltext_postgres extends \phpbb\search\base  		}  		// generate a search_key from all the options to identify the results -		$search_key = md5(implode('#', array( +		$search_key_array = array(  			implode(', ', $this->split_words),  			$type,  			$fields, @@ -363,7 +352,39 @@ class fulltext_postgres extends \phpbb\search\base  			implode(',', $ex_fid_ary),  			$post_visibility,  			implode(',', $author_ary) -		))); +		); + +		/** +		* Allow changing the search_key for cached results +		* +		* @event core.search_postgres_by_keyword_modify_search_key +		* @var	array	search_key_array	Array with search parameters to generate the search_key +		* @var	string	type				Searching type ('posts', 'topics') +		* @var	string	fields				Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') +		* @var	string	terms				Searching terms ('all', 'any') +		* @var	int		sort_days			Time, in days, of the oldest possible post to list +		* @var	string	sort_key			The sort type used from the possible sort types +		* @var	int		topic_id			Limit the search to this topic_id only +		* @var	array	ex_fid_ary			Which forums not to search on +		* @var	string	post_visibility		Post visibility data +		* @var	array	author_ary			Array of user_id containing the users to filter the results to +		* @since 3.1.7-RC1 +		*/ +		$vars = array( +			'search_key_array', +			'type', +			'fields', +			'terms', +			'sort_days', +			'sort_key', +			'topic_id', +			'ex_fid_ary', +			'post_visibility', +			'author_ary', +		); +		extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_by_keyword_modify_search_key', compact($vars))); + +		$search_key = md5(implode('#', $search_key_array));  		if ($start < 0)  		{ @@ -428,10 +449,58 @@ class fulltext_postgres extends \phpbb\search\base  			break;  		} +		$tsearch_query = $this->tsearch_query; + +		/** +		* Allow changing the query used to search for posts using fulltext_postgres +		* +		* @event core.search_postgres_keywords_main_query_before +		* @var	string	tsearch_query		The parsed keywords used for this search +		* @var	int		result_count		The previous result count for the format of the query. +		*									Set to 0 to force a re-count +		* @var	bool	join_topic			Weather or not TOPICS_TABLE should be CROSS JOIN'ED +		* @var	array	author_ary			Array of user_id containing the users to filter the results to +		* @var	string	author_name			An extra username to search on (!empty(author_ary) must be true, to be relevant) +		* @var	array	ex_fid_ary			Which forums not to search on +		* @var	int		topic_id			Limit the search to this topic_id only +		* @var	string	sql_sort_table		Extra tables to include in the SQL query. +		*									Used in conjunction with sql_sort_join +		* @var	string	sql_sort_join		SQL conditions to join all the tables used together. +		*									Used in conjunction with sql_sort_table +		* @var	int		sort_days			Time, in days, of the oldest possible post to list +		* @var	string	sql_match			Which columns to do the search on. +		* @var	string	sql_match_where		Extra conditions to use to properly filter the matching process +		* @var	string	sort_by_sql			The possible predefined sort types +		* @var	string	sort_key			The sort type used from the possible sort types +		* @var	string	sort_dir			"a" for ASC or "d" dor DESC for the sort order used +		* @var	string	sql_sort			The result SQL when processing sort_by_sql + sort_key + sort_dir +		* @var	int		start				How many posts to skip in the search results (used for pagination) +		* @since 3.1.5-RC1 +		*/ +		$vars = array( +			'tsearch_query', +			'result_count', +			'join_topic', +			'author_ary', +			'author_name', +			'ex_fid_ary', +			'topic_id', +			'sql_sort_table', +			'sql_sort_join', +			'sort_days', +			'sql_match', +			'sql_match_where', +			'sort_by_sql', +			'sort_key', +			'sort_dir', +			'sql_sort', +			'start', +		); +		extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_keywords_main_query_before', compact($vars))); +  		$sql_select			= ($type == 'posts') ? 'p.post_id' : 'DISTINCT t.topic_id';  		$sql_from			= ($join_topic) ? TOPICS_TABLE . ' t, ' : '';  		$field				= ($type == 'posts') ? 'post_id' : 'topic_id'; -		$sql_author			= (sizeof($author_ary) == 1) ? ' = ' . $author_ary[0] : 'IN (' . implode(', ', $author_ary) . ')';  		if (sizeof($author_ary) && $author_name)  		{ @@ -456,16 +525,13 @@ class fulltext_postgres extends \phpbb\search\base  		$sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';  		$sql_where_options .= $sql_match_where; -		$tmp_sql_match = array(); -		foreach (explode(',', $sql_match) as $sql_match_column) -		{ -			$tmp_sql_match[] = "to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', " . $sql_match_column . ") @@ to_tsquery ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', '" . $this->db->sql_escape($this->tsearch_query) . "')"; -		} +		$sql_match = str_replace(',', " || ' ' ||", $sql_match); +		$tmp_sql_match = "to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', " . $sql_match . ") @@ to_tsquery ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', '" . $this->db->sql_escape($this->tsearch_query) . "')";  		$this->db->sql_transaction('begin');  		$sql_from = "FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p"; -		$sql_where = "WHERE (" . implode(' OR ', $tmp_sql_match) . ") +		$sql_where = "WHERE (" . $tmp_sql_match . ")  			$sql_where_options";  		$sql = "SELECT $sql_select  			$sql_from @@ -549,7 +615,7 @@ class fulltext_postgres extends \phpbb\search\base  		}  		// generate a search_key from all the options to identify the results -		$search_key = md5(implode('#', array( +		$search_key_array = array(  			'',  			$type,  			($firstpost_only) ? 'firstpost' : '', @@ -562,7 +628,39 @@ class fulltext_postgres extends \phpbb\search\base  			$post_visibility,  			implode(',', $author_ary),  			$author_name, -		))); +		); + +		/** +		* Allow changing the search_key for cached results +		* +		* @event core.search_postgres_by_author_modify_search_key +		* @var	array	search_key_array	Array with search parameters to generate the search_key +		* @var	string	type				Searching type ('posts', 'topics') +		* @var	boolean	firstpost_only		Flag indicating if only topic starting posts are considered +		* @var	int		sort_days			Time, in days, of the oldest possible post to list +		* @var	string	sort_key			The sort type used from the possible sort types +		* @var	int		topic_id			Limit the search to this topic_id only +		* @var	array	ex_fid_ary			Which forums not to search on +		* @var	string	post_visibility		Post visibility data +		* @var	array	author_ary			Array of user_id containing the users to filter the results to +		* @var	string	author_name			The username to search on +		* @since 3.1.7-RC1 +		*/ +		$vars = array( +			'search_key_array', +			'type', +			'firstpost_only', +			'sort_days', +			'sort_key', +			'topic_id', +			'ex_fid_ary', +			'post_visibility', +			'author_ary', +			'author_name', +		); +		extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_by_author_modify_search_key', compact($vars))); + +		$search_key = md5(implode('#', $search_key_array));  		if ($start < 0)  		{ @@ -616,6 +714,55 @@ class fulltext_postgres extends \phpbb\search\base  		$m_approve_fid_sql = ' AND ' . $post_visibility; +		/** +		* Allow changing the query used to search for posts by author in fulltext_postgres +		* +		* @event core.search_postgres_author_count_query_before +		* @var	int		result_count		The previous result count for the format of the query. +		*									Set to 0 to force a re-count +		* @var	string	sql_sort_table		CROSS JOIN'ed table to allow doing the sort chosen +		* @var	string	sql_sort_join		Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table +		* @var	array	author_ary			Array of user_id containing the users to filter the results to +		* @var	string	author_name			An extra username to search on +		* @var	string	sql_author			SQL WHERE condition for the post author ids +		* @var	int		topic_id			Limit the search to this topic_id only +		* @var	string	sql_topic_id		SQL of topic_id +		* @var	string	sort_by_sql			The possible predefined sort types +		* @var	string	sort_key			The sort type used from the possible sort types +		* @var	string	sort_dir			"a" for ASC or "d" dor DESC for the sort order used +		* @var	string	sql_sort			The result SQL when processing sort_by_sql + sort_key + sort_dir +		* @var	string	sort_days			Time, in days, that the oldest post showing can have +		* @var	string	sql_time			The SQL to search on the time specifyed by sort_days +		* @var	bool	firstpost_only		Wether or not to search only on the first post of the topics +		* @var	array	ex_fid_ary			Forum ids that must not be searched on +		* @var	array	sql_fora			SQL query for ex_fid_ary +		* @var	string	m_approve_fid_sql	WHERE clause condition on post_visibility restrictions +		* @var	int		start				How many posts to skip in the search results (used for pagination) +		* @since 3.1.5-RC1 +		*/ +		$vars = array( +			'result_count', +			'sql_sort_table', +			'sql_sort_join', +			'author_ary', +			'author_name', +			'sql_author', +			'topic_id', +			'sql_topic_id', +			'sort_by_sql', +			'sort_key', +			'sort_dir', +			'sql_sort', +			'sort_days', +			'sql_time', +			'firstpost_only', +			'ex_fid_ary', +			'sql_fora', +			'm_approve_fid_sql', +			'start', +		); +		extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_author_count_query_before', compact($vars))); +  		// Build the query for really selecting the post_ids  		if ($type == 'posts')  		{ @@ -689,7 +836,7 @@ class fulltext_postgres extends \phpbb\search\base  					GROUP BY t.topic_id, $sort_by_sql[$sort_key]";  			} -			$result = $this->db->sql_query($sql_count); +			$this->db->sql_query($sql_count);  			$result_count = (int) $this->db->sql_fetchfield('result_count');  			if (!$result_count) @@ -767,7 +914,7 @@ class fulltext_postgres extends \phpbb\search\base  		// destroy too old cached search results  		$this->destroy_cache(array()); -		set_config('search_last_gc', time(), true); +		$this->config->set('search_last_gc', time(), false);  	}  	/** @@ -793,9 +940,9 @@ class fulltext_postgres extends \phpbb\search\base  			$this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_subject))");  		} -		if (!isset($this->stats['post_text'])) +		if (!isset($this->stats['post_content']))  		{ -			$this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_text ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text))"); +			$this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_content ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text || ' ' || post_subject))");  		}  		$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); @@ -826,9 +973,9 @@ class fulltext_postgres extends \phpbb\search\base  			$this->db->sql_query('DROP INDEX ' . $this->stats['post_subject']['relname']);  		} -		if (isset($this->stats['post_text'])) +		if (isset($this->stats['post_content']))  		{ -			$this->db->sql_query('DROP INDEX ' . $this->stats['post_text']['relname']); +			$this->db->sql_query('DROP INDEX ' . $this->stats['post_content']['relname']);  		}  		$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); @@ -846,7 +993,7 @@ class fulltext_postgres extends \phpbb\search\base  			$this->get_stats();  		} -		return (isset($this->stats['post_text']) && isset($this->stats['post_subject'])) ? true : false; +		return (isset($this->stats['post_subject']) && isset($this->stats['post_content'])) ? true : false;  	}  	/** @@ -869,7 +1016,7 @@ class fulltext_postgres extends \phpbb\search\base  	 */  	protected function get_stats()  	{ -		if ($this->db->sql_layer != 'postgres') +		if ($this->db->get_sql_layer() != 'postgres')  		{  			$this->stats = array();  			return; @@ -888,13 +1035,13 @@ class fulltext_postgres extends \phpbb\search\base  			// deal with older PostgreSQL versions which didn't use Index_type  			if (strpos($row['indexdef'], 'to_tsvector') !== false)  			{ -				if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_text' || $row['relname'] == POSTS_TABLE . '_post_text') +				if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_subject' || $row['relname'] == POSTS_TABLE . '_post_subject')  				{ -					$this->stats['post_text'] = $row; +					$this->stats['post_subject'] = $row;  				} -				else if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_subject' || $row['relname'] == POSTS_TABLE . '_post_subject') +				else if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_content' || $row['relname'] == POSTS_TABLE . '_post_content')  				{ -					$this->stats['post_subject'] = $row; +					$this->stats['post_content'] = $row;  				}  			}  		} @@ -913,13 +1060,13 @@ class fulltext_postgres extends \phpbb\search\base  		$tpl = '  		<dl>  			<dt><label>' . $this->user->lang['FULLTEXT_POSTGRES_VERSION_CHECK'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_VERSION_CHECK_EXPLAIN'] . '</span></dt> -			<dd>' . (($this->tsearch_usable) ? $this->user->lang['YES'] : $this->user->lang['NO']) . ' (PostgreSQL ' . $this->version . ')</dd> +			<dd>' . (($this->db->get_sql_layer() == 'postgres') ? $this->user->lang['YES'] : $this->user->lang['NO']) . '</dd>  		</dl>  		<dl>  			<dt><label>' . $this->user->lang['FULLTEXT_POSTGRES_TS_NAME'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_TS_NAME_EXPLAIN'] . '</span></dt>  			<dd><select name="config[fulltext_postgres_ts_name]">'; -		if ($this->db->sql_layer == 'postgres' && $this->tsearch_usable) +		if ($this->db->get_sql_layer() == 'postgres')  		{  			$sql = 'SELECT cfgname AS ts_name  				  FROM pg_ts_config'; | 
