File indexing completed on 2025-01-19 05:21:01
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 /** @see Zend_Db_Adapter_Pdo_Ibm */ 0025 // require_once 'Zend/Db/Adapter/Pdo/Ibm.php'; 0026 0027 /** @see Zend_Db_Statement_Pdo_Ibm */ 0028 // require_once 'Zend/Db/Statement/Pdo/Ibm.php'; 0029 0030 0031 /** 0032 * @category Zend 0033 * @package Zend_Db 0034 * @subpackage Adapter 0035 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0036 * @license http://framework.zend.com/license/new-bsd New BSD License 0037 */ 0038 class Zend_Db_Adapter_Pdo_Ibm_Db2 0039 { 0040 /** 0041 * @var Zend_Db_Adapter_Abstract 0042 */ 0043 protected $_adapter = null; 0044 0045 /** 0046 * Construct the data server class. 0047 * 0048 * It will be used to generate non-generic SQL 0049 * for a particular data server 0050 * 0051 * @param Zend_Db_Adapter_Abstract $adapter 0052 */ 0053 public function __construct($adapter) 0054 { 0055 $this->_adapter = $adapter; 0056 } 0057 0058 /** 0059 * Returns a list of the tables in the database. 0060 * 0061 * @return array 0062 */ 0063 public function listTables() 0064 { 0065 $sql = "SELECT tabname " 0066 . "FROM SYSCAT.TABLES "; 0067 return $this->_adapter->fetchCol($sql); 0068 } 0069 0070 /** 0071 * DB2 catalog lookup for describe table 0072 * 0073 * @param string $tableName 0074 * @param string $schemaName OPTIONAL 0075 * @return array 0076 */ 0077 public function describeTable($tableName, $schemaName = null) 0078 { 0079 $sql = "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, 0080 c.typename, c.default, c.nulls, c.length, c.scale, 0081 c.identity, tc.type AS tabconsttype, k.colseq 0082 FROM syscat.columns c 0083 LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc 0084 ON (k.tabschema = tc.tabschema 0085 AND k.tabname = tc.tabname 0086 AND tc.type = 'P')) 0087 ON (c.tabschema = k.tabschema 0088 AND c.tabname = k.tabname 0089 AND c.colname = k.colname) 0090 WHERE " 0091 . $this->_adapter->quoteInto('UPPER(c.tabname) = UPPER(?)', $tableName); 0092 if ($schemaName) { 0093 $sql .= $this->_adapter->quoteInto(' AND UPPER(c.tabschema) = UPPER(?)', $schemaName); 0094 } 0095 $sql .= " ORDER BY c.colno"; 0096 0097 $desc = array(); 0098 $stmt = $this->_adapter->query($sql); 0099 0100 /** 0101 * To avoid case issues, fetch using FETCH_NUM 0102 */ 0103 $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); 0104 0105 /** 0106 * The ordering of columns is defined by the query so we can map 0107 * to variables to improve readability 0108 */ 0109 $tabschema = 0; 0110 $tabname = 1; 0111 $colname = 2; 0112 $colno = 3; 0113 $typename = 4; 0114 $default = 5; 0115 $nulls = 6; 0116 $length = 7; 0117 $scale = 8; 0118 $identityCol = 9; 0119 $tabconstype = 10; 0120 $colseq = 11; 0121 0122 foreach ($result as $key => $row) { 0123 list ($primary, $primaryPosition, $identity) = array(false, null, false); 0124 if ($row[$tabconstype] == 'P') { 0125 $primary = true; 0126 $primaryPosition = $row[$colseq]; 0127 } 0128 /** 0129 * In IBM DB2, an column can be IDENTITY 0130 * even if it is not part of the PRIMARY KEY. 0131 */ 0132 if ($row[$identityCol] == 'Y') { 0133 $identity = true; 0134 } 0135 0136 $desc[$this->_adapter->foldCase($row[$colname])] = array( 0137 'SCHEMA_NAME' => $this->_adapter->foldCase($row[$tabschema]), 0138 'TABLE_NAME' => $this->_adapter->foldCase($row[$tabname]), 0139 'COLUMN_NAME' => $this->_adapter->foldCase($row[$colname]), 0140 'COLUMN_POSITION' => $row[$colno]+1, 0141 'DATA_TYPE' => $row[$typename], 0142 'DEFAULT' => $row[$default], 0143 'NULLABLE' => (bool) ($row[$nulls] == 'Y'), 0144 'LENGTH' => $row[$length], 0145 'SCALE' => $row[$scale], 0146 'PRECISION' => ($row[$typename] == 'DECIMAL' ? $row[$length] : 0), 0147 'UNSIGNED' => false, 0148 'PRIMARY' => $primary, 0149 'PRIMARY_POSITION' => $primaryPosition, 0150 'IDENTITY' => $identity 0151 ); 0152 } 0153 0154 return $desc; 0155 } 0156 0157 /** 0158 * Adds a DB2-specific LIMIT clause to the SELECT statement. 0159 * 0160 * @param string $sql 0161 * @param integer $count 0162 * @param integer $offset OPTIONAL 0163 * @throws Zend_Db_Adapter_Exception 0164 * @return string 0165 */ 0166 public function limit($sql, $count, $offset = 0) 0167 { 0168 $count = intval($count); 0169 if ($count < 0) { 0170 /** @see Zend_Db_Adapter_Exception */ 0171 // require_once 'Zend/Db/Adapter/Exception.php'; 0172 throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); 0173 } else { 0174 $offset = intval($offset); 0175 if ($offset < 0) { 0176 /** @see Zend_Db_Adapter_Exception */ 0177 // require_once 'Zend/Db/Adapter/Exception.php'; 0178 throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); 0179 } 0180 0181 if ($offset == 0 && $count > 0) { 0182 $limit_sql = $sql . " FETCH FIRST $count ROWS ONLY"; 0183 return $limit_sql; 0184 } 0185 /** 0186 * DB2 does not implement the LIMIT clause as some RDBMS do. 0187 * We have to simulate it with subqueries and ROWNUM. 0188 * Unfortunately because we use the column wildcard "*", 0189 * this puts an extra column into the query result set. 0190 */ 0191 $limit_sql = "SELECT z2.* 0192 FROM ( 0193 SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.* 0194 FROM ( 0195 " . $sql . " 0196 ) z1 0197 ) z2 0198 WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count); 0199 } 0200 return $limit_sql; 0201 } 0202 0203 /** 0204 * DB2-specific last sequence id 0205 * 0206 * @param string $sequenceName 0207 * @return integer 0208 */ 0209 public function lastSequenceId($sequenceName) 0210 { 0211 $sql = 'SELECT PREVVAL FOR '.$this->_adapter->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; 0212 $value = $this->_adapter->fetchOne($sql); 0213 return $value; 0214 } 0215 0216 /** 0217 * DB2-specific sequence id value 0218 * 0219 * @param string $sequenceName 0220 * @return integer 0221 */ 0222 public function nextSequenceId($sequenceName) 0223 { 0224 $sql = 'SELECT NEXTVAL FOR '.$this->_adapter->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; 0225 $value = $this->_adapter->fetchOne($sql); 0226 return $value; 0227 } 0228 }