mysql.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Bakken <ssb@php.net> |
  17. // | Maintainer: Daniel Convissor <danielc@php.net> |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: mysql.php,v 1.64 2004/02/19 15:49:34 danielc Exp $
  21. // XXX legend:
  22. //
  23. // XXX ERRORMSG: The error message from the mysql function should
  24. // be registered here.
  25. //
  26. // TODO/wishlist:
  27. // longReadlen
  28. // binmode
  29. require_once 'DB/common.php';
  30. /**
  31. * Database independent query interface definition for PHP's MySQL
  32. * extension.
  33. *
  34. * This is for MySQL versions 4.0 and below.
  35. *
  36. * @package DB
  37. * @version $Id: mysql.php,v 1.64 2004/02/19 15:49:34 danielc Exp $
  38. * @category Database
  39. * @author Stig Bakken <ssb@php.net>
  40. */
  41. class DB_mysql extends DB_common
  42. {
  43. // {{{ properties
  44. var $connection;
  45. var $phptype, $dbsyntax;
  46. var $prepare_tokens = array();
  47. var $prepare_types = array();
  48. var $num_rows = array();
  49. var $transaction_opcount = 0;
  50. var $autocommit = true;
  51. var $fetchmode = DB_FETCHMODE_ORDERED; /* Default fetch mode */
  52. var $_db = false;
  53. // }}}
  54. // {{{ constructor
  55. /**
  56. * DB_mysql constructor.
  57. *
  58. * @access public
  59. */
  60. function DB_mysql()
  61. {
  62. $this->DB_common();
  63. $this->phptype = 'mysql';
  64. $this->dbsyntax = 'mysql';
  65. $this->features = array(
  66. 'prepare' => false,
  67. 'pconnect' => true,
  68. 'transactions' => true,
  69. 'limit' => 'alter'
  70. );
  71. $this->errorcode_map = array(
  72. 1004 => DB_ERROR_CANNOT_CREATE,
  73. 1005 => DB_ERROR_CANNOT_CREATE,
  74. 1006 => DB_ERROR_CANNOT_CREATE,
  75. 1007 => DB_ERROR_ALREADY_EXISTS,
  76. 1008 => DB_ERROR_CANNOT_DROP,
  77. 1022 => DB_ERROR_ALREADY_EXISTS,
  78. 1046 => DB_ERROR_NODBSELECTED,
  79. 1050 => DB_ERROR_ALREADY_EXISTS,
  80. 1051 => DB_ERROR_NOSUCHTABLE,
  81. 1054 => DB_ERROR_NOSUCHFIELD,
  82. 1062 => DB_ERROR_ALREADY_EXISTS,
  83. 1064 => DB_ERROR_SYNTAX,
  84. 1100 => DB_ERROR_NOT_LOCKED,
  85. 1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
  86. 1146 => DB_ERROR_NOSUCHTABLE,
  87. 1048 => DB_ERROR_CONSTRAINT,
  88. 1216 => DB_ERROR_CONSTRAINT
  89. );
  90. }
  91. // }}}
  92. // {{{ connect()
  93. /**
  94. * Connect to a database and log in as the specified user.
  95. *
  96. * @param $dsn the data source name (see DB::parseDSN for syntax)
  97. * @param $persistent (optional) whether the connection should
  98. * be persistent
  99. * @access public
  100. * @return int DB_OK on success, a DB error on failure
  101. */
  102. function connect($dsninfo, $persistent = false)
  103. {
  104. if (!DB::assertExtension('mysql')) {
  105. return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  106. }
  107. $this->dsn = $dsninfo;
  108. if ($dsninfo['protocol'] && $dsninfo['protocol'] == 'unix') {
  109. $dbhost = ':' . $dsninfo['socket'];
  110. } else {
  111. $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  112. if ($dsninfo['port']) {
  113. $dbhost .= ':' . $dsninfo['port'];
  114. }
  115. }
  116. $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';
  117. if ($dbhost && $dsninfo['username'] && isset($dsninfo['password'])) {
  118. $conn = @$connect_function($dbhost, $dsninfo['username'],
  119. $dsninfo['password']);
  120. } elseif ($dbhost && $dsninfo['username']) {
  121. $conn = @$connect_function($dbhost, $dsninfo['username']);
  122. } elseif ($dbhost) {
  123. $conn = @$connect_function($dbhost);
  124. } else {
  125. $conn = false;
  126. }
  127. if (!$conn) {
  128. if (($err = @mysql_error()) != '') {
  129. return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  130. null, $err);
  131. } elseif (empty($php_errormsg)) {
  132. return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  133. } else {
  134. return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  135. null, $php_errormsg);
  136. }
  137. }
  138. if ($dsninfo['database']) {
  139. if (!@mysql_select_db($dsninfo['database'], $conn)) {
  140. switch(mysql_errno($conn)) {
  141. case 1049:
  142. return $this->raiseError(DB_ERROR_NOSUCHDB, null, null,
  143. null, mysql_error($conn));
  144. case 1044:
  145. return $this->raiseError(DB_ERROR_ACCESS_VIOLATION, null, null,
  146. null, mysql_error($conn));
  147. default:
  148. return $this->raiseError(DB_ERROR, null, null,
  149. null, mysql_error($conn));
  150. }
  151. }
  152. // fix to allow calls to different databases in the same script
  153. $this->_db = $dsninfo['database'];
  154. }
  155. if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
  156. $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
  157. $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
  158. $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
  159. }
  160. $this->connection = $conn;
  161. return DB_OK;
  162. }
  163. // }}}
  164. // {{{ disconnect()
  165. /**
  166. * Log out and disconnect from the database.
  167. *
  168. * @access public
  169. *
  170. * @return bool TRUE on success, FALSE if not connected.
  171. */
  172. function disconnect()
  173. {
  174. $ret = mysql_close($this->connection);
  175. $this->connection = null;
  176. return $ret;
  177. }
  178. // }}}
  179. // {{{ simpleQuery()
  180. /**
  181. * Send a query to MySQL and return the results as a MySQL resource
  182. * identifier.
  183. *
  184. * @param the SQL query
  185. *
  186. * @access public
  187. *
  188. * @return mixed returns a valid MySQL result for successful SELECT
  189. * queries, DB_OK for other successful queries. A DB error is
  190. * returned on failure.
  191. */
  192. function simpleQuery($query)
  193. {
  194. $ismanip = DB::isManip($query);
  195. $this->last_query = $query;
  196. $query = $this->modifyQuery($query);
  197. if ($this->_db) {
  198. if (!@mysql_select_db($this->_db, $this->connection)) {
  199. return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  200. }
  201. }
  202. if (!$this->autocommit && $ismanip) {
  203. if ($this->transaction_opcount == 0) {
  204. $result = @mysql_query('SET AUTOCOMMIT=0', $this->connection);
  205. $result = @mysql_query('BEGIN', $this->connection);
  206. if (!$result) {
  207. return $this->mysqlRaiseError();
  208. }
  209. }
  210. $this->transaction_opcount++;
  211. }
  212. $result = @mysql_query($query, $this->connection);
  213. if (!$result) {
  214. return $this->mysqlRaiseError();
  215. }
  216. if (is_resource($result)) {
  217. $numrows = $this->numrows($result);
  218. if (is_object($numrows)) {
  219. return $numrows;
  220. }
  221. $this->num_rows[(int)$result] = $numrows;
  222. return $result;
  223. }
  224. return DB_OK;
  225. }
  226. // }}}
  227. // {{{ nextResult()
  228. /**
  229. * Move the internal mysql result pointer to the next available result
  230. *
  231. * This method has not been implemented yet.
  232. *
  233. * @param a valid sql result resource
  234. *
  235. * @access public
  236. *
  237. * @return false
  238. */
  239. function nextResult($result)
  240. {
  241. return false;
  242. }
  243. // }}}
  244. // {{{ fetchInto()
  245. /**
  246. * Fetch a row and insert the data into an existing array.
  247. *
  248. * Formating of the array and the data therein are configurable.
  249. * See DB_result::fetchInto() for more information.
  250. *
  251. * @param resource $result query result identifier
  252. * @param array $arr (reference) array where data from the row
  253. * should be placed
  254. * @param int $fetchmode how the resulting array should be indexed
  255. * @param int $rownum the row number to fetch
  256. *
  257. * @return mixed DB_OK on success, NULL when end of result set is
  258. * reached or on failure
  259. *
  260. * @see DB_result::fetchInto()
  261. * @access private
  262. */
  263. function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  264. {
  265. if ($rownum !== null) {
  266. if (!@mysql_data_seek($result, $rownum)) {
  267. return null;
  268. }
  269. }
  270. if ($fetchmode & DB_FETCHMODE_ASSOC) {
  271. $arr = @mysql_fetch_array($result, MYSQL_ASSOC);
  272. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  273. $arr = array_change_key_case($arr, CASE_LOWER);
  274. }
  275. } else {
  276. $arr = @mysql_fetch_row($result);
  277. }
  278. if (!$arr) {
  279. // See: http://bugs.php.net/bug.php?id=22328
  280. // for why we can't check errors on fetching
  281. return null;
  282. /*
  283. $errno = @mysql_errno($this->connection);
  284. if (!$errno) {
  285. return NULL;
  286. }
  287. return $this->mysqlRaiseError($errno);
  288. */
  289. }
  290. if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  291. /*
  292. * Even though this DBMS already trims output, we do this because
  293. * a field might have intentional whitespace at the end that
  294. * gets removed by DB_PORTABILITY_RTRIM under another driver.
  295. */
  296. $this->_rtrimArrayValues($arr);
  297. }
  298. if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  299. $this->_convertNullArrayValuesToEmpty($arr);
  300. }
  301. return DB_OK;
  302. }
  303. // }}}
  304. // {{{ freeResult()
  305. /**
  306. * Free the internal resources associated with $result.
  307. *
  308. * @param $result MySQL result identifier
  309. *
  310. * @access public
  311. *
  312. * @return bool TRUE on success, FALSE if $result is invalid
  313. */
  314. function freeResult($result)
  315. {
  316. unset($this->num_rows[(int)$result]);
  317. return @mysql_free_result($result);
  318. }
  319. // }}}
  320. // {{{ numCols()
  321. /**
  322. * Get the number of columns in a result set.
  323. *
  324. * @param $result MySQL result identifier
  325. *
  326. * @access public
  327. *
  328. * @return int the number of columns per row in $result
  329. */
  330. function numCols($result)
  331. {
  332. $cols = @mysql_num_fields($result);
  333. if (!$cols) {
  334. return $this->mysqlRaiseError();
  335. }
  336. return $cols;
  337. }
  338. // }}}
  339. // {{{ numRows()
  340. /**
  341. * Get the number of rows in a result set.
  342. *
  343. * @param $result MySQL result identifier
  344. *
  345. * @access public
  346. *
  347. * @return int the number of rows in $result
  348. */
  349. function numRows($result)
  350. {
  351. $rows = @mysql_num_rows($result);
  352. if ($rows === null) {
  353. return $this->mysqlRaiseError();
  354. }
  355. return $rows;
  356. }
  357. // }}}
  358. // {{{ autoCommit()
  359. /**
  360. * Enable/disable automatic commits
  361. */
  362. function autoCommit($onoff = false)
  363. {
  364. // XXX if $this->transaction_opcount > 0, we should probably
  365. // issue a warning here.
  366. $this->autocommit = $onoff ? true : false;
  367. return DB_OK;
  368. }
  369. // }}}
  370. // {{{ commit()
  371. /**
  372. * Commit the current transaction.
  373. */
  374. function commit()
  375. {
  376. if ($this->transaction_opcount > 0) {
  377. if ($this->_db) {
  378. if (!@mysql_select_db($this->_db, $this->connection)) {
  379. return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  380. }
  381. }
  382. $result = @mysql_query('COMMIT', $this->connection);
  383. $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection);
  384. $this->transaction_opcount = 0;
  385. if (!$result) {
  386. return $this->mysqlRaiseError();
  387. }
  388. }
  389. return DB_OK;
  390. }
  391. // }}}
  392. // {{{ rollback()
  393. /**
  394. * Roll back (undo) the current transaction.
  395. */
  396. function rollback()
  397. {
  398. if ($this->transaction_opcount > 0) {
  399. if ($this->_db) {
  400. if (!@mysql_select_db($this->_db, $this->connection)) {
  401. return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  402. }
  403. }
  404. $result = @mysql_query('ROLLBACK', $this->connection);
  405. $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection);
  406. $this->transaction_opcount = 0;
  407. if (!$result) {
  408. return $this->mysqlRaiseError();
  409. }
  410. }
  411. return DB_OK;
  412. }
  413. // }}}
  414. // {{{ affectedRows()
  415. /**
  416. * Gets the number of rows affected by the data manipulation
  417. * query. For other queries, this function returns 0.
  418. *
  419. * @return number of rows affected by the last query
  420. */
  421. function affectedRows()
  422. {
  423. if (DB::isManip($this->last_query)) {
  424. return @mysql_affected_rows($this->connection);
  425. } else {
  426. return 0;
  427. }
  428. }
  429. // }}}
  430. // {{{ errorNative()
  431. /**
  432. * Get the native error code of the last error (if any) that
  433. * occured on the current connection.
  434. *
  435. * @access public
  436. *
  437. * @return int native MySQL error code
  438. */
  439. function errorNative()
  440. {
  441. return mysql_errno($this->connection);
  442. }
  443. // }}}
  444. // {{{ nextId()
  445. /**
  446. * Returns the next free id in a sequence
  447. *
  448. * @param string $seq_name name of the sequence
  449. * @param boolean $ondemand when true, the seqence is automatically
  450. * created if it does not exist
  451. *
  452. * @return int the next id number in the sequence. DB_Error if problem.
  453. *
  454. * @internal
  455. * @see DB_common::nextID()
  456. * @access public
  457. */
  458. function nextId($seq_name, $ondemand = true)
  459. {
  460. $seqname = $this->getSequenceName($seq_name);
  461. do {
  462. $repeat = 0;
  463. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  464. $result = $this->query("UPDATE ${seqname} ".
  465. 'SET id=LAST_INSERT_ID(id+1)');
  466. $this->popErrorHandling();
  467. if ($result == DB_OK) {
  468. /** COMMON CASE **/
  469. $id = mysql_insert_id($this->connection);
  470. if ($id != 0) {
  471. return $id;
  472. }
  473. /** EMPTY SEQ TABLE **/
  474. // Sequence table must be empty for some reason, so fill it and return 1
  475. // Obtain a user-level lock
  476. $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
  477. if (DB::isError($result)) {
  478. return $this->raiseError($result);
  479. }
  480. if ($result == 0) {
  481. // Failed to get the lock, bail with a DB_ERROR_NOT_LOCKED error
  482. return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED);
  483. }
  484. // add the default value
  485. $result = $this->query("REPLACE INTO ${seqname} VALUES (0)");
  486. if (DB::isError($result)) {
  487. return $this->raiseError($result);
  488. }
  489. // Release the lock
  490. $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
  491. if (DB::isError($result)) {
  492. return $this->raiseError($result);
  493. }
  494. // We know what the result will be, so no need to try again
  495. return 1;
  496. /** ONDEMAND TABLE CREATION **/
  497. } elseif ($ondemand && DB::isError($result) &&
  498. $result->getCode() == DB_ERROR_NOSUCHTABLE)
  499. {
  500. $result = $this->createSequence($seq_name);
  501. if (DB::isError($result)) {
  502. return $this->raiseError($result);
  503. } else {
  504. $repeat = 1;
  505. }
  506. /** BACKWARDS COMPAT **/
  507. } elseif (DB::isError($result) &&
  508. $result->getCode() == DB_ERROR_ALREADY_EXISTS)
  509. {
  510. // see _BCsequence() comment
  511. $result = $this->_BCsequence($seqname);
  512. if (DB::isError($result)) {
  513. return $this->raiseError($result);
  514. }
  515. $repeat = 1;
  516. }
  517. } while ($repeat);
  518. return $this->raiseError($result);
  519. }
  520. // }}}
  521. // {{{ createSequence()
  522. /**
  523. * Creates a new sequence
  524. *
  525. * @param string $seq_name name of the new sequence
  526. *
  527. * @return int DB_OK on success. A DB_Error object is returned if
  528. * problems arise.
  529. *
  530. * @internal
  531. * @see DB_common::createSequence()
  532. * @access public
  533. */
  534. function createSequence($seq_name)
  535. {
  536. $seqname = $this->getSequenceName($seq_name);
  537. $res = $this->query("CREATE TABLE ${seqname} ".
  538. '(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'.
  539. ' PRIMARY KEY(id))');
  540. if (DB::isError($res)) {
  541. return $res;
  542. }
  543. // insert yields value 1, nextId call will generate ID 2
  544. $res = $this->query("INSERT INTO ${seqname} VALUES(0)");
  545. if (DB::isError($res)) {
  546. return $res;
  547. }
  548. // so reset to zero
  549. return $this->query("UPDATE ${seqname} SET id = 0;");
  550. }
  551. // }}}
  552. // {{{ dropSequence()
  553. /**
  554. * Deletes a sequence
  555. *
  556. * @param string $seq_name name of the sequence to be deleted
  557. *
  558. * @return int DB_OK on success. DB_Error if problems.
  559. *
  560. * @internal
  561. * @see DB_common::dropSequence()
  562. * @access public
  563. */
  564. function dropSequence($seq_name)
  565. {
  566. return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
  567. }
  568. // }}}
  569. // {{{ _BCsequence()
  570. /**
  571. * Backwards compatibility with old sequence emulation implementation
  572. * (clean up the dupes)
  573. *
  574. * @param string $seqname The sequence name to clean up
  575. * @return mixed DB_Error or true
  576. */
  577. function _BCsequence($seqname)
  578. {
  579. // Obtain a user-level lock... this will release any previous
  580. // application locks, but unlike LOCK TABLES, it does not abort
  581. // the current transaction and is much less frequently used.
  582. $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
  583. if (DB::isError($result)) {
  584. return $result;
  585. }
  586. if ($result == 0) {
  587. // Failed to get the lock, can't do the conversion, bail
  588. // with a DB_ERROR_NOT_LOCKED error
  589. return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED);
  590. }
  591. $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}");
  592. if (DB::isError($highest_id)) {
  593. return $highest_id;
  594. }
  595. // This should kill all rows except the highest
  596. // We should probably do something if $highest_id isn't
  597. // numeric, but I'm at a loss as how to handle that...
  598. $result = $this->query("DELETE FROM ${seqname} WHERE id <> $highest_id");
  599. if (DB::isError($result)) {
  600. return $result;
  601. }
  602. // If another thread has been waiting for this lock,
  603. // it will go thru the above procedure, but will have no
  604. // real effect
  605. $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
  606. if (DB::isError($result)) {
  607. return $result;
  608. }
  609. return true;
  610. }
  611. // }}}
  612. // {{{ quoteIdentifier()
  613. /**
  614. * Quote a string so it can be safely used as a table or column name
  615. *
  616. * Quoting style depends on which database driver is being used.
  617. *
  618. * MySQL can't handle the backtick character (<kbd>`</kbd>) in
  619. * table or column names.
  620. *
  621. * @param string $str identifier name to be quoted
  622. *
  623. * @return string quoted identifier string
  624. *
  625. * @since 1.6.0
  626. * @access public
  627. * @internal
  628. */
  629. function quoteIdentifier($str)
  630. {
  631. return '`' . $str . '`';
  632. }
  633. // }}}
  634. // {{{ quote()
  635. /**
  636. * @deprecated Deprecated in release 1.6.0
  637. * @internal
  638. */
  639. function quote($str) {
  640. return $this->quoteSmart($str);
  641. }
  642. // }}}
  643. // {{{ escapeSimple()
  644. /**
  645. * Escape a string according to the current DBMS's standards
  646. *
  647. * @param string $str the string to be escaped
  648. *
  649. * @return string the escaped string
  650. *
  651. * @internal
  652. */
  653. function escapeSimple($str) {
  654. if(function_exists('mysql_real_escape_string')) {
  655. return mysql_real_escape_string($str, $this->connection);
  656. } else {
  657. return mysql_escape_string($str);
  658. }
  659. }
  660. // }}}
  661. // {{{ modifyQuery()
  662. function modifyQuery($query)
  663. {
  664. if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
  665. // "DELETE FROM table" gives 0 affected rows in MySQL.
  666. // This little hack lets you know how many rows were deleted.
  667. if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
  668. $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  669. 'DELETE FROM \1 WHERE 1=1', $query);
  670. }
  671. }
  672. return $query;
  673. }
  674. // }}}
  675. // {{{ modifyLimitQuery()
  676. function modifyLimitQuery($query, $from, $count)
  677. {
  678. if (DB::isManip($query)) {
  679. return $query . " LIMIT $count";
  680. } else {
  681. return $query . " LIMIT $from, $count";
  682. }
  683. }
  684. // }}}
  685. // {{{ mysqlRaiseError()
  686. /**
  687. * Gather information about an error, then use that info to create a
  688. * DB error object and finally return that object.
  689. *
  690. * @param integer $errno PEAR error number (usually a DB constant) if
  691. * manually raising an error
  692. * @return object DB error object
  693. * @see DB_common::errorCode()
  694. * @see DB_common::raiseError()
  695. */
  696. function mysqlRaiseError($errno = null)
  697. {
  698. if ($errno === null) {
  699. $errno = $this->errorCode(mysql_errno($this->connection));
  700. }
  701. return $this->raiseError($errno, null, null, null,
  702. @mysql_errno($this->connection) . ' ** ' .
  703. @mysql_error($this->connection));
  704. }
  705. // }}}
  706. // {{{ tableInfo()
  707. /**
  708. * Returns information about a table or a result set.
  709. *
  710. * @param object|string $result DB_result object from a query or a
  711. * string containing the name of a table
  712. * @param int $mode a valid tableInfo mode
  713. * @return array an associative array with the information requested
  714. * or an error object if something is wrong
  715. * @access public
  716. * @internal
  717. * @see DB_common::tableInfo()
  718. */
  719. function tableInfo($result, $mode = null) {
  720. if (isset($result->result)) {
  721. /*
  722. * Probably received a result object.
  723. * Extract the result resource identifier.
  724. */
  725. $id = $result->result;
  726. $got_string = false;
  727. } elseif (is_string($result)) {
  728. /*
  729. * Probably received a table name.
  730. * Create a result resource identifier.
  731. */
  732. $id = @mysql_list_fields($this->dsn['database'],
  733. $result, $this->connection);
  734. $got_string = true;
  735. } else {
  736. /*
  737. * Probably received a result resource identifier.
  738. * Copy it.
  739. * Deprecated. Here for compatibility only.
  740. */
  741. $id = $result;
  742. $got_string = false;
  743. }
  744. if (!is_resource($id)) {
  745. return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA);
  746. }
  747. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  748. $case_func = 'strtolower';
  749. } else {
  750. $case_func = 'strval';
  751. }
  752. $count = @mysql_num_fields($id);
  753. // made this IF due to performance (one if is faster than $count if's)
  754. if (!$mode) {
  755. for ($i=0; $i<$count; $i++) {
  756. $res[$i]['table'] = $case_func(@mysql_field_table($id, $i));
  757. $res[$i]['name'] = $case_func(@mysql_field_name($id, $i));
  758. $res[$i]['type'] = @mysql_field_type($id, $i);
  759. $res[$i]['len'] = @mysql_field_len($id, $i);
  760. $res[$i]['flags'] = @mysql_field_flags($id, $i);
  761. }
  762. } else { // full
  763. $res['num_fields']= $count;
  764. for ($i=0; $i<$count; $i++) {
  765. $res[$i]['table'] = $case_func(@mysql_field_table($id, $i));
  766. $res[$i]['name'] = $case_func(@mysql_field_name($id, $i));
  767. $res[$i]['type'] = @mysql_field_type($id, $i);
  768. $res[$i]['len'] = @mysql_field_len($id, $i);
  769. $res[$i]['flags'] = @mysql_field_flags($id, $i);
  770. if ($mode & DB_TABLEINFO_ORDER) {
  771. $res['order'][$res[$i]['name']] = $i;
  772. }
  773. if ($mode & DB_TABLEINFO_ORDERTABLE) {
  774. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  775. }
  776. }
  777. }
  778. // free the result only if we were called on a table
  779. if ($got_string) {
  780. @mysql_free_result($id);
  781. }
  782. return $res;
  783. }
  784. // }}}
  785. // {{{ getSpecialQuery()
  786. /**
  787. * Returns the query needed to get some backend info
  788. * @param string $type What kind of info you want to retrieve
  789. * @return string The SQL query string
  790. */
  791. function getSpecialQuery($type)
  792. {
  793. switch ($type) {
  794. case 'tables':
  795. return 'SHOW TABLES';
  796. case 'views':
  797. return DB_ERROR_NOT_CAPABLE;
  798. case 'users':
  799. $sql = 'select distinct User from user';
  800. if($this->dsn['database'] != 'mysql') {
  801. $dsn = $this->dsn;
  802. $dsn['database'] = 'mysql';
  803. if (DB::isError($db = DB::connect($dsn))) {
  804. return $db;
  805. }
  806. $sql = $db->getCol($sql);
  807. $db->disconnect();
  808. // XXX Fixme the mysql driver should take care of this
  809. if (!@mysql_select_db($this->dsn['database'], $this->connection)) {
  810. return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  811. }
  812. }
  813. return $sql;
  814. case 'databases':
  815. return 'SHOW DATABASES';
  816. default:
  817. return null;
  818. }
  819. }
  820. // }}}
  821. }
  822. /*
  823. * Local variables:
  824. * tab-width: 4
  825. * c-basic-offset: 4
  826. * End:
  827. */
  828. ?>