Gestion des pointeurs , nouveaux codes opération en V3R70 : ........................................................................... : Code : Facteur 1 : Facteur 2 : zone result : > : < : = : ........................................................................... : ALLOC : : longueur : pointeur : :ER : : : : : : : : : : : REALLOC : : longueur : pointeur : :ER : : : : : : : : : : : DEALLOC(N) : : pointeur : :ER : : :...........:.................:.................:.............:...:...:...: (N) avec DEALLOC = assignation de la valeur nulle au pointeur. en V5R10, deux fonctions intégrées viennent remplacer ALLOC et REALLOC. %ALLOC(nb) renseigne un pointeur après réservation de "nb" octets %REALLOC(prt : nb) alloue un espace mémoire plus grand. DEALLOC est admis en format libre (/free, /end-free) |
Quelque précisions sur les pointeurs , cela permet de redéfinir une zone mémoire. la syntaxe est la suivante : Dpointeur * inz(%addr(variable_connue)) Dredefine ds based(pointeur) Exemple Dptindic * inz(%addr(*in)) Ddsindic ds based(ptindic) D sortie N overlay(dsindic:3) D annul N overlay(dsindec:12) en traitement : C dow sortie = *off ... C if annul |
les ordres ALLOC, REALLOC et DEALLOC permettent une gestion dynamique de la taille d'un tableau : Dpttbl * Ddstbl ds based(pttbl) D tbl 5 dim(32767) Dunpaquet s 7 0 inz(50) Dindice_maxi s 5 0 inz(10) DIndice s 5 0 * on demande 50 octets à l'OS C alloc unpaquet pttbl * en V5R10 * pttbl = %alloc(unpaquet) ; C DOU .... ... C eval Indice = Indice + 1 C if indice > indice_maxi c exsr plusgrand C endif |
C ... C enddo C dealloc(N) pttbl C eval *inlr = *on C plusgrand begsr C eval indice_maxi = indice_maxi + 10 C eval unpaquet = %size(tbl) * indice_maxi C realloc unpaquet pttbl * en V5R10 * pttbl = %realloc(pttbl : indice_maxi * %size(tbl) ); * c endsr --------------------------------------------------------------------------- La gestion des pointeurs est simplifiée en V3R70 par la possibilité de manipuler directement un pointeur par: C eval pt = pt + lglue "lglue" représentant alors un nombre d'octets dont il faut se déplacer vers la droite (en incrémentation), très pratique avec un USER SPACE |
Exemple: Structure d'un USER SPACE. De à .......................... -- 1 01: Espace utilisateur : ! Octets à blanc pour : (64 octets à blanc) : ! la communication ..........................64 -- entre programmes 2 65: ENTETE GENERALE : ! : DU USER SPACE : > Découpage image : : ! suivante ..........................140 -- 3 141: Rappel des paramètres : INPUT ! : reçus par l'API : ! .......................... ! 4 : En-tête API : HEADER ! voir structures : (valeurs rencontrées) : > dans QSYSINC .......................... ! (option 13 de l'OS) 5 : Liste générée par API : LIST ! : : ! : (liste des membres : -- : des objets...) : :........................:??? |
....................................................................... : De : à :Fmt: Signification ( DECOUPAGE DE "ENTETE" ) : ......................................................................: : 65 : 68 : B : Taille de l'en-tête générale (2) : : 69 : 72 : C : Version : : 73 : 80 : C : Nom du format utilisé par l'API (ex:OBJD0100) : : 81 : 90 : C : Nom de l'API ayant généré la liste : : 91 : 103 : C : Siècle-date-heure(SDDDDDDHHHHHH) de remplissage : : 104 : 104 : C : Etat (C=Complet,I=Incomplet,P=Partiel) : : 105 : 108 : B : Nb d'octets utilisés dans le user space : : : : : : 109 : 112 : B : Déplacement pour atteindre la zone INPUT : : 113 : 116 : B : Taille de la zone INPUT : : : : : : 117 : 120 : B : Déplacement pour atteindre la zone HEADER : : 121 : 124 : B : Taille de la zone HEADER : : : : : : 125 : 128 : B : Déplacement pour atteindre la liste (LIST) : : 129 : 132 : B : Taille de la liste : : 133 : 136 : B : Nb d'entrées dans la liste : : 137 : 140 : B : Taille de chaque entrée. : .:.......:.......:...:.................................................: |
* lecture d'un user space contenant la liste des membres d'un fichier * (le user space doit être déja rempli par l'API QUSLMBR) * =================================================================== * va contenir l'adresse de début du User Space D pointeur1 s * D i s 10i 0 * l'entête (sera plaquée sur les positions 125 à 140) * Dptrinfos s * DRTVINF ds based(ptrinfos) D offset 10i 0 D taille 10i 0 D nbpostes 10i 0 D lgposte 10i 0 * LIST : DS à plaquer sur un poste (ici représentant un membre) * dptrliste s * DLIST ds based(ptrliste) d ... (informations membre: nom, date de création etc...) |
* prototype pour API qui retrouve pointeur de début du USER SPACE dQUSPTRUS PR EXTPGM('QUSPTRUS') d space 20 const d ptr * /free // extraction du pointeur de début QUSPTRUS('EXEMPLE QTEMP' : pointeur1); // positionnement sur la partie entête (125éme octet) ptrinfos = pointeur1 + 124; // maintenant RTVINF (DS) a un contenu valide // (rappel) // RTVINF e ds based(ptrinfos) // offset 10i 0 // taille 10i 0 // nbpostes 10i 0 // lgposte 10i 0 |
// positionnement sur le premier poste // (la structure "LIST" vient se positionner "par dessus") ptrliste = pointeur1 + offset; // boucle (nbpostes fois) for i = 1 to nbpostes; // traitement d'un élément ... ... ... ... ... if i < nbpostes; ptrliste = ptrliste + lgposte; endif; endfor; et enfin, Trigger : |
Trigger : Pgm associé à une action base de données (ajout, màj, supression) cette association se fait par ADDPFTRG : Ajouter déclencheur fich phys (ADDPFTRG) Indiquez vos choix, puis appuyez sur ENTREE. Fichier physique . . . . . . . . > CLIENTP Nom Bibliothèque . . . . . . . . . *LIBL Nom, *LIBL, *CURLIB Moment de déclenchement . . . . > *BEFORE *BEFORE, *AFTER Evénement de déclenchement . . . > *UPDATE <--+ *INSERT, *DELETE, *UPDATE Programme . . . . . . . . . . . > TRIGGER1 | Nom Bibliothèque . . . . . . . . . *LIBL | Nom, *LIBL, *CURLIB Remplacer déclencheur . . . . . *NO | *NO, *YES Condition déclenchement en màj *ALWAYS <--+ *ALWAYS, *CHANGE | | .....................|........................ : le mot-clé TRGUPDCND ne s'affiche que si : : TRGEVENT est saisi avec la valeur *UPDATE : :............................................: |
Le pgm trigger peut signaler une erreur logique : + il doit envoyer un message à l'appelant + l'action base de données est interrompue inachevée. + le message CPF502B est émis, le message envoyé par votre trigger n'est pas retransmis (donc le texte est inutilisable) Mais, la gestion des triggers change en V3R70 la commande ADDPFTRG accepte un nouveau paramètre ALWREPCHG. |
lorsque ce paramètre est renseigné à oui, le trigger peut modifier l'enregistrement base de donnée qui a provoqué son appel : c'est à dire faire de la substitution de données. RAPPEL, un trigger recoit un buffer contenant : - des informations système - la version AVANT de l'enregistrement - la version APRES. le trigger peut donc maintenant faire de la substitution de données et/ou renseigner automatiquement les champs vides. ce sont les données du trigger qui seront placées dans la base et non celles initialement indiquées par le programme. |
Exemple : soit un fichier article avec le buffer suivant | codearticle | libellé | datecrt | | | | | le trigger recoit un paramètre infos système | code |libellé |date | code |libellé |date | | | Dep1 | Dep2 | | | ! ! ^ ^ !-----!----! ! ! ! !--------------------------! dep1 indique le déplacement pour aller à la version avant du buffer dep2 " " " " " " après du buffer |
le paramètre ALWREPCHG fait que si le trigger modifie la version après c'est cette version de l'enregistrement qui est stockée dans la base. Imaginons maintenant de rajouter dans le fichier article une zone SIECLE complétant la zone date de création (6,0) (répenser à la nouveauté CHGPF qui permet de modifier un fichier ONLINE) Puis recompilons tous les programmes utilisant le fichier article. si nous n'avons pas modifié le source de ces programmes la zone SIECLE n'est JAMAIS renseignée. Ajoutons maintenant un trigger BEFORE/UPDATE, BEFORE/INSERT qui calcule automiquement le SIECLE en fonction de l'année. Vous avez le SIECLE dans vos fichiers, reste à modifier les programmes devant afficher cette information. |
techniquement cela ce fait de la manière suivante : définition des paramètres recus : Dparam ds D filler 64 D dep2 10I 0 puis déclaration d'une DS externe(avec le fichier article) basée sur un pointeur. il s'agit en fait d'un découpage théorique qui n'a pas d'existence tant que le pointeur n'a pas de valeur. Dptr S * Darticle e ds based(ptr) EXTNAME(articlp1) attribuer à ptr l'adresse de param revient à "plaquer" article sur param, "+ dep2" revient à le décaler de "dep2" octets. c eval ptr = %addr(param) + dep2 |
code complet : ============== Dparam DS D filler 64 D dep2 10I 0 Dlgparam S 10I 0 Dptr S * Darticle E DS based(ptr) EXTNAME(articlp1) C *entry plist C parm param C parm lgparam c eval ptr = %addr(param) + dep2 c if datcrt < 500101 c eval siecle = 20 c else c eval siecle = 19 c endif * n'oublions pas le C return |