PageRenderTime 27ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/pear/MDB2/Driver/fbsql.php

https://bitbucket.org/Yason/armory
PHP | 741 lines | 685 code | 1 blank | 55 comment | 0 complexity | 4d663677a720c8bb65cfa52723d03d74 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. // vim: set et ts=4 sw=4 fdm=marker:
  3. // +----------------------------------------------------------------------+
  4. // | PHP versions 4 and 5 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
  7. // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
  8. // | All rights reserved. |
  9. // +----------------------------------------------------------------------+
  10. // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
  11. // | API as well as database abstraction for PHP applications. |
  12. // | This LICENSE is in the BSD license style. |
  13. // | |
  14. // | Redistribution and use in source and binary forms, with or without |
  15. // | modification, are permitted provided that the following conditions |
  16. // | are met: |
  17. // | |
  18. // | Redistributions of source code must retain the above copyright |
  19. // | notice, this list of conditions and the following disclaimer. |
  20. // | |
  21. // | Redistributions in binary form must reproduce the above copyright |
  22. // | notice, this list of conditions and the following disclaimer in the |
  23. // | documentation and/or other materials provided with the distribution. |
  24. // | |
  25. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
  26. // | Lukas Smith nor the names of his contributors may be used to endorse |
  27. // | or promote products derived from this software without specific prior|
  28. // | written permission. |
  29. // | |
  30. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
  31. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
  32. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
  33. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
  34. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
  35. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  36. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  37. // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
  38. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  39. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  40. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
  41. // | POSSIBILITY OF SUCH DAMAGE. |
  42. // +----------------------------------------------------------------------+
  43. // | Author: Lukas Smith <smith@pooteeweet.org> |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: fbsql.php,v 1.93 2006/04/16 11:55:14 lsmith Exp $
  47. //
  48. /**
  49. * MDB2 FrontBase driver
  50. *
  51. * @package MDB2
  52. * @category Database
  53. * @author Lukas Smith <smith@pooteeweet.org>
  54. * @author Frank M. Kromann <frank@kromann.info>
  55. */
  56. class MDB2_Driver_fbsql extends MDB2_Driver_Common
  57. {
  58. // {{{ properties
  59. var $escape_quotes = "'";
  60. // }}}
  61. // {{{ constructor
  62. /**
  63. * Constructor
  64. */
  65. function __construct()
  66. {
  67. parent::__construct();
  68. $this->phptype = 'fbsql';
  69. $this->dbsyntax = 'fbsql';
  70. $this->supported['sequences'] = 'emulated';
  71. $this->supported['indexes'] = true;
  72. $this->supported['affected_rows'] = true;
  73. $this->supported['transactions'] = true;
  74. $this->supported['summary_functions'] = true;
  75. $this->supported['order_by_text'] = true;
  76. $this->supported['current_id'] = 'emulated';
  77. $this->supported['limit_queries'] = 'emulated';
  78. $this->supported['LOBs'] = true;
  79. $this->supported['replace'] ='emulated';
  80. $this->supported['sub_selects'] = true;
  81. $this->supported['auto_increment'] = false; // not implemented
  82. $this->supported['primary_key'] = false; // not implemented
  83. $this->supported['result_introspection'] = true;
  84. }
  85. // }}}
  86. // {{{ errorInfo()
  87. /**
  88. * This method is used to collect information about an error
  89. *
  90. * @param integer $error
  91. * @return array
  92. * @access public
  93. */
  94. function errorInfo($error = null)
  95. {
  96. if ($this->connection) {
  97. $native_code = @fbsql_errno($this->connection);
  98. $native_msg = @fbsql_error($this->connection);
  99. } else {
  100. $native_code = @fbsql_errno();
  101. $native_msg = @fbsql_error();
  102. }
  103. if (is_null($error)) {
  104. static $ecode_map;
  105. if (empty($ecode_map)) {
  106. $ecode_map = array(
  107. 22 => MDB2_ERROR_SYNTAX,
  108. 85 => MDB2_ERROR_ALREADY_EXISTS,
  109. 108 => MDB2_ERROR_SYNTAX,
  110. 116 => MDB2_ERROR_NOSUCHTABLE,
  111. 124 => MDB2_ERROR_VALUE_COUNT_ON_ROW,
  112. 215 => MDB2_ERROR_NOSUCHFIELD,
  113. 217 => MDB2_ERROR_INVALID_NUMBER,
  114. 226 => MDB2_ERROR_NOSUCHFIELD,
  115. 231 => MDB2_ERROR_INVALID,
  116. 239 => MDB2_ERROR_TRUNCATED,
  117. 251 => MDB2_ERROR_SYNTAX,
  118. 266 => MDB2_ERROR_NOT_FOUND,
  119. 357 => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  120. 358 => MDB2_ERROR_CONSTRAINT,
  121. 360 => MDB2_ERROR_CONSTRAINT,
  122. 361 => MDB2_ERROR_CONSTRAINT,
  123. );
  124. }
  125. if (isset($ecode_map[$native_code])) {
  126. $error = $ecode_map[$native_code];
  127. }
  128. }
  129. return array($error, $native_code, $native_msg);
  130. }
  131. // }}}
  132. // {{{ beginTransaction()
  133. /**
  134. * Start a transaction.
  135. *
  136. * @return mixed MDB2_OK on success, a MDB2 error on failure
  137. * @access public
  138. */
  139. function beginTransaction()
  140. {
  141. $this->debug('starting transaction', 'beginTransaction');
  142. if ($this->in_transaction) {
  143. return MDB2_OK; //nothing to do
  144. }
  145. if (!$this->destructor_registered && $this->opened_persistent) {
  146. $this->destructor_registered = true;
  147. register_shutdown_function('MDB2_closeOpenTransactions');
  148. }
  149. $result = $this->_doQuery('SET COMMIT FALSE;', true);
  150. if (PEAR::isError($result)) {
  151. return $result;
  152. }
  153. $this->in_transaction = true;
  154. return MDB2_OK;
  155. }
  156. // }}}
  157. // {{{ commit()
  158. /**
  159. * Commit the database changes done during a transaction that is in
  160. * progress.
  161. *
  162. * @return mixed MDB2_OK on success, a MDB2 error on failure
  163. * @access public
  164. */
  165. function commit()
  166. {
  167. $this->debug('commit transaction', 'commit');
  168. if (!$this->in_transaction) {
  169. return $this->raiseError(MDB2_ERROR, null, null,
  170. 'commit: transaction changes are being auto commited');
  171. }
  172. $result = $this->_doQuery('COMMIT;', true);
  173. if (PEAR::isError($result)) {
  174. return $result;
  175. }
  176. $result = $this->_doQuery('SET COMMIT TRUE;', true);
  177. if (PEAR::isError($result)) {
  178. return $result;
  179. }
  180. $this->in_transaction = false;
  181. return MDB2_OK;
  182. }
  183. // }}}
  184. // {{{ rollback()
  185. /**
  186. * Cancel any database changes done during a transaction that is in
  187. * progress.
  188. *
  189. * @return mixed MDB2_OK on success, a MDB2 error on failure
  190. * @access public
  191. */
  192. function rollback()
  193. {
  194. $this->debug('rolling back transaction', 'rollback');
  195. if (!$this->in_transaction) {
  196. return $this->raiseError(MDB2_ERROR, null, null,
  197. 'rollback: transactions can not be rolled back when changes are auto committed');
  198. }
  199. $result = $this->_doQuery('ROLLBACK;', true);
  200. if (PEAR::isError($result)) {
  201. return $result;
  202. }
  203. $result = $this->_doQuery('SET COMMIT TRUE;', true);
  204. if (PEAR::isError($result)) {
  205. return $result;
  206. }
  207. $this->in_transaction = false;
  208. return MDB2_OK;
  209. }
  210. // }}}
  211. // {{{ connect()
  212. /**
  213. * Connect to the database
  214. *
  215. * @return true on success, MDB2 Error Object on failure
  216. **/
  217. function connect()
  218. {
  219. if (is_resource($this->connection)) {
  220. if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
  221. && $this->opened_persistent == $this->options['persistent']
  222. ) {
  223. return MDB2_OK;
  224. }
  225. $this->disconnect(false);
  226. }
  227. if (!PEAR::loadExtension($this->phptype)) {
  228. return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  229. 'connect: extension '.$this->phptype.' is not compiled into PHP');
  230. }
  231. if (isset($this->dsn['charset']) && !empty($this->dsn['charset'])) {
  232. return $this->raiseError(MDB2_ERROR_UNSUPPORTED,
  233. null, null, 'Unable to set client charset: '.$this->dsn['charset']);
  234. }
  235. $params = array(
  236. $this->dsn['hostspec'] ? $this->dsn['hostspec'] : 'localhost',
  237. $this->dsn['username'] ? $this->dsn['username'] : null,
  238. $this->dsn['password'] ? $this->dsn['password'] : null,
  239. );
  240. $connect_function = $this->options['persistent'] ? 'fbsql_pconnect' : 'fbsql_connect';
  241. @ini_set('track_errors', true);
  242. $php_errormsg = '';
  243. $connection = @call_user_func_array($connect_function, $params);
  244. @ini_restore('track_errors');
  245. if ($connection <= 0) {
  246. return $this->raiseError(MDB2_ERROR_CONNECT_FAILED);
  247. }
  248. $this->connection = $connection;
  249. $this->connected_dsn = $this->dsn;
  250. $this->connected_database_name = '';
  251. $this->opened_persistent = $this->options['persistent'];
  252. $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
  253. return MDB2_OK;
  254. }
  255. // }}}
  256. // {{{ disconnect()
  257. /**
  258. * Log out and disconnect from the database.
  259. *
  260. * @param boolean $force if the disconnect should be forced even if the
  261. * connection is opened persistently
  262. * @return mixed true on success, false if not connected and error
  263. * object on error
  264. * @access public
  265. */
  266. function disconnect($force = true)
  267. {
  268. if (is_resource($this->connection)) {
  269. if ($this->in_transaction) {
  270. $this->rollback();
  271. }
  272. if (!$this->opened_persistent || $force) {
  273. @fbsql_close($this->connection);
  274. }
  275. }
  276. return parent::disconnect($force);
  277. return MDB2_OK;
  278. }
  279. // }}}
  280. // {{{ _doQuery()
  281. /**
  282. * Execute a query
  283. * @param string $query query
  284. * @param boolean $is_manip if the query is a manipulation query
  285. * @param resource $connection
  286. * @param string $database_name
  287. * @return result or error object
  288. * @access protected
  289. */
  290. function _doQuery($query, $is_manip = false, $connection = null, $database_name = null)
  291. {
  292. $this->last_query = $query;
  293. $this->debug($query, 'query', $is_manip);
  294. if ($this->options['disable_query']) {
  295. if ($is_manip) {
  296. return 0;
  297. }
  298. return null;
  299. }
  300. if (is_null($connection)) {
  301. $connection = $this->getConnection();
  302. if (PEAR::isError($connection)) {
  303. return $connection;
  304. }
  305. }
  306. if (is_null($database_name)) {
  307. $database_name = $this->database_name;
  308. }
  309. if ($database_name) {
  310. if ($database_name != $this->connected_database_name) {
  311. if (!@fbsql_select_db($database_name, $connection)) {
  312. return $this->raiseError();
  313. }
  314. $this->connected_database_name = $database_name;
  315. }
  316. }
  317. $result = @fbsql_query($query, $connection);
  318. if (!$result) {
  319. return $this->raiseError();
  320. }
  321. return $result;
  322. }
  323. // }}}
  324. // {{{ _affectedRows()
  325. /**
  326. * returns the number of rows affected
  327. *
  328. * @param resource $result
  329. * @param resource $connection
  330. * @return mixed MDB2 Error Object or the number of rows affected
  331. * @access private
  332. */
  333. function _affectedRows($connection, $result = null)
  334. {
  335. if (is_null($connection)) {
  336. $connection = $this->getConnection();
  337. if (PEAR::isError($connection)) {
  338. return $connection;
  339. }
  340. }
  341. return @fbsql_affected_rows($connection);
  342. }
  343. // }}}
  344. // {{{ _modifyQuery()
  345. /**
  346. * Changes a query string for various DBMS specific reasons
  347. *
  348. * @param string $query query to modify
  349. * @param boolean $is_manip if it is a DML query
  350. * @param integer $limit limit the number of rows
  351. * @param integer $offset start reading from given offset
  352. * @return string modified query
  353. * @access protected
  354. */
  355. function _modifyQuery($query, $is_manip, $limit, $offset)
  356. {
  357. if ($limit > 0) {
  358. if ($is_manip) {
  359. return preg_replace('/^([\s(])*SELECT(?!\s*TOP\s*\()/i',
  360. "\\1SELECT TOP($limit)", $query);
  361. } else {
  362. return preg_replace('/([\s(])*SELECT(?!\s*TOP\s*\()/i',
  363. "\\1SELECT TOP($offset,$limit)", $query);
  364. }
  365. }
  366. // Add ; to the end of the query. This is required by FrontBase
  367. return $query.';';
  368. }
  369. // }}}
  370. // {{{ nextID()
  371. /**
  372. * returns the next free id of a sequence
  373. *
  374. * @param string $seq_name name of the sequence
  375. * @param boolean $ondemand when true the seqence is
  376. * automatic created, if it
  377. * not exists
  378. *
  379. * @return mixed MDB2 Error Object or id
  380. * @access public
  381. */
  382. function nextID($seq_name, $ondemand = true)
  383. {
  384. $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
  385. $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
  386. $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL);";
  387. $this->expectError(MDB2_ERROR_NOSUCHTABLE);
  388. $result = $this->_doQuery($query, true);
  389. $this->popExpect();
  390. if (PEAR::isError($result)) {
  391. if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
  392. $this->loadModule('Manager', null, true);
  393. // Since we are creating the sequence on demand
  394. // we know the first id = 1 so initialize the
  395. // sequence at 2
  396. $result = $this->manager->createSequence($seq_name, 2);
  397. if (PEAR::isError($result)) {
  398. return $this->raiseError(MDB2_ERROR, null, null,
  399. 'nextID: on demand sequence '.$seq_name.' could not be created');
  400. } else {
  401. // First ID of a newly created sequence is 1
  402. return 1;
  403. }
  404. }
  405. return $result;
  406. }
  407. $value = $this->lastInsertID();
  408. if (is_numeric($value)) {
  409. $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value";
  410. $result = $this->_doQuery($query, true);
  411. if (PEAR::isError($result)) {
  412. $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name;
  413. }
  414. }
  415. return $value;
  416. }
  417. // }}}
  418. // {{{ lastInsertID()
  419. /**
  420. * returns the autoincrement ID if supported or $id
  421. *
  422. * @param mixed $id value as returned by getBeforeId()
  423. * @param string $table name of the table into which a new row was inserted
  424. * @return mixed MDB2 Error Object or id
  425. * @access public
  426. */
  427. function lastInsertID($table = null, $field = null)
  428. {
  429. $connection = $this->getConnection();
  430. if (PEAR::isError($connection)) {
  431. return $connection;
  432. }
  433. $value = @fbsql_insert_id($connection);
  434. if (!$value) {
  435. return $this->raiseError();
  436. }
  437. return $value;
  438. }
  439. // }}}
  440. // {{{ currID()
  441. /**
  442. * returns the current id of a sequence
  443. *
  444. * @param string $seq_name name of the sequence
  445. * @return mixed MDB2 Error Object or id
  446. * @access public
  447. */
  448. function currID($seq_name)
  449. {
  450. $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
  451. $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
  452. $query = "SELECT MAX($seqcol_name) FROM $sequence_name";
  453. return $this->queryOne($query, 'integer');
  454. }
  455. }
  456. class MDB2_Result_fbsql extends MDB2_Result_Common
  457. {
  458. // }}}
  459. // {{{ fetchRow()
  460. /**
  461. * Fetch a row and insert the data into an existing array.
  462. *
  463. * @param int $fetchmode how the array data should be indexed
  464. * @param int $rownum number of the row where the data can be found
  465. * @return int data array on success, a MDB2 error on failure
  466. * @access public
  467. */
  468. function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
  469. {
  470. if (!is_null($rownum)) {
  471. $seek = $this->seek($rownum);
  472. if (PEAR::isError($seek)) {
  473. return $seek;
  474. }
  475. }
  476. if ($fetchmode == MDB2_FETCHMODE_DEFAULT) {
  477. $fetchmode = $this->db->fetchmode;
  478. }
  479. if ($fetchmode & MDB2_FETCHMODE_ASSOC) {
  480. $row = @fbsql_fetch_assoc($this->result);
  481. if (is_array($row)
  482. && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
  483. ) {
  484. $row = array_change_key_case($row, $this->db->options['field_case']);
  485. }
  486. } else {
  487. $row = @fbsql_fetch_row($this->result);
  488. }
  489. if (!$row) {
  490. if ($this->result === false) {
  491. $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  492. 'fetchRow: resultset has already been freed');
  493. return $err;
  494. }
  495. $null = null;
  496. return $null;
  497. }
  498. if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) {
  499. $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_EMPTY_TO_NULL);
  500. }
  501. if (!empty($this->values)) {
  502. $this->_assignBindColumns($row);
  503. }
  504. if (!empty($this->types)) {
  505. $row = $this->db->datatype->convertResultRow($this->types, $row);
  506. }
  507. if ($fetchmode === MDB2_FETCHMODE_OBJECT) {
  508. $object_class = $this->db->options['fetch_class'];
  509. if ($object_class == 'stdClass') {
  510. $row = (object) $row;
  511. } else {
  512. $row = &new $object_class($row);
  513. }
  514. }
  515. ++$this->rownum;
  516. return $row;
  517. }
  518. // }}}
  519. // {{{ _getColumnNames()
  520. /**
  521. * Retrieve the names of columns returned by the DBMS in a query result.
  522. *
  523. * @return mixed an associative array variable
  524. * that will hold the names of columns. The
  525. * indexes of the array are the column names
  526. * mapped to lower case and the values are the
  527. * respective numbers of the columns starting
  528. * from 0. Some DBMS may not return any
  529. * columns when the result set does not
  530. * contain any rows.
  531. *
  532. * a MDB2 error on failure
  533. * @access private
  534. */
  535. function _getColumnNames()
  536. {
  537. $columns = array();
  538. $numcols = $this->numCols();
  539. if (PEAR::isError($numcols)) {
  540. return $numcols;
  541. }
  542. for ($column = 0; $column < $numcols; $column++) {
  543. $column_name = @fbsql_field_name($this->result, $column);
  544. $columns[$column_name] = $column;
  545. }
  546. if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  547. $columns = array_change_key_case($columns, $this->db->options['field_case']);
  548. }
  549. return $columns;
  550. }
  551. // }}}
  552. // {{{ numCols()
  553. /**
  554. * Count the number of columns returned by the DBMS in a query result.
  555. *
  556. * @return mixed integer value with the number of columns, a MDB2 error
  557. * on failure
  558. * @access public
  559. */
  560. function numCols()
  561. {
  562. $cols = @fbsql_num_fields($this->result);
  563. if (is_null($cols)) {
  564. if ($this->result === false) {
  565. return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  566. 'numCols: resultset has already been freed');
  567. } elseif (is_null($this->result)) {
  568. return count($this->types);
  569. }
  570. return $this->db->raiseError();
  571. }
  572. return $cols;
  573. }
  574. // }}}
  575. // {{{ nextResult()
  576. /**
  577. * Move the internal result pointer to the next available result
  578. * Currently not supported
  579. *
  580. * @return true on success, false if there is no more result set or an error object on failure
  581. * @access public
  582. */
  583. function nextResult()
  584. {
  585. if ($this->result === false) {
  586. return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  587. 'nextResult: resultset has already been freed');
  588. } elseif (is_null($this->result)) {
  589. return false;
  590. }
  591. return @fbsql_next_result($this->result);
  592. }
  593. // }}}
  594. // {{{ free()
  595. /**
  596. * Free the internal resources associated with result.
  597. *
  598. * @return boolean true on success, false if result is invalid
  599. * @access public
  600. */
  601. function free()
  602. {
  603. $free = @fbsql_free_result($this->result);
  604. if (!$free) {
  605. if (!$this->result) {
  606. return MDB2_OK;
  607. }
  608. return $this->db->raiseError();
  609. }
  610. $this->result = false;
  611. return MDB2_OK;
  612. }
  613. }
  614. class MDB2_BufferedResult_fbsql extends MDB2_Result_fbsql
  615. {
  616. // }}}
  617. // {{{ seek()
  618. /**
  619. * seek to a specific row in a result set
  620. *
  621. * @param int $rownum number of the row where the data can be found
  622. * @return mixed MDB2_OK on success, a MDB2 error on failure
  623. * @access public
  624. */
  625. function seek($rownum = 0)
  626. {
  627. if ($this->rownum != ($rownum - 1) && !@fbsql_data_seek($this->result, $rownum)) {
  628. if ($this->result === false) {
  629. return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  630. 'seek: resultset has already been freed');
  631. } elseif (is_null($this->result)) {
  632. return MDB2_OK;
  633. }
  634. return $this->db->raiseError(MDB2_ERROR_INVALID, null, null,
  635. 'seek: tried to seek to an invalid row number ('.$rownum.')');
  636. }
  637. $this->rownum = $rownum - 1;
  638. return MDB2_OK;
  639. }
  640. // }}}
  641. // {{{ valid()
  642. /**
  643. * check if the end of the result set has been reached
  644. *
  645. * @return mixed true or false on sucess, a MDB2 error on failure
  646. * @access public
  647. */
  648. function valid()
  649. {
  650. $numrows = $this->numRows();
  651. if (PEAR::isError($numrows)) {
  652. return $numrows;
  653. }
  654. return $this->rownum < ($numrows - 1);
  655. }
  656. // }}}
  657. // {{{ numRows()
  658. /**
  659. * returns the number of rows in a result object
  660. *
  661. * @return mixed MDB2 Error Object or the number of rows
  662. * @access public
  663. */
  664. function numRows()
  665. {
  666. $rows = @fbsql_num_rows($this->result);
  667. if (is_null($rows)) {
  668. if ($this->result === false) {
  669. return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  670. 'numRows: resultset has already been freed');
  671. } elseif (is_null($this->result)) {
  672. return 0;
  673. }
  674. return $this->db->raiseError();
  675. }
  676. return $rows;
  677. }
  678. }
  679. class MDB2_Statement_fbsql extends MDB2_Statement_Common
  680. {
  681. }
  682. ?>