You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

882 lines
27 KiB

25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
25 years ago
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 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. // | Authors: Stig Bakken <ssb@fast.no> |
  17. // | Tomas V.V.Cox <cox@idecnet.com> |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id$
  21. //
  22. // Database independent query interface.
  23. //
  24. require_once "PEAR.php";
  25. /*
  26. * The method mapErrorCode in each DB_dbtype implementation maps
  27. * native error codes to one of these.
  28. *
  29. * If you add an error code here, make sure you also add a textual
  30. * version of it in DB::errorMessage().
  31. */
  32. define("DB_OK", 1);
  33. define("DB_ERROR", -1);
  34. define("DB_ERROR_SYNTAX", -2);
  35. define("DB_ERROR_CONSTRAINT", -3);
  36. define("DB_ERROR_NOT_FOUND", -4);
  37. define("DB_ERROR_ALREADY_EXISTS", -5);
  38. define("DB_ERROR_UNSUPPORTED", -6);
  39. define("DB_ERROR_MISMATCH", -7);
  40. define("DB_ERROR_INVALID", -8);
  41. define("DB_ERROR_NOT_CAPABLE", -9);
  42. define("DB_ERROR_TRUNCATED", -10);
  43. define("DB_ERROR_INVALID_NUMBER", -11);
  44. define("DB_ERROR_INVALID_DATE", -12);
  45. define("DB_ERROR_DIVZERO", -13);
  46. define("DB_ERROR_NODBSELECTED", -14);
  47. define("DB_ERROR_CANNOT_CREATE", -15);
  48. define("DB_ERROR_CANNOT_DELETE", -16);
  49. define("DB_ERROR_CANNOT_DROP", -17);
  50. define("DB_ERROR_NOSUCHTABLE", -18);
  51. define("DB_ERROR_NOSUCHFIELD", -19);
  52. define("DB_ERROR_NEED_MORE_DATA", -20);
  53. define("DB_ERROR_NOT_LOCKED", -21);
  54. define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
  55. define("DB_ERROR_INVALID_DSN", -23);
  56. define("DB_ERROR_CONNECT_FAILED", -24);
  57. define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
  58. define("DB_ERROR_NOSUCHDB", -25);
  59. define("DB_ERROR_ACCESS_VIOLATION", -26);
  60. /*
  61. * Warnings are not detected as errors by DB::isError(), and are not
  62. * fatal. You can detect whether an error is in fact a warning with
  63. * DB::isWarning().
  64. */
  65. define('DB_WARNING', -1000);
  66. define('DB_WARNING_READ_ONLY', -1001);
  67. /*
  68. * These constants are used when storing information about prepared
  69. * statements (using the "prepare" method in DB_dbtype).
  70. *
  71. * The prepare/execute model in DB is mostly borrowed from the ODBC
  72. * extension, in a query the "?" character means a scalar parameter.
  73. * There are two extensions though, a "&" character means an opaque
  74. * parameter. An opaque parameter is simply a file name, the real
  75. * data are in that file (useful for putting uploaded files into your
  76. * database and such). The "!" char means a parameter that must be
  77. * left as it is.
  78. * They modify the quote behavoir:
  79. * DB_PARAM_SCALAR (?) => 'original string quoted'
  80. * DB_PARAM_OPAQUE (&) => 'string from file quoted'
  81. * DB_PARAM_MISC (!) => original string
  82. */
  83. define('DB_PARAM_SCALAR', 1);
  84. define('DB_PARAM_OPAQUE', 2);
  85. define('DB_PARAM_MISC', 3);
  86. /*
  87. * These constants define different ways of returning binary data
  88. * from queries. Again, this model has been borrowed from the ODBC
  89. * extension.
  90. *
  91. * DB_BINMODE_PASSTHRU sends the data directly through to the browser
  92. * when data is fetched from the database.
  93. * DB_BINMODE_RETURN lets you return data as usual.
  94. * DB_BINMODE_CONVERT returns data as well, only it is converted to
  95. * hex format, for example the string "123" would become "313233".
  96. */
  97. define('DB_BINMODE_PASSTHRU', 1);
  98. define('DB_BINMODE_RETURN', 2);
  99. define('DB_BINMODE_CONVERT', 3);
  100. /**
  101. * This is a special constant that tells DB the user hasn't specified
  102. * any particular get mode, so the default should be used.
  103. */
  104. define('DB_FETCHMODE_DEFAULT', 0);
  105. /**
  106. * Column data indexed by numbers, ordered from 0 and up
  107. */
  108. define('DB_FETCHMODE_ORDERED', 1);
  109. /**
  110. * Column data indexed by column names
  111. */
  112. define('DB_FETCHMODE_ASSOC', 2);
  113. /**
  114. * Column data as object properties
  115. */
  116. define('DB_FETCHMODE_OBJECT', 3);
  117. /**
  118. * For multi-dimensional results: normally the first level of arrays
  119. * is the row number, and the second level indexed by column number or name.
  120. * DB_FETCHMODE_FLIPPED switches this order, so the first level of arrays
  121. * is the column name, and the second level the row number.
  122. */
  123. define('DB_FETCHMODE_FLIPPED', 4);
  124. /* for compatibility */
  125. define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
  126. define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC);
  127. define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED);
  128. /**
  129. * these are constants for the tableInfo-function
  130. * they are bitwised or'ed. so if there are more constants to be defined
  131. * in the future, adjust DB_TABLEINFO_FULL accordingly
  132. */
  133. define('DB_TABLEINFO_ORDER', 1);
  134. define('DB_TABLEINFO_ORDERTABLE', 2);
  135. define('DB_TABLEINFO_FULL', 3);
  136. /**
  137. * The main "DB" class is simply a container class with some static
  138. * methods for creating DB objects as well as some utility functions
  139. * common to all parts of DB.
  140. *
  141. * The object model of DB is as follows (indentation means inheritance):
  142. *
  143. * DB The main DB class. This is simply a utility class
  144. * with some "static" methods for creating DB objects as
  145. * well as common utility functions for other DB classes.
  146. *
  147. * DB_common The base for each DB implementation. Provides default
  148. * | implementations (in OO lingo virtual methods) for
  149. * | the actual DB implementations as well as a bunch of
  150. * | query utility functions.
  151. * |
  152. * +-DB_mysql The DB implementation for MySQL. Inherits DB_common.
  153. * When calling DB::factory or DB::connect for MySQL
  154. * connections, the object returned is an instance of this
  155. * class.
  156. *
  157. * @package DB
  158. * @version 2
  159. * @author Stig Bakken <ssb@fast.no>
  160. * @since PHP 4.0
  161. */
  162. class DB
  163. {
  164. /**
  165. * Create a new DB connection object for the specified database
  166. * type
  167. *
  168. * @param string $type database type, for example "mysql"
  169. *
  170. * @return mixed a newly created DB object, or a DB error code on
  171. * error
  172. *
  173. * access public
  174. */
  175. function &factory($type)
  176. {
  177. @include_once("DB/${type}.php");
  178. $classname = "DB_${type}";
  179. if (!class_exists($classname)) {
  180. return PEAR::raiseError(null, DB_ERROR_NOT_FOUND,
  181. null, null, null, 'DB_Error', true);
  182. }
  183. @$obj =& new $classname;
  184. return $obj;
  185. }
  186. /**
  187. * Create a new DB connection object and connect to the specified
  188. * database
  189. *
  190. * @param mixed $dsn "data source name", see the DB::parseDSN
  191. * method for a description of the dsn format. Can also be
  192. * specified as an array of the format returned by DB::parseDSN.
  193. *
  194. * @param mixed $options An associative array of option names and
  195. * their values. For backwards compatibility, this parameter may
  196. * also be a boolean that tells whether the connection should be
  197. * persistent. See DB_common::setOption for more information on
  198. * connection options.
  199. *
  200. * @return mixed a newly created DB connection object, or a DB
  201. * error object on error
  202. *
  203. * @see DB::parseDSN
  204. * @see DB::isError
  205. * @see DB_common::setOption
  206. */
  207. function &connect($dsn, $options = false)
  208. {
  209. if (is_array($dsn)) {
  210. $dsninfo = $dsn;
  211. } else {
  212. $dsninfo = DB::parseDSN($dsn);
  213. }
  214. $type = $dsninfo["phptype"];
  215. if (is_array($options) && isset($options["debug"]) &&
  216. $options["debug"] >= 2) {
  217. // expose php errors with sufficient debug level
  218. include_once "DB/${type}.php";
  219. } else {
  220. @include_once "DB/${type}.php";
  221. }
  222. $classname = "DB_${type}";
  223. if (!class_exists($classname)) {
  224. return PEAR::raiseError(null, DB_ERROR_NOT_FOUND,
  225. null, null, null, 'DB_Error', true);
  226. }
  227. @$obj =& new $classname;
  228. if (isset($options['connect_ondemand']) && !extension_loaded("overload")) {
  229. unset($options['connect_ondemand']);
  230. }
  231. if (is_array($options)) {
  232. foreach ($options as $option => $value) {
  233. $test = $obj->setOption($option, $value);
  234. if (DB::isError($test)) {
  235. return $test;
  236. }
  237. }
  238. } else {
  239. $obj->setOption('persistent', $options);
  240. }
  241. if (!$obj->getOption('connect_ondemand')) {
  242. $err = $obj->connect($dsninfo, $obj->getOption('persistent'));
  243. if (DB::isError($err)) {
  244. $err->addUserInfo($dsn);
  245. return $err;
  246. }
  247. } else {
  248. $obj->dsn = $dsninfo;
  249. }
  250. return $obj;
  251. }
  252. /**
  253. * Return the DB API version
  254. *
  255. * @return int the DB API version number
  256. *
  257. * @access public
  258. */
  259. function apiVersion()
  260. {
  261. return 2;
  262. }
  263. /**
  264. * Tell whether a result code from a DB method is an error
  265. *
  266. * @param $value int result code
  267. *
  268. * @return bool whether $value is an error
  269. *
  270. * @access public
  271. */
  272. function isError($value)
  273. {
  274. return (is_object($value) &&
  275. (get_class($value) == 'db_error' ||
  276. is_subclass_of($value, 'db_error')));
  277. }
  278. /**
  279. * Tell whether a query is a data manipulation query (insert,
  280. * update or delete) or a data definition query (create, drop,
  281. * alter, grant, revoke).
  282. *
  283. * @access public
  284. *
  285. * @param string $query the query
  286. *
  287. * @return boolean whether $query is a data manipulation query
  288. */
  289. function isManip($query)
  290. {
  291. $manips = 'INSERT|UPDATE|DELETE|'.'REPLACE|CREATE|DROP|'.
  292. 'ALTER|GRANT|REVOKE|'.'LOCK|UNLOCK';
  293. if (preg_match('/^\s*"?('.$manips.')\s+/i', $query)) {
  294. return true;
  295. }
  296. return false;
  297. }
  298. /**
  299. * Tell whether a result code from a DB method is a warning.
  300. * Warnings differ from errors in that they are generated by DB,
  301. * and are not fatal.
  302. *
  303. * @param mixed $value result value
  304. *
  305. * @return boolean whether $value is a warning
  306. *
  307. * @access public
  308. */
  309. function isWarning($value)
  310. {
  311. return (is_object($value) &&
  312. (get_class($value) == "db_warning" ||
  313. is_subclass_of($value, "db_warning")));
  314. }
  315. /**
  316. * Return a textual error message for a DB error code
  317. *
  318. * @param integer $value error code
  319. *
  320. * @return string error message, or false if the error code was
  321. * not recognized
  322. */
  323. function errorMessage($value)
  324. {
  325. static $errorMessages;
  326. if (!isset($errorMessages)) {
  327. $errorMessages = array(
  328. DB_ERROR => 'unknown error',
  329. DB_ERROR_ALREADY_EXISTS => 'already exists',
  330. DB_ERROR_CANNOT_CREATE => 'can not create',
  331. DB_ERROR_CANNOT_DELETE => 'can not delete',
  332. DB_ERROR_CANNOT_DROP => 'can not drop',
  333. DB_ERROR_CONSTRAINT => 'constraint violation',
  334. DB_ERROR_DIVZERO => 'division by zero',
  335. DB_ERROR_INVALID => 'invalid',
  336. DB_ERROR_INVALID_DATE => 'invalid date or time',
  337. DB_ERROR_INVALID_NUMBER => 'invalid number',
  338. DB_ERROR_MISMATCH => 'mismatch',
  339. DB_ERROR_NODBSELECTED => 'no database selected',
  340. DB_ERROR_NOSUCHFIELD => 'no such field',
  341. DB_ERROR_NOSUCHTABLE => 'no such table',
  342. DB_ERROR_NOT_CAPABLE => 'DB backend not capable',
  343. DB_ERROR_NOT_FOUND => 'not found',
  344. DB_ERROR_NOT_LOCKED => 'not locked',
  345. DB_ERROR_SYNTAX => 'syntax error',
  346. DB_ERROR_UNSUPPORTED => 'not supported',
  347. DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
  348. DB_ERROR_INVALID_DSN => 'invalid DSN',
  349. DB_ERROR_CONNECT_FAILED => 'connect failed',
  350. DB_OK => 'no error',
  351. DB_WARNING => 'unknown warning',
  352. DB_WARNING_READ_ONLY => 'read only',
  353. DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied',
  354. DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
  355. DB_ERROR_NOSUCHDB => 'no such database',
  356. DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions'
  357. );
  358. }
  359. if (DB::isError($value)) {
  360. $value = $value->getCode();
  361. }
  362. return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[DB_ERROR];
  363. }
  364. /**
  365. * Parse a data source name
  366. *
  367. * A array with the following keys will be returned:
  368. * phptype: Database backend used in PHP (mysql, odbc etc.)
  369. * dbsyntax: Database used with regards to SQL syntax etc.
  370. * protocol: Communication protocol to use (tcp, unix etc.)
  371. * hostspec: Host specification (hostname[:port])
  372. * database: Database to use on the DBMS server
  373. * username: User name for login
  374. * password: Password for login
  375. *
  376. * The format of the supplied DSN is in its fullest form:
  377. *
  378. * phptype(dbsyntax)://username:password@protocol+hostspec/database
  379. *
  380. * Most variations are allowed:
  381. *
  382. * phptype://username:password@protocol+hostspec:110//usr/db_file.db
  383. * phptype://username:password@hostspec/database_name
  384. * phptype://username:password@hostspec
  385. * phptype://username@hostspec
  386. * phptype://hostspec/database
  387. * phptype://hostspec
  388. * phptype(dbsyntax)
  389. * phptype
  390. *
  391. * @param string $dsn Data Source Name to be parsed
  392. *
  393. * @return array an associative array
  394. *
  395. * @author Tomas V.V.Cox <cox@idecnet.com>
  396. */
  397. function parseDSN($dsn)
  398. {
  399. if (is_array($dsn)) {
  400. return $dsn;
  401. }
  402. $parsed = array(
  403. 'phptype' => false,
  404. 'dbsyntax' => false,
  405. 'username' => false,
  406. 'password' => false,
  407. 'protocol' => false,
  408. 'hostspec' => false,
  409. 'port' => false,
  410. 'socket' => false,
  411. 'database' => false
  412. );
  413. // Find phptype and dbsyntax
  414. if (($pos = strpos($dsn, '://')) !== false) {
  415. $str = substr($dsn, 0, $pos);
  416. $dsn = substr($dsn, $pos + 3);
  417. } else {
  418. $str = $dsn;
  419. $dsn = NULL;
  420. }
  421. // Get phptype and dbsyntax
  422. // $str => phptype(dbsyntax)
  423. if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
  424. $parsed['phptype'] = $arr[1];
  425. $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
  426. } else {
  427. $parsed['phptype'] = $str;
  428. $parsed['dbsyntax'] = $str;
  429. }
  430. if (empty($dsn)) {
  431. return $parsed;
  432. }
  433. // Get (if found): username and password
  434. // $dsn => username:password@protocol+hostspec/database
  435. if (($at = strrpos($dsn,'@')) !== false) {
  436. $str = substr($dsn, 0, $at);
  437. $dsn = substr($dsn, $at + 1);
  438. if (($pos = strpos($str, ':')) !== false) {
  439. $parsed['username'] = urldecode(substr($str, 0, $pos));
  440. $parsed['password'] = urldecode(substr($str, $pos + 1));
  441. } else {
  442. $parsed['username'] = urldecode($str);
  443. }
  444. }
  445. // Find protocol and hostspec
  446. // $dsn => proto(proto_opts)/database
  447. if (preg_match('|^(.+?)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
  448. $proto = $match[1];
  449. $proto_opts = (!empty($match[2])) ? $match[2] : false;
  450. $dsn = $match[3];
  451. // $dsn => protocol+hostspec/database (old format)
  452. } else {
  453. if (strpos($dsn, '+') !== false) {
  454. list($proto, $dsn) = explode('+', $dsn, 2);
  455. }
  456. if (strpos($dsn, '/') !== false) {
  457. list($proto_opts, $dsn) = explode('/', $dsn, 2);
  458. } else {
  459. $proto_opts = $dsn;
  460. $dsn = null;
  461. }
  462. }
  463. // process the different protocol options
  464. $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
  465. $proto_opts = urldecode($proto_opts);
  466. if ($parsed['protocol'] == 'tcp') {
  467. if (strpos($proto_opts, ':') !== false) {
  468. list($parsed['hostspec'], $parsed['port']) = explode(':', $proto_opts);
  469. } else {
  470. $parsed['hostspec'] = $proto_opts;
  471. }
  472. } elseif ($parsed['protocol'] == 'unix') {
  473. $parsed['socket'] = $proto_opts;
  474. }
  475. // Get dabase if any
  476. // $dsn => database
  477. if (!empty($dsn)) {
  478. // /database
  479. if (($pos = strpos($dsn, '?')) === false) {
  480. $parsed['database'] = $dsn;
  481. // /database?param1=value1&param2=value2
  482. } else {
  483. $parsed['database'] = substr($dsn, 0, $pos);
  484. $dsn = substr($dsn, $pos + 1);
  485. if (strpos($dsn, '&') !== false) {
  486. $opts = explode('&', $dsn);
  487. } else { // database?param1=value1
  488. $opts = array($dsn);
  489. }
  490. foreach ($opts as $opt) {
  491. list($key, $value) = explode('=', $opt);
  492. if (!isset($parsed[$key])) { // don't allow params overwrite
  493. $parsed[$key] = urldecode($value);
  494. }
  495. }
  496. }
  497. }
  498. return $parsed;
  499. }
  500. /**
  501. * Load a PHP database extension if it is not loaded already.
  502. *
  503. * @access public
  504. *
  505. * @param string $name the base name of the extension (without the .so or
  506. * .dll suffix)
  507. *
  508. * @return boolean true if the extension was already or successfully
  509. * loaded, false if it could not be loaded
  510. */
  511. function assertExtension($name)
  512. {
  513. if (!extension_loaded($name)) {
  514. $dlext = OS_WINDOWS ? '.dll' : '.so';
  515. @dl($name . $dlext);
  516. }
  517. return extension_loaded($name);
  518. }
  519. }
  520. /**
  521. * DB_Error implements a class for reporting portable database error
  522. * messages.
  523. *
  524. * @package DB
  525. * @author Stig Bakken <ssb@fast.no>
  526. */
  527. class DB_Error extends PEAR_Error
  528. {
  529. /**
  530. * DB_Error constructor.
  531. *
  532. * @param mixed $code DB error code, or string with error message.
  533. * @param integer $mode what "error mode" to operate in
  534. * @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER
  535. * @param smixed $debuginfo additional debug info, such as the last query
  536. *
  537. * @access public
  538. *
  539. * @see PEAR_Error
  540. */
  541. function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN,
  542. $level = E_USER_NOTICE, $debuginfo = null)
  543. {
  544. if (is_int($code)) {
  545. $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, $mode, $level, $debuginfo);
  546. } else {
  547. $this->PEAR_Error("DB Error: $code", DB_ERROR, $mode, $level, $debuginfo);
  548. }
  549. }
  550. }
  551. /**
  552. * DB_Warning implements a class for reporting portable database
  553. * warning messages.
  554. *
  555. * @package DB
  556. * @author Stig Bakken <ssb@fast.no>
  557. */
  558. class DB_Warning extends PEAR_Error
  559. {
  560. /**
  561. * DB_Warning constructor.
  562. *
  563. * @param mixed $code DB error code, or string with error message.
  564. * @param integer $mode what "error mode" to operate in
  565. * @param integer $level what error level to use for $mode == PEAR_ERROR_TRIGGER
  566. * @param mmixed $debuginfo additional debug info, such as the last query
  567. *
  568. * @access public
  569. *
  570. * @see PEAR_Error
  571. */
  572. function DB_Warning($code = DB_WARNING, $mode = PEAR_ERROR_RETURN,
  573. $level = E_USER_NOTICE, $debuginfo = null)
  574. {
  575. if (is_int($code)) {
  576. $this->PEAR_Error('DB Warning: ' . DB::errorMessage($code), $code, $mode, $level, $debuginfo);
  577. } else {
  578. $this->PEAR_Error("DB Warning: $code", 0, $mode, $level, $debuginfo);
  579. }
  580. }
  581. }
  582. /**
  583. * This class implements a wrapper for a DB result set.
  584. * A new instance of this class will be returned by the DB implementation
  585. * after processing a query that returns data.
  586. *
  587. * @package DB
  588. * @author Stig Bakken <ssb@fast.no>
  589. */
  590. class DB_result
  591. {
  592. var $dbh;
  593. var $result;
  594. var $row_counter = null;
  595. /**
  596. * for limit queries, the row to start fetching
  597. * @var integer
  598. */
  599. var $limit_from = null;
  600. /**
  601. * for limit queries, the number of rows to fetch
  602. * @var integer
  603. */
  604. var $limit_count = null;
  605. /**
  606. * DB_result constructor.
  607. * @param resource $dbh DB object reference
  608. * @param resource $result result resource id
  609. */
  610. function DB_result(&$dbh, $result)
  611. {
  612. $this->dbh = &$dbh;
  613. $this->result = $result;
  614. }
  615. /**
  616. * Fetch and return a row of data (it uses driver->fetchInto for that)
  617. * @param int $fetchmode format of fetched row
  618. * @param int $rownum the row number to fetch
  619. *
  620. * @return array a row of data, NULL on no more rows or PEAR_Error on error
  621. *
  622. * @access public
  623. */
  624. function fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null)
  625. {
  626. if ($fetchmode === DB_FETCHMODE_DEFAULT) {
  627. $fetchmode = $this->dbh->fetchmode;
  628. }
  629. if ($fetchmode === DB_FETCHMODE_OBJECT) {
  630. $fetchmode = DB_FETCHMODE_ASSOC;
  631. $object_class = $this->dbh->fetchmode_object_class;
  632. }
  633. if ($this->limit_from !== null) {
  634. if ($this->row_counter === null) {
  635. $this->row_counter = $this->limit_from;
  636. // For Interbase
  637. if ($this->dbh->features['limit'] == false) {
  638. $i = 0;
  639. while ($i++ < $this->limit_from) {
  640. $this->dbh->fetchInto($this->result, $arr, $fetchmode);
  641. }
  642. }
  643. }
  644. if ($this->row_counter >= (
  645. $this->limit_from + $this->limit_count))
  646. {
  647. return null;
  648. }
  649. if ($this->dbh->features['limit'] == 'emulate') {
  650. $rownum = $this->row_counter;
  651. }
  652. $this->row_counter++;
  653. }
  654. $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum);
  655. if ($res !== DB_OK) {
  656. return $res;
  657. }
  658. if (isset($object_class)) {
  659. // default mode specified in DB_common::fetchmode_object_class property
  660. if ($object_class == 'stdClass') {
  661. $ret = (object) $arr;
  662. } else {
  663. $ret =& new $object_class($arr);
  664. }
  665. return $ret;
  666. }
  667. return $arr;
  668. }
  669. /**
  670. * Fetch a row of data into an existing variable.
  671. *
  672. * @param mixed $arr reference to data containing the row
  673. * @param integer $fetchmode format of fetched row
  674. * @param integer $rownum the row number to fetch
  675. *
  676. * @return mixed DB_OK on success, NULL on no more rows or
  677. * a DB_Error object on error
  678. *
  679. * @access public
  680. */
  681. function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null)
  682. {
  683. if ($fetchmode === DB_FETCHMODE_DEFAULT) {
  684. $fetchmode = $this->dbh->fetchmode;
  685. }
  686. if ($fetchmode === DB_FETCHMODE_OBJECT) {
  687. $fetchmode = DB_FETCHMODE_ASSOC;
  688. $object_class = $this->dbh->fetchmode_object_class;
  689. }
  690. if ($this->limit_from !== null) {
  691. if ($this->row_counter === null) {
  692. $this->row_counter = $this->limit_from;
  693. // For Interbase
  694. if ($this->dbh->features['limit'] == false) {
  695. $i = 0;
  696. while ($i++ < $this->limit_from) {
  697. $this->dbh->fetchInto($this->result, $arr, $fetchmode);
  698. }
  699. }
  700. }
  701. if ($this->row_counter >= (
  702. $this->limit_from + $this->limit_count))
  703. {
  704. return null;
  705. }
  706. if ($this->dbh->features['limit'] == 'emulate') {
  707. $rownum = $this->row_counter;
  708. }
  709. $this->row_counter++;
  710. }
  711. $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum);
  712. if (($res === DB_OK) && isset($object_class)) {
  713. // default mode specified in DB_common::fetchmode_object_class property
  714. if ($object_class == 'stdClass') {
  715. $arr = (object) $arr;
  716. } else {
  717. $arr = new $object_class($arr);
  718. }
  719. }
  720. return $res;
  721. }
  722. /**
  723. * Get the the number of columns in a result set.
  724. *
  725. * @return int the number of columns, or a DB error
  726. *
  727. * @access public
  728. */
  729. function numCols()
  730. {
  731. return $this->dbh->numCols($this->result);
  732. }
  733. /**
  734. * Get the number of rows in a result set.
  735. *
  736. * @return int the number of rows, or a DB error
  737. *
  738. * @access public
  739. */
  740. function numRows()
  741. {
  742. return $this->dbh->numRows($this->result);
  743. }
  744. /**
  745. * Get the next result if a batch of queries was executed.
  746. *
  747. * @return bool true if a new result is available or false if not.
  748. *
  749. * @access public
  750. */
  751. function nextResult()
  752. {
  753. return $this->dbh->nextResult($this->result);
  754. }
  755. /**
  756. * Frees the resources allocated for this result set.
  757. * @return int error code
  758. *
  759. * @access public
  760. */
  761. function free()
  762. {
  763. $err = $this->dbh->freeResult($this->result);
  764. if(DB::isError($err)) {
  765. return $err;
  766. }
  767. $this->result = false;
  768. return true;
  769. }
  770. /**
  771. * @deprecated
  772. */
  773. function tableInfo($mode = null)
  774. {
  775. return $this->dbh->tableInfo($this->result, $mode);
  776. }
  777. /**
  778. * returns the actual rows number
  779. * @return integer
  780. */
  781. function getRowCounter()
  782. {
  783. return $this->row_counter;
  784. }
  785. }
  786. /**
  787. * Pear DB Row Object
  788. * @see DB_common::setFetchMode()
  789. */
  790. class DB_row
  791. {
  792. /**
  793. * constructor
  794. *
  795. * @param resource row data as array
  796. */
  797. function DB_row(&$arr)
  798. {
  799. for (reset($arr); $key = key($arr); next($arr)) {
  800. $this->$key = &$arr[$key];
  801. }
  802. }
  803. }
  804. ?>