00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 class Varien_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Mysql
00031 {
00032 const DEBUG_CONNECT = 0;
00033 const DEBUG_TRANSACTION = 1;
00034 const DEBUG_QUERY = 2;
00035
00036 const ISO_DATE_FORMAT = 'yyyy-MM-dd';
00037 const ISO_DATETIME_FORMAT = 'yyyy-MM-dd HH-mm-ss';
00038
00039 const DDL_DESCRIBE = 1;
00040 const DDL_CREATE = 2;
00041 const DDL_INDEX = 3;
00042 const DDL_FOREIGN_KEY = 4;
00043
00044
00045
00046
00047
00048
00049 protected $_transactionLevel = 0;
00050
00051
00052
00053
00054
00055
00056 protected $_connectionFlagsSet = false;
00057
00058
00059
00060
00061
00062
00063 protected $_ddlCache = array();
00064
00065
00066
00067
00068
00069
00070 protected $_bindParams = array();
00071
00072
00073
00074
00075
00076
00077 protected $_bindIncrement = 0;
00078
00079
00080
00081
00082
00083
00084 protected $_debug = false;
00085
00086
00087
00088
00089
00090
00091 protected $_logQueryTime = 0.05;
00092
00093
00094
00095
00096
00097
00098 protected $_debugFile = 'var/debug/sql.txt';
00099
00100
00101
00102
00103
00104
00105 protected $_debugIoAdapter;
00106
00107
00108
00109
00110
00111
00112 protected $_debugTimer = 0;
00113
00114
00115
00116
00117
00118
00119 public function beginTransaction()
00120 {
00121 if ($this->_transactionLevel===0) {
00122 $this->_debugTimer();
00123 parent::beginTransaction();
00124 $this->_debugStat(self::DEBUG_TRANSACTION, 'BEGIN');
00125 }
00126 $this->_transactionLevel++;
00127 return $this;
00128 }
00129
00130
00131
00132
00133
00134
00135 public function commit()
00136 {
00137 if ($this->_transactionLevel===1) {
00138 $this->_debugTimer();
00139 parent::commit();
00140 $this->_debugStat(self::DEBUG_TRANSACTION, 'COMMIT');
00141 }
00142 $this->_transactionLevel--;
00143 return $this;
00144 }
00145
00146
00147
00148
00149
00150
00151 public function rollback()
00152 {
00153 if ($this->_transactionLevel===1) {
00154 $this->_debugTimer();
00155 parent::rollback();
00156 $this->_debugStat(self::DEBUG_TRANSACTION, 'ROLLBACK');
00157 }
00158 $this->_transactionLevel--;
00159 return $this;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168 public function convertDate($date)
00169 {
00170 if ($date instanceof Zend_Date) {
00171 return $date->toString(self::ISO_DATE_FORMAT);
00172 }
00173 return strftime('%Y-%m-%d', strtotime($date));
00174 }
00175
00176
00177
00178
00179
00180
00181
00182 public function convertDateTime($datetime)
00183 {
00184 if ($datetime instanceof Zend_Date) {
00185 return $datetime->toString(self::ISO_DATETIME_FORMAT);
00186 }
00187 return strftime('%Y-%m-%d %H:%M:%S', strtotime($datetime));
00188 }
00189
00190
00191
00192
00193 protected function _connect()
00194 {
00195 if ($this->_connection) {
00196 return;
00197 }
00198
00199 if (!extension_loaded('pdo_mysql')) {
00200 throw new Zend_Db_Adapter_Exception('pdo_mysql extension is not installed');
00201 }
00202
00203 if (strpos($this->_config['host'], '/')!==false) {
00204 $this->_config['unix_socket'] = $this->_config['host'];
00205 unset($this->_config['host']);
00206 } elseif (strpos($this->_config['host'], ':')!==false) {
00207 list($this->_config['host'], $this->_config['port']) = explode(':', $this->_config['host']);
00208 }
00209
00210 $this->_debugTimer();
00211 parent::_connect();
00212 $this->_debugStat(self::DEBUG_CONNECT, '');
00213
00214
00215 $this->_connection->query("SET SQL_MODE=''");
00216
00217 if (!$this->_connectionFlagsSet) {
00218 $this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
00219 $this->_connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
00220 $this->_connectionFlagsSet = true;
00221 }
00222 }
00223
00224 public function raw_query($sql)
00225 {
00226 do {
00227 $retry = false;
00228 $tries = 0;
00229 try {
00230 $result = $this->getConnection()->query($sql);
00231 } catch (PDOException $e) {
00232 if ($e->getMessage()=='SQLSTATE[HY000]: General error: 2013 Lost connection to MySQL server during query') {
00233 $retry = true;
00234 } else {
00235 throw $e;
00236 }
00237 $tries++;
00238 }
00239 } while ($retry && $tries<10);
00240
00241 return $result;
00242 }
00243
00244 public function raw_fetchRow($sql, $field=null)
00245 {
00246 if (!$result = $this->raw_query($sql)) {
00247 return false;
00248 }
00249 if (!$row = $result->fetch(PDO::FETCH_ASSOC)) {
00250 return false;
00251 }
00252 if (empty($field)) {
00253 return $row;
00254 } else {
00255 return isset($row[$field]) ? $row[$field] : false;
00256 }
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 public function query($sql, $bind = array())
00269 {
00270 $this->_debugTimer();
00271 try {
00272 $sql = (string)$sql;
00273 if (strpos($sql, ':') !== false || strpos($sql, '?') !== false) {
00274 $this->_bindParams = $bind;
00275 $sql = preg_replace_callback('#(([\'"])((\\2)|((.*?[^\\\\])\\2)))#', array($this, 'proccessBindCallback'), $sql);
00276 $bind = $this->_bindParams;
00277 }
00278
00279
00280
00281 $result = parent::query($sql, $bind);
00282 }
00283 catch (Exception $e) {
00284 $this->_debugStat(self::DEBUG_QUERY, $sql, $bind);
00285 $this->_debugException($e);
00286 }
00287 $this->_debugStat(self::DEBUG_QUERY, $sql, $bind, $result);
00288 return $result;
00289 }
00290
00291 public function proccessBindCallback($matches)
00292 {
00293 if (isset($matches[6]) && (
00294 strpos($matches[6], "'") !== false ||
00295 strpos($matches[6], ":") !== false ||
00296 strpos($matches[6], "?") !== false)) {
00297 $bindName = ':_mage_bind_var_' . ( ++ $this->_bindIncrement );
00298 $this->_bindParams[$bindName] = $this->_unQuote($matches[6]);
00299 return ' ' . $bindName;
00300 }
00301 return $matches[0];
00302 }
00303
00304
00305
00306
00307
00308
00309
00310 protected function _unQuote($string)
00311 {
00312 $translate = array(
00313 "\\000" => "\000",
00314 "\\n" => "\n",
00315 "\\r" => "\r",
00316 "\\\\" => "\\",
00317 "\'" => "'",
00318 "\\\"" => "\"",
00319 "\\032" => "\032"
00320 );
00321 return strtr($string, $translate);
00322 }
00323
00324
00325
00326
00327
00328
00329
00330 public function multi_query($sql)
00331 {
00332 ##$result = $this->raw_query($sql);
00333
00334 #$this->beginTransaction();
00335 try {
00336 $stmts = $this->_splitMultiQuery($sql);
00337 $result = array();
00338 foreach ($stmts as $stmt) {
00339 $result[] = $this->raw_query($stmt);
00340 }
00341 #$this->commit();
00342 } catch (Exception $e) {
00343 #$this->rollback();
00344 throw $e;
00345 }
00346
00347 $this->resetDdlCache();
00348
00349 return $result;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358 protected function _splitMultiQuery($sql)
00359 {
00360 $parts = preg_split('#(;|\'|"|\\\\|//|--|\n|/\*|\*/)#', $sql, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
00361
00362 $q = false;
00363 $c = false;
00364 $stmts = array();
00365 $s = '';
00366
00367 foreach ($parts as $i=>$part) {
00368
00369 if (($part==="'" || $part==='"') && ($i===0 || $parts[$i-1]!=='\\')) {
00370 if ($q===false) {
00371 $q = $part;
00372 } elseif ($q===$part) {
00373 $q = false;
00374 }
00375 }
00376
00377
00378 if (($part==='//' || $part==='--') && ($i===0 || $parts[$i-1]==="\n")) {
00379 $c = $part;
00380 } elseif ($part==="\n" && ($c==='//' || $c==='--')) {
00381 $c = false;
00382 }
00383
00384
00385 if ($part==='/*' && $c===false) {
00386 $c = '/*';
00387 } elseif ($part==='*/' && $c==='/*') {
00388 $c = false;
00389 }
00390
00391
00392 if ($part===';' && $q===false && $c===false) {
00393 if (trim($s)!=='') {
00394 $stmts[] = trim($s);
00395 $s = '';
00396 }
00397 } else {
00398 $s .= $part;
00399 }
00400 }
00401 if (trim($s)!=='') {
00402 $stmts[] = trim($s);
00403 }
00404
00405 return $stmts;
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 public function dropForeignKey($tableName, $foreignKey, $schemaName = null)
00417 {
00418 $foreignKeys = $this->getForeignKeys($tableName, $schemaName);
00419 if (isset($foreignKeys[strtoupper($foreignKey)])) {
00420 $sql = sprintf('ALTER TABLE %s DROP FOREIGN KEY %s',
00421 $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
00422 $this->quoteIdentifier($foreignKeys[strtoupper($foreignKey)]['FK_NAME']));
00423
00424
00425
00426
00427 $this->resetDdlCache($tableName, $schemaName);
00428
00429 return $this->raw_query($sql);
00430 }
00431
00432 return true;
00433 }
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 public function dropKey($tableName, $keyName, $shemaName = null)
00444 {
00445 $indexList = $this->getIndexList($tableName, $shemaName);
00446 $keyName = strtoupper($keyName);
00447 if (!isset($indexList[$keyName])) {
00448 return true;
00449 }
00450
00451 if ($keyName == 'PRIMARY') {
00452 $cond = 'DROP PRIMARY KEY';
00453 }
00454 else {
00455 $cond = sprintf('DROP KEY %s', $this->quoteIdentifier($indexList[$keyName]['KEY_NAME']));
00456 }
00457 $sql = sprintf('ALTER TABLE %s %s',
00458 $this->quoteIdentifier($this->_getTableName($tableName, $shemaName)),
00459 $cond);
00460
00461 $this->resetDdlCache($tableName, $shemaName);
00462 return $this->raw_query($sql);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 public function purgeOrphanRecords($tableName, $columnName, $refTableName, $refColumnName, $onDelete = 'cascade')
00476 {
00477 if (strtoupper($onDelete) == 'CASCADE'
00478 || strtoupper($onDelete) == 'RESTRICT') {
00479 $sql = "DELETE `p`.* FROM `{$tableName}` AS `p`"
00480 . " LEFT JOIN `{$refTableName}` AS `r`"
00481 . " ON `p`.`{$columnName}` = `r`.`{$refColumnName}`"
00482 . " WHERE `r`.`{$refColumnName}` IS NULL";
00483 $this->raw_query($sql);
00484 }
00485 elseif (strtoupper($onDelete) == 'SET NULL') {
00486 $sql = "UPDATE `{$tableName}` AS `p`"
00487 . " LEFT JOIN `{$refTableName}` AS `r`"
00488 . " ON `p`.`{$columnName}` = `r`.`{$refColumnName}`"
00489 . " SET `p`.`{$columnName}`=NULL"
00490 . " WHERE `r`.`{$refColumnName}` IS NULL";
00491 $this->raw_query($sql);
00492 }
00493
00494 return $this;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 public function addConstraint($fkName, $tableName, $columnName,
00511 $refTableName, $refColumnName, $onDelete = 'cascade', $onUpdate = 'cascade', $purge = false)
00512 {
00513 if (substr($fkName, 0, 3) != 'FK_') {
00514 $fkName = 'FK_' . $fkName;
00515 }
00516
00517 $this->dropForeignKey($tableName, $fkName);
00518
00519 if ($purge) {
00520 $this->purgeOrphanRecords($tableName, $columnName, $refTableName, $refColumnName, $onDelete);
00521 }
00522
00523 $sql = 'ALTER TABLE `'.$tableName.'` ADD CONSTRAINT `'.$fkName.'`'
00524 . ' FOREIGN KEY (`'.$columnName.'`) REFERENCES `'.$refTableName.'` (`'.$refColumnName.'`)';
00525 if (!is_null($onDelete)) {
00526 $sql .= ' ON DELETE ' . strtoupper($onDelete);
00527 }
00528 if (!is_null($onUpdate)) {
00529 $sql .= ' ON UPDATE ' . strtoupper($onUpdate);
00530 }
00531
00532 $this->resetDdlCache($tableName);
00533 return $this->raw_query($sql);
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 public function tableColumnExists($tableName, $columnName, $schemaName = null)
00545 {
00546 $describe = $this->describeTable($tableName, $schemaName);
00547 foreach ($describe as $column) {
00548 if ($column['COLUMN_NAME'] == $columnName) {
00549 return true;
00550 }
00551 }
00552 return false;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 public function addColumn($tableName, $columnName, $definition)
00564 {
00565 if ($this->tableColumnExists($tableName, $columnName)) {
00566 return true;
00567 }
00568
00569 $sql = sprintf('ALTER TABLE %s ADD COLUMN %s %s',
00570 $this->quoteIdentifier($tableName),
00571 $this->quoteIdentifier($columnName),
00572 $definition
00573 );
00574 $result = $this->raw_query($sql);
00575 $this->resetDdlCache($tableName);
00576 return $result;
00577 }
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587 public function dropColumn($tableName, $columnName, $shemaName = null)
00588 {
00589 if (!$this->tableColumnExists($tableName, $columnName, $shemaName)) {
00590 return true;
00591 }
00592
00593 $alterDrop = array();
00594
00595 $foreignKeys = $this->getForeignKeys($tableName, $shemaName);
00596 foreach ($foreignKeys as $fkProp) {
00597 if ($fkProp['COLUMN_NAME'] == $columnName) {
00598 $alterDrop[] = sprintf('DROP FOREIGN KEY %s', $this->quoteIdentifier($fkProp['FK_NAME']));
00599 }
00600 }
00601
00602 $alterDrop[] = sprintf('DROP COLUMN %s', $this->quoteIdentifier($columnName));
00603 $sql = sprintf('ALTER TABLE %s %s',
00604 $this->quoteIdentifier($this->_getTableName($tableName, $shemaName)),
00605 join(', ', $alterDrop));
00606
00607 $this->resetDdlCache($tableName, $shemaName);
00608 return $this->raw_query($sql);
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 public function changeColumn($tableName, $oldColumnName, $newColumnName, $definition, $showStatus = false)
00623 {
00624 if (!$this->tableColumnExists($tableName, $oldColumnName)) {
00625 throw new Exception(sprintf('Column "%s" does not exists on table "%s"', $oldColumnName, $tableName));
00626 }
00627
00628 $sql = sprintf('ALTER TABLE %s CHANGE COLUMN %s %s %s',
00629 $this->quoteIdentifier($tableName),
00630 $this->quoteIdentifier($oldColumnName),
00631 $this->quoteIdentifier($newColumnName),
00632 $definition);
00633
00634 $result = $this->raw_query($sql);
00635 if ($showStatus) {
00636 $this->showTableStatus($tableName);
00637 }
00638
00639 $this->resetDdlCache($tableName);
00640 return $result;
00641 }
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 public function modifyColumn($tableName, $columnName, $definition, $showStatus = false)
00654 {
00655 if (!$this->tableColumnExists($tableName, $columnName)) {
00656 throw new Exception(sprintf('Column "%s" does not exists on table "%s"', $columnName, $tableName));
00657 }
00658
00659 $sql = sprintf('ALTER TABLE %s MODIFY COLUMN %s %s',
00660 $this->quoteIdentifier($tableName),
00661 $this->quoteIdentifier($columnName),
00662 $definition);
00663 $result = $this->raw_query($sql);
00664 if ($showStatus) {
00665 $this->showTableStatus($tableName);
00666 }
00667
00668 $this->resetDdlCache($tableName);
00669 return $result;
00670 }
00671
00672
00673
00674
00675
00676
00677
00678 public function showTableStatus($tableName)
00679 {
00680 $sql = $this->quoteInto('SHOW TABLE STATUS LIKE ?', $tableName);
00681 return $this->raw_fetchRow($sql);
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692 public function getKeyList($tableName, $schemaName = null)
00693 {
00694 $keyList = array();
00695 $indexList = $this->getIndexList($tableName, $schemaName);
00696
00697 foreach ($indexList as $indexProp) {
00698 $keyList[$indexProp['KEY_NAME']] = $indexProp['COLUMNS_LIST'];
00699 }
00700
00701 return $keyList;
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711 public function getCreateTable($tableName, $schemaName = null)
00712 {
00713 $tableName = $this->_getTableName($tableName, $schemaName);
00714 if (!isset($this->_ddlCache[self::DDL_CREATE][$tableName])) {
00715 $sql = sprintf('SHOW CREATE TABLE %s', $this->quoteIdentifier($tableName));
00716 $this->_ddlCache[self::DDL_CREATE][$tableName] = $this->raw_fetchRow($sql, 'Create Table');
00717 }
00718 return $this->_ddlCache[self::DDL_CREATE][$tableName];
00719 }
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 public function getForeignKeys($tableName, $schemaName = null)
00745 {
00746 $cacheKey = $this->_getTableName($tableName, $schemaName);
00747 if (!isset($this->_ddlCache[self::DDL_FOREIGN_KEY][$cacheKey])) {
00748 $foreignKeys = array();
00749 $createSql = $this->getCreateTable($tableName, $schemaName);
00750
00751
00752 $regExp = '#,\s+CONSTRAINT `([^`]*)` FOREIGN KEY \(`([^`]*)`\) '
00753 . 'REFERENCES (`[^`]*\.)?`([^`]*)` \(`([^`]*)`\)'
00754 . '( ON DELETE (RESTRICT|CASCADE|SET NULL|NO ACTION))?'
00755 . '( ON UPDATE (RESTRICT|CASCADE|SET NULL|NO ACTION))?#';
00756 $matches = array();
00757 preg_match_all($regExp, $createSql, $matches, PREG_SET_ORDER);
00758 foreach ($matches as $match) {
00759 $foreignKeys[strtoupper($match[1])] = array(
00760 'FK_NAME' => $match[1],
00761 'SCHEMA_NAME' => $schemaName,
00762 'TABLE_NAME' => $tableName,
00763 'COLUMN_NAME' => $match[2],
00764 'REF_SHEMA_NAME' => isset($match[3]) ? $match[3] : $schemaName,
00765 'REF_TABLE_NAME' => $match[4],
00766 'REF_COLUMN_NAME' => $match[5],
00767 'ON_DELETE' => isset($match[6]) ? $match[7] : '',
00768 'ON_UPDATE' => isset($match[8]) ? $match[9] : ''
00769 );
00770 }
00771
00772 $this->_ddlCache[self::DDL_FOREIGN_KEY][$cacheKey] = $foreignKeys;
00773 }
00774
00775 return $this->_ddlCache[self::DDL_FOREIGN_KEY][$cacheKey];
00776 }
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 public function getIndexList($tableName, $schemaName = null)
00801 {
00802 $cacheKey = $this->_getTableName($tableName, $schemaName);
00803 if (!isset($this->_ddlCache[self::DDL_INDEX][$cacheKey])) {
00804 $indexList = array();
00805
00806 $sql = sprintf('SHOW INDEX FROM %s',
00807 $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)));
00808 foreach ($this->fetchAll($sql) as $row) {
00809 $fieldKeyName = 'Key_name';
00810 $fieldNonUnique = 'Non_unique';
00811 $fieldColumn = 'Column_name';
00812 $fieldIndexType = 'Index_type';
00813
00814 if ($row[$fieldKeyName] == 'PRIMARY') {
00815 $indexType = 'primary';
00816 }
00817 elseif ($row[$fieldNonUnique] == 0) {
00818 $indexType = 'unique';
00819 }
00820 elseif ($row[$fieldIndexType] == 'FULLTEXT') {
00821 $indexType = 'fulltext';
00822 }
00823 else {
00824 $indexType = 'index';
00825 }
00826
00827 if (isset($indexList[$row[$fieldKeyName]])) {
00828 $indexList[$row[$fieldKeyName]]['fields'][] = $row[$fieldColumn];
00829 $indexList[$row[$fieldKeyName]]['COLUMNS_LIST'][] = $row[$fieldColumn];
00830 }
00831 else {
00832 $indexList[strtoupper($row[$fieldKeyName])] = array(
00833 'SCHEMA_NAME' => $schemaName,
00834 'TABLE_NAME' => $tableName,
00835 'KEY_NAME' => $row[$fieldKeyName],
00836 'COLUMNS_LIST' => array($row[$fieldColumn]),
00837 'INDEX_TYPE' => strtoupper($indexType),
00838 'INDEX_METHOD' => $row[$fieldIndexType],
00839 'type' => $indexType,
00840 'fields' => array($row[$fieldColumn])
00841 );
00842 }
00843 }
00844
00845 $this->_ddlCache[self::DDL_INDEX][$cacheKey] = $indexList;
00846 }
00847
00848 return $this->_ddlCache[self::DDL_INDEX][$cacheKey];
00849 }
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860 public function addKey($tableName, $indexName, $fields, $indexType = 'index')
00861 {
00862 $columns = $this->describeTable($tableName);
00863 $keyList = $this->getKeyList($tableName);
00864
00865 $sql = 'ALTER TABLE '.$this->quoteIdentifier($tableName);
00866 if (isset($keyList[$indexName])) {
00867 $sql .= ' DROP INDEX ' . $this->quoteIdentifier($indexName) . ',';
00868 }
00869
00870 if (!is_array($fields)) {
00871 $fields = array($fields);
00872 }
00873
00874 $fieldSql = array();
00875 foreach ($fields as $field) {
00876 if (!isset($columns[$field])) {
00877 $msg = sprintf('There is no field "%s" that you are trying to create an index on "%s"',
00878 $field, $tableName);
00879 throw new Exception($msg);
00880 }
00881 $fieldSql[] = $this->quoteIdentifier($field);
00882 }
00883 $fieldSql = join(',', $fieldSql);
00884
00885 switch (strtolower($indexType)) {
00886 case 'primary':
00887 $condition = 'PRIMARY KEY';
00888 break;
00889 case 'unique':
00890 $condition = 'UNIQUE ' . $this->quoteIdentifier($indexName);
00891 break;
00892 case 'fulltext':
00893 $condition = 'FULLTEXT ' . $this->quoteIdentifier($indexName);
00894 break;
00895 default:
00896 $condition = 'INDEX ' . $this->quoteIdentifier($indexName);
00897 break;
00898 }
00899
00900 $sql .= ' ADD ' . $condition . ' (' . $fieldSql . ')';
00901
00902 $cycle = true;
00903 while ($cycle === true) {
00904 try {
00905 $result = $this->raw_query($sql);
00906 $cycle = false;
00907 }
00908 catch (PDOException $e) {
00909 if (in_array(strtolower($indexType), array('primary', 'unique'))) {
00910 $match = array();
00911 if (preg_match('#SQLSTATE\[23000\]: [^:]+: 1062[^\']+\'([\d-]+)\'#', $e->getMessage(), $match)) {
00912 $ids = explode('-', $match[1]);
00913 $this->_removeDuplicateEntry($tableName, $fields, $ids);
00914 continue;
00915 }
00916 }
00917 throw $e;
00918 }
00919 catch (Exception $e) {
00920 throw $e;
00921 }
00922 }
00923
00924 $this->resetDdlCache($tableName);
00925
00926 return $result;
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937 protected function _removeDuplicateEntry($table, $fields, $ids)
00938 {
00939 $where = array();
00940 $i = 0;
00941 foreach ($fields as $field) {
00942 $where[] = $this->quoteInto($field . '=?', $ids[$i]);
00943 $i ++;
00944 }
00945
00946 if (!$where) {
00947 return $this;
00948 }
00949 $whereCond = join(' AND ', $where);
00950 $sql = sprintf('SELECT COUNT(*) as `cnt` FROM `%s` WHERE %s', $table, $whereCond);
00951
00952 if ($cnt = $this->raw_fetchRow($sql, 'cnt')) {
00953 $sql = sprintf('DELETE FROM `%s` WHERE %s LIMIT %d',
00954 $table,
00955 $whereCond,
00956 $cnt - 1
00957 );
00958 $this->raw_query($sql);
00959 }
00960
00961 return $this;
00962 }
00963
00964
00965
00966
00967
00968
00969 public function select()
00970 {
00971 return new Varien_Db_Select($this);
00972 }
00973
00974
00975
00976
00977
00978
00979 protected function _debugTimer()
00980 {
00981 if ($this->_debug) {
00982 $this->_debugTimer = microtime(true);
00983 }
00984 return $this;
00985 }
00986
00987
00988
00989
00990
00991
00992 protected function _debugStat($type, $sql, $bind = array(), $result = null)
00993 {
00994 if (!$this->_debug) {
00995 return $this;
00996 }
00997
00998 $code = '## ' . getmypid() . ' ## ';
00999 $nl = "\n";
01000 $time = sprintf('%.4f', microtime(true) - $this->_debugTimer);
01001
01002 if ($time < $this->_logQueryTime) {
01003 return $this;
01004 }
01005 switch ($type) {
01006 case self::DEBUG_CONNECT:
01007 $code .= 'CONNECT' . $nl;
01008 break;
01009 case self::DEBUG_TRANSACTION:
01010 $code .= 'TRANSACTION ' . $sql . $nl;
01011 break;
01012 case self::DEBUG_QUERY:
01013 $code .= 'QUERY' . $nl;
01014 $code .= 'SQL: ' . $sql . $nl;
01015 if ($bind) {
01016 $code .= 'BIND: ' . print_r($bind, true) . $nl;
01017 }
01018 if ($result instanceof Zend_Db_Statement_Pdo) {
01019 $code .= 'AFF: ' . $result->rowCount() . $nl;
01020 }
01021 break;
01022 }
01023 $code .= 'TIME: ' . $time . $nl . $nl;
01024
01025 $this->_debugWriteToFile($code);
01026
01027 return $this;
01028 }
01029
01030
01031
01032
01033
01034
01035
01036 protected function _debugException(Exception $e)
01037 {
01038 if (!$this->_debug) {
01039 throw $e;
01040 }
01041
01042 $nl = "\n";
01043 $code = 'EXCEPTION ' . $e->getMessage() . $nl
01044 . 'E TRACE: ' . print_r($e->getTrace(), true) . $nl . $nl;
01045 $this->_debugWriteToFile($code);
01046
01047 throw $e;
01048 }
01049
01050
01051
01052
01053
01054
01055 protected function _debugWriteToFile($str)
01056 {
01057 if (!$this->_debugIoAdapter) {
01058 $this->_debugIoAdapter = new Varien_Io_File();
01059 $dir = $this->_debugIoAdapter->dirname($this->_debugFile);
01060 $this->_debugIoAdapter->checkAndCreateFolder($dir);
01061 $this->_debugIoAdapter->open(array('path' => $dir));
01062 $this->_debugFile = basename($this->_debugFile);
01063 }
01064
01065 $this->_debugIoAdapter->streamOpen($this->_debugFile, 'a');
01066 $this->_debugIoAdapter->streamLock();
01067 $this->_debugIoAdapter->streamWrite($str);
01068 $this->_debugIoAdapter->streamUnlock();
01069 $this->_debugIoAdapter->streamClose();
01070 }
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083 public function quoteInto($text, $value, $type = null, $count = null)
01084 {
01085 if (is_array($value) && empty($value)) {
01086 $value = new Zend_Db_Expr('NULL');
01087 }
01088 return parent::quoteInto($text, $value, $type, $count);
01089 }
01090
01091
01092
01093
01094
01095
01096
01097 protected function _getTableName($tableName, $schemaName = null)
01098 {
01099 return ($schemaName ? $schemaName . '.' : '') . $tableName;
01100 }
01101
01102
01103
01104
01105
01106
01107
01108
01109 public function resetDdlCache($tableName = null, $schemaName = null)
01110 {
01111 if (is_null($tableName)) {
01112 $this->_ddlCache = array();
01113 }
01114 else {
01115 $cacheKey = $this->_getTableName($tableName, $schemaName);
01116
01117 unset($this->_ddlCache[self::DDL_DESCRIBE][$cacheKey]);
01118 unset($this->_ddlCache[self::DDL_CREATE][$cacheKey]);
01119 unset($this->_ddlCache[self::DDL_INDEX][$cacheKey]);
01120 unset($this->_ddlCache[self::DDL_FOREIGN_KEY][$cacheKey]);
01121 }
01122
01123 return $this;
01124 }
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154 public function describeTable($tableName, $schemaName = null)
01155 {
01156 $cacheKey = $this->_getTableName($tableName, $schemaName);
01157
01158 if (!isset($this->_ddlCache[self::DDL_DESCRIBE][$cacheKey])) {
01159 $this->_ddlCache[self::DDL_DESCRIBE][$cacheKey] = parent::describeTable($tableName, $schemaName);
01160 }
01161
01162 return $this->_ddlCache[self::DDL_DESCRIBE][$cacheKey];
01163 }
01164
01165
01166
01167
01168
01169
01170
01171
01172 public function truncate($tableName, $schemaName = null)
01173 {
01174 $tableName = $this->_getTableName($tableName, $schemaName);
01175 $sql = sprintf('TRUNCATE %s', $this->quoteIdentifier($tableName));
01176 $this->raw_query($sql);
01177
01178 return $this;
01179 }
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189 public function changeTableEngine($tableName, $engine, $schemaName = null)
01190 {
01191 $sql = sprintf('ALTER TABLE %s ENGINE=%s',
01192 $this->quoteIdentifier($this->_getTableName($tableName, $schemaName)),
01193 $engine);
01194 return $this->raw_query($sql);
01195 }
01196 }