Ajout des fonctions de migration dans les taches Cron. Ajout du champ 'TB_Generations_bateaux.Version_soft' afin de mémoriser quelle est la structure en cours de la BDD active du bateau. Cette version est mise à jour à chaque détection (automatique) d'update, juste après la migration de la structure de la base du bateau sur le VPS
This commit is contained in:
+11
-4
@@ -445,7 +445,7 @@ function Executer_cron_archivage()
|
||||
{
|
||||
$motif = 'creation_initiale';
|
||||
}
|
||||
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine);
|
||||
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine, $version_cible);
|
||||
if (!$resultat_generation['ok'])
|
||||
{
|
||||
echo " ÉCHEC de création de génération : " . $resultat_generation['raison'] . " - rejetée.\n";
|
||||
@@ -458,9 +458,16 @@ function Executer_cron_archivage()
|
||||
else
|
||||
{
|
||||
$nom_base_cible = $generation_active['nom_base'];
|
||||
echo " Génération existante : {$nom_base_cible}.\n";
|
||||
// Bloc suivant : rejeu des segments incrémentaux si la version a changé,
|
||||
// via Extraire_segments_incrementaux() + exécution (même mécanique que Creer_generation).
|
||||
// Migration du schéma AVANT chargement si la version logicielle a évolué (mise à jour du
|
||||
// bateau) - les données de l'archive ont été produites avec le nouveau schéma (synthèse §46) :
|
||||
$migration = Migrer_generation($db, $generation_active, $version_cible, $fichier_sql, $contenu_fichier_sql);
|
||||
if (!$migration['ok'])
|
||||
{
|
||||
echo " ÉCHEC : " . $migration['raison'] . " - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, $migration['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
echo " Génération existante : {$nom_base_cible} (" . $migration['message'] . ").\n";
|
||||
}
|
||||
$chargement = Charger_contenu_archive($nom_base_cible, $dechiffrement['sql']);
|
||||
if (!$chargement['ok'])
|
||||
|
||||
+11
-1
@@ -195,7 +195,7 @@ function Executer_cron_quarantaine()
|
||||
continue;
|
||||
}
|
||||
$motif = ($origine_bdd === 'factory' || $origine_bdd === 'restauration') ? $origine_bdd : 'creation_initiale';
|
||||
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine);
|
||||
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine, $version_cible);
|
||||
if (!$resultat_generation['ok'])
|
||||
{
|
||||
echo " - {$nom} : échec de création de génération : " . $resultat_generation['raison'] . " - rejetée.\n";
|
||||
@@ -209,6 +209,16 @@ function Executer_cron_quarantaine()
|
||||
else
|
||||
{
|
||||
$nom_base_cible = $generation_active['nom_base'];
|
||||
// Même migration préalable que cron_archivage.php (synthèse §46) :
|
||||
$migration = Migrer_generation($db, $generation_active, $version_cible, $fichier_sql, $contenu_fichier_sql);
|
||||
if (!$migration['ok'])
|
||||
{
|
||||
echo " - {$nom} : " . $migration['raison'] . " - rejetée.\n";
|
||||
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', $migration['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
||||
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
||||
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$chargement = Charger_contenu_archive($nom_base_cible, $dechiffrement['sql']);
|
||||
|
||||
+131
-8
@@ -140,22 +140,24 @@ function Decrypter_archive($contenu_chiffre)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Résout la génération active d'un bateau (cf synthèse §35.4). Renvoie
|
||||
// ['existe'=>bool, 'cle'=>int|null, 'numero'=>int|null, 'nom_base'=>string|null]
|
||||
// ['existe'=>bool, 'cle'=>int|null, 'numero'=>int|null, 'nom_base'=>string|null,
|
||||
// 'version'=>string|null] - 'version' = Version_soft, version logicielle à
|
||||
// laquelle correspond le schéma de cette base (synthèse §46)
|
||||
// - 'existe'=>false signifie "aucune génération active" (tout premier bateau,
|
||||
// cf synthèse §35.5 point 4), PAS une erreur.
|
||||
// ----------------------------------------------------------------------------
|
||||
function Resoudre_generation_active($db, $id_bateau)
|
||||
{
|
||||
$requete = "SELECT Cle_primaire, Numero_generation, Nom_base FROM TB_Generations_bateaux WHERE ID_Bateau=? AND Date_fin IS NULL";
|
||||
$requete = "SELECT Cle_primaire, Numero_generation, Nom_base, Version_soft FROM TB_Generations_bateaux WHERE ID_Bateau=? AND Date_fin IS NULL";
|
||||
$stmt = $db->prepare($requete);
|
||||
$stmt->bind_param('i', $id_bateau);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($cle, $numero, $nom_base);
|
||||
$stmt->bind_result($cle, $numero, $nom_base, $version_soft);
|
||||
$trouve = $stmt->fetch();
|
||||
$stmt->close();
|
||||
|
||||
if (!$trouve) return ['existe' => false, 'cle' => null, 'numero' => null, 'nom_base' => null];
|
||||
return ['existe' => true, 'cle' => $cle, 'numero' => $numero, 'nom_base' => $nom_base];
|
||||
if (!$trouve) return ['existe' => false, 'cle' => null, 'numero' => null, 'nom_base' => null, 'version' => null];
|
||||
return ['existe' => true, 'cle' => $cle, 'numero' => $numero, 'nom_base' => $nom_base, 'version' => $version_soft];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -259,7 +261,7 @@ function Adapter_nom_base($contenu_sql, $nom_base_cible)
|
||||
// updater.php) - un bloc SQL avec DROP/CREATE DATABASE ne se prête pas bien
|
||||
// à mysqli::multi_query.
|
||||
// ----------------------------------------------------------------------------
|
||||
function Creer_generation($db_principale, $id_bateau, $motif, $contenu_sql)
|
||||
function Creer_generation($db_principale, $id_bateau, $motif, $contenu_sql, $version_soft)
|
||||
{
|
||||
$generation_actuelle = Resoudre_generation_active($db_principale, $id_bateau);
|
||||
$prochain_numero = $generation_actuelle['existe'] ? $generation_actuelle['numero'] + 1 : 1;
|
||||
@@ -293,9 +295,11 @@ function Creer_generation($db_principale, $id_bateau, $motif, $contenu_sql)
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
$requete = "INSERT INTO TB_Generations_bateaux (ID_Bateau, Numero_generation, Nom_base, Motif) VALUES (?, ?, ?, ?)";
|
||||
// Version_soft : version de l'archive qui a provoqué cette génération - le schéma de la nouvelle base
|
||||
// est celui de la zone usine du fichier SQL de cette version (synthèse §46) :
|
||||
$requete = "INSERT INTO TB_Generations_bateaux (ID_Bateau, Numero_generation, Nom_base, Motif, Version_soft) VALUES (?, ?, ?, ?, ?)";
|
||||
$stmt = $db_principale->prepare($requete);
|
||||
$stmt->bind_param('iiss', $id_bateau, $prochain_numero, $nom_base, $motif);
|
||||
$stmt->bind_param('iisss', $id_bateau, $prochain_numero, $nom_base, $motif, $version_soft);
|
||||
if (!$stmt->execute())
|
||||
{
|
||||
$erreur = $db_principale->error;
|
||||
@@ -346,6 +350,125 @@ function Extraire_segments_incrementaux($contenu_fichier, $depart, $cible)
|
||||
return substr($contenu_fichier, $debut, $fin - $debut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Migre le schéma de la base d'une génération EXISTANTE vers la version
|
||||
// logicielle d'une archive 'normale' plus récente (synthèse §32.2, §46) - cas
|
||||
// d'une mise à jour logicielle du bateau (updater.php, Type="update"), qui
|
||||
// laisse Origine_bdd à 'normale' (§35.6). À appeler AVANT le chargement de
|
||||
// l'archive, dont les données ont été produites avec le nouveau schéma.
|
||||
//
|
||||
// Déroulé :
|
||||
// - Version_soft de la génération = version de l'archive -> rien à faire.
|
||||
// - Sinon : fichier SQL actuel (Version_soft -> TB_Versions -> TB_Versions_sql)
|
||||
// et fichier SQL cible (déjà résolu par l'appelant) ; extraction, dans le
|
||||
// fichier cible, de tout ce qui suit le marqueur "# Fin de <actuel>"
|
||||
// jusqu'au marqueur "# Fin de <cible>" inclus ; exécution sur la base de
|
||||
// la génération (nom de base substitué dans les USE) ; puis mise à jour de
|
||||
// Version_soft - même si aucune ligne n'était à exécuter (plusieurs
|
||||
// versions logicielles peuvent partager le même fichier SQL).
|
||||
//
|
||||
// Version_soft n'est mise à jour qu'APRÈS une migration réussie, et AVANT le
|
||||
// chargement : si le chargement échoue ensuite, la base est bien migrée et
|
||||
// la version enregistrée le dit (pas de rejeu à tort). Si la migration
|
||||
// échoue, Version_soft ne bouge pas.
|
||||
//
|
||||
// Limite connue : les ALTER TABLE ne sont pas annulables. Un segment qui
|
||||
// échoue en cours de route laisse une base partiellement migrée -> rejet de
|
||||
// l'archive avec le détail de l'erreur, intervention manuelle nécessaire.
|
||||
//
|
||||
// Renvoie ['ok'=>true, 'message'=>string] ou ['ok'=>false, 'raison'=>string].
|
||||
// ----------------------------------------------------------------------------
|
||||
function Migrer_generation($db_principale, $generation_active, $version_cible, $fichier_cible, $contenu_fichier_cible)
|
||||
{
|
||||
$version_actuelle = $generation_active['version'];
|
||||
$nom_base = $generation_active['nom_base'];
|
||||
|
||||
if ($version_actuelle === null || $version_actuelle === '')
|
||||
{
|
||||
return ['ok' => false, 'raison' => "version de schéma de la génération {$nom_base} inconnue (TB_Generations_bateaux.Version_soft vide) - à renseigner manuellement"];
|
||||
}
|
||||
if ($version_actuelle === $version_cible)
|
||||
{
|
||||
return ['ok' => true, 'message' => "schéma déjà en version {$version_cible}"];
|
||||
}
|
||||
|
||||
$fichier_actuel = Resoudre_fichier_sql($db_principale, $version_actuelle);
|
||||
if ($fichier_actuel === false)
|
||||
{
|
||||
return ['ok' => false, 'raison' => "version actuelle '{$version_actuelle}' de {$nom_base} inconnue de TB_Versions"];
|
||||
}
|
||||
|
||||
$segments = Extraire_segments_incrementaux($contenu_fichier_cible, $fichier_actuel, $fichier_cible);
|
||||
if ($segments === false)
|
||||
{
|
||||
return ['ok' => false, 'raison' => "migration {$version_actuelle} ({$fichier_actuel}) -> {$version_cible} ({$fichier_cible}) impossible : marqueur introuvable dans {$fichier_cible}, ou version cible antérieure à la version actuelle"];
|
||||
}
|
||||
|
||||
$nb_requetes = 0;
|
||||
if ($segments !== '')
|
||||
{
|
||||
// Les segments commencent par "USE `shipheart`;" (base du CM5) : substitution ciblée vers la base de
|
||||
// la génération, comme pour la zone usine (Adapter_nom_base). Puis contrôle qu'il ne reste AUCUN
|
||||
// USE vers une autre base - une migration ne doit jamais pouvoir s'exécuter ailleurs que sur la base
|
||||
// de ce bateau :
|
||||
[$sql_adapte, ] = Adapter_nom_base($segments, $nom_base);
|
||||
if (preg_match_all('/^\s*USE\s+`?([A-Za-z0-9_]+)`?\s*;/mi', $sql_adapte, $m))
|
||||
{
|
||||
foreach ($m[1] as $base_visee)
|
||||
{
|
||||
if ($base_visee !== $nom_base)
|
||||
{
|
||||
return ['ok' => false, 'raison' => "segment de migration visant une autre base ('{$base_visee}') - exécution refusée"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$execution = Executer_sql_base($nom_base, $sql_adapte);
|
||||
if (!$execution['ok'])
|
||||
{
|
||||
return ['ok' => false, 'raison' => "échec de la migration {$version_actuelle} -> {$version_cible} sur {$nom_base} (base possiblement partiellement migrée) : " . $execution['raison']];
|
||||
}
|
||||
// Nombre de requêtes exécutées, à titre indicatif dans le journal (hors USE) :
|
||||
$nb_requetes = preg_match_all('/;\s*$/m', $sql_adapte) - preg_match_all('/^\s*USE\s+[^;]*;\s*$/mi', $sql_adapte);
|
||||
}
|
||||
|
||||
$requete = "UPDATE TB_Generations_bateaux SET Version_soft=? WHERE Cle_primaire=?";
|
||||
$stmt = $db_principale->prepare($requete);
|
||||
$stmt->bind_param('si', $version_cible, $generation_active['cle']);
|
||||
$ok = $stmt->execute();
|
||||
$stmt->close();
|
||||
if (!$ok)
|
||||
{
|
||||
return ['ok' => false, 'raison' => "migration {$version_actuelle} -> {$version_cible} appliquée sur {$nom_base}, mais Version_soft n'a pas pu être mise à jour : " . $db_principale->error . " - à corriger manuellement avant la prochaine archive"];
|
||||
}
|
||||
|
||||
if ($nb_requetes === 0)
|
||||
{
|
||||
return ['ok' => true, 'message' => "version {$version_actuelle} -> {$version_cible}, même fichier SQL ou aucun changement de schéma"];
|
||||
}
|
||||
return ['ok' => true, 'message' => "schéma migré {$version_actuelle} -> {$version_cible} ({$nb_requetes} requête(s))"];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Exécute un bloc SQL sur une base bateau via le client mysql en ligne de
|
||||
// commande (même mécanique que Creer_generation/Charger_contenu_archive - un
|
||||
// bloc contenant des ALTER/CREATE/DROP se prête mal à mysqli::multi_query).
|
||||
// Renvoie ['ok'=>true] ou ['ok'=>false, 'raison'=>string].
|
||||
// ----------------------------------------------------------------------------
|
||||
function Executer_sql_base($nom_base, $sql)
|
||||
{
|
||||
$fichier_temp = tempnam(sys_get_temp_dir(), 'migr_');
|
||||
file_put_contents($fichier_temp, $sql);
|
||||
$commande = "mysql --host=" . escapeshellarg(BDD_BATEAUX_HOST) . " --port=" . escapeshellarg(BDD_BATEAUX_PORT)
|
||||
. " --user=" . escapeshellarg(BDD_BATEAUX_USER) . " --password=" . escapeshellarg(BDD_BATEAUX_PASSWORD)
|
||||
. " " . escapeshellarg($nom_base) . " < " . escapeshellarg($fichier_temp) . " 2>&1";
|
||||
exec($commande, $sortie, $code_retour);
|
||||
unlink($fichier_temp);
|
||||
|
||||
if ($code_retour !== 0) return ['ok' => false, 'raison' => implode(" | ", $sortie)];
|
||||
return ['ok' => true];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Détermine la liste des tables fragmentées (incrémentales) d'une base bateau,
|
||||
// par la MÊME méthode que côté CM5 (SHOW TABLES LIKE 'TB_Mesures%' + TB_Historique,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- ============================================================================
|
||||
-- Ajout de TB_Generations_bateaux.Version_soft (synthèse §46)
|
||||
-- Version logicielle (TB_Versions.Nom, ex : "4.1.6") à laquelle correspond le
|
||||
-- schéma de la base de la génération. Renseignée à la création de la
|
||||
-- génération (version de l'archive qui l'a provoquée), puis à chaque
|
||||
-- migration incrémentale réussie (archive 'normale' de version plus récente).
|
||||
-- NULL = inconnue (générations créées avant l'ajout de la colonne) : une
|
||||
-- génération ACTIVE à NULL fait rejeter les archives du bateau, jusqu'à
|
||||
-- saisie manuelle de la bonne valeur.
|
||||
-- ============================================================================
|
||||
ALTER TABLE TB_Generations_bateaux
|
||||
ADD COLUMN Version_soft VARCHAR(20) NULL
|
||||
COMMENT 'Version logicielle (TB_Versions.Nom) du schéma de cette base - NULL si inconnue'
|
||||
AFTER Motif;
|
||||
Reference in New Issue
Block a user