Don't fallback from uk to ru
[lhc/web/wiklou.git] / includes / db / DatabaseUtility.php
1 <?php
2 /**
3 * This file contains database-related utility classes.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup Database
22 */
23
24 /**
25 * Utility class
26 * @ingroup Database
27 *
28 * This allows us to distinguish a blob from a normal string and an array of strings
29 */
30 class Blob {
31 /** @var string */
32 protected $mData;
33
34 function __construct( $data ) {
35 $this->mData = $data;
36 }
37
38 function fetch() {
39 return $this->mData;
40 }
41 }
42
43 /**
44 * Base for all database-specific classes representing information about database fields
45 * @ingroup Database
46 */
47 interface Field {
48 /**
49 * Field name
50 * @return string
51 */
52 function name();
53
54 /**
55 * Name of table this field belongs to
56 * @return string
57 */
58 function tableName();
59
60 /**
61 * Database type
62 * @return string
63 */
64 function type();
65
66 /**
67 * Whether this field can store NULL values
68 * @return bool
69 */
70 function isNullable();
71 }
72
73 /**
74 * Result wrapper for grabbing data queried by someone else
75 * @ingroup Database
76 */
77 class ResultWrapper implements Iterator {
78 /** @var resource */
79 public $result;
80
81 /** @var DatabaseBase */
82 protected $db;
83
84 /** @var int */
85 protected $pos = 0;
86
87 /** @var object|null */
88 protected $currentRow = null;
89
90 /**
91 * Create a new result object from a result resource and a Database object
92 *
93 * @param DatabaseBase $database
94 * @param resource|ResultWrapper $result
95 */
96 function __construct( $database, $result ) {
97 $this->db = $database;
98
99 if ( $result instanceof ResultWrapper ) {
100 $this->result = $result->result;
101 } else {
102 $this->result = $result;
103 }
104 }
105
106 /**
107 * Get the number of rows in a result object
108 *
109 * @return int
110 */
111 function numRows() {
112 return $this->db->numRows( $this );
113 }
114
115 /**
116 * Fetch the next row from the given result object, in object form. Fields can be retrieved with
117 * $row->fieldname, with fields acting like member variables. If no more rows are available,
118 * false is returned.
119 *
120 * @return stdClass|bool
121 * @throws DBUnexpectedError Thrown if the database returns an error
122 */
123 function fetchObject() {
124 return $this->db->fetchObject( $this );
125 }
126
127 /**
128 * Fetch the next row from the given result object, in associative array form. Fields are
129 * retrieved with $row['fieldname']. If no more rows are available, false is returned.
130 *
131 * @return array|bool
132 * @throws DBUnexpectedError Thrown if the database returns an error
133 */
134 function fetchRow() {
135 return $this->db->fetchRow( $this );
136 }
137
138 /**
139 * Free a result object
140 */
141 function free() {
142 $this->db->freeResult( $this );
143 unset( $this->result );
144 unset( $this->db );
145 }
146
147 /**
148 * Change the position of the cursor in a result object.
149 * See mysql_data_seek()
150 *
151 * @param int $row
152 */
153 function seek( $row ) {
154 $this->db->dataSeek( $this, $row );
155 }
156
157 /*
158 * ======= Iterator functions =======
159 * Note that using these in combination with the non-iterator functions
160 * above may cause rows to be skipped or repeated.
161 */
162
163 function rewind() {
164 if ( $this->numRows() ) {
165 $this->db->dataSeek( $this, 0 );
166 }
167 $this->pos = 0;
168 $this->currentRow = null;
169 }
170
171 /**
172 * @return stdClass|array|bool
173 */
174 function current() {
175 if ( is_null( $this->currentRow ) ) {
176 $this->next();
177 }
178
179 return $this->currentRow;
180 }
181
182 /**
183 * @return int
184 */
185 function key() {
186 return $this->pos;
187 }
188
189 /**
190 * @return stdClass
191 */
192 function next() {
193 $this->pos++;
194 $this->currentRow = $this->fetchObject();
195
196 return $this->currentRow;
197 }
198
199 /**
200 * @return bool
201 */
202 function valid() {
203 return $this->current() !== false;
204 }
205 }
206
207 /**
208 * Overloads the relevant methods of the real ResultsWrapper so it
209 * doesn't go anywhere near an actual database.
210 */
211 class FakeResultWrapper extends ResultWrapper {
212 /** @var array */
213 public $result = [];
214
215 /** @var null And it's going to stay that way :D */
216 protected $db = null;
217
218 /** @var int */
219 protected $pos = 0;
220
221 /** @var array|stdClass|bool */
222 protected $currentRow = null;
223
224 /**
225 * @param array $array
226 */
227 function __construct( $array ) {
228 $this->result = $array;
229 }
230
231 /**
232 * @return int
233 */
234 function numRows() {
235 return count( $this->result );
236 }
237
238 /**
239 * @return array|bool
240 */
241 function fetchRow() {
242 if ( $this->pos < count( $this->result ) ) {
243 $this->currentRow = $this->result[$this->pos];
244 } else {
245 $this->currentRow = false;
246 }
247 $this->pos++;
248 if ( is_object( $this->currentRow ) ) {
249 return get_object_vars( $this->currentRow );
250 } else {
251 return $this->currentRow;
252 }
253 }
254
255 function seek( $row ) {
256 $this->pos = $row;
257 }
258
259 function free() {
260 }
261
262 /**
263 * Callers want to be able to access fields with $this->fieldName
264 * @return bool|stdClass
265 */
266 function fetchObject() {
267 $this->fetchRow();
268 if ( $this->currentRow ) {
269 return (object)$this->currentRow;
270 } else {
271 return false;
272 }
273 }
274
275 function rewind() {
276 $this->pos = 0;
277 $this->currentRow = null;
278 }
279
280 /**
281 * @return bool|stdClass
282 */
283 function next() {
284 return $this->fetchObject();
285 }
286 }
287
288 /**
289 * Used by DatabaseBase::buildLike() to represent characters that have special
290 * meaning in SQL LIKE clauses and thus need no escaping. Don't instantiate it
291 * manually, use DatabaseBase::anyChar() and anyString() instead.
292 */
293 class LikeMatch {
294 /** @var string */
295 private $str;
296
297 /**
298 * Store a string into a LikeMatch marker object.
299 *
300 * @param string $s
301 */
302 public function __construct( $s ) {
303 $this->str = $s;
304 }
305
306 /**
307 * Return the original stored string.
308 *
309 * @return string
310 */
311 public function toString() {
312 return $this->str;
313 }
314 }
315
316 /**
317 * An object representing a master or slave position in a replicated setup.
318 *
319 * The implementation details of this opaque type are up to the database subclass.
320 */
321 interface DBMasterPos {
322 /**
323 * @return float UNIX timestamp
324 * @since 1.25
325 */
326 public function asOfTime();
327
328 /**
329 * @param DBMasterPos $pos
330 * @return bool Whether this position is at or higher than $pos
331 * @since 1.27
332 */
333 public function hasReached( DBMasterPos $pos );
334
335 /**
336 * @param DBMasterPos $pos
337 * @return bool Whether this position appears to be for the same channel as another
338 * @since 1.27
339 */
340 public function channelsMatch( DBMasterPos $pos );
341
342 /**
343 * @return string
344 * @since 1.27
345 */
346 public function __toString();
347 }