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());
 }