Db2.php 27 KB

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