Completed
Pull Request — master (#25)
by Matt
01:56
created

postgres::get_engine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 *
4
 * Precise Similar Topics
5
 *
6
 * @copyright (c) 2018 Matt Friedman
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace vse\similartopics\driver;
12
13
class postgres implements driver_interface
14
{
15
	/** @var \phpbb\db\driver\driver_interface */
16
	protected $db;
17
18
	/** @var \phpbb\config\config */
19
	protected $config;
20
21
	/** @var string */
22
	protected $ts_name;
23
24
	/**
25
	 * mysql constructor.
26
	 *
27
	 * @param \phpbb\db\driver\driver_interface $db
28
	 * @param \phpbb\config\config              $config
29
	 */
30
	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config)
31
	{
32
		$this->db = $db;
33
		$this->config = $config;
34
35
		$this->set_ts_name($config['pst_postgres_ts_name']);
36
	}
37
38
	/**
39
	 * {@inheritdoc}
40
	 */
41
	public function get_name()
42
	{
43
		return 'postgres';
44
	}
45
46
	/**
47
	 * {@inheritdoc}
48
	 */
49
	public function get_type()
50
	{
51
		return 'postgres';
52
	}
53
54
	/**
55
	 * {@inheritdoc}
56
	 */
57
	public function get_query($topic_id, $topic_title, $length, $sensitivity)
58
	{
59
		$ts_name = $this->db->sql_escape($this->ts_name);
60
		$ts_query_text = $this->db->sql_escape(str_replace(' ', '|', $topic_title));
61
62
		return array(
63
			'SELECT'	=> "f.forum_id, f.forum_name, t.*,
64
				ts_rank_cd(to_tsvector('$ts_name', t.topic_title), to_tsquery('$ts_query_text'), 32) AS score",
65
66
			'FROM'		=> array(
67
				TOPICS_TABLE	=> 't',
68
			),
69
			'LEFT_JOIN'	=> array(
70
				array(
71
					'FROM'	=>	array(FORUMS_TABLE	=> 'f'),
72
					'ON'	=> 'f.forum_id = t.forum_id',
73
				),
74
			),
75
			'WHERE'		=> "ts_rank_cd(to_tsvector('$ts_name', t.topic_title), to_tsquery('$ts_query_text'), 32) >= " . (float) $sensitivity . '
76
				AND t.topic_status <> ' . ITEM_MOVED . '
77
				AND t.topic_visibility = ' . ITEM_APPROVED . '
78
				AND t.topic_time > (extract(epoch from current_timestamp)::integer - ' . (int) $length . ')
79
				AND t.topic_id <> ' . (int) $topic_id,
80
			'ORDER_BY'	=> 'score DESC, t.topic_time DESC',
81
		);
82
	}
83
84
	/**
85
	 * {@inheritdoc}
86
	 */
87
	public function is_supported()
88
	{
89
		return ($this->db->get_sql_layer() === 'postgres');
90
	}
91
92
	/**
93
	 * {@inheritdoc}
94
	 */
95
	public function is_index($column = 'topic_title')
96
	{
97
		foreach ($this->get_fulltext_indexes($column) as $index)
98
		{
99
			if ($index === TOPICS_TABLE . '_' . $this->ts_name . '_' . $column)
100
			{
101
				return true;
102
			}
103
		}
104
105
		return false;
106
	}
107
108
	/**
109
	 * {@inheritdoc}
110
	 */
111
	public function get_fulltext_indexes($column = 'topic_title')
112
	{
113
		$indexes = array();
114
115
		if (!$this->is_supported())
116
		{
117
			return $indexes;
118
		}
119
120
		$sql = "SELECT c2.relname, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS indexdef
121
			FROM pg_catalog.pg_class c1, pg_catalog.pg_index i, pg_catalog.pg_class c2
122
			WHERE c1.relname = '" . TOPICS_TABLE . "'
123
				AND pg_catalog.pg_table_is_visible(c1.oid)
124
				AND c1.oid = i.indrelid
125
				AND i.indexrelid = c2.oid";
126
		$result = $this->db->sql_query($sql);
127
		while ($row = $this->db->sql_fetchrow($result))
128
		{
129
			if (strpos($row['relname'], $column) !== false)
130
			{
131
				$indexes[] = $row['relname'];
132
			}
133
		}
134
		$this->db->sql_freeresult($result);
135
136
		return $indexes;
137
	}
138
139
	/**
140
	 * {@inheritdoc}
141
	 */
142
	public function create_fulltext_index($column = 'topic_title')
143
	{
144
		// Make sure ts_name is current
145
		$this->set_ts_name($this->config['pst_postgres_ts_name']);
146
147
		$new_index = TOPICS_TABLE . '_' . $this->ts_name . '_' . $column;
148
149
		$indexed = false;
150
151
		foreach ($this->get_fulltext_indexes() as $index)
152
		{
153
			if ($index === $new_index)
154
			{
155
				$indexed = true;
156
			}
157
			else
158
			{
159
				$sql = 'DROP INDEX ' . $index;
160
				$this->db->sql_query($sql);
161
			}
162
		}
163
164
		if (!$indexed)
165
		{
166
			$sql = 'CREATE INDEX ' . $this->db->sql_escape($new_index) . ' 
167
				ON '  . TOPICS_TABLE . " 
168
				USING gin (to_tsvector ('" . $this->db->sql_escape($this->ts_name) . "', " . $this->db->sql_escape($column) . '))';
169
			$this->db->sql_query($sql);
170
		}
171
	}
172
173
	/**
174
	 * {@inheritdoc}
175
	 */
176
	public function get_engine()
177
	{
178
		return '';
179
	}
180
181
	/**
182
	 * Set the PostgreSQL Text Search name (dictionary)
183
	 *
184
	 * @param string $ts_name Dictionary name
185
	 */
186
	protected function set_ts_name($ts_name)
187
	{
188
		$this->ts_name = $ts_name ?: 'simple';
189
	}
190
}
191