Tivoli Service Desk 6.0 Developer's Toolkit - Guide de programmation TSD Script

Chapitre 8 : Fonctions de gestion de base de données

Retour à la table des matières


Introduction

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.

Présentation de SQL

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.

Bases de données prises en charge

Les bases de données suivantes (que l'on appelle également sources) sont prises en charge par le Developer's Toolkit :

Support SQL dans 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.

Instructions SQL non prises en charge avec les pilotes directs

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.

Attributs et description des sources de données

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.

Définition d'une source de base de données

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.

Attributs de la source

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.

CASE_CONVERSION

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.

CASE_SENSITIVE

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.

COLUMN_DEFINITION_TABLE

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.

COMMIT_SELECTS

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

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.

Spécification du jour

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

Spécification du mois

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

Spécification de l'année

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

Séparateurs

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

DBMS

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 :

DEFAULT

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.

DRV

Il s'agit du nom du pilote du SGBD. Cette entrée est nécessaire à l'établissement de la connexion.

DSN

Cet attribut indique le nom de la source de données pour le fichier de configuration SQL (ODBC uniquement).

MANUAL_COMMITS

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.

MULTIPLE_CONNECT

Cette entrée reçoit la valeur TRUE si le SGBD admet plusieurs connexions simultanées.

MULTIPLE_CONNECT_REQUIRED

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.

QUAL

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.

SYSQUAL

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).

TABLE_DEFINITION_TABLE

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 :

Valeur par défaut du nom de la table

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)

TIME_FORMAT

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.


Format sur 24 heures

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

Formats horaires insensibles à la casse des caractères

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

Suppression des zéros non significatifs

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.

Spécification des 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

Séparateurs

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

UPPERCASE_FUNCTION

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 :

Connexion de votre application à une base de données

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.

Nom du fichier de configuration SQL

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).

Autres emplacements des instructions de configuration

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.

Exemple de configuration d'une base de données

Pour ajouter un client de base de données, suivez les étapes ci-après :

  1. Dans le groupe de programmes Developer's Toolkit, choisissez Editeur de configuration SQL.
    Résultat : La boîte de dialogue Editeur de configuration SQL s'affiche.

La boîte de dialogue Editeur de configuration SQL comporte les éléments suivants :

  1. Si ce n'est déjà fait, entrez l'emplacement (unité et chemin d'accès) et le nom du fichier sai_sql.cfg dans la zone Fichier (son emplacement par défaut est c:\sai\cfg\sai_sql.cfg), puis choisissez Ajouter.
    Résultat : Vous avez créé un fichier de configuration et ajouté la première source de données. La boîte de dialogue Sélection du pilote s'affiche.
  2. Sélectionnez l'option correspondant au pilote de base de données à utiliser, puis choisissez OK.
    Résultat : La boîte de dialogue Configuration de la source s'affiche.
  3. Entrez les informations relatives à votre client de base de données dans les zones appropriées, puis choisissez OK ou Avancé.

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.

  1. Choisissez Ajouter.
    Résultat : La boîte de dialogue Sélection de l'option apparaît.
  2. Sélectionnez l'option que vous souhaitez configurer, puis cliquez sur Sélection.
    Résultat : La boîte de dialogue Valeur de l'option s'affiche.
  3. Entrez l'attribut et la valeur de l'option que vous configurez. Si vous avez besoin d'informations complémentaires, choisissez Aide.
  4. Cliquez sur OK pour quitter l'Editeur de configuration SQL.

Test de la connexion du client à la base de donné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 :

  1. Dans le groupe de programmes Developer's Toolkit, choisissez Editeur de configuration SQL.
  2. Sélectionnez la source de données à tester, puis cliquez sur Tester la connexion. Si vous obtenez un message d'erreur en retour, contrôlez les paramètres entrés dans la boîte de dialogue Configuration de la source, ou bien testez la connectivité à la base de données.

Informations de connexion dans le fichier de configuration SQL

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).

Elimination du fichier de configuration SQL

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='); 

Exemple de base de données

Tables et vues de la base de données

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

Récupération de données avec SQLSelectInto

SQLSelectInto

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.

Premier argument

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 

Arguments suivants

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.

Utilisation d'une variable enregistrement

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);


Types enregistrements

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); 

Utilisation des instructions d'importation TSD Script

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; 

Instructions d'importation

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.

Chaîne de connexion

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).

Analyse avec l'option /S

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).

Utilisation de mots clés

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.

Exemples d'instructions IMPORT

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);

Exemple de syntaxe incorrecte

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 !*)

Types de données

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.


Récupération de lignes multiples

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.

Processus

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.

Exemple

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.

Qualifiants

Utilisation de qualifiants

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.

Substitution de qualification

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 :

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'); 

Apostrophes

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';

Concaténation de chaînes comportant des apostrophes

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.

Exceptions

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);

Formatage des données avec l'instruction SQLFormat

Utilisation de SQLFormat

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 :

Exemple

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.

Abstraction des noms

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

Récupération de données indépendamment des noms de colonne

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.

Mise à jour de données

Introduction

Cette section décrit comment insérer, supprimer et modifier des données dans une base de données SQL.

Insertion de données

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); 

Suppression de données

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''');

Modification de données

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 :

Contrôle passif des accès concurrents

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.

Traitement transactionnel

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.

Description

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 :

Exemple

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; 

Valeurs inconnues dans les colonnes SQL

Utilisation de valeurs Null

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.

Mappage de valeurs inconnues

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.

Gestion des erreurs

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 :

Détection des messages d'erreur

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);

Filtrage des messages d'erreur

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.

Utilisation de commandes d'exécution multiple

Préparation de commandes SQL à exécuter en boucle

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.

Marqueurs de paramètre

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).

Instructions SQL imbriquées

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

Retour à la table des matières

Copyright