PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/pear/DB/common.php

http://interra.googlecode.com/
PHP | 1399 lines | 592 code | 148 blank | 659 comment | 117 complexity | 0f35d0e9a42dcda37acb33dde99110d6 MD5 | raw file
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 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@fast.no> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: common.php 2 2005-06-13 10:42:23Z alex $
  20. //
  21. // Base class for DB implementations.
  22. //
  23. /**
  24. * DB_common is a base class for DB implementations, and must be
  25. * inherited by all such.
  26. */
  27. //require_once "PEAR.php";
  28. class DB_common extends PEAR
  29. {
  30. // {{{ properties
  31. /**
  32. * assoc of capabilities for this DB implementation
  33. * $features['limit'] => 'emulate' => emulate with fetch row by number
  34. * 'alter' => alter the query
  35. * false => skip rows
  36. * @var array
  37. */
  38. var $features;
  39. /**
  40. * assoc mapping native error codes to DB ones
  41. * @var array
  42. */
  43. var $errorcode_map;
  44. /**
  45. * DB type (mysql, oci8, odbc etc.)
  46. * @var string
  47. */
  48. var $type;
  49. /**
  50. * @var string
  51. */
  52. var $prepare_tokens;
  53. /**
  54. * @var string
  55. */
  56. var $prepare_types;
  57. /**
  58. * @var string
  59. */
  60. var $prepared_queries;
  61. /**
  62. * @var integer
  63. */
  64. var $prepare_maxstmt = 0;
  65. /**
  66. * @var string
  67. */
  68. var $last_query = '';
  69. /**
  70. * @var integer
  71. */
  72. var $fetchmode = DB_FETCHMODE_ORDERED;
  73. /**
  74. * @var string
  75. */
  76. var $fetchmode_object_class = 'stdClass';
  77. /**
  78. * $options["persistent"] -> boolean persistent connection true|false?
  79. * $options["optimize"] -> string 'performance' or 'portability'
  80. * $options["debug"] -> integer numeric debug level
  81. * @var array
  82. */
  83. var $options = array(
  84. 'persistent' => false,
  85. 'optimize' => 'performance',
  86. 'debug' => 0,
  87. 'seqname_format' => '%s_seq',
  88. 'autofree' => false
  89. );
  90. /**
  91. * DB handle
  92. * @var resource
  93. */
  94. var $dbh;
  95. var $totq = 0;
  96. // }}}
  97. // {{{ toString()
  98. /**
  99. * String conversation
  100. *
  101. * @return string
  102. * @access private
  103. */
  104. function toString()
  105. {
  106. $info = get_class($this);
  107. $info .= ": (phptype=" . $this->phptype .
  108. ", dbsyntax=" . $this->dbsyntax .
  109. ")";
  110. if ($this->connection) {
  111. $info .= " [connected]";
  112. }
  113. return $info;
  114. }
  115. // }}}
  116. // {{{ constructor
  117. /**
  118. * Constructor
  119. */
  120. function DB_common()
  121. {
  122. $this->PEAR('DB_Error');
  123. $this->features = array();
  124. $this->errorcode_map = array();
  125. $this->fetchmode = DB_FETCHMODE_ORDERED;
  126. }
  127. // }}}
  128. // {{{ quoteString()
  129. /**
  130. * Quotes a string so it can be safely used within string delimiters
  131. * in a query (preserved for compatibility issues, quote() is preffered).
  132. *
  133. * @return string quoted string
  134. * @access public
  135. * @see quote()
  136. */
  137. function quoteString($string)
  138. {
  139. $string = $this->quote($string);
  140. if ($string{0} == "'") {
  141. return substr($string, 1, -1);
  142. }
  143. return $string;
  144. }
  145. /**
  146. * Quotes a string so it can be safely used in a query. It will return
  147. * the string with single quotes around. Other backend quote styles
  148. * should override this method.
  149. *
  150. * @param string $string the input string to quote
  151. *
  152. * @return string The NULL string or the string quotes
  153. * in magic_quote_sybase style
  154. */
  155. function quote($string)
  156. {
  157. return ($string === null) ? 'NULL' : "'".str_replace("'", "''", $string)."'";
  158. }
  159. // }}}
  160. // {{{ provides()
  161. /**
  162. * Tell whether a DB implementation or its backend extension
  163. * supports a given feature.
  164. *
  165. * @param array $feature name of the feature (see the DB class doc)
  166. * @return bool whether this DB implementation supports $feature
  167. * @access public
  168. */
  169. function provides($feature)
  170. {
  171. return $this->features[$feature];
  172. }
  173. // }}}
  174. // {{{ errorCode()
  175. /**
  176. * Map native error codes to DB's portable ones. Requires that
  177. * the DB implementation's constructor fills in the $errorcode_map
  178. * property.
  179. *
  180. * @param mixed $nativecode the native error code, as returned by the backend
  181. * database extension (string or integer)
  182. *
  183. * @return int a portable DB error code, or FALSE if this DB
  184. * implementation has no mapping for the given error code.
  185. *
  186. * @access public
  187. */
  188. function errorCode($nativecode)
  189. {
  190. if (isset($this->errorcode_map[$nativecode])) {
  191. return $this->errorcode_map[$nativecode];
  192. }
  193. // Fall back to DB_ERROR if there was no mapping.
  194. return DB_ERROR;
  195. }
  196. // }}}
  197. // {{{ errorMessage()
  198. /**
  199. * Map a DB error code to a textual message. This is actually
  200. * just a wrapper for DB::errorMessage().
  201. *
  202. * @param integer $dbcode the DB error code
  203. *
  204. * @return string the corresponding error message, of FALSE
  205. * if the error code was unknown
  206. *
  207. * @access public
  208. */
  209. function errorMessage($dbcode)
  210. {
  211. return DB::errorMessage($this->errorcode_map[$dbcode]);
  212. }
  213. // }}}
  214. // {{{ raiseError()
  215. /**
  216. * This method is used to communicate an error and invoke error
  217. * callbacks etc. Basically a wrapper for PEAR::raiseError
  218. * without the message string.
  219. *
  220. * @param mixed integer error code, or a PEAR error object (all
  221. * other parameters are ignored if this parameter is
  222. * an object
  223. *
  224. * @param int error mode, see PEAR_Error docs
  225. *
  226. * @param mixed If error mode is PEAR_ERROR_TRIGGER, this is the
  227. * error level (E_USER_NOTICE etc). If error mode is
  228. * PEAR_ERROR_CALLBACK, this is the callback function,
  229. * either as a function name, or as an array of an
  230. * object and method name. For other error modes this
  231. * parameter is ignored.
  232. *
  233. * @param string Extra debug information. Defaults to the last
  234. * query and native error code.
  235. *
  236. * @param mixed Native error code, integer or string depending the
  237. * backend.
  238. *
  239. * @return object a PEAR error object
  240. *
  241. * @access public
  242. * @see PEAR_Error
  243. */
  244. function &raiseError($code = DB_ERROR, $mode = null, $options = null,
  245. $userinfo = null, $nativecode = null)
  246. {
  247. // The error is yet a DB error object
  248. if (is_object($code)) {
  249. // because we the static PEAR::raiseError, our global
  250. // handler should be used if it is set
  251. if ($mode === null && !empty($this->_default_error_mode)) {
  252. $mode = $this->_default_error_mode;
  253. $options = $this->_default_error_options;
  254. }
  255. return PEAR::raiseError($code, null, $mode, $options, null, null, true);
  256. }
  257. if ($userinfo === null) {
  258. $userinfo = $this->last_query;
  259. }
  260. if ($nativecode) {
  261. $userinfo .= " [nativecode=$nativecode]";
  262. }
  263. return PEAR::raiseError(null, $code, $mode, $options, $userinfo,
  264. 'DB_Error', true);
  265. }
  266. // }}}
  267. // {{{ setFetchMode()
  268. /**
  269. * Sets which fetch mode should be used by default on queries
  270. * on this connection.
  271. *
  272. * @param integer $fetchmode DB_FETCHMODE_ORDERED or
  273. * DB_FETCHMODE_ASSOC, possibly bit-wise OR'ed with
  274. * DB_FETCHMODE_FLIPPED.
  275. *
  276. * @param string $object_class The class of the object
  277. * to be returned by the fetch methods when
  278. * the DB_FETCHMODE_OBJECT mode is selected.
  279. * If no class is specified by default a cast
  280. * to object from the assoc array row will be done.
  281. * There is also the posibility to use and extend the
  282. * 'DB_Row' class.
  283. *
  284. * @see DB_FETCHMODE_ORDERED
  285. * @see DB_FETCHMODE_ASSOC
  286. * @see DB_FETCHMODE_FLIPPED
  287. * @see DB_FETCHMODE_OBJECT
  288. * @see DB_Row::DB_Row()
  289. * @access public
  290. */
  291. function setFetchMode($fetchmode, $object_class = null)
  292. {
  293. switch ($fetchmode) {
  294. case DB_FETCHMODE_OBJECT:
  295. if ($object_class) {
  296. $this->fetchmode_object_class = $object_class;
  297. }
  298. case DB_FETCHMODE_ORDERED:
  299. case DB_FETCHMODE_ASSOC:
  300. $this->fetchmode = $fetchmode;
  301. break;
  302. default:
  303. return $this->raiseError('invalid fetchmode mode');
  304. }
  305. }
  306. // }}}
  307. // {{{ setOption()
  308. /**
  309. * set the option for the db class
  310. *
  311. * @param string $option option name
  312. * @param mixed $value value for the option
  313. *
  314. * @return mixed DB_OK or DB_Error
  315. */
  316. function setOption($option, $value)
  317. {
  318. if (isset($this->options[$option])) {
  319. $this->options[$option] = $value;
  320. return DB_OK;
  321. }
  322. return $this->raiseError("unknown option $option");
  323. }
  324. // }}}
  325. // {{{ getOption()
  326. /**
  327. * returns the value of an option
  328. *
  329. * @param string $option option name
  330. *
  331. * @return mixed the option value
  332. */
  333. function getOption($option)
  334. {
  335. if (isset($this->options[$option])) {
  336. return $this->options[$option];
  337. }
  338. return $this->raiseError("unknown option $option");
  339. }
  340. // }}}
  341. // {{{ prepare()
  342. /**
  343. * Prepares a query for multiple execution with execute().
  344. * With some database backends, this is emulated.
  345. * prepare() requires a generic query as string like
  346. * "INSERT INTO numbers VALUES(?,?,?)". The ? are wildcards.
  347. * Types of wildcards:
  348. * ? - a quoted scalar value, i.e. strings, integers
  349. * & - requires a file name, the content of the file
  350. * insert into the query (i.e. saving binary data
  351. * in a db)
  352. * ! - value is inserted 'as is'
  353. *
  354. * @param string the query to prepare
  355. *
  356. * @return resource handle for the query
  357. *
  358. * @access public
  359. * @see execute
  360. */
  361. function prepare($query)
  362. {
  363. $tokens = split("[\&\?\!]", $query);
  364. $token = 0;
  365. $types = array();
  366. for ($i = 0; $i < strlen($query); $i++) {
  367. switch ($query[$i]) {
  368. case '?':
  369. $types[$token++] = DB_PARAM_SCALAR;
  370. break;
  371. case '&':
  372. $types[$token++] = DB_PARAM_OPAQUE;
  373. break;
  374. case '!':
  375. $types[$token++] = DB_PARAM_MISC;
  376. break;
  377. }
  378. }
  379. $this->prepare_tokens[] = &$tokens;
  380. end($this->prepare_tokens);
  381. $k = key($this->prepare_tokens);
  382. $this->prepare_types[$k] = $types;
  383. $this->prepared_queries[$k] = &$query;
  384. return $k;
  385. }
  386. // }}}
  387. // {{{ autoPrepare()
  388. /**
  389. * Make automaticaly an insert or update query and call prepare() with it
  390. *
  391. * @param string $table name of the table
  392. * @param array $table_fields ordered array containing the fields names
  393. * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE)
  394. * @param string $where in case of update queries, this string will be put after the sql WHERE statement
  395. * @return resource handle for the query
  396. * @see buildManipSQL
  397. * @access public
  398. */
  399. function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, $where = false)
  400. {
  401. $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
  402. return $this->prepare($query);
  403. }
  404. // {{{
  405. // }}} autoExecute()
  406. /**
  407. * Make automaticaly an insert or update query and call prepare() and execute() with it
  408. *
  409. * @param string $table name of the table
  410. * @param array $fields_values assoc ($key=>$value) where $key is a field name and $value its value
  411. * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE)
  412. * @param string $where in case of update queries, this string will be put after the sql WHERE statement
  413. * @return mixed a new DB_Result or a DB_Error when fail
  414. * @see buildManipSQL
  415. * @see autoPrepare
  416. * @access public
  417. */
  418. function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, $where = false)
  419. {
  420. $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, $where);
  421. return $this->execute($sth, array_values($fields_values));
  422. }
  423. // {{{
  424. // }}} buildManipSQL()
  425. /**
  426. * Make automaticaly an sql query for prepare()
  427. *
  428. * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), DB_AUTOQUERY_INSERT)
  429. * will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?)
  430. * NB : - This belongs more to a SQL Builder class, but this is a simple facility
  431. * - Be carefull ! If you don't give a $where param with an UPDATE query, all
  432. * the records of the table will be updated !
  433. *
  434. * @param string $table name of the table
  435. * @param array $table_fields ordered array containing the fields names
  436. * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE)
  437. * @param string $where in case of update queries, this string will be put after the sql WHERE statement
  438. * @return string sql query for prepare()
  439. * @access public
  440. */
  441. function buildManipSQL($table, $table_fields, $mode, $where = false)
  442. {
  443. if (count($table_fields) == 0) {
  444. $this->raiseError(DB_ERROR_NEED_MORE_DATA);
  445. }
  446. $first = true;
  447. switch ($mode) {
  448. case DB_AUTOQUERY_INSERT:
  449. $values = '';
  450. $names = '';
  451. while (list(, $value) = each($table_fields)) {
  452. if ($first) {
  453. $first = false;
  454. } else {
  455. $names .= ',';
  456. $values .= ',';
  457. }
  458. $names .= $value;
  459. $values .= '?';
  460. }
  461. return "INSERT INTO $table ($names) VALUES ($values)";
  462. break;
  463. case DB_AUTOQUERY_UPDATE:
  464. $set = '';
  465. while (list(, $value) = each($table_fields)) {
  466. if ($first) {
  467. $first = false;
  468. } else {
  469. $set .= ',';
  470. }
  471. $set .= "$value = ?";
  472. }
  473. $sql = "UPDATE $table SET $set";
  474. if ($where) {
  475. $sql .= " WHERE $where";
  476. }
  477. return $sql;
  478. break;
  479. default:
  480. $this->raiseError(DB_ERROR_SYNTAX);
  481. }
  482. }
  483. // }}}
  484. // {{{ execute()
  485. /**
  486. * Executes a prepared SQL query
  487. * With execute() the generic query of prepare is
  488. * assigned with the given data array. The values
  489. * of the array inserted into the query in the same
  490. * order like the array order
  491. *
  492. * @param resource $stmt query handle from prepare()
  493. * @param array $data numeric array containing the
  494. * data to insert into the query
  495. *
  496. * @return mixed a new DB_Result or a DB_Error when fail
  497. *
  498. * @access public
  499. * @see prepare()
  500. */
  501. function &execute($stmt, $data = false)
  502. {
  503. $realquery = $this->executeEmulateQuery($stmt, $data);
  504. if (DB::isError($realquery)) {
  505. return $realquery;
  506. }
  507. $result = $this->simpleQuery($realquery);
  508. if (DB::isError($result) || $result === DB_OK) {
  509. return $result;
  510. } else {
  511. return new DB_result($this, $result);
  512. }
  513. }
  514. // }}}
  515. // {{{ executeEmulateQuery()
  516. /**
  517. * Emulates the execute statement, when not supported
  518. *
  519. * @param resource $stmt query handle from prepare()
  520. * @param array $data numeric array containing the
  521. * data to insert into the query
  522. *
  523. * @return mixed a string containing the real query run when emulating
  524. * prepare/execute. A DB error code is returned on failure.
  525. *
  526. * @access private
  527. * @see execute()
  528. */
  529. function executeEmulateQuery($stmt, $data = false)
  530. {
  531. $p = &$this->prepare_tokens;
  532. if (!isset($this->prepare_tokens[$stmt]) ||
  533. !is_array($this->prepare_tokens[$stmt]) ||
  534. !sizeof($this->prepare_tokens[$stmt]))
  535. {
  536. return $this->raiseError(DB_ERROR_INVALID);
  537. }
  538. $qq = &$this->prepare_tokens[$stmt];
  539. $qp = sizeof($qq) - 1;
  540. if ((!$data && $qp > 0) ||
  541. (!is_array($data) && $qp > 1) ||
  542. (is_array($data) && $qp > sizeof($data)))
  543. {
  544. $this->last_query = $this->prepared_queries[$stmt];
  545. return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
  546. }
  547. $realquery = $qq[0];
  548. for ($i = 0; $i < $qp; $i++) {
  549. $type = $this->prepare_types[$stmt][$i];
  550. if ($type == DB_PARAM_OPAQUE) {
  551. if (is_array($data)) {
  552. $fp = fopen($data[$i], 'r');
  553. } else {
  554. $fp = fopen($data, 'r');
  555. }
  556. $pdata = '';
  557. if ($fp) {
  558. while (($buf = fread($fp, 4096)) != false) {
  559. $pdata .= $buf;
  560. }
  561. }
  562. } else {
  563. if (is_array($data)) {
  564. $pdata = &$data[$i];
  565. } else {
  566. $pdata = &$data;
  567. }
  568. }
  569. $realquery .= ($type != DB_PARAM_MISC) ? $this->quote($pdata) : $pdata;
  570. $realquery .= $qq[$i + 1];
  571. }
  572. return $realquery;
  573. }
  574. // }}}
  575. // {{{ executeMultiple()
  576. /**
  577. * This function does several execute() calls on the same
  578. * statement handle. $data must be an array indexed numerically
  579. * from 0, one execute call is done for every "row" in the array.
  580. *
  581. * If an error occurs during execute(), executeMultiple() does not
  582. * execute the unfinished rows, but rather returns that error.
  583. *
  584. * @param resource $stmt query handle from prepare()
  585. * @param array $data numeric array containing the
  586. * data to insert into the query
  587. *
  588. * @return mixed DB_OK or DB_Error
  589. *
  590. * @access public
  591. * @see prepare(), execute()
  592. */
  593. function executeMultiple( $stmt, &$data )
  594. {
  595. for($i = 0; $i < sizeof( $data ); $i++) {
  596. $res = $this->execute($stmt, $data[$i]);
  597. if (DB::isError($res)) {
  598. return $res;
  599. }
  600. }
  601. return DB_OK;
  602. }
  603. // }}}
  604. // {{{ modifyQuery()
  605. /**
  606. * This method is used by backends to alter queries for various
  607. * reasons. It is defined here to assure that all implementations
  608. * have this method defined.
  609. *
  610. * @param string $query query to modify
  611. *
  612. * @return the new (modified) query
  613. *
  614. * @access private
  615. */
  616. function modifyQuery($query) {
  617. return $query;
  618. }
  619. // }}}
  620. // {{{ modifyLimitQuery()
  621. /**
  622. * This method is used by backends to alter limited queries
  623. *
  624. * @param string $query query to modify
  625. * @param integer $from the row to start to fetching
  626. * @param integer $count the numbers of rows to fetch
  627. *
  628. * @return the new (modified) query
  629. *
  630. * @access private
  631. */
  632. function modifyLimitQuery($query, $from, $count)
  633. {
  634. return $query;
  635. }
  636. // }}}
  637. // {{{ query()
  638. /**
  639. * Send a query to the database and return any results with a
  640. * DB_result object.
  641. *
  642. * @access public
  643. *
  644. * @param string $query the SQL query or the statement to prepare
  645. * @param string $params the data to be added to the query
  646. * @return mixed a DB_result object or DB_OK on success, a DB
  647. * error on failure
  648. *
  649. * @see DB::isError
  650. * @see DB_common::prepare
  651. * @see DB_common::execute
  652. */
  653. function &query($query, $params = array()) {
  654. $query = str_replace("''","NULL",$query); // pvl patch
  655. $this->totq++;
  656. //echo $this->totq . "--" . $query . "<br /><br />";
  657. if (sizeof($params) > 0) {
  658. $sth = $this->prepare($query);
  659. if (DB::isError($sth)) {
  660. return $sth;
  661. }
  662. return $this->execute($sth, $params);
  663. } else {
  664. $result = $this->simpleQuery($query);
  665. if (DB::isError($result) || $result === DB_OK) {
  666. return $result;
  667. } else {
  668. return new DB_result($this, $result);
  669. }
  670. }
  671. }
  672. // }}}
  673. // {{{ limitQuery()
  674. /**
  675. * Generates a limited query
  676. *
  677. * @param string $query query
  678. * @param integer $from the row to start to fetching
  679. * @param integer $count the numbers of rows to fetch
  680. * @param array $params required for a statement
  681. *
  682. * @return mixed a DB_Result object, DB_OK or a DB_Error
  683. *
  684. * @access public
  685. */
  686. function &limitQuery($query, $from, $count, $params = array())
  687. {
  688. $query = $this->modifyLimitQuery($query, $from, $count);
  689. $result = $this->query($query, $params);
  690. if (DB::isError($result) || get_class($result) == 'db_result' ||
  691. $result === DB_OK) {
  692. return $result;
  693. } else {
  694. $options['limit_from'] = $from;
  695. $options['limit_count'] = $count;
  696. return new DB_result($this, $result, $options);
  697. }
  698. }
  699. // }}}
  700. // {{{ getOne()
  701. /**
  702. * Fetch the first column of the first row of data returned from
  703. * a query. Takes care of doing the query and freeing the results
  704. * when finished.
  705. *
  706. * @param string $query the SQL query
  707. * @param array $params if supplied, prepare/execute will be used
  708. * with this array as execute parameters
  709. *
  710. * @return mixed DB_Error or the returned value of the query
  711. *
  712. * @access public
  713. */
  714. function &getOne($query, $params = array())
  715. {
  716. settype($params, "array");
  717. if (sizeof($params) > 0) {
  718. $sth = $this->prepare($query);
  719. if (DB::isError($sth)) {
  720. return $sth;
  721. }
  722. $res = $this->execute($sth, $params);
  723. } else {
  724. $res = $this->query($query);
  725. }
  726. if (DB::isError($res)) {
  727. return $res;
  728. }
  729. $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED);
  730. if ($err !== DB_OK) {
  731. return $err;
  732. }
  733. $res->free();
  734. if (isset($sth)) {
  735. $this->freeResult($sth);
  736. }
  737. return $row[0];
  738. }
  739. // }}}
  740. // {{{ getRow()
  741. /**
  742. * Fetch the first row of data returned from a query. Takes care
  743. * of doing the query and freeing the results when finished.
  744. *
  745. * @param string $query the SQL query
  746. * @param integer $fetchmode the fetch mode to use
  747. * @param array $params array if supplied, prepare/execute will be used
  748. * with this array as execute parameters
  749. * @access public
  750. * @return array the first row of results as an array indexed from
  751. * 0, or a DB error code.
  752. */
  753. function &getRow($query,
  754. $params = null,
  755. $fetchmode = DB_FETCHMODE_DEFAULT)
  756. {
  757. // compat check, the params and fetchmode parameters used to
  758. // have the opposite order
  759. if (!is_array($params)) {
  760. if (is_array($fetchmode)) {
  761. $tmp = $params;
  762. $params = $fetchmode;
  763. $fetchmode = $tmp;
  764. } elseif ($params !== null) {
  765. $fetchmode = $params;
  766. $params = null;
  767. }
  768. }
  769. $params = (empty($params)) ? array() : $params;
  770. $fetchmode = (empty($fetchmode)) ? DB_FETCHMODE_DEFAULT : $fetchmode;
  771. settype($params, 'array');
  772. if (sizeof($params) > 0) {
  773. $sth = $this->prepare($query);
  774. if (DB::isError($sth)) {
  775. return $sth;
  776. }
  777. $res = $this->execute($sth, $params);
  778. } else {
  779. $res = $this->query($query);
  780. }
  781. if (DB::isError($res)) {
  782. return $res;
  783. }
  784. $err = $res->fetchInto($row, $fetchmode);
  785. if ($err !== DB_OK) {
  786. return $err;
  787. }
  788. $res->free();
  789. if (isset($sth)) {
  790. $this->freeResult($sth);
  791. }
  792. return $row;
  793. }
  794. // }}}
  795. // {{{ getCol()
  796. /**
  797. * Fetch a single column from a result set and return it as an
  798. * indexed array.
  799. *
  800. * @param string $query the SQL query
  801. *
  802. * @param mixed $col which column to return (integer [column number,
  803. * starting at 0] or string [column name])
  804. *
  805. * @param array $params array if supplied, prepare/execute will be used
  806. * with this array as execute parameters
  807. * @access public
  808. *
  809. * @return array an indexed array with the data from the first
  810. * row at index 0, or a DB error code.
  811. */
  812. function &getCol($query, $col = 0, $params = array())
  813. {
  814. settype($params, "array");
  815. if (sizeof($params) > 0) {
  816. $sth = $this->prepare($query);
  817. if (DB::isError($sth)) {
  818. return $sth;
  819. }
  820. $res = $this->execute($sth, $params);
  821. } else {
  822. $res = $this->query($query);
  823. }
  824. if (DB::isError($res)) {
  825. return $res;
  826. }
  827. $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
  828. $ret = array();
  829. while (is_array($row = $res->fetchRow($fetchmode))) {
  830. $ret[] = $row[$col];
  831. }
  832. if (DB::isError($row)) {
  833. $ret = $row;
  834. }
  835. $res->free();
  836. if (isset($sth)) {
  837. $this->freeResult($sth);
  838. }
  839. return $ret;
  840. }
  841. // }}}
  842. // {{{ getAssoc()
  843. /**
  844. * Fetch the entire result set of a query and return it as an
  845. * associative array using the first column as the key.
  846. *
  847. * If the result set contains more than two columns, the value
  848. * will be an array of the values from column 2-n. If the result
  849. * set contains only two columns, the returned value will be a
  850. * scalar with the value of the second column (unless forced to an
  851. * array with the $force_array parameter). A DB error code is
  852. * returned on errors. If the result set contains fewer than two
  853. * columns, a DB_ERROR_TRUNCATED error is returned.
  854. *
  855. * For example, if the table "mytable" contains:
  856. *
  857. * ID TEXT DATE
  858. * --------------------------------
  859. * 1 'one' 944679408
  860. * 2 'two' 944679408
  861. * 3 'three' 944679408
  862. *
  863. * Then the call getAssoc('SELECT id,text FROM mytable') returns:
  864. * array(
  865. * '1' => 'one',
  866. * '2' => 'two',
  867. * '3' => 'three',
  868. * )
  869. *
  870. * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
  871. * array(
  872. * '1' => array('one', '944679408'),
  873. * '2' => array('two', '944679408'),
  874. * '3' => array('three', '944679408')
  875. * )
  876. *
  877. * If the more than one row occurs with the same value in the
  878. * first column, the last row overwrites all previous ones by
  879. * default. Use the $group parameter if you don't want to
  880. * overwrite like this. Example:
  881. *
  882. * getAssoc('SELECT category,id,name FROM mytable', false, null,
  883. * DB_FETCHMODE_ASSOC, true) returns:
  884. * array(
  885. * '1' => array(array('id' => '4', 'name' => 'number four'),
  886. * array('id' => '6', 'name' => 'number six')
  887. * ),
  888. * '9' => array(array('id' => '4', 'name' => 'number four'),
  889. * array('id' => '6', 'name' => 'number six')
  890. * )
  891. * )
  892. *
  893. * Keep in mind that database functions in PHP usually return string
  894. * values for results regardless of the database's internal type.
  895. *
  896. * @param string $query the SQL query
  897. *
  898. * @param boolean $force_array used only when the query returns
  899. * exactly two columns. If true, the values of the returned array
  900. * will be one-element arrays instead of scalars.
  901. *
  902. * @param array $params array if supplied, prepare/execute will be used
  903. * with this array as execute parameters
  904. *
  905. * @param boolean $group if true, the values of the returned array
  906. * is wrapped in another array. If the same
  907. * key value (in the first column) repeats
  908. * itself, the values will be appended to
  909. * this array instead of overwriting the
  910. * existing values.
  911. *
  912. * @access public
  913. *
  914. * @return array associative array with results from the query.
  915. */
  916. function &getAssoc($query, $force_array = false, $params = array(),
  917. $fetchmode = DB_FETCHMODE_ORDERED, $group = false)
  918. {
  919. settype($params, "array");
  920. if (sizeof($params) > 0) {
  921. $sth = $this->prepare($query);
  922. if (DB::isError($sth)) {
  923. return $sth;
  924. }
  925. $res = $this->execute($sth, $params);
  926. } else {
  927. $res = $this->query($query);
  928. }
  929. if (DB::isError($res)) {
  930. return $res;
  931. }
  932. $cols = $res->numCols();
  933. if ($cols < 2) {
  934. return $this->raiseError(DB_ERROR_TRUNCATED);
  935. }
  936. $results = array();
  937. if ($cols > 2 || $force_array) {
  938. // return array values
  939. // XXX this part can be optimized
  940. if ($fetchmode == DB_FETCHMODE_ASSOC) {
  941. while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) {
  942. reset($row);
  943. $key = current($row);
  944. unset($row[key($row)]);
  945. if ($group) {
  946. $results[$key][] = $row;
  947. } else {
  948. $results[$key] = $row;
  949. }
  950. }
  951. } else {
  952. while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
  953. // we shift away the first element to get
  954. // indices running from 0 again
  955. $key = array_shift($row);
  956. if ($group) {
  957. $results[$key][] = $row;
  958. } else {
  959. $results[$key] = $row;
  960. }
  961. }
  962. }
  963. if (DB::isError($row)) {
  964. $results = $row;
  965. }
  966. } else {
  967. // return scalar values
  968. while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
  969. if ($group) {
  970. $results[$row[0]][] = $row[1];
  971. } else {
  972. $results[$row[0]] = $row[1];
  973. }
  974. }
  975. if (DB::isError($row)) {
  976. $results = $row;
  977. }
  978. }
  979. $res->free();
  980. if (isset($sth)) {
  981. $this->freeResult($sth);
  982. }
  983. return $results;
  984. }
  985. // }}}
  986. // {{{ getAll()
  987. /**
  988. * Fetch all the rows returned from a query.
  989. *
  990. * @param string $query the SQL query
  991. *
  992. * @param array $params array if supplied, prepare/execute will be used
  993. * with this array as execute parameters
  994. * @param integer $fetchmode the fetch mode to use
  995. *
  996. * @access public
  997. * @return array an nested array, or a DB error
  998. */
  999. function &getAll($query,
  1000. $params = null,
  1001. $fetchmode = DB_FETCHMODE_DEFAULT)
  1002. {
  1003. // compat check, the params and fetchmode parameters used to
  1004. // have the opposite order
  1005. if (!is_array($params)) {
  1006. if (is_array($fetchmode)) {
  1007. $tmp = $params;
  1008. $params = $fetchmode;
  1009. $fetchmode = $tmp;
  1010. } elseif ($params !== null) {
  1011. $fetchmode = $params;
  1012. $params = null;
  1013. }
  1014. }
  1015. $params = (empty($params)) ? array() : $params;
  1016. $fetchmode = (empty($fetchmode)) ? DB_FETCHMODE_DEFAULT : $fetchmode;
  1017. settype($params, "array");
  1018. if (sizeof($params) > 0) {
  1019. $sth = $this->prepare($query);
  1020. if (DB::isError($sth)) {
  1021. return $sth;
  1022. }
  1023. $res = $this->execute($sth, $params);
  1024. } else {
  1025. $res = $this->query($query);
  1026. }
  1027. if (DB::isError($res)) {
  1028. return $res;
  1029. }
  1030. $results = array();
  1031. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  1032. while (DB_OK === $res->fetchInto($row, $fetchmode)) {
  1033. if ($fetchmode & DB_FETCHMODE_FLIPPED) {
  1034. foreach ($row as $key => $val) {
  1035. $results[$key][] = $val;
  1036. }
  1037. } else {
  1038. $results[] = $row;
  1039. }
  1040. }
  1041. $this->popErrorHandling();
  1042. $res->free();
  1043. if (isset($sth)) {
  1044. $this->freeResult($sth);
  1045. }
  1046. if (DB::isError($row)) {
  1047. return $this->raiseError($row);
  1048. }
  1049. return $results;
  1050. }
  1051. // }}}
  1052. // {{{ autoCommit()
  1053. /**
  1054. * enable automatic Commit
  1055. *
  1056. * @param boolean $onoff
  1057. * @return mixed DB_Error
  1058. *
  1059. * @access public
  1060. */
  1061. function autoCommit($onoff=false)
  1062. {
  1063. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1064. }
  1065. // }}}
  1066. // {{{ commit()
  1067. /**
  1068. * starts a Commit
  1069. *
  1070. * @return mixed DB_Error
  1071. *
  1072. * @access public
  1073. */
  1074. function commit()
  1075. {
  1076. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1077. }
  1078. // }}}
  1079. // {{{ rollback()
  1080. /**
  1081. * starts a rollback
  1082. *
  1083. * @return mixed DB_Error
  1084. *
  1085. * @access public
  1086. */
  1087. function rollback()
  1088. {
  1089. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1090. }
  1091. // }}}
  1092. // {{{ numRows()
  1093. /**
  1094. * returns the number of rows in a result object
  1095. *
  1096. * @param object DB_Result the result object to check
  1097. *
  1098. * @return mixed DB_Error or the number of rows
  1099. *
  1100. * @access public
  1101. */
  1102. function numRows($result)
  1103. {
  1104. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1105. }
  1106. // }}}
  1107. // {{{ affectedRows()
  1108. /**
  1109. * returns the affected rows of a query
  1110. *
  1111. * @return mixed DB_Error or number of rows
  1112. *
  1113. * @access public
  1114. */
  1115. function affectedRows()
  1116. {
  1117. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1118. }
  1119. // }}}
  1120. // {{{ errorNative()
  1121. /**
  1122. * returns an errormessage, provides by the database
  1123. *
  1124. * @return mixed DB_Error or message
  1125. *
  1126. * @access public
  1127. */
  1128. function errorNative()
  1129. {
  1130. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1131. }
  1132. // }}}
  1133. // {{{ nextId()
  1134. /**
  1135. * returns the next free id of a sequence
  1136. *
  1137. * @param string $seq_name name of the sequence
  1138. * @param boolean $ondemand when true the seqence is
  1139. * automatic created, if it
  1140. * not exists
  1141. *
  1142. * @return mixed DB_Error or id
  1143. */
  1144. function nextId($seq_name, $ondemand = true)
  1145. {
  1146. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1147. }
  1148. // }}}
  1149. // {{{ createSequence()
  1150. /**
  1151. * creates a new sequence
  1152. *
  1153. * @param string $seq_name name of the new sequence
  1154. *
  1155. * @return mixed DB_Error
  1156. *
  1157. * @access public
  1158. */
  1159. function createSequence($seq_name)
  1160. {
  1161. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1162. }
  1163. // }}}
  1164. // {{{ dropSequence()
  1165. /**
  1166. * deletes a sequence
  1167. *
  1168. * @param string $seq_name name of the sequence
  1169. *
  1170. * @return mixed DB_Error
  1171. *
  1172. * @access public
  1173. */
  1174. function dropSequence($seq_name)
  1175. {
  1176. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1177. }
  1178. // }}}
  1179. // {{{ tableInfo()
  1180. /**
  1181. * returns meta data about the result set
  1182. *
  1183. * @param object DB_Result $result the result object to analyse
  1184. * @param mixed $mode depends on implementation
  1185. *
  1186. * @return mixed DB_Error
  1187. *
  1188. * @access public
  1189. */
  1190. function tableInfo($result, $mode = null)
  1191. {
  1192. return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1193. }
  1194. // }}}
  1195. // {{{ getTables()
  1196. /**
  1197. * @deprecated
  1198. */
  1199. function getTables()
  1200. {
  1201. return $this->getListOf('tables');
  1202. }
  1203. // }}}
  1204. // {{{ getListOf()
  1205. /**
  1206. * list internal DB info
  1207. * valid values for $type are db dependent,
  1208. * often: databases, users, view, functions
  1209. *
  1210. * @param string $type type of requested info
  1211. *
  1212. * @return mixed DB_Error or the requested data
  1213. *
  1214. * @access public
  1215. */
  1216. function getListOf($type)
  1217. {
  1218. $sql = $this->getSpecialQuery($type);
  1219. if ($sql === null) { // No support
  1220. return $this->raiseError(DB_ERROR_UNSUPPORTED);
  1221. } elseif (is_int($sql) || DB::isError($sql)) { // Previous error
  1222. return $this->raiseError($sql);
  1223. } elseif (is_array($sql)) { // Already the result
  1224. return $sql;
  1225. }
  1226. return $this->getCol($sql); // Launch this query
  1227. }
  1228. // }}}
  1229. // {{{ getSequenceName()
  1230. function getSequenceName($sqn)
  1231. {
  1232. return sprintf($this->getOption("seqname_format"),
  1233. preg_replace('/[^a-z0-9_]/i', '_', $sqn));
  1234. }
  1235. // }}}
  1236. }
  1237. // Used by many drivers
  1238. if (!function_exists('array_change_key_case')) {
  1239. define('CASE_UPPER', 1);
  1240. define('CASE_LOWER', 0);
  1241. function &array_change_key_case(&$array, $case) {
  1242. $casefunc = ($case == CASE_LOWER) ? 'strtolower' : 'strtoupper';
  1243. $ret = array();
  1244. foreach ($array as $key => $value) {
  1245. $ret[$casefunc($key)] = $value;
  1246. }
  1247. return $ret;
  1248. }
  1249. }
  1250. ?>