PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/php/DB/mysqli.php

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