Skip to content

Commit

Permalink
Add a temporary fix to fix a bug in the SQLite Adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
HavokInspiration committed Sep 18, 2015
1 parent d0d8d89 commit fbf08e5
Showing 1 changed file with 80 additions and 2 deletions.
82 changes: 80 additions & 2 deletions src/CakeAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Cake\Database\Connection;
use Phinx\Db\Adapter\AdapterInterface;
use Phinx\Db\Adapter\SQLiteAdapter;
use Phinx\Db\Table;
use Phinx\Db\Table\Column;
use Phinx\Db\Table\ForeignKey;
Expand Down Expand Up @@ -506,6 +507,9 @@ public function addForeignKey(Table $table, ForeignKey $foreignKey)

/**
* Drops the specified foreign key from a database table.
* If the adapter property is an instance of the \Phinx\Db\Adapter\SQLiteAdapter,
* a specific method will be called. The original one from Phinx contains a bug
* that can drop a table in certain conditions.
*
* @param string $tableName
* @param string[] $columns Column(s)
Expand All @@ -514,7 +518,81 @@ public function addForeignKey(Table $table, ForeignKey $foreignKey)
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
return $this->adapter->dropForeignKey($tableName, $columns, $constraint);
if (!($this->adapter instanceof SQLiteAdapter)) {
return $this->adapter->dropForeignKey($tableName, $columns, $constraint);
}

$this->dropForeignKeySqlite($tableName, $columns, $constraint);
}

/**
* Specific method to drop a foreign key when SQLite is being used.
* This is to prevent a bug from Phinx that could drop tables.
*
* @param string $tableName
* @param string[] $columns Column(s)
* @param string $constraint Constraint name
* @return void
*/
public function dropForeignKeySqlite($tableName, $columns, $constraint = null)
{
$this->startCommandTimer();
if (is_string($columns)) {
$columns = [$columns]; // str to array
}

$this->writeCommand('dropForeignKey', [$tableName, $columns]);

$tmpTableName = 'tmp_' . $tableName;

$rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');

$sql = '';
foreach ($rows as $table) {
if ($table['tbl_name'] == $tableName) {
$sql = $table['sql'];
}
}

$rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
$replaceColumns = [];
foreach ($rows as $row) {
if (!in_array($row['name'], $columns)) {
$replaceColumns[] = $row['name'];
} else {
$found = true;
}
}

if (!isset($found)) {
throw new \InvalidArgumentException(sprintf(
'The specified column doesn\'t exist: '
));
}

$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $this->quoteTableName($tableName), $tmpTableName));

foreach ($columns as $columnName) {
$search = sprintf(
"/,[^,]*\(%s(?:,`?(.*)`?)?\) REFERENCES[^,]*\([^\)]*\)[^,)]*/",
$this->quoteColumnName($columnName)
);
$sql = preg_replace($search, '', $sql, 1);
}

$this->execute($sql);

$sql = sprintf(
'INSERT INTO %s(%s) SELECT %s FROM %s',
$tableName,
implode(', ', $columns),
implode(', ', $columns),
$tmpTableName
);

$this->execute($sql);
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tmpTableName)));
$this->endCommandTimer();
}

/**
Expand Down Expand Up @@ -557,7 +635,7 @@ public function getSqlType($type, $limit = null)
* @param array $options Options
* @return void
*/
public function createDatabase($name, $options = array())
public function createDatabase($name, $options = [])
{
return $this->adapter->createDatabase($name, $options);
}
Expand Down

0 comments on commit fbf08e5

Please sign in to comment.