PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/php/DB/ifx.php

https://bitbucket.org/adarshj/convenient_website
PHP | 681 lines | 298 code | 60 blank | 323 comment | 37 complexity | 18a3c8f4dc84e0275bb27c6ae261dbd9 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 ifx extension
  5. * for interacting with Informix databases
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * LICENSE: This source file is subject to version 3.0 of the PHP license
  10. * that is available through the world-wide-web at the following URI:
  11. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  12. * the PHP License and are unable to obtain it through the web, please
  13. * send a note to license@php.net so we can mail you a copy immediately.
  14. *
  15. * @category Database
  16. * @package DB
  17. * @author Tomas V.V.Cox <cox@idecnet.com>
  18. * @author Daniel Convissor <danielc@php.net>
  19. * @copyright 1997-2005 The PHP Group
  20. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  21. * @version CVS: $Id: ifx.php,v 1.70 2005/02/20 00:44:48 danielc Exp $
  22. * @link http://pear.php.net/package/DB
  23. */
  24. /**
  25. * Obtain the DB_common class so it can be extended from
  26. */
  27. require_once 'DB/common.php';
  28. /**
  29. * The methods PEAR DB uses to interact with PHP's ifx extension
  30. * for interacting with Informix databases
  31. *
  32. * These methods overload the ones declared in DB_common.
  33. *
  34. * More info on Informix errors can be found at:
  35. * http://www.informix.com/answers/english/ierrors.htm
  36. *
  37. * TODO:
  38. * - set needed env Informix vars on connect
  39. * - implement native prepare/execute
  40. *
  41. * @category Database
  42. * @package DB
  43. * @author Tomas V.V.Cox <cox@idecnet.com>
  44. * @author Daniel Convissor <danielc@php.net>
  45. * @copyright 1997-2005 The PHP Group
  46. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  47. * @version Release: 1.7.6
  48. * @link http://pear.php.net/package/DB
  49. */
  50. class DB_ifx extends DB_common
  51. {
  52. // {{{ properties
  53. /**
  54. * The DB driver type (mysql, oci8, odbc, etc.)
  55. * @var string
  56. */
  57. var $phptype = 'ifx';
  58. /**
  59. * The database syntax variant to be used (db2, access, etc.), if any
  60. * @var string
  61. */
  62. var $dbsyntax = 'ifx';
  63. /**
  64. * The capabilities of this DB implementation
  65. *
  66. * The 'new_link' element contains the PHP version that first provided
  67. * new_link support for this DBMS. Contains false if it's unsupported.
  68. *
  69. * Meaning of the 'limit' element:
  70. * + 'emulate' = emulate with fetch row by number
  71. * + 'alter' = alter the query
  72. * + false = skip rows
  73. *
  74. * @var array
  75. */
  76. var $features = array(
  77. 'limit' => 'emulate',
  78. 'new_link' => false,
  79. 'numrows' => 'emulate',
  80. 'pconnect' => true,
  81. 'prepare' => false,
  82. 'ssl' => false,
  83. 'transactions' => true,
  84. );
  85. /**
  86. * A mapping of native error codes to DB error codes
  87. * @var array
  88. */
  89. var $errorcode_map = array(
  90. '-201' => DB_ERROR_SYNTAX,
  91. '-206' => DB_ERROR_NOSUCHTABLE,
  92. '-217' => DB_ERROR_NOSUCHFIELD,
  93. '-236' => DB_ERROR_VALUE_COUNT_ON_ROW,
  94. '-239' => DB_ERROR_CONSTRAINT,
  95. '-253' => DB_ERROR_SYNTAX,
  96. '-292' => DB_ERROR_CONSTRAINT_NOT_NULL,
  97. '-310' => DB_ERROR_ALREADY_EXISTS,
  98. '-316' => DB_ERROR_ALREADY_EXISTS,
  99. '-319' => DB_ERROR_NOT_FOUND,
  100. '-329' => DB_ERROR_NODBSELECTED,
  101. '-346' => DB_ERROR_CONSTRAINT,
  102. '-386' => DB_ERROR_CONSTRAINT_NOT_NULL,
  103. '-391' => DB_ERROR_CONSTRAINT_NOT_NULL,
  104. '-554' => DB_ERROR_SYNTAX,
  105. '-691' => DB_ERROR_CONSTRAINT,
  106. '-692' => DB_ERROR_CONSTRAINT,
  107. '-703' => DB_ERROR_CONSTRAINT_NOT_NULL,
  108. '-1204' => DB_ERROR_INVALID_DATE,
  109. '-1205' => DB_ERROR_INVALID_DATE,
  110. '-1206' => DB_ERROR_INVALID_DATE,
  111. '-1209' => DB_ERROR_INVALID_DATE,
  112. '-1210' => DB_ERROR_INVALID_DATE,
  113. '-1212' => DB_ERROR_INVALID_DATE,
  114. '-1213' => DB_ERROR_INVALID_NUMBER,
  115. );
  116. /**
  117. * The raw database connection created by PHP
  118. * @var resource
  119. */
  120. var $connection;
  121. /**
  122. * The DSN information for connecting to a database
  123. * @var array
  124. */
  125. var $dsn = array();
  126. /**
  127. * Should data manipulation queries be committed automatically?
  128. * @var bool
  129. * @access private
  130. */
  131. var $autocommit = true;
  132. /**
  133. * The quantity of transactions begun
  134. *
  135. * {@internal While this is private, it can't actually be designated
  136. * private in PHP 5 because it is directly accessed in the test suite.}}
  137. *
  138. * @var integer
  139. * @access private
  140. */
  141. var $transaction_opcount = 0;
  142. /**
  143. * The number of rows affected by a data manipulation query
  144. * @var integer
  145. * @access private
  146. */
  147. var $affected = 0;
  148. // }}}
  149. // {{{ constructor
  150. /**
  151. * This constructor calls <kbd>$this->DB_common()</kbd>
  152. *
  153. * @return void
  154. */
  155. function DB_ifx()
  156. {
  157. $this->DB_common();
  158. }
  159. // }}}
  160. // {{{ connect()
  161. /**
  162. * Connect to the database server, log in and open the database
  163. *
  164. * Don't call this method directly. Use DB::connect() instead.
  165. *
  166. * @param array $dsn the data source name
  167. * @param bool $persistent should the connection be persistent?
  168. *
  169. * @return int DB_OK on success. A DB_Error object on failure.
  170. */
  171. function connect($dsn, $persistent = false)
  172. {
  173. if (!PEAR::loadExtension('informix') &&
  174. !PEAR::loadExtension('Informix'))
  175. {
  176. return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  177. }
  178. $this->dsn = $dsn;
  179. if ($dsn['dbsyntax']) {
  180. $this->dbsyntax = $dsn['dbsyntax'];
  181. }
  182. $dbhost = $dsn['hostspec'] ? '@' . $dsn['hostspec'] : '';
  183. $dbname = $dsn['database'] ? $dsn['database'] . $dbhost : '';
  184. $user = $dsn['username'] ? $dsn['username'] : '';
  185. $pw = $dsn['password'] ? $dsn['password'] : '';
  186. $connect_function = $persistent ? 'ifx_pconnect' : 'ifx_connect';
  187. $this->connection = @$connect_function($dbname, $user, $pw);
  188. if (!is_resource($this->connection)) {
  189. return $this->ifxRaiseError(DB_ERROR_CONNECT_FAILED);
  190. }
  191. return DB_OK;
  192. }
  193. // }}}
  194. // {{{ disconnect()
  195. /**
  196. * Disconnects from the database server
  197. *
  198. * @return bool TRUE on success, FALSE on failure
  199. */
  200. function disconnect()
  201. {
  202. $ret = @ifx_close($this->connection);
  203. $this->connection = null;
  204. return $ret;
  205. }
  206. // }}}
  207. // {{{ simpleQuery()
  208. /**
  209. * Sends a query to the database server
  210. *
  211. * @param string the SQL query string
  212. *
  213. * @return mixed + a PHP result resrouce for successful SELECT queries
  214. * + the DB_OK constant for other successful queries
  215. * + a DB_Error object on failure
  216. */
  217. function simpleQuery($query)
  218. {
  219. $ismanip = DB::isManip($query);
  220. $this->last_query = $query;
  221. $this->affected = null;
  222. if (preg_match('/(SELECT)/i', $query)) { //TESTME: Use !DB::isManip()?
  223. // the scroll is needed for fetching absolute row numbers
  224. // in a select query result
  225. $result = @ifx_query($query, $this->connection, IFX_SCROLL);
  226. } else {
  227. if (!$this->autocommit && $ismanip) {
  228. if ($this->transaction_opcount == 0) {
  229. $result = @ifx_query('BEGIN WORK', $this->connection);
  230. if (!$result) {
  231. return $this->ifxRaiseError();
  232. }
  233. }
  234. $this->transaction_opcount++;
  235. }
  236. $result = @ifx_query($query, $this->connection);
  237. }
  238. if (!$result) {
  239. return $this->ifxRaiseError();
  240. }
  241. $this->affected = @ifx_affected_rows($result);
  242. // Determine which queries should return data, and which
  243. // should return an error code only.
  244. if (preg_match('/(SELECT)/i', $query)) {
  245. return $result;
  246. }
  247. // XXX Testme: free results inside a transaction
  248. // may cause to stop it and commit the work?
  249. // Result has to be freed even with a insert or update
  250. @ifx_free_result($result);
  251. return DB_OK;
  252. }
  253. // }}}
  254. // {{{ nextResult()
  255. /**
  256. * Move the internal ifx result pointer to the next available result
  257. *
  258. * @param a valid fbsql result resource
  259. *
  260. * @access public
  261. *
  262. * @return true if a result is available otherwise return false
  263. */
  264. function nextResult($result)
  265. {
  266. return false;
  267. }
  268. // }}}
  269. // {{{ affectedRows()
  270. /**
  271. * Determines the number of rows affected by a data maniuplation query
  272. *
  273. * 0 is returned for queries that don't manipulate data.
  274. *
  275. * @return int the number of rows. A DB_Error object on failure.
  276. */
  277. function affectedRows()
  278. {
  279. if (DB::isManip($this->last_query)) {
  280. return $this->affected;
  281. } else {
  282. return 0;
  283. }
  284. }
  285. // }}}
  286. // {{{ fetchInto()
  287. /**
  288. * Places a row from the result set into the given array
  289. *
  290. * Formating of the array and the data therein are configurable.
  291. * See DB_result::fetchInto() for more information.
  292. *
  293. * This method is not meant to be called directly. Use
  294. * DB_result::fetchInto() instead. It can't be declared "protected"
  295. * because DB_result is a separate object.
  296. *
  297. * @param resource $result the query result resource
  298. * @param array $arr the referenced array to put the data in
  299. * @param int $fetchmode how the resulting array should be indexed
  300. * @param int $rownum the row number to fetch (0 = first row)
  301. *
  302. * @return mixed DB_OK on success, NULL when the end of a result set is
  303. * reached or on failure
  304. *
  305. * @see DB_result::fetchInto()
  306. */
  307. function fetchInto($result, &$arr, $fetchmode, $rownum = null)
  308. {
  309. if (($rownum !== null) && ($rownum < 0)) {
  310. return null;
  311. }
  312. if ($rownum === null) {
  313. /*
  314. * Even though fetch_row() should return the next row if
  315. * $rownum is null, it doesn't in all cases. Bug 598.
  316. */
  317. $rownum = 'NEXT';
  318. } else {
  319. // Index starts at row 1, unlike most DBMS's starting at 0.
  320. $rownum++;
  321. }
  322. if (!$arr = @ifx_fetch_row($result, $rownum)) {
  323. return null;
  324. }
  325. if ($fetchmode !== DB_FETCHMODE_ASSOC) {
  326. $i=0;
  327. $order = array();
  328. foreach ($arr as $val) {
  329. $order[$i++] = $val;
  330. }
  331. $arr = $order;
  332. } elseif ($fetchmode == DB_FETCHMODE_ASSOC &&
  333. $this->options['portability'] & DB_PORTABILITY_LOWERCASE)
  334. {
  335. $arr = array_change_key_case($arr, CASE_LOWER);
  336. }
  337. if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  338. $this->_rtrimArrayValues($arr);
  339. }
  340. if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  341. $this->_convertNullArrayValuesToEmpty($arr);
  342. }
  343. return DB_OK;
  344. }
  345. // }}}
  346. // {{{ numCols()
  347. /**
  348. * Gets the number of columns in a result set
  349. *
  350. * This method is not meant to be called directly. Use
  351. * DB_result::numCols() instead. It can't be declared "protected"
  352. * because DB_result is a separate object.
  353. *
  354. * @param resource $result PHP's query result resource
  355. *
  356. * @return int the number of columns. A DB_Error object on failure.
  357. *
  358. * @see DB_result::numCols()
  359. */
  360. function numCols($result)
  361. {
  362. if (!$cols = @ifx_num_fields($result)) {
  363. return $this->ifxRaiseError();
  364. }
  365. return $cols;
  366. }
  367. // }}}
  368. // {{{ freeResult()
  369. /**
  370. * Deletes the result set and frees the memory occupied by the result set
  371. *
  372. * This method is not meant to be called directly. Use
  373. * DB_result::free() instead. It can't be declared "protected"
  374. * because DB_result is a separate object.
  375. *
  376. * @param resource $result PHP's query result resource
  377. *
  378. * @return bool TRUE on success, FALSE if $result is invalid
  379. *
  380. * @see DB_result::free()
  381. */
  382. function freeResult($result)
  383. {
  384. return @ifx_free_result($result);
  385. }
  386. // }}}
  387. // {{{ autoCommit()
  388. /**
  389. * Enables or disables automatic commits
  390. *
  391. * @param bool $onoff true turns it on, false turns it off
  392. *
  393. * @return int DB_OK on success. A DB_Error object if the driver
  394. * doesn't support auto-committing transactions.
  395. */
  396. function autoCommit($onoff = true)
  397. {
  398. // XXX if $this->transaction_opcount > 0, we should probably
  399. // issue a warning here.
  400. $this->autocommit = $onoff ? true : false;
  401. return DB_OK;
  402. }
  403. // }}}
  404. // {{{ commit()
  405. /**
  406. * Commits the current transaction
  407. *
  408. * @return int DB_OK on success. A DB_Error object on failure.
  409. */
  410. function commit()
  411. {
  412. if ($this->transaction_opcount > 0) {
  413. $result = @ifx_query('COMMIT WORK', $this->connection);
  414. $this->transaction_opcount = 0;
  415. if (!$result) {
  416. return $this->ifxRaiseError();
  417. }
  418. }
  419. return DB_OK;
  420. }
  421. // }}}
  422. // {{{ rollback()
  423. /**
  424. * Reverts the current transaction
  425. *
  426. * @return int DB_OK on success. A DB_Error object on failure.
  427. */
  428. function rollback()
  429. {
  430. if ($this->transaction_opcount > 0) {
  431. $result = @ifx_query('ROLLBACK WORK', $this->connection);
  432. $this->transaction_opcount = 0;
  433. if (!$result) {
  434. return $this->ifxRaiseError();
  435. }
  436. }
  437. return DB_OK;
  438. }
  439. // }}}
  440. // {{{ ifxRaiseError()
  441. /**
  442. * Produces a DB_Error object regarding the current problem
  443. *
  444. * @param int $errno if the error is being manually raised pass a
  445. * DB_ERROR* constant here. If this isn't passed
  446. * the error information gathered from the DBMS.
  447. *
  448. * @return object the DB_Error object
  449. *
  450. * @see DB_common::raiseError(),
  451. * DB_ifx::errorNative(), DB_ifx::errorCode()
  452. */
  453. function ifxRaiseError($errno = null)
  454. {
  455. if ($errno === null) {
  456. $errno = $this->errorCode(ifx_error());
  457. }
  458. return $this->raiseError($errno, null, null, null,
  459. $this->errorNative());
  460. }
  461. // }}}
  462. // {{{ errorNative()
  463. /**
  464. * Gets the DBMS' native error code and message produced by the last query
  465. *
  466. * @return string the DBMS' error code and message
  467. */
  468. function errorNative()
  469. {
  470. return @ifx_error() . ' ' . @ifx_errormsg();
  471. }
  472. // }}}
  473. // {{{ errorCode()
  474. /**
  475. * Maps native error codes to DB's portable ones.
  476. *
  477. * Requires that the DB implementation's constructor fills
  478. * in the <var>$errorcode_map</var> property.
  479. *
  480. * @param string $nativecode error code returned by the database
  481. * @return int a portable DB error code, or DB_ERROR if this DB
  482. * implementation has no mapping for the given error code.
  483. */
  484. function errorCode($nativecode)
  485. {
  486. if (ereg('SQLCODE=(.*)]', $nativecode, $match)) {
  487. $code = $match[1];
  488. if (isset($this->errorcode_map[$code])) {
  489. return $this->errorcode_map[$code];
  490. }
  491. }
  492. return DB_ERROR;
  493. }
  494. // }}}
  495. // {{{ tableInfo()
  496. /**
  497. * Returns information about a table or a result set
  498. *
  499. * NOTE: only supports 'table' if <var>$result</var> is a table name.
  500. *
  501. * If analyzing a query result and the result has duplicate field names,
  502. * an error will be raised saying
  503. * <samp>can't distinguish duplicate field names</samp>.
  504. *
  505. * @param object|string $result DB_result object from a query or a
  506. * string containing the name of a table.
  507. * While this also accepts a query result
  508. * resource identifier, this behavior is
  509. * deprecated.
  510. * @param int $mode a valid tableInfo mode
  511. *
  512. * @return array an associative array with the information requested.
  513. * A DB_Error object on failure.
  514. *
  515. * @see DB_common::tableInfo()
  516. * @since Method available since Release 1.6.0
  517. */
  518. function tableInfo($result, $mode = null)
  519. {
  520. if (is_string($result)) {
  521. /*
  522. * Probably received a table name.
  523. * Create a result resource identifier.
  524. */
  525. $id = @ifx_query("SELECT * FROM $result WHERE 1=0",
  526. $this->connection);
  527. $got_string = true;
  528. } elseif (isset($result->result)) {
  529. /*
  530. * Probably received a result object.
  531. * Extract the result resource identifier.
  532. */
  533. $id = $result->result;
  534. $got_string = false;
  535. } else {
  536. /*
  537. * Probably received a result resource identifier.
  538. * Copy it.
  539. */
  540. $id = $result;
  541. $got_string = false;
  542. }
  543. if (!is_resource($id)) {
  544. return $this->ifxRaiseError(DB_ERROR_NEED_MORE_DATA);
  545. }
  546. $flds = @ifx_fieldproperties($id);
  547. $count = @ifx_num_fields($id);
  548. if (count($flds) != $count) {
  549. return $this->raiseError("can't distinguish duplicate field names");
  550. }
  551. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  552. $case_func = 'strtolower';
  553. } else {
  554. $case_func = 'strval';
  555. }
  556. $i = 0;
  557. $res = array();
  558. if ($mode) {
  559. $res['num_fields'] = $count;
  560. }
  561. foreach ($flds as $key => $value) {
  562. $props = explode(';', $value);
  563. $res[$i] = array(
  564. 'table' => $got_string ? $case_func($result) : '',
  565. 'name' => $case_func($key),
  566. 'type' => $props[0],
  567. 'len' => $props[1],
  568. 'flags' => $props[4] == 'N' ? 'not_null' : '',
  569. );
  570. if ($mode & DB_TABLEINFO_ORDER) {
  571. $res['order'][$res[$i]['name']] = $i;
  572. }
  573. if ($mode & DB_TABLEINFO_ORDERTABLE) {
  574. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  575. }
  576. $i++;
  577. }
  578. // free the result only if we were called on a table
  579. if ($got_string) {
  580. @ifx_free_result($id);
  581. }
  582. return $res;
  583. }
  584. // }}}
  585. // {{{ getSpecialQuery()
  586. /**
  587. * Obtains the query string needed for listing a given type of objects
  588. *
  589. * @param string $type the kind of objects you want to retrieve
  590. *
  591. * @return string the SQL query string or null if the driver doesn't
  592. * support the object type requested
  593. *
  594. * @access protected
  595. * @see DB_common::getListOf()
  596. */
  597. function getSpecialQuery($type)
  598. {
  599. switch ($type) {
  600. case 'tables':
  601. return 'SELECT tabname FROM systables WHERE tabid >= 100';
  602. default:
  603. return null;
  604. }
  605. }
  606. // }}}
  607. }
  608. /*
  609. * Local variables:
  610. * tab-width: 4
  611. * c-basic-offset: 4
  612. * End:
  613. */
  614. ?>