public function providerForTestGetModifyTableForeignKeysSkipSql4DDL() { $schema1 = <<<EOF <database name="test"> \t<table name="test"> \t\t<column name="test" type="INTEGER" primaryKey="true" autoIncrement="true" required="true" /> \t\t<column name="ref_test" type="INTEGER"/> \t\t<foreign-key foreignTable="test2" onDelete="CASCADE" onUpdate="CASCADE" skipSql="true"> \t\t <reference local="ref_test" foreign="test" /> \t </foreign-key> \t</table> \t<table name="test2"> \t\t<column name="test" type="integer" primaryKey="true" /> \t</table> </database> EOF; $schema2 = <<<EOF <database name="test"> <table name="test"> <column name="test" type="INTEGER" primaryKey="true" autoIncrement="true" required="true" /> <column name="ref_test" type="INTEGER"/> </table> <table name="test2"> <column name="test" type="integer" primaryKey="true" /> </table> </database> EOF; $d1 = $this->getDatabaseFromSchema($schema1); $d2 = $this->getDatabaseFromSchema($schema2); $diff = PropelDatabaseComparator::computeDiff($d2, $d1); return array(array($diff)); }
public function testGetModifyDatabaseWithBlockStorageDDL() { $schema1 = <<<EOF <database name="test"> \t<table name="foo1"> \t\t<column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" /> \t\t<column name="blooopoo" type="INTEGER" /> \t</table> \t<table name="foo2"> \t\t<column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" /> \t\t<column name="bar" type="INTEGER" /> \t\t<column name="baz" type="VARCHAR" size="12" required="true" /> \t</table> \t<table name="foo3"> \t\t<column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" /> \t\t<column name="yipee" type="INTEGER" /> \t</table> </database> EOF; $schema2 = <<<EOF <database name="test"> \t<table name="foo2"> \t\t<column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" /> \t\t<column name="bar1" type="INTEGER" /> \t\t<column name="baz" type="VARCHAR" size="12" required="false" /> \t\t<column name="baz3" type="CLOB" /> \t\t<vendor type="oracle"> \t\t\t<parameter name="PCTFree" value="20"/> \t\t\t<parameter name="InitTrans" value="4"/> \t\t\t<parameter name="MinExtents" value="1"/> \t\t\t<parameter name="MaxExtents" value="99"/> \t\t\t<parameter name="PCTIncrease" value="0"/> \t\t\t<parameter name="Tablespace" value="L_128K"/> \t\t\t<parameter name="PKPCTFree" value="20"/> \t\t\t<parameter name="PKInitTrans" value="4"/> \t\t\t<parameter name="PKMinExtents" value="1"/> \t\t\t<parameter name="PKMaxExtents" value="99"/> \t\t\t<parameter name="PKPCTIncrease" value="0"/> \t\t\t<parameter name="PKTablespace" value="IL_128K"/> \t\t</vendor> \t</table> \t<table name="foo4"> \t\t<column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" /> \t\t<column name="yipee" type="INTEGER" /> \t\t<vendor type="oracle"> \t\t\t<parameter name="PCTFree" value="20"/> \t\t\t<parameter name="InitTrans" value="4"/> \t\t\t<parameter name="MinExtents" value="1"/> \t\t\t<parameter name="MaxExtents" value="99"/> \t\t\t<parameter name="PCTIncrease" value="0"/> \t\t\t<parameter name="Tablespace" value="L_128K"/> \t\t\t<parameter name="PKPCTFree" value="20"/> \t\t\t<parameter name="PKInitTrans" value="4"/> \t\t\t<parameter name="PKMinExtents" value="1"/> \t\t\t<parameter name="PKMaxExtents" value="99"/> \t\t\t<parameter name="PKPCTIncrease" value="0"/> \t\t\t<parameter name="PKTablespace" value="IL_128K"/> \t\t</vendor> \t</table> \t<table name="foo5"> \t\t<column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" /> \t\t<column name="lkdjfsh" type="INTEGER" /> \t\t<column name="dfgdsgf" type="CLOB" /> \t\t<index name="lkdjfsh_IDX"> \t\t\t<index-column name="lkdjfsh"/> \t\t\t<vendor type="oracle"> \t\t\t\t<parameter name="PCTFree" value="20"/> \t\t\t\t<parameter name="InitTrans" value="4"/> \t\t\t\t<parameter name="MinExtents" value="1"/> \t\t\t\t<parameter name="MaxExtents" value="99"/> \t\t\t\t<parameter name="PCTIncrease" value="0"/> \t\t\t\t<parameter name="Tablespace" value="L_128K"/> \t\t\t</vendor> \t\t</index> \t\t<vendor type="oracle"> \t\t\t<parameter name="PCTFree" value="20"/> \t\t\t<parameter name="InitTrans" value="4"/> \t\t\t<parameter name="MinExtents" value="1"/> \t\t\t<parameter name="MaxExtents" value="99"/> \t\t\t<parameter name="PCTIncrease" value="0"/> \t\t\t<parameter name="Tablespace" value="L_128K"/> \t\t\t<parameter name="PKPCTFree" value="20"/> \t\t\t<parameter name="PKInitTrans" value="4"/> \t\t\t<parameter name="PKMinExtents" value="1"/> \t\t\t<parameter name="PKMaxExtents" value="99"/> \t\t\t<parameter name="PKPCTIncrease" value="0"/> \t\t\t<parameter name="PKTablespace" value="IL_128K"/> \t\t</vendor> \t</table> </database> EOF; $d1 = $this->getDatabaseFromSchema($schema1); $d2 = $this->getDatabaseFromSchema($schema2); $databaseDiff = PropelDatabaseComparator::computeDiff($d1, $d2); $expected = "\nALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD';\nALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS';\n\nDROP TABLE foo1 CASCADE CONSTRAINTS;\n\nDROP SEQUENCE foo1_SEQ;\n\nALTER TABLE foo3 RENAME TO foo4;\n\nCREATE TABLE foo5\n(\n\tid NUMBER NOT NULL,\n\tlkdjfsh NUMBER,\n\tdfgdsgf CLOB\n)\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n\tMINEXTENTS 1\n\tMAXEXTENTS 99\n\tPCTINCREASE 0\n)\nTABLESPACE L_128K;\n\nALTER TABLE foo5 ADD CONSTRAINT foo5_PK PRIMARY KEY (id)\nUSING INDEX\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n\tMINEXTENTS 1\n\tMAXEXTENTS 99\n\tPCTINCREASE 0\n)\nTABLESPACE IL_128K;\n\nCREATE SEQUENCE foo5_SEQ\n\tINCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE NOCACHE ORDER;\n\nCREATE INDEX lkdjfsh_IDX ON foo5 (lkdjfsh)\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n\tMINEXTENTS 1\n\tMAXEXTENTS 99\n\tPCTINCREASE 0\n)\nTABLESPACE L_128K;\n\nALTER TABLE foo2 RENAME COLUMN bar TO bar1;\n\nALTER TABLE foo2 MODIFY\n(\n\tbaz NVARCHAR2(12)\n);\n\nALTER TABLE foo2 ADD\n(\n\tbaz3 CLOB\n);\n"; $this->assertEquals($expected, $this->getPlatform()->getModifyDatabaseDDL($databaseDiff)); }
/** * Main method builds all the targets for a typical propel project. */ public function main() { // check to make sure task received all correct params $this->validate(); $generatorConfig = $this->getGeneratorConfig(); // loading model from database $this->log('Reading databases structure...'); $connections = $generatorConfig->getBuildConnections(); if (!$connections) { throw new Exception('You must define database connection settings in a buildtime-conf.xml file to use diff'); } $totalNbTables = 0; $ad = new AppData(); foreach ($connections as $name => $params) { $this->log(sprintf('Connecting to database "%s" using DSN "%s"', $name, $params['dsn']), Project::MSG_VERBOSE); $pdo = $generatorConfig->getBuildPDO($name); $database = new Database($name); $platform = $generatorConfig->getConfiguredPlatform($pdo); if (!$platform->supportsMigrations()) { $this->log(sprintf('Skipping database "%s" since vendor "%s" does not support migrations', $name, $platform->getDatabaseType())); continue; } $database->setPlatform($platform); $database->setDefaultIdMethod(IDMethod::NATIVE); $parser = $generatorConfig->getConfiguredSchemaParser($pdo); $nbTables = $parser->parse($database, $this); $ad->addDatabase($database); $totalNbTables += $nbTables; $this->log(sprintf('%d tables found in database "%s"', $nbTables, $name), Project::MSG_VERBOSE); } if ($totalNbTables) { $this->log(sprintf('%d tables found in all databases.', $totalNbTables)); } else { $this->log('No table found in all databases'); } // loading model from XML $this->packageObjectModel = true; $appDatasFromXml = $this->getDataModels(); $appDataFromXml = array_pop($appDatasFromXml); // comparing models $this->log('Comparing models...'); $manager = new PropelMigrationManager(); $manager->setConnections($connections); $manager->setMigrationDir($this->getOutputDirectory()); $migrationsUp = array(); $migrationsDown = array(); foreach ($ad->getDatabases() as $database) { $name = $database->getName(); $this->log(sprintf('Comparing database "%s"', $name), Project::MSG_VERBOSE); if (!$appDataFromXml->hasDatabase($name)) { // FIXME: tables present in database but not in XML continue; } $databaseDiff = PropelDatabaseComparator::computeDiff($database, $appDataFromXml->getDatabase($name), $this->isCaseInsensitive()); if (!$databaseDiff) { $this->log(sprintf('Same XML and database structures for datasource "%s" - no diff to generate', $name), Project::MSG_VERBOSE); continue; } $this->log(sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription())); $platform = $generatorConfig->getConfiguredPlatform(null, $name); $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff); $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff()); } if (!$migrationsUp) { $this->log('Same XML and database structures for all datasource - no diff to generate'); return; } $timestamp = time(); $migrationFileName = $manager->getMigrationFileName($timestamp); $migrationClassBody = $manager->getMigrationClassBody($migrationsUp, $migrationsDown, $timestamp); $_f = new PhingFile($this->getOutputDirectory(), $migrationFileName); file_put_contents($_f->getAbsolutePath(), $migrationClassBody); $this->log(sprintf('"%s" file successfully created in %s', $_f->getName(), $_f->getParent())); if ($editorCmd = $this->getEditorCmd()) { $this->log(sprintf('Using "%s" as text editor', $editorCmd)); shell_exec($editorCmd . ' ' . escapeshellarg($_f->getAbsolutePath())); } else { $this->log(' Please review the generated SQL statements, and add data migration code if necessary.'); $this->log(' Once the migration class is valid, call the "migrate" task to execute it.'); } }
public function testCompareSeveralTableDifferences() { $d1 = new Database(); $t1 = new Table('Foo_Table'); $c1 = new Column('Foo'); $c1->getDomain()->copy($this->platform->getDomainForType('DOUBLE')); $c1->getDomain()->replaceScale(2); $c1->getDomain()->replaceSize(3); $c1->setNotNull(true); $c1->getDomain()->setDefaultValue(new ColumnDefaultValue(123, ColumnDefaultValue::TYPE_VALUE)); $t1->addColumn($c1); $d1->addTable($t1); $t2 = new Table('Bar'); $c2 = new Column('Bar_Column'); $c2->getDomain()->copy($this->platform->getDomainForType('DOUBLE')); $t2->addColumn($c2); $d1->addTable($t2); $t11 = new Table('Baz'); $d1->addTable($t11); $d2 = new Database(); $t3 = new Table('Foo_Table'); $c3 = new Column('Foo1'); $c3->getDomain()->copy($this->platform->getDomainForType('DOUBLE')); $c3->getDomain()->replaceScale(2); $c3->getDomain()->replaceSize(3); $c3->setNotNull(true); $c3->getDomain()->setDefaultValue(new ColumnDefaultValue(123, ColumnDefaultValue::TYPE_VALUE)); $t3->addColumn($c3); $d2->addTable($t3); $t4 = new Table('Bar2'); $c4 = new Column('Bar_Column'); $c4->getDomain()->copy($this->platform->getDomainForType('DOUBLE')); $t4->addColumn($c4); $d2->addTable($t4); $t5 = new Table('Biz'); $c5 = new Column('Biz_Column'); $c5->getDomain()->copy($this->platform->getDomainForType('INTEGER')); $t5->addColumn($c5); $d2->addTable($t5); // Foo_Table was modified, Bar was renamed, Baz was removed, Biz was added $dc = new PropelDatabaseComparator(); $dc->setFromDatabase($d1); $dc->setToDatabase($d2); $nbDiffs = $dc->compareTables(); $databaseDiff = $dc->getDatabaseDiff(); $this->assertEquals(4, $nbDiffs); $this->assertEquals(array('Bar' => 'Bar2'), $databaseDiff->getRenamedTables()); $this->assertEquals(array('Biz' => $t5), $databaseDiff->getAddedTables()); $this->assertEquals(array('Baz' => $t11), $databaseDiff->getRemovedTables()); $tableDiff = PropelTableComparator::computeDiff($t1, $t3); $this->assertEquals(array('Foo_Table' => $tableDiff), $databaseDiff->getModifiedTables()); }