commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / packages / DB / mysqli.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * The PEAR DB driver for PHP's mysqli extension
7 * for interacting with MySQL databases
8 *
9 * PHP versions 4 and 5
10 *
11 * LICENSE: This source file is subject to version 3.0 of the PHP license
12 * that is available through the world-wide-web at the following URI:
13 * http://www.php.net/license/3_0.txt. If you did not receive a copy of
14 * the PHP License and are unable to obtain it through the web, please
15 * send a note to license@php.net so we can mail you a copy immediately.
16 *
17 * @category Database
18 * @package DB
19 * @author Daniel Convissor <danielc@php.net>
20 * @copyright 1997-2007 The PHP Group
21 * @license http://www.php.net/license/3_0.txt PHP License 3.0
22 * @version CVS: $Id: mysqli.php,v 1.82 2007/09/21 13:40:41 aharvey Exp $
23 * @link http://pear.php.net/package/DB
24 */
25
26 /**
27 * Obtain the DB_common class so it can be extended from
28 */
29 require_once 'DB/common.php';
30
31 /**
32 * The methods PEAR DB uses to interact with PHP's mysqli extension
33 * for interacting with MySQL databases
34 *
35 * This is for MySQL versions 4.1 and above. Requires PHP 5.
36 *
37 * Note that persistent connections no longer exist.
38 *
39 * These methods overload the ones declared in DB_common.
40 *
41 * @category Database
42 * @package DB
43 * @author Daniel Convissor <danielc@php.net>
44 * @copyright 1997-2007 The PHP Group
45 * @license http://www.php.net/license/3_0.txt PHP License 3.0
46 * @version Release: 1.7.13
47 * @link http://pear.php.net/package/DB
48 * @since Class functional since Release 1.6.3
49 */
50 class DB_mysqli extends DB_common
51 {
52 // {{{ properties
53
54 /**
55 * The DB driver type (mysql, oci8, odbc, etc.)
56 * @var string
57 */
58 var $phptype = 'mysqli';
59
60 /**
61 * The database syntax variant to be used (db2, access, etc.), if any
62 * @var string
63 */
64 var $dbsyntax = 'mysqli';
65
66 /**
67 * The capabilities of this DB implementation
68 *
69 * The 'new_link' element contains the PHP version that first provided
70 * new_link support for this DBMS. Contains false if it's unsupported.
71 *
72 * Meaning of the 'limit' element:
73 * + 'emulate' = emulate with fetch row by number
74 * + 'alter' = alter the query
75 * + false = skip rows
76 *
77 * @var array
78 */
79 var $features = array(
80 'limit' => 'alter',
81 'new_link' => false,
82 'numrows' => true,
83 'pconnect' => false,
84 'prepare' => false,
85 'ssl' => true,
86 'transactions' => true,
87 );
88
89 /**
90 * A mapping of native error codes to DB error codes
91 * @var array
92 */
93 var $errorcode_map = array(
94 1004 => DB_ERROR_CANNOT_CREATE,
95 1005 => DB_ERROR_CANNOT_CREATE,
96 1006 => DB_ERROR_CANNOT_CREATE,
97 1007 => DB_ERROR_ALREADY_EXISTS,
98 1008 => DB_ERROR_CANNOT_DROP,
99 1022 => DB_ERROR_ALREADY_EXISTS,
100 1044 => DB_ERROR_ACCESS_VIOLATION,
101 1046 => DB_ERROR_NODBSELECTED,
102 1048 => DB_ERROR_CONSTRAINT,
103 1049 => DB_ERROR_NOSUCHDB,
104 1050 => DB_ERROR_ALREADY_EXISTS,
105 1051 => DB_ERROR_NOSUCHTABLE,
106 1054 => DB_ERROR_NOSUCHFIELD,
107 1061 => DB_ERROR_ALREADY_EXISTS,
108 1062 => DB_ERROR_ALREADY_EXISTS,
109 1064 => DB_ERROR_SYNTAX,
110 1091 => DB_ERROR_NOT_FOUND,
111 1100 => DB_ERROR_NOT_LOCKED,
112 1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
113 1142 => DB_ERROR_ACCESS_VIOLATION,
114 1146 => DB_ERROR_NOSUCHTABLE,
115 1216 => DB_ERROR_CONSTRAINT,
116 1217 => DB_ERROR_CONSTRAINT,
117 1356 => DB_ERROR_INVALID_VIEW,
118 1365 => DB_ERROR_DIVZERO,
119 1451 => DB_ERROR_CONSTRAINT,
120 1452 => DB_ERROR_CONSTRAINT,
121 );
122
123 /**
124 * The raw database connection created by PHP
125 * @var resource
126 */
127 var $connection;
128
129 /**
130 * The DSN information for connecting to a database
131 * @var array
132 */
133 var $dsn = array();
134
135
136 /**
137 * Should data manipulation queries be committed automatically?
138 * @var bool
139 * @access private
140 */
141 var $autocommit = true;
142
143 /**
144 * The quantity of transactions begun
145 *
146 * {@internal While this is private, it can't actually be designated
147 * private in PHP 5 because it is directly accessed in the test suite.}}
148 *
149 * @var integer
150 * @access private
151 */
152 var $transaction_opcount = 0;
153
154 /**
155 * The database specified in the DSN
156 *
157 * It's a fix to allow calls to different databases in the same script.
158 *
159 * @var string
160 * @access private
161 */
162 var $_db = '';
163
164 /**
165 * Array for converting MYSQLI_*_FLAG constants to text values
166 * @var array
167 * @access public
168 * @since Property available since Release 1.6.5
169 */
170 var $mysqli_flags = array(
171 MYSQLI_NOT_NULL_FLAG => 'not_null',
172 MYSQLI_PRI_KEY_FLAG => 'primary_key',
173 MYSQLI_UNIQUE_KEY_FLAG => 'unique_key',
174 MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key',
175 MYSQLI_BLOB_FLAG => 'blob',
176 MYSQLI_UNSIGNED_FLAG => 'unsigned',
177 MYSQLI_ZEROFILL_FLAG => 'zerofill',
178 MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
179 MYSQLI_TIMESTAMP_FLAG => 'timestamp',
180 MYSQLI_SET_FLAG => 'set',
181 // MYSQLI_NUM_FLAG => 'numeric', // unnecessary
182 // MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie
183 MYSQLI_GROUP_FLAG => 'group_by'
184 );
185
186 /**
187 * Array for converting MYSQLI_TYPE_* constants to text values
188 * @var array
189 * @access public
190 * @since Property available since Release 1.6.5
191 */
192 var $mysqli_types = array(
193 MYSQLI_TYPE_DECIMAL => 'decimal',
194 MYSQLI_TYPE_TINY => 'tinyint',
195 MYSQLI_TYPE_SHORT => 'int',
196 MYSQLI_TYPE_LONG => 'int',
197 MYSQLI_TYPE_FLOAT => 'float',
198 MYSQLI_TYPE_DOUBLE => 'double',
199 // MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it
200 MYSQLI_TYPE_TIMESTAMP => 'timestamp',
201 MYSQLI_TYPE_LONGLONG => 'bigint',
202 MYSQLI_TYPE_INT24 => 'mediumint',
203 MYSQLI_TYPE_DATE => 'date',
204 MYSQLI_TYPE_TIME => 'time',
205 MYSQLI_TYPE_DATETIME => 'datetime',
206 MYSQLI_TYPE_YEAR => 'year',
207 MYSQLI_TYPE_NEWDATE => 'date',
208 MYSQLI_TYPE_ENUM => 'enum',
209 MYSQLI_TYPE_SET => 'set',
210 MYSQLI_TYPE_TINY_BLOB => 'tinyblob',
211 MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
212 MYSQLI_TYPE_LONG_BLOB => 'longblob',
213 MYSQLI_TYPE_BLOB => 'blob',
214 MYSQLI_TYPE_VAR_STRING => 'varchar',
215 MYSQLI_TYPE_STRING => 'char',
216 MYSQLI_TYPE_GEOMETRY => 'geometry',
217 /* These constants are conditionally compiled in ext/mysqli, so we'll
218 * define them by number rather than constant. */
219 16 => 'bit',
220 246 => 'decimal',
221 );
222
223
224 // }}}
225 // {{{ constructor
226
227 /**
228 * This constructor calls <kbd>$this->DB_common()</kbd>
229 *
230 * @return void
231 */
232 function DB_mysqli()
233 {
234 $this->DB_common();
235 }
236
237 // }}}
238 // {{{ connect()
239
240 /**
241 * Connect to the database server, log in and open the database
242 *
243 * Don't call this method directly. Use DB::connect() instead.
244 *
245 * PEAR DB's mysqli driver supports the following extra DSN options:
246 * + When the 'ssl' $option passed to DB::connect() is true:
247 * + key The path to the key file.
248 * + cert The path to the certificate file.
249 * + ca The path to the certificate authority file.
250 * + capath The path to a directory that contains trusted SSL
251 * CA certificates in pem format.
252 * + cipher The list of allowable ciphers for SSL encryption.
253 *
254 * Example of how to connect using SSL:
255 * <code>
256 * require_once 'DB.php';
257 *
258 * $dsn = array(
259 * 'phptype' => 'mysqli',
260 * 'username' => 'someuser',
261 * 'password' => 'apasswd',
262 * 'hostspec' => 'localhost',
263 * 'database' => 'thedb',
264 * 'key' => 'client-key.pem',
265 * 'cert' => 'client-cert.pem',
266 * 'ca' => 'cacert.pem',
267 * 'capath' => '/path/to/ca/dir',
268 * 'cipher' => 'AES',
269 * );
270 *
271 * $options = array(
272 * 'ssl' => true,
273 * );
274 *
275 * $db = DB::connect($dsn, $options);
276 * if (PEAR::isError($db)) {
277 * die($db->getMessage());
278 * }
279 * </code>
280 *
281 * @param array $dsn the data source name
282 * @param bool $persistent should the connection be persistent?
283 *
284 * @return int DB_OK on success. A DB_Error object on failure.
285 */
286 function connect($dsn, $persistent = false)
287 {
288 if (!PEAR::loadExtension('mysqli')) {
289 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
290 }
291
292 $this->dsn = $dsn;
293 if ($dsn['dbsyntax']) {
294 $this->dbsyntax = $dsn['dbsyntax'];
295 }
296
297 $ini = ini_get('track_errors');
298 @ini_set('track_errors', 1);
299 $php_errormsg = '';
300
301 if (((int) $this->getOption('ssl')) === 1) {
302 $init = mysqli_init();
303 mysqli_ssl_set(
304 $init,
305 empty($dsn['key']) ? null : $dsn['key'],
306 empty($dsn['cert']) ? null : $dsn['cert'],
307 empty($dsn['ca']) ? null : $dsn['ca'],
308 empty($dsn['capath']) ? null : $dsn['capath'],
309 empty($dsn['cipher']) ? null : $dsn['cipher']
310 );
311 if ($this->connection = @mysqli_real_connect(
312 $init,
313 $dsn['hostspec'],
314 $dsn['username'],
315 $dsn['password'],
316 $dsn['database'],
317 $dsn['port'],
318 $dsn['socket']))
319 {
320 $this->connection = $init;
321 }
322 } else {
323 $this->connection = @mysqli_connect(
324 $dsn['hostspec'],
325 $dsn['username'],
326 $dsn['password'],
327 $dsn['database'],
328 $dsn['port'],
329 $dsn['socket']
330 );
331 }
332
333 @ini_set('track_errors', $ini);
334
335 if (!$this->connection) {
336 if (($err = @mysqli_connect_error()) != '') {
337 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
338 null, null, null,
339 $err);
340 } else {
341 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
342 null, null, null,
343 $php_errormsg);
344 }
345 }
346
347 if ($dsn['database']) {
348 $this->_db = $dsn['database'];
349 }
350
351 return DB_OK;
352 }
353
354 // }}}
355 // {{{ disconnect()
356
357 /**
358 * Disconnects from the database server
359 *
360 * @return bool TRUE on success, FALSE on failure
361 */
362 function disconnect()
363 {
364 $ret = @mysqli_close($this->connection);
365 $this->connection = null;
366 return $ret;
367 }
368
369 // }}}
370 // {{{ simpleQuery()
371
372 /**
373 * Sends a query to the database server
374 *
375 * @param string the SQL query string
376 *
377 * @return mixed + a PHP result resrouce for successful SELECT queries
378 * + the DB_OK constant for other successful queries
379 * + a DB_Error object on failure
380 */
381 function simpleQuery($query)
382 {
383 $ismanip = $this->_checkManip($query);
384 $this->last_query = $query;
385 $query = $this->modifyQuery($query);
386 if ($this->_db) {
387 if (!@mysqli_select_db($this->connection, $this->_db)) {
388 return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
389 }
390 }
391 if (!$this->autocommit && $ismanip) {
392 if ($this->transaction_opcount == 0) {
393 $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=0');
394 $result = @mysqli_query($this->connection, 'BEGIN');
395 if (!$result) {
396 return $this->mysqliRaiseError();
397 }
398 }
399 $this->transaction_opcount++;
400 }
401 $result = @mysqli_query($this->connection, $query);
402 if (!$result) {
403 return $this->mysqliRaiseError();
404 }
405 if (is_object($result)) {
406 return $result;
407 }
408 return DB_OK;
409 }
410
411 // }}}
412 // {{{ nextResult()
413
414 /**
415 * Move the internal mysql result pointer to the next available result.
416 *
417 * This method has not been implemented yet.
418 *
419 * @param resource $result a valid sql result resource
420 * @return false
421 * @access public
422 */
423 function nextResult($result)
424 {
425 return false;
426 }
427
428 // }}}
429 // {{{ fetchInto()
430
431 /**
432 * Places a row from the result set into the given array
433 *
434 * Formating of the array and the data therein are configurable.
435 * See DB_result::fetchInto() for more information.
436 *
437 * This method is not meant to be called directly. Use
438 * DB_result::fetchInto() instead. It can't be declared "protected"
439 * because DB_result is a separate object.
440 *
441 * @param resource $result the query result resource
442 * @param array $arr the referenced array to put the data in
443 * @param int $fetchmode how the resulting array should be indexed
444 * @param int $rownum the row number to fetch (0 = first row)
445 *
446 * @return mixed DB_OK on success, NULL when the end of a result set is
447 * reached or on failure
448 *
449 * @see DB_result::fetchInto()
450 */
451 function fetchInto($result, &$arr, $fetchmode, $rownum = null)
452 {
453 if ($rownum !== null) {
454 if (!@mysqli_data_seek($result, $rownum)) {
455 return null;
456 }
457 }
458 if ($fetchmode & DB_FETCHMODE_ASSOC) {
459 $arr = @mysqli_fetch_array($result, MYSQLI_ASSOC);
460 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
461 $arr = array_change_key_case($arr, CASE_LOWER);
462 }
463 } else {
464 $arr = @mysqli_fetch_row($result);
465 }
466 if (!$arr) {
467 return null;
468 }
469 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
470 /*
471 * Even though this DBMS already trims output, we do this because
472 * a field might have intentional whitespace at the end that
473 * gets removed by DB_PORTABILITY_RTRIM under another driver.
474 */
475 $this->_rtrimArrayValues($arr);
476 }
477 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
478 $this->_convertNullArrayValuesToEmpty($arr);
479 }
480 return DB_OK;
481 }
482
483 // }}}
484 // {{{ freeResult()
485
486 /**
487 * Deletes the result set and frees the memory occupied by the result set
488 *
489 * This method is not meant to be called directly. Use
490 * DB_result::free() instead. It can't be declared "protected"
491 * because DB_result is a separate object.
492 *
493 * @param resource $result PHP's query result resource
494 *
495 * @return bool TRUE on success, FALSE if $result is invalid
496 *
497 * @see DB_result::free()
498 */
499 function freeResult($result)
500 {
501 return is_resource($result) ? mysqli_free_result($result) : false;
502 }
503
504 // }}}
505 // {{{ numCols()
506
507 /**
508 * Gets the number of columns in a result set
509 *
510 * This method is not meant to be called directly. Use
511 * DB_result::numCols() instead. It can't be declared "protected"
512 * because DB_result is a separate object.
513 *
514 * @param resource $result PHP's query result resource
515 *
516 * @return int the number of columns. A DB_Error object on failure.
517 *
518 * @see DB_result::numCols()
519 */
520 function numCols($result)
521 {
522 $cols = @mysqli_num_fields($result);
523 if (!$cols) {
524 return $this->mysqliRaiseError();
525 }
526 return $cols;
527 }
528
529 // }}}
530 // {{{ numRows()
531
532 /**
533 * Gets the number of rows in a result set
534 *
535 * This method is not meant to be called directly. Use
536 * DB_result::numRows() instead. It can't be declared "protected"
537 * because DB_result is a separate object.
538 *
539 * @param resource $result PHP's query result resource
540 *
541 * @return int the number of rows. A DB_Error object on failure.
542 *
543 * @see DB_result::numRows()
544 */
545 function numRows($result)
546 {
547 $rows = @mysqli_num_rows($result);
548 if ($rows === null) {
549 return $this->mysqliRaiseError();
550 }
551 return $rows;
552 }
553
554 // }}}
555 // {{{ autoCommit()
556
557 /**
558 * Enables or disables automatic commits
559 *
560 * @param bool $onoff true turns it on, false turns it off
561 *
562 * @return int DB_OK on success. A DB_Error object if the driver
563 * doesn't support auto-committing transactions.
564 */
565 function autoCommit($onoff = false)
566 {
567 // XXX if $this->transaction_opcount > 0, we should probably
568 // issue a warning here.
569 $this->autocommit = $onoff ? true : false;
570 return DB_OK;
571 }
572
573 // }}}
574 // {{{ commit()
575
576 /**
577 * Commits the current transaction
578 *
579 * @return int DB_OK on success. A DB_Error object on failure.
580 */
581 function commit()
582 {
583 if ($this->transaction_opcount > 0) {
584 if ($this->_db) {
585 if (!@mysqli_select_db($this->connection, $this->_db)) {
586 return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
587 }
588 }
589 $result = @mysqli_query($this->connection, 'COMMIT');
590 $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
591 $this->transaction_opcount = 0;
592 if (!$result) {
593 return $this->mysqliRaiseError();
594 }
595 }
596 return DB_OK;
597 }
598
599 // }}}
600 // {{{ rollback()
601
602 /**
603 * Reverts the current transaction
604 *
605 * @return int DB_OK on success. A DB_Error object on failure.
606 */
607 function rollback()
608 {
609 if ($this->transaction_opcount > 0) {
610 if ($this->_db) {
611 if (!@mysqli_select_db($this->connection, $this->_db)) {
612 return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
613 }
614 }
615 $result = @mysqli_query($this->connection, 'ROLLBACK');
616 $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
617 $this->transaction_opcount = 0;
618 if (!$result) {
619 return $this->mysqliRaiseError();
620 }
621 }
622 return DB_OK;
623 }
624
625 // }}}
626 // {{{ affectedRows()
627
628 /**
629 * Determines the number of rows affected by a data maniuplation query
630 *
631 * 0 is returned for queries that don't manipulate data.
632 *
633 * @return int the number of rows. A DB_Error object on failure.
634 */
635 function affectedRows()
636 {
637 if ($this->_last_query_manip) {
638 return @mysqli_affected_rows($this->connection);
639 } else {
640 return 0;
641 }
642 }
643
644 // }}}
645 // {{{ nextId()
646
647 /**
648 * Returns the next free id in a sequence
649 *
650 * @param string $seq_name name of the sequence
651 * @param boolean $ondemand when true, the seqence is automatically
652 * created if it does not exist
653 *
654 * @return int the next id number in the sequence.
655 * A DB_Error object on failure.
656 *
657 * @see DB_common::nextID(), DB_common::getSequenceName(),
658 * DB_mysqli::createSequence(), DB_mysqli::dropSequence()
659 */
660 function nextId($seq_name, $ondemand = true)
661 {
662 $seqname = $this->getSequenceName($seq_name);
663 do {
664 $repeat = 0;
665 $this->pushErrorHandling(PEAR_ERROR_RETURN);
666 $result = $this->query('UPDATE ' . $seqname
667 . ' SET id = LAST_INSERT_ID(id + 1)');
668 $this->popErrorHandling();
669 if ($result === DB_OK) {
670 // COMMON CASE
671 $id = @mysqli_insert_id($this->connection);
672 if ($id != 0) {
673 return $id;
674 }
675
676 // EMPTY SEQ TABLE
677 // Sequence table must be empty for some reason,
678 // so fill it and return 1
679 // Obtain a user-level lock
680 $result = $this->getOne('SELECT GET_LOCK('
681 . "'${seqname}_lock', 10)");
682 if (DB::isError($result)) {
683 return $this->raiseError($result);
684 }
685 if ($result == 0) {
686 return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED);
687 }
688
689 // add the default value
690 $result = $this->query('REPLACE INTO ' . $seqname
691 . ' (id) VALUES (0)');
692 if (DB::isError($result)) {
693 return $this->raiseError($result);
694 }
695
696 // Release the lock
697 $result = $this->getOne('SELECT RELEASE_LOCK('
698 . "'${seqname}_lock')");
699 if (DB::isError($result)) {
700 return $this->raiseError($result);
701 }
702 // We know what the result will be, so no need to try again
703 return 1;
704
705 } elseif ($ondemand && DB::isError($result) &&
706 $result->getCode() == DB_ERROR_NOSUCHTABLE)
707 {
708 // ONDEMAND TABLE CREATION
709 $result = $this->createSequence($seq_name);
710
711 // Since createSequence initializes the ID to be 1,
712 // we do not need to retrieve the ID again (or we will get 2)
713 if (DB::isError($result)) {
714 return $this->raiseError($result);
715 } else {
716 // First ID of a newly created sequence is 1
717 return 1;
718 }
719
720 } elseif (DB::isError($result) &&
721 $result->getCode() == DB_ERROR_ALREADY_EXISTS)
722 {
723 // BACKWARDS COMPAT
724 // see _BCsequence() comment
725 $result = $this->_BCsequence($seqname);
726 if (DB::isError($result)) {
727 return $this->raiseError($result);
728 }
729 $repeat = 1;
730 }
731 } while ($repeat);
732
733 return $this->raiseError($result);
734 }
735
736 /**
737 * Creates a new sequence
738 *
739 * @param string $seq_name name of the new sequence
740 *
741 * @return int DB_OK on success. A DB_Error object on failure.
742 *
743 * @see DB_common::createSequence(), DB_common::getSequenceName(),
744 * DB_mysqli::nextID(), DB_mysqli::dropSequence()
745 */
746 function createSequence($seq_name)
747 {
748 $seqname = $this->getSequenceName($seq_name);
749 $res = $this->query('CREATE TABLE ' . $seqname
750 . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
751 . ' PRIMARY KEY(id))');
752 if (DB::isError($res)) {
753 return $res;
754 }
755 // insert yields value 1, nextId call will generate ID 2
756 return $this->query("INSERT INTO ${seqname} (id) VALUES (0)");
757 }
758
759 // }}}
760 // {{{ dropSequence()
761
762 /**
763 * Deletes a sequence
764 *
765 * @param string $seq_name name of the sequence to be deleted
766 *
767 * @return int DB_OK on success. A DB_Error object on failure.
768 *
769 * @see DB_common::dropSequence(), DB_common::getSequenceName(),
770 * DB_mysql::nextID(), DB_mysql::createSequence()
771 */
772 function dropSequence($seq_name)
773 {
774 return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
775 }
776
777 // }}}
778 // {{{ _BCsequence()
779
780 /**
781 * Backwards compatibility with old sequence emulation implementation
782 * (clean up the dupes)
783 *
784 * @param string $seqname the sequence name to clean up
785 *
786 * @return bool true on success. A DB_Error object on failure.
787 *
788 * @access private
789 */
790 function _BCsequence($seqname)
791 {
792 // Obtain a user-level lock... this will release any previous
793 // application locks, but unlike LOCK TABLES, it does not abort
794 // the current transaction and is much less frequently used.
795 $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
796 if (DB::isError($result)) {
797 return $result;
798 }
799 if ($result == 0) {
800 // Failed to get the lock, can't do the conversion, bail
801 // with a DB_ERROR_NOT_LOCKED error
802 return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED);
803 }
804
805 $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}");
806 if (DB::isError($highest_id)) {
807 return $highest_id;
808 }
809
810 // This should kill all rows except the highest
811 // We should probably do something if $highest_id isn't
812 // numeric, but I'm at a loss as how to handle that...
813 $result = $this->query('DELETE FROM ' . $seqname
814 . " WHERE id <> $highest_id");
815 if (DB::isError($result)) {
816 return $result;
817 }
818
819 // If another thread has been waiting for this lock,
820 // it will go thru the above procedure, but will have no
821 // real effect
822 $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
823 if (DB::isError($result)) {
824 return $result;
825 }
826 return true;
827 }
828
829 // }}}
830 // {{{ quoteIdentifier()
831
832 /**
833 * Quotes a string so it can be safely used as a table or column name
834 * (WARNING: using names that require this is a REALLY BAD IDEA)
835 *
836 * WARNING: Older versions of MySQL can't handle the backtick
837 * character (<kbd>`</kbd>) in table or column names.
838 *
839 * @param string $str identifier name to be quoted
840 *
841 * @return string quoted identifier string
842 *
843 * @see DB_common::quoteIdentifier()
844 * @since Method available since Release 1.6.0
845 */
846 function quoteIdentifier($str)
847 {
848 return '`' . str_replace('`', '``', $str) . '`';
849 }
850
851 // }}}
852 // {{{ escapeSimple()
853
854 /**
855 * Escapes a string according to the current DBMS's standards
856 *
857 * @param string $str the string to be escaped
858 *
859 * @return string the escaped string
860 *
861 * @see DB_common::quoteSmart()
862 * @since Method available since Release 1.6.0
863 */
864 function escapeSimple($str)
865 {
866 return @mysqli_real_escape_string($this->connection, $str);
867 }
868
869 // }}}
870 // {{{ modifyLimitQuery()
871
872 /**
873 * Adds LIMIT clauses to a query string according to current DBMS standards
874 *
875 * @param string $query the query to modify
876 * @param int $from the row to start to fetching (0 = the first row)
877 * @param int $count the numbers of rows to fetch
878 * @param mixed $params array, string or numeric data to be used in
879 * execution of the statement. Quantity of items
880 * passed must match quantity of placeholders in
881 * query: meaning 1 placeholder for non-array
882 * parameters or 1 placeholder per array element.
883 *
884 * @return string the query string with LIMIT clauses added
885 *
886 * @access protected
887 */
888 function modifyLimitQuery($query, $from, $count, $params = array())
889 {
890 if (DB::isManip($query) || $this->_next_query_manip) {
891 return $query . " LIMIT $count";
892 } else {
893 return $query . " LIMIT $from, $count";
894 }
895 }
896
897 // }}}
898 // {{{ mysqliRaiseError()
899
900 /**
901 * Produces a DB_Error object regarding the current problem
902 *
903 * @param int $errno if the error is being manually raised pass a
904 * DB_ERROR* constant here. If this isn't passed
905 * the error information gathered from the DBMS.
906 *
907 * @return object the DB_Error object
908 *
909 * @see DB_common::raiseError(),
910 * DB_mysqli::errorNative(), DB_common::errorCode()
911 */
912 function mysqliRaiseError($errno = null)
913 {
914 if ($errno === null) {
915 if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
916 $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
917 $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
918 $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
919 } else {
920 // Doing this in case mode changes during runtime.
921 $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
922 $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
923 $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
924 }
925 $errno = $this->errorCode(mysqli_errno($this->connection));
926 }
927 return $this->raiseError($errno, null, null, null,
928 @mysqli_errno($this->connection) . ' ** ' .
929 @mysqli_error($this->connection));
930 }
931
932 // }}}
933 // {{{ errorNative()
934
935 /**
936 * Gets the DBMS' native error code produced by the last query
937 *
938 * @return int the DBMS' error code
939 */
940 function errorNative()
941 {
942 return @mysqli_errno($this->connection);
943 }
944
945 // }}}
946 // {{{ tableInfo()
947
948 /**
949 * Returns information about a table or a result set
950 *
951 * @param object|string $result DB_result object from a query or a
952 * string containing the name of a table.
953 * While this also accepts a query result
954 * resource identifier, this behavior is
955 * deprecated.
956 * @param int $mode a valid tableInfo mode
957 *
958 * @return array an associative array with the information requested.
959 * A DB_Error object on failure.
960 *
961 * @see DB_common::setOption()
962 */
963 function tableInfo($result, $mode = null)
964 {
965 if (is_string($result)) {
966 // Fix for bug #11580.
967 if ($this->_db) {
968 if (!@mysqli_select_db($this->connection, $this->_db)) {
969 return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
970 }
971 }
972
973 /*
974 * Probably received a table name.
975 * Create a result resource identifier.
976 */
977 $id = @mysqli_query($this->connection,
978 "SELECT * FROM $result LIMIT 0");
979 $got_string = true;
980 } elseif (isset($result->result)) {
981 /*
982 * Probably received a result object.
983 * Extract the result resource identifier.
984 */
985 $id = $result->result;
986 $got_string = false;
987 } else {
988 /*
989 * Probably received a result resource identifier.
990 * Copy it.
991 * Deprecated. Here for compatibility only.
992 */
993 $id = $result;
994 $got_string = false;
995 }
996
997 if (!is_a($id, 'mysqli_result')) {
998 return $this->mysqliRaiseError(DB_ERROR_NEED_MORE_DATA);
999 }
1000
1001 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
1002 $case_func = 'strtolower';
1003 } else {
1004 $case_func = 'strval';
1005 }
1006
1007 $count = @mysqli_num_fields($id);
1008 $res = array();
1009
1010 if ($mode) {
1011 $res['num_fields'] = $count;
1012 }
1013
1014 for ($i = 0; $i < $count; $i++) {
1015 $tmp = @mysqli_fetch_field($id);
1016
1017 $flags = '';
1018 foreach ($this->mysqli_flags as $const => $means) {
1019 if ($tmp->flags & $const) {
1020 $flags .= $means . ' ';
1021 }
1022 }
1023 if ($tmp->def) {
1024 $flags .= 'default_' . rawurlencode($tmp->def);
1025 }
1026 $flags = trim($flags);
1027
1028 $res[$i] = array(
1029 'table' => $case_func($tmp->table),
1030 'name' => $case_func($tmp->name),
1031 'type' => isset($this->mysqli_types[$tmp->type])
1032 ? $this->mysqli_types[$tmp->type]
1033 : 'unknown',
1034 // http://bugs.php.net/?id=36579
1035 'len' => $tmp->length,
1036 'flags' => $flags,
1037 );
1038
1039 if ($mode & DB_TABLEINFO_ORDER) {
1040 $res['order'][$res[$i]['name']] = $i;
1041 }
1042 if ($mode & DB_TABLEINFO_ORDERTABLE) {
1043 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
1044 }
1045 }
1046
1047 // free the result only if we were called on a table
1048 if ($got_string) {
1049 @mysqli_free_result($id);
1050 }
1051 return $res;
1052 }
1053
1054 // }}}
1055 // {{{ getSpecialQuery()
1056
1057 /**
1058 * Obtains the query string needed for listing a given type of objects
1059 *
1060 * @param string $type the kind of objects you want to retrieve
1061 *
1062 * @return string the SQL query string or null if the driver doesn't
1063 * support the object type requested
1064 *
1065 * @access protected
1066 * @see DB_common::getListOf()
1067 */
1068 function getSpecialQuery($type)
1069 {
1070 switch ($type) {
1071 case 'tables':
1072 return 'SHOW TABLES';
1073 case 'users':
1074 return 'SELECT DISTINCT User FROM mysql.user';
1075 case 'databases':
1076 return 'SHOW DATABASES';
1077 default:
1078 return null;
1079 }
1080 }
1081
1082 // }}}
1083
1084 }
1085
1086 /*
1087 * Local variables:
1088 * tab-width: 4
1089 * c-basic-offset: 4
1090 * End:
1091 */
1092
1093 ?>