From d0b81aaa0165b6b564fd2a9dd847c05673183a63 Mon Sep 17 00:00:00 2001 From: Dima Nagorniy Date: Thu, 22 Dec 2016 18:25:37 +0200 Subject: [PATCH] AUD-81: Alter table SQL commands command --- src/Application/AuditApplication.php | 2 + src/MySql/AuditAlter.php | 252 ++++++++++++++++++ src/MySql/AuditDiff.php | 2 +- src/MySql/AuditDiffTable.php | 12 +- src/MySql/Command/AlterTableCommand.php | 64 +++++ src/MySql/Command/DiffCommand.php | 27 -- src/MySql/Helper/MySqlAlterTableCodeStore.php | 39 +++ 7 files changed, 369 insertions(+), 29 deletions(-) mode change 100644 => 100755 src/Application/AuditApplication.php create mode 100755 src/MySql/AuditAlter.php create mode 100755 src/MySql/Command/AlterTableCommand.php mode change 100644 => 100755 src/MySql/Command/DiffCommand.php create mode 100755 src/MySql/Helper/MySqlAlterTableCodeStore.php diff --git a/src/Application/AuditApplication.php b/src/Application/AuditApplication.php old mode 100644 new mode 100755 index 7092e15..fa14198 --- a/src/Application/AuditApplication.php +++ b/src/Application/AuditApplication.php @@ -3,6 +3,7 @@ namespace SetBased\Audit\Application; use SetBased\Audit\Command\AboutCommand; +use SetBased\Audit\MySql\Command\AlterTableCommand; use SetBased\Audit\MySql\Command\AuditCommand; use SetBased\Audit\MySql\Command\DiffCommand; use SetBased\Audit\MySql\Command\DropTriggersCommand; @@ -38,6 +39,7 @@ protected function getDefaultCommands() $commands[] = new AuditCommand(); $commands[] = new DiffCommand(); $commands[] = new DropTriggersCommand(); + $commands[] = new AlterTableCommand(); return $commands; } diff --git a/src/MySql/AuditAlter.php b/src/MySql/AuditAlter.php new file mode 100755 index 0000000..536a648 --- /dev/null +++ b/src/MySql/AuditAlter.php @@ -0,0 +1,252 @@ + + */ + private $diffColumns; + + //-------------------------------------------------------------------------------------------------------------------- + /** + * Object constructor. + * + * @param array[] $config The content of the configuration file. + * @param array[] $configMetadata The content of the metadata file. + */ + public function __construct(&$config, $configMetadata) + { + $this->config = &$config; + $this->configMetadata = $configMetadata; + $this->codeStore = new MySqlAlterTableCodeStore(); + } + + //-------------------------------------------------------------------------------------------------------------------- + /** + * Create Sql statement for alter table. + * + * @param string $tableName The table name. + * @param TableColumnsMetadata $columns Columns metadata for alter statement. + */ + public function createSqlStatement($tableName, $columns) + { + $editCharSet = false; + $charSet = ''; + $this->codeStore->append(sprintf('ALTER TABLE %s CHANGE', $tableName)); + $countMax = $columns->getNumberOfColumns(); + $count = 1; + /** @var MultiSourceColumnMetadata $rowMetadata */ + foreach ($columns->getColumns() as $columnName => $rowMetadata) + { + $columnProperties = $rowMetadata->getProperties(); + /** @var ColumnMetadata $data */ + $data = isset($columnProperties['data']) ? $columnProperties['data'] : null; + /** @var ColumnMetadata $config */ + $config = isset($columnProperties['config']) ? $columnProperties['config'] : null; + + $dataMetadata = isset($data) ? $data->getProperties() : null; + $configMetadata = isset($config) ? $config->getProperties() : null; + + if (!isset($dataMetadata)) + { + if (isset($configMetadata['character_set_name'])) + { + $editCharSet = true; + $charSet = $configMetadata['character_set_name']; + } + $line = sprintf('%s %s %s', $columnName, $columnName, $configMetadata['column_type']); + if ($count!=$countMax) $line .= ','; + $this->codeStore->append($line); + } + else + { + if (isset($dataMetadata['character_set_name'])) + { + $editCharSet = true; + $charSet = $dataMetadata['character_set_name']; + } + $line = sprintf('%s %s %s', $columnName, $columnName, $dataMetadata['column_type']); + if ($count!=$countMax) $line .= ','; + $this->codeStore->append($line); + } + $count++; + } + $this->codeStore->append(';'); + if ($editCharSet) + { + $this->codeStore->append(sprintf('ALTER TABLE %s DEFAULT CHARACTER SET %s;', $tableName, $charSet)); + } + } + + + + //-------------------------------------------------------------------------------------------------------------------- + /** + * The main method: executes the create alter table statement actions for tables. + * + * return string + */ + public function main() + { + $this->processData(); + + return $this->codeStore->getCode(); + } + + //-------------------------------------------------------------------------------------------------------------------- + /** + * Computes the difference between data and audit tables. + */ + private function getDiff() + { + foreach ($this->dataSchemaTables as $table) + { + if ($this->config['tables'][$table['table_name']]['audit']) + { + $res = StaticDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables); + if (isset($res)) + { + $this->diffColumns[$table['table_name']] = new AuditDiffTable($this->config['database']['data_schema'], + $this->config['database']['audit_schema'], + $table['table_name'], + $this->auditColumnsMetadata, + $this->configMetadata[$table['table_name']]); + } + } + } + } + + //-------------------------------------------------------------------------------------------------------------------- + /** + * Getting list of all tables from information_schema of database from config file. + */ + private function listOfTables() + { + $this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']); + + $this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']); + } + + //-------------------------------------------------------------------------------------------------------------------- + /** + * Work on data for each table. + */ + private function processData() + { + $this->resolveCanonicalAuditColumns(); + + $this->listOfTables(); + + $this->getDiff(); + + /** @var AuditDiffTable $diffTable */ + foreach ($this->diffColumns as $tableName => $diffTable) + { + // Remove matching columns. + $columns = $diffTable->removeMatchingColumns(true); + + $this->createSqlStatement($tableName, $columns); + } + } + + //-------------------------------------------------------------------------------------------------------------------- + /** + * Resolves the canonical column types of the audit table columns. + */ + private function resolveCanonicalAuditColumns() + { + if (empty($this->config['audit_columns'])) + { + $this->auditColumnsMetadata = []; + } + else + { + $schema = $this->config['database']['audit_schema']; + $tableName = '_TMP_'.uniqid(); + AuditDataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']); + $columns = AuditDataLayer::getTableColumns($schema, $tableName); + AuditDataLayer::dropTemporaryTable($schema, $tableName); + + foreach ($this->config['audit_columns'] as $audit_column) + { + $key = StaticDataLayer::searchInRowSet('column_name', $audit_column['column_name'], $columns); + + if ($columns[$key]['is_nullable']==='NO') + { + $columns[$key]['column_type'] = sprintf('%s not null', $columns[$key]['column_type']); + } + if (isset($audit_column['value_type'])) + { + $columns[$key]['value_type'] = $audit_column['value_type']; + } + if (isset($audit_column['expression'])) + { + $columns[$key]['expression'] = $audit_column['expression']; + } + } + + $this->auditColumnsMetadata = $columns; + } + } + + //-------------------------------------------------------------------------------------------------------------------- +} + +//---------------------------------------------------------------------------------------------------------------------- diff --git a/src/MySql/AuditDiff.php b/src/MySql/AuditDiff.php index aed3794..4060d69 100755 --- a/src/MySql/AuditDiff.php +++ b/src/MySql/AuditDiff.php @@ -215,7 +215,7 @@ private function printDiff() // Remove matching columns unless the full option is used. if (!$this->full) { - $columns = $diffTable->removeMatchingColumns(); + $columns = $diffTable->removeMatchingColumns(false); } if ($columns->getNumberOfColumns()>0) diff --git a/src/MySql/AuditDiffTable.php b/src/MySql/AuditDiffTable.php index 59022ff..c970005 100755 --- a/src/MySql/AuditDiffTable.php +++ b/src/MySql/AuditDiffTable.php @@ -97,9 +97,11 @@ public function getDiffColumns() /** * Check full and return array without new or obsolete columns if full not set. * + * @param bool $skipObsoleteNew Flag for skipping obsolete and new columns. + * * @return TableColumnsMetadata */ - public function removeMatchingColumns() + public function removeMatchingColumns($skipObsoleteNew) { $metadata = $this->diffColumns->getColumns(); /** @var MultiSourceColumnMetadata $column */ @@ -126,6 +128,10 @@ public function removeMatchingColumns() } } } + elseif ($skipObsoleteNew) + { + $metadata->removeColumn($columnName); + } } else { @@ -137,6 +143,10 @@ public function removeMatchingColumns() $metadata->removeColumn($columnName); } } + elseif ($skipObsoleteNew) + { + $metadata->removeColumn($columnName); + } } } diff --git a/src/MySql/Command/AlterTableCommand.php b/src/MySql/Command/AlterTableCommand.php new file mode 100755 index 0000000..533793b --- /dev/null +++ b/src/MySql/Command/AlterTableCommand.php @@ -0,0 +1,64 @@ +setName('alter-table-sql') + ->setDescription('Create alter table SQL commands for audit tables columns that are different from the config columns or from columns data tables') + ->addArgument('config file', InputArgument::OPTIONAL, 'The audit configuration file', 'etc/audit.json') + ->addArgument('result sql file', InputArgument::OPTIONAL, 'The result file for SQL statement', 'etc/alter-table-sql-result.sql'); + } + + //-------------------------------------------------------------------------------------------------------------------- + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->io = new StratumStyle($input, $output); + + $resultSqlFile = $input->getArgument('result sql file'); + + $this->configFileName = $input->getArgument('config file'); + $this->readConfigFile(); + + $this->connect($this->config); + + $alter = new AuditAlter($this->config, $this->configMetadata); + $content = $alter->main(); + + $this->writeTwoPhases($resultSqlFile, $content); + } + + //-------------------------------------------------------------------------------------------------------------------- + +} + +//---------------------------------------------------------------------------------------------------------------------- diff --git a/src/MySql/Command/DiffCommand.php b/src/MySql/Command/DiffCommand.php old mode 100644 new mode 100755 index 7bd629e..9166ee9 --- a/src/MySql/Command/DiffCommand.php +++ b/src/MySql/Command/DiffCommand.php @@ -26,33 +26,6 @@ class DiffCommand extends AuditCommand */ protected $io; - /** - * The names of all tables in audit schema. - * - * @var array - */ - private $auditSchemaTables; - - //-------------------------------------------------------------------------------------------------------------------- - - /** - * The names of all tables in data schema. - * - * @var array - */ - private $dataSchemaTables; - - //-------------------------------------------------------------------------------------------------------------------- - /** - * Getting list of all tables from information_schema of database from config file. - */ - public function listOfTables() - { - $this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']); - - $this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']); - } - //-------------------------------------------------------------------------------------------------------------------- /** * {@inheritdoc} diff --git a/src/MySql/Helper/MySqlAlterTableCodeStore.php b/src/MySql/Helper/MySqlAlterTableCodeStore.php new file mode 100755 index 0000000..6b1ea49 --- /dev/null +++ b/src/MySql/Helper/MySqlAlterTableCodeStore.php @@ -0,0 +1,39 @@ +