Merge "Made text profiler output a bit less noisy by bumping "thresholdMs""
[lhc/web/wiklou.git] / includes / db / DatabaseMysqli.php
1 <?php
2 /**
3 * This is the MySQLi database abstraction layer.
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 * Database abstraction object for PHP extension mysqli.
26 *
27 * @ingroup Database
28 * @since 1.22
29 * @see Database
30 */
31 class DatabaseMysqli extends DatabaseMysqlBase {
32 /**
33 * @param string $sql
34 * @return resource
35 */
36 protected function doQuery( $sql ) {
37 $conn = $this->getBindingHandle();
38
39 if ( $this->bufferResults() ) {
40 $ret = $conn->query( $sql );
41 } else {
42 $ret = $conn->query( $sql, MYSQLI_USE_RESULT );
43 }
44
45 return $ret;
46 }
47
48 /**
49 * @param string $realServer
50 * @return bool|mysqli
51 * @throws DBConnectionError
52 */
53 protected function mysqlConnect( $realServer ) {
54 global $wgDBmysql5;
55
56 # Avoid suppressed fatal error, which is very hard to track down
57 if ( !function_exists( 'mysqli_init' ) ) {
58 throw new DBConnectionError( $this, "MySQLi functions missing,"
59 . " have you compiled PHP with the --with-mysqli option?\n" );
60 }
61
62 // Other than mysql_connect, mysqli_real_connect expects an explicit port
63 // and socket parameters. So we need to parse the port and socket out of
64 // $realServer
65 $port = null;
66 $socket = null;
67 $hostAndPort = IP::splitHostAndPort( $realServer );
68 if ( $hostAndPort ) {
69 $realServer = $hostAndPort[0];
70 if ( $hostAndPort[1] ) {
71 $port = $hostAndPort[1];
72 }
73 } elseif ( substr_count( $realServer, ':' ) == 1 ) {
74 // If we have a colon and something that's not a port number
75 // inside the hostname, assume it's the socket location
76 $hostAndSocket = explode( ':', $realServer );
77 $realServer = $hostAndSocket[0];
78 $socket = $hostAndSocket[1];
79 }
80
81 $connFlags = 0;
82 if ( $this->mFlags & DBO_SSL ) {
83 $connFlags |= MYSQLI_CLIENT_SSL;
84 }
85 if ( $this->mFlags & DBO_COMPRESS ) {
86 $connFlags |= MYSQLI_CLIENT_COMPRESS;
87 }
88 if ( $this->mFlags & DBO_PERSISTENT ) {
89 $realServer = 'p:' . $realServer;
90 }
91
92 $mysqli = mysqli_init();
93 if ( $wgDBmysql5 ) {
94 // Tell the server we're communicating with it in UTF-8.
95 // This may engage various charset conversions.
96 $mysqli->options( MYSQLI_SET_CHARSET_NAME, 'utf8' );
97 } else {
98 $mysqli->options( MYSQLI_SET_CHARSET_NAME, 'binary' );
99 }
100 $mysqli->options( MYSQLI_OPT_CONNECT_TIMEOUT, 3 );
101
102 if ( $mysqli->real_connect( $realServer, $this->mUser,
103 $this->mPassword, $this->mDBname, $port, $socket, $connFlags )
104 ) {
105 return $mysqli;
106 }
107
108 return false;
109 }
110
111 protected function connectInitCharset() {
112 // already done in mysqlConnect()
113 return true;
114 }
115
116 /**
117 * @param string $charset
118 * @return bool
119 */
120 protected function mysqlSetCharset( $charset ) {
121 $conn = $this->getBindingHandle();
122
123 if ( method_exists( $conn, 'set_charset' ) ) {
124 return $conn->set_charset( $charset );
125 } else {
126 return $this->query( 'SET NAMES ' . $charset, __METHOD__ );
127 }
128 }
129
130 /**
131 * @return bool
132 */
133 protected function closeConnection() {
134 $conn = $this->getBindingHandle();
135
136 return $conn->close();
137 }
138
139 /**
140 * @return int
141 */
142 function insertId() {
143 $conn = $this->getBindingHandle();
144
145 return (int)$conn->insert_id;
146 }
147
148 /**
149 * @return int
150 */
151 function lastErrno() {
152 if ( $this->mConn ) {
153 return $this->mConn->errno;
154 } else {
155 return mysqli_connect_errno();
156 }
157 }
158
159 /**
160 * @return int
161 */
162 function affectedRows() {
163 $conn = $this->getBindingHandle();
164
165 return $conn->affected_rows;
166 }
167
168 /**
169 * @param string $db
170 * @return bool
171 */
172 function selectDB( $db ) {
173 $conn = $this->getBindingHandle();
174
175 $this->mDBname = $db;
176
177 return $conn->select_db( $db );
178 }
179
180 /**
181 * @param mysqli $res
182 * @return bool
183 */
184 protected function mysqlFreeResult( $res ) {
185 $res->free_result();
186
187 return true;
188 }
189
190 /**
191 * @param mysqli $res
192 * @return bool
193 */
194 protected function mysqlFetchObject( $res ) {
195 $object = $res->fetch_object();
196 if ( $object === null ) {
197 return false;
198 }
199
200 return $object;
201 }
202
203 /**
204 * @param mysqli $res
205 * @return bool
206 */
207 protected function mysqlFetchArray( $res ) {
208 $array = $res->fetch_array();
209 if ( $array === null ) {
210 return false;
211 }
212
213 return $array;
214 }
215
216 /**
217 * @param mysqli $res
218 * @return mixed
219 */
220 protected function mysqlNumRows( $res ) {
221 return $res->num_rows;
222 }
223
224 /**
225 * @param mysqli $res
226 * @return mixed
227 */
228 protected function mysqlNumFields( $res ) {
229 return $res->field_count;
230 }
231
232 /**
233 * @param mysqli $res
234 * @param int $n
235 * @return mixed
236 */
237 protected function mysqlFetchField( $res, $n ) {
238 $field = $res->fetch_field_direct( $n );
239
240 // Add missing properties to result (using flags property)
241 // which will be part of function mysql-fetch-field for backward compatibility
242 $field->not_null = $field->flags & MYSQLI_NOT_NULL_FLAG;
243 $field->primary_key = $field->flags & MYSQLI_PRI_KEY_FLAG;
244 $field->unique_key = $field->flags & MYSQLI_UNIQUE_KEY_FLAG;
245 $field->multiple_key = $field->flags & MYSQLI_MULTIPLE_KEY_FLAG;
246 $field->binary = $field->flags & MYSQLI_BINARY_FLAG;
247 $field->numeric = $field->flags & MYSQLI_NUM_FLAG;
248 $field->blob = $field->flags & MYSQLI_BLOB_FLAG;
249 $field->unsigned = $field->flags & MYSQLI_UNSIGNED_FLAG;
250 $field->zerofill = $field->flags & MYSQLI_ZEROFILL_FLAG;
251
252 return $field;
253 }
254
255 /**
256 * @param resource|ResultWrapper $res
257 * @param int $n
258 * @return mixed
259 */
260 protected function mysqlFieldName( $res, $n ) {
261 $field = $res->fetch_field_direct( $n );
262
263 return $field->name;
264 }
265
266 /**
267 * @param resource|ResultWrapper $res
268 * @param int $n
269 * @return mixed
270 */
271 protected function mysqlFieldType( $res, $n ) {
272 $field = $res->fetch_field_direct( $n );
273
274 return $field->type;
275 }
276
277 /**
278 * @param resource|ResultWrapper $res
279 * @param int $row
280 * @return mixed
281 */
282 protected function mysqlDataSeek( $res, $row ) {
283 return $res->data_seek( $row );
284 }
285
286 /**
287 * @param mysqli $conn Optional connection object
288 * @return string
289 */
290 protected function mysqlError( $conn = null ) {
291 if ( $conn === null ) {
292 return mysqli_connect_error();
293 } else {
294 return $conn->error;
295 }
296 }
297
298 /**
299 * Escapes special characters in a string for use in an SQL statement
300 * @param string $s
301 * @return string
302 */
303 protected function mysqlRealEscapeString( $s ) {
304 $conn = $this->getBindingHandle();
305
306 return $conn->real_escape_string( $s );
307 }
308
309 protected function mysqlPing() {
310 $conn = $this->getBindingHandle();
311
312 return $conn->ping();
313 }
314
315 /**
316 * Give an id for the connection
317 *
318 * mysql driver used resource id, but mysqli objects cannot be cast to string.
319 * @return string
320 */
321 public function __toString() {
322 if ( $this->mConn instanceof Mysqli ) {
323 return (string)$this->mConn->thread_id;
324 } else {
325 // mConn might be false or something.
326 return (string)$this->mConn;
327 }
328 }
329 }