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_Adapter_Pdo_Abstract 0026 */ 0027 // require_once 'Zend/Db/Adapter/Pdo/Abstract.php'; 0028 0029 0030 /** 0031 * Class for connecting to SQLite2 and SQLite3 databases and performing common operations. 0032 * 0033 * @category Zend 0034 * @package Zend_Db 0035 * @subpackage Adapter 0036 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0037 * @license http://framework.zend.com/license/new-bsd New BSD License 0038 */ 0039 class Zend_Db_Adapter_Pdo_Sqlite extends Zend_Db_Adapter_Pdo_Abstract 0040 { 0041 0042 /** 0043 * PDO type 0044 * 0045 * @var string 0046 */ 0047 protected $_pdoType = 'sqlite'; 0048 0049 /** 0050 * Keys are UPPERCASE SQL datatypes or the constants 0051 * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. 0052 * 0053 * Values are: 0054 * 0 = 32-bit integer 0055 * 1 = 64-bit integer 0056 * 2 = float or decimal 0057 * 0058 * @var array Associative array of datatypes to values 0, 1, or 2. 0059 */ 0060 protected $_numericDataTypes = array( 0061 Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, 0062 Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, 0063 Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, 0064 'INTEGER' => Zend_Db::BIGINT_TYPE, 0065 'REAL' => Zend_Db::FLOAT_TYPE 0066 ); 0067 0068 /** 0069 * Constructor. 0070 * 0071 * $config is an array of key/value pairs containing configuration 0072 * options. Note that the SQLite options are different than most of 0073 * the other PDO adapters in that no username or password are needed. 0074 * Also, an extra config key "sqlite2" specifies compatibility mode. 0075 * 0076 * dbname => (string) The name of the database to user (required, 0077 * use :memory: for memory-based database) 0078 * 0079 * sqlite2 => (boolean) PDO_SQLITE defaults to SQLite 3. For compatibility 0080 * with an older SQLite 2 database, set this to TRUE. 0081 * 0082 * @param array $config An array of configuration keys. 0083 */ 0084 public function __construct(array $config = array()) 0085 { 0086 if (isset($config['sqlite2']) && $config['sqlite2']) { 0087 $this->_pdoType = 'sqlite2'; 0088 } 0089 0090 // SQLite uses no username/password. Stub to satisfy parent::_connect() 0091 $this->_config['username'] = null; 0092 $this->_config['password'] = null; 0093 0094 return parent::__construct($config); 0095 } 0096 0097 /** 0098 * Check for config options that are mandatory. 0099 * Throw exceptions if any are missing. 0100 * 0101 * @param array $config 0102 * @throws Zend_Db_Adapter_Exception 0103 */ 0104 protected function _checkRequiredOptions(array $config) 0105 { 0106 // we need at least a dbname 0107 if (! array_key_exists('dbname', $config)) { 0108 /** @see Zend_Db_Adapter_Exception */ 0109 // require_once 'Zend/Db/Adapter/Exception.php'; 0110 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); 0111 } 0112 } 0113 0114 /** 0115 * DSN builder 0116 */ 0117 protected function _dsn() 0118 { 0119 return $this->_pdoType .':'. $this->_config['dbname']; 0120 } 0121 0122 /** 0123 * Special configuration for SQLite behavior: make sure that result sets 0124 * contain keys like 'column' instead of 'table.column'. 0125 * 0126 * @throws Zend_Db_Adapter_Exception 0127 */ 0128 protected function _connect() 0129 { 0130 /** 0131 * if we already have a PDO object, no need to re-connect. 0132 */ 0133 if ($this->_connection) { 0134 return; 0135 } 0136 0137 parent::_connect(); 0138 0139 $retval = $this->_connection->exec('PRAGMA full_column_names=0'); 0140 if ($retval === false) { 0141 $error = $this->_connection->errorInfo(); 0142 /** @see Zend_Db_Adapter_Exception */ 0143 // require_once 'Zend/Db/Adapter/Exception.php'; 0144 throw new Zend_Db_Adapter_Exception($error[2]); 0145 } 0146 0147 $retval = $this->_connection->exec('PRAGMA short_column_names=1'); 0148 if ($retval === false) { 0149 $error = $this->_connection->errorInfo(); 0150 /** @see Zend_Db_Adapter_Exception */ 0151 // require_once 'Zend/Db/Adapter/Exception.php'; 0152 throw new Zend_Db_Adapter_Exception($error[2]); 0153 } 0154 } 0155 0156 /** 0157 * Returns a list of the tables in the database. 0158 * 0159 * @return array 0160 */ 0161 public function listTables() 0162 { 0163 $sql = "SELECT name FROM sqlite_master WHERE type='table' " 0164 . "UNION ALL SELECT name FROM sqlite_temp_master " 0165 . "WHERE type='table' ORDER BY name"; 0166 0167 return $this->fetchCol($sql); 0168 } 0169 0170 /** 0171 * Returns the column descriptions for a table. 0172 * 0173 * The return value is an associative array keyed by the column name, 0174 * as returned by the RDBMS. 0175 * 0176 * The value of each array element is an associative array 0177 * with the following keys: 0178 * 0179 * SCHEMA_NAME => string; name of database or schema 0180 * TABLE_NAME => string; 0181 * COLUMN_NAME => string; column name 0182 * COLUMN_POSITION => number; ordinal position of column in table 0183 * DATA_TYPE => string; SQL datatype name of column 0184 * DEFAULT => string; default expression of column, null if none 0185 * NULLABLE => boolean; true if column can have nulls 0186 * LENGTH => number; length of CHAR/VARCHAR 0187 * SCALE => number; scale of NUMERIC/DECIMAL 0188 * PRECISION => number; precision of NUMERIC/DECIMAL 0189 * UNSIGNED => boolean; unsigned property of an integer type 0190 * PRIMARY => boolean; true if column is part of the primary key 0191 * PRIMARY_POSITION => integer; position of column in primary key 0192 * IDENTITY => integer; true if column is auto-generated with unique values 0193 * 0194 * @param string $tableName 0195 * @param string $schemaName OPTIONAL 0196 * @return array 0197 */ 0198 public function describeTable($tableName, $schemaName = null) 0199 { 0200 $sql = 'PRAGMA '; 0201 0202 if ($schemaName) { 0203 $sql .= $this->quoteIdentifier($schemaName) . '.'; 0204 } 0205 0206 $sql .= 'table_info('.$this->quoteIdentifier($tableName).')'; 0207 0208 $stmt = $this->query($sql); 0209 0210 /** 0211 * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection 0212 */ 0213 $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); 0214 0215 $cid = 0; 0216 $name = 1; 0217 $type = 2; 0218 $notnull = 3; 0219 $dflt_value = 4; 0220 $pk = 5; 0221 0222 $desc = array(); 0223 0224 $p = 1; 0225 foreach ($result as $key => $row) { 0226 list($length, $scale, $precision, $primary, $primaryPosition, $identity) = 0227 array(null, null, null, false, null, false); 0228 if (preg_match('/^((?:var)?char)\((\d+)\)/i', $row[$type], $matches)) { 0229 $row[$type] = $matches[1]; 0230 $length = $matches[2]; 0231 } else if (preg_match('/^decimal\((\d+),(\d+)\)/i', $row[$type], $matches)) { 0232 $row[$type] = 'DECIMAL'; 0233 $precision = $matches[1]; 0234 $scale = $matches[2]; 0235 } 0236 if ((bool) $row[$pk]) { 0237 $primary = true; 0238 $primaryPosition = $p; 0239 /** 0240 * SQLite INTEGER primary key is always auto-increment. 0241 */ 0242 $identity = (bool) ($row[$type] == 'INTEGER'); 0243 ++$p; 0244 } 0245 $desc[$this->foldCase($row[$name])] = array( 0246 'SCHEMA_NAME' => $this->foldCase($schemaName), 0247 'TABLE_NAME' => $this->foldCase($tableName), 0248 'COLUMN_NAME' => $this->foldCase($row[$name]), 0249 'COLUMN_POSITION' => $row[$cid]+1, 0250 'DATA_TYPE' => $row[$type], 0251 'DEFAULT' => $row[$dflt_value], 0252 'NULLABLE' => ! (bool) $row[$notnull], 0253 'LENGTH' => $length, 0254 'SCALE' => $scale, 0255 'PRECISION' => $precision, 0256 'UNSIGNED' => null, // Sqlite3 does not support unsigned data 0257 'PRIMARY' => $primary, 0258 'PRIMARY_POSITION' => $primaryPosition, 0259 'IDENTITY' => $identity 0260 ); 0261 } 0262 return $desc; 0263 } 0264 0265 /** 0266 * Adds an adapter-specific LIMIT clause to the SELECT statement. 0267 * 0268 * @param string $sql 0269 * @param integer $count 0270 * @param integer $offset OPTIONAL 0271 * @return string 0272 */ 0273 public function limit($sql, $count, $offset = 0) 0274 { 0275 $count = intval($count); 0276 if ($count <= 0) { 0277 /** @see Zend_Db_Adapter_Exception */ 0278 // require_once 'Zend/Db/Adapter/Exception.php'; 0279 throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); 0280 } 0281 0282 $offset = intval($offset); 0283 if ($offset < 0) { 0284 /** @see Zend_Db_Adapter_Exception */ 0285 // require_once 'Zend/Db/Adapter/Exception.php'; 0286 throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); 0287 } 0288 0289 $sql .= " LIMIT $count"; 0290 if ($offset > 0) { 0291 $sql .= " OFFSET $offset"; 0292 } 0293 0294 return $sql; 0295 } 0296 0297 /** 0298 * Quote a raw string. 0299 * 0300 * @param string $value Raw string 0301 * @return string Quoted string 0302 */ 0303 protected function _quote($value) 0304 { 0305 if (!is_int($value) && !is_float($value)) { 0306 // Fix for null-byte injection 0307 $value = addcslashes($value, "\000\032"); 0308 } 0309 return parent::_quote($value); 0310 } 0311 }