Skip to content
Snippets Groups Projects
Commit e8660176 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Eclatement de la commande generate-db-scripts en 4 commandes : vidage de...

Eclatement de la commande generate-db-scripts en 4 commandes : vidage de schéma, création de schéma avec/sans contraintes de ref, création des contraintes de ref, inserts de données.
parent 0c929677
Branches
Tags 1.2.4
No related merge requests found
......@@ -31,13 +31,37 @@ class Module implements ConsoleUsageProviderInterface
{
return [
// command
'generate-db-scripts --src-schema= --dst-schema= [--output-dir=] [--connection=]' =>
"Générer les scripts SQL de vidage, création, peuplement d'un schéma destination à partir d'un schéma source.",
'generate-script-for-schema-clearing --connection= [--output-dir=]' =>
"Générer les scripts SQL de vidage d'un schéma.",
// parameters
['--src-schema', "Requis. Nom du schema source, ex: 'SYGAL'."],
['--dst-schema', "Requis. Nom du schema destination, ex: 'SYGAL_TEST'."],
['--connection', "Requis. Nom de la connexion Doctrine concernée, ex: 'doctrine.connection.orm_default'."],
['--output-dir', "Facultatif. Chemin du répertoire où seront générés les scripts. Par défaut: '/tmp'."],
// command
'generate-script-for-schema-creation --src-connection= --dst-connection= [--ref-constraints-included=] [--output-dir=]' =>
"Générer les scripts SQL de création d'un schéma destination à l'image d'un schéma source.",
// parameters
['--src-connection', "Requis. Nom de la connexion Doctrine source, ex: 'doctrine.connection.orm_default'."],
['--dst-connection', "Requis. Nom de la connexion Doctrine destination, ex: 'doctrine.connection.orm_default'."],
['--ref-constraints-included', "Facultatif. Faut-il inclure la génération des contraintes de référence ? Valeur par défaut: 1."],
['--output-dir', "Facultatif. Chemin du répertoire où seront générés les scripts. Par défaut: '/tmp'."],
// command
'generate-script-for-ref-constraints-creation --src-connection= --dst-connection= [--output-dir=]' =>
"Générer les scripts SQL de création des contraintes de référence d'un schéma source dans un schéma destination.",
// parameters
['--src-connection', "Requis. Nom de la connexion Doctrine source, ex: 'doctrine.connection.orm_default'."],
['--dst-connection', "Requis. Nom de la connexion Doctrine destination, ex: 'doctrine.connection.orm_default'."],
['--output-dir', "Facultatif. Chemin du répertoire où seront générés les scripts. Par défaut: '/tmp'."],
// command
'generate-scripts-for-data-inserts --src-connection= --dst-connection= --tables= [--output-dir=]' =>
"Générer les scripts SQL d'insertion des données d'un schéma source dans un schéma destination.",
// parameters
['--src-connection', "Requis. Nom de la connexion Doctrine source, ex: 'doctrine.connection.orm_default'."],
['--dst-connection', "Requis. Nom de la connexion Doctrine destination, ex: 'doctrine.connection.orm_default'."],
['--tables', "Requis. Noms des tables concernées séparés par une virgule, ex: 'ACTEUR,ATTESTATION,DIFFUSION'."],
['--output-dir', "Facultatif. Chemin du répertoire où seront générés les scripts. Par défaut: '/tmp'."],
['--connection', "Facultatif. Nom de la connexion Doctrine à utiliser. Par défaut: 'doctrine.connection.orm_default'."],
];
}
}
......@@ -44,13 +44,43 @@ return [
'console' => [
'router' => [
'routes' => [
'generate-db-scripts' => [
'generateScriptForSchemaClearingConsole' => [
'type' => Simple::class,
'options' => [
'route' => 'generate-db-scripts --src-schema= --dst-schema= [--output-dir=] [--connection=]',
'route' => 'generate-script-for-schema-clearing --connection= [--output-dir=]',
'defaults' => [
'controller' => IndexController::class,
'action' => 'generateDbScriptsConsole',
'action' => 'generateScriptForSchemaClearingConsole',
],
],
],
'generateScriptForSchemaCreationConsole' => [
'type' => Simple::class,
'options' => [
'route' => 'generate-script-for-schema-creation --src-connection= --dst-connection= [--ref-constraints-included=] [--output-dir=]',
'defaults' => [
'controller' => IndexController::class,
'action' => 'generateScriptForSchemaCreationConsole',
],
],
],
'generateScriptForRefConstraintsCreationConsole' => [
'type' => Simple::class,
'options' => [
'route' => 'generate-script-for-ref-constraints-creation --src-connection= --dst-connection= [--output-dir=]',
'defaults' => [
'controller' => IndexController::class,
'action' => 'generateScriptForRefConstraintsCreationConsole',
],
],
],
'generateScriptsForDataInsertsConsole' => [
'type' => Simple::class,
'options' => [
'route' => 'generate-scripts-for-data-inserts --src-connection= --dst-connection= --tables= [--output-dir=]',
'defaults' => [
'controller' => IndexController::class,
'action' => 'generateScriptsForDataInsertsConsole',
],
],
],
......
......@@ -3,8 +3,6 @@
namespace UnicaenOracle\Controller;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\NoResultException;
use UnicaenApp\Exception\RuntimeException;
use UnicaenOracle\Service\Traits\DataServiceAwareTrait;
use UnicaenOracle\Service\Traits\SchemaServiceAwareTrait;
use Zend\Log\LoggerAwareTrait;
......@@ -19,113 +17,87 @@ class IndexController extends AbstractActionController
/**
* Action en mode CLI.
*/
public function generateDbScriptsConsoleAction()
public function generateScriptForSchemaClearingConsoleAction()
{
$srcSchema = $this->params('src-schema'); // ex: 'SYGAL'
$dstSchema = $this->params('dst-schema'); // ex: 'SYGAL_TEST'
$destDir = $this->params('output-dir', '/tmp'); // ex: '/tmp'
$connName = $this->params('connection', 'doctrine.connection.orm_default');
/** @var Connection $srcSchemaConn */
$srcSchemaConn = $this->getServiceLocator()->get($connName);
/** @var Connection $connection */
$connection = $this->getServiceLocator()->get($connName);
$schemaName = $this->schemaService->extractSchemaNameFromConnection($connection);
$this->log("=================================");
$this->log("Database schema scripts generator");
$this->log("=================================");
$this->log("=====================================");
$this->log(" Db schema clearing script generator");
$this->log("=====================================");
/**
* Schema clearing.
*/
$this->log("# Generating database clearing scripts...");
$outputFilePath = $destDir . "/oracle-clear-schema-$dstSchema.sql";
try {
$this->schemaService->createSchemaClearingScriptFile($srcSchemaConn, $dstSchema, $outputFilePath);
} catch (NoResultException $e) {
throw new RuntimeException(
"Impossible de générer le script de vidage du schéma '$dstSchema'.
Peut-être est-il déjà vide ou alors le schéma n'est pas accessible avec la connexion utilisée.");
}
$outputFilePath = $destDir . "/oracle-clear-schema-$schemaName.sql";
$this->schemaService->createSchemaClearingScriptFile($connection, $outputFilePath);
$this->log($outputFilePath);
$this->log("Done.");
exit(0);
}
/**
* Schema creation.
* Action en mode CLI.
*/
$this->log("# Generating schema creation script...");
$outputFilePath = $destDir . "/oracle-generate-schema-$dstSchema-from-$srcSchema.sql";
$this->schemaService->createSchemaCreationScriptFile($srcSchemaConn, $srcSchema, $dstSchema, $outputFilePath);
public function generateScriptForSchemaCreationConsoleAction()
{
$destDir = $this->params('output-dir', '/tmp'); // ex: '/tmp'
$srcConnName = $this->params('src-connection', 'doctrine.connection.orm_default');
$dstConnName = $this->params('dst-connection', 'doctrine.connection.orm_default');
$refConstraintsIncluded = (bool) $this->params('ref-constraints-included', 1);
/** @var Connection $srcConn */
/** @var Connection $dstConn */
$srcConn = $this->getServiceLocator()->get($srcConnName);
$dstConn = $this->getServiceLocator()->get($dstConnName);
$srcSchemaName = $this->schemaService->extractSchemaNameFromConnection($srcConn);
$dstSchemaName = $this->schemaService->extractSchemaNameFromConnection($dstConn);
$this->log("=====================================");
$this->log(" Db schema creation script generator");
$this->log("=====================================");
$this->log("# Generating schema creation script " . ($refConstraintsIncluded ? 'with' : 'without') . ' ref constraints...');
$outputFilePath = $destDir . "/oracle-generate-schema-$dstSchemaName-from-$srcSchemaName.sql";
$this->schemaService->createSchemaCreationScriptFile($srcConn, $dstConn, $refConstraintsIncluded, $outputFilePath);
$this->log($outputFilePath);
$this->log("Done.");
exit(0);
}
/**
* Data inserts.
* Action en mode CLI.
*/
public function generateScriptsForDataInsertsConsoleAction()
{
$destDir = $this->params('output-dir', '/tmp'); // ex: '/tmp'
$tableNames = $this->params('tables');
$srcConnName = $this->params('src-connection', 'doctrine.connection.orm_default');
$dstConnName = $this->params('dst-connection', 'doctrine.connection.orm_default');
/** @var Connection $srcConn */
/** @var Connection $dstConn */
$srcConn = $this->getServiceLocator()->get($srcConnName);
$dstConn = $this->getServiceLocator()->get($dstConnName);
$srcSchemaName = $this->schemaService->extractSchemaNameFromConnection($srcConn);
$dstSchemaName = $this->schemaService->extractSchemaNameFromConnection($dstConn);
$this->log("===================================");
$this->log(" Db data inserts scripts generator");
$this->log("===================================");
$this->log("# Generating data inserts scripts...");
$tableNames = [
'ACTEUR',
'ATTESTATION',
'CATEGORIE_PRIVILEGE',
'DIFFUSION',
'DOCTORANT',
'DOCTORANT_COMPL',
'DOMAINE_SCIENTIFIQUE',
'ECOLE_DOCT',
'ETABLISSEMENT',
'ETABLISSEMENT_RATTACH',
'FAQ',
'FICHIER',
'FINANCEMENT',
'IMPORT_NOTIF',
'IMPORT_OBS_NOTIF',
'IMPORT_OBS_RESULT_NOTIF',
'IMPORT_OBSERV',
'IMPORT_OBSERV_RESULT',
'INDICATEUR',
'INDIVIDU',
'INDIVIDU_ROLE',
'MAIL_CONFIRMATION',
'METADONNEE_THESE',
'NATURE_FICHIER',
'NOTIF',
'NOTIF_RESULT',
'ORIGINE_FINANCEMENT',
'PRIVILEGE',
'RDV_BU',
'ROLE',
'ROLE_MODELE',
'ROLE_PRIVILEGE',
'ROLE_PRIVILEGE_MODELE',
'SOURCE',
'STRUCTURE',
'STRUCTURE_SUBSTIT',
'SYNC_LOG',
'SYNCHRO_LOG',
'THESE',
'TITRE_ACCES',
'TMP_ACTEUR',
'TMP_DOCTORANT',
'TMP_ECOLE_DOCT',
'TMP_ETABLISSEMENT',
'TMP_FINANCEMENT',
'TMP_INDIVIDU',
'TMP_ORIGINE_FINANCEMENT',
'TMP_ROLE',
'TMP_STRUCTURE',
'TMP_THESE',
'TMP_TITRE_ACCES',
'TMP_UNITE_RECH',
'TMP_VARIABLE',
'TYPE_STRUCTURE',
'TYPE_VALIDATION',
'UNITE_DOMAINE_LINKER',
'UNITE_RECH',
'UTILISATEUR',
'VALIDATION',
'VALIDITE_FICHIER',
'VARIABLE',
'VERSION_FICHIER',
'WF_ETAPE',
];
$outputFilePathTemplate = $destDir . "/oracle-data-insert-from-$srcSchema.%s-into-$dstSchema.sql";
$outputFilePaths = $this->dataService->createDataInsertsScriptFile($srcSchemaConn, $dstSchema, $tableNames, $outputFilePathTemplate);
$tableNames = array_filter(array_map('trim', explode(',', $tableNames)));
$outputFilePathTemplate = $destDir . "/oracle-data-insert-from-$srcSchemaName.%s-into-$dstSchemaName.sql";
$outputFilePaths = $this->dataService->createDataInsertsScriptFile($srcConn, $dstSchemaName, $tableNames, $outputFilePathTemplate);
foreach ($outputFilePaths as $outputFilePath) {
$this->log($outputFilePath);
}
......@@ -135,6 +107,37 @@ class IndexController extends AbstractActionController
exit(0);
}
/**
* Action en mode CLI.
*/
public function generateScriptForRefConstraintsCreationConsoleAction()
{
$destDir = $this->params('output-dir', '/tmp'); // ex: '/tmp'
$srcConnName = $this->params('src-connection', 'doctrine.connection.orm_default');
$dstConnName = $this->params('dst-connection', 'doctrine.connection.orm_default');
/** @var Connection $srcConn */
/** @var Connection $dstConn */
$srcConn = $this->getServiceLocator()->get($srcConnName);
$dstConn = $this->getServiceLocator()->get($dstConnName);
$srcSchemaName = $this->schemaService->extractSchemaNameFromConnection($srcConn);
$dstSchemaName = $this->schemaService->extractSchemaNameFromConnection($dstConn);
$this->log("==============================================");
$this->log(" Db ref constraints creation script generator");
$this->log("==============================================");
$this->log("# Generating ref constraints creation script...");
$outputFilePath = $destDir . "/oracle-generate-ref-constraints-$dstSchemaName-from-$srcSchemaName.sql";
$this->schemaService->createRefConstraintsCreationScriptFile($srcConn, $dstConn, $outputFilePath);
$this->log($outputFilePath);
$this->log("Done.");
exit(0);
}
/**
* @param string $message
*/
......
......@@ -4,7 +4,6 @@ namespace UnicaenOracle\Service;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\NoResultException;
use UnicaenApp\Exception\RuntimeException;
/**
......@@ -15,62 +14,131 @@ use UnicaenApp\Exception\RuntimeException;
class SchemaService
{
/**
* @param Connection $srcSchemaConn
* @param string $schemaName
* @param Connection $conn
* @return string
*/
public function extractSchemaNameFromConnection(Connection $conn)
{
$connParams = $conn->getParams();
$candidateKeys = ['CURRENT_SCHEMA', 'user'];
foreach ($candidateKeys as $candidateKey) {
if (isset($connParams[$candidateKey])) {
return strtoupper($connParams[$candidateKey]);
}
}
throw new RuntimeException(
"L'une au moins des clés suivantes doit exister dans les paramètres de la connexion: " .
implode(', ', $candidateKeys)
);
}
/**
* @param Connection $connection
* @param string $outputFilePath
* @throws NoResultException
*/
public function createSchemaClearingScriptFile(Connection $srcSchemaConn, $schemaName, $outputFilePath)
public function createSchemaClearingScriptFile(Connection $connection, $outputFilePath)
{
try {
$stmt = $srcSchemaConn->executeQuery($this->generateSQLForSchemaClearing($schemaName));
$stmt = $connection->executeQuery($this->generateSQLForSchemaClearing($connection));
$stmt->execute();
} catch (DBALException $e) {
throw new RuntimeException("Erreur!", null, $e);
}
$result = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// NB: si le résultat est vide, c'est que le schéma est lui-même vide,
// ou alors c'est un problème de droit du USER Oracle utilisé pour exécuter les commandes.
if (count($result) === 0) {
$result[] = "-- Noop! Schema is empty?";
}
$sql = implode('', $result);
file_put_contents($outputFilePath, $sql);
}
/**
* @param Connection $srcConn
* @param Connection $dstConn
* @param bool $refConstraintsIncluded
* @param string $outputFilePath
*/
public function createSchemaCreationScriptFile(Connection $srcConn, Connection $dstConn, $refConstraintsIncluded, $outputFilePath)
{
$srcSchemaName = $this->extractSchemaNameFromConnection($srcConn);
$dstSchemaName = $this->extractSchemaNameFromConnection($dstConn);
// config DBMS Metadata
try {
$stmt = $srcConn->executeQuery($this->generateSQLForDBMSMetadataPackageConfiguration());
$stmt->execute();
} catch (DBALException $e) {
throw new RuntimeException("Erreur!", null, $e);
}
// génération DDL
try {
$stmt = $srcConn->prepare($this->generateSQLForSchemaCreation($dstConn, $refConstraintsIncluded));
$stmt->execute();
} catch (DBALException $e) {
throw new RuntimeException("Erreur!", null, $e);
}
$result = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// NB: si le résultat est vide, c'est sans doute un problème de droit du USER Oracle utilisé pour exécuter les commandes.
if (count($result) === 0) {
throw new NoResultException();
$result[] = "-- Noop!";
}
$sql = implode('', $result);
$sql = str_replace("\"$srcSchemaName\"", "\"$dstSchemaName\"", $sql);
file_put_contents($outputFilePath, $sql);
}
/**
* @param Connection $srcSchemaConn
* @param string $srcSchemaName
* @param string $dstSchemaName
* @param Connection $srcConn
* @param Connection $dstConn
* @param string $outputFilePath
*/
public function createSchemaCreationScriptFile(Connection $srcSchemaConn, $srcSchemaName, $dstSchemaName, $outputFilePath)
public function createRefConstraintsCreationScriptFile(Connection $srcConn, Connection $dstConn, $outputFilePath)
{
$srcSchemaName = $this->extractSchemaNameFromConnection($srcConn);
$dstSchemaName = $this->extractSchemaNameFromConnection($dstConn);
// config DBMS Metadata
try {
$stmt = $srcSchemaConn->executeQuery($this->generateSQLForDBMSMetadataPackageConfiguration());
$stmt = $srcConn->executeQuery($this->generateSQLForDBMSMetadataPackageConfiguration());
$stmt->execute();
} catch (DBALException $e) {
throw new RuntimeException("Erreur!", null, $e);
}
// generate DDL
// génération des contraintes de référence
try {
$stmt = $srcSchemaConn->prepare($this->generateSQLForSchemaCreation($srcSchemaName));
$stmt = $srcConn->prepare($this->generateSQLForRefConstraintsCreation($dstConn));
$stmt->execute();
} catch (DBALException $e) {
throw new RuntimeException("Erreur!", null, $e);
}
$result = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// NB: si le résultat est vide, c'est sans doute un problème de droit du USER Oracle utilisé pour exécuter les commandes
// NB: si le résultat est vide, c'est sans doute un problème de droit du USER Oracle utilisé pour exécuter les commandes.
if (count($result) === 0) {
$result[] = "-- Noop!";
}
$sql = implode('', $result);
$sql = str_replace("\"$srcSchemaName\"", "\"$dstSchemaName\"", $sql);
file_put_contents($outputFilePath, $sql);
}
/**
* @param string $schemaName
* @param Connection $connection
* @return string
*/
function generateSQLForSchemaClearing($schemaName)
function generateSQLForSchemaClearing(Connection $connection)
{
$schemaName = $this->extractSchemaNameFromConnection($connection);
return <<<EOS
--
-- triggers
......@@ -209,22 +277,25 @@ begin
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'CONSTRAINTS_AS_ALTER', false); --
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'CONSTRAINTS', true); -- including non-referential table constraints in the CREATE TABLE statement ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'REF_CONSTRAINTS', false); -- including referential constraints (foreign keys) in the CREATE TABLE statement ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.session_transform, 'FORCE', true); -- using the FORCE keyword in the CREATE VIEW statement ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.session_transform, 'TABLESPACE', false); -- including tablespace clauses in the DDL ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.session_transform, 'SEGMENT_ATTRIBUTES', false); -- including segment attributes clauses (physical attributes, storage attributes, tablespace, logging) in the DDL ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.session_transform, 'STORAGE', false); -- including storage clauses in the DDL ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'FORCE', true); -- using the FORCE keyword in the CREATE VIEW statement ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'TABLESPACE', false); -- including tablespace clauses in the DDL ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', false); -- including segment attributes clauses (physical attributes, storage attributes, tablespace, logging) in the DDL ?
DBMS_METADATA.set_transform_param(DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', false); -- including storage clauses in the DDL ?
end;
EOS;
}
/**
* @param string $schemaName
* @param Connection $connection
* @param bool $refConstraintsIncluded
* @return string
*/
function generateSQLForSchemaCreation($schemaName)
function generateSQLForSchemaCreation(Connection $connection, $refConstraintsIncluded = true)
{
return <<<EOS
$schemaName = $this->extractSchemaNameFromConnection($connection);
$sql = <<<EOS
--
-- sequences
--
......@@ -347,20 +418,32 @@ SELECT DBMS_METADATA.get_ddl ('MATERIALIZED_VIEW', mview_name, owner) as sql
FROM all_mviews
WHERE owner = '$schemaName'
EOS;
if ($refConstraintsIncluded) {
$refConstraintsSql = $this->generateSQLForRefConstraintsCreation($connection);
$sql .= <<<EOS
UNION ALL
--
-- data inserts
--
$refConstraintsSql
EOS;
}
--
-- [...]
--
return $sql;
}
/**
* @param Connection $connection
* @return string
*/
function generateSQLForRefConstraintsCreation(Connection $connection)
{
$schemaName = $this->extractSchemaNameFromConnection($connection);
return <<<EOS
--
-- constraints
-- reference constraints
--
--select DBMS_METADATA.GET_DDL('CONSTRAINT', constraint_name, owner) as sql
......@@ -373,7 +456,6 @@ from all_constraints
where owner = '$schemaName'
and constraint_type = 'R'
EOS;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment