protected function parseTables(Database $database, $filterTable = null) { $sql = 'SHOW FULL TABLES'; if ($filterTable) { if ($schema = $filterTable->getSchema()) { $sql .= ' FROM ' . $database->getPlatform()->doQuoting($schema); } $sql .= sprintf(" LIKE '%s'", $filterTable->getCommonName()); } else { if ($schema = $database->getSchema()) { $sql .= ' FROM ' . $database->getPlatform()->doQuoting($schema); } } $dataFetcher = $this->dbh->query($sql); // First load the tables (important that this happen before filling out details of tables) $tables = array(); foreach ($dataFetcher as $row) { $name = $row[0]; $type = $row[1]; if ($name == $this->getMigrationTable() || $type !== 'BASE TABLE') { continue; } $table = new Table($name); $table->setIdMethod($database->getDefaultIdMethod()); if ($filterTable && $filterTable->getSchema()) { $table->setSchema($filterTable->getSchema()); } $database->addTable($table); $tables[] = $table; } }
/** * Detects the differences between current connected database and $pDatabase * and updates the schema. This does not DROP tables. * * @param Database $pDatabase */ public function updateSchema($pDatabase) { $diff = DatabaseComparator::computeDiff($this->database, $pDatabase); $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { if (strpos($statement, 'DROP') === 0) { // drop statements cause errors since the table doesn't exist continue; } $stmt = $this->con->prepare($statement); $stmt->execute(); } }
/** * */ public function parse(Database $database) { $this->addVendorInfo = $this->getGeneratorConfig()->getBuildProperty('addVendorInfo'); $sql = 'SHOW FULL TABLES'; if ($schema = $database->getSchema()) { $sql .= ' FROM ' . $database->getPlatform()->quoteIdentifier($schema); } $dataFetcher = $this->dbh->query($sql); // First load the tables (important that this happen before filling out details of tables) $tables = array(); foreach ($dataFetcher as $row) { $name = $row[0]; $type = $row[1]; if ($name == $this->getMigrationTable() || $type !== 'BASE TABLE') { continue; } $table = new Table($name); $table->setIdMethod($database->getDefaultIdMethod()); $database->addTable($table); $tables[] = $table; } // Now populate only columns. foreach ($tables as $table) { $this->addColumns($table); } // Now add indices and constraints. foreach ($tables as $table) { $this->addForeignKeys($table); $this->addIndexes($table); $this->addPrimaryKey($table); $this->addTableVendorInfo($table); } return count($tables); }
/** * Compares the current database with $database. * * @param Database $database */ public function compareCurrentDatabase(Database $database) { $this->readDatabase(); $diff = DatabaseComparator::computeDiff($this->database, $database); if (false !== $diff) { $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $this->fail(sprintf("There are unexpected diffs: \n%s\n`%s`\nCurrent Database: \n%s\nTo XML Database: \n%s\n", $diff, $sql, $this->database, $database)); } $this->assertFalse($diff, 'no changes.'); }
/** * Compares the current database with $database. * * @param Database $database * @throws BuildException if a difference has been found between $database and the real database */ public function compareCurrentDatabase(Database $database) { $this->readDatabase(); $diff = DatabaseComparator::computeDiff($this->database, $database); if (false !== $diff) { $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); throw new BuildException(sprintf("There are unexpected diffs (real to model): \n%s\n-----%s-----\nCurrent Database: \n%s\nTo XML Database: \n%s\n", $diff, $sql, $this->database, $database)); } $this->assertFalse($diff, 'no changes.'); }
/** * Returns the number of differences. * * Compares the tables of the fromDatabase and the toDatabase, and modifies * the inner databaseDiff if necessary. * * @param boolean $caseInsensitive * @return integer */ public function compareTables($caseInsensitive = false) { $fromDatabaseTables = $this->fromDatabase->getTables(); $toDatabaseTables = $this->toDatabase->getTables(); $databaseDifferences = 0; $platform = $this->toDatabase->getPlatform() ?: $this->fromDatabase->getPlatform(); // check for new tables in $toDatabase foreach ($toDatabaseTables as $table) { if ($platform) { $platform->normalizeTable($table); } if (!$this->fromDatabase->hasTable($table->getName(), $caseInsensitive) && !$table->isSkipSql()) { $this->databaseDiff->addAddedTable($table->getName(), $table); $databaseDifferences++; } } // check for removed tables in $toDatabase foreach ($fromDatabaseTables as $table) { if (!$this->toDatabase->hasTable($table->getName(), $caseInsensitive) && !$table->isSkipSql()) { $this->databaseDiff->addRemovedTable($table->getName(), $table); $databaseDifferences++; } } // check for table differences foreach ($fromDatabaseTables as $fromTable) { if ($this->toDatabase->hasTable($fromTable->getName(), $caseInsensitive)) { $toTable = $this->toDatabase->getTable($fromTable->getName(), $caseInsensitive); $databaseDiff = TableComparator::computeDiff($fromTable, $toTable, $caseInsensitive); if ($databaseDiff) { $this->databaseDiff->addModifiedTable($fromTable->getName(), $databaseDiff); $databaseDifferences++; } } } $renamed = []; // check for table renamings foreach ($this->databaseDiff->getAddedTables() as $addedTableName => $addedTable) { foreach ($this->databaseDiff->getRemovedTables() as $removedTableName => $removedTable) { if (!in_array($addedTableName, $renamed) && !TableComparator::computeDiff($addedTable, $removedTable, $caseInsensitive)) { // no difference except the name, that's probably a renaming $renamed[] = $addedTableName; $this->databaseDiff->addRenamedTable($removedTableName, $addedTableName); $this->databaseDiff->removeAddedTable($addedTableName); $this->databaseDiff->removeRemovedTable($removedTableName); $databaseDifferences--; } } } return $databaseDifferences; }
public function updateDB(ConnectionInterface $con) { $database = $this->readConnectedDatabase(); $diff = DatabaseComparator::computeDiff($database, $this->database); if (false === $diff) { return null; } $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { $stmt = $con->prepare($statement); $stmt->execute(); } catch (\Exception $e) { //echo $sql; //uncomment for better debugging throw new BuildException(sprintf("Can not execute SQL: \n%s\nFrom database: \n%s\n\nTo database: \n%s\n\nDiff:\n%s", $statement, $this->database, $database, $diff), null, $e); } } return $database; }
/** * Adds a database to the list and sets the Schema property to this * Schema. The database can be specified as a Database object or a * DOMNode object. * * @param Database|array $database * @return Database */ public function addDatabase($database) { if ($database instanceof Database) { $platform = null; $database->setParentSchema($this); if (null === $database->getPlatform()) { if ($config = $this->getGeneratorConfig()) { $platform = $config->getConfiguredPlatform(null, $database->getName()); } $database->setPlatform($platform ? $platform : $this->platform); } $this->databases[] = $database; return $database; } // XML attributes array / hash $db = new Database(); $db->setParentSchema($this); $db->loadMapping($database); return $this->addDatabase($db); }
/** * Returns the Database platform. * * @return PlatformInterface */ public function getPlatform() { return $this->database ? $this->database->getPlatform() : null; }
public function startElement($parser, $name, $attributes) { $parentTag = $this->peekCurrentSchemaTag(); if (false === $parentTag) { switch ($name) { case 'database': if ($this->isExternalSchema()) { $this->currentPackage = isset($attributes['package']) ? $attributes['package'] : null; if (null === $this->currentPackage) { $this->currentPackage = $this->defaultPackage; } } else { $this->currDB = $this->schema->addDatabase($attributes); } break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('database' === $parentTag) { switch ($name) { case 'external-schema': $xmlFile = isset($attributes['filename']) ? $attributes['filename'] : null; // 'referenceOnly' attribute is valid in the main schema XML file only, // and it's ignored in the nested external-schemas if (!$this->isExternalSchema()) { $isForRefOnly = isset($attributes['referenceOnly']) ? $attributes['referenceOnly'] : null; $this->isForReferenceOnly = null !== $isForRefOnly ? 'true' === strtolower($isForRefOnly) : true; // defaults to TRUE } if ('/' !== $xmlFile[0]) { $xmlFile = realpath(dirname($this->currentXmlFile) . DIRECTORY_SEPARATOR . $xmlFile); if (!file_exists($xmlFile)) { throw new SchemaException(sprintf('Unknown include external "%s"', $xmlFile)); } } $this->parseFile($xmlFile); break; case 'domain': $this->currDB->addDomain($attributes); break; case 'table': if (!isset($attributes['schema']) && $this->currDB->getSchema() && $this->currDB->getPlatform()->supportsSchemas() && false === strpos($attributes['name'], $this->currDB->getPlatform()->getSchemaDelimiter())) { $attributes['schema'] = $this->currDB->getSchema(); } $this->currTable = $this->currDB->addTable($attributes); if ($this->isExternalSchema()) { $this->currTable->setForReferenceOnly($this->isForReferenceOnly); $this->currTable->setPackage($this->currentPackage); } break; case 'vendor': $this->currVendorObject = $this->currDB->addVendorInfo($attributes); break; case 'behavior': $this->currBehavior = $this->currDB->addBehavior($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('table' === $parentTag) { switch ($name) { case 'column': $this->currColumn = $this->currTable->addColumn($attributes); break; case 'foreign-key': $this->currFK = $this->currTable->addForeignKey($attributes); break; case 'index': $this->currIndex = new Index(); $this->currIndex->setTable($this->currTable); $this->currIndex->loadMapping($attributes); break; case 'unique': $this->currUnique = new Unique(); $this->currUnique->setTable($this->currTable); $this->currUnique->loadMapping($attributes); break; case 'vendor': $this->currVendorObject = $this->currTable->addVendorInfo($attributes); break; case 'id-method-parameter': $this->currTable->addIdMethodParameter($attributes); break; case 'behavior': $this->currBehavior = $this->currTable->addBehavior($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('column' === $parentTag) { switch ($name) { case 'inheritance': $this->currColumn->addInheritance($attributes); break; case 'vendor': $this->currVendorObject = $this->currColumn->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('foreign-key' === $parentTag) { switch ($name) { case 'reference': $this->currFK->addReference($attributes); break; case 'vendor': $this->currVendorObject = $this->currUnique->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('index' === $parentTag) { switch ($name) { case 'index-column': $this->currIndex->addColumn($attributes); break; case 'vendor': $this->currVendorObject = $this->currIndex->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('unique' === $parentTag) { switch ($name) { case 'unique-column': $this->currUnique->addColumn($attributes); break; case 'vendor': $this->currVendorObject = $this->currUnique->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ($parentTag == 'behavior') { switch ($name) { case 'parameter': $this->currBehavior->addParameter($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('vendor' === $parentTag) { switch ($name) { case 'parameter': $this->currVendorObject->setParameter($attributes['name'], $attributes['value']); break; default: $this->_throwInvalidTagException($parser, $name); } } else { // it must be an invalid tag $this->_throwInvalidTagException($parser, $name); } $this->pushCurrentSchemaTag($name); }