Tivoli Service Desk 6.0 Developer's Toolkit - Guide de programmation TSD Script
Retour à la table des matières
Le Developer's Toolkit a été conçu dans une optique de simplification du processus
de construction d'applications de base de données client-serveur.
A cet effet, le langage TSD Script contient un jeu d'instructions dédié
à l'interaction avec les bases de données SQL.
L'interface SQL de TSD Script est une partie intrinsèque du langage.
Elle tire parti de la souplesse que confèrent les types de données TSD Script RECORD et LIST.
En outre, les instructions SQL de TSD Script exercent un contrôle passif des accès
concurrents (ou simultanés), permettant ainsi le développement d'applications multi-utilisateurs à
haut niveau de fiabilité.
Une autre caractéristique particulièrement utile du langage est la possibilité d'utiliser des
extractions par tableau avec Oracle.
Ce mode d'extraction améliore de manière significative le temps nécessaire à l'interrogation
d'une base de données.
SQL (Structured Query Language) est un langage standard utilisé pour :
Ce manuel n'ayant pas pour vocation de vous enseigner le langage SQL, il est préférable que vous soyez déjà familiarisé avec sa syntaxe avant d'aborder le présent chapitre.
Les bases de données suivantes (que l'on appelle également sources) sont prises en charge par le Developer's Toolkit :
Le Developer's Toolkit et le langage TSD Script prennent en charge diverses instructions SQL et bases de données SQL utilisées pour le développement d'applications client-serveur.
Certaines instructions SQL ne sont pas compatibles avec les pilotes directs des bases de données Oracle, Sybase/SQLServer et Informix. Elles sont répertoriées dans le tableau suivant.
Cette instruction... | Est admise uniquement dans... |
SQLDeleteCurrent | DB2/2 |
SQLGetCursorName | DB2/2 |
SQLUpdateCurrent | DB2/2 |
Remarque : SQLUpdateCurrent et SQLDeleteCurrent nécessitent l'utilisation d'instructions imbriquées et doivent être utilisées le moins souvent possible. Elles sont généralement considérées comme obsolètes et, pour cette raison, elles ne bénéficient pas d'un support étendu.
Cette section décrit les attributs dont vous disposez pour configurer une source de données. Ces attributs contrôlent le comportement d'une couche base de données dans le Developer's Toolkit.
Remarque : Ces attributs ne sont pas nécessaires lorsque vous utilisez l'Editeur de configuration SQL pour configurer votre source de données. Pour plus de détails, reportez-vous à la section Connexion de votre application à une base de données, plus loin dans ce chapitre.
Une source de base de données est une collection d'informations identifiée par un nom spécifique. Elle est utilisée pour définir la base de données et la connexion à celle-ci.
Remarque : Le choix du nom de la source est libre. TSD Script ne requiert et ne reconnaît aucun nom prédéfini. Il exige en revanche que les noms de source ne commencent pas par un chiffre. Il se peut toutefois que les applications écrites avec TSD Script aient des exigences particulières en ce qui concerne les noms de source. Ainsi, Tivoli Problem Management attend "ADVISOR" comme nom de source de données. Consultez la documentation de votre application pour savoir si elle a des exigences de ce type.
Lorsqu'une source de données est configurée, vous pouvez lister ses attributs (ou caractéristiques) en utilisant la syntaxe ATTRIB=VALEUR. Les attributs possibles sont les suivants :
Normalement, les attributs suivants ne sont pas utilisés :
TSD Script utilise automatiquement les valeurs par défaut pour chaque SGBD qu'il prend en charge. Ces attributs sont utilisés uniquement pour supplanter certaines valeurs par défaut, dans des cas particuliers tels que la nécessité de respecter la casse des objets de base de données (attribut CASE_SENSITIVE).
Dans la plupart des cas, les valeurs par défaut conviennent et vous n'avez donc pas besoin de les remplacer. Nombre de ces attributs agissent sur des fonctions avancées de la base de données et, pour cette raison, il est souhaitable que seul l'administrateur de la base de données soit autorisé à les modifier.
Si votre base de données utilise des noms d'objet dont la casse doit être respectée, vous devez coder les requêtes en conséquence. Si vous créez tous les objets de votre base de données dans la même casse (c'est-à-dire en utilisant que des majuscules ou que des minuscules), TSD Script peut se charger pour vous de la conversion de tous les noms d'objet dans cette casse. Les valeurs possibles de cet attribut sont : UPPER, LOWER et NONE. S'il n'est pas spécifié explicitement, sa valeur par défaut est NONE (aucune conversion).
Remarque : TSD Script préserve toujours la casse des chaînes figurant entre apostrophes dans une requête.
Cet attribut détermine comment votre SGBD traite la casse des objets de base de données. On entend par objets de base de données les noms de table, de colonne, etc. Si sa valeur est TRUE, TSD Script préserve la casse de tous les noms d'objet (à moins que l'attribut CASE_CONVERSION ait une valeur autre que NONE). Si CASE_SENSITIVE n'est pas défini explicitement, sa valeur par défaut est FALSE.
Les entrées suivantes peuvent être utilisées pour supplanter les noms de colonne attendus par TSD Script dans la vue du catalogue des colonnes par défaut.
Colonne | Valeur par défaut |
COL_NAME_COLUMN | NAME |
COL_REMARKS_COLUMN | REMARKS |
COL_LENGTH_COLUMN | LENGTH |
COL_SCALE_COLUMN | SCALE |
COL_TYPE_COLUMN | COLTYPE |
COL_NULLS_COLUMN | NULLS |
COL_TBNAME_COLUMN | TBNAME |
COL_TBCREATOR_COLUMN | TBCREATOR |
Remarque : TSD Script utilise automatiquement les valeurs par défaut pour chaque SGBD qu'il prend en charge. Par conséquent, cet attribut n'est pas utilisé en temps normal. Vous devez y recourir uniquement dans des cas particuliers, lorsque les valeurs par défaut ne conviennent pas. Il contient le nom de la table ou de la vue du catalogue/dictionnaire des colonnes. Etant donné que les produits Tivoli offrent une vue "encapsulée" pour plus de cohérence, sa valeur par défaut est toujours SAI_SYSCOLUMNS.
Cette entrée est disponible uniquement si la valeur
de l'attribut MANUAL_COMMITS est TRUE.
Le cas échéant, la valeur par défaut de
COMMIT_SELECTS est TRUE.
Donnez à COMMIT_SELECTS la valeur TRUE si vous souhaitez que les sélections soient suivies
d'une validation automatique.
DATE_FORMAT est le format de date attendu pour la source de données (SGBD). Pour la plupart des systèmes, le format de date par défaut est : mm/jj/aaaa. Le format de date par défaut pour Oracle est jj-MOI-aa.
Pour personnaliser le format de date, vous devez indiquer sous quelle forme le jour, le mois et l'année doivent apparaître et préciser le séparateur à utiliser. La plupart des combinaisons sont acceptées, mais il existe quelques exceptions. Par exemple, aaaammjj est admis, mais pas aaaajjmm.
Vous pouvez supprimer le zéro non significatif pour le jour et le mois. Dans le cas du jour, il suffit d'indiquer un seul "j" dans la date.
Remarque : Si vous supprimez le zéro non significatif du jour, vous devez le faire également pour le mois. Par exemple, mm/j/aaaa n'est pas une combinaison valide.
Exemple | Résultat |
mm/jj/aaaa | 07/08/1999 |
m/j/aaaa | 7/8/1999 |
Le mois peut être spécifié soit par son numéro dans l'année calendaire (1=janvier),
soit par son nom.
Pour spécifier le mois sous forme de numéro, utilisez la forme
"MM". Pour supprimer le zéro non significatif du mois, indiquez
"M". Pour spécifier le mois par son nom ou par une abréviation,
utilisez "Mois" ou "Moi".
Il est tenu compte de la casse des caractères dans les
spécificateurs de nom de mois (sous forme complète ou abrégée).
Remarque : Si vous supprimez le zéro non significatif du mois, vous devez le faire également pour le jour.
Exemple | Résultat |
MM | 08 |
M | 8 |
Mois | Août |
Moi | Aoû |
MOIS | AOUT |
MOI | AOU |
Vous pouvez spécifier l'année sous sa forme complète ou vous limiter aux deux derniers chiffres.
Avertissement : Tivoli recommande l'utilisation du format à quatre chiffres pour les dates à compter de l'an 2000.
Exemple | Résultat |
mm/jj/aaaa | 07/08/1999 |
mm/jj/aa | 07/08/99 |
Les dates peuvent être mises en forme à l'aide des séparateurs suivants :
Type de séparateur | Exemple | Résultat |
aucun | aaaammjj | 19990626 |
point | mm.jj.aaaa | 06.26.1999 |
tiret | jj-mm-aaaa | 26-06-1999 |
barre oblique | mm/jj/aaaa | 06/26/1999 |
Pour les pilotes ODBC, le fichier de configuration SQL doit contenir la liste des SGBD (DBMS). Les bases de données qui peuvent être listées sous forme d'entrées DBMS= sont les suivantes :
Si la valeur est TRUE, cette source de données est considérée comme la source par défaut lors de l'établissement de la connexion. Il ne peut y avoir qu'une seule entrée DEFAULT par fichier de configuration SQL. Si cette entrée n'est pas spécifiée explicitement, sa valeur par défaut est FALSE.
Il s'agit du nom du pilote du SGBD. Cette entrée est nécessaire à l'établissement de la connexion.
Cet attribut indique le nom de la source de données pour le fichier de configuration SQL (ODBC uniquement).
Cette entrée est prévue pour les interfaces directes. Elle doit recevoir la valeur TRUE si vous voulez que le contrôle des transactions soit géré au niveau du Developer's Toolkit.
Cette entrée reçoit la valeur TRUE si le SGBD admet plusieurs connexions simultanées.
Donnez à cette entrée la valeur TRUE si le SGBD a besoin de plusieurs connexions pour pouvoir exécuter plusieurs instructions d'ouverture (open) à la fois (par exemple, des boucles de sélection/extraction imbriquées). Pour Sybase et SQLServer, la valeur par défaut est TRUE. Pour toutes les autres bases de données, la valeur par défaut est FALSE.
Remarque : TSD Script ouvre pour vous les connexions supplémentaires, lorsqu'elles sont nécessaires.
Il s'agit du qualifiant utilisé pour l'accès aux tables. SQL stocke le nom du créateur/propriétaire d'une table dans la définition de cette dernière. Ce nom est appelé qualifiant de la table. Pour identifier sans équivoque une table de la base de données, il faut utiliser une combinaison du qualifiant et du nom de cette table.
Cette entrée contient le nom du qualifiant nécessaire à l'accès aux tables/vues du catalogue du système. Etant donné que les produits Tivoli offrent une vue "encapsulée" pour plus de cohérence, la valeur par défaut de cette entrée est le qualifiant en cours (dans la chaîne de connexion par défaut).
Cette entrée contient le nom de la table ou de la vue du catalogue/dictionnaire des tables. Etant donné que les produits Tivoli offrent une vue "encapsulée" pour plus de cohérence, sa valeur par défaut est toujours SAI_SYSCOLUMNS.
Les cinq entrées suivantes peuvent être utilisées pour supplanter les noms de colonne attendus par TSD Script dans la vue du catalogue des tables par défaut :
TAB_NAME_COLUMN | NAME |
TAB_REMARKS_COLUMN | REMARKS |
TAB_TYPE_COLUMN | TYPE |
TAB_CREATOR_COLUMN | CREATOR |
TAB_COLCOUNT_COLUMN | COLCOUNT (pour DB2/2 et SQLBase) |
Cette entrée est le format horaire attendu pour la source de données. Pour tous les SGBD, sa valeur par défaut est hh:mm:ss. La plupart des formats horaires sont valides. Il existe toutefois quelques exceptions. Par exemple, hh:mm:ss est admis, mais pas mm:hh:ss.
Pour plus de détails sur les formats horaires admis, reportez-vous à la description de l'instruction TimeFormat, dans le document Tivoli Service Desk 6.0 Developer's Toolkit - Manuel de référence du langage TSD Script.
Par défaut, le format horaire est sur 24 heures. Si vous souhaitez obtenir un format sur 12 heures, ajoutez le suffixe AM_PM.
Exemple | Résultat |
hh:mmAM_PM | 09:08 PM |
hh:mm | 21:08 |
Il n'est pas tenu compte de la casse des caractères dans le spécificateur de format. Ainsi, hh:mm:ss est équivalent à HH:MM:SS
Pour supprimer les zéros non significatifs, spécifiez uniquement h, m et s. Par exemple :
Exemple | Résultat |
hh:mm:ss | 08:35:09 |
h:m:s | 8:35:9 |
Remarque : Si vous choisissez de supprimer les zéros non significatifs, vous devez le faire pour les heures, les minutes et les secondes.
Pour spécifiez les secondes, incluez la désignation ss. Vous pouvez omettre les secondes dans le format horaire.
Exemple | Résultat |
hh:mm:ss | 08:35:09 |
h:m | 8:35 |
Vous pouvez séparer les données de l'heure par des signes deux-points ou des points.
Type de séparateur | Exemple | Résultat |
aucun | hhmmss | 121604 |
point | hh.mm.ss | 12.16.04 |
deux-points | hh:mm:ss | 12:16:04 |
Cette entrée contient le nom de la fonction, spécifique au SGBD, servant à convertir en majuscules les colonnes d'une requête (utilisée par SQLCreateSearchString). Les valeurs par défaut sont les suivantes :
La liaison ou la connexion à une base de données est un processus commun à tous les SGBD SQL. Le moyen employé varie cependant en fonction de la base de données utilisée. Par exemple :
Pour masquer ces différences, TSD Script fournit un ensemble de services de connexion qui utilisent l'instruction SQLCommand. Celle-ci permet d'utiliser, pour les informations de connexion spécifiques au SGBD, des commandes externes placées dans un fichier de configuration SQL. Cette méthode a le double avantage de simplifier le code de votre application et de le rendre portable.
Le nom par défaut du fichier de configuration SQL du Developer's Toolkit est sai_sql.cfg. C'est donc ce fichier que le Developer's Toolkit recherche dans le sous-répertoire CFG du répertoire racine SAI.
Vous pouvez cependant désigner un autre fichier en indiquant son nom comme valeur d'une variable d'environnement appelée SAISQLCFG. La valeur de SAISQLCFG est prioritaire sur le chemin dérivé de SAI_ROOT, si ces deux variables sont définies. Si le fichier désigné est introuvable, une erreur est signalée.
Le fichier de configuration SQL est divisé en sections qui décrivent une source de données. Considérez une source de données comme le SGBD avec lequel vous travaillez. Normalement, les sources de données correspondent à des serveurs de bases de données physiques, bien que ce concept puisse être étendu aux sources logiques d'un serveur (une source par base de données, par exemple).
Le Developer's Toolkit fournit un certain nombre d'interfaces directes que vous pouvez utiliser lorsqu'elles répondent à vos besoins en termes de base de données. Elles sont utilisées, par le Developer's Toolkit, comme mécanisme par défaut pour la connectivité aux bases de données.
Si vous préférez utiliser ODBC à la place des interfaces de bases de données directes, vous trouverez des informations détaillées sur les pilotes ODBC dans l'Annexe A, "Configurations ODBC", du Guide d'installation de Tivoli Service Desk 6.0.
Si vous utilisez les interfaces directes du Developer's Toolkit, reportez-vous à la section "Processus de configuration", dans le Guide d'installation de Tivoli Service Desk 6.0. Vous y trouverez toutes les instructions de configuration et de test.
Pour ajouter un client de base de données, suivez les étapes ci-après :
La boîte de dialogue Editeur de configuration SQL comporte les éléments suivants :
- Fichier - Zone de saisie du nom du fichier de configuration utilisé pour mettre en place une connexion client vers la base de données. Cette zone contient normalement le nom du fichier que vous utilisez.
- Sources - Liste contenant les noms des sources de données.
- Options - Liste répertoriant les options de la source de données sélectionnée.
- Configurer - Bouton servant à configurer les options de la source de données sélectionnée.
- Ajouter - Bouton servant à créer une nouvelle entrée dans la liste des sources de données.
- Supprimer - Bouton servant à supprimer une entrée préalablement sélectionnée dans la liste des sources de données.
- Copier - Bouton servant à copier le contenu de la source de données sélectionnée. La copie contient les mêmes données que l'original, mais elle porte un nom différent.
- Renommer - Bouton servant à renommer la source de données sélectionnée. Cette fonction permet simplement de renommer une source existante, sans la copier.
- Source par défaut - Bouton servant à désigner la source sélectionnée comme source par défaut.
- Tester la connexion - Bouton servant à tester la connexion configurée. Le résultat du test est un message indiquant le succès ou l'échec de la connexion.
- Tracer la configuration - Bouton utilisé pour tracer l'activité de la base de données en vue d'obtenir des informations pour le débogage.
- Sécurisation du mot de passe -
- Qualifiant - Parce que SQL autorise la présence de plusieurs tables portant le même nom dans une base de données, il stocke le nom du créateur/propriétaire de chaque table dans la définition de celle-ci. Ce nom est appelé qualifiant de la table. Par exemple, EXAV peut être utilisé comme qualifiant dans la boîte de dialogue Configuration de la source.
- Serveur - Nom du serveur auquel les demandes des clients sont adressées.
- Base de données - Nom de la base de données que vous utilisez.
- Pilote - Nom du pilote utilisé pour vous connecter à la base de données.
- Nom de la source ODBC - Si vous avez choisi le pilote ODBC dans la boîte de dialogue Sélection du pilote, vous devez indiquer dans cette zone le nom de la source de données ODBC. Veillez également à consulter l'Annexe A du Guide d'installation de Tivoli Service Desk 6.0, qui contient des instructions sur la configuration ODBC.
- ID utilisateur - ID utilisé pour accéder à la base de données (son emploi est facultatif).
- Mot de passe - Mot de passe d'accès à la base de données (son emploi est facultatif).
- Valeurs par défaut - Cochez cette case si les informations que vous entrez doivent constituer la configuration par défaut de votre connexion à la base de données.
Résultat : Si vous choisissez OK, la procédure de configuration s'arrête là. Si vous choisissez Avancé dans la boîte de dialogue Configuration de la source, vous obtenez la boîte de dialogue Configuration des options avancées.
Lorsque vous ajoutez une nouvelle connexion à la base de données, vous devez la tester pour vous assurer de son fonctionnement correct. Voici comment procéder :
Conserver les ID utilisateur et les mots de passe dans le fichier de configuration SQL
met en péril la sécurité du système.
De même, il est risqué d'y stocker les informations de connexion de plusieurs utilisateurs,
car ce fichier est accessible à tous et, par défaut, les mots de passe ne sont pas
chiffrés.
Le chiffrement des mots de passe peut être sélectionné dans l'Editeur de configuration SQL.
Pour plus de détails, reportez-vous à
l'exemple de configuration d'une base de données,
plus haut dans ce document.
Avec TSD Script, il existe un moyen simple de fournir les informations de connexion dans l'instruction de connexion (CONNECT) elle-même :
ret := SQLCommand('CONNECT SOURCE=DB2_TEST; UID=FRED; PWD=DERF;');
Voici ce qui se produit lorsque TSD Script rencontre ce type de demande de connexion :
La chaîne de connexion par défaut de la source DB2_TEST est localisée (DB2_TEST doit être une source déclarée dans le fichier de configuration SQL). Si aucune entrée SOURCE= n'est trouvée, TSD Script utilise la chaîne par défaut.
Remarque : Lorsque d'autres attributs sont présents dans l'instruction de connexion, vous devez placer SOURCE= devant le nom de la source de données.
Une nouvelle chaîne de connexion est formée par la substitution des paires ATTRIBUT=VALEUR restantes aux entrées correspondantes de la chaîne par défaut, et par l'insertion des nouvelles paires qui n'ont pas de correspondance dans la chaîne par défaut.
Vous pouvez ainsi supplanter n'importe quelle entrée de la chaîne de connexion par défaut, à l'exception de celle qui désigne le pilote (DRV=). De cette manière, vos informations de connexion par défaut (base de données, qualifiant de table, etc.) peuvent être remplacées de manière ponctuelle, au gré de vos besoins. Vous pouvez aussi obtenir un résultat semblable en créant de nouvelles sources de données (une source par base de données, par exemple).
Il est possible de fournir toutes les informations de connexion à l'instruction SQLCommand
et d'éliminer ainsi le besoin de recourir à un fichier de configuration SQL.
Cependant, vous devez être disposé à accepter toutes les valeurs par défaut
de la source (MULTI_CONNECT, etc.).
En temps normal, l'externalisation des informations spécifiques au SGBD est une bonne
solution.
Cependant, dans certains cas, vous pouvez être amené à contourner le fichier
de configuration SQL.
A cet effet, TSD Script vous permet d'enregistrer une nouvelle source, qui ne figure
dans aucun fichier de configuration SQL, et de vous y connecter .
ret := SQLCommand('CONNECT NEWSOURCE=MYAPP; DRV=XOORA;SRVR=X:ORASERV; UID=MARY; PWD=');
Le reste de ce chapitre s'appuie sur un exemple de base de données appelé COMPANY. Cette base de données est constituée des tables et vues suivantes. Les attributs de colonne sont répertoriés sous chaque nom de table ou de vue.
Table DEPARTMENT
Table EMPLOYEE
Table MANAGER
L'instruction SQLSelectInto offre un moyen simple d'extraire des informations d'une table ou d'une vue SQL. Elle reçoit un nombre variable d'arguments.
Le premier argument est toujours une expression de type chaîne qui représente une instruction SQLSelect telle que :
SELECT * FROM EMPLOYEE WHERE EMPLOYEE_ID='305-83-3811'.
Dans la plupart des cas, on utilise SQLSelectInto pour extraire une seule ligne d'une table. L'expression de sélection transmise comme premier argument contient généralement une clause de la forme :
WHERE <clé-primaire>=<valeur>
En général, le format d'une instruction SELECT est le suivant :
SELECT <liste-colonnes> FROM <nom-table-ou-vue> WHERE <condition>.
<liste-colonne> est une liste d'un ou de plusieurs noms de colonne séparés par des virgules (telle que "FIRST_NAME, LAST_NAME"). Si vous souhaitez extraire toutes les colonnes d'une table, vous pouvez utiliser l'astérisque (*) à la place de cette liste.
<condition> est une condition TRUE/FALSE généralement formée d'un nom de colonne, d'un opérateur relationnel (=, >, <, >=, <=) et d'une valeur (telle que 'SMITH').
Voici quelques exemples d'instructions SELECT valides :
SELECT EMPLOYEE_ID,LAST_NAME FROM EMPLOYEE WHERE DEPARTMENT_ID='SALES' SELECT FIRST_NAME,LAST_NAME,PHONE FROM EMPLOYEE SELECT * FROM MANAGER
Les arguments suivants de SQLSelectInto sont des variables TSD Script. Les noms de ces variables doivent correspondre aux noms des colonnes de la table ou de la vue SQL à laquelle on accède, comme dans l'exemple suivant :
VARIABLES last_name, first_name: String; ACTIONS SQLSelectInto('SELECT LAST_NAME,FIRST_NAME FROM EMPLOYEE WHERE EMPLOYEE_ID=123', last_name,first_name);
Dans ces exemples, la casse des caractères des variables TSD Script n'a pas d'importance pour le traitement. La valeur tirée de la colonne LAST_NAME est lue dans la variable chaîne last_name. Celle de la colonne FIRST_NAME est lue dans la variable first_name.
Un moyen plus simple d'extraire des informations de tables SQL est de recourir à des variables enregistrements TSD Script. Vous devez pour cela définir un type enregistrement dont les champs correspondent aux noms des colonnes de la table SQL concernée. Dès lors, vous pouvez transmettre un enregistrement de ce type à SQLSelectInto, comme le montre l'exemple ci-dessous :
TYPES EmployeeRec IS RECORD employee_ID: Integer; last_name: String; first_name: String; birth_date: Date; salary: Real; END; VARIABLES r: EmployeeRec; SQLSelectInto('SELECT LAST_NAME,FIRST_NAME FROM EMPLOYEE WHERE EMPLOYEE_ID=123',r);
En général, vous déclarez un type enregistrement dont le nom est le même pour chaque table ou vue de la base de données. Grâce aux fonctions de liaison de noms de TSD Script, vous pouvez utiliser des variables de ce type pour extraire des informations d'une base de données ou pour en insérer.
Dans l'exemple précédent, le type enregistrement EmployeeRec est déclaré de telle manière que les noms et les types de ses champs correspondent aux noms et aux types des colonnes de la table SQL EMPLOYEE. Lorsque vous transmettez un enregistrement (r) de ce type à SQLSelectInto, le Developer's Toolkit copie automatiquement les informations de la ligne demandée dans les champs concordants. Après l'exécution de SQLSelectInto, la variable r comporte les valeurs suivantes :
r.employee_ID = $Unknown r.last_name = 'Brown' r.first_name = 'Robert' r.birth_date = $Unknown r.salary = $Unknown
Notez que seuls les champs r.LAST_NAME et r.FIRST_NAME contiennent une valeur. Initialement, tous les champs d'un enregistrement contiennent la valeur $Unknown. Etant donné que l'instruction SQLSelectInto a limité la sélection aux colonnes LAST_NAME et FIRST_NAME, seuls les champs r.LAST_NAME et r.FIRST_NAME ont reçu une valeur. Tous les champs de la variable r comporteraient des valeurs si l'instruction avait été la suivante :
SQLSelectInto('SELECT * FROM EMPLOYEE WHERE EMPLOYEE_ID=123',r);
Le mappage (ou mise en correspondance) entre les types enregistrements TSD Script et les tables SQL est un processus intuitif. TSD Script permet de créer une association automatique entre une table, une vue et un type enregistrement au moyen d'instructions d'importation (import).
Cela signifie que vous n'avez pas à déclarer manuellement le champ de l'enregistrement qui correspond à chaque colonne d'une table ou d'une vue. Etudiez l'exemple suivant :
TYPES EmployeeRec IS RECORD IMPORT('EMPLOYEE'); END;
Il est possible d'utiliser des instructions d'importation à l'intérieur d'une déclaration
d'enregistrement pour créer les déclarations des champs directement à partir des
noms et des types des colonnes de la table ou de la vue SQL.
De cette manière, en cas de changement de la table ou de la vue, les modifications
sont automatiquement répercutées dans la déclaration de l'enregistrement.
Par exemple, si vous ajoutez une nouvelle colonne ADDRESS à la table EMPLOYEE, nul
besoin d'ajouter un nouveau champ
address: String;
à la déclaration de EmployeeRec. IMPORT est une instruction exécutée au moment de l'analyse syntaxique (parse). Ainsi, chaque fois qu'un module contenant une instruction IMPORT est reconstruit (donc réanalysé), la table ou la vue SQL désignée est lue et les déclarations des champs sont créées en fonction des colonnes trouvées.
Les instructions d'importation prennent en argument une chaîne de connexion qui est spécifiée avec le nom de la table ou de la vue. Cette chaîne remplace la chaîne de connexion par défaut qui est définie dans le fichier de configuration sai_sql.cfg. Dans un but de compatibilité ascendante, vous pouvez utiliser le format 'DATABASE xxx' pour spécifier le nom de la base de données (xxx représentant ici le nom de la base en question).
Lors de l'analyse syntaxique, transmettez l'option /S à l'Analyseur TSD Script si vous avez besoin de remplacer certaines informations codées en dur, relatives à la base de données ou à la connexion.
L'option /S permet de spécifier une base de données au moment de l'analyse, si bien que vous n'avez pas besoin de figer le nom de la base de données dans le code (c'est-à-dire le "coder en dur"). Vous pouvez également l'utiliser pour spécifier l'ID utilisateur et le mot de passe lorsque vous exécutez l'Analyseur TSD Script à partir de la ligne de commande. Toutes les valeurs spécifiées à l'aide de cette option se substituent aux valeurs par défaut correspondantes qui sont définies dans le fichier sai_sql.cfg.
L'idéal est de définir toutes les valeurs dans le fichier sai_sql.cfg, à l'exception de l'ID utilisateur et du mot de passe, qui seront indiqués au moment de l'analyse à l'aide de l'option /S. Par exemple :
/S"UID=IDutil;PWD=Motpasse"
(où IDutil est l'ID utilisateur et Motpasse le mot de passe correspondant).
Avec IMPORT, vous pouvez utiliser des mots clés optionnels pour préciser le classement du contenu de cette instruction. Ces mots clés sont les suivants :
Si vous ne spécifiez aucun mot clé, l'ordre des éléments de la chaîne d'importation est considéré comme étant le suivant : le nom de la table en premier, suivi de la chaîne de connexion.
Utilisez des espaces et/ou des virgules pour séparer le nom de table et les informations de connexion.
Remarque : Vous pouvez utiliser soit le mot clé TABLE, soit le mot clé VIEW pour identifier un nom de table ou de vue. L'un et l'autre sont traités de la même manière.
Le système ne tient pas compte de la casse des caractères des mots clés (c'est par commodité qu'ils apparaissent en majuscules dans le présent manuel). En revanche, il est possible que la casse des noms de table et des informations de connexion soit prise en compte, selon le SGBD utilisé. Au besoin, renseignez-vous auprès d'un administrateur du réseau local ou de l'administrateur de la base de données. Vous pouvez également vous référer aux manuels qui accompagnent votre SGBD.
Il existe de nombreuses façons de construire une chaîne d'importation valide.
Les exemples suivants offrent un aperçu des possibilités dans ce domaine.
Nous vous recommandons toutefois de choisir un style et de l'utiliser de manière cohérente.
L'utilisation recommandée de l'instruction IMPORT est indiquée ci-après :
Import('ALARMS');
La syntaxe suivante était admise dans SA-ASE 4.1 :
Import('DATABASE ADVISOR TABLE ALARMS');
Pour SA-ASE 4.2 et versions ultérieures, la syntaxe est :
'CONNECT DB=ADVISOR'
Les exemples suivants sont équivalents à l'exemple précédent :
Import ('CONNECT DB=ADVISOR TABLE ALARMS');
Import('TABLE ALARMS CONNECT DB=ADVISOR');
Import('ALARMS, CONNECT');
Import('TABLE ALARMS');
Import('VIEW PROBLEM_VIEW');
Dans l'exemple suivant, remarquez l'absence d'espaces dans la chaîne de connexion :
Import('ALARMS, SRVR=X:ORASRV;DB=ADVISOR');
Cette syntaxe est également correcte :
Import('TABLE ALARMS, CONNECT SRVR=X:ORASRV; DB=ADVISOR);
Dans l'exemple suivant, le "'" est optionnel.
Import('TABLE ALARMS CONNECT SRVR=X:ORASRV; DB=ADVISOR');
Cette syntaxe est également correcte :
Import('CONNECT SOURCE=ADVTEST;SRVR=X:ORASRV; DB=ADVISOR, TABLE ALARMS);
La syntaxe suivante est incorrecte, car 'ADVISOR' n'est pas une chaîne de connexion valide ('DB=ADVISOR' est une chaîne de connexion valide).
Import('ALARMS,ADVISOR'); (* SYNTAXE INCORRECTE !*)
TSD Script fournit six types de données simples :
L'instruction IMPORT s'appuie sur une approche générique pour mapper les colonnes vers les champs en fonction de leur type.
Colonne de type... | Mappée vers le type TSD Script... |
CHAR, VARCHAR ou LONG VARCHAR | STRING |
INTEGER | INTEGER |
DATE | DATE |
TIME | TIME |
Types SQL à séparateur décimal (fixe ou flottant) | REAL |
Quant au type BOOLEAN, la plupart des implémentations SQL ne le prennent pas en charge. Cependant, si vous utilisez Oracle ou IBM DB2/2, vous pouvez inclure $ASETYPE=BOOLEAN dans le commentaire d'une colonne afin que celle-ci donne lieu à la génération, par l'instruction IMPORT, d'un champ de type BOOLEAN. Pour SQLServer, le Developer's Toolkit crée un type BOOLEAN défini par l'utilisateur.
Le Developer's Toolkit crée une table des types qui est liée à la vue SYSCOLUMNS pour Informix.
L'utilisation de SQLSelectInto est un moyen simple de récupérer une ligne
unique d'une table ou d'une vue.
Elle ne peut cependant pas scruter une table.
TSD Script fournit une variable curseur (cursor) permettant de récupérer, à l'intérieur
d'une boucle, plusieurs éléments de la base de données.
Le curseur conserve la trace de la position en cours dans la liste des éléments
récupérés.
Voici le processus de base à mettre en oeuvre pour récupérer plusieurs lignes de données :
Pour permettre la récupération de plusieurs lignes, TSD Script fournit trois instructions :
Le document Tivoli Service Desk 6.0 Developer's Toolkit - Manuel de référence du langage TSD Script fournit des informations complémentaires sur ces instructions.
Ces instructions sont utilisées dans l'exemple suivant :
VARIABLES cursor: SQLCursor; r: EmployeeRec; ACTIONS IF SQLSelect(cursor,'SELECT * FROM EMPLOYEE WHERE SALARY>>0000.00') > 0 THEN WHILE SQLFetch(cursor,r) > 0 DO ProcessEmployee(r); END; SQLCloseCursor(cursor); END;
Dans cet exemple, le code effectue le traitement suivant :
L'opération SQLCloseCursor est très importante. Lorsqu'un curseur SQL est ouvert, la plupart des implémentations SQL verrouillent toutes les lignes de la table de résultats. Ce n'est qu'à l'exécution de SQLCloseCursor qu'elles sont déverrouillées.
Remarque : Il est peu probable que vous ayez à programmer des interactions avec l'utilisateur entre l'instruction SQLSelect et l'instruction SQLCloseCursor. De plus, TSD Script admet un nombre limité de curseurs simultanés. Si vous oubliez de les fermer, les curseurs disponibles seront vite épuisés.
SQL autorise la présence de plusieurs tables homonymes dans une base de données. Aussi, pour qu'une table puisse être distinguée de ses homonymes, le nom de son créateur/propriétaire est stocké dans sa définition. Ce nom est appelé qualifiant de la table. Pour identifier sans équivoque une table de la base de données, il faut utiliser une combinaison du qualifiant et du nom de cette table. Par exemple :
mary.address
La plupart des SGBD SQL utilisent l'ID de l'utilisateur en cours comme qualifiant lorsque celui-ci n'est pas fourni explicitement. Si vous n'êtes pas connecté sous l'ID de l'utilisateur qui a créé la base de données et que vous ne fournissez pas de qualifiant, certaines implémentations SQL poursuivent le traitement en utilisant comme qualifiant le nom du propriétaire de la base de données comme qualifiant. Dans d'autres implémentations SQL (telles que DB2/2), vous devez fournir le qualifiant à chaque fois.
TSD Script effectue les substitutions de qualification appropriées pour autant que vous
fournissiez une entrée QUAL= dans la chaîne de connexion.
Ces substitutions ont lieu dans toutes les instructions, à l'exception des suivantes :
SQLPrepare SQLExecuteImmediate
Si vous utilisez des requêtes complexes, contenant des noms de corrélation, il se peut
que les substitutions ne soient pas effectuées correctement.
Pour prévenir ce risque dans de tels cas, TSD Script fournit un pseudo-qualifiant,
$QUAL, qui est substitué au qualifiant en cours (c'est-à-dire celui qui est défini par l'entrée
QUAL= de la chaîne de connexion).
Par exemple, dans le fragment de code suivant, on utilise $QUAL pour éviter
d'avoir à coder le véritable qualifiant :
ret := SQLExecuteImmediate('DROP TABLE $QUAL.ADDRESS');
Dans TSD Script, toutes les chaînes sont encadrées d'apostrophes. En langage SQL, les littéraux de type caractère, date et heure doivent également être encadrés d'apostrophes. Par exemple, pour lancer cette requête SQL :
SELECT * FROM EMPLOYEE WHERE LAST_NAME='BROWN'
vous devez utiliser l'instruction TSD Script suivante :
SQLSelectInto('SELECT * FROM EMPLOYEE WHERE LAST_NAME=''BROWN''',r);
Dans cet exemple d'instruction SQLSelectInto, vous pouvez observer que les deux apostrophes à gauche du "B" de "BROWN" se traduise en fait par une seule apostrophe. De même, les deux apostrophes qui suivent le "N" de "BROWN" ont pour effet d'insérer une seule apostrophe à cet endroit. Quant à la troisième apostrophe après le "N" de "BROWN", c'est celle qui ferme la chaîne.
Lorsqu'un littéral chaîne figurant dans une instruction TSD Script comprend une apostrophe, celle-ci doit être doublée. Par exemple, pour affecter la chaîne "Tom's Place" à une variable TSD Script, vous devez utiliser la syntaxe suivante :
s := 'Tom''s Place';
La concaténation de chaînes dans lesquelles figurent des apostrophes se complique quelque peu. Dans l'exemple suivant, le nom de famille (last name) que l'on recherche est stocké dans une variable chaîne appelée last_name :
last_name := 'BROWN';
SQLSelectInto('SELECT * FROM EMPLOYEE WHERE LAST_NAME=''' & last_name & '''',r);
Lorsque vous créez une chaîne de sélection utilisant l'opérateur de concaténation TSD Script (&), veillez à insérer une apostrophe de part et d'autre de la valeur littérale sur laquelle vous faites porter la recherche. La requête résultante se présente comme suit :
SELECT * FROM EMPLOYEE WHERE LAST_NAME = 'BROWN'
L'apostrophe figurant à gauche de la valeur du nom (BROWN) résulte des trois apostrophes qui suivent LAST_NAME=.
Les deux premières servent à insérer l'apostrophe nécessaire, tandis que la troisième ferme simplement la première constante chaîne, 'SELECT * ... ='.
La seconde apostrophe nécessaire est obtenue par la concaténation du littéral '''' à la fin de l'expression entière.
Lorsque vous créez une expression de sélection dans laquelle la valeur recherchée est une chaîne, une date ou une heure, vous devez placer trois apostrophes avant la variable contenant la valeur, et quatre apostrophes après.
Les apostrophes ne sont pas nécessaires lorsque la recherche porte sur d'autres types de données, comme le montre l'exemple suivant :
SQLSelectInto('SELECT * FROM EMPLOYEE WHERE AGE=30',r);
Il n'est pas nécessaire d'encadrer le 30 avec des apostrophes, car il s'agit d'un entier. Si, au lieu d'être spécifiée directement, la valeur 30 était contenue dans une variable de type entier, l'instruction aurait l'apparence suivante :
age := 30; SQLSelectInto('SELECT * FROM EMPLOYEE WHERE AGE=' & age,r);
SQLFormat est une instruction TSD Script utilisée dans les manipulations SQL. Elle convertit la valeur d'une donnée en une chaîne adaptée au format de données du SGBD que vous utilisez.
L'instruction SQLFormat est particulièrement utile dans le cas de variables date et heure. Sa syntaxe est la suivante :
SQLFormat(valeur : EXPRESSION SIMPLE): STRING;
Remarque : Il est possible que votre SGBD nécessite des formats de date et d'heure différents des formats par défaut utilisés par le Developer's Toolkit pour l'affichage. Par exemple, le format de date par défaut d'Oracle est JJ-MOI-AA, alors que celui du Developer's Toolkit est MM/JJ/AAAA.
L'argument reçu par SQLFormat doit être un type simple, tel que DATE ou STRING. SQLFormat renvoie la chaîne formatée, et non un code retour, qui indique si l'option a abouti ou échoué. Si la valeur transmise en argument est $Unknown, la chaîne 'NULL' est renvoyée. Le formatage spécifique de la chaîne dépend du type de celle-ci :
Voici un exemple de base de connaissances utilisant l'instruction SQLFormat :
KNOWLEDGEBASE Example;
--PUBLIC ROUTINES FUNCTION GetCount(VAL d: DATE): INTEGER;
PRIVATE ROUTINES FUNCTION GetCount(VAL d: DATE): INTEGER IS VARIABLES retCd : INTEGER; cmd : STRING; $SQLColumn_1 : INTEGER; ACTIONS cmd := 'SELECT COUNT(*) FROM COMPANIES WHERE name = ' & SQLFormat('Joe''s place') & ' AND founded_date='& SQLFormat(d); retCd := SQLSelectInto(cmd, $SQLColumn_1); IF retCd < 0 THEN Exit( retCd ); ELSE Exit( $SQLColumn_1 ); END; END;
Pour plus d'informations sur les instructions TSD Script servant au formatage des données, reportez-vous au document Tivoli Service Desk 6.0 Developer's Toolkit - Manuel de référence du langage TSD Script.
Pour faciliter la récupération des données, TSD Script établit une relation d'équivalence entre les noms de variable et les noms de colonne. Cependant, il arrive parfois que cette relation ne convienne pas ou ne soit pas utilisable.
Considérons la requête SQL suivante, que l'on utilise pour déterminer le nombre d'employés (lignes de données) dans la table EMPLOYEE :
SELECT COUNT(*) FROM EMPLOYEE
Avec TSD Script, il existe un moyen simple de récupérer des données d'une colonne SQL sans se baser sur son nom. Tout ce que vous avez à faire est de déclarer une variable nommée $SQLCOLUMN_n, dans laquelle "n" est le numéro de la colonne à récupérer. Le type de cette variable doit correspondre à celui de la colonne que l'on récupère.
Pour récupérer le nombre d'employés (lignes) dans la table EMPLOYEE, vous pourriez utiliser le code suivant :
VARIABLES $SQLCOLUMN_1: INTEGER; ACTIONS SQLSelectInto('SELECT COUNT(*) FROM EMPLOYEE',$SQLCOLUMN_1);
$SQLCOLUMN_1 est une variable normale. Vous pouvez donc l'affecter, la tester, l'utiliser dans des expressions, etc.
Cette section décrit comment insérer, supprimer et modifier des données dans une base de données SQL.
L'instruction SQLInsert peut être utilisée pour insérer de nouvelles lignes dans une table. Vous devez simplement fournir un nom de table, suivi d'une ou de plusieurs variables contenant les données à insérer. Comme pour la fonction de récupération, les noms des variables TSD Script sont mis en correspondance (mappés) avec les noms des colonnes SQL.
Dans l'exemple suivant, des valeurs sont affectées aux différents champs d'une variable du type EmployeeRecord. Pour insérer ces informations dans la table EMPLOYEE, on appelle SQLInsert avec, comme arguments, le nom de la table cible et la variable.
VARIABLE r: EmployeeRecord; ACTIONS r.employee_ID:'312-34-3444'; r.last_name:'Lebrun' r.first_name:'Robert' r.birth_date:'05/08/1964'; r.salary: $Unknown SQLInsert('EMPLOYEE',r);
Comme SQLSelectInto et SQLSelect, l'instruction SQLInsert reçoit un nombre variable d'arguments. Le premier argument est le nom de la table. Les arguments restants représentent les valeurs à insérer dans chaque colonne de la nouvelle ligne. Vous pouvez transmettre soit un enregistrement unique, soit plusieurs variables simples, comme c'est le cas dans l'exemple suivant :
VARIABLE employee_ID: STRING; last_name: STRING; first_name: STRING; birth_date: DATE; salary: REAL; ACTIONS employee_ID:'312-34-3444'; last_name:'Lebrun'; first_name:'Robert'; birth_date:'05/08/1964'; salary:$Unknown; SQLInsert('EMPLOYEE',employee_ID,last_name, first_name,birth_date,salary);
SQLDelete peut être utilisée pour supprimer une ou plusieurs lignes d'une table.
Elle prend deux arguments : le nom de la table et une clause SQL WHERE identifiant les lignes à
supprimer.
La présence du mot WHERE dans cette clause est facultatif.
Dans l'exemple suivant, on supprime l'enregistrement de chaque employé dont le
nom de famille (last name) est "Smith".
SQLDelete('EMPLOYEE','LAST_NAME=''Smith''');
Dans l'exemple suivant, on supprime l'enregistrement de l'employé identifié par le matricule (employee ID) indiqué.
SQLDelete('EMPLOYEE','EMPLOYEE_ID=''123-45- 6789''');
L'instruction SQLUpdate peut être utilisée pour modifier le contenu de lignes existantes dans une table. Ses arguments sont les suivants :
Supposons, par exemple, que l'employé dont le matricule (ID) est le 345-67-8901 ait reçu une augmentation de 10 %. Pour refléter ce changement, on met à jour la base de données de la façon suivante :
VARIABLES salary: REAL; ACTIONS IF SQLSelectInto('SELECT SALARY FROM EMPLOYEE WHERE EMPLOYEE_ID= ''345-67-8901''', salary) > 0 THEN salary := salary * 1.10; SQLUpdate('EMPLOYEE','EMPLOYEE_ID=' '345-67- 8901''',salary); END;
Dans l'exemple suivant, la société décide d'accorder une augmentation de 10 % à chaque employé. Voici comment mettre à jour la base de données en conséquence :
VARIABLES salary: REAL; cursor: SQLCursor; ACTIONS IF SQLSelect(cursor, 'SELECT SALARY FROM EMPLOYEE ') > 0 THEN WHILE SQLFetch(cursor,salary) > 0 DO salary := salary * 1.10; SQLUpdateCurrent(cursor,salary); END; SQLCloseCursor(cursor); END;
SQLUpdateCurrent est une version spéciale de SQLUpdate qui permet de mettre à jour la ligne la plus récemment extraite d'un curseur. Elle reçoit comme arguments la variable cursor et les nouvelles valeurs de mise à jour.
Enfin, SQLUpdate et SQLUpdateCurrent peuvent prendre comme argument un enregistrement, au lieu d'une série de variables de types simples. C'est ce qu'illustre l'exemple suivant :
VARIABLE r: EmployeeRecord; ACTIONS r.employee_ID: = '312-34-3444'; IF SQLSelectInto('SELECT * FROM EMPLOYEE WHERE EMPLOYEE_ID=''' & r.employee_ID & '''',r) > 0 THEN EditEmployee(r); SQLUpdate('EMPLOYEE', 'EMPLOYEE_ID=''' & r.employee_ID & '''',r); END;
Voici, sous forme résumée, les opérations effectuées par ce code :
Peut-être avez-vous remarqué, dans les exemples précédents, que les enregistrements n'ont pas été verrouillés, de même qu'aucune mesure n'a été prise pour empêcher plusieurs utilisateurs d'accéder simultanément aux mêmes enregistrements.
Dans le Developer's Toolkit, une fonction de contrôle passif gère les problèmes de concurrence d'accès souvent rencontrés dans les applications multi-utilisateurs. Voici en quoi elle consiste :
Le message d'erreur comporte un code d'erreur négatif. Dans certains cas, il peut être utile de tester ce code d'erreur et d'entreprendre différentes actions en fonction de sa valeur.
Par exemple, si une section de code dépend du succès d'une opération d'insertion, vous devez entourer ce code d'un test en vue de contrôler que le retour de l'instruction SQLInsert est positif.
Le Developer's Toolkit génère alors un message d'erreur à l'attention du second utilisateur (celui qui tente une nouvelle suppression).
Remarque : Pour que le contrôle passif des accès concurrents puisse s'exercer, l'instruction SQLUpdate doit recevoir un argument supplémentaire.
Soit l'exemple suivant :
VARIABLE r, oldR: EmployeeRecord; ACTIONS r.employee_ID: = '312-34-3444'; IF SQLSelectInto('SELECT * FROM EMPLOYEE WHERE EMPLOYEE_ID=''' & r.employee_ID & '''', r, oldR) > 0 THEN EditEmployee(r); SQLUpdate('EMPLOYEE', 'EMPLOYEE_ID=''' & r.employee_ID & '''',r,oldR); END;
Cet exemple se caractérise par les événements suivants :
Lorsque TSD Script aborde le traitement de l'instruction SQLUpdate, il détecte la variable enregistrement supplémentaire, oldR. Il procède alors comme suit :
Si des différences sont constatées, cela signifie que quelqu'un d'autre a modifié la ligne entre les deux lectures ; la mise à jour est alors annulée. SQLUpdate renvoie un code d'erreur négatif et un message d'erreur est présenté à l'utilisateur. En outre, la valeur en cours dans la ligne est placée dans oldR (de sorte qu'il n'est pas nécessaire à l'utilisateur d'extraire la version de l'enregistrement en cours).
Le contrôle passif des accès concurrents est un moyen simple et efficace d'éviter les conflits dans un environnement multi-utilisateur. Il exige un petit traitement supplémentaire, car la ligne à mettre à jour est récupérée une seconde fois, mais cela est largement compensé par le surcroît de protection obtenu.
Remarque : A moins d'être certain qu'il n'existe aucun risque de perte de mise à jour, utilisez toujours la forme de SQLUpdate avec contrôle passif des accès concurrents.
La plupart des moteurs SQL de base de données offrent la possibilité de grouper les opérations SQL en unités de travail. Vous pouvez dès lors utiliser des fonctions intégrées pour déterminer le succès ou l'échec de chaque unité de travail considérée dans sa globalité.
Dans un traitement normal, toutes les modifications sont validées dans la base de données dès qu'elles ont lieu. Dans un traitement transactionnel, les modifications des données sont gérées différemment.
L'instruction SQLBeginWork marque le début d'une unité de travail. Dès lors qu'il reçoit cette instruction, le moteur SQL de la base de données sait qu'il ne doit pas appeler l'instruction SQLCommit ou SQLRollback tant qu'il n'en reçoit pas l'ordre.
L'instruction SQLCommit indique que toutes les modifications apportées aux données depuis le dernier appel de SQLBeginWork doivent être appliquées à la base de données et rendues permanentes.
L'opération SQLRollback a lieu lorsque l'un des processus définis pour l'unité de travail a échoué. Elle indique que toutes les modifications apportées aux données depuis le dernier appel de SQLBeginWork doivent être annulées.
Par exemple, dans une application bancaire, un transfert peut être réalisé du compte épargne d'un client vers son compte courant. Une telle opération implique de réduire le montant de la colonne solde (balance) dans une table (SAVINGS_ACCOUNTS) et de l'augmenter d'autant dans une autre table (CHECKING_ACCOUNTS). Le succès de la première opération suivi de l'échec de la seconde poserait sans aucun doute un problème. Pour empêcher ce cas de figure, voici ce que ferait une application à traitement transactionnel :
Le fragment de code ci-après illustre les principes exposés précédemment. Il s'agit d'un enchaînement de plusieurs opérations SQL qui doivent toutes aboutir pour que les modifications soient validées dans la base de données. De toute évidence, il ne doit pas y avoir de validation après la première mise à jour, car en cas d'échec de la seconde mise à jour, le client se retrouverait avec un solde diminué sur son compte épargne, mais avec un solde inchangé sur son compte courant.
PROCEDURE SavingsToCheckingTransfer( VAL savings_ID: STRING, VAL checking_ID: STRING, VAL amount: REAL) IS VARIABLES debited, credited: BOOLEAN; balance: REAL; ACTIONS SQLBeginWork; debited := FALSE; IF SQLSelectInto('SELECT BALANCE FROM SAVINGS WHERE ACCOUNT_ID=''' & savings_ID & '''' ,balance) > 0 THEN balance := balance - amount; IF SQLUpdate('SAVINGS', 'ACCOUNT_ID=''' & savings_ID & '''', balance) > 0 THEN debited := TRUE; END; END; IF debited THEN credited := FALSE; IF SQLSelectInto('SELECT BALANCE FROM CHECKING WHERE ACCOUNT_ID=''' & checking_ID & '''',balance) > 0 THEN balance := balance + amount; IF SQLUpdate('CHECKING', 'ACCOUNT_ID=''' & checking_ID & '''' , balance) > 0 THEN credited := TRUE; END; END; IF credited THEN SQLCommit; ELSE SQLRollback; END; END; END;
Lorsque vous définissez une table de base de données, vous pouvez préciser si chaque colonne admet ou non les valeurs Null (ou valeurs indéfinies). Déclarer qu'une colonne peut contenir une valeur Null revient à dire qu'il n'est pas obligatoire qu'elle contienne une valeur (à ne pas confondre avec une chaîne vide).
Remarque : Le type SQL NULL trouve un équivalent parfait du côté TSD Script, car celui-ci admet les valeurs inconnues (unknown). Dans TSD Script, chaque variable est initialisée à la valeur $Unknown. Dans le cas d'une variable enregistrement, ce sont les champs qui sont initialisés à la valeur $Unknown.
Lorsque des valeurs sont échangées entre TSD Script et SQL, la correspondance entre $Unknown et NULL est préservée. Considérons l'exemple suivant :
SQLInsert('EMPLOYEE',r);
Dans cet exemple, si le champ r.salary est $Unknown, alors la colonne SALARY de la ligne insérée contiendra une valeur NULL.
Réciproquement, si la colonne PHONE contient NULL pour une ligne donnée et que cette ligne est récupérée dans une variable enregistrement (via une instruction SQLSelectInto ou une boucle SQLSelect/SQLFetch), le champ phone de cette variable contiendra la valeur $Unknown.
Dans le système de formulaires du Developer's Toolkit, les valeurs Null sont également prises en charge. Si un utilisateur laisse une zone de boîte de dialogue en blanc, le champ correspondant de l'enregistrement prendra la valeur $Unknown.
Remarque : Une erreur est signalée si vous tentez d'insérer une valeur $Unknown dans un champ qui correspond à une colonne n'ayant pas été déclarée comme acceptant les valeurs Null. Généralement, cela arrive uniquement lorsque des zones de formulaire sont laissées en blanc.
Dans les applications professionnelles, une partie non négligeable du code est consacrée à la gestion des erreurs. Une fois le code écrit, il faut le tester. Cela implique souvent d'évaluer le code retour de chaque instruction.
Le Developer's Toolkit comprend un mécanisme de gestion automatique des erreurs qui offre les avantages suivants :
Par défaut, le Developer's Toolkit détecte les opérations SQL qui échouent et présente des messages d'erreur à l'utilisateur.
Les messages affichés contiennent autant d'informations contextuelles que possible pour faciliter l'identification de l'erreur (colonne en double, erreur d'E-S, disque saturé, etc.). Si le succès ou l'échec d'une opération ne revêt aucune importance significative, il n'est pas nécessaire de contrôler la valeur de retour. Dans ce cas particulier, un nouvel employé est inséré dans la table EMPLOYEE :
SQLInsert('EMPLOYEE',r);
Vous pouvez avoir besoin de désactiver temporairement la fonction de génération automatique des messages d'erreur. $ErrorFilter est une fonction système, de type entier, qui permet de définir un seuil de niveau d'erreur. Les erreurs dont le niveau est en dessous du seuil spécifié ne donnent pas lieu à la génération de messages d'erreur.
Les niveaux de gravité suivants donnent lieu à la génération automatique de messages avec les codes d'erreur indiqués :
Code de gravité d'erreur | Description |
0 | Erreur fatale |
1 | Erreur non fatale |
2 | Message d'avertissement |
3 | Message d'information |
Par exemple, $ErrorFilter(3) signifie que seuls les erreurs et les avertissements ayant un code de gravité inférieur ou égal à 3 donneront lieu à la génération automatique de messages. Les erreurs ayant un code de gravité supérieur ne provoquent pas l'affichage de messages d'erreur ; elles sont détectables uniquement par l'examen des codes retour des instructions.
Les codes de gravité diminuent alors que la gravité augmente. Par conséquent, vous pouvez appeler ErrorFilter(0) pour désactiver la génération de tous les messages à l'exception des messages d'erreur fatale.
Si vous comptez exécuter une commande SQL plusieurs fois dans une boucle, il est souvent plus efficace de la préparer (la précompiler) une fois pour toutes en dehors de la boucle et de l'appeler sous sa forme préparée dans la boucle.
La boîte à outils du développeur permet de préparer la plupart des commandes SQL, à l'exception des instructions Select et des commandes qui ne peuvent pas être préparées dynamiquement. Pour connaître les commandes qui n'admettent pas la préparation dynamique, reportez-vous à votre documentation SQL.
La boîte à outils du développeur fournit deux commandes de préparation pour les commandes SQL :
Remarque : SQLPrepare et SQLExecute sont admises uniquement dans DB2/2, DB2/6000 et Oracle.
L'utilisation de SQLPrepare et SQLExecute équivaut à utiliser SQLExecuteImmediate, à ceci près que l'exécution est retardée jusqu'au moment où vous en avez besoin. Dans l'exemple suivant, on utilise la combinaison SQLPrepare/SQLExecute pour insérer une liste de nouveaux utilisateurs dans une table appelée USER :
FUNCTION InsertNewUsers(REF users: LIST OF STRING):INTEGER IS VARIABLES stmt: SQLStatement; retCd: INTEGER; ACTIONS (* insert the user names passed in *) retCd := SQLPrepare(stmt,'INSERT INTO USERS VALUES (?)'); IF retCd <= 0 THEN EXIT retCd; END;
(* perform the insertions *) FOR users DO retCd := SQLExecute(stmt,users[$current]); IF retCd <= 0 THEN SQLRollback; (* reverse changes and release locks *) EXIT retCd; END; END; (* for *)
(* release the resources used by this Prepared statement *) SQLCloseStatement(stmt); END;
Remarque : Etant donné que TSD Script dispose d'un nombre limité de ressources pour les instructions préparées et simultanées, veillez à fermer l'instruction préparée en appelant SQLCloseStatement.
La substitution de marqueurs de paramètre fait partie intégrante du processus d'utilisation d'instructions préparées. Marqueur de paramètre- Représenté par un point d'interrogation (?),il constitue un emplacement réservé qui sera remplacé ultérieurement par une valeur.
Pour chaque valeur, un point d'interrogation est inséré dans la chaîne de l'instruction (fournie à SQLPrepare). Les directives suivantes s'appliquent à ces valeurs :
Remarque : Avec les marqueurs de paramètre, TSD Script ne peut pas assurer des conversions de type aussi efficaces que pour les paramètres normaux (ceux utilisés dans les instructions SQLInsert, SQLUpdate, SQLSelectInto et SQLFetch).
Remarque : Ces instructions concernent uniquement Sybase et Microsoft SQLServer.
Certains SGBD n'admettent qu'une seule instruction SQL active à la fois sur une connexion particulière. Par exemple, l'insertion d'une instruction SQLSelectInto dans le corps d'une boucle SQLFetch exige deux instructions SQL simultanées avec SQLServer. Le Developer's Toolkit répond à ce besoin en clonant les connexions. Les connexions clonées, ou "secondaires", possèdent leur propre espace de transaction.
Le modèle transactionnel de Developer's Toolkit est tel que toutes les connexions se comportent comme si elles appartenaient à la même transaction. En pratique, cette méthode fonctionne correctement, même si elle n'est pas très orthodoxe (aucun protocole de validation en deux phases n'est utilisé). Dans les environnements où les curseurs ouverts et les instructions préparées sont normalement fermés dès la validation (commit) ou l'annulation (rollback), les validations automatiques implicites doivent être retardées jusqu'à ce que le curseur extérieur soit fermé.
Dans les premières versions du Developer's Toolkit, toutes les opérations SQL imbriquées ou simultanées étaient exécutées à l'intérieur d'une transaction. L'instruction SQLBeginWork était appelée avant l'ouverture du curseur le plus à l'extérieur, et une validation (ou une annulation) devait être opérée une fois que ce curseur était refermé.
Si vous souhaitiez voir les instructions s'exécuter dans leur propre espace de transaction, d'autres connexions primaires devaient être ouvertes pour chacune d'elles, à l'aide de SQLCommand.
Le Developer's Toolkit version 6.0 n'impose plus l'encapsulation des transactions pour l'exécution simultanée de plusieurs instructions, en mode de validation manuel ("manual"). Cependant, cette encapsulation reste nécessaire en mode de validation "auto", si le SGBD n'admet pas que les curseurs s'étendent sur plusieurs transactions.
En raison de la complexité inhérente aux instructions SQL imbriquées et des effets
secondaires qu'elles entraînent (tels que le supplément de temps système nécessaire
à l'établissement des connexions, le risque d'interblocage lors de l'accès à une même
table à partir de deux connexions dans des espaces de transaction différents, etc.),
il est vivement recommandé d'éviter leur emploi lorsqu'il existe une solution
de rechange.
Il est presque toujours possible de scinder les opérations SQL en deux parties :
Outre qu'elle élimine nombre des effets secondaires des instructions imbriquées, cette approche offre de meilleures possibilités d'accès simultanés, car vous n'êtes pas tenu d'exécuter les opérations à l'intérieur d'une transaction. Cependant, en fonction de l'application, il est possible que vous deviez faire appel à une transaction pour la seconde partie.
Tivoli Service Desk 6.0 Developer's Toolkit - Guide de programmation TSD Script