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 }