Drizzle DBI: default to fully buffered query, like in mysql and mysqli
[phpmyadmin.git] / libraries / dbi / drizzle.dbi.lib.php
blob153c64d82cde46026124cc5e36a34023c020b15f
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Interface to the Drizzle extension
6 * WARNING - EXPERIMENTAL, never use in production, drizzle module segfaults often and when you least expect it to
8 * TODO: This file and drizzle-wrappers.lib.php should be devoid of any segault related hacks.
9 * TODO: Crashing versions of drizzle module and/or libdrizzle should be blacklisted
11 * @package phpMyAdmin-DBI-Drizzle
13 if (! defined('PHPMYADMIN')) {
14 exit;
17 require_once './libraries/logging.lib.php';
18 require_once './libraries/dbi/drizzle-wrappers.lib.php';
20 /**
21 * MySQL client API
23 if (!defined('PMA_MYSQL_CLIENT_API')) {
24 define('PMA_MYSQL_CLIENT_API', (int)drizzle_version());
27 /**
28 * Helper function for connecting to the database server
30 * @param PMA_Drizzle $drizzle
31 * @param string $host
32 * @param int $port
33 * @param string $uds
34 * @param string $user
35 * @param string $password
36 * @param string $db
37 * @param int $options
38 * @return PMA_DrizzleCon
40 function PMA_DBI_real_connect($drizzle, $host, $port, $uds, $user, $password, $db = null, $options = DRIZZLE_CON_NONE)
42 if ($uds) {
43 $con = $drizzle->addUds($uds, $user, $password, $db, $options);
44 } else {
45 $con = $drizzle->addTcp($host, $port, $user, $password, $db, $options);
48 return $con;
51 /**
52 * connects to the database server
54 * @param string $user drizzle user name
55 * @param string $password drizzle user password
56 * @param bool $is_controluser
57 * @param array $server host/port/socket
58 * @param bool $auxiliary_connection (when true, don't go back to login if connection fails)
59 * @return mixed false on error or a mysqli object on success
61 function PMA_DBI_connect($user, $password, $is_controluser = false, $server = null, $auxiliary_connection = false)
63 global $cfg;
65 if ($server) {
66 $server_port = (empty($server['port']))
67 ? false
68 : (int)$server['port'];
69 $server_socket = (empty($server['socket']))
70 ? ''
71 : $server['socket'];
72 $server['host'] = (empty($server['host']))
73 ? 'localhost'
74 : $server['host'];
75 } else {
76 $server_port = (empty($cfg['Server']['port']))
77 ? false
78 : (int) $cfg['Server']['port'];
79 $server_socket = (empty($cfg['Server']['socket']))
80 ? null
81 : $cfg['Server']['socket'];
84 if (strtolower($GLOBALS['cfg']['Server']['connect_type']) == 'tcp') {
85 $GLOBALS['cfg']['Server']['socket'] = '';
88 $drizzle = new PMA_Drizzle();
90 $client_flags = 0;
92 /* Optionally compress connection */
93 if ($GLOBALS['cfg']['Server']['compress']) {
94 $client_flags |= DRIZZLE_CAPABILITIES_COMPRESS;
97 /* Optionally enable SSL */
98 if ($GLOBALS['cfg']['Server']['ssl']) {
99 $client_flags |= DRIZZLE_CAPABILITIES_SSL;
102 if (!$server) {
103 $link = @PMA_DBI_real_connect($drizzle, $cfg['Server']['host'], $server_port, $server_socket, $user, $password, false, $client_flags);
104 // Retry with empty password if we're allowed to
105 if ($link == false && isset($cfg['Server']['nopassword']) && $cfg['Server']['nopassword'] && !$is_controluser) {
106 $link = @PMA_DBI_real_connect($drizzle, $cfg['Server']['host'], $server_port, $server_socket, $user, null, false, $client_flags);
108 } else {
109 $link = @PMA_DBI_real_connect($drizzle, $server['host'], $server_port, $server_socket, $user, $password);
112 if ($link == false) {
113 if ($is_controluser) {
114 trigger_error(__('Connection for controluser as defined in your configuration failed.'), E_USER_WARNING);
115 return false;
117 // we could be calling PMA_DBI_connect() to connect to another
118 // server, for example in the Synchronize feature, so do not
119 // go back to main login if it fails
120 if (! $auxiliary_connection) {
121 PMA_log_user($user, 'drizzle-denied');
122 PMA_auth_fails();
123 } else {
124 return false;
126 } else {
127 PMA_DBI_postConnect($link, $is_controluser);
130 return $link;
134 * selects given database
136 * @param string $dbname database name to select
137 * @param PMA_DrizzleCom $link connection object
138 * @return bool
140 function PMA_DBI_select_db($dbname, $link = null)
142 if (empty($link)) {
143 if (isset($GLOBALS['userlink'])) {
144 $link = $GLOBALS['userlink'];
145 } else {
146 return false;
149 return $link->selectDb($dbname);
153 * runs a query and returns the result
155 * @param string $query query to execute
156 * @param PMA_DrizzleCon $link connection object
157 * @param int $options
158 * @return PMA_DrizzleResult
160 function PMA_DBI_real_query($query, $link, $options)
162 $buffer_mode = $options & PMA_DBI_QUERY_UNBUFFERED
163 ? PMA_Drizzle::BUFFER_ROW
164 : PMA_Drizzle::BUFFER_RESULT;
165 $res = $link->query($query, $buffer_mode);
166 return $res;
170 * returns array of rows with associative and numeric keys from $result
172 * @param PMA_DrizzleResult $result
173 * @return array
175 function PMA_DBI_fetch_array($result)
177 return $result->fetchRow(PMA_Drizzle::FETCH_BOTH);
181 * returns array of rows with associative keys from $result
183 * @param PMA_DrizzleResult $result
184 * @return array
186 function PMA_DBI_fetch_assoc($result)
188 return $result->fetchRow(PMA_Drizzle::FETCH_ASSOC);
192 * returns array of rows with numeric keys from $result
194 * @param PMA_DrizzleResult $result
195 * @return array
197 function PMA_DBI_fetch_row($result)
199 return $result->fetchRow(PMA_Drizzle::FETCH_NUM);
203 * Adjusts the result pointer to an arbitrary row in the result
205 * @param PMA_DrizzleResult $result
206 * @param int $offset
207 * @return boolean true on success, false on failure
209 function PMA_DBI_data_seek($result, $offset)
211 return $result->seek($offset);
215 * Frees memory associated with the result
217 * @param PMA_DrizzleResult $result
219 function PMA_DBI_free_result($result)
221 if ($result instanceof PMA_DrizzleResult) {
222 $result->free();
227 * Check if there are any more query results from a multi query
229 * @return bool false
231 function PMA_DBI_more_results() {
232 // N.B.: PHP's 'mysql' extension does not support
233 // multi_queries so this function will always
234 // return false. Use the 'mysqli' extension, if
235 // you need support for multi_queries.
236 return false;
240 * Prepare next result from multi_query
242 * @return bool false
244 function PMA_DBI_next_result() {
245 // N.B.: PHP's 'mysql' extension does not support
246 // multi_queries so this function will always
247 // return false. Use the 'mysqli' extension, if
248 // you need support for multi_queries.
249 return false;
253 * Returns a string representing the type of connection used
254 * @param PMA_DrizzleCon $link connection object
255 * @return string type of connection used
257 function PMA_DBI_get_host_info($link = null)
259 if (null === $link) {
260 if (isset($GLOBALS['userlink'])) {
261 $link = $GLOBALS['userlink'];
262 } else {
263 return false;
267 $str = $link->port()
268 ? $link->host() . ':' . $link->port() . ' via TCP/IP'
269 : 'Localhost via UNIX socket';
270 return $str;
274 * Returns the version of the Drizzle protocol used
275 * @param PMA_DrizzleCon $link connection object
276 * @return int version of the Drizzle protocol used
278 function PMA_DBI_get_proto_info($link = null)
280 if (null === $link) {
281 if (isset($GLOBALS['userlink'])) {
282 $link = $GLOBALS['userlink'];
283 } else {
284 return false;
288 return $link->protocolVersion();
292 * returns a string that represents the client library version
293 * @return string Drizzle client library version
295 function PMA_DBI_get_client_info()
297 return 'libdrizzle (Drizzle ' . drizzle_version() . ')';
301 * returns last error message or false if no errors occured
303 * @param PMA_DrizzleCon $link connection object
304 * @return string|bool $error or false
306 function PMA_DBI_getError($link = null)
308 $GLOBALS['errno'] = 0;
310 /* Treat false same as null because of controllink */
311 if ($link === false) {
312 $link = null;
315 if (null === $link && isset($GLOBALS['userlink'])) {
316 $link =& $GLOBALS['userlink'];
317 // Do not stop now. We still can get the error code
318 // with mysqli_connect_errno()
319 // } else {
320 // return false;
323 if (null !== $link) {
324 $error_number = drizzle_con_errno($link->getConnectionObject());
325 $error_message = drizzle_con_error($link->getConnectionObject());
326 } else {
327 $error_number = drizzle_errno();
328 $error_message = drizzle_error();
330 if (0 == $error_number) {
331 return false;
334 // keep the error number for further check after the call to PMA_DBI_getError()
335 $GLOBALS['errno'] = $error_number;
337 if (! empty($error_message)) {
338 $error_message = PMA_DBI_convert_message($error_message);
341 $error_message = htmlspecialchars($error_message);
343 if ($error_number == 2002) {
344 $error = '#' . ((string) $error_number) . ' - ' . __('The server is not responding') . ' ' . __('(or the local Drizzle server\'s socket is not correctly configured)');
345 } else {
346 $error = '#' . ((string) $error_number) . ' - ' . $error_message;
348 return $error;
352 * returns the number of rows returned by last query
354 * @param PMA_DrizzleResult $result
355 * @return string|int
357 function PMA_DBI_num_rows($result)
359 // see the note for PMA_DBI_try_query();
360 if (!is_bool($result)) {
361 return @$result->numRows();
362 } else {
363 return 0;
368 * returns last inserted auto_increment id for given $link or $GLOBALS['userlink']
370 * @param PMA_DrizzleCon $link connection object
371 * @return string|int
373 function PMA_DBI_insert_id($link = null)
375 if (empty($link)) {
376 if (isset($GLOBALS['userlink'])) {
377 $link = $GLOBALS['userlink'];
378 } else {
379 return false;
383 // copied from mysql and mysqli
385 // When no controluser is defined, using mysqli_insert_id($link)
386 // does not always return the last insert id due to a mixup with
387 // the tracking mechanism, but this works:
388 return PMA_DBI_fetch_value('SELECT LAST_INSERT_ID();', 0, 0, $link);
389 // Curiously, this problem does not happen with the mysql extension but
390 // there is another problem with BIGINT primary keys so PMA_DBI_insert_id()
391 // in the mysql extension also uses this logic.
395 * returns the number of rows affected by last query
397 * @param PMA_DrizzleResult $link connection object
398 * @param bool $get_from_cache
399 * @return string|int
401 function PMA_DBI_affected_rows($link = null, $get_from_cache = true)
403 if (empty($link)) {
404 if (isset($GLOBALS['userlink'])) {
405 $link = $GLOBALS['userlink'];
406 } else {
407 return false;
410 if ($get_from_cache) {
411 return $GLOBALS['cached_affected_rows'];
412 } else {
413 return $link->affectedRows();
418 * returns metainfo for fields in $result
420 * @param PMA_DrizzleResult $result
421 * @return array meta info for fields in $result
423 function PMA_DBI_get_fields_meta($result)
425 // Build an associative array for a type look up
426 $typeAr = array();
427 /*$typeAr[DRIZZLE_COLUMN_TYPE_DECIMAL] = 'real';
428 $typeAr[DRIZZLE_COLUMN_TYPE_NEWDECIMAL] = 'real';
429 $typeAr[DRIZZLE_COLUMN_TYPE_BIT] = 'int';
430 $typeAr[DRIZZLE_COLUMN_TYPE_TINY] = 'int';
431 $typeAr[DRIZZLE_COLUMN_TYPE_SHORT] = 'int';
432 $typeAr[DRIZZLE_COLUMN_TYPE_LONG] = 'int';
433 $typeAr[DRIZZLE_COLUMN_TYPE_FLOAT] = 'real';
434 $typeAr[DRIZZLE_COLUMN_TYPE_DOUBLE] = 'real';
435 $typeAr[DRIZZLE_COLUMN_TYPE_NULL] = 'null';
436 $typeAr[DRIZZLE_COLUMN_TYPE_TIMESTAMP] = 'timestamp';
437 $typeAr[DRIZZLE_COLUMN_TYPE_LONGLONG] = 'int';
438 $typeAr[DRIZZLE_COLUMN_TYPE_INT24] = 'int';
439 $typeAr[DRIZZLE_COLUMN_TYPE_DATE] = 'date';
440 $typeAr[DRIZZLE_COLUMN_TYPE_TIME] = 'date';
441 $typeAr[DRIZZLE_COLUMN_TYPE_DATETIME] = 'datetime';
442 $typeAr[DRIZZLE_COLUMN_TYPE_YEAR] = 'year';
443 $typeAr[DRIZZLE_COLUMN_TYPE_NEWDATE] = 'date';
444 $typeAr[DRIZZLE_COLUMN_TYPE_ENUM] = 'unknown';
445 $typeAr[DRIZZLE_COLUMN_TYPE_SET] = 'unknown';
446 $typeAr[DRIZZLE_COLUMN_TYPE_VIRTUAL] = 'unknown';
447 $typeAr[DRIZZLE_COLUMN_TYPE_TINY_BLOB] = 'blob';
448 $typeAr[DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB] = 'blob';
449 $typeAr[DRIZZLE_COLUMN_TYPE_LONG_BLOB] = 'blob';
450 $typeAr[DRIZZLE_COLUMN_TYPE_BLOB] = 'blob';
451 $typeAr[DRIZZLE_COLUMN_TYPE_VAR_STRING] = 'string';
452 $typeAr[DRIZZLE_COLUMN_TYPE_VARCHAR] = 'string';
453 $typeAr[DRIZZLE_COLUMN_TYPE_STRING] = 'string';
454 $typeAr[DRIZZLE_COLUMN_TYPE_GEOMETRY] = 'geometry';*/
456 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_BLOB] = 'blob';
457 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_DATE] = 'date';
458 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_DATETIME] = 'datetime';
459 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_DOUBLE] = 'real';
460 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_ENUM] = 'unknown';
461 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_LONG] = 'int';
462 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_LONGLONG] = 'int';
463 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_MAX] = 'unknown';
464 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_NULL] = 'null';
465 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_TIMESTAMP] = 'timestamp';
466 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_TINY] = 'int';
467 $typeAr[DRIZZLE_COLUMN_TYPE_DRIZZLE_VARCHAR] = 'string';
469 // array of DrizzleColumn
470 $columns = $result->getColumns();
471 // columns in a standarized format
472 $std_columns = array();
474 foreach ($columns as $k => $column) {
475 $c = new stdClass();
476 $c->name = $column->name();
477 $c->orgname = $column->origName();
478 $c->table = $column->table();
479 $c->orgtable = $column->origTable();
480 $c->def = $column->defaultValue();
481 $c->db = $column->db();
482 $c->catalog = $column->catalog();
483 // $column->maxSize() returns always 0 while size() seems
484 // to return a correct value (drizzle extension v.0.5, API v.7)
485 $c->max_length = $column->size();
486 $c->decimals = $column->decimals();
487 $c->charsetnr = $column->charset();
488 $c->type = $typeAr[$column->typeDrizzle()];
489 $c->_type = $column->type();
490 $c->flags = PMA_DBI_field_flags($result, $k);
491 $c->_flags = $column->flags();
493 $c->multiple_key = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_MULTIPLE_KEY);
494 $c->primary_key = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_PRI_KEY);
495 $c->unique_key = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_UNIQUE_KEY);
496 $c->not_null = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_NOT_NULL);
497 $c->unsigned = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_UNSIGNED);
498 $c->zerofill = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_ZEROFILL);
499 $c->numeric = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_NUM);
500 $c->blob = (int) (bool) ($c->_flags & DRIZZLE_COLUMN_FLAGS_BLOB);
502 $std_columns[] = $c;
505 return $std_columns;
509 * return number of fields in given $result
511 * @param PMA_DrizzleResult $result
512 * @return int field count
514 function PMA_DBI_num_fields($result)
516 return $result->numColumns();
520 * returns the length of the given field $i in $result
522 * @param PMA_DrizzleResult $result
523 * @param int $i field
524 * @return int length of field
526 function PMA_DBI_field_len($result, $i)
528 $colums = $result->getColumns();
529 return $colums[$i]->size();
533 * returns name of $i. field in $result
535 * @param PMA_DrizzleResult $result
536 * @param int $i field
537 * @return string name of $i. field in $result
539 function PMA_DBI_field_name($result, $i)
541 $colums = $result->getColumns();
542 return $colums[$i]->name();
546 * returns concatenated string of human readable field flags
548 * @param PMA_DrizzleResult $result
549 * @param int $i field
550 * @return string field flags
552 function PMA_DBI_field_flags($result, $i)
554 $columns = $result->getColumns();
555 $f = $columns[$i];
556 $type = $f->typeDrizzle();
557 $charsetnr = $f->charset();
558 $f = $f->flags();
559 $flags = '';
560 if ($f & DRIZZLE_COLUMN_FLAGS_UNIQUE_KEY) { $flags .= 'unique '; }
561 if ($f & DRIZZLE_COLUMN_FLAGS_NUM) { $flags .= 'num '; }
562 if ($f & DRIZZLE_COLUMN_FLAGS_PART_KEY) { $flags .= 'part_key '; }
563 if ($f & DRIZZLE_COLUMN_FLAGS_SET) { $flags .= 'set '; }
564 if ($f & DRIZZLE_COLUMN_FLAGS_TIMESTAMP) { $flags .= 'timestamp '; }
565 if ($f & DRIZZLE_COLUMN_FLAGS_AUTO_INCREMENT) { $flags .= 'auto_increment '; }
566 if ($f & DRIZZLE_COLUMN_FLAGS_ENUM) { $flags .= 'enum '; }
567 // See http://dev.mysql.com/doc/refman/6.0/en/c-api-datatypes.html:
568 // to determine if a string is binary, we should not use MYSQLI_BINARY_FLAG
569 // but instead the charsetnr member of the MYSQL_FIELD
570 // structure. Watch out: some types like DATE returns 63 in charsetnr
571 // so we have to check also the type.
572 // Unfortunately there is no equivalent in the mysql extension.
573 if (($type == DRIZZLE_COLUMN_TYPE_DRIZZLE_BLOB || $type == DRIZZLE_COLUMN_TYPE_DRIZZLE_VARCHAR) && 63 == $charsetnr) { $flags .= 'binary ';}
574 if ($f & DRIZZLE_COLUMN_FLAGS_ZEROFILL) { $flags .= 'zerofill ';}
575 if ($f & DRIZZLE_COLUMN_FLAGS_UNSIGNED) { $flags .= 'unsigned ';}
576 if ($f & DRIZZLE_COLUMN_FLAGS_BLOB) { $flags .= 'blob ';}
577 if ($f & DRIZZLE_COLUMN_FLAGS_MULTIPLE_KEY) { $flags .= 'multiple_key ';}
578 if ($f & DRIZZLE_COLUMN_FLAGS_UNIQUE_KEY) { $flags .= 'unique_key ';}
579 if ($f & DRIZZLE_COLUMN_FLAGS_PRI_KEY) { $flags .= 'primary_key ';}
580 if ($f & DRIZZLE_COLUMN_FLAGS_NOT_NULL) { $flags .= 'not_null ';}
581 return trim($flags);