PageRenderTime 184ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/php/DB/ibase.php

https://bitbucket.org/adarshj/convenient_website
PHP | 1071 lines | 508 code | 95 blank | 468 comment | 72 complexity | 2737eb9b3a5fbb7f48d35d203118b1e4 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-2-Clause, GPL-2.0, LGPL-3.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * The PEAR DB driver for PHP's interbase extension
  5. * for interacting with Interbase and Firebird databases
  6. *
  7. * While this class works with PHP 4, PHP's InterBase extension is
  8. * unstable in PHP 4. Use PHP 5.
  9. *
  10. * PHP versions 4 and 5
  11. *
  12. * LICENSE: This source file is subject to version 3.0 of the PHP license
  13. * that is available through the world-wide-web at the following URI:
  14. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  15. * the PHP License and are unable to obtain it through the web, please
  16. * send a note to license@php.net so we can mail you a copy immediately.
  17. *
  18. * @category Database
  19. * @package DB
  20. * @author Sterling Hughes <sterling@php.net>
  21. * @author Daniel Convissor <danielc@php.net>
  22. * @copyright 1997-2005 The PHP Group
  23. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  24. * @version CVS: $Id: ibase.php,v 1.109 2005/03/04 23:12:36 danielc Exp $
  25. * @link http://pear.php.net/package/DB
  26. */
  27. /**
  28. * Obtain the DB_common class so it can be extended from
  29. */
  30. require_once 'DB/common.php';
  31. /**
  32. * The methods PEAR DB uses to interact with PHP's interbase extension
  33. * for interacting with Interbase and Firebird databases
  34. *
  35. * These methods overload the ones declared in DB_common.
  36. *
  37. * While this class works with PHP 4, PHP's InterBase extension is
  38. * unstable in PHP 4. Use PHP 5.
  39. *
  40. * NOTICE: limitQuery() only works for Firebird.
  41. *
  42. * @category Database
  43. * @package DB
  44. * @author Sterling Hughes <sterling@php.net>
  45. * @author Daniel Convissor <danielc@php.net>
  46. * @copyright 1997-2005 The PHP Group
  47. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  48. * @version Release: 1.7.6
  49. * @link http://pear.php.net/package/DB
  50. * @since Class became stable in Release 1.7.0
  51. */
  52. class DB_ibase extends DB_common
  53. {
  54. // {{{ properties
  55. /**
  56. * The DB driver type (mysql, oci8, odbc, etc.)
  57. * @var string
  58. */
  59. var $phptype = 'ibase';
  60. /**
  61. * The database syntax variant to be used (db2, access, etc.), if any
  62. * @var string
  63. */
  64. var $dbsyntax = 'ibase';
  65. /**
  66. * The capabilities of this DB implementation
  67. *
  68. * The 'new_link' element contains the PHP version that first provided
  69. * new_link support for this DBMS. Contains false if it's unsupported.
  70. *
  71. * Meaning of the 'limit' element:
  72. * + 'emulate' = emulate with fetch row by number
  73. * + 'alter' = alter the query
  74. * + false = skip rows
  75. *
  76. * NOTE: only firebird supports limit.
  77. *
  78. * @var array
  79. */
  80. var $features = array(
  81. 'limit' => false,
  82. 'new_link' => false,
  83. 'numrows' => 'emulate',
  84. 'pconnect' => true,
  85. 'prepare' => true,
  86. 'ssl' => false,
  87. 'transactions' => true,
  88. );
  89. /**
  90. * A mapping of native error codes to DB error codes
  91. * @var array
  92. */
  93. var $errorcode_map = array(
  94. -104 => DB_ERROR_SYNTAX,
  95. -150 => DB_ERROR_ACCESS_VIOLATION,
  96. -151 => DB_ERROR_ACCESS_VIOLATION,
  97. -155 => DB_ERROR_NOSUCHTABLE,
  98. -157 => DB_ERROR_NOSUCHFIELD,
  99. -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
  100. -170 => DB_ERROR_MISMATCH,
  101. -171 => DB_ERROR_MISMATCH,
  102. -172 => DB_ERROR_INVALID,
  103. // -204 => // Covers too many errors, need to use regex on msg
  104. -205 => DB_ERROR_NOSUCHFIELD,
  105. -206 => DB_ERROR_NOSUCHFIELD,
  106. -208 => DB_ERROR_INVALID,
  107. -219 => DB_ERROR_NOSUCHTABLE,
  108. -297 => DB_ERROR_CONSTRAINT,
  109. -303 => DB_ERROR_INVALID,
  110. -413 => DB_ERROR_INVALID_NUMBER,
  111. -530 => DB_ERROR_CONSTRAINT,
  112. -551 => DB_ERROR_ACCESS_VIOLATION,
  113. -552 => DB_ERROR_ACCESS_VIOLATION,
  114. // -607 => // Covers too many errors, need to use regex on msg
  115. -625 => DB_ERROR_CONSTRAINT_NOT_NULL,
  116. -803 => DB_ERROR_CONSTRAINT,
  117. -804 => DB_ERROR_VALUE_COUNT_ON_ROW,
  118. -904 => DB_ERROR_CONNECT_FAILED,
  119. -922 => DB_ERROR_NOSUCHDB,
  120. -923 => DB_ERROR_CONNECT_FAILED,
  121. -924 => DB_ERROR_CONNECT_FAILED
  122. );
  123. /**
  124. * The raw database connection created by PHP
  125. * @var resource
  126. */
  127. var $connection;
  128. /**
  129. * The DSN information for connecting to a database
  130. * @var array
  131. */
  132. var $dsn = array();
  133. /**
  134. * The number of rows affected by a data manipulation query
  135. * @var integer
  136. * @access private
  137. */
  138. var $affected = 0;
  139. /**
  140. * Should data manipulation queries be committed automatically?
  141. * @var bool
  142. * @access private
  143. */
  144. var $autocommit = true;
  145. /**
  146. * The prepared statement handle from the most recently executed statement
  147. *
  148. * {@internal Mainly here because the InterBase/Firebird API is only
  149. * able to retrieve data from result sets if the statemnt handle is
  150. * still in scope.}}
  151. *
  152. * @var resource
  153. */
  154. var $last_stmt;
  155. /**
  156. * Is the given prepared statement a data manipulation query?
  157. * @var array
  158. * @access private
  159. */
  160. var $manip_query = array();
  161. // }}}
  162. // {{{ constructor
  163. /**
  164. * This constructor calls <kbd>$this->DB_common()</kbd>
  165. *
  166. * @return void
  167. */
  168. function DB_ibase()
  169. {
  170. $this->DB_common();
  171. }
  172. // }}}
  173. // {{{ connect()
  174. /**
  175. * Connect to the database server, log in and open the database
  176. *
  177. * Don't call this method directly. Use DB::connect() instead.
  178. *
  179. * PEAR DB's ibase driver supports the following extra DSN options:
  180. * + buffers The number of database buffers to allocate for the
  181. * server-side cache.
  182. * + charset The default character set for a database.
  183. * + dialect The default SQL dialect for any statement
  184. * executed within a connection. Defaults to the
  185. * highest one supported by client libraries.
  186. * Functional only with InterBase 6 and up.
  187. * + role Functional only with InterBase 5 and up.
  188. *
  189. * @param array $dsn the data source name
  190. * @param bool $persistent should the connection be persistent?
  191. *
  192. * @return int DB_OK on success. A DB_Error object on failure.
  193. */
  194. function connect($dsn, $persistent = false)
  195. {
  196. if (!PEAR::loadExtension('interbase')) {
  197. return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  198. }
  199. $this->dsn = $dsn;
  200. if ($dsn['dbsyntax']) {
  201. $this->dbsyntax = $dsn['dbsyntax'];
  202. }
  203. if ($this->dbsyntax == 'firebird') {
  204. $this->features['limit'] = 'alter';
  205. }
  206. $params = array(
  207. $dsn['hostspec']
  208. ? ($dsn['hostspec'] . ':' . $dsn['database'])
  209. : $dsn['database'],
  210. $dsn['username'] ? $dsn['username'] : null,
  211. $dsn['password'] ? $dsn['password'] : null,
  212. isset($dsn['charset']) ? $dsn['charset'] : null,
  213. isset($dsn['buffers']) ? $dsn['buffers'] : null,
  214. isset($dsn['dialect']) ? $dsn['dialect'] : null,
  215. isset($dsn['role']) ? $dsn['role'] : null,
  216. );
  217. $connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect';
  218. $this->connection = @call_user_func_array($connect_function, $params);
  219. if (!$this->connection) {
  220. return $this->ibaseRaiseError(DB_ERROR_CONNECT_FAILED);
  221. }
  222. return DB_OK;
  223. }
  224. // }}}
  225. // {{{ disconnect()
  226. /**
  227. * Disconnects from the database server
  228. *
  229. * @return bool TRUE on success, FALSE on failure
  230. */
  231. function disconnect()
  232. {
  233. $ret = @ibase_close($this->connection);
  234. $this->connection = null;
  235. return $ret;
  236. }
  237. // }}}
  238. // {{{ simpleQuery()
  239. /**
  240. * Sends a query to the database server
  241. *
  242. * @param string the SQL query string
  243. *
  244. * @return mixed + a PHP result resrouce for successful SELECT queries
  245. * + the DB_OK constant for other successful queries
  246. * + a DB_Error object on failure
  247. */
  248. function simpleQuery($query)
  249. {
  250. $ismanip = DB::isManip($query);
  251. $this->last_query = $query;
  252. $query = $this->modifyQuery($query);
  253. $result = @ibase_query($this->connection, $query);
  254. if (!$result) {
  255. return $this->ibaseRaiseError();
  256. }
  257. if ($this->autocommit && $ismanip) {
  258. @ibase_commit($this->connection);
  259. }
  260. if ($ismanip) {
  261. $this->affected = $result;
  262. return DB_OK;
  263. } else {
  264. $this->affected = 0;
  265. return $result;
  266. }
  267. }
  268. // }}}
  269. // {{{ modifyLimitQuery()
  270. /**
  271. * Adds LIMIT clauses to a query string according to current DBMS standards
  272. *
  273. * Only works with Firebird.
  274. *
  275. * @param string $query the query to modify
  276. * @param int $from the row to start to fetching (0 = the first row)
  277. * @param int $count the numbers of rows to fetch
  278. * @param mixed $params array, string or numeric data to be used in
  279. * execution of the statement. Quantity of items
  280. * passed must match quantity of placeholders in
  281. * query: meaning 1 placeholder for non-array
  282. * parameters or 1 placeholder per array element.
  283. *
  284. * @return string the query string with LIMIT clauses added
  285. *
  286. * @access protected
  287. */
  288. function modifyLimitQuery($query, $from, $count, $params = array())
  289. {
  290. if ($this->dsn['dbsyntax'] == 'firebird') {
  291. $query = preg_replace('/^([\s(])*SELECT/i',
  292. "SELECT FIRST $count SKIP $from", $query);
  293. }
  294. return $query;
  295. }
  296. // }}}
  297. // {{{ nextResult()
  298. /**
  299. * Move the internal ibase result pointer to the next available result
  300. *
  301. * @param a valid fbsql result resource
  302. *
  303. * @access public
  304. *
  305. * @return true if a result is available otherwise return false
  306. */
  307. function nextResult($result)
  308. {
  309. return false;
  310. }
  311. // }}}
  312. // {{{ fetchInto()
  313. /**
  314. * Places a row from the result set into the given array
  315. *
  316. * Formating of the array and the data therein are configurable.
  317. * See DB_result::fetchInto() for more information.
  318. *
  319. * This method is not meant to be called directly. Use
  320. * DB_result::fetchInto() instead. It can't be declared "protected"
  321. * because DB_result is a separate object.
  322. *
  323. * @param resource $result the query result resource
  324. * @param array $arr the referenced array to put the data in
  325. * @param int $fetchmode how the resulting array should be indexed
  326. * @param int $rownum the row number to fetch (0 = first row)
  327. *
  328. * @return mixed DB_OK on success, NULL when the end of a result set is
  329. * reached or on failure
  330. *
  331. * @see DB_result::fetchInto()
  332. */
  333. function fetchInto($result, &$arr, $fetchmode, $rownum = null)
  334. {
  335. if ($rownum !== null) {
  336. return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
  337. }
  338. if ($fetchmode & DB_FETCHMODE_ASSOC) {
  339. if (function_exists('ibase_fetch_assoc')) {
  340. $arr = @ibase_fetch_assoc($result);
  341. } else {
  342. $arr = get_object_vars(ibase_fetch_object($result));
  343. }
  344. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  345. $arr = array_change_key_case($arr, CASE_LOWER);
  346. }
  347. } else {
  348. $arr = @ibase_fetch_row($result);
  349. }
  350. if (!$arr) {
  351. return null;
  352. }
  353. if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  354. $this->_rtrimArrayValues($arr);
  355. }
  356. if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  357. $this->_convertNullArrayValuesToEmpty($arr);
  358. }
  359. return DB_OK;
  360. }
  361. // }}}
  362. // {{{ freeResult()
  363. /**
  364. * Deletes the result set and frees the memory occupied by the result set
  365. *
  366. * This method is not meant to be called directly. Use
  367. * DB_result::free() instead. It can't be declared "protected"
  368. * because DB_result is a separate object.
  369. *
  370. * @param resource $result PHP's query result resource
  371. *
  372. * @return bool TRUE on success, FALSE if $result is invalid
  373. *
  374. * @see DB_result::free()
  375. */
  376. function freeResult($result)
  377. {
  378. return @ibase_free_result($result);
  379. }
  380. // }}}
  381. // {{{ freeQuery()
  382. function freeQuery($query)
  383. {
  384. @ibase_free_query($query);
  385. return true;
  386. }
  387. // }}}
  388. // {{{ affectedRows()
  389. /**
  390. * Determines the number of rows affected by a data maniuplation query
  391. *
  392. * 0 is returned for queries that don't manipulate data.
  393. *
  394. * @return int the number of rows. A DB_Error object on failure.
  395. */
  396. function affectedRows()
  397. {
  398. if (is_integer($this->affected)) {
  399. return $this->affected;
  400. }
  401. return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
  402. }
  403. // }}}
  404. // {{{ numCols()
  405. /**
  406. * Gets the number of columns in a result set
  407. *
  408. * This method is not meant to be called directly. Use
  409. * DB_result::numCols() instead. It can't be declared "protected"
  410. * because DB_result is a separate object.
  411. *
  412. * @param resource $result PHP's query result resource
  413. *
  414. * @return int the number of columns. A DB_Error object on failure.
  415. *
  416. * @see DB_result::numCols()
  417. */
  418. function numCols($result)
  419. {
  420. $cols = @ibase_num_fields($result);
  421. if (!$cols) {
  422. return $this->ibaseRaiseError();
  423. }
  424. return $cols;
  425. }
  426. // }}}
  427. // {{{ prepare()
  428. /**
  429. * Prepares a query for multiple execution with execute().
  430. *
  431. * prepare() requires a generic query as string like <code>
  432. * INSERT INTO numbers VALUES (?, ?, ?)
  433. * </code>. The <kbd>?</kbd> characters are placeholders.
  434. *
  435. * Three types of placeholders can be used:
  436. * + <kbd>?</kbd> a quoted scalar value, i.e. strings, integers
  437. * + <kbd>!</kbd> value is inserted 'as is'
  438. * + <kbd>&</kbd> requires a file name. The file's contents get
  439. * inserted into the query (i.e. saving binary
  440. * data in a db)
  441. *
  442. * Use backslashes to escape placeholder characters if you don't want
  443. * them to be interpreted as placeholders. Example: <code>
  444. * "UPDATE foo SET col=? WHERE col='over \& under'"
  445. * </code>
  446. *
  447. * @param string $query query to be prepared
  448. * @return mixed DB statement resource on success. DB_Error on failure.
  449. */
  450. function prepare($query)
  451. {
  452. $tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1,
  453. PREG_SPLIT_DELIM_CAPTURE);
  454. $token = 0;
  455. $types = array();
  456. $newquery = '';
  457. foreach ($tokens as $key => $val) {
  458. switch ($val) {
  459. case '?':
  460. $types[$token++] = DB_PARAM_SCALAR;
  461. break;
  462. case '&':
  463. $types[$token++] = DB_PARAM_OPAQUE;
  464. break;
  465. case '!':
  466. $types[$token++] = DB_PARAM_MISC;
  467. break;
  468. default:
  469. $tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val);
  470. $newquery .= $tokens[$key] . '?';
  471. }
  472. }
  473. $newquery = substr($newquery, 0, -1);
  474. $this->last_query = $query;
  475. $newquery = $this->modifyQuery($newquery);
  476. $stmt = @ibase_prepare($this->connection, $newquery);
  477. $this->prepare_types[(int)$stmt] = $types;
  478. $this->manip_query[(int)$stmt] = DB::isManip($query);
  479. return $stmt;
  480. }
  481. // }}}
  482. // {{{ execute()
  483. /**
  484. * Executes a DB statement prepared with prepare().
  485. *
  486. * @param resource $stmt a DB statement resource returned from prepare()
  487. * @param mixed $data array, string or numeric data to be used in
  488. * execution of the statement. Quantity of items
  489. * passed must match quantity of placeholders in
  490. * query: meaning 1 for non-array items or the
  491. * quantity of elements in the array.
  492. * @return object a new DB_Result or a DB_Error when fail
  493. * @see DB_ibase::prepare()
  494. * @access public
  495. */
  496. function &execute($stmt, $data = array())
  497. {
  498. $data = (array)$data;
  499. $this->last_parameters = $data;
  500. $types =& $this->prepare_types[(int)$stmt];
  501. if (count($types) != count($data)) {
  502. $tmp =& $this->raiseError(DB_ERROR_MISMATCH);
  503. return $tmp;
  504. }
  505. $i = 0;
  506. foreach ($data as $key => $value) {
  507. if ($types[$i] == DB_PARAM_MISC) {
  508. /*
  509. * ibase doesn't seem to have the ability to pass a
  510. * parameter along unchanged, so strip off quotes from start
  511. * and end, plus turn two single quotes to one single quote,
  512. * in order to avoid the quotes getting escaped by
  513. * ibase and ending up in the database.
  514. */
  515. $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]);
  516. $data[$key] = str_replace("''", "'", $data[$key]);
  517. } elseif ($types[$i] == DB_PARAM_OPAQUE) {
  518. $fp = @fopen($data[$key], 'rb');
  519. if (!$fp) {
  520. $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  521. return $tmp;
  522. }
  523. $data[$key] = fread($fp, filesize($data[$key]));
  524. fclose($fp);
  525. }
  526. $i++;
  527. }
  528. array_unshift($data, $stmt);
  529. $res = call_user_func_array('ibase_execute', $data);
  530. if (!$res) {
  531. $tmp =& $this->ibaseRaiseError();
  532. return $tmp;
  533. }
  534. /* XXX need this?
  535. if ($this->autocommit && $this->manip_query[(int)$stmt]) {
  536. @ibase_commit($this->connection);
  537. }*/
  538. $this->last_stmt = $stmt;
  539. if ($this->manip_query[(int)$stmt]) {
  540. $tmp = DB_OK;
  541. } else {
  542. $tmp =& new DB_result($this, $res);
  543. }
  544. return $tmp;
  545. }
  546. /**
  547. * Frees the internal resources associated with a prepared query
  548. *
  549. * @param resource $stmt the prepared statement's PHP resource
  550. * @param bool $free_resource should the PHP resource be freed too?
  551. * Use false if you need to get data
  552. * from the result set later.
  553. *
  554. * @return bool TRUE on success, FALSE if $result is invalid
  555. *
  556. * @see DB_ibase::prepare()
  557. */
  558. function freePrepared($stmt, $free_resource = true)
  559. {
  560. if (!is_resource($stmt)) {
  561. return false;
  562. }
  563. if ($free_resource) {
  564. @ibase_free_query($stmt);
  565. }
  566. unset($this->prepare_tokens[(int)$stmt]);
  567. unset($this->prepare_types[(int)$stmt]);
  568. unset($this->manip_query[(int)$stmt]);
  569. return true;
  570. }
  571. // }}}
  572. // {{{ autoCommit()
  573. /**
  574. * Enables or disables automatic commits
  575. *
  576. * @param bool $onoff true turns it on, false turns it off
  577. *
  578. * @return int DB_OK on success. A DB_Error object if the driver
  579. * doesn't support auto-committing transactions.
  580. */
  581. function autoCommit($onoff = false)
  582. {
  583. $this->autocommit = $onoff ? 1 : 0;
  584. return DB_OK;
  585. }
  586. // }}}
  587. // {{{ commit()
  588. /**
  589. * Commits the current transaction
  590. *
  591. * @return int DB_OK on success. A DB_Error object on failure.
  592. */
  593. function commit()
  594. {
  595. return @ibase_commit($this->connection);
  596. }
  597. // }}}
  598. // {{{ rollback()
  599. /**
  600. * Reverts the current transaction
  601. *
  602. * @return int DB_OK on success. A DB_Error object on failure.
  603. */
  604. function rollback()
  605. {
  606. return @ibase_rollback($this->connection);
  607. }
  608. // }}}
  609. // {{{ transactionInit()
  610. function transactionInit($trans_args = 0)
  611. {
  612. return $trans_args
  613. ? @ibase_trans($trans_args, $this->connection)
  614. : @ibase_trans();
  615. }
  616. // }}}
  617. // {{{ nextId()
  618. /**
  619. * Returns the next free id in a sequence
  620. *
  621. * @param string $seq_name name of the sequence
  622. * @param boolean $ondemand when true, the seqence is automatically
  623. * created if it does not exist
  624. *
  625. * @return int the next id number in the sequence.
  626. * A DB_Error object on failure.
  627. *
  628. * @see DB_common::nextID(), DB_common::getSequenceName(),
  629. * DB_ibase::createSequence(), DB_ibase::dropSequence()
  630. */
  631. function nextId($seq_name, $ondemand = true)
  632. {
  633. $sqn = strtoupper($this->getSequenceName($seq_name));
  634. $repeat = 0;
  635. do {
  636. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  637. $result =& $this->query("SELECT GEN_ID(${sqn}, 1) "
  638. . 'FROM RDB$GENERATORS '
  639. . "WHERE RDB\$GENERATOR_NAME='${sqn}'");
  640. $this->popErrorHandling();
  641. if ($ondemand && DB::isError($result)) {
  642. $repeat = 1;
  643. $result = $this->createSequence($seq_name);
  644. if (DB::isError($result)) {
  645. return $result;
  646. }
  647. } else {
  648. $repeat = 0;
  649. }
  650. } while ($repeat);
  651. if (DB::isError($result)) {
  652. return $this->raiseError($result);
  653. }
  654. $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
  655. $result->free();
  656. return $arr[0];
  657. }
  658. // }}}
  659. // {{{ createSequence()
  660. /**
  661. * Creates a new sequence
  662. *
  663. * @param string $seq_name name of the new sequence
  664. *
  665. * @return int DB_OK on success. A DB_Error object on failure.
  666. *
  667. * @see DB_common::createSequence(), DB_common::getSequenceName(),
  668. * DB_ibase::nextID(), DB_ibase::dropSequence()
  669. */
  670. function createSequence($seq_name)
  671. {
  672. $sqn = strtoupper($this->getSequenceName($seq_name));
  673. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  674. $result = $this->query("CREATE GENERATOR ${sqn}");
  675. $this->popErrorHandling();
  676. return $result;
  677. }
  678. // }}}
  679. // {{{ dropSequence()
  680. /**
  681. * Deletes a sequence
  682. *
  683. * @param string $seq_name name of the sequence to be deleted
  684. *
  685. * @return int DB_OK on success. A DB_Error object on failure.
  686. *
  687. * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  688. * DB_ibase::nextID(), DB_ibase::createSequence()
  689. */
  690. function dropSequence($seq_name)
  691. {
  692. return $this->query('DELETE FROM RDB$GENERATORS '
  693. . "WHERE RDB\$GENERATOR_NAME='"
  694. . strtoupper($this->getSequenceName($seq_name))
  695. . "'");
  696. }
  697. // }}}
  698. // {{{ _ibaseFieldFlags()
  699. /**
  700. * Get the column's flags
  701. *
  702. * Supports "primary_key", "unique_key", "not_null", "default",
  703. * "computed" and "blob".
  704. *
  705. * @param string $field_name the name of the field
  706. * @param string $table_name the name of the table
  707. *
  708. * @return string the flags
  709. *
  710. * @access private
  711. */
  712. function _ibaseFieldFlags($field_name, $table_name)
  713. {
  714. $sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'
  715. .' FROM RDB$INDEX_SEGMENTS I'
  716. .' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
  717. .' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\''
  718. .' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'';
  719. $result = @ibase_query($this->connection, $sql);
  720. if (!$result) {
  721. return $this->ibaseRaiseError();
  722. }
  723. $flags = '';
  724. if ($obj = @ibase_fetch_object($result)) {
  725. @ibase_free_result($result);
  726. if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') {
  727. $flags .= 'primary_key ';
  728. }
  729. if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') {
  730. $flags .= 'unique_key ';
  731. }
  732. }
  733. $sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,'
  734. .' R.RDB$DEFAULT_SOURCE AS DSOURCE,'
  735. .' F.RDB$FIELD_TYPE AS FTYPE,'
  736. .' F.RDB$COMPUTED_SOURCE AS CSOURCE'
  737. .' FROM RDB$RELATION_FIELDS R '
  738. .' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
  739. .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''
  740. .' AND R.RDB$FIELD_NAME=\'' . $field_name . '\'';
  741. $result = @ibase_query($this->connection, $sql);
  742. if (!$result) {
  743. return $this->ibaseRaiseError();
  744. }
  745. if ($obj = @ibase_fetch_object($result)) {
  746. @ibase_free_result($result);
  747. if (isset($obj->NFLAG)) {
  748. $flags .= 'not_null ';
  749. }
  750. if (isset($obj->DSOURCE)) {
  751. $flags .= 'default ';
  752. }
  753. if (isset($obj->CSOURCE)) {
  754. $flags .= 'computed ';
  755. }
  756. if (isset($obj->FTYPE) && $obj->FTYPE == 261) {
  757. $flags .= 'blob ';
  758. }
  759. }
  760. return trim($flags);
  761. }
  762. // }}}
  763. // {{{ ibaseRaiseError()
  764. /**
  765. * Produces a DB_Error object regarding the current problem
  766. *
  767. * @param int $errno if the error is being manually raised pass a
  768. * DB_ERROR* constant here. If this isn't passed
  769. * the error information gathered from the DBMS.
  770. *
  771. * @return object the DB_Error object
  772. *
  773. * @see DB_common::raiseError(),
  774. * DB_ibase::errorNative(), DB_ibase::errorCode()
  775. */
  776. function &ibaseRaiseError($errno = null)
  777. {
  778. if ($errno === null) {
  779. $errno = $this->errorCode($this->errorNative());
  780. }
  781. $tmp =& $this->raiseError($errno, null, null, null, @ibase_errmsg());
  782. return $tmp;
  783. }
  784. // }}}
  785. // {{{ errorNative()
  786. /**
  787. * Gets the DBMS' native error code produced by the last query
  788. *
  789. * @return int the DBMS' error code. NULL if there is no error code.
  790. *
  791. * @since Method available since Release 1.7.0
  792. */
  793. function errorNative()
  794. {
  795. if (function_exists('ibase_errcode')) {
  796. return @ibase_errcode();
  797. }
  798. if (preg_match('/^Dynamic SQL Error SQL error code = ([0-9-]+)/i',
  799. @ibase_errmsg(), $m)) {
  800. return (int)$m[1];
  801. }
  802. return null;
  803. }
  804. // }}}
  805. // {{{ errorCode()
  806. /**
  807. * Maps native error codes to DB's portable ones
  808. *
  809. * @param int $nativecode the error code returned by the DBMS
  810. *
  811. * @return int the portable DB error code. Return DB_ERROR if the
  812. * current driver doesn't have a mapping for the
  813. * $nativecode submitted.
  814. *
  815. * @since Method available since Release 1.7.0
  816. */
  817. function errorCode($nativecode = null)
  818. {
  819. if (isset($this->errorcode_map[$nativecode])) {
  820. return $this->errorcode_map[$nativecode];
  821. }
  822. static $error_regexps;
  823. if (!isset($error_regexps)) {
  824. $error_regexps = array(
  825. '/generator .* is not defined/'
  826. => DB_ERROR_SYNTAX, // for compat. w ibase_errcode()
  827. '/table.*(not exist|not found|unknown)/i'
  828. => DB_ERROR_NOSUCHTABLE,
  829. '/table .* already exists/i'
  830. => DB_ERROR_ALREADY_EXISTS,
  831. '/unsuccessful metadata update .* failed attempt to store duplicate value/i'
  832. => DB_ERROR_ALREADY_EXISTS,
  833. '/unsuccessful metadata update .* not found/i'
  834. => DB_ERROR_NOT_FOUND,
  835. '/validation error for column .* value "\*\*\* null/i'
  836. => DB_ERROR_CONSTRAINT_NOT_NULL,
  837. '/violation of [\w ]+ constraint/i'
  838. => DB_ERROR_CONSTRAINT,
  839. '/conversion error from string/i'
  840. => DB_ERROR_INVALID_NUMBER,
  841. '/no permission for/i'
  842. => DB_ERROR_ACCESS_VIOLATION,
  843. '/arithmetic exception, numeric overflow, or string truncation/i'
  844. => DB_ERROR_INVALID,
  845. );
  846. }
  847. $errormsg = @ibase_errmsg();
  848. foreach ($error_regexps as $regexp => $code) {
  849. if (preg_match($regexp, $errormsg)) {
  850. return $code;
  851. }
  852. }
  853. return DB_ERROR;
  854. }
  855. // }}}
  856. // {{{ tableInfo()
  857. /**
  858. * Returns information about a table or a result set
  859. *
  860. * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  861. * is a table name.
  862. *
  863. * @param object|string $result DB_result object from a query or a
  864. * string containing the name of a table.
  865. * While this also accepts a query result
  866. * resource identifier, this behavior is
  867. * deprecated.
  868. * @param int $mode a valid tableInfo mode
  869. *
  870. * @return array an associative array with the information requested.
  871. * A DB_Error object on failure.
  872. *
  873. * @see DB_common::tableInfo()
  874. */
  875. function tableInfo($result, $mode = null)
  876. {
  877. if (is_string($result)) {
  878. /*
  879. * Probably received a table name.
  880. * Create a result resource identifier.
  881. */
  882. $id = @ibase_query($this->connection,
  883. "SELECT * FROM $result WHERE 1=0");
  884. $got_string = true;
  885. } elseif (isset($result->result)) {
  886. /*
  887. * Probably received a result object.
  888. * Extract the result resource identifier.
  889. */
  890. $id = $result->result;
  891. $got_string = false;
  892. } else {
  893. /*
  894. * Probably received a result resource identifier.
  895. * Copy it.
  896. * Deprecated. Here for compatibility only.
  897. */
  898. $id = $result;
  899. $got_string = false;
  900. }
  901. if (!is_resource($id)) {
  902. return $this->ibaseRaiseError(DB_ERROR_NEED_MORE_DATA);
  903. }
  904. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  905. $case_func = 'strtolower';
  906. } else {
  907. $case_func = 'strval';
  908. }
  909. $count = @ibase_num_fields($id);
  910. $res = array();
  911. if ($mode) {
  912. $res['num_fields'] = $count;
  913. }
  914. for ($i = 0; $i < $count; $i++) {
  915. $info = @ibase_field_info($id, $i);
  916. $res[$i] = array(
  917. 'table' => $got_string ? $case_func($result) : '',
  918. 'name' => $case_func($info['name']),
  919. 'type' => $info['type'],
  920. 'len' => $info['length'],
  921. 'flags' => ($got_string)
  922. ? $this->_ibaseFieldFlags($info['name'], $result)
  923. : '',
  924. );
  925. if ($mode & DB_TABLEINFO_ORDER) {
  926. $res['order'][$res[$i]['name']] = $i;
  927. }
  928. if ($mode & DB_TABLEINFO_ORDERTABLE) {
  929. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  930. }
  931. }
  932. // free the result only if we were called on a table
  933. if ($got_string) {
  934. @ibase_free_result($id);
  935. }
  936. return $res;
  937. }
  938. // }}}
  939. // {{{ getSpecialQuery()
  940. /**
  941. * Obtains the query string needed for listing a given type of objects
  942. *
  943. * @param string $type the kind of objects you want to retrieve
  944. *
  945. * @return string the SQL query string or null if the driver doesn't
  946. * support the object type requested
  947. *
  948. * @access protected
  949. * @see DB_common::getListOf()
  950. */
  951. function getSpecialQuery($type)
  952. {
  953. switch ($type) {
  954. case 'tables':
  955. return 'SELECT DISTINCT R.RDB$RELATION_NAME FROM '
  956. . 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0';
  957. case 'views':
  958. return 'SELECT DISTINCT RDB$VIEW_NAME from RDB$VIEW_RELATIONS';
  959. case 'users':
  960. return 'SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES';
  961. default:
  962. return null;
  963. }
  964. }
  965. // }}}
  966. }
  967. /*
  968. * Local variables:
  969. * tab-width: 4
  970. * c-basic-offset: 4
  971. * End:
  972. */
  973. ?>