Commit 63b7ef12 authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge pull request #220 from hason/sqlite_alter

[WIP] Added support for alter table, foreign keys and autoincrement detection to Sqlite platform and schema
parents aad1a946 a42b8ed1
...@@ -1833,6 +1833,10 @@ abstract class AbstractPlatform ...@@ -1833,6 +1833,10 @@ abstract class AbstractPlatform
$default = " DEFAULT ".$field['default']; $default = " DEFAULT ".$field['default'];
} else if ((string)$field['type'] == 'DateTime' && $field['default'] == $this->getCurrentTimestampSQL()) { } else if ((string)$field['type'] == 'DateTime' && $field['default'] == $this->getCurrentTimestampSQL()) {
$default = " DEFAULT ".$this->getCurrentTimestampSQL(); $default = " DEFAULT ".$this->getCurrentTimestampSQL();
} else if ((string)$field['type'] == 'Time' && $field['default'] == $this->getCurrentTimeSQL()) {
$default = " DEFAULT ".$this->getCurrentTimeSQL();
} else if ((string)$field['type'] == 'Date' && $field['default'] == $this->getCurrentDateSQL()) {
$default = " DEFAULT ".$this->getCurrentDateSQL();
} else if ((string) $field['type'] == 'Boolean') { } else if ((string) $field['type'] == 'Boolean') {
$default = " DEFAULT '" . $this->convertBooleans($field['default']) . "'"; $default = " DEFAULT '" . $this->convertBooleans($field['default']) . "'";
} }
......
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
namespace Doctrine\DBAL\Platforms; namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Constraint;
/** /**
* The SqlitePlatform class describes the specifics and dialects of the SQLite * The SqlitePlatform class describes the specifics and dialects of the SQLite
...@@ -28,6 +33,7 @@ use Doctrine\DBAL\DBALException; ...@@ -28,6 +33,7 @@ use Doctrine\DBAL\DBALException;
* @since 2.0 * @since 2.0
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de> * @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Martin Hasoň <martin.hason@gmail.com>
* @todo Rename: SQLitePlatform * @todo Rename: SQLitePlatform
*/ */
class SqlitePlatform extends AbstractPlatform class SqlitePlatform extends AbstractPlatform
...@@ -263,16 +269,32 @@ class SqlitePlatform extends AbstractPlatform ...@@ -263,16 +269,32 @@ class SqlitePlatform extends AbstractPlatform
*/ */
protected function _getCreateTableSQL($name, array $columns, array $options = array()) protected function _getCreateTableSQL($name, array $columns, array $options = array())
{ {
$name = str_replace(".", "__", $name); $name = str_replace('.', '__', $name);
$queryFields = $this->getColumnDeclarationListSQL($columns); $queryFields = $this->getColumnDeclarationListSQL($columns);
if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
foreach ($options['uniqueConstraints'] as $name => $definition) {
$queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
}
}
if (isset($options['primary']) && ! empty($options['primary'])) { if (isset($options['primary']) && ! empty($options['primary'])) {
$keyColumns = array_unique(array_values($options['primary'])); $keyColumns = array_unique(array_values($options['primary']));
$queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')'; $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')';
} }
if (isset($options['foreignKeys'])) {
foreach ($options['foreignKeys'] as $foreignKey) {
$queryFields.= ', '.$this->getForeignKeyDeclarationSQL($foreignKey);
}
}
$query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')'; $query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')';
if (isset($options['alter']) && true === $options['alter']) {
return $query;
}
if (isset($options['indexes']) && ! empty($options['indexes'])) { if (isset($options['indexes']) && ! empty($options['indexes'])) {
foreach ($options['indexes'] as $index => $indexDef) { foreach ($options['indexes'] as $index => $indexDef) {
$query[] = $this->getCreateIndexSQL($indexDef, $name); $query[] = $this->getCreateIndexSQL($indexDef, $name);
...@@ -305,16 +327,22 @@ class SqlitePlatform extends AbstractPlatform ...@@ -305,16 +327,22 @@ class SqlitePlatform extends AbstractPlatform
return 'CLOB'; return 'CLOB';
} }
/**
* {@inheritDoc}
*/
public function getListTableConstraintsSQL($table) public function getListTableConstraintsSQL($table)
{ {
$table = str_replace(".", "__", $table); $table = str_replace('.', '__', $table);
return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = '$table' AND sql NOT NULL ORDER BY name"; return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = '$table' AND sql NOT NULL ORDER BY name";
} }
/**
* {@inheritDoc}
*/
public function getListTableColumnsSQL($table, $currentDatabase = null) public function getListTableColumnsSQL($table, $currentDatabase = null)
{ {
$table = str_replace(".", "__", $table); $table = str_replace('.', '__', $table);
return "PRAGMA table_info($table)"; return "PRAGMA table_info($table)";
} }
...@@ -324,11 +352,14 @@ class SqlitePlatform extends AbstractPlatform ...@@ -324,11 +352,14 @@ class SqlitePlatform extends AbstractPlatform
*/ */
public function getListTableIndexesSQL($table, $currentDatabase = null) public function getListTableIndexesSQL($table, $currentDatabase = null)
{ {
$table = str_replace(".", "__", $table); $table = str_replace('.', '__', $table);
return "PRAGMA index_list($table)"; return "PRAGMA index_list($table)";
} }
/**
* {@inheritDoc}
*/
public function getListTablesSQL() public function getListTablesSQL()
{ {
return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' " return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' "
...@@ -344,34 +375,33 @@ class SqlitePlatform extends AbstractPlatform ...@@ -344,34 +375,33 @@ class SqlitePlatform extends AbstractPlatform
return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL"; return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
} }
/**
* {@inheritDoc}
*/
public function getCreateViewSQL($name, $sql) public function getCreateViewSQL($name, $sql)
{ {
return 'CREATE VIEW ' . $name . ' AS ' . $sql; return 'CREATE VIEW ' . $name . ' AS ' . $sql;
} }
public function getDropViewSQL($name)
{
return 'DROP VIEW '. $name;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*
* SQLite does support foreign key constraints, but only in CREATE TABLE statements...
* This really limits their usefulness and requires SQLite specific handling, so
* we simply say that SQLite does NOT support foreign keys for now...
*/ */
public function supportsForeignKeyConstraints() public function getDropViewSQL($name)
{ {
return false; return 'DROP VIEW '. $name;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function supportsAlterTable() public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
{ {
return false; $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
$query .= (($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) ? ' ' : ' NOT ') . 'DEFERRABLE';
$query .= ' INITIALLY ' . (($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) ? 'DEFERRED' : 'IMMEDIATE');
return $query;
} }
/** /**
...@@ -395,7 +425,8 @@ class SqlitePlatform extends AbstractPlatform ...@@ -395,7 +425,8 @@ class SqlitePlatform extends AbstractPlatform
*/ */
public function getTruncateTableSQL($tableName, $cascade = false) public function getTruncateTableSQL($tableName, $cascade = false)
{ {
$tableName = str_replace(".", "__", $tableName); $tableName = str_replace('.', '__', $tableName);
return 'DELETE FROM '.$tableName; return 'DELETE FROM '.$tableName;
} }
...@@ -441,6 +472,9 @@ class SqlitePlatform extends AbstractPlatform ...@@ -441,6 +472,9 @@ class SqlitePlatform extends AbstractPlatform
return 0; return 0;
} }
/**
* {@inheritDoc}
*/
public function getForUpdateSql() public function getForUpdateSql()
{ {
return ''; return '';
...@@ -495,6 +529,47 @@ class SqlitePlatform extends AbstractPlatform ...@@ -495,6 +529,47 @@ class SqlitePlatform extends AbstractPlatform
return 'Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords'; return 'Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords';
} }
/**
* {@inheritDoc}
*/
protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
{
if ( ! $diff->fromTable instanceof Table) {
throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
}
$sql = array();
foreach ($diff->fromTable->getIndexes() as $index) {
if ( ! $index->isPrimary()) {
$sql[] = $this->getDropIndexSQL($index, $diff->name);
}
}
return $sql;
}
/**
* {@inheritDoc}
*/
protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
{
if ( ! $diff->fromTable instanceof Table) {
throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
}
$sql = array();
$tableName = $diff->newName ?: $diff->name;
foreach ($this->getIndexesInAlteredTable($diff) as $indexName => $index) {
if ($index->isPrimary()) {
continue;
}
$sql[] = $this->getCreateIndexSQL($index, $tableName);
}
return $sql;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
...@@ -508,7 +583,7 @@ class SqlitePlatform extends AbstractPlatform ...@@ -508,7 +583,7 @@ class SqlitePlatform extends AbstractPlatform
*/ */
public function getTemporaryTableName($tableName) public function getTemporaryTableName($tableName)
{ {
$tableName = str_replace(".", "__", $tableName); $tableName = str_replace('.', '__', $tableName);
return $tableName; return $tableName;
} }
...@@ -526,4 +601,353 @@ class SqlitePlatform extends AbstractPlatform ...@@ -526,4 +601,353 @@ class SqlitePlatform extends AbstractPlatform
{ {
return true; return true;
} }
/**
* {@inheritDoc}
*/
public function getCreatePrimaryKeySQL(Index $index, $table)
{
throw new DBALException('Sqlite platform does not support alter primary key.');
}
/**
* {@inheritdoc}
*/
public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
{
throw new DBALException('Sqlite platform does not support alter foreign key.');
}
/**
* {@inheritdoc}
*/
public function getDropForeignKeySQL($foreignKey, $table)
{
throw new DBALException('Sqlite platform does not support alter foreign key.');
}
/**
* {@inheritDoc}
*/
public function getCreateConstraintSQL(Constraint $constraint, $table)
{
throw new DBALException('Sqlite platform does not support alter constraint.');
}
/**
* {@inheritDoc}
*/
public function getCreateTableSQL(Table $table, $createFlags = null)
{
$createFlags = null === $createFlags ? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS : $createFlags;
return parent::getCreateTableSQL($table, $createFlags);
}
/**
* {@inheritDoc}
*/
public function getListTableForeignKeysSQL($table, $database = null)
{
$table = str_replace('.', '__', $table);
return "PRAGMA foreign_key_list($table)";
}
/**
* {@inheritDoc}
*/
public function getAlterTableSQL(TableDiff $diff)
{
$sql = $this->getSimpleAlterTableSQL($diff);
if (false !== $sql) {
return $sql;
}
$fromTable = $diff->fromTable;
if ( ! $fromTable instanceof Table) {
throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
}
$table = clone $fromTable;
$columns = array();
$oldColumnNames = array();
$newColumnNames = array();
$columnSql = array();
foreach ($table->getColumns() as $columnName => $column) {
$columnName = strtolower($columnName);
$columns[$columnName] = $column;
$oldColumnNames[$columnName] = $newColumnNames[$columnName] = $column->getQuotedName($this);
}
foreach ($diff->removedColumns as $columnName => $column) {
if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
continue;
}
$columnName = strtolower($columnName);
if (isset($columns[$columnName])) {
unset($columns[$columnName]);
unset($oldColumnNames[$columnName]);
unset($newColumnNames[$columnName]);
}
}
foreach ($diff->renamedColumns as $oldColumnName => $column) {
if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
continue;
}
$oldColumnName = strtolower($oldColumnName);
if (isset($columns[$oldColumnName])) {
unset($columns[$oldColumnName]);
}
$columns[strtolower($column->getName())] = $column;
if (isset($newColumnNames[$oldColumnName])) {
$newColumnNames[$oldColumnName] = $column->getQuotedName($this);
}
}
foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
continue;
}
if (isset($columns[$oldColumnName])) {
unset($columns[$oldColumnName]);
}
$columns[strtolower($columnDiff->column->getName())] = $columnDiff->column;
if (isset($newColumnNames[$oldColumnName])) {
$newColumnNames[$oldColumnName] = $columnDiff->column->getQuotedName($this);
}
}
foreach ($diff->addedColumns as $columnName => $column) {
if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
continue;
}
$columns[strtolower($columnName)] = $column;
}
$sql = array();
$tableSql = array();
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
$newTableName = $diff->newName ?: $diff->name;
$dataTable = new Table('__temp__'.$table->getName());
$newTable = new Table($table->getName(), $columns, $this->getPrimaryIndexInAlteredTable($diff), $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions());
$newTable->addOption('alter', true);
$sql = $this->getPreAlterTableIndexForeignKeySQL($diff);
//$sql = array_merge($sql, $this->getCreateTableSQL($dataTable, 0));
$sql[] = sprintf('CREATE TEMPORARY TABLE %s AS SELECT %s FROM %s', $dataTable->getQuotedName($this), implode(', ', $oldColumnNames), $table->getQuotedName($this));
$sql[] = $this->getDropTableSQL($fromTable);
$sql = array_merge($sql, $this->getCreateTableSQL($newTable));
$sql[] = sprintf('INSERT INTO %s (%s) SELECT %s FROM %s', $newTable->getQuotedName($this), implode(', ', $newColumnNames), implode(', ', $oldColumnNames), $dataTable->getQuotedName($this));
$sql[] = $this->getDropTableSQL($dataTable);
if ($diff->newName && $diff->newName != $diff->name) {
$renamedTable = new Table($diff->newName);
$sql[] = 'ALTER TABLE '.$newTable->getQuotedName($this).' RENAME TO '.$renamedTable->getQuotedName($this);
}
$sql = array_merge($sql, $this->getPostAlterTableIndexForeignKeySQL($diff));
}
return array_merge($sql, $tableSql, $columnSql);
}
private function getSimpleAlterTableSQL(TableDiff $diff)
{
if ( ! empty($diff->renamedColumns) || ! empty($diff->addedForeignKeys) || ! empty($diff->addedIndexes)
|| ! empty($diff->changedColumns) || ! empty($diff->changedForeignKeys) || ! empty($diff->changedIndexes)
|| ! empty($diff->removedColumns) || ! empty($diff->removedForeignKeys) || ! empty($diff->removedIndexes)
) {
return false;
}
$table = new Table($diff->name);
$sql = array();
$tableSql = array();
$columnSql = array();
foreach ($diff->addedColumns as $columnName => $column) {
if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
continue;
}
$field = array_merge(array('unique' => null, 'autoincrement' => null, 'default' => null), $column->toArray());
$type = (string) $field['type'];
switch (true) {
case isset($field['columnDefinition']) || $field['autoincrement'] || $field['unique']:
case $type == 'DateTime' && $field['default'] == $this->getCurrentTimestampSQL():
case $type == 'Date' && $field['default'] == $this->getCurrentDateSQL():
case $type == 'Time' && $field['default'] == $this->getCurrentTimeSQL():
return false;
}
$field['name'] = $column->getQuotedName($this);
if (strtolower($field['type']) == 'string' && $field['length'] === null) {
$field['length'] = 255;
}
$sql[] = 'ALTER TABLE '.$table->getQuotedName($this).' ADD COLUMN '.$this->getColumnDeclarationSQL($field['name'], $field);
}
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if ($diff->newName !== false) {
$newTable = new Table($diff->newName);
$sql[] = 'ALTER TABLE '.$table->getQuotedName($this).' RENAME TO '.$newTable->getQuotedName($this);
}
}
return array_merge($sql, $tableSql, $columnSql);
}
private function getColumnNamesInAlteredTable(TableDiff $diff)
{
$columns = array();
foreach ($diff->fromTable->getColumns() as $columnName => $column) {
$columns[strtolower($columnName)] = $column->getName();
}
foreach ($diff->removedColumns as $columnName => $column) {
$columnName = strtolower($columnName);
if (isset($columns[$columnName])) {
unset($columns[$columnName]);
}
}
foreach ($diff->renamedColumns as $oldColumnName => $column) {
$columnName = $column->getName();
$columns[strtolower($oldColumnName)] = $columnName;
$columns[strtolower($columnName)] = $columnName;
}
foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
$columnName = $columnDiff->column->getName();
$columns[strtolower($oldColumnName)] = $columnName;
$columns[strtolower($columnName)] = $columnName;
}
foreach ($diff->addedColumns as $columnName => $column) {
$columns[strtolower($columnName)] = $columnName;
}
return $columns;
}
private function getIndexesInAlteredTable(TableDiff $diff)
{
$indexes = $diff->fromTable->getIndexes();
$columnNames = $this->getColumnNamesInAlteredTable($diff);
foreach ($indexes as $key => $index) {
$changed = false;
$indexColumns = array();
foreach ($index->getColumns() as $columnName) {
$normalizedColumnName = strtolower($columnName);
if ( ! isset($columnNames[$normalizedColumnName])) {
unset($indexes[$key]);
continue 2;
} else {
$indexColumns[] = $columnNames[$normalizedColumnName];
if ($columnName !== $columnNames[$normalizedColumnName]) {
$changed = true;
}
}
}
if ($changed) {
$indexes[$key] = new Index($index->getName(), $indexColumns, $index->isUnique(), $index->isPrimary(), $index->getFlags());
}
}
foreach ($diff->removedIndexes as $index) {
$indexName = strtolower($index->getName());
if (strlen($indexName) && isset($indexes[$indexName])) {
unset($indexes[$indexName]);
}
}
foreach (array_merge($diff->changedIndexes, $diff->addedIndexes) as $index) {
$indexName = strtolower($index->getName());
if (strlen($indexName)) {
$indexes[$indexName] = $index;
} else {
$indexes[] = $index;
}
}
return $indexes;
}
private function getForeignKeysInAlteredTable(TableDiff $diff)
{
$foreignKeys = $diff->fromTable->getForeignKeys();
$columnNames = $this->getColumnNamesInAlteredTable($diff);
foreach ($foreignKeys as $key => $constraint) {
$changed = false;
$localColumns = array();
foreach ($constraint->getLocalColumns() as $columnName) {
$normalizedColumnName = strtolower($columnName);
if ( ! isset($columnNames[$normalizedColumnName])) {
unset($foreignKeys[$key]);
continue 2;
} else {
$localColumns[] = $columnNames[$normalizedColumnName];
if ($columnName !== $columnNames[$normalizedColumnName]) {
$changed = true;
}
}
}
if ($changed) {
$foreignKeys[$key] = new ForeignKeyConstraint($localColumns, $constraint->getForeignTableName(), $constraint->getForeignColumns(), $constraint->getName(), $constraint->getOptions());
}
}
foreach ($diff->removedForeignKeys as $constraint) {
$constraintName = strtolower($constraint->getName());
if (strlen($constraintName) && isset($foreignKeys[$constraintName])) {
unset($foreignKeys[$constraintName]);
}
}
foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) {
$constraintName = strtolower($constraint->getName());
if (strlen($constraintName)) {
$foreignKeys[$constraintName] = $constraint;
} else {
$foreignKeys[] = $constraint;
}
}
return $foreignKeys;
}
private function getPrimaryIndexInAlteredTable(TableDiff $diff)
{
$primaryIndex = array();
foreach ($this->getIndexesInAlteredTable($diff) as $index) {
if ($index->isPrimary()) {
$primaryIndex = array($index->getName() => $index);
}
}
return $primaryIndex;
}
} }
...@@ -24,7 +24,7 @@ namespace Doctrine\DBAL\Schema; ...@@ -24,7 +24,7 @@ namespace Doctrine\DBAL\Schema;
/** /**
* Represent the change of a column * Represent the change of a column
* *
* *
* @link www.doctrine-project.org * @link www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
...@@ -44,11 +44,17 @@ class ColumnDiff ...@@ -44,11 +44,17 @@ class ColumnDiff
*/ */
public $changedProperties = array(); public $changedProperties = array();
public function __construct($oldColumnName, Column $column, array $changedProperties = array()) /**
* @var Column
*/
public $fromColumn;
public function __construct($oldColumnName, Column $column, array $changedProperties = array(), Column $fromColumn = null)
{ {
$this->oldColumnName = $oldColumnName; $this->oldColumnName = $oldColumnName;
$this->column = $column; $this->column = $column;
$this->changedProperties = $changedProperties; $this->changedProperties = $changedProperties;
$this->fromColumn = $fromColumn;
} }
public function hasChanged($propertyName) public function hasChanged($propertyName)
......
...@@ -58,6 +58,7 @@ class Comparator ...@@ -58,6 +58,7 @@ class Comparator
public function compare(Schema $fromSchema, Schema $toSchema) public function compare(Schema $fromSchema, Schema $toSchema)
{ {
$diff = new SchemaDiff(); $diff = new SchemaDiff();
$diff->fromSchema = $fromSchema;
$foreignKeysToTable = array(); $foreignKeysToTable = array();
...@@ -179,6 +180,7 @@ class Comparator ...@@ -179,6 +180,7 @@ class Comparator
{ {
$changes = 0; $changes = 0;
$tableDifferences = new TableDiff($table1->getName()); $tableDifferences = new TableDiff($table1->getName());
$tableDifferences->fromTable = $table1;
$table1Columns = $table1->getColumns(); $table1Columns = $table1->getColumns();
$table2Columns = $table2->getColumns(); $table2Columns = $table2->getColumns();
...@@ -203,6 +205,7 @@ class Comparator ...@@ -203,6 +205,7 @@ class Comparator
$changedProperties = $this->diffColumn( $column, $table2->getColumn($columnName) ); $changedProperties = $this->diffColumn( $column, $table2->getColumn($columnName) );
if (count($changedProperties) ) { if (count($changedProperties) ) {
$columnDiff = new ColumnDiff($column->getName(), $table2->getColumn($columnName), $changedProperties); $columnDiff = new ColumnDiff($column->getName(), $table2->getColumn($columnName), $changedProperties);
$columnDiff->fromColumn = $column;
$tableDifferences->changedColumns[$column->getName()] = $columnDiff; $tableDifferences->changedColumns[$column->getName()] = $columnDiff;
$changes++; $changes++;
} }
......
...@@ -204,6 +204,16 @@ class Index extends AbstractAsset implements Constraint ...@@ -204,6 +204,16 @@ class Index extends AbstractAsset implements Constraint
return false; return false;
} }
/**
* Returns platform specific flags for indexes.
*
* @return array
*/
public function getFlags()
{
return array_keys($this->_flags);
}
/** /**
* Add Flag for an index that translates to platform specific handling. * Add Flag for an index that translates to platform specific handling.
* *
......
...@@ -24,7 +24,7 @@ use \Doctrine\DBAL\Platforms\AbstractPlatform; ...@@ -24,7 +24,7 @@ use \Doctrine\DBAL\Platforms\AbstractPlatform;
/** /**
* Schema Diff * Schema Diff
* *
* *
* @link www.doctrine-project.org * @link www.doctrine-project.org
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License * @license http://ez.no/licenses/new_bsd New BSD License
...@@ -34,6 +34,11 @@ use \Doctrine\DBAL\Platforms\AbstractPlatform; ...@@ -34,6 +34,11 @@ use \Doctrine\DBAL\Platforms\AbstractPlatform;
*/ */
class SchemaDiff class SchemaDiff
{ {
/**
* @var Schema
*/
public $fromSchema;
/** /**
* All added tables * All added tables
* *
...@@ -81,12 +86,14 @@ class SchemaDiff ...@@ -81,12 +86,14 @@ class SchemaDiff
* @param array(string=>Table) $newTables * @param array(string=>Table) $newTables
* @param array(string=>TableDiff) $changedTables * @param array(string=>TableDiff) $changedTables
* @param array(string=>bool) $removedTables * @param array(string=>bool) $removedTables
* @param Schema $fromSchema
*/ */
public function __construct($newTables = array(), $changedTables = array(), $removedTables = array()) public function __construct($newTables = array(), $changedTables = array(), $removedTables = array(), Schema $fromSchema = null)
{ {
$this->newTables = $newTables; $this->newTables = $newTables;
$this->changedTables = $changedTables; $this->changedTables = $changedTables;
$this->removedTables = $removedTables; $this->removedTables = $removedTables;
$this->fromSchema = $fromSchema;
} }
/** /**
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema; namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\DBALException;
/** /**
* SqliteSchemaManager * SqliteSchemaManager
* *
...@@ -26,6 +28,7 @@ namespace Doctrine\DBAL\Schema; ...@@ -26,6 +28,7 @@ namespace Doctrine\DBAL\Schema;
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Jonathan H. Wage <jonwage@gmail.com> * @author Jonathan H. Wage <jonwage@gmail.com>
* @author Martin Hasoň <martin.hason@gmail.com>
* @version $Revision$ * @version $Revision$
* @since 2.0 * @since 2.0
*/ */
...@@ -61,6 +64,93 @@ class SqliteSchemaManager extends AbstractSchemaManager ...@@ -61,6 +64,93 @@ class SqliteSchemaManager extends AbstractSchemaManager
$conn->close(); $conn->close();
} }
/**
* {@inheritdoc}
*/
public function renameTable($name, $newName)
{
$tableDiff = new TableDiff($name);
$tableDiff->fromTable = $this->listTableDetails($name);
$tableDiff->newName = $newName;
$this->alterTable($tableDiff);
}
/**
* {@inheritdoc}
*/
public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
{
$tableDiff = $this->getTableDiffForAlterForeignKey($foreignKey, $table);
$tableDiff->addedForeignKeys[] = $foreignKey;
$this->alterTable($tableDiff);
}
/**
* {@inheritdoc}
*/
public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
{
$tableDiff = $this->getTableDiffForAlterForeignKey($foreignKey, $table);
$tableDiff->changedForeignKeys[] = $foreignKey;
$this->alterTable($tableDiff);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($foreignKey, $table)
{
$tableDiff = $this->getTableDiffForAlterForeignKey($foreignKey, $table);
$tableDiff->removedForeignKeys[] = $foreignKey;
$this->alterTable($tableDiff);
}
/**
* {@inheritdoc}
*/
public function listTableForeignKeys($table, $database = null)
{
if (null === $database) {
$database = $this->_conn->getDatabase();
}
$sql = $this->_platform->getListTableForeignKeysSQL($table, $database);
$tableForeignKeys = $this->_conn->fetchAll($sql);
if ( ! empty($tableForeignKeys)) {
$createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
$createSql = isset($createSql[0]['sql']) ? $createSql[0]['sql'] : '';
if (preg_match_all('#
(?:CONSTRAINT\s+([^\s]+)\s+)?
(?:FOREIGN\s+KEY[^\)]+\)\s*)?
REFERENCES\s+[^\s]+\s+(?:\([^\)]+\))?
(?:
[^,]*?
(NOT\s+DEFERRABLE|DEFERRABLE)
(?:\s+INITIALLY\s+(DEFERRED|IMMEDIATE))?
)?#isx',
$createSql, $match)) {
$names = array_reverse($match[1]);
$deferrable = array_reverse($match[2]);
$deferred = array_reverse($match[3]);
} else {
$names = $deferrable = $deferred = array();
}
foreach ($tableForeignKeys as $key => $value) {
$id = $value['id'];
$tableForeignKeys[$key]['constraint_name'] = isset($names[$id]) && '' != $names[$id] ? $names[$id] : $id;
$tableForeignKeys[$key]['deferrable'] = isset($deferrable[$id]) && 'deferrable' == strtolower($deferrable[$id]) ? true : false;
$tableForeignKeys[$key]['deferred'] = isset($deferred[$id]) && 'deferred' == strtolower($deferred[$id]) ? true : false;
}
}
return $this->_getPortableTableForeignKeysList($tableForeignKeys);
}
protected function _getPortableTableDefinition($table) protected function _getPortableTableDefinition($table)
{ {
return $table['name']; return $table['name'];
...@@ -122,6 +212,31 @@ class SqliteSchemaManager extends AbstractSchemaManager ...@@ -122,6 +212,31 @@ class SqliteSchemaManager extends AbstractSchemaManager
); );
} }
protected function _getPortableTableColumnList($table, $database, $tableColumns)
{
$list = parent::_getPortableTableColumnList($table, $database, $tableColumns);
$autoincrementColumn = null;
$autoincrementCount = 0;
foreach ($tableColumns as $tableColumn) {
if ('1' == $tableColumn['pk']) {
$autoincrementCount++;
if (null === $autoincrementColumn && 'integer' == strtolower($tableColumn['type'])) {
$autoincrementColumn = $tableColumn['name'];
}
}
}
if (1 == $autoincrementCount && null !== $autoincrementColumn) {
foreach ($list as $column) {
if ($autoincrementColumn == $column->getName()) {
$column->setAutoincrement(true);
}
}
}
return $list;
}
protected function _getPortableTableColumnDefinition($tableColumn) protected function _getPortableTableColumnDefinition($tableColumn)
{ {
$e = explode('(', $tableColumn['type']); $e = explode('(', $tableColumn['type']);
...@@ -190,4 +305,67 @@ class SqliteSchemaManager extends AbstractSchemaManager ...@@ -190,4 +305,67 @@ class SqliteSchemaManager extends AbstractSchemaManager
{ {
return new View($view['name'], $view['sql']); return new View($view['name'], $view['sql']);
} }
protected function _getPortableTableForeignKeysList($tableForeignKeys)
{
$list = array();
foreach ($tableForeignKeys as $key => $value) {
$value = array_change_key_case($value, CASE_LOWER);
$name = $value['constraint_name'];
if ( ! isset($list[$name])) {
if ( ! isset($value['on_delete']) || $value['on_delete'] == "RESTRICT") {
$value['on_delete'] = null;
}
if ( ! isset($value['on_update']) || $value['on_update'] == "RESTRICT") {
$value['on_update'] = null;
}
$list[$name] = array(
'name' => $name,
'local' => array(),
'foreign' => array(),
'foreignTable' => $value['table'],
'onDelete' => $value['on_delete'],
'onUpdate' => $value['on_update'],
'deferrable' => $value['deferrable'],
'deferred'=> $value['deferred'],
);
}
$list[$name]['local'][] = $value['from'];
$list[$name]['foreign'][] = $value['to'];
}
$result = array();
foreach($list as $constraint) {
$result[] = new ForeignKeyConstraint(
array_values($constraint['local']), $constraint['foreignTable'],
array_values($constraint['foreign']), $constraint['name'],
array(
'onDelete' => $constraint['onDelete'],
'onUpdate' => $constraint['onUpdate'],
'deferrable' => $constraint['deferrable'],
'deferred'=> $constraint['deferred'],
)
);
}
return $result;
}
private function getTableDiffForAlterForeignKey(ForeignKeyConstraint $foreignKey, $table)
{
if ( ! $table instanceof Table) {
$tableDetails = $this->tryMethod('listTableDetails', $table);
if (false === $table) {
throw new \DBALException(sprintf('Sqlite schema manager requires to modify foreign keys table definition "%s".', $table));
}
$table = $tableDetails;
}
$tableDiff = new TableDiff($table->getName());
$tableDiff->fromTable = $table;
return $tableDiff;
}
} }
...@@ -22,7 +22,7 @@ namespace Doctrine\DBAL\Schema; ...@@ -22,7 +22,7 @@ namespace Doctrine\DBAL\Schema;
/** /**
* Table Diff * Table Diff
* *
* *
* @link www.doctrine-project.org * @link www.doctrine-project.org
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License * @license http://ez.no/licenses/new_bsd New BSD License
...@@ -111,6 +111,11 @@ class TableDiff ...@@ -111,6 +111,11 @@ class TableDiff
*/ */
public $removedForeignKeys = array(); public $removedForeignKeys = array();
/**
* @var Table
*/
public $fromTable;
/** /**
* Constructs an TableDiff object. * Constructs an TableDiff object.
* *
...@@ -120,10 +125,11 @@ class TableDiff ...@@ -120,10 +125,11 @@ class TableDiff
* @param array(string=>Index) $addedIndexes * @param array(string=>Index) $addedIndexes
* @param array(string=>Index) $changedIndexes * @param array(string=>Index) $changedIndexes
* @param array(string=>bool) $removedIndexes * @param array(string=>bool) $removedIndexes
* @param Table $fromTable
*/ */
public function __construct($tableName, $addedColumns = array(), public function __construct($tableName, $addedColumns = array(),
$changedColumns = array(), $removedColumns = array(), $addedIndexes = array(), $changedColumns = array(), $removedColumns = array(), $addedIndexes = array(),
$changedIndexes = array(), $removedIndexes = array()) $changedIndexes = array(), $removedIndexes = array(), Table $fromTable = null)
{ {
$this->name = $tableName; $this->name = $tableName;
$this->addedColumns = $addedColumns; $this->addedColumns = $addedColumns;
...@@ -132,5 +138,6 @@ class TableDiff ...@@ -132,5 +138,6 @@ class TableDiff
$this->addedIndexes = $addedIndexes; $this->addedIndexes = $addedIndexes;
$this->changedIndexes = $changedIndexes; $this->changedIndexes = $changedIndexes;
$this->removedIndexes = $removedIndexes; $this->removedIndexes = $removedIndexes;
$this->fromTable = $fromTable;
} }
} }
...@@ -17,14 +17,14 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -17,14 +17,14 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
*/ */
protected $_sm; protected $_sm;
protected function getPlatformName() protected function getPlatformName()
{ {
$class = get_class($this); $class = get_class($this);
$e = explode('\\', $class); $e = explode('\\', $class);
$testClass = end($e); $testClass = end($e);
$dbms = strtolower(str_replace('SchemaManagerTest', null, $testClass)); $dbms = strtolower(str_replace('SchemaManagerTest', null, $testClass));
return $dbms; return $dbms;
} }
protected function setUp() protected function setUp()
{ {
...@@ -376,7 +376,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -376,7 +376,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->markTestSkipped('Alter Table is not supported by this platform.'); $this->markTestSkipped('Alter Table is not supported by this platform.');
} }
$this->createTestTable('alter_table'); $alterTable = $this->createTestTable('alter_table');
$this->createTestTable('alter_table_foreign'); $this->createTestTable('alter_table_foreign');
$table = $this->_sm->listTableDetails('alter_table'); $table = $this->_sm->listTableDetails('alter_table');
...@@ -387,6 +387,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -387,6 +387,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertEquals(1, count($table->getIndexes())); $this->assertEquals(1, count($table->getIndexes()));
$tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
$tableDiff->fromTable = $alterTable;
$tableDiff->addedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', Type::getType('integer')); $tableDiff->addedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', Type::getType('integer'));
$tableDiff->removedColumns['test'] = $table->getColumn('test'); $tableDiff->removedColumns['test'] = $table->getColumn('test');
...@@ -397,6 +398,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -397,6 +398,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertTrue($table->hasColumn('foo')); $this->assertTrue($table->hasColumn('foo'));
$tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
$tableDiff->fromTable = $table;
$tableDiff->addedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo')); $tableDiff->addedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo'));
$this->_sm->alterTable($tableDiff); $this->_sm->alterTable($tableDiff);
...@@ -409,6 +411,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -409,6 +411,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertFalse($table->getIndex('foo_idx')->isUnique()); $this->assertFalse($table->getIndex('foo_idx')->isUnique());
$tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
$tableDiff->fromTable = $table;
$tableDiff->changedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test')); $tableDiff->changedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test'));
$this->_sm->alterTable($tableDiff); $this->_sm->alterTable($tableDiff);
...@@ -419,6 +422,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -419,6 +422,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); $this->assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
$tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
$tableDiff->fromTable = $table;
$tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test')); $tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test'));
$fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id')); $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id'));
$tableDiff->addedForeignKeys[] = $fk; $tableDiff->addedForeignKeys[] = $fk;
...@@ -585,6 +589,8 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -585,6 +589,8 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$table = $this->getTestTable($name, $options); $table = $this->getTestTable($name, $options);
$this->_sm->dropAndCreateTable($table); $this->_sm->dropAndCreateTable($table);
return $table;
} }
protected function getTestTable($name, $options=array()) protected function getTestTable($name, $options=array())
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace Doctrine\Tests\DBAL\Functional\Schema; namespace Doctrine\Tests\DBAL\Functional\Schema;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema; use Doctrine\DBAL\Schema;
require_once __DIR__ . '/../../../TestInit.php'; require_once __DIR__ . '/../../../TestInit.php';
...@@ -28,19 +30,46 @@ class SqliteSchemaManagerTest extends SchemaManagerFunctionalTestCase ...@@ -28,19 +30,46 @@ class SqliteSchemaManagerTest extends SchemaManagerFunctionalTestCase
$this->assertEquals(false, file_exists($path)); $this->assertEquals(false, file_exists($path));
} }
/**
* @expectedException \Doctrine\DBAL\DBALException
*/
public function testRenameTable() public function testRenameTable()
{ {
$this->createTestTable('oldname');
$this->_sm->renameTable('oldname', 'newname'); $this->_sm->renameTable('oldname', 'newname');
$tables = $this->_sm->listTableNames();
$this->assertContains('newname', $tables);
$this->assertNotContains('oldname', $tables);
} }
public function testAutoincrementDetection() public function createListTableColumns()
{ {
$this->markTestSkipped( $table = parent::createListTableColumns();
'There is currently no reliable way to determine whether an SQLite column is marked as ' $table->getColumn('id')->setAutoincrement(true);
. 'auto-increment. So, while it does support a single identity column, we cannot with '
. 'certainty determine which it is.'); return $table;
}
public function testListForeignKeysFromExistingDatabase()
{
$this->_conn->executeQuery(<<<EOS
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
page INTEGER CONSTRAINT FK_1 REFERENCES page (key) DEFERRABLE INITIALLY DEFERRED,
parent INTEGER REFERENCES user(id) ON DELETE CASCADE,
log INTEGER,
CONSTRAINT FK_3 FOREIGN KEY (log) REFERENCES log ON UPDATE SET NULL NOT DEFERRABLE
)
EOS
);
$expected = array(
new ForeignKeyConstraint(array('log'), 'log', array(null), 'FK_3',
array('onUpdate' => 'SET NULL', 'onDelete' => 'NO ACTION', 'deferrable' => false, 'deferred' => false)),
new ForeignKeyConstraint(array('parent'), 'user', array('id'), '1',
array('onUpdate' => 'NO ACTION', 'onDelete' => 'CASCADE', 'deferrable' => false, 'deferred' => false)),
new ForeignKeyConstraint(array('page'), 'page', array('key'), 'FK_1',
array('onUpdate' => 'NO ACTION', 'onDelete' => 'NO ACTION', 'deferrable' => true, 'deferred' => true)),
);
$this->assertEquals($expected, $this->_sm->listTableForeignKeys('user'));
} }
} }
\ No newline at end of file
...@@ -205,7 +205,15 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase ...@@ -205,7 +205,15 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase
{ {
$expectedSql = $this->getGenerateAlterTableSql(); $expectedSql = $this->getGenerateAlterTableSql();
$table = new Table('mytable');
$table->addColumn('id', 'integer', array('autoincrement' => true));
$table->addColumn('foo', 'integer');
$table->addColumn('bar', 'string');
$table->addColumn('bloo', 'boolean');
$table->setPrimaryKey(array('id'));
$tableDiff = new TableDiff('mytable'); $tableDiff = new TableDiff('mytable');
$tableDiff->fromTable = $table;
$tableDiff->newName = 'userlist'; $tableDiff->newName = 'userlist';
$tableDiff->addedColumns['quota'] = new \Doctrine\DBAL\Schema\Column('quota', \Doctrine\DBAL\Types\Type::getType('integer'), array('notnull' => false)); $tableDiff->addedColumns['quota'] = new \Doctrine\DBAL\Schema\Column('quota', \Doctrine\DBAL\Types\Type::getType('integer'), array('notnull' => false));
$tableDiff->removedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', \Doctrine\DBAL\Types\Type::getType('integer')); $tableDiff->removedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', \Doctrine\DBAL\Types\Type::getType('integer'));
...@@ -309,7 +317,13 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase ...@@ -309,7 +317,13 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase
$this->_platform->setEventManager($eventManager); $this->_platform->setEventManager($eventManager);
$table = new Table('mytable');
$table->addColumn('removed', 'integer');
$table->addColumn('changed', 'integer');
$table->addColumn('renamed', 'integer');
$tableDiff = new TableDiff('mytable'); $tableDiff = new TableDiff('mytable');
$tableDiff->fromTable = $table;
$tableDiff->addedColumns['added'] = new \Doctrine\DBAL\Schema\Column('added', \Doctrine\DBAL\Types\Type::getType('integer'), array()); $tableDiff->addedColumns['added'] = new \Doctrine\DBAL\Schema\Column('added', \Doctrine\DBAL\Types\Type::getType('integer'), array());
$tableDiff->removedColumns['removed'] = new \Doctrine\DBAL\Schema\Column('removed', \Doctrine\DBAL\Types\Type::getType('integer'), array()); $tableDiff->removedColumns['removed'] = new \Doctrine\DBAL\Schema\Column('removed', \Doctrine\DBAL\Types\Type::getType('integer'), array());
$tableDiff->changedColumns['changed'] = new \Doctrine\DBAL\Schema\ColumnDiff( $tableDiff->changedColumns['changed'] = new \Doctrine\DBAL\Schema\ColumnDiff(
......
...@@ -2,8 +2,12 @@ ...@@ -2,8 +2,12 @@
namespace Doctrine\Tests\DBAL\Platforms; namespace Doctrine\Tests\DBAL\Platforms;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\DBALException;
require_once __DIR__ . '/../../TestInit.php'; require_once __DIR__ . '/../../TestInit.php';
...@@ -105,9 +109,25 @@ class SqlitePlatformTest extends AbstractPlatformTestCase ...@@ -105,9 +109,25 @@ class SqlitePlatformTest extends AbstractPlatformTestCase
return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
} }
/**
* @expectedException \Doctrine\DBAL\DBALException
*/
public function testGeneratesForeignKeyCreationSql()
{
parent::testGeneratesForeignKeyCreationSql();
}
/**
* @expectedException \Doctrine\DBAL\DBALException
*/
public function testGeneratesConstraintCreationSql()
{
parent::testGeneratesConstraintCreationSql();
}
public function getGenerateForeignKeySql() public function getGenerateForeignKeySql()
{ {
$this->markTestSkipped('SQLite does not support ForeignKeys.'); return null;
} }
public function testModifyLimitQuery() public function testModifyLimitQuery()
...@@ -124,12 +144,14 @@ class SqlitePlatformTest extends AbstractPlatformTestCase ...@@ -124,12 +144,14 @@ class SqlitePlatformTest extends AbstractPlatformTestCase
public function getGenerateAlterTableSql() public function getGenerateAlterTableSql()
{ {
$this->markTestSkipped('SQlite does not support ALTER Table.'); return array(
} "CREATE TEMPORARY TABLE __temp__mytable AS SELECT id, bar, bloo FROM mytable",
"DROP TABLE mytable",
public function testGetAlterTableSqlDispatchEvent() "CREATE TABLE mytable (id INTEGER NOT NULL, baz VARCHAR(255) DEFAULT 'def' NOT NULL, bloo BOOLEAN DEFAULT '0' NOT NULL, quota INTEGER DEFAULT NULL, PRIMARY KEY(id))",
{ "INSERT INTO mytable (id, baz, bloo) SELECT id, bar, bloo FROM __temp__mytable",
$this->markTestSkipped('SQlite does not support ALTER Table.'); "DROP TABLE __temp__mytable",
"ALTER TABLE mytable RENAME TO userlist",
);
} }
/** /**
...@@ -146,11 +168,113 @@ class SqlitePlatformTest extends AbstractPlatformTestCase ...@@ -146,11 +168,113 @@ class SqlitePlatformTest extends AbstractPlatformTestCase
'CREATE TABLE test ("like" INTEGER NOT NULL, PRIMARY KEY("like"))', 'CREATE TABLE test ("like" INTEGER NOT NULL, PRIMARY KEY("like"))',
$createTableSQL[0] $createTableSQL[0]
); );
}
$this->assertEquals( public function testAlterTableAddColumns()
'ALTER TABLE test ADD PRIMARY KEY ("like")', {
$this->_platform->getCreatePrimaryKeySQL($table->getIndex('primary'), 'test') $diff = new TableDiff('user');
$diff->addedColumns['foo'] = new Column('foo', Type::getType('string'));
$diff->addedColumns['count'] = new Column('count', Type::getType('integer'), array('notnull' => false, 'default' => 1));
$expected = array(
'ALTER TABLE user ADD COLUMN foo VARCHAR(255) NOT NULL',
'ALTER TABLE user ADD COLUMN count INTEGER DEFAULT 1',
); );
$this->assertEquals($expected, $this->_platform->getAlterTableSQL($diff));
}
public function testAlterTableAddComplexColumns()
{
$diff = new TableDiff('user');
$diff->addedColumns['time'] = new Column('time', Type::getType('date'), array('default' => 'CURRENT_DATE'));
try {
$this->_platform->getAlterTableSQL($diff);
$this->fail();
} catch (DBALException $e) {
}
$diff = new TableDiff('user');
$diff->addedColumns['id'] = new Column('id', Type::getType('integer'), array('autoincrement' => true));
try {
$this->_platform->getAlterTableSQL($diff);
$this->fail();
} catch (DBALException $e) {
}
}
public function testCreateTableWithDeferredForeignKeys()
{
$table = new Table('user');
$table->addColumn('id', 'integer');
$table->addColumn('article', 'integer');
$table->addColumn('post', 'integer');
$table->addColumn('parent', 'integer');
$table->setPrimaryKey(array('id'));
$table->addForeignKeyConstraint('article', array('article'), array('id'), array('deferrable' => true));
$table->addForeignKeyConstraint('post', array('post'), array('id'), array('deferred' => true));
$table->addForeignKeyConstraint('user', array('parent'), array('id'), array('deferrable' => true, 'deferred' => true));
$sql = array(
'CREATE TABLE user ('
. 'id INTEGER NOT NULL, article INTEGER NOT NULL, post INTEGER NOT NULL, parent INTEGER NOT NULL'
. ', PRIMARY KEY(id)'
. ', CONSTRAINT FK_8D93D64923A0E66 FOREIGN KEY (article) REFERENCES article (id) DEFERRABLE INITIALLY IMMEDIATE'
. ', CONSTRAINT FK_8D93D6495A8A6C8D FOREIGN KEY (post) REFERENCES post (id) NOT DEFERRABLE INITIALLY DEFERRED'
. ', CONSTRAINT FK_8D93D6493D8E604F FOREIGN KEY (parent) REFERENCES user (id) DEFERRABLE INITIALLY DEFERRED'
. ')',
'CREATE INDEX IDX_8D93D64923A0E66 ON user (article)',
'CREATE INDEX IDX_8D93D6495A8A6C8D ON user (post)',
'CREATE INDEX IDX_8D93D6493D8E604F ON user (parent)',
);
$this->assertEquals($sql, $this->_platform->getCreateTableSQL($table));
}
public function testAlterTable()
{
$table = new Table('user');
$table->addColumn('id', 'integer');
$table->addColumn('article', 'integer');
$table->addColumn('post', 'integer');
$table->addColumn('parent', 'integer');
$table->setPrimaryKey(array('id'));
$table->addForeignKeyConstraint('article', array('article'), array('id'), array('deferrable' => true));
$table->addForeignKeyConstraint('post', array('post'), array('id'), array('deferred' => true));
$table->addForeignKeyConstraint('user', array('parent'), array('id'), array('deferrable' => true, 'deferred' => true));
$table->addIndex(array('article', 'post'), 'index1');
$diff = new TableDiff('user');
$diff->fromTable = $table;
$diff->newName = 'client';
$diff->renamedColumns['id'] = new \Doctrine\DBAL\Schema\Column('key', \Doctrine\DBAL\Types\Type::getType('integer'), array());
$diff->renamedColumns['post'] = new \Doctrine\DBAL\Schema\Column('comment', \Doctrine\DBAL\Types\Type::getType('integer'), array());
$diff->removedColumns['parent'] = new \Doctrine\DBAL\Schema\Column('comment', \Doctrine\DBAL\Types\Type::getType('integer'), array());
$diff->removedIndexes['index1'] = $table->getIndex('index1');
$sql = array(
'DROP INDEX IDX_8D93D64923A0E66',
'DROP INDEX IDX_8D93D6495A8A6C8D',
'DROP INDEX IDX_8D93D6493D8E604F',
'DROP INDEX index1',
'CREATE TEMPORARY TABLE __temp__user AS SELECT id, article, post FROM user',
'DROP TABLE user',
'CREATE TABLE user ('
. '"key" INTEGER NOT NULL, article INTEGER NOT NULL, comment INTEGER NOT NULL'
. ', PRIMARY KEY("key")'
. ', CONSTRAINT FK_8D93D64923A0E66 FOREIGN KEY (article) REFERENCES article (id) DEFERRABLE INITIALLY IMMEDIATE'
. ', CONSTRAINT FK_8D93D6495A8A6C8D FOREIGN KEY (comment) REFERENCES post (id) NOT DEFERRABLE INITIALLY DEFERRED'
. ')',
'INSERT INTO user ("key", article, comment) SELECT id, article, post FROM __temp__user',
'DROP TABLE __temp__user',
'ALTER TABLE user RENAME TO client',
'CREATE INDEX IDX_8D93D64923A0E66 ON client (article)',
'CREATE INDEX IDX_8D93D6495A8A6C8D ON client (comment)',
);
$this->assertEquals($sql, $this->_platform->getAlterTableSQL($diff));
} }
protected function getQuotedColumnInPrimaryKeySQL() protected function getQuotedColumnInPrimaryKeySQL()
......
...@@ -29,6 +29,7 @@ use Doctrine\DBAL\Schema\Schema, ...@@ -29,6 +29,7 @@ use Doctrine\DBAL\Schema\Schema,
Doctrine\DBAL\Schema\Sequence, Doctrine\DBAL\Schema\Sequence,
Doctrine\DBAL\Schema\SchemaDiff, Doctrine\DBAL\Schema\SchemaDiff,
Doctrine\DBAL\Schema\TableDiff, Doctrine\DBAL\Schema\TableDiff,
Doctrine\DBAL\Schema\ColumnDiff,
Doctrine\DBAL\Schema\Comparator, Doctrine\DBAL\Schema\Comparator,
Doctrine\DBAL\Types\Type, Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Schema\ForeignKeyConstraint; Doctrine\DBAL\Schema\ForeignKeyConstraint;
...@@ -61,7 +62,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -61,7 +62,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
), ),
) ); ) );
$this->assertEquals(new SchemaDiff(), Comparator::compareSchemas( $schema1, $schema2 ) ); $expected = new SchemaDiff();
$expected->fromSchema = $schema1;
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
public function testCompareSame2() public function testCompareSame2()
...@@ -82,7 +85,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -82,7 +85,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
) )
), ),
) ); ) );
$this->assertEquals(new SchemaDiff(), Comparator::compareSchemas( $schema1, $schema2 ) );
$expected = new SchemaDiff();
$expected->fromSchema = $schema1;
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
public function testCompareMissingTable() public function testCompareMissingTable()
...@@ -94,7 +100,7 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -94,7 +100,7 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$schema1 = new Schema( array($table), array(), $schemaConfig ); $schema1 = new Schema( array($table), array(), $schemaConfig );
$schema2 = new Schema( array(), array(), $schemaConfig ); $schema2 = new Schema( array(), array(), $schemaConfig );
$expected = new SchemaDiff( array(), array(), array('bugdb' => $table) ); $expected = new SchemaDiff( array(), array(), array('bugdb' => $table), $schema1 );
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
...@@ -108,7 +114,8 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -108,7 +114,8 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$schema1 = new Schema( array(), array(), $schemaConfig ); $schema1 = new Schema( array(), array(), $schemaConfig );
$schema2 = new Schema( array($table), array(), $schemaConfig ); $schema2 = new Schema( array($table), array(), $schemaConfig );
$expected = new SchemaDiff( array('bugdb' => $table), array(), array() ); $expected = new SchemaDiff( array('bugdb' => $table), array(), array(), $schema1 );
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
...@@ -151,6 +158,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -151,6 +158,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
) )
) )
); );
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
...@@ -181,6 +191,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -181,6 +191,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
), ),
) )
); );
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
...@@ -251,6 +264,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -251,6 +264,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
), ),
) )
); );
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
...@@ -295,6 +311,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -295,6 +311,9 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
), ),
) )
); );
$expected->fromSchema = $schema1;
$expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
} }
...@@ -346,8 +365,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -346,8 +365,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
), ),
) )
); );
$actual = Comparator::compareSchemas( $schema1, $schema2 ); $expected->fromSchema = $schema1;
$this->assertEquals($expected, $actual); $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ));
} }
public function testCompareChangedIndexFieldPositions() public function testCompareChangedIndexFieldPositions()
...@@ -384,8 +405,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -384,8 +405,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
), ),
) )
); );
$actual = Comparator::compareSchemas( $schema1, $schema2 ); $expected->fromSchema = $schema1;
$this->assertEquals($expected, $actual); $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ));
} }
public function testCompareSequences() public function testCompareSequences()
...@@ -740,8 +763,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -740,8 +763,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$newSchema= new Schema(array(), array(), $config); $newSchema= new Schema(array(), array(), $config);
$newSchema->createTable('foo.bar'); $newSchema->createTable('foo.bar');
$c = new Comparator(); $expected = new SchemaDiff();
$this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema)); $expected->fromSchema = $oldSchema;
$this->assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
} }
/** /**
...@@ -758,9 +783,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -758,9 +783,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$newSchema = new Schema(); $newSchema = new Schema();
$newSchema->createTable('bar'); $newSchema->createTable('bar');
$c = new Comparator(); $expected = new SchemaDiff();
$diff = $c->compare($oldSchema, $newSchema); $expected->fromSchema = $oldSchema;
$this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema));
$this->assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
} }
/** /**
...@@ -776,10 +802,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -776,10 +802,10 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$newSchema = new Schema(); $newSchema = new Schema();
$newSchema->createTable('bar'); $newSchema->createTable('bar');
$c = new Comparator(); $expected = new SchemaDiff();
$diff = $c->compare($oldSchema, $newSchema); $expected->fromSchema = $oldSchema;
$this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema)); $this->assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
} }
/** /**
...@@ -833,6 +859,27 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -833,6 +859,27 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$this->assertCount(1, $diff->orphanedForeignKeys); $this->assertCount(1, $diff->orphanedForeignKeys);
} }
public function testCompareChangedColumn()
{
$oldSchema = new Schema();
$tableFoo = $oldSchema->createTable('foo');
$tableFoo->addColumn('id', 'integer');
$newSchema = new Schema();
$table = $newSchema->createTable('foo');
$table->addColumn('id', 'string');
$expected = new SchemaDiff();
$expected->fromSchema = $oldSchema;
$tableDiff = $expected->changedTables['foo'] = new TableDiff('foo');
$tableDiff->fromTable = $tableFoo;
$columnDiff = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id'));
$columnDiff->fromColumn = $tableFoo->getColumn('id');
$columnDiff->changedProperties = array('type');
$this->assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
}
/** /**
* @param SchemaDiff $diff * @param SchemaDiff $diff
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment