diff --git a/src/UnicaenImport/Entity/Schema/Column.php b/src/UnicaenImport/Entity/Schema/Column.php index 7b59c3c4f3cc1ca6690053db09eb8e221b82e874..747f7854c442eada559620ccc2587451421533f8 100644 --- a/src/UnicaenImport/Entity/Schema/Column.php +++ b/src/UnicaenImport/Entity/Schema/Column.php @@ -5,13 +5,23 @@ namespace UnicaenImport\Entity\Schema; /** - * + * * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ class Column { - + + /** + * @var string + */ + public $table; + + /** + * @var string + */ + public $name; + /** * Type de données * @@ -61,4 +71,11 @@ class Column */ public $importActif; + + + function __toString() + { + return $this->name; + } + } \ No newline at end of file diff --git a/src/UnicaenImport/Service/QueryGeneratorService.php b/src/UnicaenImport/Service/QueryGeneratorService.php index 5caf7817884370b36fe96ed9d25cdb624c62eab6..5a82bbd42ad080f5c17d28e4e7b302768e817d4c 100644 --- a/src/UnicaenImport/Service/QueryGeneratorService.php +++ b/src/UnicaenImport/Service/QueryGeneratorService.php @@ -1,6 +1,7 @@ <?php namespace UnicaenImport\Service; +use UnicaenImport\Entity\Schema\Column; use UnicaenImport\Exception\Exception; use UnicaenImport\Entity\Differentiel\Query; use UnicaenImport\Options\Traits\ModuleOptionsAwareTrait; @@ -111,7 +112,7 @@ class QueryGeneratorService extends AbstractService $ignoreFields = $this->escape(implode(',', $ignoreFields)); } - $sql = "BEGIN ".$this->getPackage().".SET_CURRENT_USER($userId);".$this->getPackage().".$procName($conditions,$ignoreFields); END;"; + $sql = "BEGIN " . $this->getPackage() . ".SET_CURRENT_USER($userId);" . $this->getPackage() . ".$procName($conditions,$ignoreFields); END;"; try { $this->getEntityManager()->getConnection()->exec($sql); } catch (\Doctrine\DBAL\DBALException $e) { @@ -140,7 +141,7 @@ class QueryGeneratorService extends AbstractService $errors = []; $lastLogId = $this->getLastLogId(); - $sql = "BEGIN ".$this->getPackage().".SET_CURRENT_USER($userId);".$this->getPackage()."." . $this->escapeKW('MAJ_' . $tableName) . "; END;"; + $sql = "BEGIN " . $this->getPackage() . ".SET_CURRENT_USER($userId);" . $this->getPackage() . "." . $this->escapeKW('MAJ_' . $tableName) . "; END;"; try { $this->getEntityManager()->getConnection()->exec($sql); } catch (\Doctrine\DBAL\DBALException $e) { @@ -201,7 +202,7 @@ class QueryGeneratorService extends AbstractService */ public function getSqlCriterion($tableName) { - $sql = 'SELECT '.$this->getPackage().'.GET_SQL_CRITERION(' . $this->escape($tableName) . ',\'\') res FROM DUAL'; + $sql = 'SELECT ' . $this->getPackage() . '.GET_SQL_CRITERION(' . $this->escape($tableName) . ',\'\') res FROM DUAL'; $stmt = $this->getEntityManager()->getConnection()->executeQuery($sql); if ($r = $stmt->fetch()) { @@ -285,7 +286,7 @@ class QueryGeneratorService extends AbstractService */ protected function getPackageDeclaration() { - $sql = "SELECT TEXT FROM USER_SOURCE WHERE NAME = '".$this->getPackage()."' AND type = 'PACKAGE'"; + $sql = "SELECT TEXT FROM USER_SOURCE WHERE NAME = '" . $this->getPackage() . "' AND type = 'PACKAGE'"; $result = $this->query($sql, [], 'TEXT'); return implode("", $result); @@ -300,7 +301,7 @@ class QueryGeneratorService extends AbstractService */ protected function getPackageBody() { - $sql = "SELECT TEXT FROM USER_SOURCE WHERE NAME = '".$this->getPackage()."' AND type = 'PACKAGE BODY'"; + $sql = "SELECT TEXT FROM USER_SOURCE WHERE NAME = '" . $this->getPackage() . "' AND type = 'PACKAGE BODY'"; $result = $this->query($sql, [], 'TEXT'); return implode("", $result); @@ -361,10 +362,13 @@ class QueryGeneratorService extends AbstractService return $result; } + + /** * Teste que la séquence correspondant à la table spécifiée existe bien. * * @param string $table + * * @throws \Doctrine\DBAL\DBALException En cas d'erreur en BDD * @throws Exception Si la séquence n'existe pas. * @@ -374,13 +378,13 @@ class QueryGeneratorService extends AbstractService $sql = 'SELECT COUNT(*) SEQ_FOUND FROM USER_SEQUENCES WHERE SEQUENCE_NAME = :sequenceName'; $sequenceName = strtoupper($table) . '_ID_SEQ'; - $stmt = $this->getEntityManager()->getConnection()->executeQuery($sql, ['sequenceName' => $sequenceName]); + $stmt = $this->getEntityManager()->getConnection()->executeQuery($sql, ['sequenceName' => $sequenceName]); $sequenceFound = false; if ($r = $stmt->fetch()) { $sequenceFound = (bool)(int)$r['SEQ_FOUND']; } - if (! $sequenceFound) { + if (!$sequenceFound) { throw new Exception("La séquence '$sequenceName' doit être créée (ex: CREATE SEQUENCE $sequenceName)"); } } @@ -467,11 +471,11 @@ class QueryGeneratorService extends AbstractService $joinCond = ' AND S.' . self::ANNEE_COLUMN_NAME . ' = d.' . self::ANNEE_COLUMN_NAME; } // destruction ssi dans l'année d'import courante - $delCond = ' AND d.' . self::ANNEE_COLUMN_NAME . ' = '.$this->getPackage().'.get_current_annee'; + $delCond = ' AND d.' . self::ANNEE_COLUMN_NAME . ' = ' . $this->getPackage() . '.get_current_annee'; } else { // on recherche si la table dépend d'une table qui, elle, serait annualisée foreach ($schema as $columnName => $column) { - /* @var $column \Import\Entity\Schema\Column */ + /* @var $column \UnicaenImport\Entity\Schema\Column */ if (!empty($column->refTableName)) { $refSchema = $this->getServiceSchema()->getSchema($column->refTableName); if (!empty($refSchema) && array_key_exists(self::ANNEE_COLUMN_NAME, $refSchema)) { @@ -479,7 +483,7 @@ class QueryGeneratorService extends AbstractService // Donc, on utilise la table référente $depJoin = "\n LEFT JOIN " . $column->refTableName . " rt ON rt." . $column->refColumnName . " = d." . $columnName; // destruction ssi dans l'année d'import courante de la table référente - $delCond = ' AND rt.' . self::ANNEE_COLUMN_NAME . ' = '.$this->getPackage().'.get_current_annee'; + $delCond = ' AND rt.' . self::ANNEE_COLUMN_NAME . ' = ' . $this->getPackage() . '.get_current_annee'; break; /* on stoppe à la première table contenant une année. @@ -493,7 +497,10 @@ class QueryGeneratorService extends AbstractService // on génère ensuite la bonne requête !!! $cols = $this->getCols($tableName); - $sql = "CREATE OR REPLACE FORCE VIEW V_DIFF_$tableName AS + foreach ($cols as $id => $col) { + $cols[$id] = $schema[$col]; + } + $sql = "CREATE OR REPLACE FORCE VIEW V_DIFF_$tableName AS select diff.* from (SELECT COALESCE( D.id, S.id ) id, COALESCE( S.source_id, D.source_id ) source_id, @@ -503,8 +510,20 @@ CASE WHEN S.source_code IS NOT NULL AND D.source_code IS NOT NULL AND (D.histo_destruction IS NULL OR D.histo_destruction > SYSDATE) THEN 'update' WHEN S.source_code IS NULL AND D.source_code IS NOT NULL AND (D.histo_destruction IS NULL OR D.histo_destruction > SYSDATE)$delCond THEN 'delete' WHEN S.source_code IS NOT NULL AND D.source_code IS NOT NULL AND D.histo_destruction IS NOT NULL AND D.histo_destruction <= SYSDATE THEN 'undelete' END import_action, - " . $this->formatColQuery($cols, ' CASE WHEN S.source_code IS NULL AND D.source_code IS NOT NULL THEN D.:column ELSE S.:column END :column', ",\n ") . ", - " . $this->formatColQuery($cols, ' CASE WHEN D.:column <> S.:column OR (D.:column IS NULL AND S.:column IS NOT NULL) OR (D.:column IS NOT NULL AND S.:column IS NULL) THEN 1 ELSE 0 END U_:column', ",\n ") . " + " . $this->formatColQuery($cols, function (Column $col) { + if ($col->dataType == 'CLOB') { + return ' CASE WHEN S.source_code IS NULL AND D.source_code IS NOT NULL THEN D.:column ELSE to_clob(S.:column) END :column'; + } else { + return ' CASE WHEN S.source_code IS NULL AND D.source_code IS NOT NULL THEN D.:column ELSE S.:column END :column'; + } + }, ",\n ") . ", + " . $this->formatColQuery($cols, function (Column $col) { + if ($col->dataType == 'CLOB') { + return ' CASE WHEN dbms_lob.compare(D.:column,S.:column) <> 0 OR (D.:column IS NULL AND S.:column IS NOT NULL) OR (D.:column IS NOT NULL AND S.:column IS NULL) THEN 1 ELSE 0 END U_:column'; + } else { + return ' CASE WHEN D.:column <> S.:column OR (D.:column IS NULL AND S.:column IS NOT NULL) OR (D.:column IS NOT NULL AND S.:column IS NULL) THEN 1 ELSE 0 END U_:column'; + } + }, ",\n ") . " FROM $tableName D$depJoin FULL JOIN SRC_$tableName S ON S.source_id = D.source_id AND S.source_code = D.source_code$joinCond @@ -512,7 +531,13 @@ WHERE (S.source_code IS NOT NULL AND D.source_code IS NOT NULL AND D.histo_destruction IS NOT NULL AND D.histo_destruction <= SYSDATE) OR (S.source_code IS NULL AND D.source_code IS NOT NULL AND (D.histo_destruction IS NULL OR D.histo_destruction > SYSDATE)) OR (S.source_code IS NOT NULL AND D.source_code IS NULL) - OR " . $this->formatColQuery($cols, 'D.:column <> S.:column OR (D.:column IS NULL AND S.:column IS NOT NULL) OR (D.:column IS NOT NULL AND S.:column IS NULL)', "\n OR ") . " + OR " . $this->formatColQuery($cols, function (Column $col) { + if ($col->dataType == 'CLOB') { + return 'dbms_lob.compare(D.:column,S.:column) <> 0 OR (D.:column IS NULL AND S.:column IS NOT NULL) OR (D.:column IS NOT NULL AND S.:column IS NULL)'; + } else { + return 'D.:column <> S.:column OR (D.:column IS NULL AND S.:column IS NOT NULL) OR (D.:column IS NOT NULL AND S.:column IS NULL)'; + } + }, "\n OR ") . " ) diff JOIN source on source.id = diff.source_id WHERE import_action IS NOT NULL AND source.importable = 1"; return $sql; @@ -585,7 +610,7 @@ WHERE END CASE; EXCEPTION WHEN OTHERS THEN - ".$this->getPackage().".SYNC_LOG( SQLERRM, '$tableName', diff_row.source_code ); + " . $this->getPackage() . ".SYNC_LOG( SQLERRM, '$tableName', diff_row.source_code ); END; END LOOP; CLOSE diff_cur; @@ -613,7 +638,13 @@ WHERE { $res = []; foreach ($cols as $col) { - $res[] = str_replace(':column', $col, $format); + if (is_callable($format)) { + $f = $format($col); + } else { + $f = $format; + } + + $res[] = str_replace(':column', $col, $f); } return implode($separator, $res); diff --git a/src/UnicaenImport/Service/SchemaService.php b/src/UnicaenImport/Service/SchemaService.php index 0497c4f1b60080b4c3b06266aadd1a77dfbd0bfd..f94f48f3e55b9233e78c36e4bf93ae6cf6c97616 100644 --- a/src/UnicaenImport/Service/SchemaService.php +++ b/src/UnicaenImport/Service/SchemaService.php @@ -54,6 +54,8 @@ class SchemaService extends AbstractService $sc = []; foreach( $d as $col ){ $column = new Column; + $column->table = $col['TABLE_NAME']; + $column->name = $col['COLUMN_NAME']; $column->dataType = $col['DATA_TYPE']; $column->length = (null === $col['LENGTH']) ? null : (integer)$col['LENGTH']; $column->nullable = $col['NULLABLE'] == '1'; @@ -102,7 +104,7 @@ class SchemaService extends AbstractService } /** - * + * * @param string $tableName * @param string $columnName */