diff options
Diffstat (limited to 'library/vendor/Zend/Db/Adapter/Pdo')
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Abstract.php | 397 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Ibm.php | 354 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php | 224 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php | 297 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Mssql.php | 435 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Mysql.php | 269 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Oci.php | 375 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php | 333 | ||||
-rw-r--r-- | library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php | 305 |
9 files changed, 2989 insertions, 0 deletions
diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php b/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php new file mode 100644 index 0000000..3a0e13e --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php @@ -0,0 +1,397 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * @see Zend_Db_Adapter_Abstract + */ + + +/** + * @see Zend_Db_Statement_Pdo + */ + + +/** + * Class for connecting to SQL databases and performing common operations using PDO. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract +{ + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Pdo'; + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + // don't pass the username, password, charset, persistent and driver_options in the DSN + unset($dsn['username']); + unset($dsn['password']); + unset($dsn['options']); + unset($dsn['charset']); + unset($dsn['persistent']); + unset($dsn['driver_options']); + + // use all remaining parts in the DSN + foreach ($dsn as $key => $val) { + $dsn[$key] = "$key=$val"; + } + + return $this->_pdoType . ':' . implode(';', $dsn); + } + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + // if we already have a PDO object, no need to re-connect. + if ($this->_connection) { + return; + } + + // get the dsn first, because some adapters alter the $_pdoType + $dsn = $this->_dsn(); + + // check for PDO extension + if (!extension_loaded('pdo')) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); + } + + // check the PDO driver is available + if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The ' . $this->_pdoType . ' driver is not currently installed'); + } + + // create PDO connection + $q = $this->_profiler->queryStart('connect', Zend_Db_Profiler::CONNECT); + + // add the persistence flag if we find it in our config array + if (isset($this->_config['persistent']) && ($this->_config['persistent'] == true)) { + $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; + } + + try { + $this->_connection = new PDO( + $dsn, + $this->_config['username'], + $this->_config['password'], + $this->_config['driver_options'] + ); + + $this->_profiler->queryEnd($q); + + // set the PDO connection to perform case-folding on array keys, or not + $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding); + + // always use exceptions. + $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + } catch (PDOException $e) { + $message = $e->getMessage(); + if ($e->getPrevious() !== null && preg_match('~^SQLSTATE\[HY000\] \[\d{1,4}\]\s$~', $message)) { + // See https://bugs.php.net/bug.php?id=76604 + $message .= $e->getPrevious()->getMessage(); + } + + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($message, $e->getCode(), $e); + } + + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return ((bool) ($this->_connection instanceof PDO)); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + $this->_connection = null; + } + + /** + * Prepares an SQL statement. + * + * @param string $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return PDOStatement + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + if (!class_exists($stmtClass)) { + Zend_Loader::loadClass($stmtClass); + } + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * On RDBMS brands that don't support sequences, $tableName and $primaryKey + * are ignored. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $this->_connect(); + return $this->_connection->lastInsertId(); + } + + /** + * Special handling for PDO query(). + * All bind parameter names must begin with ':' + * + * @param string|Zend_Db_Select $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return Zend_Db_Statement_Pdo + * @throws Zend_Db_Adapter_Exception To re-throw PDOException. + */ + public function query($sql, $bind = array()) + { + if (empty($bind) && $sql instanceof Zend_Db_Select) { + $bind = $sql->getBind(); + } + + if (is_array($bind)) { + foreach ($bind as $name => $value) { + if (!is_int($name) && !preg_match('/^:/', $name)) { + $newName = ":$name"; + unset($bind[$name]); + $bind[$newName] = $value; + } + } + } + + try { + return parent::query($sql, $bind); + } catch (PDOException $e) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Executes an SQL statement and return the number of affected rows + * + * @param mixed $sql The SQL statement with placeholders. + * May be a string or Zend_Db_Select. + * @return integer Number of rows that were modified + * or deleted by the SQL statement + */ + public function exec($sql) + { + if ($sql instanceof Zend_Db_Select) { + $sql = $sql->assemble(); + } + + try { + $affected = $this->getConnection()->exec($sql); + + if ($affected === false) { + $errorInfo = $this->getConnection()->errorInfo(); + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($errorInfo[2]); + } + + return $affected; + } catch (PDOException $e) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if ($value === null) { + $value = ''; + } elseif (is_int($value) || is_float($value)) { + return $value; + } + $this->_connect(); + return $this->_connection->quote($value); + } + + /** + * Begin a transaction. + */ + protected function _beginTransaction() + { + $this->_connect(); + $this->_connection->beginTransaction(); + } + + /** + * Commit a transaction. + */ + protected function _commit() + { + $this->_connect(); + $this->_connection->commit(); + } + + /** + * Roll-back a transaction. + */ + protected function _rollBack() { + $this->_connect(); + $this->_connection->rollBack(); + } + + /** + * Set the PDO fetch mode. + * + * @todo Support FETCH_CLASS and FETCH_INTO. + * + * @param int $mode A PDO fetch mode. + * @return void + * @throws Zend_Db_Adapter_Exception + */ + public function setFetchMode($mode) + { + //check for PDO extension + if (!extension_loaded('pdo')) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); + } + switch ($mode) { + case PDO::FETCH_LAZY: + case PDO::FETCH_ASSOC: + case PDO::FETCH_NUM: + case PDO::FETCH_BOTH: + case PDO::FETCH_NAMED: + case PDO::FETCH_OBJ: + $this->_fetchMode = $mode; + break; + default: + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + switch ($type) { + case 'positional': + case 'named': + default: + return true; + } + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + try { + $version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION); + } catch (PDOException $e) { + // In case of the driver doesn't support getting attributes + return null; + } + $matches = null; + if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) { + return $matches[1]; + } else { + return null; + } + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Ibm.php b/library/vendor/Zend/Db/Adapter/Pdo/Ibm.php new file mode 100644 index 0000000..cfb11a3 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Ibm.php @@ -0,0 +1,354 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** @see Zend_Db_Adapter_Pdo_Abstract */ + +/** @see Zend_Db_Abstract_Pdo_Ibm_Db2 */ + +/** @see Zend_Db_Abstract_Pdo_Ibm_Ids */ + +/** @see Zend_Db_Statement_Pdo_Ibm */ + + +/** + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Ibm extends Zend_Db_Adapter_Pdo_Abstract +{ + /** + * PDO type. + * + * @var string + */ + protected $_pdoType = 'ibm'; + + /** + * The IBM data server connected to + * + * @var string + */ + protected $_serverType = null; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DEC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO object and connects to the database. + * + * The IBM data server is set. + * Current options are DB2 or IDS + * @todo also differentiate between z/OS and i/5 + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + public function _connect() + { + if ($this->_connection) { + return; + } + parent::_connect(); + + $this->getConnection()->setAttribute(Zend_Db::ATTR_STRINGIFY_FETCHES, true); + + try { + if ($this->_serverType === null) { + $server = substr($this->getConnection()->getAttribute(PDO::ATTR_SERVER_INFO), 0, 3); + + switch ($server) { + case 'DB2': + $this->_serverType = new Zend_Db_Adapter_Pdo_Ibm_Db2($this); + + // Add DB2-specific numeric types + $this->_numericDataTypes['DECFLOAT'] = Zend_Db::FLOAT_TYPE; + $this->_numericDataTypes['DOUBLE'] = Zend_Db::FLOAT_TYPE; + $this->_numericDataTypes['NUM'] = Zend_Db::FLOAT_TYPE; + + break; + case 'IDS': + $this->_serverType = new Zend_Db_Adapter_Pdo_Ibm_Ids($this); + + // Add IDS-specific numeric types + $this->_numericDataTypes['SERIAL'] = Zend_Db::INT_TYPE; + $this->_numericDataTypes['SERIAL8'] = Zend_Db::BIGINT_TYPE; + $this->_numericDataTypes['INT8'] = Zend_Db::BIGINT_TYPE; + $this->_numericDataTypes['SMALLFLOAT'] = Zend_Db::FLOAT_TYPE; + $this->_numericDataTypes['MONEY'] = Zend_Db::FLOAT_TYPE; + + break; + } + } + } catch (PDOException $e) { + /** @see Zend_Db_Adapter_Exception */ + $error = strpos($e->getMessage(), 'driver does not support that attribute'); + if ($error) { + throw new Zend_Db_Adapter_Exception("PDO_IBM driver extension is downlevel. Please use driver release version 1.2.1 or later", 0, $e); + } else { + throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); + } + } + } + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + $this->_checkRequiredOptions($this->_config); + + // check if using full connection string + if (array_key_exists('host', $this->_config)) { + $dsn = ';DATABASE=' . $this->_config['dbname'] + . ';HOSTNAME=' . $this->_config['host'] + . ';PORT=' . $this->_config['port'] + // PDO_IBM supports only DB2 TCPIP protocol + . ';PROTOCOL=' . 'TCPIP;'; + } else { + // catalogued connection + $dsn = $this->_config['dbname']; + } + return $this->_pdoType . ': ' . $dsn; + } + + /** + * Checks required options + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + * @return void + */ + protected function _checkRequiredOptions(array $config) + { + parent::_checkRequiredOptions($config); + + if (array_key_exists('host', $this->_config) && + !array_key_exists('port', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration must have a key for 'port' when 'host' is specified"); + } + } + + /** + * Prepares an SQL statement. + * + * @param string $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return PDOStatement + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $this->_connect(); + return $this->_serverType->listTables(); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $this->_connect(); + return $this->_serverType->describeTable($tableName, $schemaName); + } + + /** + * Inserts a table row with specified data. + * Special handling for PDO_IBM + * remove empty slots + * + * @param mixed $table The table to insert data into. + * @param array $bind Column-value pairs. + * @return int The number of affected rows. + */ + public function insert($table, array $bind) + { + $this->_connect(); + $newbind = array(); + if (is_array($bind)) { + foreach ($bind as $name => $value) { + if($value !== null) { + $newbind[$name] = $value; + } + } + } + + return parent::insert($table, $newbind); + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $this->_connect(); + return $this->_serverType->limit($sql, $count, $offset); + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT + * column. + * + * @param string $tableName OPTIONAL + * @param string $primaryKey OPTIONAL + * @return integer + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $this->_connect(); + + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + + $id = $this->getConnection()->lastInsertId(); + + return $id; + } + + /** + * Return the most recent value from the specified sequence in the database. + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + return $this->_serverType->lastSequenceId($sequenceName); + } + + /** + * Generate a new value from the specified sequence in the database, + * and return it. + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + return $this->_serverType->nextSequenceId($sequenceName); + } + + /** + * Retrieve server version in PHP style + * Pdo_Idm doesn't support getAttribute(PDO::ATTR_SERVER_VERSION) + * @return string + */ + public function getServerVersion() + { + try { + $stmt = $this->query('SELECT service_level, fixpack_num FROM TABLE (sysproc.env_get_inst_info()) as INSTANCEINFO'); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + if (count($result)) { + $matches = null; + if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $result[0][0], $matches)) { + return $matches[1]; + } else { + return null; + } + } + return null; + } catch (PDOException $e) { + return null; + } + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php new file mode 100644 index 0000000..1c11c8b --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php @@ -0,0 +1,224 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** @see Zend_Db_Adapter_Pdo_Ibm */ + +/** @see Zend_Db_Statement_Pdo_Ibm */ + + +/** + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Ibm_Db2 +{ + /** + * @var Zend_Db_Adapter_Abstract + */ + protected $_adapter = null; + + /** + * Construct the data server class. + * + * It will be used to generate non-generic SQL + * for a particular data server + * + * @param Zend_Db_Adapter_Abstract $adapter + */ + public function __construct($adapter) + { + $this->_adapter = $adapter; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT tabname " + . "FROM SYSCAT.TABLES "; + return $this->_adapter->fetchCol($sql); + } + + /** + * DB2 catalog lookup for describe table + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, + c.typename, c.default, c.nulls, c.length, c.scale, + c.identity, tc.type AS tabconsttype, k.colseq + FROM syscat.columns c + LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc + ON (k.tabschema = tc.tabschema + AND k.tabname = tc.tabname + AND tc.type = 'P')) + ON (c.tabschema = k.tabschema + AND c.tabname = k.tabname + AND c.colname = k.colname) + WHERE " + . $this->_adapter->quoteInto('UPPER(c.tabname) = UPPER(?)', $tableName); + if ($schemaName) { + $sql .= $this->_adapter->quoteInto(' AND UPPER(c.tabschema) = UPPER(?)', $schemaName); + } + $sql .= " ORDER BY c.colno"; + + $desc = array(); + $stmt = $this->_adapter->query($sql); + + /** + * To avoid case issues, fetch using FETCH_NUM + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + /** + * The ordering of columns is defined by the query so we can map + * to variables to improve readability + */ + $tabschema = 0; + $tabname = 1; + $colname = 2; + $colno = 3; + $typename = 4; + $default = 5; + $nulls = 6; + $length = 7; + $scale = 8; + $identityCol = 9; + $tabconstype = 10; + $colseq = 11; + + foreach ($result as $key => $row) { + list ($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$tabconstype] == 'P') { + $primary = true; + $primaryPosition = $row[$colseq]; + } + /** + * In IBM DB2, an column can be IDENTITY + * even if it is not part of the PRIMARY KEY. + */ + if ($row[$identityCol] == 'Y') { + $identity = true; + } + + $desc[$this->_adapter->foldCase($row[$colname])] = array( + 'SCHEMA_NAME' => $this->_adapter->foldCase($row[$tabschema]), + 'TABLE_NAME' => $this->_adapter->foldCase($row[$tabname]), + 'COLUMN_NAME' => $this->_adapter->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$colno]+1, + 'DATA_TYPE' => $row[$typename], + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) ($row[$nulls] == 'Y'), + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => ($row[$typename] == 'DECIMAL' ? $row[$length] : 0), + 'UNSIGNED' => false, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + + return $desc; + } + + /** + * Adds a DB2-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } else { + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + if ($offset == 0 && $count > 0) { + $limit_sql = $sql . " FETCH FIRST $count ROWS ONLY"; + return $limit_sql; + } + /** + * DB2 does not implement the LIMIT clause as some RDBMS do. + * We have to simulate it with subqueries and ROWNUM. + * Unfortunately because we use the column wildcard "*", + * this puts an extra column into the query result set. + */ + $limit_sql = "SELECT z2.* + FROM ( + SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.* + FROM ( + " . $sql . " + ) z1 + ) z2 + WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count); + } + return $limit_sql; + } + + /** + * DB2-specific last sequence id + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $sql = 'SELECT PREVVAL FOR '.$this->_adapter->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } + + /** + * DB2-specific sequence id value + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $sql = 'SELECT NEXTVAL FOR '.$this->_adapter->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php new file mode 100644 index 0000000..eeec43f --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php @@ -0,0 +1,297 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** @see Zend_Db_Adapter_Pdo_Ibm */ + +/** @see Zend_Db_Statement_Pdo_Ibm */ + + +/** + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Ibm_Ids +{ + /** + * @var Zend_Db_Adapter_Abstract + */ + protected $_adapter = null; + + /** + * Construct the data server class. + * + * It will be used to generate non-generic SQL + * for a particular data server + * + * @param Zend_Db_Adapter_Abstract $adapter + */ + public function __construct($adapter) + { + $this->_adapter = $adapter; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT tabname " + . "FROM systables "; + + return $this->_adapter->fetchCol($sql); + } + + /** + * IDS catalog lookup for describe table + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + // this is still a work in progress + + $sql= "SELECT DISTINCT t.owner, t.tabname, c.colname, c.colno, c.coltype, + d.default, c.collength, t.tabid + FROM syscolumns c + JOIN systables t ON c.tabid = t.tabid + LEFT JOIN sysdefaults d ON c.tabid = d.tabid AND c.colno = d.colno + WHERE " + . $this->_adapter->quoteInto('UPPER(t.tabname) = UPPER(?)', $tableName); + if ($schemaName) { + $sql .= $this->_adapter->quoteInto(' AND UPPER(t.owner) = UPPER(?)', $schemaName); + } + $sql .= " ORDER BY c.colno"; + + $desc = array(); + $stmt = $this->_adapter->query($sql); + + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + /** + * The ordering of columns is defined by the query so we can map + * to variables to improve readability + */ + $tabschema = 0; + $tabname = 1; + $colname = 2; + $colno = 3; + $typename = 4; + $default = 5; + $length = 6; + $tabid = 7; + + $primaryCols = null; + + foreach ($result as $key => $row) { + $primary = false; + $primaryPosition = null; + + if (!$primaryCols) { + $primaryCols = $this->_getPrimaryInfo($row[$tabid]); + } + + if (array_key_exists($row[$colno], $primaryCols)) { + $primary = true; + $primaryPosition = $primaryCols[$row[$colno]]; + } + + $identity = false; + if ($row[$typename] == 6 + 256 || + $row[$typename] == 18 + 256) { + $identity = true; + } + + $desc[$this->_adapter->foldCase($row[$colname])] = array ( + 'SCHEMA_NAME' => $this->_adapter->foldCase($row[$tabschema]), + 'TABLE_NAME' => $this->_adapter->foldCase($row[$tabname]), + 'COLUMN_NAME' => $this->_adapter->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$colno], + 'DATA_TYPE' => $this->_getDataType($row[$typename]), + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) !($row[$typename] - 256 >= 0), + 'LENGTH' => $row[$length], + 'SCALE' => ($row[$typename] == 5 ? $row[$length]&255 : 0), + 'PRECISION' => ($row[$typename] == 5 ? (int)($row[$length]/256) : 0), + 'UNSIGNED' => false, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + + return $desc; + } + + /** + * Map number representation of a data type + * to a string + * + * @param int $typeNo + * @return string + */ + protected function _getDataType($typeNo) + { + $typemap = array( + 0 => "CHAR", + 1 => "SMALLINT", + 2 => "INTEGER", + 3 => "FLOAT", + 4 => "SMALLFLOAT", + 5 => "DECIMAL", + 6 => "SERIAL", + 7 => "DATE", + 8 => "MONEY", + 9 => "NULL", + 10 => "DATETIME", + 11 => "BYTE", + 12 => "TEXT", + 13 => "VARCHAR", + 14 => "INTERVAL", + 15 => "NCHAR", + 16 => "NVARCHAR", + 17 => "INT8", + 18 => "SERIAL8", + 19 => "SET", + 20 => "MULTISET", + 21 => "LIST", + 22 => "Unnamed ROW", + 40 => "Variable-length opaque type", + 4118 => "Named ROW" + ); + + if ($typeNo - 256 >= 0) { + $typeNo = $typeNo - 256; + } + + return $typemap[$typeNo]; + } + + /** + * Helper method to retrieve primary key column + * and column location + * + * @param int $tabid + * @return array + */ + protected function _getPrimaryInfo($tabid) + { + $sql = "SELECT i.part1, i.part2, i.part3, i.part4, i.part5, i.part6, + i.part7, i.part8, i.part9, i.part10, i.part11, i.part12, + i.part13, i.part14, i.part15, i.part16 + FROM sysindexes i + JOIN sysconstraints c ON c.idxname = i.idxname + WHERE i.tabid = " . $tabid . " AND c.constrtype = 'P'"; + + $stmt = $this->_adapter->query($sql); + $results = $stmt->fetchAll(); + + $cols = array(); + + // this should return only 1 row + // unless there is no primary key, + // in which case, the empty array is returned + if ($results) { + $row = $results[0]; + } else { + return $cols; + } + + $position = 0; + foreach ($row as $key => $colno) { + $position++; + if ($colno == 0) { + return $cols; + } else { + $cols[$colno] = $position; + } + } + } + + /** + * Adds an IDS-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } else if ($count == 0) { + $limit_sql = str_ireplace("SELECT", "SELECT * FROM (SELECT", $sql); + $limit_sql .= ") WHERE 0 = 1"; + } else { + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + if ($offset == 0) { + $limit_sql = str_ireplace("SELECT", "SELECT FIRST $count", $sql); + } else { + $limit_sql = str_ireplace("SELECT", "SELECT SKIP $offset LIMIT $count", $sql); + } + } + return $limit_sql; + } + + /** + * IDS-specific last sequence id + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $sql = 'SELECT '.$this->_adapter->quoteIdentifier($sequenceName).'.CURRVAL FROM ' + .'systables WHERE tabid = 1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } + + /** + * IDS-specific sequence id value + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $sql = 'SELECT '.$this->_adapter->quoteIdentifier($sequenceName).'.NEXTVAL FROM ' + .'systables WHERE tabid = 1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Mssql.php b/library/vendor/Zend/Db/Adapter/Pdo/Mssql.php new file mode 100644 index 0000000..7c7c1cd --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Mssql.php @@ -0,0 +1,435 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * @see Zend_Db_Adapter_Pdo_Abstract + */ + + +/** + * Class for connecting to Microsoft SQL Server databases and performing common operations. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Mssql extends Zend_Db_Adapter_Pdo_Abstract +{ + /** + * PDO type. + * + * @var string + */ + protected $_pdoType = 'mssql'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE, + 'MONEY' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE, + 'SMALLMONEY' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + // don't pass the username and password in the DSN + unset($dsn['username']); + unset($dsn['password']); + unset($dsn['options']); + unset($dsn['persistent']); + unset($dsn['driver_options']); + + if (isset($dsn['port'])) { + $seperator = ':'; + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $seperator = ','; + } + $dsn['host'] .= $seperator . $dsn['port']; + unset($dsn['port']); + } + + // this driver supports multiple DSN prefixes + // @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php + if (isset($dsn['pdoType'])) { + switch (strtolower($dsn['pdoType'])) { + case 'freetds': + case 'sybase': + $this->_pdoType = 'sybase'; + break; + case 'mssql': + $this->_pdoType = 'mssql'; + break; + case 'dblib': + default: + $this->_pdoType = 'dblib'; + break; + } + unset($dsn['pdoType']); + } + + // use all remaining parts in the DSN + foreach ($dsn as $key => $val) { + $dsn[$key] = "$key=$val"; + } + + $dsn = $this->_pdoType . ':' . implode(';', $dsn); + return $dsn; + } + + /** + * @return void + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + parent::_connect(); + $this->_connection->exec('SET QUOTED_IDENTIFIER ON'); + } + + /** + * Begin a transaction. + * + * It is necessary to override the abstract PDO transaction functions here, as + * the PDO driver for MSSQL does not support transactions. + */ + protected function _beginTransaction() + { + $this->_connect(); + $this->_connection->exec('BEGIN TRANSACTION'); + return true; + } + + /** + * Commit a transaction. + * + * It is necessary to override the abstract PDO transaction functions here, as + * the PDO driver for MSSQL does not support transactions. + */ + protected function _commit() + { + $this->_connect(); + $this->_connection->exec('COMMIT TRANSACTION'); + return true; + } + + /** + * Roll-back a transaction. + * + * It is necessary to override the abstract PDO transaction functions here, as + * the PDO driver for MSSQL does not support transactions. + */ + protected function _rollBack() { + $this->_connect(); + $this->_connection->exec('ROLLBACK TRANSACTION'); + return true; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * PRIMARY_AUTO => integer; position of auto-generated column in primary key + * + * @todo Discover column primary key position. + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + if ($schemaName != null) { + if (strpos($schemaName, '.') !== false) { + $result = explode('.', $schemaName); + $schemaName = $result[1]; + } + } + /** + * Discover metadata information about this table. + */ + $sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true); + if ($schemaName != null) { + $sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true); + } + + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $table_name = 2; + $column_name = 3; + $type_name = 5; + $precision = 6; + $length = 7; + $scale = 8; + $nullable = 10; + $column_def = 12; + $column_position = 16; + + /** + * Discover primary key column(s) for this table. + */ + $sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true); + if ($schemaName != null) { + $sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true); + } + + $stmt = $this->query($sql); + $primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM); + $primaryKeyColumn = array(); + $pkey_column_name = 3; + $pkey_key_seq = 4; + foreach ($primaryKeysResult as $pkeysRow) { + $primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq]; + } + + $desc = array(); + $p = 1; + foreach ($result as $key => $row) { + $identity = false; + $words = explode(' ', $row[$type_name], 2); + if (isset($words[0])) { + $type = $words[0]; + if (isset($words[1])) { + $identity = (bool) preg_match('/identity/', $words[1]); + } + } + + $isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn); + if ($isPrimary) { + $primaryPosition = $primaryKeyColumn[$row[$column_name]]; + } else { + $primaryPosition = null; + } + + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => (int) $row[$column_position], + 'DATA_TYPE' => $type, + 'DEFAULT' => $row[$column_def], + 'NULLABLE' => (bool) $row[$nullable], + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => $row[$precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $isPrimary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql = preg_replace( + '/^SELECT\s+(DISTINCT\s)?/i', + 'SELECT $1TOP ' . ($count+$offset) . ' ', + $sql + ); + + if ($offset > 0) { + $orderby = stristr($sql, 'ORDER BY'); + + if ($orderby !== false) { + $orderParts = explode(',', substr($orderby, 8)); + $pregReplaceCount = null; + $orderbyInverseParts = array(); + foreach ($orderParts as $orderPart) { + $orderPart = rtrim($orderPart); + $inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount); + if ($pregReplaceCount) { + $orderbyInverseParts[] = $inv; + continue; + } + $inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount); + if ($pregReplaceCount) { + $orderbyInverseParts[] = $inv; + continue; + } else { + $orderbyInverseParts[] = $orderPart . ' DESC'; + } + } + + $orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts); + } + + + + + $sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl'; + if ($orderby !== false) { + $sql .= ' ' . $orderbyInverse . ' '; + } + $sql .= ') AS outer_tbl'; + if ($orderby !== false) { + $sql .= ' ' . $orderby; + } + } + + return $sql; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * Microsoft SQL Server does not support sequences, so the arguments to + * this method are ignored. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + * @throws Zend_Db_Adapter_Exception + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $sql = 'SELECT SCOPE_IDENTITY()'; + return (int)$this->fetchOne($sql); + } + + /** + * Retrieve server version in PHP style + * Pdo_Mssql doesn't support getAttribute(PDO::ATTR_SERVER_VERSION) + * @return string + */ + public function getServerVersion() + { + try { + $stmt = $this->query("SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR)"); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + if (count($result)) { + return $result[0][0]; + } + return null; + } catch (PDOException $e) { + return null; + } + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (!is_int($value) && !is_float($value)) { + // Fix for null-byte injection + $value = addcslashes($value, "\000\032"); + } + return parent::_quote($value); + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php b/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php new file mode 100644 index 0000000..951d665 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php @@ -0,0 +1,269 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * @see Zend_Db_Adapter_Pdo_Abstract + */ + + +/** + * Class for connecting to MySQL databases and performing common operations. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Abstract +{ + + /** + * PDO type. + * + * @var string + */ + protected $_pdoType = 'mysql'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'MEDIUMINT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'SERIAL' => Zend_Db::BIGINT_TYPE, + 'DEC' => Zend_Db::FLOAT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'FIXED' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE + ); + + /** + * Override _dsn() and ensure that charset is incorporated in mysql + * @see Zend_Db_Adapter_Pdo_Abstract::_dsn() + */ + protected function _dsn() + { + $dsn = parent::_dsn(); + if (isset($this->_config['charset'])) { + $dsn .= ';charset=' . $this->_config['charset']; + } + return $dsn; + } + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + if (!empty($this->_config['charset']) + && version_compare(PHP_VERSION, '5.3.6', '<') + ) { + $initCommand = "SET NAMES '" . $this->_config['charset'] . "'"; + $this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND + } + + parent::_connect(); + } + + /** + * @return string + */ + public function getQuoteIdentifierSymbol() + { + return "`"; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + return $this->fetchCol('SHOW TABLES'); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + // @todo use INFORMATION_SCHEMA someday when MySQL's + // implementation has reasonably good performance and + // the version with this improvement is in wide use. + + if ($schemaName) { + $sql = 'DESCRIBE ' . $this->quoteIdentifier("$schemaName.$tableName", true); + } else { + $sql = 'DESCRIBE ' . $this->quoteIdentifier($tableName, true); + } + $stmt = $this->query($sql); + + // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $field = 0; + $type = 1; + $null = 2; + $key = 3; + $default = 4; + $extra = 5; + + $desc = array(); + $i = 1; + $p = 1; + foreach ($result as $row) { + list($length, $scale, $precision, $unsigned, $primary, $primaryPosition, $identity) + = array(null, null, null, null, false, null, false); + if (preg_match('/unsigned/', $row[$type])) { + $unsigned = true; + } + if (preg_match('/^((?:var)?char)\((\d+)\)/', $row[$type], $matches)) { + $row[$type] = $matches[1]; + $length = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/', $row[$type], $matches)) { + $row[$type] = 'decimal'; + $precision = $matches[1]; + $scale = $matches[2]; + } else if (preg_match('/^float\((\d+),(\d+)\)/', $row[$type], $matches)) { + $row[$type] = 'float'; + $precision = $matches[1]; + $scale = $matches[2]; + } else if (preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row[$type], $matches)) { + $row[$type] = $matches[1]; + // The optional argument of a MySQL int type is not precision + // or length; it is only a hint for display width. + } + if (strtoupper($row[$key]) == 'PRI') { + $primary = true; + $primaryPosition = $p; + if ($row[$extra] == 'auto_increment') { + $identity = true; + } else { + $identity = false; + } + ++$p; + } + $desc[$this->foldCase($row[$field])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row[$field]), + 'COLUMN_POSITION' => $i, + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) ($row[$null] == 'YES'), + 'LENGTH' => $length, + 'SCALE' => $scale, + 'PRECISION' => $precision, + 'UNSIGNED' => $unsigned, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + ++$i; + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Oci.php b/library/vendor/Zend/Db/Adapter/Pdo/Oci.php new file mode 100644 index 0000000..eb4e6fc --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Oci.php @@ -0,0 +1,375 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * @see Zend_Db_Adapter_Pdo_Abstract + */ + + +/** + * Class for connecting to Oracle databases and performing common operations. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Oci extends Zend_Db_Adapter_Pdo_Abstract +{ + + /** + * PDO type. + * + * @var string + */ + protected $_pdoType = 'oci'; + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Pdo_Oci'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'BINARY_DOUBLE' => Zend_Db::FLOAT_TYPE, + 'BINARY_FLOAT' => Zend_Db::FLOAT_TYPE, + 'NUMBER' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + if (isset($dsn['host'])) { + $tns = 'dbname=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' . + '(HOST=' . $dsn['host'] . ')'; + + if (isset($dsn['port'])) { + $tns .= '(PORT=' . $dsn['port'] . ')'; + } else { + $tns .= '(PORT=1521)'; + } + + $tns .= '))(CONNECT_DATA=(SID=' . $dsn['dbname'] . ')))'; + } else { + $tns = 'dbname=' . $dsn['dbname']; + } + + if (isset($dsn['charset'])) { + $tns .= ';charset=' . $dsn['charset']; + } + + return $this->_pdoType . ':' . $tns; + } + + /** + * Quote a raw string. + * Most PDO drivers have an implementation for the quote() method, + * but the Oracle OCI driver must use the same implementation as the + * Zend_Db_Adapter_Abstract class. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value) || is_float($value)) { + return $value; + } + $value = str_replace("'", "''", $value); + return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + } + + /** + * Quote a table identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the table. + * @return string The quoted identifier and alias. + */ + public function quoteTableAs($ident, $alias = null, $auto = false) + { + // Oracle doesn't allow the 'AS' keyword between the table identifier/expression and alias. + return $this->_quoteIdentifierAs($ident, $alias, $auto, ' '); + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $data = $this->fetchCol('SELECT table_name FROM all_tables'); + return $data; + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $version = $this->getServerVersion(); + if (($version === null) || version_compare($version, '9.0.0', '>=')) { + $sql = "SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE, + TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH, + TC.DATA_SCALE, TC.DATA_PRECISION, C.CONSTRAINT_TYPE, CC.POSITION + FROM ALL_TAB_COLUMNS TC + LEFT JOIN (ALL_CONS_COLUMNS CC JOIN ALL_CONSTRAINTS C + ON (CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME AND CC.TABLE_NAME = C.TABLE_NAME AND CC.OWNER = C.OWNER AND C.CONSTRAINT_TYPE = 'P')) + ON TC.TABLE_NAME = CC.TABLE_NAME AND TC.COLUMN_NAME = CC.COLUMN_NAME + WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME)"; + $bind[':TBNAME'] = $tableName; + if ($schemaName) { + $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)'; + $bind[':SCNAME'] = $schemaName; + } + $sql .= ' ORDER BY TC.COLUMN_ID'; + } else { + $subSql="SELECT AC.OWNER, AC.TABLE_NAME, ACC.COLUMN_NAME, AC.CONSTRAINT_TYPE, ACC.POSITION + from ALL_CONSTRAINTS AC, ALL_CONS_COLUMNS ACC + WHERE ACC.CONSTRAINT_NAME = AC.CONSTRAINT_NAME + AND ACC.TABLE_NAME = AC.TABLE_NAME + AND ACC.OWNER = AC.OWNER + AND AC.CONSTRAINT_TYPE = 'P' + AND UPPER(AC.TABLE_NAME) = UPPER(:TBNAME)"; + $bind[':TBNAME'] = $tableName; + if ($schemaName) { + $subSql .= ' AND UPPER(ACC.OWNER) = UPPER(:SCNAME)'; + $bind[':SCNAME'] = $schemaName; + } + $sql="SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE, + TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH, + TC.DATA_SCALE, TC.DATA_PRECISION, CC.CONSTRAINT_TYPE, CC.POSITION + FROM ALL_TAB_COLUMNS TC, ($subSql) CC + WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME) + AND TC.OWNER = CC.OWNER(+) AND TC.TABLE_NAME = CC.TABLE_NAME(+) AND TC.COLUMN_NAME = CC.COLUMN_NAME(+)"; + if ($schemaName) { + $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)'; + } + $sql .= ' ORDER BY TC.COLUMN_ID'; + } + + $stmt = $this->query($sql, $bind); + + /** + * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $table_name = 0; + $owner = 1; + $column_name = 2; + $data_type = 3; + $data_default = 4; + $nullable = 5; + $column_id = 6; + $data_length = 7; + $data_scale = 8; + $data_precision = 9; + $constraint_type = 10; + $position = 11; + + $desc = array(); + foreach ($result as $key => $row) { + list ($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$constraint_type] == 'P') { + $primary = true; + $primaryPosition = $row[$position]; + /** + * Oracle does not support auto-increment keys. + */ + $identity = false; + } + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$owner]), + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => $row[$column_id], + 'DATA_TYPE' => $row[$data_type], + 'DEFAULT' => $row[$data_default], + 'NULLABLE' => (bool) ($row[$nullable] == 'Y'), + 'LENGTH' => $row[$data_length], + 'SCALE' => $row[$data_scale], + 'PRECISION' => $row[$data_precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $value = $this->fetchOne('SELECT '.$this->quoteIdentifier($sequenceName, true).'.CURRVAL FROM dual'); + return $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $value = $this->fetchOne('SELECT '.$this->quoteIdentifier($sequenceName, true).'.NEXTVAL FROM dual'); + return $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * Oracle does not support IDENTITY columns, so if the sequence is not + * specified, this method returns null. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + * @throws Zend_Db_Adapter_Oracle_Exception + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= $this->foldCase("_$primaryKey"); + } + $sequenceName .= $this->foldCase('_seq'); + return $this->lastSequenceId($sequenceName); + } + // No support for IDENTITY columns; return null + return null; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + /** + * Oracle does not implement the LIMIT clause as some RDBMS do. + * We have to simulate it with subqueries and ROWNUM. + * Unfortunately because we use the column wildcard "*", + * this puts an extra column into the query result set. + */ + $limit_sql = "SELECT z2.* + FROM ( + SELECT z1.*, ROWNUM AS \"zend_db_rownum\" + FROM ( + " . $sql . " + ) z1 + ) z2 + WHERE z2.\"zend_db_rownum\" BETWEEN " . ($offset+1) . " AND " . ($offset+$count); + return $limit_sql; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php b/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php new file mode 100644 index 0000000..060ed28 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php @@ -0,0 +1,333 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * @see Zend_Db_Adapter_Pdo_Abstract + */ + + +/** + * Class for connecting to PostgreSQL databases and performing common operations. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Pgsql extends Zend_Db_Adapter_Pdo_Abstract +{ + + /** + * PDO type. + * + * @var string + */ + protected $_pdoType = 'pgsql'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'SERIAL' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'BIGSERIAL' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + parent::_connect(); + + if (!empty($this->_config['charset'])) { + $sql = "SET NAMES '" . $this->_config['charset'] . "'"; + $this->_connection->exec($sql); + } + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + // @todo use a better query with joins instead of subqueries + $sql = "SELECT c.relname AS table_name " + . "FROM pg_class c, pg_user u " + . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' " + . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " + . "AND c.relname !~ '^(pg_|sql_)' " + . "UNION " + . "SELECT c.relname AS table_name " + . "FROM pg_class c " + . "WHERE c.relkind = 'r' " + . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " + . "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) " + . "AND c.relname !~ '^pg_'"; + + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = "SELECT + a.attnum, + n.nspname, + c.relname, + a.attname AS colname, + t.typname AS type, + a.atttypmod, + FORMAT_TYPE(a.atttypid, a.atttypmod) AS complete_type, + d.adsrc AS default_value, + a.attnotnull AS notnull, + a.attlen AS length, + co.contype, + ARRAY_TO_STRING(co.conkey, ',') AS conkey + FROM pg_attribute AS a + JOIN pg_class AS c ON a.attrelid = c.oid + JOIN pg_namespace AS n ON c.relnamespace = n.oid + JOIN pg_type AS t ON a.atttypid = t.oid + LEFT OUTER JOIN pg_constraint AS co ON (co.conrelid = c.oid + AND a.attnum = ANY(co.conkey) AND co.contype = 'p') + LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum + WHERE a.attnum > 0 AND c.relname = ".$this->quote($tableName); + if ($schemaName) { + $sql .= " AND n.nspname = ".$this->quote($schemaName); + } + $sql .= ' ORDER BY a.attnum'; + + $stmt = $this->query($sql); + + // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $attnum = 0; + $nspname = 1; + $relname = 2; + $colname = 3; + $type = 4; + $atttypemod = 5; + $complete_type = 6; + $default_value = 7; + $notnull = 8; + $length = 9; + $contype = 10; + $conkey = 11; + + $desc = array(); + foreach ($result as $key => $row) { + $defaultValue = $row[$default_value]; + if ($row[$type] == 'varchar' || $row[$type] == 'bpchar' ) { + if (preg_match('/character(?: varying)?(?:\((\d+)\))?/', $row[$complete_type], $matches)) { + if (isset($matches[1])) { + $row[$length] = $matches[1]; + } else { + $row[$length] = null; // unlimited + } + } + if (preg_match("/^'(.*?)'::(?:character varying|bpchar)$/", $defaultValue, $matches)) { + $defaultValue = $matches[1]; + } + } + list($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$contype] == 'p') { + $primary = true; + $primaryPosition = array_search($row[$attnum], explode(',', $row[$conkey])) + 1; + $identity = (bool) (preg_match('/^nextval/', $row[$default_value])); + } + $desc[$this->foldCase($row[$colname])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$nspname]), + 'TABLE_NAME' => $this->foldCase($row[$relname]), + 'COLUMN_NAME' => $this->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$attnum], + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $defaultValue, + 'NULLABLE' => (bool) ($row[$notnull] != 't'), + 'LENGTH' => $row[$length], + 'SCALE' => null, // @todo + 'PRECISION' => null, // @todo + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $sequenceName = str_replace($this->getQuoteIdentifierSymbol(), '', (string) $sequenceName); + $value = $this->fetchOne("SELECT CURRVAL(" + . $this->quote($this->quoteIdentifier($sequenceName, true)) + . ")"); + return $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $sequenceName = str_replace($this->getQuoteIdentifierSymbol(), '', (string) $sequenceName); + $value = $this->fetchOne("SELECT NEXTVAL(" + . $this->quote($this->quoteIdentifier($sequenceName, true)) + . ")"); + return $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + return $this->_connection->lastInsertId($tableName); + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php b/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php new file mode 100644 index 0000000..6453339 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php @@ -0,0 +1,305 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * @see Zend_Db_Adapter_Pdo_Abstract + */ + + +/** + * Class for connecting to SQLite2 and SQLite3 databases and performing common operations. + * + * @category Zend + * @package Zend_Db + * @subpackage Adapter + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Db_Adapter_Pdo_Sqlite extends Zend_Db_Adapter_Pdo_Abstract +{ + + /** + * PDO type + * + * @var string + */ + protected $_pdoType = 'sqlite'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::BIGINT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE + ); + + /** + * Constructor. + * + * $config is an array of key/value pairs containing configuration + * options. Note that the SQLite options are different than most of + * the other PDO adapters in that no username or password are needed. + * Also, an extra config key "sqlite2" specifies compatibility mode. + * + * dbname => (string) The name of the database to user (required, + * use :memory: for memory-based database) + * + * sqlite2 => (boolean) PDO_SQLITE defaults to SQLite 3. For compatibility + * with an older SQLite 2 database, set this to TRUE. + * + * @param array $config An array of configuration keys. + */ + public function __construct(array $config = array()) + { + if (isset($config['sqlite2']) && $config['sqlite2']) { + $this->_pdoType = 'sqlite2'; + } + + // SQLite uses no username/password. Stub to satisfy parent::_connect() + $this->_config['username'] = null; + $this->_config['password'] = null; + + return parent::__construct($config); + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + } + + /** + * DSN builder + */ + protected function _dsn() + { + return $this->_pdoType .':'. $this->_config['dbname']; + } + + /** + * Special configuration for SQLite behavior: make sure that result sets + * contain keys like 'column' instead of 'table.column'. + * + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + /** + * if we already have a PDO object, no need to re-connect. + */ + if ($this->_connection) { + return; + } + + parent::_connect(); + + $retval = $this->_connection->exec('PRAGMA full_column_names=0'); + if ($retval === false) { + $error = $this->_connection->errorInfo(); + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception($error[2]); + } + + $retval = $this->_connection->exec('PRAGMA short_column_names=1'); + if ($retval === false) { + $error = $this->_connection->errorInfo(); + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception($error[2]); + } + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"; + + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = 'PRAGMA '; + + if ($schemaName) { + $sql .= $this->quoteIdentifier($schemaName) . '.'; + } + + $sql .= 'table_info('.$this->quoteIdentifier($tableName).')'; + + $stmt = $this->query($sql); + + /** + * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $cid = 0; + $name = 1; + $type = 2; + $notnull = 3; + $dflt_value = 4; + $pk = 5; + + $desc = array(); + + $p = 1; + foreach ($result as $key => $row) { + list($length, $scale, $precision, $primary, $primaryPosition, $identity) = + array(null, null, null, false, null, false); + if (preg_match('/^((?:var)?char)\((\d+)\)/i', $row[$type], $matches)) { + $row[$type] = $matches[1]; + $length = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/i', $row[$type], $matches)) { + $row[$type] = 'DECIMAL'; + $precision = $matches[1]; + $scale = $matches[2]; + } + if ((bool) $row[$pk]) { + $primary = true; + $primaryPosition = $p; + /** + * SQLite INTEGER primary key is always auto-increment. + */ + $identity = (bool) ($row[$type] == 'INTEGER'); + ++$p; + } + $desc[$this->foldCase($row[$name])] = array( + 'SCHEMA_NAME' => $this->foldCase($schemaName), + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row[$name]), + 'COLUMN_POSITION' => $row[$cid]+1, + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $row[$dflt_value], + 'NULLABLE' => ! (bool) $row[$notnull], + 'LENGTH' => $length, + 'SCALE' => $scale, + 'PRECISION' => $precision, + 'UNSIGNED' => null, // Sqlite3 does not support unsigned data + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (!is_int($value) && !is_float($value)) { + // Fix for null-byte injection + $value = addcslashes($value, "\000\032"); + } + return parent::_quote($value); + } +} |