2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Interface to the improved MySQL extension (MySQLi)
6 * @package PhpMyAdmin-DBI-MySQLi
8 if (! defined('PHPMYADMIN')) {
12 require_once './libraries/logging.lib.php';
17 if (!defined('PMA_MYSQL_CLIENT_API')) {
18 $client_api = explode('.', mysqli_get_client_info());
19 define('PMA_MYSQL_CLIENT_API', (int)sprintf('%d%02d%02d', $client_api[0], $client_api[1], intval($client_api[2])));
24 * some PHP versions are reporting extra messages like "No index used in query"
27 mysqli_report(MYSQLI_REPORT_OFF
);
30 * some older mysql client libs are missing these constants ...
32 if (! defined('MYSQLI_BINARY_FLAG')) {
33 define('MYSQLI_BINARY_FLAG', 128);
37 * @see http://bugs.php.net/36007
39 if (! defined('MYSQLI_TYPE_NEWDECIMAL')) {
40 define('MYSQLI_TYPE_NEWDECIMAL', 246);
42 if (! defined('MYSQLI_TYPE_BIT')) {
43 define('MYSQLI_TYPE_BIT', 16);
47 if (! defined('MYSQLI_TYPE_VARCHAR')) {
48 define('MYSQLI_TYPE_VARCHAR', 15);
52 * Helper function for connecting to the database server
57 * @param string $password
58 * @param string $dbname
59 * @param int $server_port
60 * @param string $server_socket
61 * @param int $client_flags
62 * @param bool $persistent
65 function PMA_DBI_real_connect($link, $host, $user, $password, $dbname, $server_port, $server_socket, $client_flags = null, $persistent = false)
69 if ($cfg['PersistentConnections'] ||
$persistent) {
72 if ($client_flags === null) {
73 return @mysqli_real_connect
(
83 return @mysqli_real_connect
(
97 * connects to the database server
99 * @param string $user mysql user name
100 * @param string $password mysql user password
101 * @param bool $is_controluser
102 * @param array $server host/port/socket
103 * @param bool $auxiliary_connection (when true, don't go back to login if connection fails)
104 * @return mixed false on error or a mysqli object on success
106 function PMA_DBI_connect($user, $password, $is_controluser = false, $server = null, $auxiliary_connection = false)
111 $server_port = (empty($server['port']))
113 : (int)$server['port'];
114 $server_socket = (empty($server['socket']))
117 $server['host'] = (empty($server['host']))
121 $server_port = (empty($cfg['Server']['port']))
123 : (int) $cfg['Server']['port'];
124 $server_socket = (empty($cfg['Server']['socket']))
126 : $cfg['Server']['socket'];
129 // NULL enables connection to the default socket
131 $link = mysqli_init();
133 mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE
, true);
137 /* Optionally compress connection */
138 if ($cfg['Server']['compress'] && defined('MYSQLI_CLIENT_COMPRESS')) {
139 $client_flags |
= MYSQLI_CLIENT_COMPRESS
;
142 /* Optionally enable SSL */
143 if ($cfg['Server']['ssl'] && defined('MYSQLI_CLIENT_SSL')) {
144 $client_flags |
= MYSQLI_CLIENT_SSL
;
148 $return_value = @PMA_DBI_real_connect
(
150 $cfg['Server']['host'],
158 // Retry with empty password if we're allowed to
159 if ($return_value == false && isset($cfg['Server']['nopassword']) && $cfg['Server']['nopassword'] && !$is_controluser) {
160 $return_value = @PMA_DBI_real_connect
(
162 $cfg['Server']['host'],
172 $return_value = @PMA_DBI_real_connect
(
183 if ($return_value == false) {
184 if ($is_controluser) {
186 __('Connection for controluser as defined in your configuration failed.'),
191 // we could be calling PMA_DBI_connect() to connect to another
192 // server, for example in the Synchronize feature, so do not
193 // go back to main login if it fails
194 if (! $auxiliary_connection) {
195 PMA_log_user($user, 'mysql-denied');
201 PMA_DBI_postConnect($link, $is_controluser);
208 * selects given database
210 * @param string $dbname database name to select
211 * @param mysqli $link the mysqli object
214 function PMA_DBI_select_db($dbname, $link = null)
217 if (isset($GLOBALS['userlink'])) {
218 $link = $GLOBALS['userlink'];
223 return mysqli_select_db($link, $dbname);
227 * runs a query and returns the result
229 * @param string $query query to execute
230 * @param mysqli $link mysqli object
231 * @param int $options
232 * @return mysqli_result|bool
234 function PMA_DBI_real_query($query, $link, $options)
236 if ($options == ($options | PMA_DBI_QUERY_STORE
)) {
237 $method = MYSQLI_STORE_RESULT
;
238 } elseif ($options == ($options | PMA_DBI_QUERY_UNBUFFERED
)) {
239 $method = MYSQLI_USE_RESULT
;
244 return mysqli_query($link, $query, $method);
248 * returns array of rows with associative and numeric keys from $result
250 * @param mysqli_result $result
253 function PMA_DBI_fetch_array($result)
255 return mysqli_fetch_array($result, MYSQLI_BOTH
);
259 * returns array of rows with associative keys from $result
261 * @param mysqli_result $result
264 function PMA_DBI_fetch_assoc($result)
266 return mysqli_fetch_array($result, MYSQLI_ASSOC
);
270 * returns array of rows with numeric keys from $result
272 * @param mysqli_result $result
275 function PMA_DBI_fetch_row($result)
277 return mysqli_fetch_array($result, MYSQLI_NUM
);
281 * Adjusts the result pointer to an arbitrary row in the result
285 * @return bool true on success, false on failure
287 function PMA_DBI_data_seek($result, $offset)
289 return mysqli_data_seek($result, $offset);
293 * Frees memory associated with the result
295 * @param mysqli_result $result
297 function PMA_DBI_free_result($result)
299 if ($result instanceof mysqli_result
) {
300 mysqli_free_result($result);
305 * Check if there are any more query results from a multi query
307 * @param mysqli $link the mysqli object
308 * @return bool true or false
310 function PMA_DBI_more_results($link = null)
313 if (isset($GLOBALS['userlink'])) {
314 $link = $GLOBALS['userlink'];
319 return mysqli_more_results($link);
323 * Prepare next result from multi_query
325 * @param mysqli $link the mysqli object
326 * @return bool true or false
328 function PMA_DBI_next_result($link = null)
331 if (isset($GLOBALS['userlink'])) {
332 $link = $GLOBALS['userlink'];
337 return mysqli_next_result($link);
341 * Returns a string representing the type of connection used
343 * @param resource $link mysql link
344 * @return string type of connection used
346 function PMA_DBI_get_host_info($link = null)
348 if (null === $link) {
349 if (isset($GLOBALS['userlink'])) {
350 $link = $GLOBALS['userlink'];
355 return mysqli_get_host_info($link);
359 * Returns the version of the MySQL protocol used
361 * @param resource $link mysql link
362 * @return integer version of the MySQL protocol used
364 function PMA_DBI_get_proto_info($link = null)
366 if (null === $link) {
367 if (isset($GLOBALS['userlink'])) {
368 $link = $GLOBALS['userlink'];
373 return mysqli_get_proto_info($link);
377 * returns a string that represents the client library version
379 * @return string MySQL client library version
381 function PMA_DBI_get_client_info()
383 return mysqli_get_client_info();
387 * returns last error message or false if no errors occured
389 * @param resource $link mysql link
390 * @return string|bool $error or false
392 function PMA_DBI_getError($link = null)
394 $GLOBALS['errno'] = 0;
396 /* Treat false same as null because of controllink */
397 if ($link === false) {
401 if (null === $link && isset($GLOBALS['userlink'])) {
402 $link =& $GLOBALS['userlink'];
403 // Do not stop now. We still can get the error code
404 // with mysqli_connect_errno()
409 if (null !== $link) {
410 $error_number = mysqli_errno($link);
411 $error_message = mysqli_error($link);
413 $error_number = mysqli_connect_errno();
414 $error_message = mysqli_connect_error();
416 if (0 == $error_number) {
420 // keep the error number for further check after the call to PMA_DBI_getError()
421 $GLOBALS['errno'] = $error_number;
423 return PMA_DBI_formatError($error_number, $error_message);
427 * returns the number of rows returned by last query
429 * @param mysqli_result $result
432 function PMA_DBI_num_rows($result)
434 // see the note for PMA_DBI_try_query();
435 if (!is_bool($result)) {
436 return @mysqli_num_rows
($result);
443 * returns last inserted auto_increment id for given $link or $GLOBALS['userlink']
445 * @param mysqli $link the mysqli object
448 function PMA_DBI_insert_id($link = null)
451 if (isset($GLOBALS['userlink'])) {
452 $link = $GLOBALS['userlink'];
457 // When no controluser is defined, using mysqli_insert_id($link)
458 // does not always return the last insert id due to a mixup with
459 // the tracking mechanism, but this works:
460 return PMA_DBI_fetch_value('SELECT LAST_INSERT_ID();', 0, 0, $link);
461 // Curiously, this problem does not happen with the mysql extension but
462 // there is another problem with BIGINT primary keys so PMA_DBI_insert_id()
463 // in the mysql extension also uses this logic.
467 * returns the number of rows affected by last query
469 * @param mysqli $link the mysqli object
470 * @param boolean $get_from_cache
473 function PMA_DBI_affected_rows($link = null, $get_from_cache = true)
476 if (isset($GLOBALS['userlink'])) {
477 $link = $GLOBALS['userlink'];
482 if ($get_from_cache) {
483 return $GLOBALS['cached_affected_rows'];
485 return mysqli_affected_rows($link);
490 * returns metainfo for fields in $result
492 * @param mysqli_result $result
493 * @return array meta info for fields in $result
495 function PMA_DBI_get_fields_meta($result)
497 // Build an associative array for a type look up
499 $typeAr[MYSQLI_TYPE_DECIMAL
] = 'real';
500 $typeAr[MYSQLI_TYPE_NEWDECIMAL
] = 'real';
501 $typeAr[MYSQLI_TYPE_BIT
] = 'int';
502 $typeAr[MYSQLI_TYPE_TINY
] = 'int';
503 $typeAr[MYSQLI_TYPE_SHORT
] = 'int';
504 $typeAr[MYSQLI_TYPE_LONG
] = 'int';
505 $typeAr[MYSQLI_TYPE_FLOAT
] = 'real';
506 $typeAr[MYSQLI_TYPE_DOUBLE
] = 'real';
507 $typeAr[MYSQLI_TYPE_NULL
] = 'null';
508 $typeAr[MYSQLI_TYPE_TIMESTAMP
] = 'timestamp';
509 $typeAr[MYSQLI_TYPE_LONGLONG
] = 'int';
510 $typeAr[MYSQLI_TYPE_INT24
] = 'int';
511 $typeAr[MYSQLI_TYPE_DATE
] = 'date';
512 $typeAr[MYSQLI_TYPE_TIME
] = 'time';
513 $typeAr[MYSQLI_TYPE_DATETIME
] = 'datetime';
514 $typeAr[MYSQLI_TYPE_YEAR
] = 'year';
515 $typeAr[MYSQLI_TYPE_NEWDATE
] = 'date';
516 $typeAr[MYSQLI_TYPE_ENUM
] = 'unknown';
517 $typeAr[MYSQLI_TYPE_SET
] = 'unknown';
518 $typeAr[MYSQLI_TYPE_TINY_BLOB
] = 'blob';
519 $typeAr[MYSQLI_TYPE_MEDIUM_BLOB
] = 'blob';
520 $typeAr[MYSQLI_TYPE_LONG_BLOB
] = 'blob';
521 $typeAr[MYSQLI_TYPE_BLOB
] = 'blob';
522 $typeAr[MYSQLI_TYPE_VAR_STRING
] = 'string';
523 $typeAr[MYSQLI_TYPE_STRING
] = 'string';
524 $typeAr[MYSQLI_TYPE_VARCHAR
] = 'string'; // for Drizzle
525 // MySQL returns MYSQLI_TYPE_STRING for CHAR
526 // and MYSQLI_TYPE_CHAR === MYSQLI_TYPE_TINY
527 // so this would override TINYINT and mark all TINYINT as string
528 // https://sf.net/tracker/?func=detail&aid=1532111&group_id=23067&atid=377408
529 //$typeAr[MYSQLI_TYPE_CHAR] = 'string';
530 $typeAr[MYSQLI_TYPE_GEOMETRY
] = 'geometry';
531 $typeAr[MYSQLI_TYPE_BIT
] = 'bit';
533 $fields = mysqli_fetch_fields($result);
535 // this happens sometimes (seen under MySQL 4.0.25)
536 if (!is_array($fields)) {
540 foreach ($fields as $k => $field) {
541 $fields[$k]->_type
= $field->type
;
542 $fields[$k]->type
= $typeAr[$field->type
];
543 $fields[$k]->_flags
= $field->flags
;
544 $fields[$k]->flags
= PMA_DBI_field_flags($result, $k);
546 // Enhance the field objects for mysql-extension compatibilty
547 //$flags = explode(' ', $fields[$k]->flags);
548 //array_unshift($flags, 'dummy');
549 $fields[$k]->multiple_key
550 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_MULTIPLE_KEY_FLAG
);
551 $fields[$k]->primary_key
552 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_PRI_KEY_FLAG
);
553 $fields[$k]->unique_key
554 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_UNIQUE_KEY_FLAG
);
555 $fields[$k]->not_null
556 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_NOT_NULL_FLAG
);
557 $fields[$k]->unsigned
558 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_UNSIGNED_FLAG
);
559 $fields[$k]->zerofill
560 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_ZEROFILL_FLAG
);
562 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_NUM_FLAG
);
564 = (int) (bool) ($fields[$k]->_flags
& MYSQLI_BLOB_FLAG
);
570 * return number of fields in given $result
572 * @param mysqli_result $result
573 * @return int field count
575 function PMA_DBI_num_fields($result)
577 return mysqli_num_fields($result);
581 * returns the length of the given field $i in $result
583 * @param mysqli_result $result
584 * @param int $i field
585 * @return int length of field
587 function PMA_DBI_field_len($result, $i)
589 return mysqli_fetch_field_direct($result, $i)->length
;
593 * returns name of $i. field in $result
595 * @param mysqli_result $result
596 * @param int $i field
597 * @return string name of $i. field in $result
599 function PMA_DBI_field_name($result, $i)
601 return mysqli_fetch_field_direct($result, $i)->name
;
605 * returns concatenated string of human readable field flags
607 * @param mysqli_result $result
608 * @param int $i field
609 * @return string field flags
611 function PMA_DBI_field_flags($result, $i)
613 // This is missing from PHP 5.2.5, see http://bugs.php.net/bug.php?id=44846
614 if (! defined('MYSQLI_ENUM_FLAG')) {
615 define('MYSQLI_ENUM_FLAG', 256); // see MySQL source include/mysql_com.h
617 $f = mysqli_fetch_field_direct($result, $i);
619 $charsetnr = $f->charsetnr
;
622 if ($f & MYSQLI_UNIQUE_KEY_FLAG
) {
625 if ($f & MYSQLI_NUM_FLAG
) {
628 if ($f & MYSQLI_PART_KEY_FLAG
) {
629 $flags .= 'part_key ';
631 if ($f & MYSQLI_SET_FLAG
) {
634 if ($f & MYSQLI_TIMESTAMP_FLAG
) {
635 $flags .= 'timestamp ';
637 if ($f & MYSQLI_AUTO_INCREMENT_FLAG
) {
638 $flags .= 'auto_increment ';
640 if ($f & MYSQLI_ENUM_FLAG
) {
643 // See http://dev.mysql.com/doc/refman/6.0/en/c-api-datatypes.html:
644 // to determine if a string is binary, we should not use MYSQLI_BINARY_FLAG
645 // but instead the charsetnr member of the MYSQL_FIELD
646 // structure. Watch out: some types like DATE returns 63 in charsetnr
647 // so we have to check also the type.
648 // Unfortunately there is no equivalent in the mysql extension.
649 if (($type == MYSQLI_TYPE_TINY_BLOB ||
$type == MYSQLI_TYPE_BLOB ||
$type == MYSQLI_TYPE_MEDIUM_BLOB ||
$type == MYSQLI_TYPE_LONG_BLOB ||
$type == MYSQLI_TYPE_VAR_STRING ||
$type == MYSQLI_TYPE_STRING
) && 63 == $charsetnr) {
652 if ($f & MYSQLI_ZEROFILL_FLAG
) {
653 $flags .= 'zerofill ';
655 if ($f & MYSQLI_UNSIGNED_FLAG
) {
656 $flags .= 'unsigned ';
658 if ($f & MYSQLI_BLOB_FLAG
) {
661 if ($f & MYSQLI_MULTIPLE_KEY_FLAG
) {
662 $flags .= 'multiple_key ';
664 if ($f & MYSQLI_UNIQUE_KEY_FLAG
) {
665 $flags .= 'unique_key ';
667 if ($f & MYSQLI_PRI_KEY_FLAG
) {
668 $flags .= 'primary_key ';
670 if ($f & MYSQLI_NOT_NULL_FLAG
) {
671 $flags .= 'not_null ';