PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/external_lib/DB/mysql.php

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