/wp-includes/library/Varien/Db/Adapter/Pdo/Mysql.php
PHP | 3586 lines | 3339 code | 47 blank | 200 comment | 34 complexity | 49cec4cf8aa903eb9c4cff6bb26d7934 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * Magento
- *
- * NOTICE OF LICENSE
- *
- * This source file is subject to the Open Software License (OSL 3.0)
- * that is bundled with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://opensource.org/licenses/osl-3.0.php
- * 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@magentocommerce.com so we can send you a copy immediately.
- *
- * DISCLAIMER
- *
- * Do not edit or add to this file if you wish to upgrade Magento to newer
- * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category Varien
- * @package Varien_Db
- * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
- */
- /**
- * Mysql PDO DB adapter
- */
- class Varien_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Mysql implements Varien_Db_Adapter_Interface
- {
- const DEBUG_CONNECT = 0;
- const DEBUG_TRANSACTION = 1;
- const DEBUG_QUERY = 2;
- const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
- const DATETIME_FORMAT = 'Y-m-d H:i:s';
- const DATE_FORMAT = 'Y-m-d';
- const DDL_DESCRIBE = 1;
- const DDL_CREATE = 2;
- const DDL_INDEX = 3;
- const DDL_FOREIGN_KEY = 4;
- const DDL_CACHE_PREFIX = 'DB_PDO_MYSQL_DDL';
- const DDL_CACHE_TAG = 'DB_PDO_MYSQL_DDL';
- const LENGTH_TABLE_NAME = 64;
- const LENGTH_INDEX_NAME = 64;
- const LENGTH_FOREIGN_NAME = 64;
- /**
- * Default class name for a DB statement.
- *
- * @var string
- */
- protected $_defaultStmtClass = 'Varien_Db_Statement_Pdo_Mysql';
- /**
- * Current Transaction Level
- *
- * @var int
- */
- protected $_transactionLevel = 0;
- /**
- * Set attribute to connection flag
- *
- * @var bool
- */
- protected $_connectionFlagsSet = false;
- /**
- * Tables DDL cache
- *
- * @var array
- */
- protected $_ddlCache = array();
- /**
- * SQL bind params. Used temporarily by regexp callback.
- *
- * @var array
- */
- protected $_bindParams = array();
- /**
- * Autoincrement for bind value. Used by regexp callback.
- *
- * @var int
- */
- protected $_bindIncrement = 0;
- /**
- * Write SQL debug data to file
- *
- * @var bool
- */
- protected $_debug = false;
- /**
- * Minimum query duration time to be logged
- *
- * @var float
- */
- protected $_logQueryTime = 0.05;
- /**
- * Log all queries (ignored minimum query duration time)
- *
- * @var bool
- */
- protected $_logAllQueries = false;
- /**
- * Add to log call stack data (backtrace)
- *
- * @var bool
- */
- protected $_logCallStack = false;
- /**
- * Path to SQL debug data log
- *
- * @var string
- */
- protected $_debugFile = 'var/debug/pdo_mysql.log';
- /**
- * Io File Adapter
- *
- * @var Varien_Io_File
- */
- protected $_debugIoAdapter;
- /**
- * Debug timer start value
- *
- * @var float
- */
- protected $_debugTimer = 0;
- /**
- * Cache frontend adapter instance
- *
- * @var Zend_Cache_Core
- */
- protected $_cacheAdapter;
- /**
- * DDL cache allowing flag
- * @var bool
- */
- protected $_isDdlCacheAllowed = true;
- /**
- * MySQL column - Table DDL type pairs
- *
- * @var array
- */
- protected $_ddlColumnTypes = array(
- Varien_Db_Ddl_Table::TYPE_BOOLEAN => 'bool',
- Varien_Db_Ddl_Table::TYPE_SMALLINT => 'smallint',
- Varien_Db_Ddl_Table::TYPE_INTEGER => 'int',
- Varien_Db_Ddl_Table::TYPE_BIGINT => 'bigint',
- Varien_Db_Ddl_Table::TYPE_FLOAT => 'float',
- Varien_Db_Ddl_Table::TYPE_DECIMAL => 'decimal',
- Varien_Db_Ddl_Table::TYPE_NUMERIC => 'decimal',
- Varien_Db_Ddl_Table::TYPE_DATE => 'date',
- Varien_Db_Ddl_Table::TYPE_TIMESTAMP => 'timestamp',
- Varien_Db_Ddl_Table::TYPE_DATETIME => 'datetime',
- Varien_Db_Ddl_Table::TYPE_TEXT => 'text',
- Varien_Db_Ddl_Table::TYPE_BLOB => 'blob',
- Varien_Db_Ddl_Table::TYPE_VARBINARY => 'blob'
- );
- /**
- * Allowed interval units array
- *
- * @var array
- */
- protected $_intervalUnits = array(
- self::INTERVAL_YEAR => 'YEAR',
- self::INTERVAL_MONTH => 'MONTH',
- self::INTERVAL_DAY => 'DAY',
- self::INTERVAL_HOUR => 'HOUR',
- self::INTERVAL_MINUTE => 'MINUTE',
- self::INTERVAL_SECOND => 'SECOND',
- );
- /**
- * Hook callback to modify queries. Mysql specific property, designed only for backwards compatibility.
- *
- * @var array|null
- */
- protected $_queryHook = null;
- /**
- * Begin new DB transaction for connection
- *
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function beginTransaction()
- {
- if ($this->_transactionLevel === 0) {
- $this->_debugTimer();
- parent::beginTransaction();
- $this->_debugStat(self::DEBUG_TRANSACTION, 'BEGIN');
- }
- ++$this->_transactionLevel;
- return $this;
- }
- /**
- * Commit DB transaction
- *
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function commit()
- {
- if ($this->_transactionLevel === 1) {
- $this->_debugTimer();
- parent::commit();
- $this->_debugStat(self::DEBUG_TRANSACTION, 'COMMIT');
- }
- --$this->_transactionLevel;
- return $this;
- }
- /**
- * Rollback DB transaction
- *
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function rollback()
- {
- if ($this->_transactionLevel === 1) {
- $this->_debugTimer();
- parent::rollback();
- $this->_debugStat(self::DEBUG_TRANSACTION, 'ROLLBACK');
- }
- --$this->_transactionLevel;
- return $this;
- }
- /**
- * Get adapter transaction level state. Return 0 if all transactions are complete
- *
- * @return int
- */
- public function getTransactionLevel()
- {
- return $this->_transactionLevel;
- }
- /**
- * Convert date to DB format
- *
- * @param mixed $date
- * @return string
- */
- public function convertDate($date)
- {
- return $this->formatDate($date, false);
- }
- /**
- * Convert date and time to DB format
- *
- * @param mixed $date
- * @return string
- */
- public function convertDateTime($datetime)
- {
- return $this->formatDate($datetime, true);
- }
- /**
- * Creates a PDO object and connects to the database.
- *
- * @throws Zend_Db_Adapter_Exception
- */
- protected function _connect()
- {
- if ($this->_connection) {
- return;
- }
- if (!extension_loaded('pdo_mysql')) {
- throw new Zend_Db_Adapter_Exception('pdo_mysql extension is not installed');
- }
- if (strpos($this->_config['host'], '/') !== false) {
- $this->_config['unix_socket'] = $this->_config['host'];
- unset($this->_config['host']);
- } else if (strpos($this->_config['host'], ':') !== false) {
- list($this->_config['host'], $this->_config['port']) = explode(':', $this->_config['host']);
- }
- $this->_debugTimer();
- parent::_connect();
- $this->_debugStat(self::DEBUG_CONNECT, '');
- /** @link http://bugs.mysql.com/bug.php?id=18551 */
- $this->_connection->query("SET SQL_MODE=''");
- if (!$this->_connectionFlagsSet) {
- $this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
- $this->_connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
- $this->_connectionFlagsSet = true;
- }
- }
- /**
- * Run RAW Query
- *
- * @param string $sql
- * @return Zend_Db_Statement_Interface
- * @throws PDOException
- */
- public function raw_query($sql)
- {
- $lostConnectionMessage = 'SQLSTATE[HY000]: General error: 2013 Lost connection to MySQL server during query';
- $tries = 0;
- do {
- $retry = false;
- try {
- $result = $this->query($sql);
- } catch (Exception $e) {
- // Convert to PDOException to maintain backwards compatibility with usage of MySQL adapter
- if ($e instanceof Zend_Db_Statement_Exception) {
- $e = $e->getPrevious();
- if (!($e instanceof PDOException)) {
- $e = new PDOException($e->getMessage(), $e->getCode());
- }
- }
- // Check to reconnect
- if ($tries < 10 && $e->getMessage() == $lostConnectionMessage) {
- $retry = true;
- $tries++;
- } else {
- throw $e;
- }
- }
- } while ($retry);
- return $result;
- }
- /**
- * Run RAW query and Fetch First row
- *
- * @param string $sql
- * @param string|int $field
- * @return boolean
- */
- public function raw_fetchRow($sql, $field = null)
- {
- $result = $this->raw_query($sql);
- if (!$result) {
- return false;
- }
- $row = $result->fetch(PDO::FETCH_ASSOC);
- if (!$row) {
- return false;
- }
- if (empty($field)) {
- return $row;
- } else {
- return isset($row[$field]) ? $row[$field] : false;
- }
- }
- /**
- * Special handling for PDO query().
- * All bind parameter names must begin with ':'.
- *
- * @param string|Zend_Db_Select $sql The SQL statement with placeholders.
- * @param mixed $bind An array of data or data itself to bind to the placeholders.
- * @return Zend_Db_Pdo_Statement
- * @throws Zend_Db_Adapter_Exception To re-throw PDOException.
- */
- public function query($sql, $bind = array())
- {
- $this->_debugTimer();
- try {
- $this->_prepareQuery($sql, $bind);
- $result = parent::query($sql, $bind);
- } catch (Exception $e) {
- $this->_debugStat(self::DEBUG_QUERY, $sql, $bind);
- $this->_debugException($e);
- }
- $this->_debugStat(self::DEBUG_QUERY, $sql, $bind, $result);
- return $result;
- }
- /**
- * Prepares SQL query by moving to bind all special parameters that can be confused with bind placeholders
- * (e.g. "foo:bar"). And also changes named bind to positional one, because underlying library has problems
- * with named binds.
- *
- * @param Zend_Db_Select|string $sql
- * @param mixed $bind
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- protected function _prepareQuery(&$sql, &$bind = array())
- {
- $sql = (string) $sql;
- if (!is_array($bind)) {
- $bind = array($bind);
- }
- // Mixed bind is not supported - so remember whether it is named bind, to normalize later if required
- $isNamedBind = false;
- if ($bind) {
- foreach ($bind as $k => $v) {
- if (!is_int($k)) {
- $isNamedBind = true;
- if ($k[0] != ':') {
- $bind[":{$k}"] = $v;
- unset($bind[$k]);
- }
- }
- }
- }
- if (strpos($sql, ':') !== false || strpos($sql, '?') !== false) {
- $before = count($bind);
- $this->_bindParams = $bind; // Used by callback
- $sql = preg_replace_callback('#(([\'"])((\\2)|((.*?[^\\\\])\\2)))#',
- array($this, 'proccessBindCallback'),
- $sql);
- Varien_Exception::processPcreError();
- $bind = $this->_bindParams;
- // If _processBindCallbacks() has added named entries to positional bind - normalize it to positional
- if (!$isNamedBind && $before && (count($bind) != $before)) {
- $this->_convertMixedBind($sql, $bind);
- }
- }
- // Special query hook
- if ($this->_queryHook) {
- $object = $this->_queryHook['object'];
- $method = $this->_queryHook['method'];
- $object->$method($sql, $bind);
- }
- return $this;
- }
- /**
- * Callback function for preparation of query and bind by regexp.
- * Checks query parameters for special symbols and moves such parameters to bind array as named ones.
- * This method writes to $_bindParams, where query bind parameters are kept.
- * This method requires further normalizing, if bind array is positional.
- *
- * @param array $matches
- * @return string
- */
- public function proccessBindCallback($matches)
- {
- if (isset($matches[6]) && (
- strpos($matches[6], "'") !== false ||
- strpos($matches[6], ':') !== false ||
- strpos($matches[6], '?') !== false)
- ) {
- $bindName = ':_mage_bind_var_' . (++$this->_bindIncrement);
- $this->_bindParams[$bindName] = $this->_unQuote($matches[6]);
- return ' ' . $bindName;
- }
- return $matches[0];
- }
- /**
- * Unquote raw string (use for auto-bind)
- *
- * @param string $string
- * @return string
- */
- protected function _unQuote($string)
- {
- $translate = array(
- "\\000" => "\000",
- "\\n" => "\n",
- "\\r" => "\r",
- "\\\\" => "\\",
- "\'" => "'",
- "\\\"" => "\"",
- "\\032" => "\032"
- );
- return strtr($string, $translate);
- }
- /**
- * Normalizes mixed positional-named bind to positional bind, and replaces named placeholders in query to
- * '?' placeholders.
- *
- * @param string $sql
- * @param array $bind
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- protected function _convertMixedBind(&$sql, &$bind)
- {
- $positions = array();
- $offset = 0;
- // get positions
- while (true) {
- $pos = strpos($sql, '?', $offset);
- if ($pos !== false) {
- $positions[] = $pos;
- $offset = ++$pos;
- } else {
- break;
- }
- }
- $bindResult = array();
- $map = array();
- foreach ($bind as $k => $v) {
- // positional
- if (is_int($k)) {
- if (!isset($positions[$k])) {
- continue;
- }
- $bindResult[$positions[$k]] = $v;
- } else {
- $offset = 0;
- while (true) {
- $pos = strpos($sql, $k, $offset);
- if ($pos === false) {
- break;
- } else {
- $offset = $pos + strlen($k);
- $bindResult[$pos] = $v;
- }
- }
- $map[$k] = '?';
- }
- }
- ksort($bindResult);
- $bind = array_values($bindResult);
- $sql = strtr($sql, $map);
- return $this;
- }
- /**
- * Sets (removes) query hook.
- *
- * $hook must be either array with 'object' and 'method' entries, or null to remove hook.
- * Previous hook is returned.
- *
- * @param array $hook
- * @return mixed
- */
- public function setQueryHook($hook)
- {
- $prev = $this->_queryHook;
- $this->_queryHook = $hook;
- return $prev;
- }
- /**
- * Executes a SQL statement(s)
- *
- * @param string $sql
- * @throws Zend_Db_Exception
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function multiQuery($sql)
- {
- return $this->multi_query($sql);
- }
- /**
- * Run Multi Query
- *
- * @param string $sql
- * @return array
- */
- public function multi_query($sql)
- {
- ##$result = $this->raw_query($sql);
- #$this->beginTransaction();
- try {
- $stmts = $this->_splitMultiQuery($sql);
- $result = array();
- foreach ($stmts as $stmt) {
- $result[] = $this->raw_query($stmt);
- }
- #$this->commit();
- } catch (Exception $e) {
- #$this->rollback();
- throw $e;
- }
- $this->resetDdlCache();
- return $result;
- }
- /**
- * Split multi statement query
- *
- * @param $sql string
- * @return array
- */
- protected function _splitMultiQuery($sql)
- {
- $parts = preg_split('#(;|\'|"|\\\\|//|--|\n|/\*|\*/)#', $sql, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
- $q = false;
- $c = false;
- $stmts = array();
- $s = '';
- foreach ($parts as $i => $part) {
- // strings
- if (($part === "'" || $part === '"') && ($i === 0 || $parts[$i-1] !== '\\')) {
- if ($q === false) {
- $q = $part;
- } elseif ($q === $part) {
- $q = false;
- }
- }
- // single line comments
- if (($part === '//' || $part === '--') && ($i === 0 || $parts[$i-1] === "\n")) {
- $c = $part;
- } elseif ($part === "\n" && ($c === '//' || $c === '--')) {
- $c = false;
- }
- // multi line comments
- if ($part === '/*' && $c === false) {
- $c = '/*';
- } elseif ($part === '*/' && $c === '/*') {
- $c = false;
- }
- // statements
- if ($part === ';' && $q === false && $c === false) {
- if (trim($s)!=='') {
- $stmts[] = trim($s);
- $s = '';
- }
- } else {
- $s .= $part;
- }
- }
- if (trim($s) !== '') {
- $stmts[] = trim($s);
- }
- return $stmts;
- }
- /**
- * Drop the Foreign Key from table
- *
- * @param string $tableName
- * @param string $fkName
- * @param string $schemaName
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function dropForeignKey($tableName, $fkName, $schemaName = null)
- {
- $foreignKeys = $this->getForeignKeys($tableName, $schemaName);
- $fkName = strtoupper($fkName);
- if (substr($fkName, 0, 3) == 'FK_') {
- $fkName = substr($fkName, 3);
- }
- foreach (array($fkName, 'FK_' . $fkName) as $key) {
- if (isset($foreignKeys[$key])) {
- $sql = sprintf('ALTER TABLE %s DROP FOREIGN KEY %s',
- $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
- $this->quoteIdentifier($foreignKeys[$key]['FK_NAME'])
- );
- $this->resetDdlCache($tableName, $schemaName);
- $this->raw_query($sql);
- }
- }
- return $this;
- }
- /**
- * Delete index from a table if it exists
- *
- * @deprecated since 1.4.0.1
- * @param string $tableName
- * @param string $keyName
- * @param string $schemaName
- * @return bool|Zend_Db_Statement_Interface
- */
- public function dropKey($tableName, $keyName, $schemaName = null)
- {
- return $this->dropIndex($tableName, $keyName, $schemaName);
- }
- /**
- * Prepare table before add constraint foreign key
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $refTableName
- * @param string $refColumnName
- * @param string $onDelete
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function purgeOrphanRecords($tableName, $columnName, $refTableName, $refColumnName,
- $onDelete = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE)
- {
- $onDelete = strtoupper($onDelete);
- if ($onDelete == Varien_Db_Adapter_Interface::FK_ACTION_CASCADE
- || $onDelete == Varien_Db_Adapter_Interface::FK_ACTION_RESTRICT
- ) {
- $sql = sprintf("DELETE p.* FROM %s AS p LEFT JOIN %s AS r ON p.%s = r.%s WHERE r.%s IS NULL",
- $this->quoteIdentifier($tableName),
- $this->quoteIdentifier($refTableName),
- $this->quoteIdentifier($columnName),
- $this->quoteIdentifier($refColumnName),
- $this->quoteIdentifier($refColumnName));
- $this->raw_query($sql);
- } elseif ($onDelete == Varien_Db_Adapter_Interface::FK_ACTION_SET_NULL) {
- $sql = sprintf("UPDATE %s AS p LEFT JOIN %s AS r ON p.%s = r.%s SET p.%s = NULL WHERE r.%s IS NULL",
- $this->quoteIdentifier($tableName),
- $this->quoteIdentifier($refTableName),
- $this->quoteIdentifier($columnName),
- $this->quoteIdentifier($refColumnName),
- $this->quoteIdentifier($columnName),
- $this->quoteIdentifier($refColumnName));
- $this->raw_query($sql);
- }
- return $this;
- }
- /**
- * Add foreign key to table. If FK with same name exist - it will be deleted
- *
- * @deprecated since 1.4.0.1
- * @param string $fkName foreign key name
- * @param string $tableName main table name
- * @param string $keyName main table field name
- * @param string $refTableName refered table name
- * @param string $refKeyName refered table field name
- * @param string $onUpdate on update statement
- * @param string $onDelete on delete statement
- * @param bool $purge
- * @return mixed
- */
- public function addConstraint($fkName, $tableName, $columnName,
- $refTableName, $refColumnName, $onDelete = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE,
- $onUpdate = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE, $purge = false)
- {
- return $this->addForeignKey($fkName, $tableName, $columnName, $refTableName, $refColumnName,
- $onDelete, $onUpdate, $purge);
- }
- /**
- * Check does table column exist
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $schemaName
- * @return boolean
- */
- public function tableColumnExists($tableName, $columnName, $schemaName = null)
- {
- $describe = $this->describeTable($tableName, $schemaName);
- foreach ($describe as $column) {
- if ($column['COLUMN_NAME'] == $columnName) {
- return true;
- }
- }
- return false;
- }
- /**
- * Adds new column to table.
- *
- * Generally $defintion must be array with column data to keep this call cross-DB compatible.
- * Using string as $definition is allowed only for concrete DB adapter.
- * Adds primary key if needed
- *
- * @param string $tableName
- * @param string $columnName
- * @param array|string $definition string specific or universal array DB Server definition
- * @param string $schemaName
- * @return int|boolean
- * @throws Zend_Db_Exception
- */
- public function addColumn($tableName, $columnName, $definition, $schemaName = null)
- {
- if ($this->tableColumnExists($tableName, $columnName, $schemaName)) {
- return true;
- }
- $primaryKey = '';
- if (is_array($definition)) {
- $definition = array_change_key_case($definition, CASE_UPPER);
- if (empty($definition['COMMENT'])) {
- throw new Zend_Db_Exception("Impossible to create a column without comment.");
- }
- if (!empty($definition['PRIMARY'])) {
- $primaryKey = sprintf(', ADD PRIMARY KEY (%s)', $this->quoteIdentifier($columnName));
- }
- $definition = $this->_getColumnDefinition($definition);
- }
- $sql = sprintf('ALTER TABLE %s ADD COLUMN %s %s %s',
- $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
- $this->quoteIdentifier($columnName),
- $definition,
- $primaryKey
- );
- $result = $this->raw_query($sql);
- $this->resetDdlCache($tableName, $schemaName);
- return $result;
- }
- /**
- * Delete table column
- *
- * @param string $tableName
- * @param string $columnName
- * @param string $schemaName
- * @return bool
- */
- public function dropColumn($tableName, $columnName, $schemaName = null)
- {
- if (!$this->tableColumnExists($tableName, $columnName, $schemaName)) {
- return true;
- }
- $alterDrop = array();
- $foreignKeys = $this->getForeignKeys($tableName, $schemaName);
- foreach ($foreignKeys as $fkProp) {
- if ($fkProp['COLUMN_NAME'] == $columnName) {
- $alterDrop[] = 'DROP FOREIGN KEY ' . $this->quoteIdentifier($fkProp['FK_NAME']);
- }
- }
- $alterDrop[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName);
- $sql = sprintf('ALTER TABLE %s %s',
- $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
- implode(', ', $alterDrop));
- $result = $this->raw_query($sql);
- $this->resetDdlCache($tableName, $schemaName);
- return $result;
- }
- /**
- * Change the column name and definition
- *
- * For change definition of column - use modifyColumn
- *
- * @param string $tableName
- * @param string $oldColumnName
- * @param string $newColumnName
- * @param array $definition
- * @param boolean $flushData flush table statistic
- * @param string $schemaName
- * @return Varien_Db_Adapter_Pdo_Mysql
- * @throws Zend_Db_Exception
- */
- public function changeColumn($tableName, $oldColumnName, $newColumnName, $definition, $flushData = false,
- $schemaName = null)
- {
- if (!$this->tableColumnExists($tableName, $oldColumnName, $schemaName)) {
- throw new Zend_Db_Exception(sprintf('Column "%s" does not exists on table "%s"', $oldColumnName, $tableName));
- }
- if (is_array($definition)) {
- $definition = $this->_getColumnDefinition($definition);
- }
- $sql = sprintf('ALTER TABLE %s CHANGE COLUMN %s %s %s',
- $this->quoteIdentifier($tableName),
- $this->quoteIdentifier($oldColumnName),
- $this->quoteIdentifier($newColumnName),
- $definition);
- $result = $this->raw_query($sql);
- if ($flushData) {
- $this->showTableStatus($tableName, $schemaName);
- }
- $this->resetDdlCache($tableName, $schemaName);
- return $result;
- }
- /**
- * Modify the column definition
- *
- * @param string $tableName
- * @param string $columnName
- * @param array|string $definition
- * @param boolean $flushData
- * @param string $schemaName
- * @return Varien_Db_Adapter_Pdo_Mysql
- * @throws Zend_Db_Exception
- */
- public function modifyColumn($tableName, $columnName, $definition, $flushData = false, $schemaName = null)
- {
- if (!$this->tableColumnExists($tableName, $columnName, $schemaName)) {
- throw new Zend_Db_Exception(sprintf('Column "%s" does not exists on table "%s"', $columnName, $tableName));
- }
- if (is_array($definition)) {
- $definition = $this->_getColumnDefinition($definition);
- }
- $sql = sprintf('ALTER TABLE %s MODIFY COLUMN %s %s',
- $this->quoteIdentifier($tableName),
- $this->quoteIdentifier($columnName),
- $definition);
- $this->raw_query($sql);
- if ($flushData) {
- $this->showTableStatus($tableName, $schemaName);
- }
- $this->resetDdlCache($tableName, $schemaName);
- return $this;
- }
- /**
- * Show table status
- *
- * @param string $tableName
- * @param string $schemaName
- * @return array|false
- */
- public function showTableStatus($tableName, $schemaName = null)
- {
- $fromDbName = null;
- if ($schemaName !== null) {
- $fromDbName = ' FROM ' . $this->quoteIdentifier($schemaName);
- }
- $query = sprintf('SHOW TABLE STATUS%s LIKE %s', $fromDbName, $this->quote($tableName));
- return $this->raw_fetchRow($query);
- }
- /**
- * Retrieve table index key list
- *
- * @deprecated use getIndexList(
- * @param string $tableName
- * @param string $schemaName
- * @return array
- */
- public function getKeyList($tableName, $schemaName = null)
- {
- $keyList = array();
- $indexList = $this->getIndexList($tableName, $schemaName);
- foreach ($indexList as $indexProp) {
- $keyList[$indexProp['KEY_NAME']] = $indexProp['COLUMNS_LIST'];
- }
- return $keyList;
- }
- /**
- * Retrieve Create Table SQL
- *
- * @param string $tableName
- * @param string $schemaName
- * @return string
- */
- public function getCreateTable($tableName, $schemaName = null)
- {
- $cacheKey = $this->_getTableName($tableName, $schemaName);
- $ddl = $this->loadDdlCache($cacheKey, self::DDL_CREATE);
- if ($ddl === false) {
- $sql = 'SHOW CREATE TABLE ' . $this->quoteIdentifier($tableName);
- $ddl = $this->raw_fetchRow($sql, 'Create Table');
- $this->saveDdlCache($cacheKey, self::DDL_CREATE, $ddl);
- }
- return $ddl;
- }
- /**
- * Retrieve the foreign keys descriptions for a table.
- *
- * The return value is an associative array keyed by the UPPERCASE foreign key,
- * as returned by the RDBMS.
- *
- * The value of each array element is an associative array
- * with the following keys:
- *
- * FK_NAME => string; original foreign key name
- * SCHEMA_NAME => string; name of database or schema
- * TABLE_NAME => string;
- * COLUMN_NAME => string; column name
- * REF_SCHEMA_NAME => string; name of reference database or schema
- * REF_TABLE_NAME => string; reference table name
- * REF_COLUMN_NAME => string; reference column name
- * ON_DELETE => string; action type on delete row
- * ON_UPDATE => string; action type on update row
- *
- * @param string $tableName
- * @param string $schemaName
- * @return array
- */
- public function getForeignKeys($tableName, $schemaName = null)
- {
- $cacheKey = $this->_getTableName($tableName, $schemaName);
- $ddl = $this->loadDdlCache($cacheKey, self::DDL_FOREIGN_KEY);
- if ($ddl === false) {
- $ddl = array();
- $createSql = $this->getCreateTable($tableName, $schemaName);
- // collect CONSTRAINT
- $regExp = '#,\s+CONSTRAINT `([^`]*)` FOREIGN KEY \(`([^`]*)`\) '
- . 'REFERENCES (`[^`]*\.)?`([^`]*)` \(`([^`]*)`\)'
- . '( ON DELETE (RESTRICT|CASCADE|SET NULL|NO ACTION))?'
- . '( ON UPDATE (RESTRICT|CASCADE|SET NULL|NO ACTION))?#';
- $matches = array();
- preg_match_all($regExp, $createSql, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- $ddl[strtoupper($match[1])] = array(
- 'FK_NAME' => $match[1],
- 'SCHEMA_NAME' => $schemaName,
- 'TABLE_NAME' => $tableName,
- 'COLUMN_NAME' => $match[2],
- 'REF_SHEMA_NAME' => isset($match[3]) ? $match[3] : $schemaName,
- 'REF_TABLE_NAME' => $match[4],
- 'REF_COLUMN_NAME' => $match[5],
- 'ON_DELETE' => isset($match[6]) ? $match[7] : '',
- 'ON_UPDATE' => isset($match[8]) ? $match[9] : ''
- );
- }
- $this->saveDdlCache($cacheKey, self::DDL_FOREIGN_KEY, $ddl);
- }
- return $ddl;
- }
- /**
- * Retrieve the foreign keys tree for all tables
- *
- * @return array
- */
- public function getForeignKeysTree()
- {
- $tree = array();
- foreach ($this->listTables() as $table) {
- foreach($this->getForeignKeys($table) as $key) {
- $tree[$table][$key['COLUMN_NAME']] = $key;
- }
- }
- return $tree;
- }
- /**
- * Modify tables, used for upgrade process
- * Change columns definitions, reset foreign keys, change tables comments and engines.
- *
- * The value of each array element is an associative array
- * with the following keys:
- *
- * columns => array; list of columns definitions
- * comment => string; table comment
- * engine => string; table engine
- *
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function modifyTables($tables)
- {
- $foreignKeys = $this->getForeignKeysTree();
- foreach ($tables as $table => $tableData) {
- if (!$this->isTableExists($table)) {
- continue;
- }
- foreach ($tableData['columns'] as $column =>$columnDefinition) {
- if (!$this->tableColumnExists($table, $column)) {
- continue;
- }
- $droppedKeys = array();
- foreach($foreignKeys as $keyTable => $columns) {
- foreach($columns as $columnName => $keyOptions) {
- if ($table == $keyOptions['REF_TABLE_NAME'] && $column == $keyOptions['REF_COLUMN_NAME']) {
- $this->dropForeignKey($keyTable, $keyOptions['FK_NAME']);
- $droppedKeys[] = $keyOptions;
- }
- }
- }
- $this->modifyColumn($table, $column, $columnDefinition);
- foreach ($droppedKeys as $options) {
- unset($columnDefinition['identity'], $columnDefinition['primary'], $columnDefinition['comment']);
- $onDelete = $options['ON_DELETE'];
- $onUpdate = $options['ON_UPDATE'];
- if ($onDelete == Varien_Db_Adapter_Interface::FK_ACTION_SET_NULL
- || $onUpdate == Varien_Db_Adapter_Interface::FK_ACTION_SET_NULL) {
- $columnDefinition['nullable'] = true;
- }
- $this->modifyColumn($options['TABLE_NAME'], $options['COLUMN_NAME'], $columnDefinition);
- $this->addForeignKey(
- $options['FK_NAME'],
- $options['TABLE_NAME'],
- $options['COLUMN_NAME'],
- $options['REF_TABLE_NAME'],
- $options['REF_COLUMN_NAME'],
- ($onDelete) ? $onDelete : Varien_Db_Adapter_Interface::FK_ACTION_NO_ACTION,
- ($onUpdate) ? $onUpdate : Varien_Db_Adapter_Interface::FK_ACTION_NO_ACTION
- );
- }
- }
- if (!empty($tableData['comment'])) {
- $this->changeTableComment($table, $tableData['comment']);
- }
- if (!empty($tableData['engine'])) {
- $this->changeTableEngine($table, $tableData['engine']);
- }
- }
- return $this;
- }
- /**
- * Retrieve table index information
- *
- * The return value is an associative array keyed by the UPPERCASE index key (except for primary key,
- * that is always stored under 'PRIMARY' key) 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; name of the table
- * KEY_NAME => string; the original index name
- * COLUMNS_LIST => array; array of index column names
- * INDEX_TYPE => string; lowercase, create index type
- * INDEX_METHOD => string; index method using
- * type => string; see INDEX_TYPE
- * fields => array; see COLUMNS_LIST
- *
- * @param string $tableName
- * @param string $schemaName
- * @return array
- */
- public function getIndexList($tableName, $schemaName = null)
- {
- $cacheKey = $this->_getTableName($tableName, $schemaName);
- $ddl = $this->loadDdlCache($cacheKey, self::DDL_INDEX);
- if ($ddl === false) {
- $ddl = array();
- $sql = sprintf('SHOW INDEX FROM %s',
- $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)));
- foreach ($this->fetchAll($sql) as $row) {
- $fieldKeyName = 'Key_name';
- $fieldNonUnique = 'Non_unique';
- $fieldColumn = 'Column_name';
- $fieldIndexType = 'Index_type';
- if (strtolower($row[$fieldKeyName]) == Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY) {
- $indexType = Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY;
- } elseif ($row[$fieldNonUnique] == 0) {
- $indexType = Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE;
- } elseif (strtolower($row[$fieldIndexType]) == Varien_Db_Adapter_Interface::INDEX_TYPE_FULLTEXT) {
- $indexType = Varien_Db_Adapter_Interface::INDEX_TYPE_FULLTEXT;
- } else {
- $indexType = Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX;
- }
- $upperKeyName = strtoupper($row[$fieldKeyName]);
- if (isset($ddl[$upperKeyName])) {
- $ddl[$upperKeyName]['fields'][] = $row[$fieldColumn]; // for compatible
- $ddl[$upperKeyName]['COLUMNS_LIST'][] = $row[$fieldColumn];
- } else {
- $ddl[$upperKeyName] = array(
- 'SCHEMA_NAME' => $schemaName,
- 'TABLE_NAME' => $tableName,
- 'KEY_NAME' => $row[$fieldKeyName],
- 'COLUMNS_LIST' => array($row[$fieldColumn]),
- 'INDEX_TYPE' => $indexType,
- 'INDEX_METHOD' => $row[$fieldIndexType],
- 'type' => strtolower($indexType), // for compatibility
- 'fields' => array($row[$fieldColumn]) // for compatibility
- );
- }
- }
- $this->saveDdlCache($cacheKey, self::DDL_INDEX, $ddl);
- }
- return $ddl;
- }
- /**
- * Add Index Key
- *
- * @deprecated since 1.5.0.0
- * @param string $tableName
- * @param string $indexName
- * @param string|array $fields
- * @param string $indexType
- * @param string $schemaName
- * @return Zend_Db_Statement_Interface
- */
- public function addKey($tableName, $indexName, $fields, $indexType = 'index', $schemaName = null)
- {
- return $this->addIndex($tableName, $indexName, $fields, $indexType, $schemaName);
- }
- /**
- * Remove duplicate entry for create key
- *
- * @param string $table
- * @param array $fields
- * @param array $ids
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- protected function _removeDuplicateEntry($table, $fields, $ids)
- {
- $where = array();
- $i = 0;
- foreach ($fields as $field) {
- $where[] = $this->quoteInto($field . '=?', $ids[$i++]);
- }
- if (!$where) {
- return $this;
- }
- $whereCond = implode(' AND ', $where);
- $sql = sprintf('SELECT COUNT(*) as `cnt` FROM `%s` WHERE %s', $table, $whereCond);
- $cnt = $this->raw_fetchRow($sql, 'cnt');
- if ($cnt > 1) {
- $sql = sprintf('DELETE FROM `%s` WHERE %s LIMIT %d',
- $table,
- $whereCond,
- $cnt - 1
- );
- $this->raw_query($sql);
- }
- return $this;
- }
- /**
- * Creates and returns a new Zend_Db_Select object for this adapter.
- *
- * @return Varien_Db_Select
- */
- public function select()
- {
- return new Varien_Db_Select($this);
- }
- /**
- * Start debug timer
- *
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- protected function _debugTimer()
- {
- if ($this->_debug) {
- $this->_debugTimer = microtime(true);
- }
- return $this;
- }
- /**
- * Logging debug information
- *
- * @param int $type
- * @param string $sql
- * @param array $bind
- * @param Zend_Db_Statement_Pdo $result
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- protected function _debugStat($type, $sql, $bind = array(), $result = null)
- {
- if (!$this->_debug) {
- return $this;
- }
- $code = '## ' . getmypid() . ' ## ';
- $nl = "\n";
- $time = sprintf('%.4f', microtime(true) - $this->_debugTimer);
- if (!$this->_logAllQueries && $time < $this->_logQueryTime) {
- return $this;
- }
- switch ($type) {
- case self::DEBUG_CONNECT:
- $code .= 'CONNECT' . $nl;
- break;
- case self::DEBUG_TRANSACTION:
- $code .= 'TRANSACTION ' . $sql . $nl;
- break;
- case self::DEBUG_QUERY:
- $code .= 'QUERY' . $nl;
- $code .= 'SQL: ' . $sql . $nl;
- if ($bind) {
- $code .= 'BIND: ' . var_export($bind, true) . $nl;
- }
- if ($result instanceof Zend_Db_Statement_Pdo) {
- $code .= 'AFF: ' . $result->rowCount() . $nl;
- }
- break;
- }
- $code .= 'TIME: ' . $time . $nl;
- if ($this->_logCallStack) {
- $code .= 'TRACE: ' . Varien_Debug::backtrace(true, false) . $nl;
- }
- $code .= $nl;
- $this->_debugWriteToFile($code);
- return $this;
- }
- /**
- * Write exception and thow
- *
- * @param Exception $e
- * @throws Exception
- */
- protected function _debugException(Exception $e)
- {
- if (!$this->_debug) {
- throw $e;
- }
- $nl = "\n";
- $code = 'EXCEPTION ' . $nl . $e . $nl . $nl;
- $this->_debugWriteToFile($code);
- throw $e;
- }
- /**
- * Debug write to file process
- *
- * @param string $str
- */
- protected function _debugWriteToFile($str)
- {
- $str = '## ' . date('Y-m-d H:i:s') . "\r\n" . $str;
- if (!$this->_debugIoAdapter) {
- $this->_debugIoAdapter = new Varien_Io_File();
- $dir = Mage::getBaseDir() . DS . $this->_debugIoAdapter->dirname($this->_debugFile);
- $this->_debugIoAdapter->checkAndCreateFolder($dir);
- $this->_debugIoAdapter->open(array('path' => $dir));
- $this->_debugFile = basename($this->_debugFile);
- }
- $this->_debugIoAdapter->streamOpen($this->_debugFile, 'a');
- $this->_debugIoAdapter->streamLock();
- $this->_debugIoAdapter->streamWrite($str);
- $this->_debugIoAdapter->streamUnlock();
- $this->_debugIoAdapter->streamClose();
- }
- /**
- * Quotes a value and places into a piece of text at a placeholder.
- *
- * Method revrited for handle empty arrays in value param
- *
- * @param string $text The text with a placeholder.
- * @param mixed $value The value to quote.
- * @param string $type OPTIONAL SQL datatype
- * @param integer $count OPTIONAL count of placeholders to replace
- * @return string An SQL-safe quoted value placed into the orignal text.
- */
- public function quoteInto($text, $value, $type = null, $count = null)
- {
- if (is_array($value) && empty($value)) {
- $value = new Zend_Db_Expr('NULL');
- }
- return parent::quoteInto($text, $value, $type, $count);
- }
- /**
- * Retrieve ddl cache name
- *
- * @param string $tableName
- * @param string $schemaName
- */
- protected function _getTableName($tableName, $schemaName = null)
- {
- return ($schemaName ? $schemaName . '.' : '') . $tableName;
- }
- /**
- * Retrieve Id for cache
- *
- * @param string $tableKey
- * @param int $ddlType
- * @return string
- */
- protected function _getCacheId($tableKey, $ddlType)
- {
- return sprintf('%s_%s_%s', self::DDL_CACHE_PREFIX, $tableKey, $ddlType);
- }
- /**
- * Load DDL data from cache
- * Return false if cache does not exists
- *
- * @param string $tableCacheKey the table cache key
- * @param int $ddlType the DDL constant
- * @return string|array|int|false
- */
- public function loadDdlCache($tableCacheKey, $ddlType)
- {
- if (!$this->_isDdlCacheAllowed) {
- return false;
- }
- if (isset($this->_ddlCache[$ddlType][$tableCacheKey])) {
- return $this->_ddlCache[$ddlType][$tableCacheKey];
- }
- if ($this->_cacheAdapter instanceof Zend_Cache_Core) {
- $cacheId = $this->_getCacheId($tableCacheKey, $ddlType);
- $data = $this->_cacheAdapter->load($cacheId);
- if ($data !== false) {
- $data = unserialize($data);
- $this->_ddlCache[$ddlType][$tableCacheKey] = $data;
- }
- return $data;
- }
- return false;
- }
- /**
- * Save DDL data into cache
- *
- * @param string $tableCacheKey
- * @param int $ddlType
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function saveDdlCache($tableCacheKey, $ddlType, $data)
- {
- if (!$this->_isDdlCacheAllowed) {
- return $this;
- }
- $this->_ddlCache[$ddlType][$tableCacheKey] = $data;
- if ($this->_cacheAdapter instanceof Zend_Cache_Core) {
- $cacheId = $this->_getCacheId($tableCacheKey, $ddlType);
- $data = serialize($data);
- $this->_cacheAdapter->save($data, $cacheId, array(self::DDL_CACHE_TAG));
- }
- return $this;
- }
- /**
- * Reset cached DDL data from cache
- * if table name is null - reset all cached DDL data
- *
- * @param string $tableName
- * @param string $schemaName OPTIONAL
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function resetDdlCache($tableName = null, $schemaName = null)
- {
- if (!$this->_isDdlCacheAllowed) {
- return $this;
- }
- if ($tableName === null) {
- $this->_ddlCache = array();
- if ($this->_cacheAdapter instanceof Zend_Cache_Core) {
- $this->_cacheAdapter->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array(self::DDL_CACHE_TAG));
- }
- } else {
- $cacheKey = $this->_getTableName($tableName, $schemaName);
- $ddlTypes = array(self::DDL_DESCRIBE, self::DDL_CREATE, self::DDL_INDEX, self::DDL_FOREIGN_KEY);
- foreach ($ddlTypes as $ddlType) {
- unset($this->_ddlCache[$ddlType][$cacheKey]);
- }
- if ($this->_cacheAdapter instanceof Zend_Cache_Core) {
- foreach ($ddlTypes as $ddlType) {
- $cacheId = $this->_getCacheId($cacheKey, $ddlType);
- $this->_cacheAdapter->remove($cacheId);
- }
- }
- }
- return $this;
- }
- /**
- * Disallow DDL caching
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function disallowDdlCache()
- {
- $this->_isDdlCacheAllowed = false;
- return $this;
- }
- /**
- * Allow DDL caching
- * @return Varien_Db_Adapter_Pdo_Mysql
- */
- public function allowDdlCache()
- {
- $this->_isDdlCacheAllowed = true;
- return $this;
- }
- /**
- * 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)
- {
- $cacheKey = $this->_getTableName($tableName, $schemaName);
- $ddl = $this->loadDdlCache($cacheKey, self::DDL_DESCRIBE);
- if ($ddl === false) {
- $ddl = parent::describeTable($tableName, $schemaName);
- /**
- * Remove bug in some MySQL…
Large files files are truncated, but you can click here to view the full file