La règle de base de renommage (mais elle a des exceptions, notamment si le nom de la table excède 12 caractères) consiste à renommer la table XXX en la préfixant par un "U". Ainsi, une table nommée ZMYTABLE sera renommée en UZMYTABLE. Le point d'entrée TABNAME dans TRTMIG permet d'affecter MTABLE en connaissant PTABLE avec une règle éventuellement différente.
Chaque procédure unitaire est définie par un programme migrant une ou plusieurs tables de la base. Ce traitement doit s'appeler UUMGSPExxxnn, xxx étant une racine identifiant la table a migrer et nn étant deux chiffres (pour permettre de disposer si nécessaire de plusieurs traitements). Son principe de fonctionnement est le suivant :
Afin de permettre une reprise et une interruption aisée des procédures unitaires :
Description du traitement de migration
Dans le traitement de migration, on trouvera les éléments suivants :
- Au début, des lignes permettant le déclenchement direct de la procédure.
- Un sous-programme RAZ_UUMGSPExxxnn qui servira à remettre la situation initiale afin de pouvoir. relancer la procédure.
- Un sous-programme MAJ_UUMGSPExxxnn contenant la procédure de migration.
- Un sous-programme PATCH.
- Un sous-programme UTI_MOUL.
Ces sous-programmes sont décrits ci-dessous.
On supposera dans les exemples donnés que le traitement UUMGTRTZMY01 correspond à la phase de migration unitaire d'une table unique, qui s'appelle ZMYTABLE. La phase préliminaire de revalidation de dossier a fait les choses suivantes :
- elle a renommé ZMYTABLE conformément à la règle définie ci-dessus (la table remplie avec les valeurs avant migration s'appelle par défaut UZMYTABLE).
- Elle a créé la nouvelle table ZMYTABLE avec la nouvelle structure, mais cette table est vide.
La procédure de migration va s'attacher à remplir la table ZMYTABLE à partir des informations de la table UZMYTABLE.
Les lignes préliminaires
Les lignes préliminaires permettent de lancer le traitement directement depuis l'éditeur, par la fonction Exécution. On y trouve normalement les lignes suivantes :
# Définition du dossier courant, et lecture de la table des dossiers
Local Char FOLDER(30) : FOLDER = nomap
# Nom de la procédure de migration
Local Char PROG(20) : PROG="UUMGTRTZMY01"
If !GSERVEUR
Call SAIDOS(FOLDER,"") From SAIDOS
Endif
If FOLDER<> ""
If clalev([F:ADS])=0 : Local File ADOSSIER [ADS] : Endif
Read [ADS] DOSSIER=[L]FOLDER : If fstat : Raz [F:ADS] : Endif
# Ouverture de la trace et affichage d'une fenêtre de temporisation
If !GSERVEUR
Call TEMPON("O") From GESECRAN
Call OUVRE_TRACE(PROG) From LECFIC
Endif
# Lancement de la procédure
Call MAJ_UUMGSPEZMA00(FOLDER)
# Fermeture trace
If !GSERVEUR
Call TEMPOFF From GESECRAN
Call FERME_TRACE From LECFIC
Call LEC_TRACE From LECFIC
Endif
Endif
End
Le sous-programme de remise à zéro
Le sous-programme déclaré par
Subprog RAZ_UUMGTRTZMY01(FOLDER)
sert à se remettre dans la situation initiale si nécessaire, afin de pouvoir relancer la procédure.
Il doit suivre au minimum les étapes de base suivantes :
- Vérifier que les tables d'origine et de destination existent bien, par exemple avec les lignes suivantes :
# Trouver la table d'origine pour la table à remplir (ici UZMYTABLE)
Call MIGTABNAME(FOLDER,"ZMYTABLE",OLDTABLE,ERR) From TRTMIG
If ERR : End : Endif
# La table d'origine existe-t-elle bien ?
If filinfo(filpath("FIL",OLDTABLE,"fde",[F:ADS]DOSSIER),0)<0
End
Endif - Ne faire des traces que pour les erreurs (aucun message d’avancement ou avertissement)
- Vider la ou les tables dans lesquelles la procédure MAJ insère les données. Pour ce faire, on dispose du sous-programme suivant:
# Vidage brutal et irréversible de la table ZMYTABLE
Call MIGTABRAZ(FOLDER,"ZMYTABLE",ERR)
If ERR : End : Endif - Si des tables communes à plusieurs traitement doivent être partiellement purgées, on utilisera des transactions classiques du type :
Trbegin [...] : Delete [...] Where ... : Commit - Remettre à zéro les informations sur le flux déjà migré pour cette table, par le sous-programme suivant :
# Pas de lignes migrées à cet instant
Call MIGRAZKEY(FOLDER,"UUMGTRTZMY01",ERR) From TRTMIG
Le sous-programme de mise à jour
Le sous-programme MAJ_UUMGTRTZMY01, servant à transcoder le contenu de la table UZMYTABLE pour remplir la table ZMYTABLE, doit réaliser les tâches suivantes :
- Le nom de la procédure de migration doit être défini au départ
Local Char PROG(20) : PROG="UUMGTRTZMY01" - On mettra à jour le statut de la procédure avec le sous-programme suivant (y compris si une condition préliminaire rend le lancement inutile, par exemple s'il n'y a rien à traiter : il faut alors que le statut soit Terminé pour que la procédure soit considérée comme faite et que les suivantes puissent s'enchaîner). Sinon, on mettra le statut à En cours :
# CURSTAT variable Integergérant le statut (menu local 21)
# Les valeurs possibles étant Attente, En cours, Terminée...
# Si la procédure est lancée, on aura CURSTAT=2
# Si elle est terminée, on utilisera CURSTAT=3
# En cas d'erreur, il faudra la positionner à 7
# Dans la suite, la variable PROG contient le nom du de la procédure
# (UUMGTRTZMY01 par exemple)
Call MIGSTKENDFLG (DOSSIER,PROG,CURSTAT,ERR) From TRTMIG - On testera la présence des tables et des tables antérieures en utilisant le sous-programme MIGTABNAME à l'instar de ce qui est fait dans le sous-programme d'initialisation. En cas d'erreur, il ne faut pas oublier de mettre le statut de la tâche à la bonne valeur (7) avec le sous-programme MIGSTKENDFLG.
- On ouvrira ensuite les tables nécessaires à la migration. L'ouverture des tables internes de la procédure de migration se fait par :
Call MIG_OUVRE From TRTMIG - Les traces seront utilisées avec parcimonie (inutile d'en mettre une sur chaque ligne, on a vu des migrations s'arrêter faute de place disque pour écrire les traces). Il est par contre utile de mettre une trace commençant par un message de type "Démarrage de la phase mettant à jour xxx", ainsi qu'une ligne d'horodatage avec un message tel que "Début du processus à :". Ces traces utiliseront les sous-programmes suivants :
# Ligne de trace si ERR=0, ligne d'erreur sinon
Call ECR_TRACE("message",ERR) From GESECRAN
# Ligne de trace horodatée
Call ECR_TIME("message") From DOSSUB Afin d’améliorer le temps d’insertion dans les tables, on supprime les index en ne laissant que le premier actif en début de procédure et on les recrée en fin de procédure, par les sous-programmes :
Call MIGTABINIT(FOLDER,"ZMYTABLE",ERR) From TRTMIG
Mais cela impose que la procédure soit la seule à travailler sur la table au moment où elle s’exécute. Aucune autre procédure ne doit lire, modifier ou insérer dans la table durant l’exécution de la procédure. Si la table doit être accédée par plusieurs procédures, il ne faut pas utiliser ce sous-programme.
- On retrouvera alors la première clé à traiter dans la boucle de traitement. En effet, si on reprend la migration après une interruption, cette clé n'est pas vide. On la retrouvera par le sous-programme décrit ci-dessous :
# TBMKEY(1..NBMKEY) est un tableau des valeurs de clés
# où reprendre la lecture. On retrouve au minimum les composants
# de la dernière valeur de clé traitée, mais on peut y rajouter
# un segment qui pourra indiquer le niveau de rupture atteint
# sur une clé multiple. TBMKEY doit être vide avant l'appel
# S'il est vide au retour, aucune valeur de clé courante n'existait
# (on démarre alors la procédure au début).
# NBMKEY permet de définir le nombre de valeurs que l'on attend
# NBL et NBUP comptent les lignes lues et mises à jour jusque là
Call MIGGETKEY (FOLDER,PROG,NBMKEY,TBMKEY,NBL,NBUP,ERR)
& From TRTMIG - On pourra alors entrer dans la boucle de lecture de la table ou des tables d'origine et d'écriture des tables de destination. Pour des raisons de performance, il est préférable de bannir les ordres de lecture isolés sur des tables et privilégier les instructions Link, de préférence avec des jointures strictes (syntaxe Where CLE~=... ). Si une lecture doit être faite sur une "petite" table pour des raisons d'initialisation ou de contrôle (par "petite", on entend moins de 1000 lignes), il est souvent préférable de stocker le contenu utile de cette table dans des variables en mémoire avant de commencer la boucle.
- Afin d'éviter des erreurs liées à l'écriture d'un trop grand nombre de lignes, on comptera le nombre de lignes écrites et on interrompra la boucle toutes les N lignes (N pouvant être fixé à 50.000 par exemple, par l'intermédiaire de la variable globale GMAXUPDTRS).
- Pour des raisons de performance, on utilisera aussi de préférence l'instruction Writeb (qui a été introduite à partir du moteur utilisé en version 6.4). Cette instruction groupe les écritures et améliore les performances, notamment mais pas uniquement sur une architecture multi-tiers. Cette instruction n'est utilisable que si on ne relit pas la table dans la boucle (ex : relecture pour savoir si enreg existe déjà). Elle suppose de fixer le facteur de groupage par une variable système nommée adxwrb (10 semble une bonne valeur). Il faut alors empiler les valeurs de clés écrites pour pouvoir restituer l'ensemble des clés en cours en cas d'erreur (cette erreur se produit alors sur l'instruction Flush et non pas sur Writeb). Le sous-programme suivant peut être utilisé :
# Empilement des clés.
# KEY_ARRAY est un tableau alphanumérique déclaré par
# Local Char KEY_ARRAY(N)(adxwrb) en début de traitement
# (la taille N dépend de la taille des valeurs de clés)
# NUMBER une variable Shortintindiquant le nombre de clés empilées
# KEY_VALUE valeur de clé encodée si la clé est en plusieurs parties
Call STK (KEY_ARRAY, NUMBER,KEY_VALUE) From TRTMIG - En cas de sortie de boucle (après N boucles, ou parce que le traitement est terminé), on fera un Flushsur la table (si Writebest utilisé) en gérant une éventuelle erreur. Si une erreur s'est produite, et si adxwrbest supérieur à 1, on pourra retrouver les clés sur lesquelles l'erreur a pu se produire dans le tableau KEY_ARRAY, sur les adxwrbpremiers indices : on fera un Rollback avant de mettre la procédure en l'état Terminé avec erreurs et de terminer le traitement.
- Si tout s'est bien passé, on mettra à jour le nombre de lignes lues et mises à jour par l'appel suivant:
Call MIGSTKKEY (FOLDER,PROG,NBMKEY,TBMKEY,NBL,NBUP,ERR)
& From TRTMIG
On fera ensuite un Commit. - On pourra ensuite tester si une demande d'arrêt a été faite. Si ce n'est pas le cas, et si toutes les lignes n'ont pas été traitées, on recommencera une boucle sur N lignes. Le test d'arrêt se fait par le sous-programme suivant :
# La variable STOP revient égale à 0 si une demande d'arrêt a été faite
Call MIGSTKPROGRESS (FOLDER,PROG,STOP,ERR) From TRTMIG - Si une demande d'arrêt a été faite (ou si le traitement est terminé), on fera les opérations suivantes :
# Indexation de la ou des tables traitées
# (uniquement si MIGTABINIT a été utilisé)
Call MIGTABEND(FOLDER,"ZMYTABLE",ERR) From TRTMIG
# Signaler au moniteur la fin du traitement
Call MIGTRTEND(FOLDER,PROG) From TRTMIG
Call ECR_TIME(PROG+" : Tâche terminée") From DOSSUB
On pourra ensuite fermer les tables et libérer des ressources si on en a, puis arrêter le sous-programme par l'instruction End.
Le sous-programme PATCH
Ce sous-programme permet un lancement par patch. Il doit simplement s'assurer que la table ADOSSIER est ouverte, lire l'enregistrement correspondant au dossier à traiter, puis lancer la procédure de migration. Il pourrait, par exemple, être écrit comme suit :
Subprog PATCH(FOLDER)
Value Char FOLDER
# Pas de lancement sur le dossier superviseur
If FOLDER=GDOSX3 : End : Endif
#Chargement de la classe [F:ADS]
If clalev([F:ADS])=0 Local File ADOSSIER [ADS] : Endif
Read [ADS] DOSSIER=FOLDER : If fstat : Raz [F:ADS] : Endif
# Lancement de la procédure
Call MAJ_UUMGTRTZMY01(FOLDER)
End
Le sous-programme UTI_MOUL
Ce sous-programme permet un lancement lors de la validation de dossier. Il est assez similaire au sous-programme PATCH, mais n'a pas besoin de s'assurer que la table ADOSSIER est ouverte, ni de lire l'enregistrement correspondant au dossier à traiter, puisque ceci est assuré par le traitement appelant. Sa seule tâche est donc de lancer la procédure correspondante. Il pourrait, par exemple, être écrit comme suit :
Subprog UTIL_MOUL(FOLDER)
Value Char FOLDER
# Pas de lancement sur le dossier superviseur
If FOLDER=GDOSX3 : End : Endif
# Lancement de la procédure
Call MAJ_UUMGTRTZMY01(FOLDER)
End
Le point d'entrée MIGTAB
Si on désire que des tables de flux spécifiques soient gérées par le traitement de migration d'une façon analogue (c'est-à-dire renommées de la même façon dans le début de la validation de dossier, puis créées avec la nouvelle structure), les étapes suivantes sont à faire :
- il faut utiliser le point d'entrée MIGTAB pour indiquer qu'une table de flux spécifique devra être traitée de la même façon que les tables standard dans la première phase (renommage et suppression des index superfétatoires).
- Il faut créer dans le dossier superviseur (ou dans le dossier de référence si on est dans une architecture à 3 niveaux) la description des tables spécifiques dont la structure change lors du changement de version, sinon les nouvelles tables de flux ne seront pas créées vides avec la nouvelle structure.
- Ceci est une exception un peu particulière à la règle qui indique que, normalement on ne crée pas de table spécifique dans le dossier superviseur. La raison en est simple : on a bien besoin de disposer d'un dictionnaire "de référence" dans ce cas particulier. Or le seul dont on dispose, si on est dans une architecture à deux niveaux (cas le plus fréquent) est celui du dossier "superviseur" (X3 dans le cas de Sage X3). Il est d'ailleurs à noter que ces tables spécifiques créées dans le dossier superviseur peuvent être écrasées sans préavis si on installe une nouvelle version du dossier superviseur. Il faut donc considérer que la présence de tables spécifiques dans X3 est temporaire et qu'une sauvegarde de la description de ces tables doit exister ailleurs.
- Une table spécifique pouvant être utilisée pour alimenter des champs spécifiques d'une table standard, il n'est pas forcément nécessaire de créer une nouvelle table spécifique lors du changement de version. Dans ce cas, on renommera la table spécifique en utilisant le point d'entrée MIGTAB, et on utilisera des points d'entrée dans les procédures standard ou des procédures complémentaires pour faire les mises à jour qui manqueraient sans créer de table nouvelles dans le dictionnaire d'arrivée.
Si ce point d'entrée n'est pas utilisé, les tables spécifiques, protégées par un code activité spécifique, ne seront absolument pas touchées. On les retrouvera dans l'état d'origine, ce qui correspondra souvent à ce qui doit être fait par défaut si le changement de version n'a pas d'incidence sur la structure des tables spécifiques.
De même tout champ spécifique présent dans une table de flux standard et dont le contenu devrait être transféré à l'identique ne nécessite aucune précaution particulière : les traitements standard de migration utilisent des affectations de classes pour réaliser les copies de données.
Le nom du traitement où se trouve le point d'entrée MIGTAB dépend du progiciel basé sur SAFE X3. Dans le cas de Sage X3, ce point d'entrée MIGTAB se trouve dans le traitement TRTMIGTABX3.
On y ajoutera dans ce traitement des lignes de ce type :
Call MIGTABTABADD(DOSSIER,"ZMYTABLE","ZMY","index",
& NBTAB,WTABLE,WTABLEJ,WABRJ,WTABIDX,ERR) From TRTMIG
En sachant que les noms de variables donnés ci-dessus sont pour la plupart fixes :
- DOSSIER est le code du dossier.
- le nom de la table à migrer donné comme exemple ici est "ZMYTABLE".
- "ZMY" correspond à l'abréviation de la table d'origine après qu'elle ait été renommée. Si cette valeur est vide, une abréviation temporaire est déterminé, sous la forme U## ou W##, où ## est un nombre.
Dans tous les cas cette abréviation n’est pas utilisée dans les traitements: Dans les procédures, on utilisera une autre abréviation temporaire comme [XXXM] où XXX est l’abréviation de la table migrée. - NBTAB est la variable contenant le nombre de table de flux définies comme devant être migrées (chaque appel à TRTMIG incrémente cette variable).
- WTABLE, WTABLEJ, WABRJ, WTABIDX sont des tableaux contenant l'ensemble des éléments liés aux tables de flux déjà déclarées.
- ERR renvoie une valeur non nulle en cas d'erreur.
Les points d'entrée des traitements de migration standard
Chaque procédure de migration standard dispose par ailleurs de points d'entrée permettant d'interagir avec la logique de basculement des tables standard. Ces points d'entrée sont les suivants :
- CRITSEL permet d'alimenter la variable CRITERESPE pour filtrer les données à traiter. Le détail du contexte utilisable est défini dans l'annexe décrivant les procédures de migration.
- VERIFSEL permet de recalculer des zones de la table d'origine en cours de lecture durant le traitement, et éventuellement d'exclure un enregistrement qui ne sera donc pas réécrit en mettant ISVALID à 0. Le détail du contexte utilisable est défini dans l'annexe décrivant les procédures de migration.