Scrittura di una procedura di migrazione specifica 

Partendo dalla versione 6.4. di Sage X3, la migrazione da una versione precedente sulla versione 6 si basa su un monitor di concatenamento che lancia le procedure di migrazione unitarie in modo automatizzato.

E' possibile aggiungere delle procedure di migrazione specifiche, seguendo le preconizzazioni fornite nell'allegato tecnico.

All'occorrenza, si effettuerà l'aggiunta di procedure di migrazioni specifiche:

  • scrivendo un processo di migrazione la cui descrizione dettagliata e le righe di nomina vengono precisate qui in basso.
  • indicando questo processo come una procedura di migrazione nel dossier supervisore dalla funzione corrispondente, prima di ogni creazione di un piano di migrazione e ad ogni lancio di rivalidazione di un dossier.

La documentazione descrive nel dettaglio la struttura di un simile processo di migrazione, ma si potrà, se necessario, riferirsi al processo UUMGTRTPUR01, che realizza la migrazione delle richieste d'acquisto, la cui origine è fornita a titolo d'esempio (la sua modifica è vietata - rischiando di rendere il processo di migrazione inefficace).

Principi di base

Durante la validazione del dossier:

  • ogni tabella di flusso viene rinominata (di default facendo precedere il proprio nome dalla lettera U). Si assegna loro il codice attività MIG (che permetterà di identificarli durante la cancellazione finale delle tabelle temporanee, nel momento in cui la migrazione sarà stata validata).
  • il contenuto rimane uguale alla tabella dei flussi d'origine
  • gli indici sono cancellati (ad eccezione del primo tra loro ed eventualmente di un indice supplementare che sarebbe utile per accelerare il processo di migrazione).
  • vengono create una o più nuova(e) tabella(e) di flussi in conformità del dizionario della nuova versione (integrandovi ovviamente i campi specifici o le modifiche specifiche di campi standard fatte sulla tabella d'origine). Spesso ma non sempre, la tabella vuota ha lo stesso nome della tabella d'origine (questa tabella può non esistere nella nuova versione, ad esempio perchè i dati che conteneva sono stati trasferiti in una nuova tabella).

E' possibile gestire le migrazioni di tabelle specifiche con lo stesso meccanismo. E' descritto nel paragrafo qui in seguito.

Il seguente sotto-programma permette di conoscere il nome della tabella che è stata rinominata:
     # FOLDER = codice del dossier
     # PTABLE = nome della tabella del movimento prima della migrazione
     # MTABLE = nome della tabella di movimento rinominata
     # Se ERR>0  : si è verificato un errore (il processo dovrà arrestarsi)
     Call MIGTABNAME(FOLDER,PTABLE, MTABLE, ERR) From TRTMIG

La regola di base della rinomina (ma ha delle eccezioni, soprattutto se il nome della tabella supera i 12 caratteri) consiste nel rinominare la tabella XXX facendola precedere da una "U". Così, una tabella nominata ZMYTABLE sarà rinominata in UZMYTABLE. L'entry point TABNAME in TRTMIG permette di assegnare MTABLE conoscendo PTABLE con una regola eventualmente diversa.

Ogni processo unitario è definito da un programma che fa migrare una o più tabelle del database. Questo processo deve chiamarsi UUMGSPExxxnn, xxx che è la radice che identifica la tabella da migrare e nn che è di due cifre (per permettere di disporre se necessario di più processi). Il principio di funzionamento è il seguente:

  • Leggerà la o le tabelle d'origine (trovando il loro nome grazie ai sotto-programmi qui in alto), ma non li aggiornerà.
  • Deve scrivere nella o nella tabella(e) finale(i), i dati modificati, completati o trascodificati. Queste tabelle finali sono state descritte nel dizionario della nuova versione. Esistono ma all'inizio della migrazione vengono considerate vuote.
  • E' il più "unitario" possibile, per permettere quando è possibile, una scomposizione della migrazione in procedure parallelizzabili.

Per ottenere le migliore prestazioni possibili:

  • la tabella finale è consegnata vuota all'inizio ed è indicizzata "a minima" (un solo indice). Gli altri indici saranno creati alla fine della procedura unitaria.
  • si permetterà di realizzare l'elaborazione parziale delle informazioni di partenza (per esempio migrando solo i 2 ultimi esercizi) e permettendo l'ulteriore elaborazione dei dati non migrati.
  • la scrittura su questa tabella si farà preferibilmente in modo raggruppato (utilizzando le sintassi Writeb), facendo dei Commit sulla tabella ad ogni pacchetto di N scritture (N che viene fissato ad un valore ragionabile).
  • la traccia di migrazione sarà aggiornata in modo ottimale.

Per permettere una ripresa e una interruzione facile delle procedure unitarie:

  • si scriverà su una tabella dedicata, ad ogni Commit, un puntatore che indica quali sono i dati già elaborati, ed anche le informazioni complementari.
  • si testerà, ad ogni Commit, se è stata fatta una domanda di interruzione.
  • si scriverà la procedura in modo che possa essere rieseguita ripartendo dalle tabelle di destinazione vuote.

Descrizione del processo di migrazione

Nel processo di migrazione, si troveranno i seguenti elementi:

  • All'inizio, le righe che permettono l'attivazione diretta della procedura.
  • Un sotto-programma RAZ_UUMGSPExxxnn che servirà a rimettere la situazione iniziale per poter rilanciare la procedura.
  • Un sotto-programma MAJ_UUMGSPExxxnn che contiene la procedura di migrazione
  • Un sotto-programma PATCH.
  • Un sotto-programma UTI_MOUL.

Questi programmi sono descritti qui in basso.

Si supporrà negli esempi dati che il programma UUMGTRTZMY01 corrisponde alla fase di migrazione unitaria di una tabella unica, che si chiama ZMYTABLE. La fase preliminare di rivalidazione del dossier ha fatto le seguenti cose:

  • ha rinominato ZMYTABLE in conformità della regola definita qui sopra (la tabella alimentata con i valori precedenti la migrazione si chiama di default UZMYTABLE).
  • E' stata creata la nuova tabella ZMYTABLE con la nuova struttura, ma questa tabella è vuota.

La procedura di migrazione si occuperà di alimentare la tabella ZMYTABLE dalle informazioni della tabella UZMYTABLE.

Le righe preliminari

Le righe preliminari permettono di lanciare l'elaborazione direttamente dall'editor, dalla funzione Esecuzione. Si trovano normalmente le seguenti righe:

# Definizione del dossier corrente e la lettura della tabella dei dossier
Local Char FOLDER(30) : FOLDER = nomap
# Nome della procedura di migrazione
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: Azz [F:ADS]: Endif
  # Apertura della traccia e visualizzazione di una finestra di temporizzazione
  If !GSERVEUR
    Call TEMPON("O") From GESECRAN
    Call OUVRE_TRACE(PROG) From LECFIC
  Endif
  # Lancio della procedura
  Call MAJ_UUMGSPEZMA00(FOLDER)
  # Chiusura traccia
  If !GSERVEUR
    Call TEMPOFF     From GESECRAN
    Call FERME_TRACE From LECFIC
    Call LEC_TRACE From LECFIC
  Endif
Endif
End

Il sotto programma di azzeramento

Il sotto programma dichiarato da
      Subprog RAZ_UUMGTRTZMY01(FOLDER)
serve a rimettersi, se necessario, nella situazione iniziale per poter lanciare la procedura.

Deve seguire almeno le seguenti fasi di base:

  • Verificare che le tabelle d'origine e di destinazione esistono, per esempio con le seguenti righe:
          # Trovare la tabella d'origine per la tabella da alimentare (qui UZMYTABLE)
          Call MIGTABNAME(FOLDER,"ZMYTABLE",OLDTABLE,ERR) From TRTMIG
          If ERR : End: Endif
          # Esiste davvero la tabella d'origine?
          If filinfo(filpath("FIL",OLDTABLE,"fde",[F:ADS]DOSSIER),0)<0
               End
          Endif
  • Fare delle tracce solo per gli errori (nessun messaggio di avanzamento o avvertimento)
  • Svuotare la o le tabelle in cui la procedura AGG inserisce i dati. Per farlo, si dispone del seguente sotto-programma:
          # Azzeramento netto e irreversibile nella tabella ZMYTABLE
          Call MIGTABRAZ(FOLDER,"ZMYTABLE",ERR)
          If ERR : End: Endif
  • Se le tabelle comuni a più programmi devono essere parzialmente cancellate, si utilizzeranno delle transazioni classiche del tipo:
           Trbegin [...] : Delete [...] Where ... : Commit
  • Azzerare le informazioni sui flussi già migrati per questa tabella, dal seguente sotto-programma:
          # Nessuna riga migrata in questo momentot
          Call MIGRAZKEY(FOLDER,"UUMGTRTZMY01",ERR) From TRTMIG

Il sotto programma di aggiornamento

Il sotto-programma MAJ_UUMGTRTZMY01, che serve a trascodificare il contenuto della tabella UZMYTABLE per alimentare la tabella ZMYTABLE, deve realizzare le seguenti attività:

  • Il nome della procedura di migrazione deve essere definito all'inizio
    Local Char PROG(20) : PROG="UUMGTRTZMY01"
  • Si aggiornerà lo stato della procedura con il seguente sotto-programma (anche se una condizione preliminare rende inutile il lancio, per esempio se non deve elaborare nulla: è necessario che lo stato sia Terminato affinchè la procedura sia considerata come fatta e che quelle successive possano concatenarsi). Altrimenti, si metterà lo stato In corso:
          # CURSTAT variabile Integerche gestisce lo stato (menù locale 21)
          # I valori possibili sono In attesa, In corso, Terminata...
          # Se la procedura è lanciata, si avrà CURSTAT=2.
          # Se è terminata, si utilizzerà CURSTAT=3.
          # In caso di errore, bisognerà posizionarla a 7
          # In seguito, la variabile PROG contiene il nome della procedura
          #  (UUMGTRTZMY01 per esempio)
          Call MIGSTKENDFLG (DOSSIER,PROG,CURSTAT,ERR) From TRTMIG
  • Si testerà la presenza delle tabelle e delle tabelle precedenti utilizzando il sotto-programma MIGTABNAME seguendo l'esempio di ciò che è fatto nel sotto-programma di inizializzazione. In caso di errore, non bisogna dimenticare di mettere lo stato dell'attività al giusto valore (7) con il sotto-programma MIGSTKENDFLG.
  • In seguito si apriranno le tabelle necessarie alla migrazione. L'apertura delle tabelle interne della procedura di migrazione si fa per:
          Call MIG_OUVRE From TRTMIG
  • Le tracce saranno utilizzate con parsimonia (inutile metterne una su ogni riga, si sono viste delle migrazioni fermarsi per mancanza di spazio su disco per scrivere le tracce). E' utile invece mettere una traccia che inizi con un messaggio di tipo "Avvio della fase aggiornando xxx", ed anche una riga di timestamping con un messaggio tipo "Inizio del processo a :". Queste tracce utilizzeranno i seguenti sotto-programmi:
          # Riga di traccia se ERR=0, riga d'errore altrimenti
          Call ECR_TRACE("message",ERR) From GESECRAN
          # Riga di traccia timestamp
          Call ECR_TIME("message") From DOSSUB
  • Per migliorare il tempo di inserimento nelle tabelle, si cancellano gli indici lasciando solo il primo attivo all'inizio della procedura e li si ricrea alla fine della procedura, tramite i sotto-programmi:
          Call MIGTABINIT(FOLDER,"ZMYTABLE",ERR) From TRTMIG
    Ciò impone che la procedura sia l'unica a lavorare sulla tabella nel momento in cui si esegue. Nessun'altra procedura deve leggere, modificare o inserire nella tabella durante l'esecuzione della procedura. Se alla tabella si può accedere tramite varie procedure, non bisogna utilizzare il sotto-programma.

  • Si ritroverà allora la prima chiave da elaborare nel ciclo di elaborazione. In effetti, se si riprende la migrazione dopo una interruzione, questa chiave non è vuota. La si ritroverà tramite il sotto-programma descritto qui in basso:

           # TBMKEY(1..NBMKEY) è un riquadro di valori di chiavi
           #   in cui riprendere la lettura. Si ritrovano almeno i componenti
           #   dell'ultimo valore della chiave elaborata, ma si può aggiungere
           #   un segmento che potrà indicare il livello di rottura raggiunto
           #   su una chiave multipla. TBMKEY deve essere vuota prima della chiamata
           #   Se al ritorno è vuota, non esiste nessun valore della chiave corrente
           #   (si avviano allore le procedure all'inizio).
           # NBMKEY permette di definire il numero di valori che ci si aspetta
           # NBL e NBUP conteggiano le righe lette e aggiornate fino a quel punto
           Call MIGGETKEY (FOLDER,PROG,NBMKEY,TBMKEY,NBL,NBUP,ERR)
           &    From TRTMIG
  • Si potrà allora inserire nel ciclo di lettura della tabella o delle tabelle di origine e delle scritture delle tabelle di destinazione. Per motivi di performance, bisogna vietare per quanto possibile gli ordini di lettura isolati sulle tabelle e privilegiare le istruzioni Link, preferibilmente con delle join (syntaxe Where CLE~=... ). Se una lettura deve essere su una tabella "piccola" per ragioni di inizializzazione o di controllo (per "piccola" si intende meno di 1000 righe) spesso è preferibile memorizzare il contenuto utile di questa tabella in alcune variabili nella memoria prima di iniziare il ciclo.
  • Per evitare degli errori collegati alla scrittura di un numero eccessivo di righe, si conterà il numero di righe scritte e si interromperà il circuito a tutte le N righe (per esempio N può essere fissato per esempio a 50.000, mediante la variabile globale GMAXUPDTRS).
  • Per ragioni di performance, si userà preferibilmente l'istruzione Writeb (che è stata introdotta dal motore utilizzato nella versione 6.4). Questa istruzione raggruppa le scritture e migliora le performance, prevalentemente ma non solo su una architettura multi terzi. Questa istruzione è utilizzabile solo se non si ricollega la tabella nel ciclo (es.: rilettura per sapere se enreg esiste già). Suppone di fissare il fattore di raggruppamento tramite una variabile di sistema nominata adxwrb (10 sembra un valore giusto). Bisogna allora elencare i valori di chiave scritti per poter restituire tutte le chiavi in corso in caso di errore (questo errore si produce allora sull'istruzione Flush e non su Writeb). Può essere utilizzato il seguente sotto-programma:
            # Impilamento delle chiavi.
            # KEY_ARRAY è un riquadro alfanumerico dichiarato da
            # Local Char KEY_ARRAY(N)(adxwrb)  all'inizio del programma
            # (la lunghezzaN dipende dalla lunghezza dei valori delle chiavi)
            # NUMBER une variabileShortintche indica il numero di chiavi impilate
            # KEY_VALUE valore di chiave messa in fila se la chiave è su più parti
            Call STK (KEY_ARRAY, NUMBER,KEY_VALUE) From TRTMIG
  • In caso di uscita dal ciclo (dopo N cicli, o perchè l'elaborazione è terminata), si farà un Flushsulla tabella (se è usato Writeb) gestendo un eventuale errore. Se si è prodotto un errore e se adxwrbè superiore a 1, si potranno ritrovare le chiavi su cui l'errore ha potuto riprodursi nel riquadro KEY_ARRAY, sui primi indici adxwrb: si farà un Rollback prima di mettere la procedura nello stato Terminato con errori e di terminare l'elaborazione.
  • Se è andato tutto bene, si aggiornerà il numero delle righe lette e aggiornate tramite la seguente chiamata:
         Call MIGSTKKEY (FOLDER,PROG,NBMKEY,TBMKEY,NBL,NBUP,ERR)
         &    From TRTMIG
    Si farà in seguito un Commit.
  • Si potrà in seguito testare se è stata fatta una richiesta di arresto. Se non è il caso e se non sono state processate tutte le righe, si ricomincerà un ciclo su N righe. Il test di arresto si fa tramite il seguente sotto-programma:
          # La variabile STOP è uguale a 0 se è fatta una richiesta d'arresto
          Call MIGSTKPROGRESS (FOLDER,PROG,STOP,ERR) From TRTMIG
  • Se è stata fatta una richiesta d'arresto (o se è terminato un processo), si faranno le seguenti operazioni :
          # Indicizzazione della o delle tabelle elaborate
          # (solo se è stata utilizzata MIGTABINIT)
             Call MIGTABEND(FOLDER,"ZMYTABLE",ERR) From TRTMIG
          # Segnalare a video la fine dell'elaborazione
             Call MIGTRTEND(FOLDER,PROG) From TRTMIG
             Call ECR_TIME(PROG+" : Attività terminata") From DOSSUB

Si potrà in seguito chiudere le tabelle e liberare le risorse se ci sono e poi arrestare il sotto-programma tramite l'istruzione End.

Il sotto-programma PATCH

Questo sotto-programma permette un lancio tramite patch. Deve semplicemente assicurarsi che la tabella ADOSSIER sia aperta, leggere la registrazione corrispondente al dossier da elaborare, poi lanciare la procedura di migrazione. Per esempio, potrebbe essere scritto come segue:

Subprog PATCH(FOLDER)
Value Char FOLDER
# Nessun lancio nel dossier supervisore
If FOLDER=GDOSX3 : End: Endif

#Caricamento della classe [F:ADS]
If clalev([F:ADS])=0  Local File ADOSSIER [ADS] : Endif
Read [ADS] DOSSIER=FOLDER : If fstat: Azz [F:ADS]: Endif
# Lancio della procedura
Call MAJ_UUMGTRTZMY01(FOLDER)
End


Un sotto-programma UTI_MOUL

Questo sotto-progranna permette un lancio durante la validazione del dossier. E' molto simile al sotto-programma PATCH, ma non ha bisogno di assicurarsi che la tabella ADOSSIER sia aperta, nè di leggere la registrazione corrispondente al dossier da elaborare, in quanto è assicurato dal programma chiamante. La sola attività è di lanciare la procedura corrispondente. Per esempio, potrebbe essere scritto come segue:

Subprog UTIL_MOUL(FOLDER)
Value Char FOLDER
# Nessun lancio nel dossier supervisore
If FOLDER=GDOSX3 : End: Endif

# Lancio della procedura
Call MAJ_UUMGTRTZMY01(FOLDER)
End


L'entry point MIGTAB

Se si vuole che le tabelle di flussi specifici siano gestite dal programma di migrazione in un modo analogo (cioè rinominate nello stesso modo all'inizio della validazione del dossier, in seguito creato con la nuova struttura) bisogna seguire le seguenti fasi:

  • bisogna usare l'entry point MIGTAB per indicare che una tabella di flussi specifici dovrà essere elaborata nello stesso modo delle tabelle standard nella prima fase (rinomina e cancellazione degli indici superflui).
  • Bisogna creare nel dossier supervisore (o nel dossier di riferimento se si è in una architettura su 3 livelli) la descrizione delle tabelle specifiche la cui struttura cambia durante il cambio di versione, altrimenti le nuove tabelle di flusso non saranno create vuote con la nuova struttura.
  • Si tratta di una eccezione alla regola un pò particolare che indica che, normalmente non si creano delle tabelle specifiche nel dossier supervisore. La ragione è semplice: si ha bisogno di disporre di un dizionario "di riferimento" in questo caso particolare. Oppure il solo di cui si dispone, se si è in una architettura a due livelli (caso più frequente) è quello del dossier "supervisore" (X3 nel caso di Sage X3). Si noti inoltre che le tabelle specifiche create nel dossier supervisore possono essere cancellate senza preavviso se si installa una nuova versione del dossier supervisore. Bisogna quindi considerare che la presenza di tabelle specifiche in X3 è temporanea e che un salvataggio della descrizione di queste tabelle deve esistere altrove.
  • Una tabella specifica che può essere utilizzata per alimentare i campi specifici di una tabella standard, non è obbligatoriamente necessario creare una nuova tabella specifica durante il cambio di versione. In questo caso, si rinominerà la tabella specifica utilizzando l'entry point MIGTAB e si utilizzeranno degli entry point nelle procedure standard o delle procedure complementari per fare degli aggiornamenti che non ci sarebbero senza creare delle nuove tabelle nel dizionario di arrivo.

Se questo entry point non è utilizzato, le tabelle specifiche, protette da un codice attività specifico, non saranno toccate. Si ritroveranno nello stato di origine, che corrisponderà spesso a quello che deve essere fatto di default se il cambio di versione non ha incidenza sulla struttura delle tabelle specifiche.

Ancora, ogni campo specifico presente in una tabella di flusso standard ed il cui contenuto dovrebbe essere trasferito in modo identico non necessita alcuna precauzione particolare: i programmi standard di migrazione utilizzano delle assegnazioni di classi per realizzare le copie di dati.

Il nome del programma in cui si trova l'entry point MIGTAB dipende dal software basato su Sage X3. Nel caso di Sage X3, questo entry point MIGTAB si trova nel programma TRTMIGTABX3.

In questo programma si aggiungeranno le righe di questo tipo:
    Call MIGTABTABADD(DOSSIER,"ZMYTABLE","ZMY","index",
&         NBTAB,WTABLE,WTABLEJ,WABRJ,WTABIDX,ERR) From TRTMIG

Sapendo che i nomi delle variabili presentae qui in alto sono per la maggior parte fisse:

  • DOSSIER è il codice del dossier.
  • il nome della tabella da migrare data qui come esempio è "ZMYTABLE".
  • "ZMY" corrisponde all'abbreviazione della tabella d'origine dopo essere stata rinominata. Se questo valore è vuoto, è determinata una abbreviazione temporanea, sotto forma U## o W##, in cui ## è un numero.
    In tutti i casi questa abbreviazione non è utilizzata nei programmi: Nelle procedure, si utilizzerà un'altra abbreviazione temporanea come [XXXM] in cui XXX è l'abbreviazione della tabella migrata.
  • NBTAB è la variabile che contiene il numero di tabelle di flussi definite come se dovessero essere migrate (ogni chiamata a TRTMIG incrementa questa variabile).
  • WTABLE, WTABLEJ, WABRJ, WTABIDX sono dei riquadri che contengono tutti gli elementi collegati alle tabelle di flussi già dichiarate.
  • ERR rinvia un valore non nullo in caso di errore.

Gli entry point dei programmi di migrazione standard

Ogni procedura di migrazione standard dispone di entry point che permettono di interagire con la logica di travaso delle tabelle standard. Gli entry point sono i seguenti:

  • CRITSEL permette di alimentare la variabile CRITERESPE per filtrare i dati da elaborare. Il dettaglio del contesto utilizzabile è definito nell'allegato che descrive le procedure di migrazione.
  • VERIFSEL permette di ricalcolare dei campi della tabella di origine in corso di lettura durante l'elaborazione ed eventualmente di escludere un record che di conseguenza non verrà riscritto mettendo ISVALID a 0. Il dettaglio del contesto utilizzabile è definito nell'allegato che descrive le procedure di migrazione.