File indexing completed on 2025-01-19 05:21:02
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Db 0017 * @subpackage Adapter 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 * 0022 */ 0023 0024 /** 0025 * @see Zend_Db 0026 */ 0027 // require_once 'Zend/Db.php'; 0028 0029 /** 0030 * @see Zend_Db_Adapter_Abstract 0031 */ 0032 // require_once 'Zend/Db/Adapter/Abstract.php'; 0033 0034 /** 0035 * @see Zend_Db_Statement_Db2 0036 */ 0037 // require_once 'Zend/Db/Statement/Db2.php'; 0038 0039 0040 /** 0041 * @package Zend_Db 0042 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0043 * @license http://framework.zend.com/license/new-bsd New BSD License 0044 */ 0045 0046 class Zend_Db_Adapter_Db2 extends Zend_Db_Adapter_Abstract 0047 { 0048 /** 0049 * User-provided configuration. 0050 * 0051 * Basic keys are: 0052 * 0053 * username => (string) Connect to the database as this username. 0054 * password => (string) Password associated with the username. 0055 * host => (string) What host to connect to (default 127.0.0.1) 0056 * dbname => (string) The name of the database to user 0057 * protocol => (string) Protocol to use, defaults to "TCPIP" 0058 * port => (integer) Port number to use for TCP/IP if protocol is "TCPIP" 0059 * persistent => (boolean) Set TRUE to use a persistent connection (db2_pconnect) 0060 * os => (string) This should be set to 'i5' if the db is on an os400/i5 0061 * schema => (string) The default schema the connection should use 0062 * 0063 * @var array 0064 */ 0065 protected $_config = array( 0066 'dbname' => null, 0067 'username' => null, 0068 'password' => null, 0069 'host' => 'localhost', 0070 'port' => '50000', 0071 'protocol' => 'TCPIP', 0072 'persistent' => false, 0073 'os' => null, 0074 'schema' => null 0075 ); 0076 0077 /** 0078 * Execution mode 0079 * 0080 * @var int execution flag (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF) 0081 */ 0082 protected $_execute_mode = DB2_AUTOCOMMIT_ON; 0083 0084 /** 0085 * Default class name for a DB statement. 0086 * 0087 * @var string 0088 */ 0089 protected $_defaultStmtClass = 'Zend_Db_Statement_Db2'; 0090 protected $_isI5 = false; 0091 0092 /** 0093 * Keys are UPPERCASE SQL datatypes or the constants 0094 * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. 0095 * 0096 * Values are: 0097 * 0 = 32-bit integer 0098 * 1 = 64-bit integer 0099 * 2 = float or decimal 0100 * 0101 * @var array Associative array of datatypes to values 0, 1, or 2. 0102 */ 0103 protected $_numericDataTypes = array( 0104 Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, 0105 Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, 0106 Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, 0107 'INTEGER' => Zend_Db::INT_TYPE, 0108 'SMALLINT' => Zend_Db::INT_TYPE, 0109 'BIGINT' => Zend_Db::BIGINT_TYPE, 0110 'DECIMAL' => Zend_Db::FLOAT_TYPE, 0111 'NUMERIC' => Zend_Db::FLOAT_TYPE 0112 ); 0113 0114 /** 0115 * Creates a connection resource. 0116 * 0117 * @return void 0118 */ 0119 protected function _connect() 0120 { 0121 if (is_resource($this->_connection)) { 0122 // connection already exists 0123 return; 0124 } 0125 0126 if (!extension_loaded('ibm_db2')) { 0127 /** 0128 * @see Zend_Db_Adapter_Db2_Exception 0129 */ 0130 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0131 throw new Zend_Db_Adapter_Db2_Exception('The IBM DB2 extension is required for this adapter but the extension is not loaded'); 0132 } 0133 0134 $this->_determineI5(); 0135 if ($this->_config['persistent']) { 0136 // use persistent connection 0137 $conn_func_name = 'db2_pconnect'; 0138 } else { 0139 // use "normal" connection 0140 $conn_func_name = 'db2_connect'; 0141 } 0142 0143 if (!isset($this->_config['driver_options']['autocommit'])) { 0144 // set execution mode 0145 $this->_config['driver_options']['autocommit'] = &$this->_execute_mode; 0146 } 0147 0148 if (isset($this->_config['options'][Zend_Db::CASE_FOLDING])) { 0149 $caseAttrMap = array( 0150 Zend_Db::CASE_NATURAL => DB2_CASE_NATURAL, 0151 Zend_Db::CASE_UPPER => DB2_CASE_UPPER, 0152 Zend_Db::CASE_LOWER => DB2_CASE_LOWER 0153 ); 0154 $this->_config['driver_options']['DB2_ATTR_CASE'] = $caseAttrMap[$this->_config['options'][Zend_Db::CASE_FOLDING]]; 0155 } 0156 0157 if ($this->_isI5 && isset($this->_config['driver_options']['i5_naming'])) { 0158 if ($this->_config['driver_options']['i5_naming']) { 0159 $this->_config['driver_options']['i5_naming'] = DB2_I5_NAMING_ON; 0160 } else { 0161 $this->_config['driver_options']['i5_naming'] = DB2_I5_NAMING_OFF; 0162 } 0163 } 0164 0165 if ($this->_config['host'] !== 'localhost' && !$this->_isI5) { 0166 // if the host isn't localhost, use extended connection params 0167 $dbname = 'DRIVER={IBM DB2 ODBC DRIVER}' . 0168 ';DATABASE=' . $this->_config['dbname'] . 0169 ';HOSTNAME=' . $this->_config['host'] . 0170 ';PORT=' . $this->_config['port'] . 0171 ';PROTOCOL=' . $this->_config['protocol'] . 0172 ';UID=' . $this->_config['username'] . 0173 ';PWD=' . $this->_config['password'] .';'; 0174 $this->_connection = $conn_func_name( 0175 $dbname, 0176 null, 0177 null, 0178 $this->_config['driver_options'] 0179 ); 0180 } else { 0181 // host is localhost, so use standard connection params 0182 $this->_connection = $conn_func_name( 0183 $this->_config['dbname'], 0184 $this->_config['username'], 0185 $this->_config['password'], 0186 $this->_config['driver_options'] 0187 ); 0188 } 0189 0190 // check the connection 0191 if (!$this->_connection) { 0192 /** 0193 * @see Zend_Db_Adapter_Db2_Exception 0194 */ 0195 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0196 throw new Zend_Db_Adapter_Db2_Exception(db2_conn_errormsg(), db2_conn_error()); 0197 } 0198 } 0199 0200 /** 0201 * Test if a connection is active 0202 * 0203 * @return boolean 0204 */ 0205 public function isConnected() 0206 { 0207 return ((bool) (is_resource($this->_connection) 0208 && get_resource_type($this->_connection) == 'DB2 Connection')); 0209 } 0210 0211 /** 0212 * Force the connection to close. 0213 * 0214 * @return void 0215 */ 0216 public function closeConnection() 0217 { 0218 if ($this->isConnected()) { 0219 db2_close($this->_connection); 0220 } 0221 $this->_connection = null; 0222 } 0223 0224 /** 0225 * Returns an SQL statement for preparation. 0226 * 0227 * @param string $sql The SQL statement with placeholders. 0228 * @return Zend_Db_Statement_Db2 0229 */ 0230 public function prepare($sql) 0231 { 0232 $this->_connect(); 0233 $stmtClass = $this->_defaultStmtClass; 0234 if (!class_exists($stmtClass)) { 0235 // require_once 'Zend/Loader.php'; 0236 Zend_Loader::loadClass($stmtClass); 0237 } 0238 $stmt = new $stmtClass($this, $sql); 0239 $stmt->setFetchMode($this->_fetchMode); 0240 return $stmt; 0241 } 0242 0243 /** 0244 * Gets the execution mode 0245 * 0246 * @return int the execution mode (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF) 0247 */ 0248 public function _getExecuteMode() 0249 { 0250 return $this->_execute_mode; 0251 } 0252 0253 /** 0254 * @param integer $mode 0255 * @return void 0256 */ 0257 public function _setExecuteMode($mode) 0258 { 0259 switch ($mode) { 0260 case DB2_AUTOCOMMIT_OFF: 0261 case DB2_AUTOCOMMIT_ON: 0262 $this->_execute_mode = $mode; 0263 db2_autocommit($this->_connection, $mode); 0264 break; 0265 default: 0266 /** 0267 * @see Zend_Db_Adapter_Db2_Exception 0268 */ 0269 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0270 throw new Zend_Db_Adapter_Db2_Exception("execution mode not supported"); 0271 break; 0272 } 0273 } 0274 0275 /** 0276 * Quote a raw string. 0277 * 0278 * @param string $value Raw string 0279 * @return string Quoted string 0280 */ 0281 protected function _quote($value) 0282 { 0283 if (is_int($value) || is_float($value)) { 0284 return $value; 0285 } 0286 /** 0287 * Use db2_escape_string() if it is present in the IBM DB2 extension. 0288 * But some supported versions of PHP do not include this function, 0289 * so fall back to default quoting in the parent class. 0290 */ 0291 if (function_exists('db2_escape_string')) { 0292 return "'" . db2_escape_string($value) . "'"; 0293 } 0294 return parent::_quote($value); 0295 } 0296 0297 /** 0298 * @return string 0299 */ 0300 public function getQuoteIdentifierSymbol() 0301 { 0302 $this->_connect(); 0303 $info = db2_server_info($this->_connection); 0304 if ($info) { 0305 $identQuote = $info->IDENTIFIER_QUOTE_CHAR; 0306 } else { 0307 // db2_server_info() does not return result on some i5 OS version 0308 if ($this->_isI5) { 0309 $identQuote ="'"; 0310 } 0311 } 0312 return $identQuote; 0313 } 0314 0315 /** 0316 * Returns a list of the tables in the database. 0317 * @param string $schema OPTIONAL 0318 * @return array 0319 */ 0320 public function listTables($schema = null) 0321 { 0322 $this->_connect(); 0323 0324 if ($schema === null && $this->_config['schema'] != null) { 0325 $schema = $this->_config['schema']; 0326 } 0327 0328 $tables = array(); 0329 0330 if (!$this->_isI5) { 0331 if ($schema) { 0332 $stmt = db2_tables($this->_connection, null, $schema); 0333 } else { 0334 $stmt = db2_tables($this->_connection); 0335 } 0336 while ($row = db2_fetch_assoc($stmt)) { 0337 $tables[] = $row['TABLE_NAME']; 0338 } 0339 } else { 0340 $tables = $this->_i5listTables($schema); 0341 } 0342 0343 return $tables; 0344 } 0345 0346 0347 /** 0348 * Returns the column descriptions for a table. 0349 * 0350 * The return value is an associative array keyed by the column name, 0351 * as returned by the RDBMS. 0352 * 0353 * The value of each array element is an associative array 0354 * with the following keys: 0355 * 0356 * SCHEMA_NAME => string; name of database or schema 0357 * TABLE_NAME => string; 0358 * COLUMN_NAME => string; column name 0359 * COLUMN_POSITION => number; ordinal position of column in table 0360 * DATA_TYPE => string; SQL datatype name of column 0361 * DEFAULT => string; default expression of column, null if none 0362 * NULLABLE => boolean; true if column can have nulls 0363 * LENGTH => number; length of CHAR/VARCHAR 0364 * SCALE => number; scale of NUMERIC/DECIMAL 0365 * PRECISION => number; precision of NUMERIC/DECIMAL 0366 * UNSIGNED => boolean; unsigned property of an integer type 0367 * DB2 not supports UNSIGNED integer. 0368 * PRIMARY => boolean; true if column is part of the primary key 0369 * PRIMARY_POSITION => integer; position of column in primary key 0370 * IDENTITY => integer; true if column is auto-generated with unique values 0371 * 0372 * @param string $tableName 0373 * @param string $schemaName OPTIONAL 0374 * @return array 0375 */ 0376 public function describeTable($tableName, $schemaName = null) 0377 { 0378 // Ensure the connection is made so that _isI5 is set 0379 $this->_connect(); 0380 0381 if ($schemaName === null && $this->_config['schema'] != null) { 0382 $schemaName = $this->_config['schema']; 0383 } 0384 0385 if (!$this->_isI5) { 0386 0387 $sql = "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, 0388 c.typename, c.default, c.nulls, c.length, c.scale, 0389 c.identity, tc.type AS tabconsttype, k.colseq 0390 FROM syscat.columns c 0391 LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc 0392 ON (k.tabschema = tc.tabschema 0393 AND k.tabname = tc.tabname 0394 AND tc.type = 'P')) 0395 ON (c.tabschema = k.tabschema 0396 AND c.tabname = k.tabname 0397 AND c.colname = k.colname) 0398 WHERE " 0399 . $this->quoteInto('UPPER(c.tabname) = UPPER(?)', $tableName); 0400 0401 if ($schemaName) { 0402 $sql .= $this->quoteInto(' AND UPPER(c.tabschema) = UPPER(?)', $schemaName); 0403 } 0404 0405 $sql .= " ORDER BY c.colno"; 0406 0407 } else { 0408 0409 // DB2 On I5 specific query 0410 $sql = "SELECT DISTINCT C.TABLE_SCHEMA, C.TABLE_NAME, C.COLUMN_NAME, C.ORDINAL_POSITION, 0411 C.DATA_TYPE, C.COLUMN_DEFAULT, C.NULLS ,C.LENGTH, C.SCALE, LEFT(C.IDENTITY,1), 0412 LEFT(tc.TYPE, 1) AS tabconsttype, k.COLSEQ 0413 FROM QSYS2.SYSCOLUMNS C 0414 LEFT JOIN (QSYS2.syskeycst k JOIN QSYS2.SYSCST tc 0415 ON (k.TABLE_SCHEMA = tc.TABLE_SCHEMA 0416 AND k.TABLE_NAME = tc.TABLE_NAME 0417 AND LEFT(tc.type,1) = 'P')) 0418 ON (C.TABLE_SCHEMA = k.TABLE_SCHEMA 0419 AND C.TABLE_NAME = k.TABLE_NAME 0420 AND C.COLUMN_NAME = k.COLUMN_NAME) 0421 WHERE " 0422 . $this->quoteInto('UPPER(C.TABLE_NAME) = UPPER(?)', $tableName); 0423 0424 if ($schemaName) { 0425 $sql .= $this->quoteInto(' AND UPPER(C.TABLE_SCHEMA) = UPPER(?)', $schemaName); 0426 } 0427 0428 $sql .= " ORDER BY C.ORDINAL_POSITION FOR FETCH ONLY"; 0429 } 0430 0431 $desc = array(); 0432 $stmt = $this->query($sql); 0433 0434 /** 0435 * To avoid case issues, fetch using FETCH_NUM 0436 */ 0437 $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); 0438 0439 /** 0440 * The ordering of columns is defined by the query so we can map 0441 * to variables to improve readability 0442 */ 0443 $tabschema = 0; 0444 $tabname = 1; 0445 $colname = 2; 0446 $colno = 3; 0447 $typename = 4; 0448 $default = 5; 0449 $nulls = 6; 0450 $length = 7; 0451 $scale = 8; 0452 $identityCol = 9; 0453 $tabconstType = 10; 0454 $colseq = 11; 0455 0456 foreach ($result as $key => $row) { 0457 list ($primary, $primaryPosition, $identity) = array(false, null, false); 0458 if ($row[$tabconstType] == 'P') { 0459 $primary = true; 0460 $primaryPosition = $row[$colseq]; 0461 } 0462 /** 0463 * In IBM DB2, an column can be IDENTITY 0464 * even if it is not part of the PRIMARY KEY. 0465 */ 0466 if ($row[$identityCol] == 'Y') { 0467 $identity = true; 0468 } 0469 0470 // only colname needs to be case adjusted 0471 $desc[$this->foldCase($row[$colname])] = array( 0472 'SCHEMA_NAME' => $this->foldCase($row[$tabschema]), 0473 'TABLE_NAME' => $this->foldCase($row[$tabname]), 0474 'COLUMN_NAME' => $this->foldCase($row[$colname]), 0475 'COLUMN_POSITION' => (!$this->_isI5) ? $row[$colno]+1 : $row[$colno], 0476 'DATA_TYPE' => $row[$typename], 0477 'DEFAULT' => $row[$default], 0478 'NULLABLE' => (bool) ($row[$nulls] == 'Y'), 0479 'LENGTH' => $row[$length], 0480 'SCALE' => $row[$scale], 0481 'PRECISION' => ($row[$typename] == 'DECIMAL' ? $row[$length] : 0), 0482 'UNSIGNED' => false, 0483 'PRIMARY' => $primary, 0484 'PRIMARY_POSITION' => $primaryPosition, 0485 'IDENTITY' => $identity 0486 ); 0487 } 0488 0489 return $desc; 0490 } 0491 0492 /** 0493 * Return the most recent value from the specified sequence in the database. 0494 * This is supported only on RDBMS brands that support sequences 0495 * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. 0496 * 0497 * @param string $sequenceName 0498 * @return string 0499 */ 0500 public function lastSequenceId($sequenceName) 0501 { 0502 $this->_connect(); 0503 0504 if (!$this->_isI5) { 0505 $quotedSequenceName = $this->quoteIdentifier($sequenceName, true); 0506 $sql = 'SELECT PREVVAL FOR ' . $quotedSequenceName . ' AS VAL FROM SYSIBM.SYSDUMMY1'; 0507 } else { 0508 $quotedSequenceName = $sequenceName; 0509 $sql = 'SELECT PREVVAL FOR ' . $this->quoteIdentifier($sequenceName, true) . ' AS VAL FROM QSYS2.QSQPTABL'; 0510 } 0511 0512 $value = $this->fetchOne($sql); 0513 return (string) $value; 0514 } 0515 0516 /** 0517 * Generate a new value from the specified sequence in the database, and return it. 0518 * This is supported only on RDBMS brands that support sequences 0519 * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. 0520 * 0521 * @param string $sequenceName 0522 * @return string 0523 */ 0524 public function nextSequenceId($sequenceName) 0525 { 0526 $this->_connect(); 0527 $sql = 'SELECT NEXTVAL FOR '.$this->quoteIdentifier($sequenceName, true).' AS VAL FROM SYSIBM.SYSDUMMY1'; 0528 $value = $this->fetchOne($sql); 0529 return (string) $value; 0530 } 0531 0532 /** 0533 * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. 0534 * 0535 * As a convention, on RDBMS brands that support sequences 0536 * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence 0537 * from the arguments and returns the last id generated by that sequence. 0538 * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method 0539 * returns the last value generated for such a column, and the table name 0540 * argument is disregarded. 0541 * 0542 * The IDENTITY_VAL_LOCAL() function gives the last generated identity value 0543 * in the current process, even if it was for a GENERATED column. 0544 * 0545 * @param string $tableName OPTIONAL 0546 * @param string $primaryKey OPTIONAL 0547 * @param string $idType OPTIONAL used for i5 platform to define sequence/idenity unique value 0548 * @return string 0549 */ 0550 0551 public function lastInsertId($tableName = null, $primaryKey = null, $idType = null) 0552 { 0553 $this->_connect(); 0554 0555 if ($this->_isI5) { 0556 return (string) $this->_i5LastInsertId($tableName, $idType); 0557 } 0558 0559 if ($tableName !== null) { 0560 $sequenceName = $tableName; 0561 if ($primaryKey) { 0562 $sequenceName .= "_$primaryKey"; 0563 } 0564 $sequenceName .= '_seq'; 0565 return $this->lastSequenceId($sequenceName); 0566 } 0567 0568 $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM SYSIBM.SYSDUMMY1'; 0569 $value = $this->fetchOne($sql); 0570 return (string) $value; 0571 } 0572 0573 /** 0574 * Begin a transaction. 0575 * 0576 * @return void 0577 */ 0578 protected function _beginTransaction() 0579 { 0580 $this->_setExecuteMode(DB2_AUTOCOMMIT_OFF); 0581 } 0582 0583 /** 0584 * Commit a transaction. 0585 * 0586 * @return void 0587 */ 0588 protected function _commit() 0589 { 0590 if (!db2_commit($this->_connection)) { 0591 /** 0592 * @see Zend_Db_Adapter_Db2_Exception 0593 */ 0594 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0595 throw new Zend_Db_Adapter_Db2_Exception( 0596 db2_conn_errormsg($this->_connection), 0597 db2_conn_error($this->_connection)); 0598 } 0599 0600 $this->_setExecuteMode(DB2_AUTOCOMMIT_ON); 0601 } 0602 0603 /** 0604 * Rollback a transaction. 0605 * 0606 * @return void 0607 */ 0608 protected function _rollBack() 0609 { 0610 if (!db2_rollback($this->_connection)) { 0611 /** 0612 * @see Zend_Db_Adapter_Db2_Exception 0613 */ 0614 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0615 throw new Zend_Db_Adapter_Db2_Exception( 0616 db2_conn_errormsg($this->_connection), 0617 db2_conn_error($this->_connection)); 0618 } 0619 $this->_setExecuteMode(DB2_AUTOCOMMIT_ON); 0620 } 0621 0622 /** 0623 * Set the fetch mode. 0624 * 0625 * @param integer $mode 0626 * @return void 0627 * @throws Zend_Db_Adapter_Db2_Exception 0628 */ 0629 public function setFetchMode($mode) 0630 { 0631 switch ($mode) { 0632 case Zend_Db::FETCH_NUM: // seq array 0633 case Zend_Db::FETCH_ASSOC: // assoc array 0634 case Zend_Db::FETCH_BOTH: // seq+assoc array 0635 case Zend_Db::FETCH_OBJ: // object 0636 $this->_fetchMode = $mode; 0637 break; 0638 case Zend_Db::FETCH_BOUND: // bound to PHP variable 0639 /** 0640 * @see Zend_Db_Adapter_Db2_Exception 0641 */ 0642 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0643 throw new Zend_Db_Adapter_Db2_Exception('FETCH_BOUND is not supported yet'); 0644 break; 0645 default: 0646 /** 0647 * @see Zend_Db_Adapter_Db2_Exception 0648 */ 0649 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0650 throw new Zend_Db_Adapter_Db2_Exception("Invalid fetch mode '$mode' specified"); 0651 break; 0652 } 0653 } 0654 0655 /** 0656 * Adds an adapter-specific LIMIT clause to the SELECT statement. 0657 * 0658 * @param string $sql 0659 * @param integer $count 0660 * @param integer $offset OPTIONAL 0661 * @return string 0662 */ 0663 public function limit($sql, $count, $offset = 0) 0664 { 0665 $count = intval($count); 0666 if ($count <= 0) { 0667 /** 0668 * @see Zend_Db_Adapter_Db2_Exception 0669 */ 0670 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0671 throw new Zend_Db_Adapter_Db2_Exception("LIMIT argument count=$count is not valid"); 0672 } 0673 0674 $offset = intval($offset); 0675 if ($offset < 0) { 0676 /** 0677 * @see Zend_Db_Adapter_Db2_Exception 0678 */ 0679 // require_once 'Zend/Db/Adapter/Db2/Exception.php'; 0680 throw new Zend_Db_Adapter_Db2_Exception("LIMIT argument offset=$offset is not valid"); 0681 } 0682 0683 if ($offset == 0) { 0684 $limit_sql = $sql . " FETCH FIRST $count ROWS ONLY"; 0685 return $limit_sql; 0686 } 0687 0688 /** 0689 * DB2 does not implement the LIMIT clause as some RDBMS do. 0690 * We have to simulate it with subqueries and ROWNUM. 0691 * Unfortunately because we use the column wildcard "*", 0692 * this puts an extra column into the query result set. 0693 */ 0694 $limit_sql = "SELECT z2.* 0695 FROM ( 0696 SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.* 0697 FROM ( 0698 " . $sql . " 0699 ) z1 0700 ) z2 0701 WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count); 0702 return $limit_sql; 0703 } 0704 0705 /** 0706 * Check if the adapter supports real SQL parameters. 0707 * 0708 * @param string $type 'positional' or 'named' 0709 * @return bool 0710 */ 0711 public function supportsParameters($type) 0712 { 0713 if ($type == 'positional') { 0714 return true; 0715 } 0716 0717 // if its 'named' or anything else 0718 return false; 0719 } 0720 0721 /** 0722 * Retrieve server version in PHP style 0723 * 0724 * @return string 0725 */ 0726 public function getServerVersion() 0727 { 0728 $this->_connect(); 0729 $server_info = db2_server_info($this->_connection); 0730 if ($server_info !== false) { 0731 $version = $server_info->DBMS_VER; 0732 if ($this->_isI5) { 0733 $version = (int) substr($version, 0, 2) . '.' . (int) substr($version, 2, 2) . '.' . (int) substr($version, 4); 0734 } 0735 return $version; 0736 } else { 0737 return null; 0738 } 0739 } 0740 0741 /** 0742 * Return whether or not this is running on i5 0743 * 0744 * @return bool 0745 */ 0746 public function isI5() 0747 { 0748 if ($this->_isI5 === null) { 0749 $this->_determineI5(); 0750 } 0751 0752 return (bool) $this->_isI5; 0753 } 0754 0755 /** 0756 * Check the connection parameters according to verify 0757 * type of used OS 0758 * 0759 * @return void 0760 */ 0761 protected function _determineI5() 0762 { 0763 // first us the compiled flag. 0764 $this->_isI5 = (php_uname('s') == 'OS400') ? true : false; 0765 0766 // if this is set, then us it 0767 if (isset($this->_config['os'])){ 0768 if (strtolower($this->_config['os']) === 'i5') { 0769 $this->_isI5 = true; 0770 } else { 0771 // any other value passed in, its null 0772 $this->_isI5 = false; 0773 } 0774 } 0775 0776 } 0777 0778 /** 0779 * Db2 On I5 specific method 0780 * 0781 * Returns a list of the tables in the database . 0782 * Used only for DB2/400. 0783 * 0784 * @return array 0785 */ 0786 protected function _i5listTables($schema = null) 0787 { 0788 //list of i5 libraries. 0789 $tables = array(); 0790 if ($schema) { 0791 $tablesStatement = db2_tables($this->_connection, null, $schema); 0792 while ($rowTables = db2_fetch_assoc($tablesStatement) ) { 0793 if ($rowTables['TABLE_NAME'] !== null) { 0794 $tables[] = $rowTables['TABLE_NAME']; 0795 } 0796 } 0797 } else { 0798 $schemaStatement = db2_tables($this->_connection); 0799 while ($schema = db2_fetch_assoc($schemaStatement)) { 0800 if ($schema['TABLE_SCHEM'] !== null) { 0801 // list of the tables which belongs to the selected library 0802 $tablesStatement = db2_tables($this->_connection, NULL, $schema['TABLE_SCHEM']); 0803 if (is_resource($tablesStatement)) { 0804 while ($rowTables = db2_fetch_assoc($tablesStatement) ) { 0805 if ($rowTables['TABLE_NAME'] !== null) { 0806 $tables[] = $rowTables['TABLE_NAME']; 0807 } 0808 } 0809 } 0810 } 0811 } 0812 } 0813 0814 return $tables; 0815 } 0816 0817 protected function _i5LastInsertId($objectName = null, $idType = null) 0818 { 0819 0820 if ($objectName === null) { 0821 $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM QSYS2.QSQPTABL'; 0822 $value = $this->fetchOne($sql); 0823 return $value; 0824 } 0825 0826 if (strtoupper($idType) === 'S'){ 0827 //check i5_lib option 0828 $sequenceName = $objectName; 0829 return $this->lastSequenceId($sequenceName); 0830 } 0831 0832 //returns last identity value for the specified table 0833 //if (strtoupper($idType) === 'I') { 0834 $tableName = $objectName; 0835 return $this->fetchOne('SELECT IDENTITY_VAL_LOCAL() from ' . $this->quoteIdentifier($tableName)); 0836 } 0837 0838 } 0839 0840