PageRenderTime 82ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/Zend/Db/Adapter/Db2.php

https://github.com/quarkness/piwik
PHP | 840 lines | 675 code | 24 blank | 141 comment | 25 complexity | 0e3132abd56e493b76df721eb37ad1ce MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Db
  17. * @subpackage Adapter
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Db2.php 23775 2011-03-01 17:25:24Z ralph $
  21. *
  22. */
  23. /**
  24. * @see Zend_Db
  25. */
  26. // require_once 'Zend/Db.php';
  27. /**
  28. * @see Zend_Db_Adapter_Abstract
  29. */
  30. // require_once 'Zend/Db/Adapter/Abstract.php';
  31. /**
  32. * @see Zend_Db_Statement_Db2
  33. */
  34. // require_once 'Zend/Db/Statement/Db2.php';
  35. /**
  36. * @package Zend_Db
  37. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class Zend_Db_Adapter_Db2 extends Zend_Db_Adapter_Abstract
  41. {
  42. /**
  43. * User-provided configuration.
  44. *
  45. * Basic keys are:
  46. *
  47. * username => (string) Connect to the database as this username.
  48. * password => (string) Password associated with the username.
  49. * host => (string) What host to connect to (default 127.0.0.1)
  50. * dbname => (string) The name of the database to user
  51. * protocol => (string) Protocol to use, defaults to "TCPIP"
  52. * port => (integer) Port number to use for TCP/IP if protocol is "TCPIP"
  53. * persistent => (boolean) Set TRUE to use a persistent connection (db2_pconnect)
  54. * os => (string) This should be set to 'i5' if the db is on an os400/i5
  55. * schema => (string) The default schema the connection should use
  56. *
  57. * @var array
  58. */
  59. protected $_config = array(
  60. 'dbname' => null,
  61. 'username' => null,
  62. 'password' => null,
  63. 'host' => 'localhost',
  64. 'port' => '50000',
  65. 'protocol' => 'TCPIP',
  66. 'persistent' => false,
  67. 'os' => null,
  68. 'schema' => null
  69. );
  70. /**
  71. * Execution mode
  72. *
  73. * @var int execution flag (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF)
  74. */
  75. protected $_execute_mode = DB2_AUTOCOMMIT_ON;
  76. /**
  77. * Default class name for a DB statement.
  78. *
  79. * @var string
  80. */
  81. protected $_defaultStmtClass = 'Zend_Db_Statement_Db2';
  82. protected $_isI5 = false;
  83. /**
  84. * Keys are UPPERCASE SQL datatypes or the constants
  85. * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
  86. *
  87. * Values are:
  88. * 0 = 32-bit integer
  89. * 1 = 64-bit integer
  90. * 2 = float or decimal
  91. *
  92. * @var array Associative array of datatypes to values 0, 1, or 2.
  93. */
  94. protected $_numericDataTypes = array(
  95. Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
  96. Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
  97. Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
  98. 'INTEGER' => Zend_Db::INT_TYPE,
  99. 'SMALLINT' => Zend_Db::INT_TYPE,
  100. 'BIGINT' => Zend_Db::BIGINT_TYPE,
  101. 'DECIMAL' => Zend_Db::FLOAT_TYPE,
  102. 'NUMERIC' => Zend_Db::FLOAT_TYPE
  103. );
  104. /**
  105. * Creates a connection resource.
  106. *
  107. * @return void
  108. */
  109. protected function _connect()
  110. {
  111. if (is_resource($this->_connection)) {
  112. // connection already exists
  113. return;
  114. }
  115. if (!extension_loaded('ibm_db2')) {
  116. /**
  117. * @see Zend_Db_Adapter_Db2_Exception
  118. */
  119. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  120. throw new Zend_Db_Adapter_Db2_Exception('The IBM DB2 extension is required for this adapter but the extension is not loaded');
  121. }
  122. $this->_determineI5();
  123. if ($this->_config['persistent']) {
  124. // use persistent connection
  125. $conn_func_name = 'db2_pconnect';
  126. } else {
  127. // use "normal" connection
  128. $conn_func_name = 'db2_connect';
  129. }
  130. if (!isset($this->_config['driver_options']['autocommit'])) {
  131. // set execution mode
  132. $this->_config['driver_options']['autocommit'] = &$this->_execute_mode;
  133. }
  134. if (isset($this->_config['options'][Zend_Db::CASE_FOLDING])) {
  135. $caseAttrMap = array(
  136. Zend_Db::CASE_NATURAL => DB2_CASE_NATURAL,
  137. Zend_Db::CASE_UPPER => DB2_CASE_UPPER,
  138. Zend_Db::CASE_LOWER => DB2_CASE_LOWER
  139. );
  140. $this->_config['driver_options']['DB2_ATTR_CASE'] = $caseAttrMap[$this->_config['options'][Zend_Db::CASE_FOLDING]];
  141. }
  142. if ($this->_isI5 && isset($this->_config['driver_options']['i5_naming'])) {
  143. if ($this->_config['driver_options']['i5_naming']) {
  144. $this->_config['driver_options']['i5_naming'] = DB2_I5_NAMING_ON;
  145. } else {
  146. $this->_config['driver_options']['i5_naming'] = DB2_I5_NAMING_OFF;
  147. }
  148. }
  149. if ($this->_config['host'] !== 'localhost' && !$this->_isI5) {
  150. // if the host isn't localhost, use extended connection params
  151. $dbname = 'DRIVER={IBM DB2 ODBC DRIVER}' .
  152. ';DATABASE=' . $this->_config['dbname'] .
  153. ';HOSTNAME=' . $this->_config['host'] .
  154. ';PORT=' . $this->_config['port'] .
  155. ';PROTOCOL=' . $this->_config['protocol'] .
  156. ';UID=' . $this->_config['username'] .
  157. ';PWD=' . $this->_config['password'] .';';
  158. $this->_connection = $conn_func_name(
  159. $dbname,
  160. null,
  161. null,
  162. $this->_config['driver_options']
  163. );
  164. } else {
  165. // host is localhost, so use standard connection params
  166. $this->_connection = $conn_func_name(
  167. $this->_config['dbname'],
  168. $this->_config['username'],
  169. $this->_config['password'],
  170. $this->_config['driver_options']
  171. );
  172. }
  173. // check the connection
  174. if (!$this->_connection) {
  175. /**
  176. * @see Zend_Db_Adapter_Db2_Exception
  177. */
  178. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  179. throw new Zend_Db_Adapter_Db2_Exception(db2_conn_errormsg(), db2_conn_error());
  180. }
  181. }
  182. /**
  183. * Test if a connection is active
  184. *
  185. * @return boolean
  186. */
  187. public function isConnected()
  188. {
  189. return ((bool) (is_resource($this->_connection)
  190. && get_resource_type($this->_connection) == 'DB2 Connection'));
  191. }
  192. /**
  193. * Force the connection to close.
  194. *
  195. * @return void
  196. */
  197. public function closeConnection()
  198. {
  199. if ($this->isConnected()) {
  200. db2_close($this->_connection);
  201. }
  202. $this->_connection = null;
  203. }
  204. /**
  205. * Returns an SQL statement for preparation.
  206. *
  207. * @param string $sql The SQL statement with placeholders.
  208. * @return Zend_Db_Statement_Db2
  209. */
  210. public function prepare($sql)
  211. {
  212. $this->_connect();
  213. $stmtClass = $this->_defaultStmtClass;
  214. if (!class_exists($stmtClass)) {
  215. // require_once 'Zend/Loader.php';
  216. Zend_Loader::loadClass($stmtClass);
  217. }
  218. $stmt = new $stmtClass($this, $sql);
  219. $stmt->setFetchMode($this->_fetchMode);
  220. return $stmt;
  221. }
  222. /**
  223. * Gets the execution mode
  224. *
  225. * @return int the execution mode (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF)
  226. */
  227. public function _getExecuteMode()
  228. {
  229. return $this->_execute_mode;
  230. }
  231. /**
  232. * @param integer $mode
  233. * @return void
  234. */
  235. public function _setExecuteMode($mode)
  236. {
  237. switch ($mode) {
  238. case DB2_AUTOCOMMIT_OFF:
  239. case DB2_AUTOCOMMIT_ON:
  240. $this->_execute_mode = $mode;
  241. db2_autocommit($this->_connection, $mode);
  242. break;
  243. default:
  244. /**
  245. * @see Zend_Db_Adapter_Db2_Exception
  246. */
  247. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  248. throw new Zend_Db_Adapter_Db2_Exception("execution mode not supported");
  249. break;
  250. }
  251. }
  252. /**
  253. * Quote a raw string.
  254. *
  255. * @param string $value Raw string
  256. * @return string Quoted string
  257. */
  258. protected function _quote($value)
  259. {
  260. if (is_int($value) || is_float($value)) {
  261. return $value;
  262. }
  263. /**
  264. * Use db2_escape_string() if it is present in the IBM DB2 extension.
  265. * But some supported versions of PHP do not include this function,
  266. * so fall back to default quoting in the parent class.
  267. */
  268. if (function_exists('db2_escape_string')) {
  269. return "'" . db2_escape_string($value) . "'";
  270. }
  271. return parent::_quote($value);
  272. }
  273. /**
  274. * @return string
  275. */
  276. public function getQuoteIdentifierSymbol()
  277. {
  278. $this->_connect();
  279. $info = db2_server_info($this->_connection);
  280. if ($info) {
  281. $identQuote = $info->IDENTIFIER_QUOTE_CHAR;
  282. } else {
  283. // db2_server_info() does not return result on some i5 OS version
  284. if ($this->_isI5) {
  285. $identQuote ="'";
  286. }
  287. }
  288. return $identQuote;
  289. }
  290. /**
  291. * Returns a list of the tables in the database.
  292. * @param string $schema OPTIONAL
  293. * @return array
  294. */
  295. public function listTables($schema = null)
  296. {
  297. $this->_connect();
  298. if ($schema === null && $this->_config['schema'] != null) {
  299. $schema = $this->_config['schema'];
  300. }
  301. $tables = array();
  302. if (!$this->_isI5) {
  303. if ($schema) {
  304. $stmt = db2_tables($this->_connection, null, $schema);
  305. } else {
  306. $stmt = db2_tables($this->_connection);
  307. }
  308. while ($row = db2_fetch_assoc($stmt)) {
  309. $tables[] = $row['TABLE_NAME'];
  310. }
  311. } else {
  312. $tables = $this->_i5listTables($schema);
  313. }
  314. return $tables;
  315. }
  316. /**
  317. * Returns the column descriptions for a table.
  318. *
  319. * The return value is an associative array keyed by the column name,
  320. * as returned by the RDBMS.
  321. *
  322. * The value of each array element is an associative array
  323. * with the following keys:
  324. *
  325. * SCHEMA_NAME => string; name of database or schema
  326. * TABLE_NAME => string;
  327. * COLUMN_NAME => string; column name
  328. * COLUMN_POSITION => number; ordinal position of column in table
  329. * DATA_TYPE => string; SQL datatype name of column
  330. * DEFAULT => string; default expression of column, null if none
  331. * NULLABLE => boolean; true if column can have nulls
  332. * LENGTH => number; length of CHAR/VARCHAR
  333. * SCALE => number; scale of NUMERIC/DECIMAL
  334. * PRECISION => number; precision of NUMERIC/DECIMAL
  335. * UNSIGNED => boolean; unsigned property of an integer type
  336. * DB2 not supports UNSIGNED integer.
  337. * PRIMARY => boolean; true if column is part of the primary key
  338. * PRIMARY_POSITION => integer; position of column in primary key
  339. * IDENTITY => integer; true if column is auto-generated with unique values
  340. *
  341. * @param string $tableName
  342. * @param string $schemaName OPTIONAL
  343. * @return array
  344. */
  345. public function describeTable($tableName, $schemaName = null)
  346. {
  347. // Ensure the connection is made so that _isI5 is set
  348. $this->_connect();
  349. if ($schemaName === null && $this->_config['schema'] != null) {
  350. $schemaName = $this->_config['schema'];
  351. }
  352. if (!$this->_isI5) {
  353. $sql = "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno,
  354. c.typename, c.default, c.nulls, c.length, c.scale,
  355. c.identity, tc.type AS tabconsttype, k.colseq
  356. FROM syscat.columns c
  357. LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc
  358. ON (k.tabschema = tc.tabschema
  359. AND k.tabname = tc.tabname
  360. AND tc.type = 'P'))
  361. ON (c.tabschema = k.tabschema
  362. AND c.tabname = k.tabname
  363. AND c.colname = k.colname)
  364. WHERE "
  365. . $this->quoteInto('UPPER(c.tabname) = UPPER(?)', $tableName);
  366. if ($schemaName) {
  367. $sql .= $this->quoteInto(' AND UPPER(c.tabschema) = UPPER(?)', $schemaName);
  368. }
  369. $sql .= " ORDER BY c.colno";
  370. } else {
  371. // DB2 On I5 specific query
  372. $sql = "SELECT DISTINCT C.TABLE_SCHEMA, C.TABLE_NAME, C.COLUMN_NAME, C.ORDINAL_POSITION,
  373. C.DATA_TYPE, C.COLUMN_DEFAULT, C.NULLS ,C.LENGTH, C.SCALE, LEFT(C.IDENTITY,1),
  374. LEFT(tc.TYPE, 1) AS tabconsttype, k.COLSEQ
  375. FROM QSYS2.SYSCOLUMNS C
  376. LEFT JOIN (QSYS2.syskeycst k JOIN QSYS2.SYSCST tc
  377. ON (k.TABLE_SCHEMA = tc.TABLE_SCHEMA
  378. AND k.TABLE_NAME = tc.TABLE_NAME
  379. AND LEFT(tc.type,1) = 'P'))
  380. ON (C.TABLE_SCHEMA = k.TABLE_SCHEMA
  381. AND C.TABLE_NAME = k.TABLE_NAME
  382. AND C.COLUMN_NAME = k.COLUMN_NAME)
  383. WHERE "
  384. . $this->quoteInto('UPPER(C.TABLE_NAME) = UPPER(?)', $tableName);
  385. if ($schemaName) {
  386. $sql .= $this->quoteInto(' AND UPPER(C.TABLE_SCHEMA) = UPPER(?)', $schemaName);
  387. }
  388. $sql .= " ORDER BY C.ORDINAL_POSITION FOR FETCH ONLY";
  389. }
  390. $desc = array();
  391. $stmt = $this->query($sql);
  392. /**
  393. * To avoid case issues, fetch using FETCH_NUM
  394. */
  395. $result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
  396. /**
  397. * The ordering of columns is defined by the query so we can map
  398. * to variables to improve readability
  399. */
  400. $tabschema = 0;
  401. $tabname = 1;
  402. $colname = 2;
  403. $colno = 3;
  404. $typename = 4;
  405. $default = 5;
  406. $nulls = 6;
  407. $length = 7;
  408. $scale = 8;
  409. $identityCol = 9;
  410. $tabconstType = 10;
  411. $colseq = 11;
  412. foreach ($result as $key => $row) {
  413. list ($primary, $primaryPosition, $identity) = array(false, null, false);
  414. if ($row[$tabconstType] == 'P') {
  415. $primary = true;
  416. $primaryPosition = $row[$colseq];
  417. }
  418. /**
  419. * In IBM DB2, an column can be IDENTITY
  420. * even if it is not part of the PRIMARY KEY.
  421. */
  422. if ($row[$identityCol] == 'Y') {
  423. $identity = true;
  424. }
  425. // only colname needs to be case adjusted
  426. $desc[$this->foldCase($row[$colname])] = array(
  427. 'SCHEMA_NAME' => $this->foldCase($row[$tabschema]),
  428. 'TABLE_NAME' => $this->foldCase($row[$tabname]),
  429. 'COLUMN_NAME' => $this->foldCase($row[$colname]),
  430. 'COLUMN_POSITION' => (!$this->_isI5) ? $row[$colno]+1 : $row[$colno],
  431. 'DATA_TYPE' => $row[$typename],
  432. 'DEFAULT' => $row[$default],
  433. 'NULLABLE' => (bool) ($row[$nulls] == 'Y'),
  434. 'LENGTH' => $row[$length],
  435. 'SCALE' => $row[$scale],
  436. 'PRECISION' => ($row[$typename] == 'DECIMAL' ? $row[$length] : 0),
  437. 'UNSIGNED' => false,
  438. 'PRIMARY' => $primary,
  439. 'PRIMARY_POSITION' => $primaryPosition,
  440. 'IDENTITY' => $identity
  441. );
  442. }
  443. return $desc;
  444. }
  445. /**
  446. * Return the most recent value from the specified sequence in the database.
  447. * This is supported only on RDBMS brands that support sequences
  448. * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
  449. *
  450. * @param string $sequenceName
  451. * @return string
  452. */
  453. public function lastSequenceId($sequenceName)
  454. {
  455. $this->_connect();
  456. if (!$this->_isI5) {
  457. $quotedSequenceName = $this->quoteIdentifier($sequenceName, true);
  458. $sql = 'SELECT PREVVAL FOR ' . $quotedSequenceName . ' AS VAL FROM SYSIBM.SYSDUMMY1';
  459. } else {
  460. $quotedSequenceName = $sequenceName;
  461. $sql = 'SELECT PREVVAL FOR ' . $this->quoteIdentifier($sequenceName, true) . ' AS VAL FROM QSYS2.QSQPTABL';
  462. }
  463. $value = $this->fetchOne($sql);
  464. return (string) $value;
  465. }
  466. /**
  467. * Generate a new value from the specified sequence in the database, and return it.
  468. * This is supported only on RDBMS brands that support sequences
  469. * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
  470. *
  471. * @param string $sequenceName
  472. * @return string
  473. */
  474. public function nextSequenceId($sequenceName)
  475. {
  476. $this->_connect();
  477. $sql = 'SELECT NEXTVAL FOR '.$this->quoteIdentifier($sequenceName, true).' AS VAL FROM SYSIBM.SYSDUMMY1';
  478. $value = $this->fetchOne($sql);
  479. return (string) $value;
  480. }
  481. /**
  482. * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
  483. *
  484. * As a convention, on RDBMS brands that support sequences
  485. * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
  486. * from the arguments and returns the last id generated by that sequence.
  487. * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
  488. * returns the last value generated for such a column, and the table name
  489. * argument is disregarded.
  490. *
  491. * The IDENTITY_VAL_LOCAL() function gives the last generated identity value
  492. * in the current process, even if it was for a GENERATED column.
  493. *
  494. * @param string $tableName OPTIONAL
  495. * @param string $primaryKey OPTIONAL
  496. * @param string $idType OPTIONAL used for i5 platform to define sequence/idenity unique value
  497. * @return string
  498. */
  499. public function lastInsertId($tableName = null, $primaryKey = null, $idType = null)
  500. {
  501. $this->_connect();
  502. if ($this->_isI5) {
  503. return (string) $this->_i5LastInsertId($tableName, $idType);
  504. }
  505. if ($tableName !== null) {
  506. $sequenceName = $tableName;
  507. if ($primaryKey) {
  508. $sequenceName .= "_$primaryKey";
  509. }
  510. $sequenceName .= '_seq';
  511. return $this->lastSequenceId($sequenceName);
  512. }
  513. $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM SYSIBM.SYSDUMMY1';
  514. $value = $this->fetchOne($sql);
  515. return (string) $value;
  516. }
  517. /**
  518. * Begin a transaction.
  519. *
  520. * @return void
  521. */
  522. protected function _beginTransaction()
  523. {
  524. $this->_setExecuteMode(DB2_AUTOCOMMIT_OFF);
  525. }
  526. /**
  527. * Commit a transaction.
  528. *
  529. * @return void
  530. */
  531. protected function _commit()
  532. {
  533. if (!db2_commit($this->_connection)) {
  534. /**
  535. * @see Zend_Db_Adapter_Db2_Exception
  536. */
  537. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  538. throw new Zend_Db_Adapter_Db2_Exception(
  539. db2_conn_errormsg($this->_connection),
  540. db2_conn_error($this->_connection));
  541. }
  542. $this->_setExecuteMode(DB2_AUTOCOMMIT_ON);
  543. }
  544. /**
  545. * Rollback a transaction.
  546. *
  547. * @return void
  548. */
  549. protected function _rollBack()
  550. {
  551. if (!db2_rollback($this->_connection)) {
  552. /**
  553. * @see Zend_Db_Adapter_Db2_Exception
  554. */
  555. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  556. throw new Zend_Db_Adapter_Db2_Exception(
  557. db2_conn_errormsg($this->_connection),
  558. db2_conn_error($this->_connection));
  559. }
  560. $this->_setExecuteMode(DB2_AUTOCOMMIT_ON);
  561. }
  562. /**
  563. * Set the fetch mode.
  564. *
  565. * @param integer $mode
  566. * @return void
  567. * @throws Zend_Db_Adapter_Db2_Exception
  568. */
  569. public function setFetchMode($mode)
  570. {
  571. switch ($mode) {
  572. case Zend_Db::FETCH_NUM: // seq array
  573. case Zend_Db::FETCH_ASSOC: // assoc array
  574. case Zend_Db::FETCH_BOTH: // seq+assoc array
  575. case Zend_Db::FETCH_OBJ: // object
  576. $this->_fetchMode = $mode;
  577. break;
  578. case Zend_Db::FETCH_BOUND: // bound to PHP variable
  579. /**
  580. * @see Zend_Db_Adapter_Db2_Exception
  581. */
  582. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  583. throw new Zend_Db_Adapter_Db2_Exception('FETCH_BOUND is not supported yet');
  584. break;
  585. default:
  586. /**
  587. * @see Zend_Db_Adapter_Db2_Exception
  588. */
  589. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  590. throw new Zend_Db_Adapter_Db2_Exception("Invalid fetch mode '$mode' specified");
  591. break;
  592. }
  593. }
  594. /**
  595. * Adds an adapter-specific LIMIT clause to the SELECT statement.
  596. *
  597. * @param string $sql
  598. * @param integer $count
  599. * @param integer $offset OPTIONAL
  600. * @return string
  601. */
  602. public function limit($sql, $count, $offset = 0)
  603. {
  604. $count = intval($count);
  605. if ($count <= 0) {
  606. /**
  607. * @see Zend_Db_Adapter_Db2_Exception
  608. */
  609. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  610. throw new Zend_Db_Adapter_Db2_Exception("LIMIT argument count=$count is not valid");
  611. }
  612. $offset = intval($offset);
  613. if ($offset < 0) {
  614. /**
  615. * @see Zend_Db_Adapter_Db2_Exception
  616. */
  617. // require_once 'Zend/Db/Adapter/Db2/Exception.php';
  618. throw new Zend_Db_Adapter_Db2_Exception("LIMIT argument offset=$offset is not valid");
  619. }
  620. if ($offset == 0) {
  621. $limit_sql = $sql . " FETCH FIRST $count ROWS ONLY";
  622. return $limit_sql;
  623. }
  624. /**
  625. * DB2 does not implement the LIMIT clause as some RDBMS do.
  626. * We have to simulate it with subqueries and ROWNUM.
  627. * Unfortunately because we use the column wildcard "*",
  628. * this puts an extra column into the query result set.
  629. */
  630. $limit_sql = "SELECT z2.*
  631. FROM (
  632. SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.*
  633. FROM (
  634. " . $sql . "
  635. ) z1
  636. ) z2
  637. WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count);
  638. return $limit_sql;
  639. }
  640. /**
  641. * Check if the adapter supports real SQL parameters.
  642. *
  643. * @param string $type 'positional' or 'named'
  644. * @return bool
  645. */
  646. public function supportsParameters($type)
  647. {
  648. if ($type == 'positional') {
  649. return true;
  650. }
  651. // if its 'named' or anything else
  652. return false;
  653. }
  654. /**
  655. * Retrieve server version in PHP style
  656. *
  657. * @return string
  658. */
  659. public function getServerVersion()
  660. {
  661. $this->_connect();
  662. $server_info = db2_server_info($this->_connection);
  663. if ($server_info !== false) {
  664. $version = $server_info->DBMS_VER;
  665. if ($this->_isI5) {
  666. $version = (int) substr($version, 0, 2) . '.' . (int) substr($version, 2, 2) . '.' . (int) substr($version, 4);
  667. }
  668. return $version;
  669. } else {
  670. return null;
  671. }
  672. }
  673. /**
  674. * Return whether or not this is running on i5
  675. *
  676. * @return bool
  677. */
  678. public function isI5()
  679. {
  680. if ($this->_isI5 === null) {
  681. $this->_determineI5();
  682. }
  683. return (bool) $this->_isI5;
  684. }
  685. /**
  686. * Check the connection parameters according to verify
  687. * type of used OS
  688. *
  689. * @return void
  690. */
  691. protected function _determineI5()
  692. {
  693. // first us the compiled flag.
  694. $this->_isI5 = (php_uname('s') == 'OS400') ? true : false;
  695. // if this is set, then us it
  696. if (isset($this->_config['os'])){
  697. if (strtolower($this->_config['os']) === 'i5') {
  698. $this->_isI5 = true;
  699. } else {
  700. // any other value passed in, its null
  701. $this->_isI5 = false;
  702. }
  703. }
  704. }
  705. /**
  706. * Db2 On I5 specific method
  707. *
  708. * Returns a list of the tables in the database .
  709. * Used only for DB2/400.
  710. *
  711. * @return array
  712. */
  713. protected function _i5listTables($schema = null)
  714. {
  715. //list of i5 libraries.
  716. $tables = array();
  717. if ($schema) {
  718. $tablesStatement = db2_tables($this->_connection, null, $schema);
  719. while ($rowTables = db2_fetch_assoc($tablesStatement) ) {
  720. if ($rowTables['TABLE_NAME'] !== null) {
  721. $tables[] = $rowTables['TABLE_NAME'];
  722. }
  723. }
  724. } else {
  725. $schemaStatement = db2_tables($this->_connection);
  726. while ($schema = db2_fetch_assoc($schemaStatement)) {
  727. if ($schema['TABLE_SCHEM'] !== null) {
  728. // list of the tables which belongs to the selected library
  729. $tablesStatement = db2_tables($this->_connection, NULL, $schema['TABLE_SCHEM']);
  730. if (is_resource($tablesStatement)) {
  731. while ($rowTables = db2_fetch_assoc($tablesStatement) ) {
  732. if ($rowTables['TABLE_NAME'] !== null) {
  733. $tables[] = $rowTables['TABLE_NAME'];
  734. }
  735. }
  736. }
  737. }
  738. }
  739. }
  740. return $tables;
  741. }
  742. protected function _i5LastInsertId($objectName = null, $idType = null)
  743. {
  744. if ($objectName === null) {
  745. $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM QSYS2.QSQPTABL';
  746. $value = $this->fetchOne($sql);
  747. return $value;
  748. }
  749. if (strtoupper($idType) === 'S'){
  750. //check i5_lib option
  751. $sequenceName = $objectName;
  752. return $this->lastSequenceId($sequenceName);
  753. }
  754. //returns last identity value for the specified table
  755. //if (strtoupper($idType) === 'I') {
  756. $tableName = $objectName;
  757. return $this->fetchOne('SELECT IDENTITY_VAL_LOCAL() from ' . $this->quoteIdentifier($tableName));
  758. }
  759. }