À titre d'exemple, la figure 4.27 présente les deux objets **Driver-update** construits dans la précédente section (§4.2.2.2) pour reporter dans la base les modifications effectuée en mémoire sur l'objet **james**.

<table><thead><tr><th colspan="2">Objet de classe Driver-update</th></tr></thead><tbody><tr><td>table</td><td>(emp)</td></tr><tr><td>null-attributes</td><td>()</td></tr><tr><td>attributes</td><td>(emp.responsible_for emp.empno)</td></tr><tr><td>values</td><td>(emp/7936 7655)</td></tr><tr><td>where</td><td>(emp.empno = 7655)</td></tr></tbody></table>

<table><caption>Figure 4.27 : Objets Driver-update de mise-à-jour de l'objet **james**</caption><thead><tr><th colspan="2">Objet de classe Driver-update</th></tr></thead><tbody><tr><td>table</td><td>(person)</td></tr><tr><td>null-attributes</td><td>()</td></tr><tr><td>attributes</td><td>(person PHONE person.CAR)</td></tr><tr><td>values</td><td>(40-445843 3005)</td></tr><tr><td>where</td><td>(Subselect[J[emp→person], emp.empno = 7655])</td></tr></tbody></table>

Les deux requêtes correspondant à ces objets sont :

* update emp
  set responsible_for = 'emp/7936', empno = 7655
  where empno = 7655;

* update person
  set phone = '40-445843', car = 3005
  where exists(select * from emp
                where emp.empno = 7655 and
                      (emp.ename = person.pname and emp.fname = person.fname));

### 4.2.3 Insertion d'objets dans la base

De façon générale, l'algorithme `write-object` (figure 4.31) permet d'insérer dans la base un objet qui n'est pas encore persistant. Mais du fait du critère qui sélectionne son appel, à savoir l'existence dans la base d'un n-uplet pour l'objet et la classe considérés (cf. figure 4.19), il est également sollicité :

* pour insérer des parties d'objet déjà persistant qui ne figurent pas encore dans la base. Ce cas de figure se produit quand un objet a été inséré alors qu'il était instance
d'une classe donnée et qu'il est validé à nouveau en étant instance d'une classe plus précise pour laquelle des correspondances ont été définies dans une table secondaire non utilisée dans la correspondance des classes ancêtres.

* quand l'objet ne vérifie pas encore dans la base les contraintes imposées par la classe considérée. L'application de *write-object* peut alors dans ce cas n'engendrer que des mises-à-jour de n-uplets existants.

Par souci de simplification, nous allons dans un premier temps ne considérer que le cas général d'utilisation de *write-object*, à savoir l'insertion d'un nouvel objet dans la base. Nous n'examinerons la résolution des autres cas de figure qu'ultérieurement.

### 4.2.3.1 Difficultés posées par l'insertion d'objet

Un objet persistant a pour correspondance relationnelle un ensemble de n-uplets répartis dans les tables élémentaires de sa classe. Plus exactement, sa correspondance est un unique n-uplet virtuel résultant de l'assemblage des dits n-uplets. Leur rapprochement, leur mise "bord à bord" en quelque sorte, résulte des jointures élémentaires définies entre les tables de la classe.

L'insertion d'un nouvel objet dans la base ne se réduit donc pas seulement à un problème d'insertion de n-uplets qui contiendraient les valeurs des champs. L'opération doit également faire en sorte que les jointures qui permettent d'accéder aux différentes parties de l'objet dans la base n'échouent pas lors des relectures ultérieures.

L'insertion d'un objet dans la base nécessite donc la résolution d'un système de contraintes où les variables sont les attributs des tables élémentaires de la classe considérée et où les équations sont les définitions des jointures et des contraintes de classe exprimées sous forme de contraintes sur attributs.

Afin de garantir l'accès ultérieur depuis l'environnement à tout objet relationnel auquel il offre la persistance, *DRIVER* affecte, au cours de la résolution, une valeur à chacun des attributs participant au système de contraintes. Grâce à ces valuations, tout échec de jointure ou de restriction est rendu impossible lors d'une future relecture.

Par définition, un attribut est dit *fondamental* s'il doit être nécessairement valué dans tout objet relationnel de la classe considérée.

Les attributs de tables élémentaires qui participent au système de contraintes sont donc fondamentaux. On peut faire la remarque qu'un attribut doit nécessairement appartenir à une table élémentaire de la classe pour être fondamental pour cette classe. Il existe en effet des attributs qui participent au système de contraintes et qui ne sont pas fondamentaux. Ce sont tous ceux qui n'appartiennent pas à l'une des tables élémentaires de la classe. Ces attributs proviennent de jointures sur des tables "externes" sur lesquelles ont été définis des champs de type *read-only*, accessibles en lecture seulement. Ces attributs ne sont pas considérés pendant la résolution.

Enfin, les relations élémentaires d'une classe comportent d'autres attributs fondamentaux que ceux qui sont impliqués dans le système de contraintes. Ce sont tous ceux qui
font partie de la clé de l'une d'entre elles.

Pour résumer, l'opération d'insertion d'un objet dans la base implique, avant insertion des n-uplets, de valuer l'ensemble des attributs fondamentaux de sa classe. Leurs valeurs sont contraintes par les équations issues des jointures et des restrictions.

À titre d'exemple, l'insertion d'un objet de la classe Employé donne lieu à la résolution, pour cet objet, du système suivant :

$$
\begin{array}{l}
\texttt{emp.sal} \geq 700. \\
\texttt{emp.sal} \leq 9999. \\
\texttt{emp.ename} = \texttt{person.pname} \\
\texttt{emp.fname} = \texttt{person.fname} \\
\texttt{emp.sal} \geq \texttt{salgrade.losal} \\
\texttt{emp.sal} \leq \texttt{salgrade.hisal}
\end{array}
$$

Les deux dernières équations sont issues d'une jointure sur la table salgrade, table qui n'est pas élémentaire pour la classe Employé. Cette jointure participe à la correspondance d'un champ atomique read-only. Dans ces deux équations, emp.sal est fondamental car issu d'une table élémentaire de Employé. Par contre, salgrade.losal et salgrade.hisal ne le sont pas et ne seront donc pas valués lors de la résolution.

Les clés de emp et person étant respectivement { emp.empno } et { person.pname, person.fname }, l'ensemble des attributs fondamentaux de la classe Employé est finalement :

{ emp.empno, emp.sal, emp.ename, emp.fname, person.pname, person.fname }.

4.2.3.2 Les classes système de gestion d'écriture

L'ensemble des attributs fondamentaux et le système de contraintes à résoudre pour l'insertion d'objets sont uniques et invariants pour une classe donnée. Dans le même temps, leur résolution est spécifique pour chaque objet.

DRIVER définit deux classes, Driver-class-saving et Driver-saving, pour gérer ces informations et leurs résolutions (listing 22).

<caption>Listing 22. Les classes système de gestion d'écriture d'objets</caption>

(driver-defclass Driver-class-saving ()
(cc-operators objectset Driver-sql-op)
(cc-joins objectset Driver-join)
(operators objectset Driver-sql-op)
 attributes objectset Driver-attribute)
(attr-ops dictionary ((object Driver-attribute) (objectset Driver-sql-op)))
<table><thead><tr><th colspan="3">(joins objectset Driver-join))</th></tr></thead><tbody><tr><td colspan="3">(driver-defclass Driver-saving Driver-class-saving</td></tr><tr><td>(object</td><td>object</td><td>)</td></tr><tr><td>(initial-key</td><td>atom</td><td>symbol)</td></tr><tr><td>(new-key</td><td>atom</td><td>symbol)</td></tr><tr><td>(object-class</td><td>object</td><td>Driver-class)</td></tr><tr><td>(status</td><td>atomset</td><td>symbol)</td></tr><tr><td>(unsolved-attrs</td><td>objectset</td><td>Driver-attribute)</td></tr><tr><td>(initial-pairs</td><td>dictionary</td><td>((object Driver-attribute) (atom ()))</td></tr><tr><td>(user-pairs</td><td>dictionary</td><td>((object Driver-attribute) (atom ()))</td></tr><tr><td>(prev-pairs</td><td>dictionary</td><td>((object Driver-attribute) (atom ()))</td></tr><tr><td>(pairs</td><td>dictionary</td><td>((object Driver-attribute) (atom ()))</td></tr><tr><td>(prev-transitions</td><td>ordobjset</td><td>Driver-transition)</td></tr><tr><td>(transitions</td><td>ordobjset</td><td>Driver-transition))</td></tr></tbody></table>

La première regroupe toutes les informations sur le système de contraintes et l'ensemble des attributs fondamentaux d'une classe donnée. Un objet **Driver-class-saving** propre à une classe est construit au besoin et stocké dans l'objet **Driver-class** correspondant où il est disponible dès qu'il a été construit (cf. §3.3.2.3).

La classe **Driver-class-saving** est structurée de la façon suivante :

* **cc-operators** contient l'ensemble des équations issues des contraintes de la classe, et **cc-joins**, les jointures permettant d'atteindre les attributs participant à ces équations.

* **operators** contient l'ensemble des équations issues des jointures élémentaires de la classe.

* **attributes** référencent l'ensemble des attributs **fondamentaux** de la classe, exceptés ceux issus des contraintes de classe. En effet, ces derniers ont déjà été résolus par l'appel **check-class-constraints-on-objects** (cf. figure 4.19) au moment où **write-object** est appelé. Leur présence ici ne présente donc pas d'intérêt.

Chaque attribut contenu dans **attributes** participe éventuellement à des équations. **attr-ops** contient un dictionnaire qui permet d'accéder rapidement, à partir d'un attribut, à l'ensemble des équations auxquelles il participe. Ce dictionnaire est utilisé pour accélérer les propagations de valeur lors de la résolution du système de contraintes.

* **Enfin, joins** référence l'ensemble des jointures participant au système de contraintes.

À titre d'exemple, la figure 4.28 présente les objets **Driver-class-saving** des classes **Employé** et **Vendeur**.
<table><thead><tr><th colspan="2">Objet de classe Driver-class-saving</th></tr></thead><tbody><tr><td>cc-operators</td><td>([emp.sal &gt;= 700.] [emp.sal &lt;= 9999.])</td></tr><tr><td>cc-joins</td><td>()</td></tr><tr><td>operators</td><td>([emp.ename = person.pname] [emp.fname = person.fname])</td></tr><tr><td>attributes</td><td>(emp.empno person.pname person.fname emp.ename emp.fname)</td></tr><tr><td>attr-ops</td><td>(...)</td></tr><tr><td>joins</td><td>(J emp→person])</td></tr></tbody></table>

<table><caption>Figure 4.28 : Objets Driver-class-saving des classes Employé et Vendeur</caption><thead><tr><th colspan="2">Objet de classe Driver-class-saving</th></tr></thead><tbody><tr><td>cc-operators</td><td>([emp.job = 'salesman'] [emp.sal &gt;= 700.] [emp.sal &lt;= 9999.])</td></tr><tr><td>cc-joins</td><td>()</td></tr><tr><td>operators</td><td>([emp.ename = person.pname] [emp.fname = person.fname])</td></tr><tr><td>attributes</td><td>(emp.empno person.pname person.fname emp.ename emp.fname)</td></tr><tr><td>attr-ops</td><td>(...)</td></tr><tr><td>joins</td><td>(J emp→person])</td></tr></tbody></table>

La classe Driver-saving a pour sa part été définie comme support d'aide à l'insertion d'objet dans la base. Sa structure est adaptée au calcul des attributs fondamentaux et autres, et à la construction des requêtes d'insertion et/ou de mise-à-jour qui s'en suit.

Un objet Driver-saving est défini pour chaque objet à écrire dans la base. Construits de façon opportuniste, ils sont, après construction, accessibles par l'intermédiaire du dictionnaire saving-buffer qui est initialisé en début de validation de transaction (cf. §4.2.1.3).

Définie comme sous-classe de Driver-class-saving, Driver-saving hérite de ses champs. Les équations et les attributs fondamentaux de la classe considérée sont ainsi directement disponibles dans ses instances. On notera cependant que les champs cc-operators et cc-joins contiennent toujours les informations correspondant à la classe précise de l'objet à écrire. De cette façon, dès la première résolution, on peut faire en sorte que l'objet vérifie ses contraintes qui subsument celles des classes ancêtres et qui sont les plus restrictives.

Elle ajoute un certain nombre d'autres champs, plus particulièrement destinés, pour leur part, à recueillir les données spécifiques à l'objet à insérer associé (listing 22) :

* Le champ object référence cet objet à insérer associé.

* Quand l'objet en question est déjà persistant au moment de la création de son Driver-saving, sa clé relationnelle est reportée dans le champ initial-key.

Dans le cas contraire, une clé relationnelle lui est affectée à un certain moment de la résolution. Elle est alors reportée dans le champ new-key de son Driver-saving. Une clé nouvellement attribuée n'est pas directement enregistrée dans les dictionnaires de DRIVER. Ainsi, en cas d'erreur, le simple abandon des objets Driver-saving annule simplement les attributions de clé qui ont pu être faites au cours de la validation. Si
cette validation se termine normalement, `DRIVER` procède alors à l'enregistrement définitif des clés attribuées.

* Le champ `object-class` recueille la classe précise de l'objet à insérer.

* Le champ `status` contient un ensemble de symboles renseignant sur les états courants du système. Ces symboles permettent d'orienter la résolution de l'objet en cours d'écriture. Les différents états possibles existant dans la version actuelle de `DRIVER` sont `adding-initial-pairs`, `initial-pairs`, `no-initial-pairs` et `user-pairs`. Nous reviendrons ultérieurement sur le rôle joué par chacun d'entre eux (cf. §4.2.3.4).

* Le champ `unsolved-attrs` contient l'ensemble des attributs à valuer nécessairement pour lesquels aucune valeur n'a encore été arrêtée. Au début de la résolution, `unsolved-attrs` contient donc les mêmes objets que le champ `attributes`. Puis, progressivement, il se vide. La résolution se poursuit tant que ce champ référence des attributs.

* Avant de déclencher la résolution d'un objet, il est parfois nécessaire de fixer la valeur de certains attributs. Ce cas se produit quand le champ objet d'un objet déjà persistant référence un objet non persistant et que la correspondance de ce champ objet est une jointure objet restreinte. Dans ce cas, avant l'appel de `write-object` pour l'objet contenu, on précise les valeurs des attributs de sa clé qui vont permettre son référencage dans le champ objet précédent. Les paires attribut-valeur sont placées dans le champ `initial-pairs` de son objet `Driver-saving` lors du traitement du champ objet.

* Pendant la résolution d'un objet, l'utilisateur peut être sollicité pour donner une valeur à des attributs participant à sa correspondance. Les paires attribut-valeur correspondantes sont placées dans le champ `user-pairs` de son objet `Driver-saving`.

* Au cours de la résolution d'un objet, des valeurs sont affectées aux différents attributs qui participent à sa correspondance. Les paires attribut-valeur sont systématiquement ajoutées au contenu du champ `pairs`. Comme nous l'avons vu, si la valuation de l'attribut est faite par l'utilisateur ou précède la résolution effective de l'objet, la paire est également ajoutée, selon les cas, aux contenus des champs `initial-pairs` ou `user-pairs`. Quand une paire est ajoutée au contenu de `pairs`, l'attribut correspondant est retiré de `unsolved-attrs`.

* Si, au cours de la validation de transaction, un objet doit être modifié, l'ancienne valeur du champ concerné est conservée de façon à pouvoir défaire la modification, par exemple en cas d'erreur ou d'incohérence. Les modifications successives effectuées sur un objet sont stockées dans le champ `transitions` de son `Driver-saving` sous forme d'objets transitions. Une transition est en `DRIVER` un objet de la classe `Driver-transition`, défini par un triplet `T[objet, champ, ancienne valeur]` (cf. §4.2.5).

* Pour un objet donné, `write-object` peut être appelé plusieurs fois avec des classes différentes. Au début de chaque nouvel appel, les paires attribut-valeur déterminées
pour la classe précédente sont ajoutées au champ **prev-pairs** tandis que **pairs** est réinitialisé. De la même façon, les transitions effectuées pour la classe précédente sont ajoutées au champ **prev-transitions**, puis **transitions** est réinitialisé.

L'intérêt de séparer transitions et paires attribut-valeur de l'application courante de **write-object** et leurs homologues des appels précédents sera mis en évidence en §4.2.3.4.

La figure 4.29 présente l'objet **Driver-saving** de l'employé **johnson**. Il a précisément cette valeur au début de l'appel de **write-object** pour **johnson** et la classe **Employé**, immédiatement après son initialisation pour cette classe.

<figure><img src="image_26.png" /><figcaption>Figure 4.29 : Objet Driver-saving initial de johnson pour la classe Employé</figcaption></figure>

### 4.2.3.3 Principe de résolution

Résoudre un objet consiste donc à calculer les attributs référencés dans le champ **unsolved-attrs** de son **Driver-saving** en respectant les équations contenues dans le champ **operators** du même objet.

Dans cette optique, les champs de l'objet propres à la classe considérée sont tour à tour interrogés et leurs valeurs permettent de déduire de nouvelles paires [attribut, valeur].
Chaque paire est traitée de la même façon. `DRIVER` vérifie dans un premier temps qu'elle est compatible avec les équations partiellement instanciées et qu'aucune autre valeur n'a déjà été affectée à l'attribut considéré. S'il y a incohérence, l'exécution se poursuit par un appel à *inconsistency-management*, sur lequel nous allons revenir. Dans le cas contraire, la paire est ajoutée au contenu du champ **pairs** et l'ensemble des expressions faisant intervenir l'attribut en question est déterminé à l'aide du dictionnaire **attr-ops**.

Si l'attribut participe à des expressions, on essaie ensuite de propager sa nouvelle valeur dans ces expressions de façon à déduire autant de nouvelles paires que possible. Pour chacune d'entre elles, un appel récursif à la routine d'ajout de nouvelle paire est effectué.

Parfois, l'interrogation des champs n'est pas suffisante pour valuer l'ensemble des attributs fondamentaux de la classe. Dans ce cas, selon leurs types et la valeur de l'indicateur système `driver-fix-key-generation-p`, des valeurs générées leur sont automatiquement allouées ou l'utilisateur est sollicité pour leur en fournir.

### 4.2.3.4 Gestion des incohérences

En cas d'incohérence, *inconsistency-management* est appelé. Son algorithme est présenté figure 4.30. Son rôle est de rattraper l'erreur si c'est possible et si l'indicateur `DRI-VER driver-writing-help` vaut $T$, ou de déclencher une erreur fatale dans le cas contraire.

Rattraper l'erreur consiste à annuler la résolution en cours et à la recommencer.

`undo-current-transitions` réinitialise l'objet `Driver-saving` en défaisant les éventuelles modifications faites sur les objets pendant cette résolution, en replaçant dans l'ensemble des attributs à résoudre l'ensemble des attributs fondamentaux de la classe et en remettant à {} l'ensemble des paires déterminées. On remarque au passage l'intérêt de séparer les paires et les transitions obtenues et effectuées au cours de la présente résolution de celles résultant des précédents appels de `write-object`. En cas d'incohérence, seules celles de la résolution courante sont défaites. Les autres restent accessibles dans les champs `prev-...` de l'objet `Driver-saving`.

Enfin, relancer la résolution est obtenu en déclenchant une sortie de `write-object1` qui retourne {}. Cette valeur engendre un nouvel appel de `write-object1`.

Le contenu du champ `status` de l'objet `Driver-saving` renseigne sur le déroulement de la résolution et oriente le traitement de l'incohérence s'il en apparaît une. Dans la version actuelle de `DRIVER`, `status` est susceptible de contenir quatre symboles différents :

* **adding-initial-pairs.** Au début de la résolution, il est possible d'introduire dans le système des paires imposées par la résolution d'un autre objet. De telles paires existent quand l'objet en cours d'écriture n'est pas encore persistant, qu'il est référencé dans un champ à objet et que la correspondance de ce champ objet est une jointure objet restreinte voire fixée. L'écriture en cours a été déclenchée récursivement, lors du traitement du champ objet d'un autre objet. Le lien existant entre des attributs de clé des deux objets est exprimé par ces paires.
algorithme inconsistency-management(Saving)
soit Fatal_error ← ⊥
et Message1 ← "Inconsistency in writing constraints"
et Message2 ← "";
selon
cas status.Saving = {}
faire Fatal_error ← T;
cas adding-initial-pairs ∈ status.Saving
faire Fatal_error ← T
et Message1 ← "Incompatible key and class constraints";
cas status.Saving = {initial-pairs}
si driver-writing-help = ⊥
alors faire Fatal_error ← T;
sinon faire Message2 ← "Key constraints forsaken"
et status.Saving ← {no-initial-pairs};
cas user-pairs ∈ status.Saving
si driver-writing-help = ⊥
alors faire Fatal_error ← T;
sinon faire Message2 ← "User inputs forsaken"
et status.Saving ← status.Saving \ {user-pairs};
cas sinon
faire Fatal_error ← T;
si Fatal_error = T
alors faire fatal-error(message1);
sinon faire driver-warning(message1)
et driver-warning(message2)
et undo-saving-resolution(Saving)
et sortir de write-object1() en retournant {};
fin

algorithme undo-saving-resolution(Saving)
faire undo-current-transitions(Saving)
et unsolved-attrs.Saving ← attributes.Saving
et user-pairs.Saving ← {}
et pairs.Saving ← {};
fin

<caption>Figure 4.30 : Gestion d'incohérence dans la résolution d'écriture d'objet</caption>
Avant d'introduire la première d'entre elles, le statut **adding-initial-pairs** est ajouté au champ **status** de l'objet **Driver-saving**, et en est retiré après introduction de la dernière. Ce symbole identifie donc précisément la phase d'insertion des contraintes d'attributs pendant la résolution.

S'il y a incohérence, les paires qui sont indiquées sont incompatibles avec les contraintes de la classe traitée, c'est-à-dire avec celles de la classe principale de l'objet. Cela signifie que l'objet propriétaire du champ référençant l'objet ne peut contenir aucun objet instance de la classe principale considérée. Ce champ ayant été déclaré pour référencer des objets de cette classe, l'incohérence est grave et peut provenir d'une mauvaise définition du schéma de correspondances. Elle déclenche invariablement une erreur fatale.

* **initial-pairs**. Cet indicateur est ajouté au champ **status** de l'objet **Driver-saving** aussitôt après l'introduction de paires initiales, si l'opération s'est bien passée. Sa présence dans le statut indique donc que l'ensemble des paires résolues comprend des paires initiales.

Si, par la suite, une incohérence est détectée, dans le cas où le statut du système vaut précisément `{initial-pairs}` et si `driver-writing-help` vaut $\top$, **inconsistency-management** tente de rattraper l'erreur et de recommencer la résolution en ne tenant plus compte des paires initiales.

L'apparition d'une incohérence alors que le statut ne comprend que l'indicateur **initial-pairs** signifie que l'objet en cours d'écriture n'est pas une valeur autorisée pour le champ objet dans lequel il est référencé et qui est à l'origine des paires initiales stipulées. Rattraper l'erreur veut donc dire qu'on choisit d'écrire l'objet dans la base indépendamment de son référençage dans le champ objet. Une fois l'écriture terminée, l'exécution va revenir au traitement de l'écriture du champ objet incriminé, lequel va détecter l'incompatibilité entre les contraintes du champ et l'objet contenu. L'erreur a donc été déplacée à cet endroit-là. L'utilisateur est prévenu de cette incompatibilité et il lui est demandé de choisir une nouvelle valeur pour le champ objet parmi celles que le système lui propose. Les objets proposés sont tous les objets de la couche virtuelle qui vérifient les contraintes du champ.

Si le statut comporte d'autres indicateurs que **initial-pairs**, une erreur fatale est gênérée.

* **no-initial-pairs**. Lors de la tentative de rattrapage d'erreur précédente, **inconsistency-management** demande la non-insertion de ces paires initiales lors de la nouvelle résolution en réinitialisant le statut à `{no-initial-pairs}`.

La présence de cet indicateur dans le statut signale donc qu'une tentative de rattrapage d'incohérence est en cours.

* **user-pairs**. Au cours de la résolution, il peut arriver, quand l'indicateur **DRIVER** `driver-writing-help` vaut $\top$, que l'utilisateur soit mis à contribution pour préciser une valeur de champ ou d'attribut qui se révèle nécessaire pour résoudre le système. Si
cela se produit, l'indicateur **user-pairs** est ajouté au champ **status** de l'objet **Driver-saving**. Sa présence dans le statut indique donc que l'ensemble des paires résolues comprend des paires directement indiquées par l'utilisateur.

Si une incohérence est détectée alors que cet indicateur est présent dans le statut, toujours dans le cas où **driver-writing-help** vaut $\top$, **inconsistency-management** tente de rattraper l'erreur.

En effet, comme l'utilisateur est intervenu dans la résolution, on peut supposer que l'incohérence provient d'une erreur de manipulation de sa part. Si c'est le cas, quand il est sollicité à nouveau, il lui suffit de rectifier sa réponse pour que la validation se poursuive correctement. S'il n'a pas fait d'erreur, le problème est alors ailleurs. Il peut alors interrompre et annuler la validation en cours au moment où il est interrogé en cliquant sur le bouton "Annulation transaction" prévu à cet effet.

### 4.2.3.5 Détails de l'algorithme

Le début de l'algorithme **write-object** (figure 4.31) est consacré à la recherche du **Driver-saving** de l'objet en cours d'écriture et à son initialisation pour la classe considérée en vue de la résolution.

Cette résolution à proprement parler est effectuée par **write-object1**. Quand elle se termine normalement, **write-object1** retourne la clé de l'objet écrit et l'écriture de l'objet pour la classe considérée est terminée. Quand une incohérence est détectée et jugée rattrapable par **inconsistency-management** (cf. §4.2.3.4), cette même procédure provoque la sortie de **write-object1** en retournant la valeur `{}`. Ceci a pour effet de re-déclencher un nouvel appel de **write-object1** pour une nouvelle tentative de résolution.

**write-object1** débute par l'appel de **add-key-pairs** qui assure l'introduction dans le système des paires déduites de la clé de l'objet. Bien sûr, ceci n'a de sens que quand l'objet à écrire est déjà persistant au moment où **write-object1** (et **write-object**) est exécuté. Comme nous l'avons vu, ce cas de figure correspond à l'écriture d'un objet dont la classe dans l'environnement est plus précise que celle qu'il a dans la base. L'écriture en cours est alors effectuée pour l'une de ces classes dont l'objet est instance et qui sont plus précises que celle de l'objet dans la base.

Les paires initiales sont ensuite introduites dans le système à condition que l'indicateur **no-initial-pairs** ne figure pas dans le statut de l'objet **Driver-saving**.

**build-saving** gère l'interrogation des champs de l'objet.

Les paires fournies par les champs à objet sont déduites des clés des objets référencés. Quand ces objets référencés ne sont pas encore persistants, leurs clés ne sont pas déterminées et aucune paire ne peut être immédiatement déduite. Il n'est pas non plus possible de déclencher récursivement leur écriture avant d'avoir défini et enregistré la clé de l'objet en cours de résolution. En effet, en cas de cycle dans le réseau d'objets, l'algorithme bouclerait. Selon l'état d'avancement de la résolution, les champs à objet peuvent donc ne pas pouvoir immédiatement fournir de nouvelles paires [attribut, valeur] au moment
algorithme write-object(Class, Object)
soit Saving ← do-get-object-saving(Object)
et Key ← {};
faire init-object-saving(Saving, Object, Class);
répéter
faire Key ← write-object1(Saving, Class) jusqu'à ∃ Key;
retourner Key;
fin

algorithme write-object1(Saving, Class)
faire add-key-pairs(Saving);
si no-initial-pairs /∈ status.Saving
alors faire add-initial-pairs(Saving);
faire build-saving(Saving, Class);
soit Writings ← build-writings(Saving, Class);
faire do-writings-if-any(Writings)
et initial-key.Saving ← object-key-while-saving(object.Saving);
retourner initial-key.Saving;
fin

algorithme build-saving(Saving, Class)
soit Fields ← fields(CLass
et Passnum ← 1;
tant que Fields ≠ {}
faire Fields ← ask-fields-for-saving(Fields, Saving, Passnum);
si Passnum = 2
ou (Passnum = 1 et Fields = {}
alors faire make-up-saving(Saving);
faire Passnum ← Passnum + 1;
fin

<caption>Figure 4.31 : Algorithme d'insertion d'un objet dans la base</caption>
algorithme ask-fields-for-saving(*Fields*, *Saving*, *Passnum*)

soit *Unsolved_fields* ← {};

pour tout F ∈ *Fields*

faire si mappedp.F = ⊤

et read-only.F = ⊥

alors soit UF ← info-for-writing(*Saving*, *Passnum*).F;

faire *Unsolved_fields* ← *Unsolved_fields* ∪ *UF*;

retourner *Unsolved_fields*;

fin

algorithme make-up-saving(*Saving*)

soit *Unsolved_attrs* ← {};

pour tout *Attr* ∈ *unsolved-attrs.Saving*

si attribute-pair(*Attr*) ∉ *prev-pairs.Saving*

faire *Unsolved_attrs* ← ∪ {*Attr*};

faire solve-attributes(*Unsolved_attrs*, *Saving*);

si ∉ initial-key.Saving

alors faire solve-object-key(*Saving*);

<caption>Figure 4.32 : Algorithme d’insertion d’un objet dans la base (suite)</caption>

où ils sont interrogés. Il est parfois nécessaire de les reconsulter après que la clé de l'objet en cours d'écriture ait été déterminée.

La consultation des champs se fait en plusieurs passes. Pour chacun d'entre eux, la méthode *info-for-writing* correspondant à leur type est invoquée. Quand un champ peut fournir, pour la résolution, toutes les paires [attribut, valeur] dont il est capable et qu'il n'est pas nécessaire de le consulter une seconde fois, sa méthode renvoie {}. Par contre, s'il lui manque des informations pour répondre et qu'il doit être ultérieurement ré-interrogé, elle retourne l'objet *Driver-field* qui lui correspond.

À la première passe, les champs atomiques sont les seuls à fournir des paires [attribut, valeur] pour la résolution. À la seconde, les champs à objet sont interrogés mais seuls ceux qui référencent des objets déjà persistants sont en mesure de déduire de nouvelles paires.

Après la seconde, les attributs fondamentaux non encore résolus sont valués par l'appel à *make-up-saving*, soit de façon automatique, soit en sollicitant l'utilisateur. *make-up-saving* vérifie aussi que les attributs fondamentaux participant à une clé de relation se voient affecter des valeurs cohérentes avec les valeurs de clé déjà attribuées dans la base. Cette vérification est effectuée en interrogeant le SGBD par requête SQL. En cas d'incohérence, *inconsistency-management* est appelé. Dans le cas où l'objet en cours d'écriture n'est pas
encore persistant, **make-up-saving** se termine en faisant appel à **solve-object-key**. Cette procédure prend en compte la nouvelle clé de l'objet dans les dictionnaires de **DRIVER**. Cet enregistrement peut déjà avoir eu lieu s'il a fallu déclencher récursivement l'écriture d'un autre objet référencé non encore persistant.

Avant la troisième passe, les attributs constituant la clé de la relation principale de la classe de l'objet ont donc nécessairement reçu une valeur. La clé de l'objet est déterminée et les champs à objet référençant des objets non encore persistants vont pouvoir déclencher l'écriture récursive de leur contenu sans risquer de boucler à cause de cycles dans le réseau d'objets. Suite à ces écritures, les dernières paires [attribut, valeur] de l'objet sont déterminées et la fonction **ask-fields-for-saving** retourne {} : la résolution de l'objet est terminée.

**build-writings** construit ensuite les objets **Driver-update** et les objets **Driver-insert** nécessaires pour écrire l'objet dans la base. **do-writings-if-any** adresse ensuite les requêtes correspondantes au SGBD après les avoir générées.

La clé de l'objet est ensuite reportée dans le champ **initial-key** de l'objet **Driver-saving** où elle sera disponible pour un éventuel nouvel appel de **write-object** pour le même objet mais avec une classe différente.

### 4.2.3.6 Méthodes d'insertion des différentes classes de champ

Les méthodes **info-for-writing** des différents types de champs sont présentées figure 4.33. Seules manquent les méthodes des champs de types "ensemble" qui seront présentées ultérieurement (cf. §4.2.4).

La méthode **Atom-field::info-for-writing** des champs atomiques déduit la valeur de l'attribut associé au champ de la valeur du champ lui-même. Elle introduit ensuite la paire [attribut, valeur] ainsi formée dans le système de résolution. Cette paire est toujours calculable, quelle que soit la valeur du champ; aussi, la méthode retourne-t'elle toujours {}.

La méthode **Object2-field::info-for-writing** des champs objet de classe inconnue ne consulte la valeur du champ qu'à la seconde passe. Si le champ référence un objet déjà persistant, la clé de cet objet est retrouvée par la fonction **object-key-while-saving** et la paire [attribut associé au champ, Clé de l'objet référencé] est introduite dans le système.

Si l'objet n'est pas persistant, ce n'est qu'à la troisième passe, quand la clé de l'objet référençant est déterminée, que l'objet référencé est écrit en appelant récursivement les routines d'écriture. Une fois sa clé récupérée, la paire [attribut, clé] constituée est prise en compte.

La méthode **Object-field::info-for-writing** des champs de type objet est articulée selon le même principe. À la première passe, le champ objet n'est pas consulté. À la seconde, il est examiné et les paires sont déterminées par **write-object-field-if-possible** (figure 4.34) dans deux cas :
algorithme Driver-field::info-for-writing(Saving, Passnum).Field
retourner {};
fin

algorithme Atom-field::info-for-writing(Saving, Passnum).Field
soit Attribute_value ← attr-value-to-database(attr Field, Field, object.Saving);
faire add-pair(Saving, [attr Field, Attribute_value]);
retourner {};
fin

algorithme Object2-field::info-for-writing(Saving, Passnum).Field
selon
  cas Passnum = 1
    retourner {Field};
  cas Passnum = 2
    soit Contained_object ← field-value(Field, object.Saving);
    et Key ← object-key-while-saving(Contained_object);
    si ∃ Key
      alors faire add-pair(Saving, [attr Field, Key])
        et retourner {};
      sinon retourner {Field};
    cas sinon
      soit Contained_object ← field-value(Field, object.Saving);
      et Key ← do-get-object-key(Contained_object, {}, {}, Field);
      faire add-pair(Saving, [attr Field, Key])
        et retourner {};
    fin

algorithme Object-field::info-for-writing(Saving, Passnum).Field
selon
  cas Passnum = 1
    retourner {Field};
  cas Passnum = 2
    retourner write-object-field-if-possible(Field, Saving);
  cas sinon
    retourner write-object-field(Field, Saving);
fin

<caption>Figure 4.33 : Méthodes info-for-writing</caption>
* **Quand le champ est vide :**

S'il est associé à une jointure restreinte, tous les attributs contraints doivent déjà avoir été résolus. Il faut en plus que l'absence de valeur pour le champ soit autorisée et, pour cela, que la jointure objet restreinte fasse également intervenir des attributs référentiels non contraints.

* **Quand le champ référence un objet :**

Il faut que cet objet soit déjà persistant. Si le champ est associé à une jointure restreinte, il faut également que la clé de l'objet soit compatible avec les attributs contraints déjà valués.

Si l'un de ces deux ensembles de conditions est vérifié, les paires déduites de la valeur du champ sont insérées dans le système. Dans le premier cas, les attributs référentiels non contraints se voient affecter la valeur NULL. Dans le second, tous les attributs référentiels sont valués en fonction de la clé de l'objet référencé.

Dans les autres cas, le traitement du champ est reporté à la troisième passe.

Quand débute cette troisième passe, tous les attributs fondamentaux de la classe sont valués et la clé de l'objet en cours de résolution a été déterminée. Les traitements des champs objet n'ayant pu être faits lors de la deuxième passe sont effectués par *write-object-field* (figure 4.35). Cette fonction obtient la clé de l'objet référencé par la fonction *contained-object-key2* et en déduit les paires [attribut référentiel, valeur] correspondantes.

Le principe de *contained-object-key2* est similaire à celui de *contained-object-key* (figure 4.23). En fait changent uniquement les outils d'obtention des attributs contraints et de leurs valeurs. Tandis que *contained-object-key* les tirait de l'objet *Driver-select* et du n-uplet de l'objet écrit, *contained-object-key2* les trouve pour sa part dans l'objet *Driver-saving* qui gère ici la résolution de l'objet.

Après détermination des attributs référentiels contraints et de leurs valeurs, *contained-object-key2* fait appel à *do-get-object-key* pour déclencher la recherche ou le calcul de la clé de l'objet référencé. Comme dans *contained-object-key*, la vérification de la validité de cette clé est réalisée par la procédure *check-contained-object-key*.

La clé de l'objet référencé peut avoir déjà été attribuée au cours de cette troisième passe, lors du traitement d'autres champs à objet. Nous avons vu en effet que l'écriture d'un objet effectué par *save-object* entraînait, dans la même opération, l'écriture de tous ceux qui étaient également référencés dans le même *class-object-buffer* que lui.

L'écriture de l'objet référencé est déclenchée quand clé demeure inaccessible. Si la jointure objet associée au champ est restreinte, *constrained-key-attrs* détermine les attributs clé qui leur y sont comparés. Ce sont ces attributs et leurs valeurs imposées qui vont former les éventuelles paires initiales intervenant dans la résolution de l'objet référencé.

Illustrons l'algorithme *write-object* complet en reprenant l'exemple de validation du vendeur *james* et des objets qu'il référence (cf. §4.2.1.3). Lors de cette validation, le premier appel à *write-object* est effectué pour l'objet *johnson* et la classe *Employé*. Après
algorithme write-object-field-if-possible(Field, Saving)
soit Object_key_attrs ← key.deftable.table.ownerclass(Field
et Read_attrs ← ra-compil(Field
et Const_attrs ← Read_attrs ∩ solved-attributes(Saving)
et Not_const_attrs ← Read_attrs \ Const_attrs
et Const_attrs2 ← Read_attrs ∩ Object_key_attrs
et Const_attr_values ← saving-attribute-values(Saving, Const_attrs)
et Cont_object ← field-value(Field, object.Saving)
et Key ← object-key-while-saving(Cont_object)
et Attr_values ← attr-values-from-key(Key);
selon
cas ∃ Cont_object
    et Const_attrs2 ⊂ Const_attrs
    et Not_const_attrs ≠ {}
faire build-and-add-pairs(Not_const_attrs, {}, Saving);
cas ∃ Cont_object
    et ∃ Key
    et compatible-object-key-p(Read_attrs, Attr_values, Const_attrs, Const_attr_values)
faire build-and-add-pairs(Read_attrs, Attr_values, Saving);
cas sinon
    retourner {Field};
fin

<caption>Figure 4.34 : Algorithmes de write-object-field-if-possible</caption>
algorithme write-object-field(Field, Saving)
soit Read_attrs ← ra-compile Field
et Key ← contained-object-key2(Field, Saving)
et Attr_values ← attr-values-from-key(Key);
faire build-and-add-pairs(Read_attrs, Attr_values, Saving);
retourner {};
fin

algorithme contained-object-key2(Field, Saving)
soit Object_key_attrs ← key.deftable.table.ownerclass(Field
et Read_attrs ← ra-compile Field
et Const_attrs ← Read_attrs ∩ solved-attributes(Saving)
et Const_attr_values ← saving-attribute-values(Saving, Const_attrs)
et Cont_object ← field-value(Field, object.Saving)
et Key ← do-get-object-key(Cont_object, Const_attrs, Const_attr_values, Field);
faire check-contained-object-key(Key, Read_attrs, Const_attrs, Const_attr_values,
(Read_attrs ⊂ Object_key_attrs), object.Saving, Field);
retourner Key;
fin

<caption>Figure 4.35 : Algorithmes de write-object-field</caption>
avoir été retrouvé, l'objet *Driver-saving* de *johnson* est initialisé par l'appel à *init-object-saving*. Sa valeur est ensuite celle qui a été présentée figure 4.29.

*johnson* n'étant pas encore persistant, l'appel à *add-key-pairs* est sans effet. Aucune contrainte n'ayant été posée sur les attributs de clé comme en témoigne le champ *initial-pairs* vide dans l'objet *Driver-saving*, celui à *add-initial-pairs* n'en a pas non plus. La résolution de l'objet est ensuite engagée.

La plupart des champs de la classe *Employé* sont traités lors de la première passe puisqu'au cours de celle-ci, la liste des champs non encore traités passe de `{name, prenom, num-ss, qualif, chef, responsable-de, salaire, grade, dpt, adresse, tel-prive, vehicule}` à `{chef, responsable-de, dpt, adresse, vehicule}`. À l'issue de la première passe, l'objet *Driver-saving* a pour valeur celle présentée figure 4.36.

<table><caption>Figure 4.36 : Objet *Driver-saving* de *johnson* (classe *Employé*) après la première passe</caption><thead><tr><th colspan="2">Objet de classe Driver-saving</th></tr></thead><tbody><tr><td>...</td><td>...</td></tr><tr><td>object</td><td>Object("johnson")</td></tr><tr><td>initial-key</td><td>()</td></tr><tr><td>new-key</td><td>()</td></tr><tr><td>object-class</td><td>Driver-class(Vendeur)</td></tr><tr><td>status</td><td>()</td></tr><tr><td>unsolved-attrs</td><td>(emp.empno person.pname person.fname emp.ename emp.fname)</td></tr><tr><td>initial-pairs</td><td>()</td></tr><tr><td>user-pairs</td><td>()</td></tr><tr><td>prev-pairs</td><td>()</td></tr><tr><td>pairs</td><td>([person.ssnum, NULL] [emp.job, salesman] [emp.sal, 1000.] [person PHONE, NULL])</td></tr><tr><td>prev-transitions</td><td>(T(Object("johnson"), qualif, ()] T(Object("johnson"), salaire, ()))</td></tr><tr><td>transitions</td><td>()</td></tr></tbody></table>

`emp.ename` et `emp.fname`, bien que correspondances des champs `nom` et `prenom`, sont toujours non résolus. La raison en est que ces champs sont `read-only` et que les champs `read-only` ne sont pas consultés pour la résolution (cf. figure 4.32).

À la seconde passe, La plupart des champs sont traités : le champ `responsable-de`, qui ne référence aucun objet, et les champs `chef`, `dpt`, `vehicule` qui référencent des objets persistants. Ces trois champs objet n'étant pas associés à des jointures restreintes, il n'y a aucune incompatibilité entre eux et leurs valeurs.

Le champ `adresse` par contre n'a pas encore pu être pris en compte dans la résolution. En effet, il est vide, associé à une jointure objet `J[emp→address]` (de définition `emp.empno = address.empno`) qui est fixée, donc restreinte a fortiori, et tous les attributs contraints (`{emp.empno}`) ne sont pas valués. Il sera traité à la troisième passe.

À la fin de la seconde passe, les attributs fondamentaux non encore résolus sont déter-
minés. Ce sont `{emp.empno, person.pname, person.fname, emp.ename, emp.fname}`. Les attributs correspondances de champs sont considérés en premier. Pour ceux-là, `DRIVER` regarde d'abord si une valeur n'est pas déjà disponible dans le champ. C'est le cas du champ `nom` qui contient "johnson". Sinon, il demande à l'utilisateur de valuer le champ. Dans notre exemple, le système demande une valeur pour le champ `prenom`, question à laquelle on répond par "ben". `person.pname` et `person.fname` sont déterminés par propagation de valeurs dans les contraintes. Si `driver-fix-key-generation-p` vaut T, une valeur est générée pour `emp.empno`, par exemple, 7936.

À l'issue de la seconde passe, l'objet `Driver-saving` a pour valeur celle présentée figure 4.37.

<table><caption>Figure 4.37 : Objet Driver-saving de johnson (classe Employé) après la seconde passe</caption><thead><tr><th colspan="2">Objet de classe Driver-saving</th></tr></thead><tbody><tr><td>...<br>object<br>initial-key<br>new-key<br>object-class<br>status<br>unsolved-attrs<br>initial-pairs<br>user-pairs<br>prev-pairs<br>pairs</td><td>Object("johnson")<br>()<br>()<br>Driver-class(Vendeur)<br>(user-pairs)<br>()<br>()<br>([emp.fname, ben])<br>()<br>([person.ssnum, NULL] [emp.job, salesman] [emp.sal, 1000.]<br>[person PHONE, NULL] [emp.mgr, 7698] [emp.responsible_for, NULL]<br>[emp.deptn, 30] [person.car, NULL] [emp.fname, ben] [person.fname, ben]<br>[emp.ename, johnson] [person.pname, johnson] [emp.empno, 7936])</td></tr><tr><td>prev-transitions<br>transitions</td><td>(T[Object("johnson"), qualif, ()] T[Object("johnson"), salaire, ()])<br>(T[Object("johnson"), prenom, ()])</td></tr></tbody></table>

Le champ `adresse` reste le seul en lice pour la troisième passe. La méthode `info-for-writing` des champs objet est invoqué et `contained-object-key2` est appelé pour déterminer la clé de l'objet référencé. Or, il n'y en a aucun. `do-get-object-key` retourne donc {} et `check-contained-object-key` teste ensuite la validité de cette valeur.

Or, ce champ est associé à une jointure objet fixée. Le seul attribut référentiel qu'elle comporte, `emp.empno`, est contraint et n'a pas de valeur : {} n'est donc pas une valeur autorisée pour `adresse`. Si `driver-writing-help` vaut T, le système demande à l'utilisateur de choisir une autre valeur pour le champ. Comme la jointure associée est fixée, et qu'aucun objet `Adresse` de clé `address/7936` n'existe, il n'y a pas de solution parmi les objets existants et `DRIVER` propose de valuer le champ avec un nouvel objet à créer. Si l'utilisateur valide ce choix, l'écriture de l'objet `Adresse` créé est aussitôt enchaînée par `do-get-object-key`. Cette fois, l'ensemble des attributs référentiels contraints de la jointure objet n'est pas vide puisqu'il vaut `{emp.empno}`. De cet ensemble et de la jointure elle-même est déduit
l'ensemble des attributs contraints de l'objet **Adresse** qui va être écrit. Cet ensemble est `{address.empno}`. La valeur contrainte de l'attribut `address.empno` est 7936. La paire `[address.empno, 7936]` sera, lors de l'écriture de l'objet, la seule paire initiale de la résolution.

L'objet **Driver-saving** de **johnson** pour la classe **Employé** ne subit plus ensuite de modification jusqu'à la fin de l'exécution de **write-object**. Sa valeur finale est donc identique à celle présentée figure 4.37.

Il permet finalement, par l'intermédiaire de la procédure **build-writings**, de construire un certain nombre d'objets **Driver-insert**. Comme nous allons le voir maintenant, ces objets permettent de générer des requêtes SQL qui assurent l'insertion dans la base des n-uplets correspondant à l'objet en cours d'écriture.

### 4.2.3.7 Les requêtes d'insertion

`DRIVER` insère dans la base un objet relationnel en adressant au SGBD des requêtes d'insertion. De telles requêtes sont représentées en `DRIVER` par des objets de la classe `Driver-insert`. Ces objets sont construits par la fonction `build-writings` à partir des objets `Driver-saving`. Une fois complets, ils permettent de générer les requêtes SQL correspondantes.

```sql
INSERT INTO tablename [(column {, ... })]
    VALUES (select_expr {, ...})

INSERT INTO tablename [(column {, ... })] subselect
```

<caption>Figure 4.38 : Syntaxe d'une requête SQL d'insertion de données</caption>

La syntaxe générale de la requête SQL d'insertion est donnée figure 4.38. Disons, en quelques mots, que la requête est introduite par le mot-clé `INSERT` et qu'elle s'adresse à une seule table. La liste des attributs se voyant affecter une valeur est précisée derrière le nom de la table. Elle est suivie du mot clé `VALUES` et de la liste des valeurs associées à ces attributs.

La seconde syntaxe, bien que disponible, n'est pas utilisée par `DRIVER`.

La classe `Driver-insert` a déjà été décrite en §4.2.2.3.

À titre d'exemple, la figure 4.39 présente les deux objets `Driver-insert` construits dans la précédente section (§4.2.3.6) pour insérer dans la base les n-uplets correspondant à l'objet `johnson`.
<table><thead><tr><th colspan="2">Objet de classe Driver-insert</th></tr></thead><tbody><tr><td>table</td><td>(emp)</td></tr><tr><td>null-attributes</td><td>(emp.responsible_for)</td></tr><tr><td>attributes</td><td>(emp.job emp.sal emp.mgr emp.deptn emp.fname emp.ename emp.empno)</td></tr><tr><td>values</td><td>(salesman 1000. 7698 30 ben johnson 7936)</td></tr></tbody></table>

<table><caption>Figure 4.39 : Objets Driver-insert de mise-à-jour de l'objet johnson</caption><thead><tr><th colspan="2">Objet de classe Driver-insert</th></tr></thead><tbody><tr><td>table</td><td>(person)</td></tr><tr><td>null-attributes</td><td>(person.ssnum person phone person.car)</td></tr><tr><td>attributes</td><td>(person.fname person.pname)</td></tr><tr><td>values</td><td>(ben johnson)</td></tr></tbody></table>

Les deux requêtes correspondant à ces objets sont :

* insert emp (responsible_for, job, sal, mgr, deptn, fname, lname, empno)
  values (NULL, 'salesman', 1000., 7698, 30, 'ben', 'johnson', 7936);

* insert person (ssnum, phone, car, fname, lname)
  values (NULL, NULL, NULL, 'ben', 'johnson');
### 4.2.4 Écriture des champs de type "ensemble"

Les méthodes d'écriture des champs de type "ensemble" n'ont pas encore été complètement étudiées. Elles seront détaillées dans une publication ultérieure.

### 4.2.5 Modification d'objet en cours d'écriture

Quand l'indicateur système `DRIVER driver-writing-help`, vaut `T`, la validation de transaction peut engendrer des modifications d'objet.

`DRIVER` gère un historique de ces modifications de façon à pouvoir les défaire en cas d'incohérence ou d'erreur. Cet historique se présente sous la forme d'une liste d'objets transitions, instances de la classe `Driver-transition`.

<table><caption>Listing 23. La classe `Driver-transition`</caption><tr><td>(driver-defclass Driver-transition ()</td></tr><tr><td>(object object2)</td></tr><tr><td>(fieldname atom symbol)</td></tr><tr><td>(oldvalue *)</td></tr></table>

Chaque transition comprend trois informations (listing 23) :

* l'objet modifié;

* le champ modifié;

* l'ancienne valeur de ce champ dans l'objet considéré. Cette valeur ne peut être typée. En effet, selon le type du champ, elle pourra être un symbole, un entier, un objet, un ensemble, etc...

Défaire des modifications se fait simplement en réaffectant au champ d'un objet son ancienne valeur. Comme un même champ aura pu être modifié plusieurs fois, il est important de revenir sur ces modifications dans l'ordre inverse de celui dans lequel elles ont été effectuées.

L'historique de chaque objet est géré dans le champ `transitions` de son `Driver-saving` associé.

### 4.2.6 Erreur fatale en cours d'écriture

En cas d'erreur grave intervenue pendant la validation de transaction, `DRIVER` fait appel à la procédure `fatal-error` (figure 4.40).
Cette procédure interrompt l'opération de validation de transaction en générant une erreur. Cependant, avant de provoquer cette erreur, elle procède à la restauration de l'environnement. Il est en effet souhaitable que l'exécution de **driver-commit-objects**, expliquement demandée par l'utilisateur, rende l'environnement tel qu'il était au début de la validation dans le cas où cette validation ne peut être menée à son terme. En cas d'échec, tout doit se passer comme si la tentative de validation n'avait jamais eu lieu.

algorithme fatal-error(*Message*)

faire dbms-rollback(dbms driver-current-cursor())

et undo-transitions()

et clear-saving-buffer()

et error(*Message*);

fin

<caption>Figure 4.40 : Algorithme de traitement des erreurs fatales</caption>

La restauration de l'environnement comprend principalement deux opérations :

* **La restauration de la base de données.** Toutes les requêtes d'insertions et de mise-à-jour adressées au SGBD dans le cadre de cette validation sont annulées. La base est ainsi replacée dans l'état où elle était au début de la validation. Cette opération est réalisée en envoyant au SGBD une requête SQL **rollback work**.

* **La restauration de la couche objet en mémoire.** Toutes les modifications effectuées en mémoire sur les objets dans le cadre de la validation sont annulées. Tous les champs qui ont été modifiés sont ré-affectés de leurs précédentes valeurs. Cette opération est possible grâce à la gestion par DRIVER des éléments de transition (cf. §4.2.5).

On remarquera enfin que le dictionnaire des objets système **Driver-saving** est vidée au moyen de l'appel à **clear-saving-buffer** de façon à libérer immédiatement la mémoire d'objets système volumineux qui de toute façon ne seront plus utilisés.

## 4.3 Suppression des objets relationnels

La suppression d'objets relationnels dans la base n'a pas encore été implantée en DRIVER.

Cependant, l'étude de l'algorithmme correspondant a été réalisée et aucun problème particulier n'a été identifié. La suppression d'un objet en DRIVER se décompose simplement en trois opérations principales successives (figure 4.41) :
algorithme driver-delete-object(Object)

faire delete-object-references-in-layer(Object)

et record-object-deletion(Object);

fin

algorithme delete-object-references-in-layer(Object_to_delete)

pour tout Class ∈ classes driver-current-mapping()

faire delete-object-references-in-class-objects(Class, Object_to_delete);

fin

algorithme delete-object-references-in-class-objects(Class, Object)

soit Object_fields ← object-class-fields(Class, object-class(Object))

et Object_filter ← referenced-object-filter(Object_fields)

et Class_object_references ← driver-select-objects(Object_filter);

faire driver-load-class-objects(Class, Class_object_references);

pour tout Object ∈ instances main-class(Class)

si class-instance-p(Object, Class)

alors faire delete-object-references-in-object(Object, Object_fields, Object);

fin

<caption>Figure 4.41 : Algorithme de suppression d'objet</caption>
* La première a pour but d'éliminer de l'ensemble des objets de la couche virtuelle toute référence à l'objet à supprimer.

* La seconde "marque" l'objet en question comme étant supprimé. Ceci est fait en ajoutant un objet **Driver-deletion** (listing 24) le concernant au contenu du champ **deleted-objects** du schéma de correspondances courant.

Le champ **deleted-object** référence l'objet détruit et le champ **uncommitted-objects**, les objets qui le référençaient et qui n'ont pas encore été validés dans la base.

* La troisième opération n'est effectuée qu'après validation dans la base<fnref n="8" /> de tous les objets qui référençaient l'objet détruit. Elle n'apparaît donc pas dans le détail de l'algorithme figure 4.41.

Elle se traduit d'une part par la suppression dans la base de tous les n-uplets correspondant à l'objet supprimé. Il y en a un par table élémentaire de la classe de l'objet.

Elle provoque, d'autre part, la suppression dans **DRIVER** de toute référence système à l'objet, en particulier son référençage ou le référençage de sa clé dans les dictionnaires.

<caption>Listing 24. Classe système de gestion de suppression d'objet</caption>

```
(driver-defclass Driver-deletion ()
(deleted-object object2)
(uncommitted-objects object2set))
```

La première opération est la plus complexe, aussi nous allons la détailler.

Les références éventuelles à l'objet à supprimer sont contenues dans les champs à
objet (objet, ensemble d'objets et ensemble ordonné d'objets). Pour chaque classe du
schéma de correspondances sont donc déterminés dans un premier temps les champs à
objet référençant des objets de classe une des classes ancêtres de la classe de l'objet à
supprimer ou sa classe elle-même.

Quand une classe comporte au moins un tel champ, une requête objet est construite et
adressée à la base au moyen de la fonction **driver-select-objects**. Son but est d'y retrouver
les objets relationnels de la classe considérée référençant l'objet à supprimer. S'il y en a, il
est procédé à la construction en mémoire de leurs objets jumeaux, ceci uniquement dans
le cas où ces objets jumeaux n'y auraient pas déjà été construits.

Enfin, sont recherchés parmi l'ensemble des objets jumeaux tous ceux qui référentcent
l'objet à détruire. Pour chacun d'entre eux, le champ à objet concerné est modifié pour
en enlever la référence de l'objet considéré.

<footnote n="8">⁸Par validation(s) de transaction(s) DRIVER.</footnote>
Il convient d'insister sur le fait que ce troisième volet de la première opération implique TOUS les objets jumeaux, donc pas seulement ceux des objets relationnels filtrés précédemment. De cette façon, on tient également compte des modifications d'objets effectuées pendant la transaction courante. Si, au cours de cette transaction, un objet a été modifié de façon à ce qu'il référence ou ne référence plus l'objet à supprimer, c'est sa dernière version qui est ainsi considérée, et pas sa valeur dans la base.

La troisième opération ne peut être effectuée que quand tous les objets qui référaient l'objet détruit ont été validés dans la base. En effet, si elle était déclenchée avant, la base de données se trouverait être incohérente car des objets relationnels, en l'occurrence ceux correspondant aux objets jumeaux non encore validés, référenceraient encore l'objet détruit alors que celui-ci n'existerait déjà plus dans la base. Il suffirait alors d'une annulation de transaction pour l'un de ces objets pour que la couche objet de `DRIVER` soit incohérente.

On déduira d'autre part de ce qui précède qu'il suffit en `DRIVER` d'une annulation de transaction pour l'un des objets qui référaient l'objet détruit pour également annuler la destruction de l'objet référencé. Par contre, si aucune annulation de transaction n'est effectuée pour les autres, ils continuent à ne plus référencer l'ex-"objet détruit".

## 4.4 Sélection d'objets relationnels dans la base

### 4.4.1 Généralités

La recherche d'objets relationnels dans la base s'effectue par un appel à la fonction `driver-select-objects`. Le critère de sélection est décrit sous forme d'un filtre qui constitue l'unique argument de la fonction.

Le filtre est un prédicat à *n* variables où chacune d'entre elles représente une instance d'une classe précisée, décrite dans le schéma de correspondances. Le corps du prédicat est un ensemble de contraintes liant généralement ces *n* variables et pouvant être des comparaisons entre objets, entre champs, entre champs et valeurs.

Dans l'implantation LISP de `DRIVER`, le filtre prend la forme d'une lambda-expression exprimée dans un environnement où sont précisées les classes des objets susceptibles d'être unifiés à ses variables :

((LAMBDA (objet1 ... objetN)
    corps-lambda)
    classe-objet1 ... classe-objetN)

Les accès composés aux champs de ces objets sont autorisés. À titre d'exemple, la requête présentée figure 4.42 sélectionne dans la base toutes les paires [employé - chef de l'employé] pour lesquelles l'employé a une voiture de même modèle que celle de son chef. Ne sont demandées que les paires où le chef est au moins instance de la classe Cadre.

Ici, une seule paire est solution. L'employé ayant un tel véhicule est celui dont l'empno vaut 7782, et son chef est le cadre dont l'empno vaut 7839.
```sql
? (driver-select-objects
'((lambda (objet1 objet2)
(and (eq objet2 (send 'chef objet1))
(eq (send ' modele (send 'vehicule objet1))
(send ' modele (send 'vehicule (send 'chef objet1)))))
Employe Cadre))
= (((7782) (7839))
```

<caption>Figure 4.42 : Exemple de sélection d'objets relationnels</caption>

driver-select-objects se limite à renvoyer des références symboliques sur les objets relationnels solution au lieu de directement renvoyer les objets jumeaux ou défauts d'objet correspondants, éventuellement construits pour l'occasion. On peut s'en étonner, d'autant plus que le système fournit également une primitive, driver-get-object, qui retourne l'objet correspondant à la référence qu'on lui indique. Cette référence, qui est la valeur de clé du n-uplet principal de l'objet, est semblable à celles retournées par la fonction de filtrage.

La raison en est qu'un n-uplet d'objets relationnels peut très bien vérifier dans la base les conditions imposées par un filtre, au contraire du n-uplet d'objets correspondants en mémoire. Cette divergence peut se produire quand ces n-uplets solution impliquent des objets pour lesquels des jumeaux ont déjà été construits et modifiés dans l'environnement.

De ce fait, si driver-select-objects retournait les objets jumeaux des objets relationnels solution, certains n-uplets d'objets retournés ne vérifieraient paradoxalement même pas le critère de sélection précisé par l'utilisateur.

<figure><img src="image_27.png" /><figcaption>Figure 4.43 : Justification de la sélection d'objets en deux temps</figcaption></figure>

La figure 4.43 présente un exemple qui illustre ce cas de figure. L'Objet1 a été modifié dans l'environnement et n'a pas encore été validé dans la base. L'Objet2 n'a, pour sa
part, fait l'objet d'aucune mise-à-jour.

Si on filtre dans la base les paires d'objets relationnels, l'un étant de classe A, le se-
cond de classe B, vérifiant *Objet_class_A.Champ1* = *Objet_class_B.Champ2*, la paire
[[Objet1, Objet2]] est solution. Pourtant, du fait des modifications effectuées dans l'envi-
ronnement, la paire des objets jumeaux correspondants ne vérifie pas le critère de sélec-
tion : *Champ1 Objet1* = 3 ≠ *Champ2 Objet2* = 5.

En conclusion, nous n'avons pas aujourd'hui de solution efficace permettant le filtrage
d'objets sur l'ensemble de la couche objet virtuelle de DRIVER.

4.4.2 CLERIC

Les filtres de sélection d'objets sont compilés sous une forme objet par CLERIC, Compi-
lateur de Lambda Expression en Représentation Intermédiaire de Contrainte. Ces repré-
sentations objet sont une Représentation Intermédiaire (RI) qui permet ensuite d'aisément
générer du SQL.

CLERIC est également utilisé pour générer de semblables RI pour les jointures, les contraintes de classes sur un champ ou sur un attribut, à partir des déclarations de l'utilisateur. Les classes système des objets utilisés dans ces RI sont présentées figure 4.44.

<figure><img src="image_28.png" /><figcaption>Figure 4.44 : Hiérarchie de la classe Driver-sql-op</figcaption></figure>

Le compilateur fonctionne dans un contexte courant qui lui indique quelles sont les
fonctions autorisées, leurs arguments, le type de ces arguments. Le contexte est composé
d'un ensemble d'indicateurs système :

*   **calculated**. Ce mode autorise l'utilisation des quatre opérations dans l'expression. Les arguments peuvent être de nouveaux appels fonctionnels, des variables ou des valeurs.
* **equation**. Ce mode autorise l'utilisation des prédicats **and**, **or**, **not** et **null**. Ce dernier permet de déterminer si un terme a une valeur ou non.

* **multi-tuple**. Ce mode indique que l'expression est un calcul sur un ensemble de n-uplets. Dans ce mode, les calculs de sommes et de moyennes sont autorisés.

* **attribute-manipulation**. Ce mode indique que les variables correspondent à des attributs.

* **object-manipulation**. Ce mode indique que les variables correspondent à des objets. Les accès aux champs de ces objets sont autorisés.

* **global-variables**. Enfin, ce dernier mode autorise l'usage de variables globales dans l'expression. Il est particulièrement utile pour l'usage de **driver-select-objects**, afin de permettre la définition de filtres d'objets dont les critères de sélection évoluent à chaque nouvelle évaluation de la même règle.

À titre d'exemple, la requête SQL générée pour la sélection d'objets relationnels présentée figure 4.42 est :

```sql
select distinct var126.empno, var127.empno
from emp var126, emp var127
where exists(select * from emp var128
  where var126.mgr = var128.empno and var127.empno = var128.empno)
  and exists(select * from vehicle var129, person var130, emp var131,
    vehicle var132, person var133
  where var126.ename = var130.pname
    and var126.fname = var130.fname
    and var130.car = var129.vnum
    and var126.mgr = var131.empno
    and var131.ename = var133.pname
    and var131.fname = var133.fname
    and var133.car = var132.vnum
    and var129.model = var132.model)
  and var126.sal >= 700. and var126.sal <= 9999.
  and var127.job in ('president', 'manager')
  and var127.sal >= 700. and var127.sal <= 9999.
```
# CONCLUSION

Tout en proposant une solution au problème de l'“Impedance Mismatch”, nous avons montré, dans cette thèse, qu'il était possible de construire un système proposant des correspondances entre des concepts communs à de très nombreux modèles objet et ceux existant dans le modèle relationnel.

Nous avons ainsi le moyen d'associer une représentation objet à toute base relationnelle. Notre principal résultat est de pouvoir transformer aux yeux de l'utilisateur un SGBD relationnel classique en SGBD Orienté Objet.

Le SGBD objet ainsi produit présente deux originalités majeures :

* L'utilisateur garde son modèle objet.

En effet, DRIVER peut prendre en compte tout modèle objet par simple définition d'un jeu de méthodes permettant de réaliser les opérations classiques de manipulation d'objet.

* Les bases exploitées continuent à fonctionner en relationnel pur.

Grâce aux correspondances systématiques, nous sommes capables de prendre en compte une base relationnelle quelconque, lui attribuer une représentation pertinente dans un modèle objet choisi, et l'exploiter aussitôt comme une base objet. Toute application relationnelle disponible sur le marché est ainsi immédiatement exploitable sous forme objet.

Inversement, tout objet, produit de raisonnement ou de calcul, sauvé dans une base DRIVER, est instantanément disponible sous la forme relationnelle, la plus répandue. La communication de données à un partenaire ne disposant pas de DRIVER ne nécessite aucune conversion ou traduction. Bien sûr, si ce partenaire utilise lui-même DRIVER, il peut immédiatement exploiter ces données dans le modèle objet de son choix et avec la représentation qui lui convient le mieux pour son application.
## Perspectives

On peut d'ores et déjà envisager d'enrichir cette première version de `DRIVER` de nouvelles fonctionnalités.

* **Modèle objet canonique.** L'ensemble des concepts objet pour lesquels ont été identifiées des correspondances relationnelles définissent ou, plus précisément, font émerger un *modèle objet canonique*. Toute représentation objet exprimée dans ce modèle peut être rendue complètement persistante.

Ce modèle canonique est extensible : la définition de nouvelles correspondances peut permettre la prise en compte de nouveaux concepts. Cependant, dans la version actuelle du système, si un client souhaite utiliser, dans une base de connaissance `DRIVER`, une caractéristique de modèle objet non encore gérée, sa prise en compte peut se révéler difficile. Rendre le modèle objet canonique de `DRIVER` extensible par l'utilisateur est un axe de recherche à part entière.

* **Typage des champs.** Le typage des champs doit être réexaminé et épuré. Les constructeurs de types déjà disponibles sont à généraliser de façon à les rendre orthogonaux. La composition des constructeurs de type doit en effet pouvoir être réalisée librement. Par exemple, il serait souhaitable de ne plus être limité aux seuls ensembles d'atomes et d'objets et de pouvoir définir des ensembles d'ensembles, etc.
Actuellement, seuls les constructeurs "ensemble" et "liste" (ensemble ordonné) sont disponibles. Il serait intéressant de les compléter des constructeurs "n-uplet", "sac", "dictionnaire" existant par exemple dans O2.

* **Filtrage complet.** Un filtrage des objets relationnels a été proposé. Il reste cependant à étudier une fonction de filtrage pouvant s'appliquer à l'ensemble de la couche objet virtuelle.

* **Sous-traitance.** Dans certaines applications, l'évaluation de règles de production pourrait être directement réalisée au sein du SGBD sous forme de requêtes SQL. Le contrôle de ce type d'inférence est une autre voie d'approfondissement possible.

* **Gestion de versions.** `DRIVER` ne gère pas encore les versions d'objet. Actuellement, deux validations successives d'un même objet persistant se soldent nécessairement par l'écrasement dans la base de l'ancienne valeur de l'objet par sa nouvelle valeur.
Or, au cours d'un raisonnement effectué par un système d'IA, un même objet peut transiter par une succession d'états qui marquent les différentes étapes de sa construction. S'il est persistant, il peut être intéressant de pouvoir sauver dans la base de données des versions différentes de cet objet qui correspondent à des états par lesquels il a transité ou à des solutions alternatives.

* **Persistance des méthodes.** La persistance des méthodes dans la base est un autre sujet d'étude : la forme sous laquelle elles y seraient stockées est à définir. Il serait en effet intéressant de préserver au mieux l'indépendance des données vis-à-vis de tout langage.
* **Distribution.** L'exploitation de `DRIVER` par réseau est un autre de nos objectifs. Nous travaillons actuellement sur un projet d'environnement d'IA distribué et nous aimerions pouvoir utiliser `DRIVER` dans cet environnement pour gérer nos bases de connaissances de grande taille.

Une extension du langage assurant la communication au sein d'un environnement objet distribué peut être réalisée dans cette perspective.

* **DRIVER multi-utilisateurs.** Actuellement, `DRIVER` ne gère pas les fonctionnalités du SGBD liées à son exploitation en multi-utilisateurs, par exemple les droits d'accès. Cette extension pourrait être intéressante pour certaines applications.

* Enfin, `DRIVER` a été implanté en Le_Lisp v15. Il serait intéressant de le réécrire dans d'autres langages comme C++ pour le rendre disponible à un plus grand nombre d'utilisateurs.
Références

[AB84] S. Abiteboul and N. Bidoit. Non first normal form relations to represent hierarchically organised data. In *Proceedings of 3th Symposium on Principles of database systems*, ACM SIGACT-SIGMOD, Waterloo (California), April 1984, pp. 191–200.

[ABC$^{+83}$] M. P. Atkinson, P. J. Bailey, K. J. Chisholm, P. W. Cockshott, and R. Morrison. An approach to persistent programming. *The Computer Journal*, 1983, vol. 26, no. 4, pp. 360–365.

[ABD$^{+89}$] M. P. Atkinson, F. Bancilhon, D. Dewitt, K. Dittrich, D. Maier, and S. Zdonik. The object-oriented database system manifesto. Le Chesnay (France) : INRIA - LRI, August 1989, 19 pages, Technical Report ALTAIR 30-89.

[ACO85] A. Albano, L. Cardelli, and R. Orsini. GALILEO : A strongly-typed, interactive conceptual language. *ACM Transactions on database Systems*, June 1985, vol. 10, no. 2, pp. 230–260.

[AG87] S. Abiteboul and S. Grumbach. Bases de données et objets structurés. *Technique et Science Informatiques*, 1987, vol. 6, no. 5, pp. 383–404.

[AG89a] R. Agrawal and N. H. Gehani. ODE (Object Database and Environment) : The language and the data model. In *Proceedings of the SIGMOD international conference on Management of Data*, ACM SIGMOD, Portland (Oregon), May-June 1989, pp. 36–45.

[AG89b] R. Agrawal and N. H. Gehani. Rationale for the design of persistence and query processing facilities in the database programming language O++. In *Proceedings of 2nd International workshop on database programming languages*, Gleneden Beach (Oregon), June 1989, pp. 1–16.

[AH87] T. Andrew and C. Harris. Combining language and database advances in an object-oriented development environment. In *Proceedings of the international conference on Object-Oriented Programming Systems, Languages and Applications*, Orlando (Florida), October 1987, ACM SIGPLAN Notices, vol. 22, no. 12, pp. 430–440.

[Aid92] AÏDA Version 1.65, *Manuel de référence*, Gentilly (France) : Ilog, Mars 1992, 498 pages.
[ANSI86] American National Standards Institute, editor. *American National Standard for Information systems, database language, SQL*, vol. X3.135. New-York : American National Standard for Information systems, 1986.

[Asq89] ASQUELL Version 2.02, *Manuel de référence*, Gentilly (France) : Ilog, Juin 1989, 23 pages.

[Atw85] T. M. Atwood. An object-oriented DBMS for design support applications. In *Proceedings of the international conference on Computer-Aided Technologies*, Montreal (Canada), September 1985, pp. 299-307.

[BA87] C. Beeri and S. Abiteboul. An algebra and a calculus for complex objects - Abstract. In *International workshop on Theory and Applications of Nested Relations and Complex Objects*, Darmstadt (Germany), April 1987, pp. 56-57.

[BBKV87] F. Bancilhon, T. Briggs, S. Khoshafian, and P. Valduriez. FAD : A powerful and simple database language. In *Proceedings of 13th Very Large Databases conference*, Brighton (England), September 1987, pp. 97-105.

[BC85] A. L. Brown and W. P. Cockshot. The CPOMS Persistent Object Management System. Universities of Glasgow & St Andrew (Scotland), 1985, Technical Report 13-85.

[BCG$^{+}$87] J. Banerjee, H. T. Chou, J. F. Garza, W. Kim, D. Woelk, and N. Ballou. Data model issues for object-oriented applications. *ACM Transactions on Office Information Systems*, January 1987, vol. 5, no. 1, pp. 3-26.

[BDK92] F. Bancilhon, C. Delobel, and P. Kanellakis, editors. *Building an object-oriented database system : the story of O2*. San Mateo (California) : Morgan Kaufmann Publishers, 1992, 625 pages.

[BDN$^{+}$86] J. Bocca, H. Decker, J.-M. Nicolas, L. Vieille, and M. Wallace. Some steps towards a DBMS-based KBMS. In *IFIP 10th World Computer Congress*, Dublin (Ireland), September 1986, pp. 1061-1067.

[Bee87] C. Beeri et al. Sets and negation in a logical database language (LDL1). In *Proceedings of 6th Symposium on Principles of database systems*, ACM SIGMOD-SIGACT-SIGART, San Diego (California), March 1987, pp. 21-37.

[BFKM85] L. Brownston, R. Farrel, E. Kant, and N. Martin. *Programming expert systems in OPS5 : An introduction to ruled-based programming*. Wokingham (England) : Addison-Wesley, 1985, 471 pages.

[Bid86] N. Bidoit. Efficient evaluation of relational queries using nested relations. Le Chesnay (France) : INRIA, 1986, 55 pages, Technical Report 480.
[BK89] F. Bancilhon and S. Khoshafian. A calculus for complex objects. In *Journal of Computer System Sciences*, 1989, vol. 38, no. 2, pp. 326-340.

[BKKK87] J. Banerjee, W. Kim, H. J. Kim, and H. F. Korth. Semantics and implementation of schema evolution in object-oriented databases. In *International conference on Management of Data*, ACM SIGMOD, San Francisco (california), May 1987, vol. 16, no. 3, pp. 311-322.

[BLN86] C. Batini, M. Lenzerini, and S. B. Navathe. A comparative analysis of methodologies for database schema integration. *ACM Computing Surveys*, December 1986, vol. 18, no. 4, pp. 323-364.

[BM92] S. Boyera and S. Maria. Une interface graphique pour DRIVER. Sophia-Antipolis (France) : ESSTIN, Juin 1992, 13 pages. Rapport de stage - rapport technique.

[Bor88] H. Boral. Parallelism in BUBBA. In *Proceedings of International symposium on databases in parallel and distributed systems*, IEEE, Austin (Texas), December 1988, pp. 68-71.

[BR84] M. L. Brodie and D. Ridjanovic. On the design and specification of database transactions. In M. L. Brodie, J. Mylopoulos, and J. W. Schmidt, editors, *On conceptual modelling, Perspectives from Artificial Intelligence, Databases and Programming Languages, Berlin (Germany)* : Springer, 1984, pp. 277-306.

[Bro88] M. L. Brodie. Future intelligent information systems : AI and database technologies working together. In M. L. Brodie and J. Mylopoulos, editors, *Readings in Artificial Intelligence and Databases*, San Mateo (California) : Morgan Kaufmann, 1988, pp. 623-644.

[BRS82] F. Bancilhon, P. Richard, and M. Scholl. On line processing of compacted relations. In *Proceedings of 8th Very Large Databases conference*, Mexico (Mexique), December 1982, pp. 263-269.

[But87] M. H. Butler. *Persistent LISP: Storing Interobject References in a Database*. PhD thesis : Berkeley, University of California, November 1987, 142 pages.

[BV92] E. Borelli-Vittori. *Modèle de données B-rel et approche logique B-log*. Thèse de doctorat, Université de Nice - Sophia-Antipolis (France), Février 1992, 227 pages.

[CAC$^{+}$84] W. P. Cockshott, M. P. Atkinson, K. J. Chisholm, P. J. Bailey, and R. Morrison. POMS : A Persistent Object Management System. *Software Practice and Experience*, January 1984, vol. 14, no. 1, pp. 49-71.

[Car87] M. Caruso. A conceptual overview of the VISION object-oriented database management system. In *Workshop on Database Programming Languages, Roscoff (France)*, September 1987, pp. 67-70.
[CCRG$^{+88}$] S. Ceri, S. Crespi-Reghizzi, G. Gottlob, F. Lamperti, L. Lavazza, L. Tanca, and R. Zicari. The ALGRES project. In *International Conference on Extending Database Technology*, in Lecture Notes in Computer Science, vol. 303, Venice (Italy) : Springer, 1988, pp. 551-555.

[CCRZ$^{+90}$] S. Ceri, S. Crespi-Reghizzi, R. Zicari, F. Lamperti, and L. A. Lavazza. ALGRES : An advanced database system for complex applications. *IEEE Software*, July 1990, vol. 7, no. 4, pp. 68-78.

[CD88] F. Cuppens and R. Demolombe. A prolog-relational DBMS interface using delayed evaluation. In *Proceedings of the 3rd International Conference on Data and Knowledge bases : Improving usability and responsiveness*, Jerusalem (Israel), June 1988, pp. 135-148.

[CDF$^{+86}$] M. J. Carey, D. J. DeWitt, D. Frank, G. Graefe, M. Muralikrishna, J. E. Richardson, and E. J. Shekita. The architecture of EXODUS extensible DBMS. In *Proceedings of the International workshop on object-oriented database systems*, Pacific Grove (California), September 1986, pp. 52-65.

[CDRS86] M. J. Carey, D. J. DeWitt, J. E. Richardson, and E. J. Shekita. Object and file management in the EXODUS extensible database system. In *Proceedings of the 12th Very Large Databases conference*, Kyoto (Japan), August 1986, pp. 91-100.

[CDV88] M. J. Carey, D. J. DeWitt, and S. L. Vandenberg. A data model and query language for EXODUS. In *Proceedings of the SIGMOD international conference on Management of Data*, ACM SIGMOD, Chicago (Illinois), June 1988, vol. 17, pp. 413-423.

[CFK$^{+86}$] P. Ciscia, P. Franceschi, J. Kouloumdjian, G. Levi, G. H. Moll, C. Simonelli, G. Sardu, and L. Torre. The EPSILON knowledge base management system : Architecture and database access optimization. In *Proceedings of the Workshop on Integration of logic programming and databases*, Venice (Italy), December 1986.

[CGK$^{+90}$] D. Chimenti, R. Gamboa, R. Krishnamurthy, S. Naqvi, S. Tsur, and C. Zaniolo. The LDL system prototype. *IEEE Transactions on Knowledge and Data Engineering*, March 1990, pp. 76-90.

[CGT89] S. Ceri, G. Gottlob, and L. Tanca. What you always wanted to know about Datalog (and never dared to ask). *IEEE Transactions on Knowledge and Data Engineering*, March 1989, vol. 1, no. 1, pp. 146-166.

[Cha89] J. Chailloux. *LE_LISP de l'INRIA Version 15.22, Manuel de référence*. Le Chesnay (France) : INRIA, Janvier 1989, 430 pages.

[Che76] P. P. Chen. The entity-relationship model – towards a unified view of data. *ACM Transactions on database systems*, March 1976, vol. 1, no. 1, pp. 9-36.
[CM84] G. Copeland and D. Maier. Making Smalltalk a database system. In *Proceedings of the ACM SIGMOD conference*, ACM SIGMOD record, Boston (Massachusetts), June 1984, vol. 14, no. 2, pp. 316–325.

[Cod70] E. F. Codd. A relational model for large shared data banks. *Communications of the ACM*, 1970, vol. 13, no. 6, pp. 377–387.

[Cod79] E. F. Codd. Extending the database relational model to capture more meaning. *ACM Transactions on database systems*, December 1979, vol. 4, no. 4, pp. 397–434.

[Cod90] E. F. Codd. *The Relational model for database management : version 2.* Wokingham (England) : Addison-Wesley, 1990, 538 pages.

[CW84] C. L. Chang and A. Walker. PROSQL : A prolog programming interface with SQL/DS. San Jose (California) : IBM Research Laboratory, May 1984, 23 pages, Technical Report RJ 4314.

[DDGO87] U. Dayal, M. DeWitt, D. Goldhirsch, and J. Orenstein. PROBE final report. Computer Corporation of America, 1987, Technical Report CCA-87-02.

[DKA$^{+}$86] P. Dadam, K. Kuespert, F. Andersen, H. Blanken, R. Erbe, J. Guenauer, V. Lum, P. Pistor, and G. Walch. A DBMS prototype to support extended NF2 relations : An integrated view on flat tables and hierarchies. In *International conference on Management of Data*, SIGMOD record, Washington D. C., 1986, vol. 15, no. 2, pp. 356–366.

[DKL85] N. Derret, W. Kent, and P. Lyngbaek. Some aspects of operations in an object-oriented database. *IEEE Data Engineering*, December 1985, vol. 8, no. 4, pp. 302–310.

[DPS86] U. Deppisch, H. B. Paul, and H. J. Schek. A storage system for complex objects. In *Proceedings of the 1st international workshop on Object-Oriented Database Systems*, Asilomar (California), 1986, pp. 183–195.

[DRV86] E. Denoël, D. Roelants, and M. Vauclair. Query translation for coupling prolog with a relational database management system. In *ESPRIT'86*, Brussels (Belgique), September–October 1986, pp. 595–605.

[EMS88] J. Eliot, B. Moss, and S. Sinosky. Managing persistent data with Mneme : designing a reliable, shared object interface. In *Proceedings of the 2nd Object-oriented database systems workshop*, in Lecture Notes in Computer Science, vol. 334, Bad Munster Am Stein (Germany) : Springer, September 1988, pp. 298–316.

[FBC$^{+}$87] D. Fishman, D. Beech, H. P. Cate, E.-C. Chow, T. Conners, J. W. Davis, N. Denett, C. G. Hoch, W. Kent, P. Lyngbaek, B. Mahbod, M. A. Neimat, T. A. Ryan, and M. C. Shan. IRIS: an object-oriented database management
system. *ACM Transactions on Office and Information Systems*, January 1987, vol. 5, no. 1, pp. 46–69.

[FK85] R. Fikes and T. Kehler. The role of frame-based representation in reasoning. *Communications of the ACM*, 1985, vol. 28, no. 9, pp. 904–920.

[FT83] P. Fischer and S. Thomas. Operators for non first normal form relations. In *7th International computer software and applications conference*, IEEE, Chicago (Illinois), November 1983, pp. 464–475.

[Fuc84] K. Fuchi. Revisiting original philosophy of fifth generation computer project. In *Proceedings of the International conference on 5th Generation computer systems*, Tokyo (Japan), November 1984, pp. 1–2.

[GMN84] H. Gallaire, J. Minker, and J.-M. Nicolas. Logic and databases : a deductive approach. *ACM Computing Surveys*, June 1984, vol. 16, no. 2, pp. 153–185.

[Gra86a] *G-BASE version 3.0, Reference guide*, Compiègne (France) : Graphael S.A., 1986, 56 pages.

[Gra86b] *G-BASE version 3.0, Introductory guide*, Compiègne (France) : Graphael S.A., 1986, 30 pages.

[GV90] G. Gardarin and P. Valduriez. *SGBD AVANCÉS Bases de données objets, déductives, réparties*. Paris (France) : Eyrolles, 1990, 255 pages.

[HK87a] S. E. Hudson and R. King. Object-oriented database support for software environment. In *International conference on Management of Data*, SIGMOD record, San Francisco (California), May 1987, pp. 491–503.

[HK87b] R. Hull and R. King. Semantic database modeling : Survey, applications, and research issues. *ACM Computing Surveys*, September 1987, vol. 19, no. 3, pp. 201–260.

[HL90] D. Hsieh and T. Lunt. A logic to unify semantic network knowledge systems with object-oriented database models. Menlo Park (California) : SRI International, Computer Science Laboratory, December 1990, 48 pages, Technical Report SRI-CSL-90-15.

[HM81] M. Hammer and D. McLeod. Database description with SDM : A semantic database model. *ACM Transactions on database Systems*, September 1981, vol. 6, no. 3, pp. 351–386.

[HY84] R. Hull and C. K. Yap. The Format model. *ACM Transactions on database Systems*, July 1984, vol. 31, no. 3, pp. 518–537.

[HZ87] M. F. Hornick and S. B. Zdonik. A shared, segmented memory system for an object-oriented database. *ACM Transactions on Office and Information Systems*, January 1987, vol. 5, no. 1, pp. 70–95.
[Ito86] H. Itoh. Research and development on knowledge base systems at ICOT. In *Proceedings of the 12th Very Large Databases conference*, Kyoto (Japan), August 1986, pp. 437-445

[JS82] B. Jaeschke and H. J. Schek. Remarks on the algebra of non first normal form relations. In *ACM Symposium on Principles of database systems*, ACM SIGMOD record, Los Angeles (California), March 1982, pp. 124-138.

[KBB+87a] W. Kim, N. Ballou, J. Banerjee, H. T. Chou, J. F. Garza, and D. Woelk. Composite object support in an object-oriented database system. In *Proceedings of the international conference on Object-Oriented Programming Systems, Languages and Applications*, Orlando (Florida), October 1987, ACM SIGPLAN Notices, vol. 22, no. 12, pp. 118-125.

[KBB+87b] W. Kim, N. Ballou, J. Banerjee, H. T. Chou, J. F. Garza, and D. Woelk. Features of the ORION object-oriented database system. Austin (Texas) : Microelectronics and Computer technology Corporation (MCC), September 1987, Technical Report ACA-ST-308-87.

[KBC+88] W. Kim, N. Ballou, H. T. Chou, J. F. Garza, D. Woelk, and J. Banerjee. Integrating an object-oriented programming system with a database system. In *Proceedings of the international conference on Object-Oriented Programming Systems, Languages and Applications*, San Diego (California), September 1988, ACM SIGPLAN Notices, vol. 23, no. 11, pp. 142-152.

[KEE87] IntelliCorp Inc. KEE. *KEEconnection : A bridge between databases and knowledge bases*. Mountain View (California) : IntelliCorp Inc., 1987, 33 pages, Technical report.

[Kie89] G. Kiernan. *Intégration des types abstraits de données dans un SGBD relationnel déductif*. Thèse de doctorat, Université Pierre et Marie Curie - Paris VI (France), Septembre 1989, 218 pages.

[Kim90] W. Kim. Architectural issues in Orion object-oriented database. *Journal of Object-Oriented Programming*, March-April 1990, vol. 2, no. 6, pp. 29-38.

[Kim92] W. Kim. Introduction to SQL/X. In *Proceedings of Future Databases 1992, 2nd Far-East Workshop on Future Database Systems*, Kyoto (Japan), April 1992, pp. 2-7.

[KM85] R. King and D. McLeod. A unified model and methodology for conceptual database design. *ACM Transactions on Information Systems*, January 1985, vol. 3, no 1, pp. 2-21.

[Kou85] J. Kouloumdjian. The interface between the database management system and the inference machine. ESPRIT Project P-530, November 1985, Technical Report EPSILON 4.
[KP76] L. Kerschberg and J. E. S. Pacheco. A functional database model. Rio de Janeiro (Brazil) : Pontificia University Catolica, 1976, 29 pages, Technical report.

[KSD+90] B. Koch, T. Schunke, A. Dearle, F. Vaughan, C. Marlin, R. Fazakerley, and C. Barter. Cache coherency and storage management in a persistent object management. In *Implementing persistent object bases, principles and practice, Proceedings of the 4th international workshop on persistent object systems*, Martha's Vineyard (Massachusetts), September 1990, pp. 103-113.

[Kup85] G. M. Kuper. *The Logical Data Model: A new approach to database logic*. PhD thesis, Computer Science Department, Stanford University, September 1985, 104 pages.

[KV84] G. M. Kuper and M. Y. Vardi. The Logical Data Model. In *Proceedings of 3th Symposium on Principles of database systems*, ACM SIGACT-SIGMOD, Waterloo (California), April 1984, pp. 86-96.

[LeM90] S. Le Ménec. Interface graphique d'aide à la construction du schéma de correspondances DRIVER. Caen (France) : Université de Caen, Septembre 1990, 96 pages. Rapport de DEA Intelligence Artificielle et Applications.

[LeT86] N. Le Thanh. *Contribution à l'étude de la généralisation et de l'association dans une base de données relationnelle : les iso-dépendances et le modèle B-relationnel*. Thèse de docteur d'État Es-sciences, Université de Nice (France), Avril 1986, 470 pages.

[Leb90a] F. Lebastard. DRIVER : A persistent virtual object layer for reasoning. In *ISMIS-90, 5th International Symposium on Methodologies for Intelligent Systems*, Knoxville (Tennessee), October 1990, pp. 74-81.

[Leb90b] F. Lebastard. DRIVER : A persistent virtual object layer for reasoning. In *AAAI Workshop on Knowledge Base Management Systems*, Boston (Massachusetts), July 1990, multiple p.

[Leb90c] F. Lebastard. DRIVER : Couche objet virtuelle persistante et raisonnement. In *Les systèmes experts et leurs applications*, Avignon (France), Mai 1990, pp. 857-871.

[Leb92a] F. Lebastard. DRIVER : Une couche objet pour les bases de données relationnelles. Sophia-Antipolis (France) : CERMICS-INRIA, Octobre 1992, 19 pages, Technical Report 92-6.

[Leb92b] F. Lebastard. DRIVER version 1.34, manuel de référence. Sophia-Antipolis (France) : CERMICS-INRIA, Octobre 1992, 119 pages, Technical Report 92-7.
[Leb93] F. Lebastard. Bases de données expertes et grandes bases de connaissances : l'État de l'Art. *Génie logiciel & Systèmes experts*, Juin 1993, vol. 31. À paraître.

[Lev92] M. Levene. *The nested Universal Relation Database Model, Lecture Notes in Computer Science*, vol. 595. Berlin (Germany) : Springer, 1992, 177 pages.

[LG91] K.-W. Larry Lai and L. Guzenda. How to benchmark an OODBMS. *Journal of Object-Oriented Programming*, July-August 1991, vol. 4, no. 4, pp. 12-15.

[LLOW70] C. Lamb, G. Landis, J. Orenstein, and D. Weinreb. The ObjectStore database system. *Communications of the ACM*, October 1970, vol. 34, no. 10, pp. 50-63.

[Man87] F. Manola. PDM : An object-oriented model for PROBE. Computer Corporation of America, September 1987, Technical Report CCA-87-03.

[Mas92] MASAÏ Version 1.24, *Manuel de référence*, Gentilly (France) : Ilog, août 1992, 538 pages.

[MAT92] MATISSE : Open semantic database - product overview, Saint-Quentin-en-Yvelines (France) : Intellitic International, 1992, 16 pages.

[MBG+87] J. Mylopoulos, A. Borgida, S. Greenspan, C. Meghini, and B. Nixon. Knowledge representation in the software development process : A case study. University of Toronto (Canada), 1987, 22 pages, Technical report Q/336/K56/1987.

[MD86] F. Manola and U. Dayal. PDM : An object-oriented data model. In *Proceedings of the International Workshop on Object-Oriented Database Systems*, Pacific Grove (California), September 1986, pp. 18-25.

[ME89] J. Moss and B. Elliot. The MNEME persistent object store. Amherst (Massachusetts) : University of Massachusetts, October 1989, Technical Report COINS-TR-89-107.

[Mir90] S. Miranda. *L'art des bases de données - Tome 3 - Comprendre et évaluer SQL*. Paris (France) : Eyrolles, 1990, 205 pages.

[Mis84] N. Mishkin. *Managing Permanent objects*. PhD thesis, New Haven (Connecticut) : Yale University, 1984, 90 pages.

[MKM+83] K. Murakami, T. Kakuta, N. Miyazaki, S. Shibayama, and H. Yokota. A relational database machine, first step to knowledge base machine. In *Proceedings of the 10th Annual international conference on Computer architecture*, Stockholm (Sweden), June 1983, pp. 423-425.

[MM91] G. Mopolo-Moke. NICE-C++ : Une extension C++ pour la programmation persistante à partir d'un serveur de bases d'objets. Thèse de doctorat, Université de Nice - Sophia-Antipolis (France), Décembre 1991, 295 pages.
[MNS<sup>+</sup>87] K. Morris, J. Naughton, Y. Saraiya, J. D. Ullman, and A. Van Gelder. YAWN! (Yet Another (W)indow on NAIL!). *Special issue on Databases and Logic, IEEE Data Engineering, December 1987, vol. 10, no. 4.*

[Mol87] G.-H. Moll. *Un langage pivot pour le couplage de Prolog avec des bases de données : formalisation et environnement opérationnel*. Thèse de doctorat, Université Claude Bernard - Lyon I, Octobre 1987, 221 pages.

[MS86] D. Maier and J. Stein. Development of an object-oriented DBMS. In *Proceedings of the international conference on Object-Oriented Programming Systems, Languages and Applications*, Portland (Oregon), September 1986, ACM SIGPLAN Notices, vol. 21, no. 11, pp. 472-482.

[MS87] D. Maier and J. Stein. Development and implementation of an object-oriented DBMS. In *Research directions in object-oriented programming*, Cambridge (Massachusetts) : MIT Press, 1987, pp. 355-392.

[MS91] L. Marinos and R. A. Smit. From relations to objects : A translation methodology for an object oriented front-end to RDBMS. In *The next generation of information systems : From data to knowledge, Lecture Notes in Computer Science*, vol. 611, (Germany) Berlin (Germany) : Springer, 1991, pp. 148-167.

[MUG86] K. Morris, J. D. Ullman, and A. Van Gelder. Design overview of the NAIL! system. In *Proceedings of the 3th International conference on logic programming, Lecture Notes in Computer Science*, vol. 225, New-York : Springer, 1986, pp. 554-568.

[MVGP92] S. Miranda, P. Valduriez, G. Gardarin, and E. Penny. Next-generation DBMS. Université de Nice (France) : Support du cours EUROPACE, Mai 1992.

[MW91] P. Moore and A. E. Wade. An approach to standard DDL for OODBMSs. *Computer Standards & Interfaces*, October 1991, vol. 13, nos. 1-3, pp. 139-143.

[Nev86] B. Neveu. Une nouvelle génération de systèmes experts pour les domaines de conception. In *8ème Séminaire Tuniso-Français d'Informatique*, Tunis (Tunisie), mai 1986, p. multiple.

[Nic79] J.-M. Nicolas. *Contribution à l'étude théorique des bases de données - Apports de la logique mathématique*. Thèse de docteur d'État Es-sciences, Toulouse (France) : Université Paul Sabatier, Décembre 1979, 265 pages.

[NT89] S. Naqvi and S. Tsur, editors. *A logical language for data and knowledge bases*. New-York : Computer science press, 1989, 288 pages.

[OBS86] P. O'Brien, B. Bullis, and C. Shaffert. Persistent and shared objects in Trellis/Owl. In *Proceedings of the International workshop on object-oriented database systems*, Pacific Grove (California), September 1986, pp. 113-123.
[Ont86] Ontologic Inc. VBASE functional specifications. Billerica (Massachusetts) : Ontologic publications, 1986, Technical report.

[Ont88] Ontologic Inc. VBASE for object applications. Cambridge (Massachusetts) : Ontologic publications, 1988, Technical report.

[Ont91] Ontos Inc. ONTOS : Présentation générale. Paris (France) : BIM systèmes, Septembre 1991, 9 pages, Technical report.

[PA86] P. Pistor and F. Andersen. Designing a generalized NF2 model with an SQL-type language interface. In *Proceedings of the 12th Very Large Databases conference*, Kyoto (Japan), August 1986, pp. 278-288.

[PD89] P. Pistor and P. Dadam. The advanced information management prototype. In *Nested Relations and Complex Objects in Databases, Lecture Notes in Computer Science*, vol. 361, Berlin (Germany) : Springer, 1989, pp. 3-26.

[PK86] W. D. Potter and L. Kerschberg. A unified approach to modeling knowledge and data. In *Proceedings of the conference on knowledge and data*, Albufeira (Portugal), November 1986, pp. 265-291.

[PSS+87] H. B. Paul, H. J. Schek, M. H. Sholl, G. Weikum, and U. Deppisch. Architecture and implementation of Darmstadt Database Kernel System. In *Proceedings of the annual SIGMOD conference*, SIGMOD record, vol. 16, no. 3, San Francisco (California), 1987, pp. 196-207.

[PT86] P. Pistor and R. Traunmueller. A database language for sets, lists and tables. *Information systems*, 1986, vol. 11, no. 4, pp. 323-336.

[PT89] P. Pucheral and J.-M. Thevenin. A graph based data structure for efficient implementation of main memory DBMS's. Le Chesnay (France) : INRIA, February 1989, 24 pages, Research Report 978.

[PTE89] W. D. Potter, R. P. Trueblood, and C. M. Eastman. Hyper-semantic data modeling. *Data & Knowledge Engineering*, 1989, vol. 4, pp. 69-90.

[Puc89] P. Pucheral. *Extensibilité et performance d'un gérant d'objets pour applications bases de données*. Thèse de doctorat, Université Pierre et Marie Curie - Paris VI (France), 1989, 225 pages.

[Rei84] R. Reiter. Towards a logical reconstruction of relational database theory. In M. L. Brodie, J. Mylopoulos, and J. W. Schmidt, editors, *On conceptual modelling, Perspectives from Artificial Intelligence, Databases and Programming Languages, Berlin (Germany) : Springer, 1984*, pp. 191-234.

[RK87] J. Rosenberg and J. L. Keedy. Object management and addressing in the MONADS architecture. In *Proceedings of the International Workshop on Persistent Object Systems*, Appin (Scotland), 1987.
[Ros90] J. Rosenberg. The MONADS architecture : a layered view. In *Implementing persistent object bases, principles and practice, Proceedings of the 4th international workshop on persistent object systems*, Martha's Vineyard (Massachusetts), September 1990, pp. 215-225.

[RS87] L. A. Rowe and M. R. Stonebraker. The POSTGRES data model. In *Proceedings of 13th Very Large Databases conference*, Brighton (England), September 1987, pp. 83-96.

[Rus89] D. M. Russinoff. PROTEUS : A frame-based nonmonotonic inference system. In W. Kim and F. H. Lochovsky, editors, *Object-Oriented concepts, Databases, and Applications*. New-York : ACM Press, 1989, pp. 127-150.

[SAB+89] M. Scholl, S. Abiteboul, F. Bancilhon, N. Bidoit, S. Gamerman, D. Plateau, P. Richard, and A. Verroust. VERSO : A database machine based on nested relations. In *Nested Relations and Complex Objects in Databases, Lecture Notes in Computer Science*, vol. 361, Berlin (Germany) : Springer, 1989, pp. 27-49.

[SCB+86] C. Schaffer, T. Cooper, B. Bullis, M. Kilian, and C. Wilpolt. An introduction to Trellis/Owl. In *Proceedings of the 1st international conference on Object-Oriented Programming Systems, Languages and Applications*, Portland (Oregon), September 1986, ACM SIGPLAN Notices, vol. 21, no. 11, pp. 9-16.

[Shi81] D. Shipman. The functional data model and the data language DAPLEX. *ACM Transactions on database Systems*, March 1981, vol. 6, no. 1, pp. 140-175.

[SK91] M. Stonebraker and G. Kemnitz. The POSTGRES next-generation database management system. *Communications of the ACM*, October 1991, vol. 34, no. 10, pp. 78-93.

[SKL88] S. Y. W. Su, V. Krishnamurthy, and H. Lam. An object-oriented semantic association model (OSAM*). In *AI in industrial engineering and manufacturing: Theoretical issues and applications*. Norcross (Ga) : American Institute of Industrial Engineers, 1988.

[Sme92] SMECI Version 1.65, *Manuel de référence*, Gentilly (France) : Ilog, Mai 1992, 470 pages.

[SPS87] M. H. Scholl, H. -B. Paul, and H. -J. Schek. Supporting flat relations by a nested relational kernel. In *Proceedings of 13th Very Large Databases conference*, Brighton (England), 1987, pp. 137-146.

[SS89] H. J. Schek and M. H. Scholl. The two roles of nested relations in the DASDBS project. In *Nested Relations and Complex Objects in Databases*,
*Lecture Notes in Computer Science*, vol. 361, Berlin (Germany) : Springer, 1989, pp. 49–68.

[Sto90] M. Stonebraker. Architectures for dbms-oriented expert systems. In *AAAI Workshop on Knowledge Base Management Systems*, Boston (Massachusetts), July 1990, multiple p.

[Su83] S. Y. W. Su. SAM* : A semantic association model for corporate and scientific statistical databases. *Information Sciences*, 1983, vol. 29, nos. 2-3, pp. 151–199.

[Su86] S. Y. W. Su. Modeling integrated manufacturing data with SAM*. *IEEE Computer Magazine*, January 1986, vol. 19, no. 1, pp. 34–49.

[SZ90] E. Shekita and M. Zwilling. Cricket : a mapped, persistent object store. In *Implementing persistent object bases, principles and practice, Proceedings of the 4th international workshop on persistent object systems*, Martha's Vineyard (Massachusetts), September 1990, pp. 89–102.

[TYF86] T. J. Teorey, D. Yang, and J. P. Fry. A logical design methodology for relational databases using the extended entity-relationship model. *ACM Computing Surveys*, June 1986, vol. 18, no. 2, pp. 197–222.

[TZ84] S. Tsur and C. Zaniolo. An implementation of GEM – supporting a semantic data model on a relational back-end. In *ACM SIGMOD International Conference on the Management of Data*, New-York, 1984, pp. 286–295.

[TZ86] S. Tsur and C. Zaniolo. LDL : A logic-based query language. In *Proceedings of the 12th Very Large Databases conference*, Kyoto (Japan), August 1986, pp. 33–41.

[Ulm86] J. D. Ulmann. Implementation of logical query languages for databases. *ACM Transactions on database Systems*, 1986, vol. 10, no. 3, pp. 289–321.

[WEM79] G. Wiederhold and R. El-Masri. The structural model for database design. In *International conference on Entity-Relationship Approach to Systems Analysis and Design*. Los-Angeles (California) : North-Holland, December 1979, pp. 237–257.

[WW90] I. Williams and M. Wolczko. An object-based memory architecture. In *Implementing persistent object bases, principles and practice, Proceedings of the 4th international workshop on persistent object systems*, Martha's Vineyard (Massachusetts), September 1990, pp. 114–130.

[WWH87] I. W. Williams, M. I. Wolczko, and T. P. Hopkins. Dynamic grouping in an object oriented virtual memory hierarchy. In *Proceedings of the European conference on object-oriented programming, Lecture Notes in Computer Science*, vol. 276, Paris (France) : Springer, June 1987, pp. 79–88.
[Zan83] C. Zaniolo. The database language GEM. In *ACM SIGMOD International Conference on the Management of Data*, New-York, 1983, pp. 207–217.

[Zan85] C. Zaniolo. The representation and deductive retrieval of complex objects. In *Proceedings of the 11th Very Large Databases conference*, Stockholm (Sweden), August 1985, pp. 458–469.
Annexe A

ANNEXES
## A.1 ASQUELL

DRIVER (version Le_Lisp) utilise ASQUELL [Asq89] pour accéder aux SGBD relationnels et les interroger.

ASQUELL est une interface virtuelle du langage Le_Lisp aux SGBDR. Cette interface est multi-SGBDR, multi-utilisateurs (multi-bases) et multi-requêtes : elle offre en Le_Lisp des connexions simultanées à des SGBDR différents, comme INGRES et ORACLE, et permet d'établir plusieurs canaux de communication avec chacun d'entre eux. Ces canaux sont appelés des *curseurs*.

Elle repose sur :

* une représentation objet du schéma et du dictionnaire des données de la base à laquelle l'utilisateur est connecté;

* des méthodes définies pour les classes des objets représentant les fonctions de communication avec le SGBDR. Ces méthodes rendent transparente à l'utilisateur la nature du SGBDR utilisé.

Les fonctions de l'interface peuvent être regroupées en deux catégories principales :

* Les fonctions générales d'accès au SGBD
  Elles comprennent les fonctions de connexion/déconnexion, de création/suppression de curseurs, de validation/annulation de transaction, de chargement et consultation du schéma des bases connectées.

* Les fonctions de l'interface SQL
  Elles permettent d'adresser des requêtes aux bases connectées et de recevoir les réponses dans l'environnement Le_Lisp. Les requêtes doivent leur être fournies sous forme de chaînes de caractères si bien qu'il est nécessaire de connaître SQL pour utiliser ASQUELL.
Examinons par exemple l'instance de Pièce_détachée qui correspond au premier n-uplet présenté dans la relation parts :

<table><thead><tr><th colspan="2">Objet de classe Pièce_détachée</th></tr></thead><tbody><tr><td>nom</td><td>aile-av-g</td></tr><tr><td>modèle</td><td>Object("Twingo GTL")</td></tr><tr><td>...</td><td>...</td></tr></tbody></table>

Cet objet a pour référence "parts/Renault/59843", valeur qui a été déterminée quand l'objet est devenu persistant. Une fois la référence fixée, elle ne peut plus être changée et les attributs qui la composent sont tenus de conserver la même valeur. Ainsi, pour l'objet considéré, mark et pid vaudront toujours "Renault" et "59843". En conséquence, la valeur du champ modèle ne peut plus être quelconque. Le n-uplet d'un objet candidat à être affecté dans le champ modèle de l'objet considéré doit vérifier la restriction model.mark = 'Renault'. L'objet "106SR" correspondant au troisième n-uplet de la relation model est par exemple une valeur qui n'est plus admise, l'attribut model.mark du n-uplet lui correspondant valant "Peugeot". Si on effectuait malgré tout l'affectation, la mise-à-jour du n-uplet "parts/Renault/59843" dans la base nécessiterait une modification des attributs référentiels mark et type (valeurs "Peugeot" et "456B"), ce qui n'est pas autorisé (pour mark).
## A.3 L'interface graphique de DRIVER

Une première maquette d'interface graphique a été réalisée en 1990 par [LeM90]. Une autre, complètement nouvelle, a été proposée par S. Boyera et S. Maria au cours de leur stage de fin d'école d'ingénieur [BM92]. C'est cette dernière qui est ici rapidement présentée au travers de ses principaux panneaux.

Enfin, il est utile de signaler que ces interfaces ont été élaborées à l'aide des outils AÏDA [Aid92] et MASAÏ [Mas92] de la société Ilog.

La figure A.1 présente le panneau principal de l'interface. Y sont précisés le nom du schéma de correspondances, le modèle objet à utiliser pour ce schéma et le curseur courant sur le SGBD si la connexion a été réalisée.

<figure><img src="image_29.png" /><figcaption>Figure A.1 : Panneau principal de l'interface graphique de DRIVER</figcaption></figure>

Les trois icones sur la gauche permettent d'accéder aux informations sur les classes, les tables et les correspondances.

Si la connexion avec le SGBD n'a pas été établie, elle peut être obtenue en cliquant sur le bouton "Connexion". Le panneau présenté figure A.2 apparaît alors.

L'utilisateur doit choisir un SGBD parmi ceux proposés dans un menu et préciser le

<figure><img src="image_30.png" /><figcaption>Figure A.2 : Panneau de connexion à la base</figcaption></figure>
nom de la base sur laquelle est défini le schéma de correspondances.

Le panneau des classes est présenté figure A.3. Il permet de définir, éditer et effacer une classe dans le schéma. Le bouton "créer" permet de créer la classe sélectionnée dans le modèle objet client qui a été spécifié dans le panneau principal.

<figure><img src="image_31.png" /><figcaption>Figure A.3 : Panneau des classes</figcaption></figure>

Le déclenchement d'une définition de classe appelle le panneau présenté figure A.4 où le concepteur du schéma indique le nom de la classe à définir et précise sa classe mère. Ses champs seront décrits lors de l'édition.

<figure><img src="image_32.png" /><figcaption>Figure A.4 : Définition d'une classe</figcaption></figure>

La figure A.5 présente l'éditeur de classe. La partie gauche permet d'accéder et d'éditer la classe mère et les classes filles<fnref n="1" /> de la classe considérée.

La partie centrale permet de définir, d'éditer et effacer les champs propres à la classe. Il est possible de visualiser et d'éditer (sans toutefois les modifier) les champs hérités des classes ancêtres en plaçant localp à ☐ (au lieu de ☒).

Enfin, la partie droite permet de créer, d'éditer et d'effacer des contraintes de classe sur les champs. On peut également visualiser ici les contraintes héritées des classes ancêtres.

<footnote n="1">¹En fait, toutes les classes descendantes de la classe considérée.</footnote>
<figure><img src="image_33.png" /><figcaption>Figure A.5 : Édition d'une classe</figcaption></figure>

L'édition d'un champ provoque l'apparition du panneau présenté figure A.6. Les différentes caractéristiques d'un champ reconnues par `DRIVER` y sont accessibles : Son nom, la classe à laquelle il appartient, son type, choisi parmi `{atom, object, object2, atomset, or-datomset, objectset, ordobjset, object2set, ordobj2set, monotexpr, multitexpr}`, son domaine, dont la sémantique est variable selon le type (sous-type pour le type `atom`, classe pour le type `object`, etc...), et l'expression permettant de calculer l'éventuelle valeur initiale du champ à affecter à la création d'une nouvelle instance.

Le booléen `localp` précise si le champ appartient également à la même classe dans le modèle objet client ou s'il est au contraire emprunté à une classe ancêtre. Nous avons vu que ce dernier type de déclaration permettait par exemple de définir une correspondance au champ d'une classe ancêtre non définie dans le schéma de correspondances.

<figure><img src="image_34.png" /><figcaption>Figure A.6 : Édition d'un champ</figcaption></figure>
<figure><img src="image_35.png" /><figcaption>Figure A.7 : Édition d'une contrainte de classe</figcaption></figure>

<figure><img src="image_36.png" /><figcaption>Figure A.8 : Édition de corps de contrainte</figcaption></figure>

<figure><img src="image_37.png" /><figcaption>Figure A.9 : Éditeur de contraintes de classe</figcaption></figure>
L'éditeur de classe donne également accès aux éventuelles contraintes définies pour la classe éditée et/ou ses classes ancêtres.

L'édition d'une contrainte provoque l'apparition du panneau présenté figure A.7. La classe et le champ sur lesquels est définie la contrainte sont précisés, suivi de l'expression de la contrainte.

Pour une classe donnée, il est possible de naviguer de contrainte en contrainte en choisissant un nouveau champ dans le sélectionneur prévu à cet effet.

Pour éditer l'expression d'une contrainte, il suffit de cliquer sur la fenêtre où elle apparaît. Ceci appelle alors l'éditeur présenté figure A.8.

L'expression éditée peut alors être sujette à toute modification. Les commandes de l'éditeur proposé sont celles d'Emacs; elles sont consultables en cliquant sur le bouton ?, ce qui provoque l'apparition d'un panneau d'aide.

Après modification, la validation de la nouvelle expression déclenche sa vérification. En cas d'erreur, l'interface indique à l'utilisateur l'origine du problème et le renvoie ensuite à l'édition. Il n'est ainsi possible de quitter cet éditeur que quand tout est en ordre. Au besoin, on peut interrompre et annuler la modification amorcée pour retrouver l'ancienne expression de la contrainte.

Depuis le panneau des correspondances que nous allons voir par la suite, il est également possible d'accéder aux contraintes d'une classe donnée. À partir de ce panneau, on arrive alors sur celui de la figure A.9 qui, cette fois, donne aussi accès aux contraintes de classe directement définies sur les attributs sans correspondance. De ce panneau, il est donc possible de définir des contraintes sur attributs et/ou sur champs atomiques, de les éditer et de les supprimer.

Le panneau des tables est présenté figure A.10. De façon comparable à celui des classes, il permet de définir, éditer et effacer une table dans le schéma de correspondances. Le bouton "créer" permet de créer la table sélectionnée dans la base accessible par le curseur affiché dans le panneau principal.

<figure><img src="image_38.png" /><figcaption>Figure A.10 : Panneau des tables</figcaption></figure>
Le bouton "scanner" permet d'aller reconnaître les tables déjà existantes dans la base et de proposer leur utilisation totale ou partielle dans le schéma. Déclencher l'action correspondante provoque l'interrogation de la base au sujet des structures qu'elle comprend et l'apparition du panneau présenté figure A.11.

<figure><img src="image_39.png" /><figcaption>Figure A.11 : Importation du schéma de la base</figcaption></figure>

Ce panneau présente trois ensembles de tables. Le plus à gauche est l'ensemble des structures de la base connectée. Le plus à droite correspond aux tables déjà définies dans le schéma de correspondances courant. Enfin, celui du centre regroupe les tables en cours d'importation dans ce schéma courant.

Les tables et les attributs sont importés de façon indépendante. Ainsi, on peut choisir très précisément les structures relationnelles qu'on souhaite définir dans le schéma de correspondances courant. Si on importe une table ou un attribut qui y existe déjà, l'ancienne définition est écrasée si le booléen **overwrite** des tables ou des attributs est à **T**.

Les importations en cours sont disponibles dans le schéma et exploitables immédiatement après la validation. Par contre, tant que cette validation n'a pas encore été faite, toutes peuvent être annulées en actionnant le bouton "Annuler".

L'éditeur de table est présenté figure A.12. Il permet de mettre à jour le nom de la table et de définir, éditer et effacer ses attributs.

Les noms des attributs étant soumis à une contrainte d'intégrité sont marqués d'un indicateur informant de la nature de cette contrainte :

* K identifie un attribut faisant partie de la clé de la table;

* N identifie un attribut soumis à une contrainte "NOT NULL";

* U identifie un attribut soumis à une contrainte "UNIQUE".
<figure><img src="image_40.png" /><figcaption>Figure A.12 : Édition d'une table</figcaption></figure>

<figure><img src="image_41.png" /><figcaption>Figure A.13 : Édition d'un attribut</figcaption></figure>

L'éditeur d'attribut est présenté figure A.13. Il visualise le nom de la table à laquelle appartient l'attribut et le nom de l'attribut lui-même et permet la mise-à-jour de ses trois autres caractéristiques qui sont son type, sa taille dans ce type, et son statut.

Les types possibles sont ceux retournés par la fonction driver-attribute-types, à savoir par défaut integer, float et string.

Quatre statuts existent : **keypart**, **not-null**, **unique** et **void**. Ils indiquent, pour les trois premiers, la nature de la contrainte d'intégrité qui s'applique à l'attribut considéré, et, pour le dernier, l'absence de contrainte sur l'attribut.
<figure><img src="image_42.png" /><figcaption>Figure A.14 : Panneau des correspondances (1)</figcaption></figure>

La troisième icone du panneau principal de l'interface graphique donne accès à l'éditeur de correspondances présenté figure A.14.

Dans cet éditeur, les classes et leurs champs apparaissent dans la partie gauche du panneau, les tables et leurs attributs, dans la partie droite. En dessous sont successive-ment présentés les critères d'ordre participant aux correspondances des champs de type "ensemble ordonné", les jointures et les variables de table.

Le fait de sélectionner une classe, une table, un champ ou un attribut avec la souris affiche automatiquement sa correspondance sur le panneau si elle existe. Dans l'exemple présenté figure A.14, L'utilisateur a d'abord cliqué sur la classe *Employé*, ce qui a sélectionné la table *emp*. Il a ensuite cliqué sur le champ *num-ss*, ce qui a sélectionné la table *person* et l'attribut *ssnum*, affiché la jointure $J[emp→p]$ et provoqué la mise-à-jour d'un certain nombre d'informations. Au demeurant, le même affichage sur le panneau peut être obtenu en cliquant sur la table *person* puis sur l'attribut *ssnum*.

Quand on sélectionne un élément sans correspondance, les autres scrollers ne réagissent pas. On peut ainsi choisir simultanément des informations dans chacun d'entre eux et créer une correspondance entre elles en cliquant sur le bouton "Associer". Les dissocier s'obtient simplement en sélectionnant l'une d'entre elles et en cliquant sur le bouton "Dissocier".
<figure><img src="image_43.png" /><figcaption>Figure A.15 : Panneau des correspondances (2)</figcaption></figure>

Enfin, ajoutons qu'on peut accéder aux contraintes de classes au moyen du bouton "Contrainte" qui déclenche l'apparition du panneau présenté figure A.9. Par ailleurs, ce panneau donne également accès au gestionnaire de filtres qui est activé par le bouton "Filtre".

La figure A.15 présente un autre exemple d'association au travers de ce même panneau. Cette fois, le champ choisi est le champ **chefs** de la classe **Département**, de type "ensemble ordonné d'objets". La correspondance d'un champ de type "ensemble" étant une chaîne de jointures, aucun attribut n'est sélectionné. Pour les champs objet, la table retenue est la table principale de la classe des objets référencés. Ici, c'est **emp** puisqu'elle est table principale de la classe **Cadre**.

Deux critères d'ordre ont été spécifiés. L'ordre primaire se fait selon les valeurs de l'attribut **sal** par ordre décroissant, et l'ordre secondaire, selon les valeurs de l'attribut **ename** par ordre croissant.

Une demande d'édition d'un ordre appelle l'éditeur présenté figure A.16.

Enfin, une demande d'édition d'une jointure appelle l'éditeur présenté figure A.17.
<figure><img src="image_44.png" /><figcaption>Figure A.16 : Édition d'un critère d'ordre de champ "ensemble"</figcaption></figure>

<figure><img src="image_45.png" /><figcaption>Figure A.17 : Édition d'une jointure</figcaption></figure>
## A.4 Conventions utilisées dans l'exposé des algorithmes

### *Classes*

Variable de nom "Classes" (Nom en italique commençant par une majuscule).

### *function(Arg₁, ..., ArgN)*

Fonction de nom "function" à N arguments (Nom en écriture droite suivi d'une liste d'arguments, éventuellement vide).

### *Var ← value*

### *Var ← Var2*

### *Var ← function(Arg₁, ..., ArgN)*

Affectation de la valeur "value" (resp. de la valeur référencée par la variable "Var2", resp. de la valeur retournée par l'appel fonctionnel function(Arg₁, ..., ArgN)) à la variable de nom "Var".

* Si cette affectation est faite dans l'environnement **soit**, elle est précédée de la création de la variable locale de même nom et c'est cette variable locale qui subit l'affectation. Une variable locale peut ainsi très bien masquer une autre variable, locale ou globale. La portée d'une variable locale est la fonction dans laquelle elle est créée.

* Sinon, l'affectation concerne une variable déjà existante, locale ou globale.

### *Class::method(Arg₁, ..., ArgN).Object*

Méthode de nom "method" définie pour la classe de nom "Class" (N arguments). L'objet auquelle on applique la méthode est référencé par la variable *Object*.

### *message(Arg₁, ..., ArgN).Object*

Envoi du message "message" à l'objet référencé par la variable *Object* (N arguments).

### *field Object*

Accès au champ de nom "field" de l'objet référencé par la variable *Object*.
# Annexe B

## MANUEL DE RÉFÉRENCE
(DRIVER v1.35)
Ce document présente l'interface fonctionnelle de `DRIVER` version 1.35 :

* Sont présentées dans une première partie toutes les fonctions de construction du schéma de correspondances, de manipulation et de suppression de ses composants. Les trois macros `DRIVER-DEFTABLE`, `DRIVER-DEFCLASS` et `DRIVER-DEFCLASSMAP` sont essentielles pour l'utilisateur débutant. Elles permettent à elles seules la description d'un schéma complet (voir l'exemple de schéma §B.6).

* Sont ensuite présentées toutes les primitives de gestion de la couche objet virtuelle, la connexion aux `SGBD`, le filtrage d'objets dans la base, le chargement et l'écriture des objets.

* La prise en compte d'un nouveau modèle objet est décrite en §B.4, une illustration complète pour `SMECI` en §B.8.

* Un exemple de base de données, de schéma de correspondances et de session utilisateur utilisant cette base et ce schéma suivent.

* L'index des erreurs `DRIVER` est donné en §B.9.

* Enfin, l'index des fonctions et variables est donné en §B.10.
## DRIVER

[FEATURE]

Ce trait indique que le module `DRIVER` est chargé en mémoire. Si ce n'est pas le cas, on le charge par `^Ldriver`. Le fichier `driver.11` doit se trouver dans le répertoire courant.

Exemple :

```python
? (FEATUREP 'driver)
= ()
? ^Ldriver
Chargement d'ASQUELL...
Chargement d'ASQUELL oK
Chargement de DRIVER...
DRIVER v1.35
Chargement de DRIVER oK
= driver.11
? (FEATUREP 'driver)
= t
```

# B.1 Construction d'un schéma de correspondances

Les fonctions suivantes permettent de construire un schéma de correspondances à partir de la description des éléments connus des représentations relationnelle et objet à associer. Si les deux représentations et leur couplage sont entièrement décrites, le schéma est complet et directement exploitable. Si leur description n'est que partielle, des primitives permettent de générer les éléments manquants et de compléter le schéma.

## B.1.1 Création et recherche d'un schéma de correspondances

(DRIVER-CREATE-MAPPING `<mapping-name>`. `<overwrite>`)

[SUBR à 1 ou 2 arguments]

Crée et retourne en valeur un nouveau schéma de correspondances de nom `<mapping-name>`. Ce schéma doit être complété au moyen des fonctions du paragraphe suivant avant toute utilisation. Si le schéma est le premier créé lors de la session, il devient automatiquement le schéma courant.

Si la variable système `DRIVER-AFFECT-CURSOR-P` vaut t (valeur par défaut) et si au moins une connexion vers une base a été établie, un curseur est affecté au
nouveau schéma. En cas de redéfinition d'un schéma existant, le curseur courant de ce schéma est préservé.

En cas de tentative de redéfinition d'un schéma, l'erreur "schéma déjà existant" est provoquée, sauf si <overwrite> est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle, ainsi que toutes les définitions qui y étaient rattachées (sauf son éventuel curseur). Toutes les structures qui la contenaient pointent maintenant sur la nouvelle.

Exemple:

```sql
? (DRIVER-CREATE-MAPPING 'map1)
= map1
? (DRIVER-CREATE-MAPPING 'map1)
** driver-create-mapping : existent mapping : map1
? (DRIVER-CREATE-MAPPING 'map1 t)
= map1
```

## DRIVER-AFFECT-CURSOR-P

[Variable]

Si une connexion à une base de données a été préalablement établie au moyen de la fonction `DRIVER-CONNECT`, la valeur de `DRIVER-AFFECT-CURSOR-P` conditionne l'affectation d'un curseur courant aux schémas de correspondances au moment de leurs créations. Si elle vaut t (valeur par défaut), l'affectation est faite. Le curseur choisi est le curseur courant du schéma courant s'il existe, ou celui retourné par la première exécution de `DRIVER-CONNECT` dans le cas contraire.

## (DRIVER-FIND-MAPPING <mapping-name>)

[SUBR à 1 argument]

Retourne le schéma de correspondances de nom `<mapping-name>` s'il existe.

Exemple:

```sql
? (DRIVER-FIND-MAPPING 'map1)
= map1
? (DRIVER-FIND-MAPPING 'map2)
= ()
```

## (DRIVER-MAPPING-P <mapping>)

[SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet `<mapping>` si ce dernier est un schéma de correspondances.

Exemple:
```sql
? (DRIVER-MAPPING-P 'map1)
= ()
? (DRIVER-MAPPING-P (DRIVER-FIND-MAPPING 'map1))
= map1
```

### (DRIVER-CURRENT-MAPPING <mapping-name>)

### (DRIVER-CURRENT-MAPPING0 <mapping>) [SUBR à 0 ou 1 argument]

Variables-fonctions permettant d'accéder au schéma de correspondances courant si `<mapping-name>` (resp. l'objet `<mapping>`) n'est pas fourni, et de le définir dans le cas contraire.

Exemple:

```sql
? (DRIVER-CURRENT-MAPPING)
= map1 ; initialise par le premier DRIVER-CREATE-MAPPING
? (DRIVER-CREATE-MAPPING 'map2)
= map2
? (DRIVER-CURRENT-MAPPING)
= map1
? (DRIVER-CURRENT-MAPPING 'map2)
= map2
? (DRIVER-CURRENT-MAPPING)
= map2
? (DRIVER-CURRENT-MAPPING0 (DRIVER-FIND-MAPPING 'map1))
= map1
? (DRIVER-CURRENT-MAPPING0)
= map1
```

### (DRIVER-ALL-MAPPINGS <all-p>)

[SUBR à 0 ou 1 argument]

Sans argument, cette fonction renvoie la liste de tous les schémas de correspondances de l'utilisateur créés depuis le début de la session. Si le paramètre t est précisé, tous les schémas seront renvoyés, y compris les schémas système (le méta-schéma, par exemple).

Exemple:

```sql
? (DRIVER-ALL-MAPPINGS)
= (map1 map2)
? (DRIVER-ALL-MAPPINGS t)
= (map1 map2)
? (DRIVER-METAMAPPING)
= driver-metamapping
? (DRIVER-ALL-MAPPINGS t)
= (map1 map2 driver-metamapping)
```
(DRIVER-COMPILE-MAPPING `<mapping-name>`)

(DRIVER-COMPILE-MAPPING0 `<mapping>`)

[SUBR à 1 argument]

Compile le schéma de correspondances de nom `<mapping-name>` (resp. l'objet `<mapping>`). Cette opération, qui accélère les échanges d'objets entre l'environnement et la base de données, ne doit être faite que quand le schéma est terminé. Toute nouvelle modification du schéma annihile sa compilation.

Exemple:

? (DRIVER-COMPILE-MAPPING 'map1)
= t

(DRIVER-DELETE-MAPPING `<mapping-name>`)

(DRIVER-DELETE-MAPPING0 `<mapping>`)

[SUBR à 1 argument]

Supprime le schéma de correspondances de nom `<mapping-name>` (resp. l'objet `<mapping>`) dans l'environnement. Toutes les données qu'il contient sont également perdues.

Exemple:

? (DRIVER-DELETE-MAPPING 'map2)
= t

## B.1.2 Description de la représentation relationnelle

Les fonctions suivantes s'appliquent toutes au schéma de correspondances courant.

Elles permettent de décrire la représentation relationnelle et de définir dans le schéma des tables et des attributs.

(DRIVER-DEFTABLE `<table-name> <attr1> ... <attrN>`)

[MACRO]

définit dans le schéma courant une table de nom `<table-name>` (symbole), comportant les attributs `<attr1> ... <attrN>`. L'ordre utilisé pour décrire ces attributs sera repris pour l'éventuelle création de la table considérée. Cette macro crée une table et chacun de ses attributs spécifiés.

`<attr1> ... <attrN>` décrivent les attributs de la table. Ce sont des listes à 4 éléments ayant la structure suivante :

`(<attribute-name> <attr-type> <type-length> <status>)`
Le type de l'attribut, la longueur de ce type ainsi que le statut de l'attribut doivent être spécifiés.

Les types d'attribut possibles sont par défaut *integer*, *float* et *string*. Cette liste peut être complétée en fonction de la base de données utilisée et des types qu'elle reconnaît au moyen de la fonction `DRIVER-ADD-ATTRIBUTE-TYPE`. Elle est consultée à chaque création d'attribut.

Les différents statuts possibles sont :

**unique** Il ne peut exister deux n-uplets de la table ayant même valeur (différente de null) pour l'attribut en question.

**not-null** L'attribut ne peut valoir null. Un nouveau n-uplet qu'on insère dans la table doit nécessairement définir une valeur pour l'attribut en question.

**keypart** L'attribut fait partie de la clé de la table.

**void ou ()** L'attribut est classique. Il n'a pas de statut particulier.

Si la variable globale `DRIVER-TABLE-MAKE` vaut t (la valeur par défaut est `nil`), la fonction `DRIVER-MAKE-TABLE0` est appelée et se traduit par la définition dans le SGBD courant de la relation correspondante.

`DRIVER-DEFTABLE` peut être décrit en lisp de la manière suivante (les fonctions `DRIVER-CREATE-TABLE` et `DRIVER-CREATE-ATTRIBUTE0` sont explicitées ci-après) :

```
(DEFMACRO DRIVER-DEFTABLE (name . attr-list)
    '(LET ((table (DRIVER-CREATE-TABLE ',name t)))
           ,@(MAPCAR (LAMBDA (attr)
                       '(DRIVER-CREATE-ATTRIBUTE0 table
                                              ,@(MAPCAR 'KWOTE attr)))))
           attr-list)
    (IF DRIVER-TABLE-MAKE
        (DRIVER-MAKE-TABLE0 table))
    table))
```

Exemple:

```
? (DRIVER-DEFTABLE emp
?                 (empno integer 2 keypart)
?                 (ename string 20 not-null)
?                 (fname string 18 ()
?                 (job   string 20 ()
?                 (sal   float  8 ()
?                 (mgr   integer 2 ()
?                 (dpt   integer 2 ()))
= emp
```
```
? (DRIVER-DEFTABLE vehicle
?                 (vnum   integer 2 keypart)
?                 (model  string 15 ())
?                 (licence string 15 unique))
= vehicle
```

## DRIVER-TABLE-MAKE

[Variable]

Si la variable globale `DRIVER-TABLE-MAKE` vaut t (valeur par défaut), la fonction `DRIVER-MAKE-TABLE0` est exécutée à la fin de la déclaration d'une table par `DRIVER-DEFTABLE` et se traduit par la définition dans le SGBD courant de la relation correspondante.

## (DRIVER-CREATE-TABLE <table-name> . <overwrite>)

[SUBR à 1 ou 2 arguments]

Définit la table de nom `<table-name>` dans le schéma courant. Cette définition est initialement vide d'attribut. Les attributs correspondants devront être créés au moyen de la fonction `DRIVER-CREATE-ATTRIBUTE`.

En cas de tentative de redéfinition d'une table, l'erreur "table déjà existante" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle, ainsi que toutes les définitions d'attributs qui l'utilisaient. Toutes les structures qui la contenaient pointent maintenant sur la nouvelle.

Exemple:

```
? (DRIVER-CREATE-TABLE 'person)
= person
? (DRIVER-CREATE-TABLE 'address)
= address
? (DRIVER-CREATE-TABLE 'dept)
= dept
? (DRIVER-CREATE-TABLE 'company)
= company
```

## (DRIVER-FIND-TABLE <table-name>)

[SUBR à 1 argument]

Retourne la table de nom `<table-name>` si elle existe dans le schéma courant.

Exemple:

```
? (DRIVER-FIND-TABLE 'person)
= person
```
(DRIVER-TABLE-P <table>)

[SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet <table> si ce dernier est une table.

Cette fonction est strictement identique à la fonction DRIVER-TABLE-VAR-P.

Exemple:

? (DRIVER-TABLE-P (DRIVER-FIND-TABLE 'person))
= person

(DRIVER-DELETE-TABLE <table-name>)

(DRIVER-DELETE-TABLE0 <table>)

[SUBR à 1 argument]

Détruit la table de nom <table-name> (resp. l'objet <table>) dans le schéma cou-
rant (définition et variables). Par effet de bord, les attributs définis dans cette table
sont également détruits. De même, toutes les références à la table sont retirées du
schéma de correspondances.

Cette fonction est strictement identique à la fonction DRIVER-DELETE-TABLE-DEF.

Exemple:

? (DRIVER-DELETE-TABLE 'company)
= t

(DRIVER-CREATE-ATTRIBUTE <table-name> <attr-name>

<attr-type> <typ-len> <status> . <overwrite>)

(DRIVER-CREATE-ATTRIBUTE0 <table> <attr-name>

<attr-type> <typ-len> <status> . <overwrite>)

[SUBR à 5 ou 6 arguments]

Définit l'attribut de nom <attr-name> dans la table de nom <table-name> (resp. à l'objet <table>). Le type de l'attribut, la longueur de ce type ainsi que le statut de l'attribut doivent être spécifiés.

Les types d'attribut possibles sont par défaut *integer*, *float* et *string*. Cette liste peut être complétée en fonction de la base de données utilisée et des types qu'elle reconnaît au moyen de la fonction DRIVER-ADD-ATTRIBUTE-TYPE. Elle est consultée à chaque création d'attribut.

Les différents statuts possibles sont :

**unique** Il ne peut exister deux n-uplets de la table ayant même valeur (différente de *null*) pour l'attribut en question.
**not-null** L'attribut ne peut valoir *null*. Un nouveau n-uplet qu'on insère dans la table doit nécessairement définir une valeur pour l'attribut en question.

**keypart** L'attribut fait partie de la clé de la table.

**void ou ()** L'attribut est classique. Il n'a pas de statut particulier.

En cas de tentative de redéfinition d'un attribut, l'erreur "Attribut déjà existant" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle. Toutes les structures qui le contenaient pointent maintenant sur la nouvelle.

Exemple:

```
? (DRIVER-CREATE-ATTRIBUTE 'person 'fname 'string 20 'keypart)
= person.fname
? (DRIVER-CREATE-ATTRIBUTE 'person 'fname 'string 18 'keypart)
= person.fname
? (DRIVER-CREATE-ATTRIBUTEEO
? (DRIVER-FIND-TABLE 'person) 'ssnum 'string 15 'unique)
= person.ssnum
? (DRIVER-CREATE-ATTRIBUTE 'person 'position 'string 10())
= person.weight
? (DRIVER-CREATE-ATTRIBUTE 'person 'car 'integer 2())
= person.car
? (DRIVER-CREATE-ATTRIBUTE 'address 'empno 'integer 2 'keypart)
= address.empno
? (DRIVER-CREATE-ATTRIBUTE 'address 'state 'string 5())
= address.empno
? (DRIVER-CREATE-ATTRIBUTE 'dept 'deptnum 'integer 2 'keypart)
= dept.deptnum
```

### (DRIVER-ATTRIBUTE-TYPES)

[SUBR sans argument]

Retourne la liste des types d'attribut reconnus par `DRIVER`.

```
? (DRIVER-ATTRIBUTE-TYPES)
= (integer float string)
```

### (DRIVER-ADD-ATTRIBUTE-TYPE <newtype>)

[SUBR à 1 argument]

Définit un nouveau type d'attribut. Cette fonction permet de compléter la liste des types utilisables disponibles dans le SGBD utilisé.

**ATTENTION**: cette fonction ne vérifie pas que le SGBD reconnaît effectivement le type rajouté.

Exemple:
```sql
? (DRIVER-CREATE-ATTRIBUTE 'vehicle' 'vdate' 'date' ()())
*** driver-create-attribute : Bad attribute type : date
? (DRIVER-ADD-ATTRIBUTE-TYPE 'date')
= date
? (DRIVER-CREATE-ATTRIBUTE 'vehicle' 'vdate' 'date' ()())
= vehicle.vdate
```

(DRIVER-FIND-ATTRIBUTE <table-name> <attr-name>)

(DRIVER-FIND-ATTRIBUTE0 <table> <attr-name>)

[SUBR à 2 arguments]

Retourne l'attribut de nom <attr-name> de la table de nom <table-name> (de la table <table>) si elle existe.

La fonction DRIVER-FIND-ATTRIBUTE est strictement identique à la fonction DRIVER-FIND-ATTRIBUTE-VAR.

Exemple:

```sql
? (DRIVER-FIND-ATTRIBUTE 'emp' 'empno')
= emp.empno
? (DRIVER-FIND-ATTRIBUTE 'address' 'empno')
= address.empno
```

(DRIVER-ATTRIBUTE-P <attr>)

[SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet <attr> si ce dernier est un attribut.

Cette fonction est strictement identique à la fonction DRIVER-ATTRIBUTE-VAR-P.

Exemple:

```sql
? (DRIVER-ATTRIBUTE-P (DRIVER-FIND-ATTRIBUTE 'emp' 'empno'))
= emp.empno
```

(DRIVER-DELETE-ATTRIBUTE <table-name> <attr-name>)

[SUBR à 2 arguments]

(DRIVER-DELETE-ATTRIBUTE0 <attr>)

[SUBR à 1 argument]

Détruit l'attribut de nom <attr-name> dans la table de nom <table-name> (resp. l'objet <attr>) dans le schéma courant (définition et variables). Toutes les références à l'attribut sont retirées du schéma de correspondances.

La fonction DRIVER-DELETE-ATTRIBUTE est strictement identique à la fonction DRIVER-DELETE-ATTRIBUTE-DEF.

Exemple:
? (DRIVER-DELETE-ATTRIBUTE 'vehicle 'vdate)
= t

(DRIVER-TABLE-ATTRIBUTES <table-name>)

(DRIVER-TABLE-ATTRIBUTES0 <table>)

[SUBR à 1 argument]

Renvoie dans l'ordre de leurs créations les attributs associés à une table. Ce même
ordre est utilisé pour une éventuelle création de la relation correspondante dans la
base de données relationnelle.

Les fonctions DRIVER-TABLE-ATTRIBUTES[0] sont strictement identiques aux
fonctions DRIVER-TABLEVAR-ATTRVARS[0].

Exemple:

? (DRIVER-TABLE-ATTRIBUTES 'person)
= (person.pname person.fname person.ssnum person(position person.car)

B.1.3 Description de la représentation objet

Les fonctions suivantes s'appliquent toutes au schéma de correspondances courant.

Elles permettent de décrire la représentation objet et d'ajouter au schéma des défini-
tions de classes et de champs.

(DRIVER-DEFCLASS <class-name> <super-class-name>

<field1> ... <fieldN>)
[MACRO]

définit dans le schéma courant une classe de nom <class-name>, sous-classe de la
classe de nom <super-class-name> (seul l'héritage simple est autorisé), comportant
les champs <field1> ... <fieldN>. L'ordre utilisé pour décrire ces champs sera repris
pour l'éventuelle création de la classe considérée.

<field1> ... <fieldN> décrivent les champs de la classe. Ce sont des listes d'au moins
3 éléments ayant la structure suivante :

(<field-name> <field-type> <specific-type-info> . <options>)

Le type du champ doit être un symbole appartenant à la liste des types possibles :
(atom atomset ordatomset object object2 objectset ordobjset object2set ordobj2set
monotexpr multitexpr). L'élément <specific-type-info> possède une sémantique qui
varie en fonction du type du champ. (voir la fonction DRIVER-CREATE-FIELD).

Une option se présente sous la forme d'une liste à au moins deux éléments dont le
premier est le nom de l'option et le ou les suivants donnent son expression ou sa
valeur. Elles permettent par exemple de préciser comment calculer la valeur initiale
du champ à la création de l'instance, ou encore, de contraindre un champ atomique.
Voir la fonction `DRIVER-CREATE-FIELD`.

Il est également possible de contraindre un champ atomique ou de renforcer une contrainte posée sur un champ atomique défini dans une classe mère. `<fieldM>` est alors une liste à deux éléments dont le premier est le nom du champ et le second l'option contrainte, à savoir la liste composée du symbole `constraint` et de l'expression de la contrainte (lambda) telle qu'elle est spécifiée dans la description de la fonction `DRIVER-CREATE-FIELD-CONSTRAINT`.

Si la variable globale `DRIVER-CLASS-MAKE` vaut t (valeur par défaut), la fonction `DRIVER-MAKE-CLASS0` est appelée et se traduit par la définition dans le langage objet client de la classe correspondante.

`DRIVER-DEFCLASS` peut être décrit en lisp de la manière suivante (les fonctions `DRIVER-CREATE-CLASS`, `DRIVER-CREATE-FIELD0` et `DRIVER-CREATE-CLASS-CONSTRAINT` sont explicitées ci-après) :

```
(DEFMACRO DRIVER-DEFCLASS (name super-class-name . field-list)
'(
  (LET ((class (DRIVER-CREATE-CLASS ',name
',super-class-name t)))
    ,@(MAPCAR
      (LAMBDA (field)
        (IF (AND (CONSP (CADR field))
              (EQ (CAADR field) 'constraint)))
        '(DRIVER-CREATE-FIELD-CONSTRAINT ',name
        ',(CAR field) ',(CADADR field)))
        '(DRIVER-CREATE-FIELD0 class
          ,@(MAPCAR 'KWOTE field))))
  field-list)
  (IF DRIVER-CLASS-MAKE
    (DRIVER-MAKE-CLASS0 class))
  class))
```

Exemple:

```
? (DRIVER-DEFCLASS Employe ()
?       (nom      atom      symbol)
?       (prenom    atom      symbol)
?       (num-ss   atom      string)
?       (qualif   atom      symbol)
?       (chef     object    Employe)
?       (salaire  atom      float)
?       (grade    atom      fix (initval 0))
?       (adresse   object    Adresse)
?       (vehicule  object    Vehicule))
```
= Employe
? (DRIVER-DEFCLASS Vendeur Employe
? (qualif (constraint
? (LAMBDA (qual) (EQ qual 'salesman)))))
? (situ-famille atom symbol)
? (commission atom float)
? (sal-total monotexpr float))

= Vendeur

? (DRIVER-DEFCLASS Departement ()
? (nom atom symbol)
? (site atom symbol (initval 'New-York)
? (constraint (LAMBDA (s) (MEMQ s
? ('(New-York Washington Boston)))))
? (chefs ordobjset Employe)
? (personnel objectset Employe)
? (moy-sal multitexpr float))

= Departement

DRIVER-CLASS-MAKE

[Variable]

Si la variable globale DRIVER-CLASS-MAKE vaut t (valeur par défaut), la fonction
DRIVER-MAKE-CLASS0 est exécutée à la fin de la déclaration d'une classe par
DRIVER-DEFCLASS et se traduit par la définition dans le langage objet client de
la classe correspondante.

(DRIVER-CREATE-CLASS <class-name>

<super-class-name> . <overwrite>)

[SUBR à 2 ou 3 arguments]

Ajoute la description de la classe de nom <class-name>, sous-classe de la classe
de nom <super-class-name>, dans le schéma courant. Cette description est initia-
lement vide de champ. Les champs correspondants devront être créés au moyen de
la fonction DRIVER-CREATE-FIELD. En cas de tentative de redéfinition d'une
classe, l'erreur "classe déjà existante" est provoquée, sauf si <overwrite> est pré-
cisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle, ainsi
que toutes les informations qu'elle contenait. Toutes les structures qui l'utilisaient
pointent maintenant sur la nouvelle.

Exemple:

? (DRIVER-CREATE-CLASS 'Adresse())
= Adresse
? (DRIVER-CREATE-CLASS 'Vendeur-informatique 'Vendeur)
= Vendeur-informatique
(DRIVER-FIND-CLASS <class-name>)

[SUBR à 1 argument]

Retourne la description de classe de nom <class-name> si elle existe dans le schéma courant.

Exemple:

? (DRIVER-FIND-CLASS 'Employe)
= Employe
?
( DRIVER-FIND-CLASS 'Projet)
= ()

(DRIVER-FIND-MAIN-CLASS <class-name>)

(DRIVER-FIND-MAIN-CLASS0 <class>)

[SUBR à 1 argument]

Renvoie la classe principale de la classe de nom <class-name> (de l'objet <class>).
Une classe principale est une classe qui n'a pas de classe mère décrite dans le schéma.

Exemple:

? (DRIVER-FIND-MAIN-CLASS 'Vendeur-informatique)
= Employe

(DRIVER-MAIN-CLASSES)

[SUBR sans argument]

Retourne l'ensemble des classes principales décrites dans le schéma de correspondances courant.

Exemple:

? (DRIVER-MAIN-CLASSES)
= (Employe Departement Adresse)

(DRIVER-CLASS-SUBCLASSES <class-name>)

(DRIVER-CLASS-SUBCLASSES0 <class>)

(DRIVER-DIRECT-SUBCLASSES <class-name>)

(DRIVER-DIRECT-SUBCLASSES0 <class>)

[SUBR à 1 argument]

Les fonctions DRIVER-CLASS-SUBCLASSES(0) renvoient toutes les sous-classes
de la classe de nom <class-name> (resp. l'objet <class>); les fonctions DRIVER-
DIRECT-SUBCLASSES(0) ne renvoient que les sous-classes directes.

Exemple:
? (DRIVER-CLASS-SUBCLASSES 'Employe)
= (Vendeur Vendeur-informatique)
? (DRIVER-DIRECT-SUBCLASSES 'Employe)
= (Vendeur)

(DRIVER-CLASS-P <class>) [SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet <class> si ce dernier est une description de
classe.

Exemple:

? (DRIVER-CLASS-P (DRIVER-FIND-CLASS 'Employe))
= Employe

(DRIVER-DELETE-CLASS <class-name>)
(DRIVER-DELETE-CLASS0 <class>) [SUBR à 1 argument]

Détruit la description de classe de nom <class-name> (resp. l'objet <class>) dans
le schéma courant. Par effet de bord, les champs définis dans cette classe sont éga-
lement détruits. De même, toutes les références à la classe sont retirées du schéma
de correspondances.

Exemple:

? (DRIVER-DELETE-CLASS 'Vendeur-informatique)
= t

(DRIVER-CREATE-FIELD <class-name> <field-name> <ftype>
<options> . <overwrite>)

(DRIVER-CREATE-FIELD0 <class> <field-name> <ftype>
<options> . <overwrite>)
[SUBR de 3 à 6 arguments]

Ajoute la description du champ de nom <field-name> à la classe de nom <class-name> (resp. l'objet <class>) dans le schéma courant. Le type du champ doit être spécifié ainsi que certaines informations propres à chaque type. L'ensemble des types possibles est (atom atomset ordatomset object object2 objectset ordobjset object2set ordobj2set monotexpr multitexpr) :
**atom** Type *atomique*. Ce type caractérise le champ atomique destiné à contenir une information élémentaire. Il doit être précisé immédiatement après dans la liste des paramètres par un sous-type. Six valeurs existent par défaut; elles sont *symbol*, *string*, *fix* (ou *integer*), *float* et () (divers ou inconnu). Cette liste peut être complétée en fonction du modèle objet utilisé et des types qu'il reconnaît au moyen de la fonction *DRIVER-ADD-ATOMIC-FIELD-TYPE*. Elle est consultée à chaque création de champ atomique.

Des paramètres optionnels peuvent être précisés. Ils se présentent sous forme de listes à au moins deux éléments dont le premier est le nom de l'option et le ou les suivants donnent son expression ou sa valeur. Ces options sont :

**initval** Ce mot-clé introduit une forme Lisp qui va permettre de calculer la valeur initiale du champ. La forme est évaluée lors de la création de chaque instance. Attention donc de bien "coter" les constantes symboliques ou les listes qui ne sont pas des appels fonctionnels. Cette option peut être utilisée avec tous les types de champ.

**constraint** Cet autre mot-clé introduit une forme Lisp qui va permettre de contraindre les champs de type atomique (et uniquement les champs de ce type). L'expression est une lambda à un paramètre qui sera évaluée pour toute valeur candidate du champ (voir la description de *DRIVER-CREATE-FIELD-CONSTRAINT*).

**localp** Ce mot-clé permet de déclarer le champ comme ne faisant pas partie en fait de la classe `<class-name>`, mais d'une de ses classes mère. Il ne présente donc à proprement parler aucun intérêt pour la déclaration de la classe. Il permet simplement de signaler l'existence du champ `<field-name>` plus "haut" dans la hiérarchie, de façon à pouvoir lui définir une correspondance relationnelle au niveau de la classe `<class-name>` au moyen des fonctions *DRIVER-DEFCLASSMAP* et *DRIVER-MAP-FIELD* pour le cas où la classe mère le possédant ne serait pas persistante. Par défaut, un champ est considéré comme local.

**atomset** Type *ensemble d'atomes*. Ce type doit également être immédiatement précisé d'un argument qui définit lui le type de l'élément de l'ensemble. Les remarques effectuées pour le type *atom* restent valables.

**ordatomset** Type *ensemble ordonné d'atomes*. Ce type se rapproche du précédent. Néanmoins, l'ordre des éléments est ici important, ce qui n'était pas le cas pour le type *atomset*.

**object** Type *objet*. Ce type caractérise les champs destinés à recevoir un objet. Il doit être précisé immédiatement après dans la liste des paramètres par le nom de la classe des objets à contenir.

**object2** Type *objet 2*. Il peut arriver qu'un champ objet soit amené à contenir des objets dont on ne puisse pas à l'avance connaître la classe. Cette seconde catégorie de champ objet est prévue pour ceux-là.
**objectset** Type *ensemble d'objets*. Ce type caractérise les champs destinés à recevoir un ensemble d'objets. Comme pour le type *objet*, il doit être immédiate-ment suivi par le nom de la classe commune aux objets éléments de l'ensemble.

**ordobjset** Type *ensemble ordonné d'objets*. Ce type se rapproche du précédent. Néanmoins, l'ordre des éléments est ici important, ce qui n'était pas le cas pour le type *objectset*.

**object2set** Type *ensemble d'objets 2*. Ce type caractérise les champs destinés à recevoir un ensemble d'objets de classes différentes et indépendantes (de classe principale différente).

**ordobj2set** Type *ensemble ordonné d'objets 2*. Ce type se rapproche du précédent. Néanmoins, l'ordre des éléments est ici important, ce qui n'était pas le cas pour le type *object2set*.

**monotexpr** Type *expression mono n-uplet*.

**multitexpr** Type *expression multi n-uplet*.

Ces deux derniers types permettent de caractériser une catégorie particulière de champ atomique. Ils ne peuvent être utilisés avec intérêt que dans la perspective du rapprochement de la représentation objet avec une représentation relationnelle. Les champs correspondants ne peuvent être consultés qu'en lecture. Ils sont destinés à recevoir le produit d'un calcul effectué dans la base de données.

Le premier des deux effectue ce calcul sur un seul *n-uplet*, associé généralement à l'objet considéré; Somme ou différence d'attributs du *n-uplet* sont des exemples d'expressions possibles.

Le second effectue le calcul sur un ensemble de *n-uplets*, correspondant éventuellement à un ensemble d'objets. Ce genre de calcul permet de calculer par exemple une moyenne ou la somme d'un ensemble de valeurs.

En cas de tentative de redéfinition d'un champ, l'erreur "champ déjà existant" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle. Toutes les structures qui la contenaient pointent maintenant sur la nouvelle.

Exemple:

```
? (DRIVER-CREATE-FIELD 'Adresse 'numero 'atom 'fix)
= numero
? (DRIVER-CREATE-FIELD 'Adresse 'ville 'atom 'symbol
? '(initval 'New-York))
= ville
? (DRIVER-CREATE-FIELDO
? (DRIVER-FIND-CLASS 'Adresse) 'etat 'atom 'string
? '(constraint (LAMBDA (val)
? (MEMQ val '(NY MA CA)))))
```
```
= etat
? (DRIVER-CREATE-FIELD 'Employe 'vehicule2 'object 'Vehicule
?                 '(initval (OMAKEQ #:tclass:Vehicule)))
= vehicule2
```

### (DRIVER-FIELD-TYPE <class-name> <field-name>)

[SUBR à 2 arguments]

### (DRIVER-FIELD-TYPE0 <field>)

[SUBR à 1 argument]

Retourne le type du champ de nom <field-name> de la classe de nom <class-name> (resp. la classe <class-name>).

Exemple :

```
? (DRIVER-FIELD-TYPE 'Employe 'chef)
= object
```

### (DRIVER-ATOMIC-FIELD-TYPES)

[SUBR sans argument]

Retourne la liste des types atomiques de champ reconnus par DRIVER.

```
? (DRIVER-ATOMIC-FIELD-TYPES)
= ((() integer fix float string symbol)
```

### (DRIVER-ADD-ATOMIC-FIELD-TYPE <newtype>) [SUBR à 1 argument]

Définit un nouveau type de champ atomique. Cette fonction permet de compléter la liste des types utilisables disponibles dans le modèle objet utilisé.

**ATTENTION** : cette fonction ne vérifie pas que le modèle objet reconnaît effective-ment le type rajouté.

Exemple :

```
? (DRIVER-CREATE-FIELD 'Adresse 'rue 'atom 'doublestring)
*** driver-create-field : Bad field subtype : doublestring
? (DRIVER-ADD-ATOMIC-FIELD-TYPE 'doublestring)
= doublestring
? (DRIVER-CREATE-FIELD 'Adresse 'rue 'atom 'doublestring)
= rue
```
(DRIVER-FIND-FIELD <class-name> <field-name>)

(DRIVER-FIND-FIELD0 <class> <field-name>)

(DRIVER-FIND-HERITED-FIELD <class-name> <field-name>)

(DRIVER-FIND-HERITED-FIELD0 <class> <field-name>)

(DRIVER-FIND-FIELD-IN-BRANCH <classname> <fieldname>)

(DRIVER-FIND-FIELD-IN-BRANCH0 <class> <fieldname>)

[SUBR à 2 arguments]

Les fonctions DRIVER-FIND-FIELD(0) retournent la description du champ de nom <field-name> de la classe de nom <class-name> (resp. l'objet <class>) si elle existe.

Les fonctions DRIVER-FIND-HERITED-FIELD(0) retournent la description du champ de nom <field-name> de la classe de nom <class-name> (resp. l'objet <class>) ou de l'une de ses classes mère, si cette description existe.

Les fonctions DRIVER-FIND-FIELD-IN-BRANCH(0) retournent la description du champ de nom <field-name> si elle existe dans la branche de la classe de nom <class-name> (resp. l'objet <class>). On appelle branche d'une classe l'ensemble de ses classes ancêtres jusqu'à la classe principale incluse, plus toutes ses classes descendantes (classes filles).

Exemple:

? (DRIVER-FIND-FIELD 'Employe 'nom)
= nom
? (DRIVER-FIND-FIELD 'Vendeur 'qualif)
= ()
? (DRIVER-FIND-HERITED-FIELD 'Vendeur 'qualif)
= qualif
? (DRIVER-FIND-FIELD-IN-BRANCH 'Employe situ-famille)
= situ-famille

(DRIVER-FIND-FIELD-CLASS-IN-HIERARCHY <classname> <fieldname>)

(DRIVER-FIND-FIELD-CLASS-IN-HIERARCHY0 <class> <fieldname>)

[SUBR à 2 arguments]

Recherche la classe dans laquelle se trouve le champ de nom <fieldname>. La recherche est effectuée dans la hiérarchie de la classe de nom <classname> (resp. l'objet <class>). Si plusieurs champs ont ce même nom, retourne la première classe qu'elle trouve qui possède un champ de ce nom.

Exemple :

? (DRIVER-FIND-FIELD-CLASS-IN-HIERARCHY 'Vendeur 'prenom)
= Employe
(DRIVER-FIELD-P <field>)
(DRIVER-ATOM-FIELD-P <field>)
(DRIVER-ATOMSET-FIELD-P <field>)
(DRIVER-ORDATOMSET-FIELD-P <field>)
(DRIVER-OBJECT-FIELD-P <field>)
(DRIVER-OBJECT2-FIELD-P <field>)
(DRIVER-SET-FIELD-P <field>)
(DRIVER-OBJECTSET-FIELD-P <field>)
(DRIVER-OBJECT2-FIELD-P <field>)
(DRIVER-ORDOBJSET-FIELD-P <field>)
(DRIVER-ORDOBJ2SET-FIELD-P <field>)
(DRIVER-MONOTEXPR-FIELD-P <field>)
(DRIVER-MULTITEXPR-FIELD-P <field>) [SUBR à 1 argument]

Le prédicat DRIVER-FIELD-P est vrai et renvoie l'objet <field> si ce dernier est un champ. Même chose pour ses pendants, avec un test portant sur les différents types de champs.

Exemple:

? (DRIVER-FIELD-P (DRIVER-FIND-FIELD 'Employe 'nom))
= nom
? (DRIVER-SET-FIELD-P (DRIVER-FIND-FIELD 'Employe 'nom))
= ()

(DRIVER-DELETE-FIELD <class-name> <field-name>)

[SUBR à 2 arguments]

(DRIVER-DELETE-FIELD0 <field>) [SUBR à 1 argument]

Détruit la description de champ de nom <field-name> de la classe de nom <class-name> (resp. l'objet <field>) dans le schéma courant. Par effet de bord, toute correspondance définie sur le champ est également détruite.

Exemple:

? (DRIVER-DELETE-FIELD 'Employe 'vehicule2)
= t

(DRIVER-CLASS-FIELD-P <class> <field>)
(DRIVER-HERITED-FIELD-P <class> <field>) [SUBR à 2 arguments]
Le prédicat `DRIVER-CLASS-FIELD-P` est vrai et renvoie l'objet `<field>` si ce dernier est une description de champ de la classe `<class>`. Le prédicat `DRIVER-HERITED-FIELD-P` est vrai et renvoie l'objet `<field>` si ce dernier est une description de champ de la classe `<class>` ou de l'une de ses classes mère.

Exemple:

```pascal
? (DRIVER-CLASS-FIELD-P (DRIVER-FIND-CLASS 'Employe))
? (DRIVER-FIND-FIELD 'Employe 'prenom))
= prenom
? (DRIVER-CLASS-FIELD-P (DRIVER-FIND-CLASS 'Vendeur))
? (DRIVER-FIND-FIELD 'Employe 'prenom))
= ()
? (DRIVER-HERITED-FIELD-P (DRIVER-FIND-CLASS 'Vendeur))
? (DRIVER-FIND-FIELD 'Employe 'prenom))
= prenom
```

(DRIVER-CREATE-FIELD-CONSTRAINT `<class-name>`
`<field-name> <lambda> . <overwrite>`) [SUBR à 3 ou 4 arguments]

(DRIVER-CREATE-FIELD-CONSTRAINT0 `<field>`
`<lambda> . <overwrite>`) [SUBR à 2 ou 3 arguments]

Cette fonction permet de poser une contrainte simple sur un champ atomique.

Cette contrainte s'exprime sous la forme d'une lambda à un argument qui représente la valeur à affecter au champ. Si l'application de la lambda avec une valeur possible pour le champ renvoie vrai au sens lisp, la contrainte est respectée; elle ne l'est pas dans le cas contraire. L'expression (unique) constituant le corps de la lambda peut faire appel aux primitives lisp suivantes : `and`, `or`, `not`, `=`, `eq`, `neq`, `neqn`, `null`, `<>`, `<`, `<=`, `>`, `>=`, `memq` et `nmemq` (`(notmemq)`). Les primitives à deux arguments doivent être utilisées avec la variable comme premier argument et une constante comme second.

L'usage de l'ensemble des primitives lisp de l'interprète n'est pas autorisé car `DRIVER` devra pouvoir compiler l'expression en SQL.

En cas de tentative de redéfinition d'une contrainte déjà définie sur le champ dans la même classe, l'erreur "contrainte déjà existante" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue et écrasée par la nouvelle. Toutes les descriptions qui l'utilisaient pointent maintenant sur la nouvelle.

Exemple:
```sql
? (DRIVER-CREATE-FIELD-CONSTRAINT 'Employe 'qualif
?         '(LAMBDA (value)
?         (OR (NULL value)
?         (MEMQ value
?                 '(chairman director salesman
?                 engineer secretary))))
= Cstr<Employe[qualif]>
? (DRIVER-CREATE-FIELD-CONSTRAINT 'Employe 'salaire
?         '(LAMBDA (val)
?         (AND (> = val 1000.) (< val 10000.))))
= Cstr<Employe[salaire]>
? (DRIVER-CREATE-FIELD-CONSTRAINT 'Vendeur 'commission
?         '(LAMBDA (comm)
?         (OR (MEMQ comm '(100. 200. 300. 500.))
?                 (> = comm 800.))))
= Cstr<Vendeur[commission]>
```

(DRIVER-FIND-CLASS-CONSTRAINT `<class-name>` `<field-name>`)

(DRIVER-FIND-CLASS-CONSTRAINT0 `<class>` `<field>`)

[SUBR à 2 arguments]

Retourne la contrainte définie pour la classe de nom `<class-name>` (resp. l'objet `<class>`) sur le champ de nom `<field-name>` (resp. l'objet `<field>`) si elle existe.

Complément d'information sur ces deux fonctions dans la partie *Description des correspondances*.

Exemple:

```sql
? (DRIVER-FIND-CLASS-CONSTRAINT 'Employe 'qualif)
= Cstr<Employe[qualif]>
```

(DRIVER-FIND-FIELD-CONSTRAINTS-ON-CLASS `<class-name>`)

(DRIVER-FIND-FIELD-CONSTRAINTS-ON-CLASS0 `<class>`)

[SUBR à 1 argument]

Renvoie l'ensemble des contraintes qui s'appliquent aux champs de la classe de nom `<class-name>` (de l'objet `<class>`). Une contrainte définie sur le champ d'une classe masque l'eventuelle contrainte posée sur le même champ dans une classe mère.

Exemple:

```sql
? (DRIVER-FIND-FIELD-CONSTRAINTS-ON-CLASS 'Vendeur)
= (Cstr<Vendeur[qualif]> Cstr<Vendeur[commission]>
    Cstr<Employe[salaire]>)
```
(DRIVER-CLASS-CONSTRAINT-P <constraint>) [SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet <constraint> si ce dernier est une contrainte de classe.

Exemple:

? (DRIVER-CLASS-CONSTRAINT-P
? (DRIVER-FIND-CLASS-CONSTRAINT 'Vendeur 'qualif))
= Cstr<Vendeur[qualif]>

(DRIVER-DELETE-CLASS-CONSTRAINT <class-name> <field-name>)

(DRIVER-DELETE-CLASS-CONSTRAINT0 <class> <field>)

[SUBR à 2 arguments]

Supprime la contrainte définie pour la classe de nom <class-name> (resp. l'objet <class>) sur le champ de nom <field-name> (resp. l'objet <field>).

Complément d'information sur ces deux fonctions dans la partie *Description des correspondances*.

Exemple:

? (DRIVER-DELETE-CLASS-CONSTRAINT 'Vendeur 'commission)
= t

B.1.4 Description des correspondances

Les fonctions suivantes s'appliquent toutes au schéma de correspondances courant.

(DRIVER-DEFCLASSMAP <class-name> [<table-name>]
       [<class-options>] [(fields <field1-map> ... <fieldN-map>)])

(DRIVER-DEFCLASSMAP <class-name> [<table-name>]
       [<class-options>] [(letjoins (<join1> ... <joinM>)
                             (fields <field1-map> ... <fieldN-map>)))]
       [MACRO]

Définit dans le schéma courant une correspondance entre la classe de nom <class-name> et la relation <table-name>. Si la classe <class-name> est la sous-classe d'une classe dont la correspondance a déjà été précisée, <table-name> est optionnel.

Un certain nombre d'options sont disponibles pour préciser la correspondance de la classe. Une option se présente sous la forme d'une liste à au moins deux éléments dont le premier est le nom de l'option et le ou les suivants donnent son expression ou sa valeur. Deux possibilités existent ici; elles sont *mappedp* et *attrconstraint*. Voir la description de la fonction DRIVER-MAP-CLASS.

<field1-map> ... <fieldN-map> décrivent la correspondance des champs de la classe.
Ce sont des listes de 3 à 7 éléments ayant la structure suivante :
(<field-name> <field-map> <join-vars> . <options>)

Selon le type du champ (atomique, objet, ...), sa correspondance <field-map> est un attribut, l'expression d'un calcul sur la base (lambda appliquée) ou nil, complété par <join-vars> qui identifient les jointures nécessaires pour retrouver les informations.

<join-vars> est en fait une liste de noms de variables parmi celles définies au sein du *letjoins*. Il est possible de référencer une jointure définie pour la correspondance d'une classe ancêtre au moyen d'une *référence directe de jointure*. On la présente sous forme d'une liste de trois éléments, dont le premier est le nom de la classe pour laquelle la jointure a été définie et les deux autres, la table de départ et la table d'arrivée de la jointure. On ne peut pas référencer une jointure définie pour la correspondance d'une autre classe par le nom de variable qu'on lui avait associé alors car ce dernier n'a plus aucune signification en dehors du *letjoins*.

L'ensemble des options disponibles pour chaque type de champ est présenté dans la description de la fonction DRIVER-MAP-FIELD.

Quand la correspondance d'un champ comprend au moins une jointure, l'expression (fields <field1-map> ... <fieldN-map>) qui contient cette correspondance doit être incluse dans l'environnement

(letjoins (<join1> ... <joinM>) (fields ...))

qui permet de définir localement des jointures.

<join1> ... <joinM> sont des listes à deux éléments. Le premier est un nom de variable (symbole) qui permettra de référencer la jointure dans le corps du (fields ...). Le second est une liste à trois éléments ayant la structure suivante :

(<table1-name> <table2-name> <applied-lambda>)

Pour une plus grande facilité d'usage ou par nécessité (définition d'auto-jointure), il est possible de renommer un nom de table localement à la description de la correspondance d'une classe. Il suffit de remplacer le nom de la table par la liste comprenant le nouveau nom suivi de la table (physique) dont on parle.

Consulter la description de la fonction DRIVER-CREATE-JOIN pour plus d'informations sur la création de jointure.

La description fonctionnelle de cette macro est trop complexe pour être donnée ici. DRIVER-DEFCLASS s'expanse en appels aux fonctions DRIVER-CREATE-TABLE-VAR, DRIVER-CREATE-ATTRIBUTE-VAR, DRIVER-MAP-CLASS, DRIVER-CREATE-ATTR-CONSTRAINT, DRIVER-CREATE-JOIN et DRIVER-MAP-FIELD.

Exemple:
```sql
? (DRIVER-DEFCLASSMAP Employe emp
? (attrconstraint ((LAMBDA (no) (>= no 1000))
? (emp empno)))
? (LETJOINS
? ((j1 (emp (p person)
? ((LAMBDA (a1 a2 a3 a4)
? (AND (EQ a1 a3) (EQ a2 a4)))
? (emp ename) (emp fname)
? (p fname) (p fname))))
? (j2 (emp (emp1 emp)
? ((LAMBDA (a1 a2) (EQ a1 a2))
? (emp mgr) (emp1 empno))))
? (j3 (emp address
? ((LAMBDA (a1 a2) (EQ a1 a2))
? (emp empno) (address empno))))
? (j4 (p vehicle
? ((LAMBDA (a1 a2) (EQ a1 a2))
? (p car) (vehicle vnum))))
? (FIELDS (nom (emp ename) ())
? (prenom (emp fname) ())
? (num-ss (p ssnum) (j1))
? (qualif (emp job) ())
? (chef () (j2))
? (salaire (emp sal) ())
? (adresse () (j3))
? (vehicule () (j1 j4)
? (filter veh-filtre))))
= t
? (DRIVER-DEFCLASSMAP Vendeur
? (FIELDS (situ-famille (p position) ((Employe emp p)))
? (commission (emp com) ())
? (sal-total ((LAMBDA (a1 a2) (+ a1 a2)))
? (emp sal) (emp com)) ()))
= t
```

```
(DRIVER-MAP-CLASS <class-name> [<table-name>]
    [<options>] . <overwrite>)
```

```
(DRIVER-MAP-CLASS0 <class> [<table>] [<options>] . <overwrite>)
    [SUBR de 1 à 4 arguments]
```

Définit une correspondance entre classe et relation. La classe de nom `<class-name>` (resp. l'objet `<class>`) devient la représentation de la relation de nom `<table-name>`
(resp. l'objet `<table>`) dans l'environnement objet, et inversement, la relation de-
vient la correspondance relationnelle de la classe qu'on lui associe. Par défaut, tout
n-uplet de la relation est un objet potentiel instance de la classe associée et tout
objet persistant de la classe est un représentant dans l'environnement d'un n-uplet
de la relation associée.

La relation associée à la classe est appelée sa relation principale. Une relation peut
être choisie comme relation principale d'une classe principale que si elle n'est pas
déjà relation principale d'une autre classe principale ou relation secondaire d'une
autre classe. Si la classe <class-name> est la sous-classe d'une classe dont la corres-
pondance a déjà été précisée, <table-name> n'a pas à être nécessairement re-précisé.

Les options sont toujours des listes à au moins deux éléments dont le premier est
le nom de l'option et le ou les suivants donnent son expression ou sa valeur. Deux
possibilités sont ici proposées, *mappedp* et *attrconstraint* :

**mappedp** Cette option permet de déclarer une classe comme étant sans correspondance relationnelle (alors même que l'on est en train de l'expliciter). Il y a deux intérêts à cela. D'une part, cela permet, en phase de mise au point du schéma par exemple, d'interrompre temporairement les échanges avec la base concernant une classe. Enfin, et c'est là l'intérêt majeur, cela permet de déclarer une classe sans correspondance au milieu d'une hiérarchie mappée. Toute création d'instance de la classe en question ou d'une de ses sous-classes s'effectuera ensuite correctement, les instances bénéficiant et héritant normalement des champs de la classe intermédiaire.

**attrconstraint** Cette option permet de poser une contrainte sur un attribut sans correspondance (non couplé à un champ atomique de la classe associée) de la relation considérée. La contrainte contribuera à filtrer les n-uplets "instances potentielles" de la classe en question qui devront nécessairement la vérifier.

Le mot-clé introduit une forme Lisp qui va permettre de contraindre un attribut. Une forme est une lambda à arguments typés, à savoir, une liste à deux éléments dont le premier est l'expression de la contrainte (lambda) telle qu'elle est spécifiée dans la description de la fonction `DRIVER-CREATE-ATTR-CONSTRAINT` ci-après, et le second est le "typage" de l'argument, à savoir la liste nom de la relation, nom de l'attribut dans la relation.

Exemple:

```sml
? (DRIVER-MAP-CLASS 'Dept 'dept)
= t
? (DRIVER-MAP-CLASS 'Adresse 'address
? '(attrconstraint ((LAMBDA (num) (>= num 1000))
? (address empno)))))
= t
```
(DRIVER-CLASS-MAP `<class-name>`)

(DRIVER-CLASS-MAP0 `<class>`)

[SUBR à 1 argument]

Renvoie la table associée à la classe de nom `<class-name>` (resp. l'objet `<class>`)
si elle a été spécifiée.

Exemple:

? (DRIVER-CLASS-MAP 'Adresse)

= address

? (DRIVER-CLASS-MAP 'Vendeur)

= emp

(DRIVER-TABLE-MAIN-CLASS `<table-name>`)

(DRIVER-TABLE-MAIN-CLASS0 `<table>`)

[SUBR à 1 argument]

Renvoie la classe principale dont la correspondance relationnelle est la table de nom
 `<table-name>` (resp. l'objet `<table>`).

Exemple:

? (DRIVER-TABLE-MAIN-CLASS 'emp)

= Employe

(DRIVER-DELETE-CLASS-MAP `<class-name>`)

(DRIVER-DELETE-CLASS-MAP0 `<class>`)

[SUBR à 1 argument]

Détruit la correspondance établie entre la classe principale de nom `<class-name>`
(resp. l'objet `<class>`) et la table qu'on lui a associée. Cette correspondance est éga-
lement détruite pour toutes ses sous-classes. Détruit également les correspondances
des champs de la classe et des sous-classes.

Exemple:

? (DRIVER-DELETE-CLASS-MAP 'Adresse)

= t

(DRIVER-CREATE-ATTR-CONSTRAINT `<class-name>`)

(<table-name> <attribute-name>) <lambda> <joins> . <overwrite>

(DRIVER-CREATE-ATTR-CONSTRAINT0 `<class>` `<attribute>`)

<lambda> <joins> . <overwrite>

[SUBR à 4 ou 5 arguments]
Cette fonction permet de poser une contrainte simple sur un attribut. Cette contrainte s'exprime sous la forme d'une lambda à un argument où cet argument représente l'attribut à contraindre.

Exemple:

? (DRIVER-CREATE-ATTR-CONSTRAINT 'Adresse '(address state)
?              '(lambda (val) (memq val '(NY CA))) ())
= Cstr<Adresse[address.state]>

(DRIVER-FIND-CLASS-CONSTRAINT <class-name>
(<table-name> <attribute-name>))

(DRIVER-FIND-CLASS-CONSTRAINT0 <class> <attribute>)

(DRIVER-DELETE-CLASS-CONSTRAINT <class-name>
(<table-name> <attribute-name>))

(DRIVER-DELETE-CLASS-CONSTRAINT0 <class> <attribute>)
[SUBR à 2 arguments]

Ces fonctions permettent donc également de rechercher ou détruire une contrainte
posée sur un attribut. Voir les précédentes descriptions dans le paragraphe B.1.3.

Exemple:

? (DRIVER-FIND-CLASS-CONSTRAINT 'Adresse '(address state))
= Cstr<Adresse[address.state]>

(DRIVER-FIND-ATTR-CONSTRAINTS-ON-CLASS <class-name>)

(DRIVER-FIND-ATTR-CONSTRAINTS-ON-CLASS0 <class>)
[SUBR à 1 argument]

Renvoie l'ensemble des contraintes s'appliquant à la classe de nom <class-name>
(de l'objet <class>) et posées sur des attributs. Une contrainte définie pour une
classe sur un attribut masque l'eventuelle contrainte posée sur le même attribut
dans une classe mère.

Exemple:

? (DRIVER-FIND-ATTR-CONSTRAINTS-ON-CLASS 'Vendeur
= (Cstr<Employe[emp.empno]>)

(DRIVER-FIND-CONSTRAINTS-ON-CLASS <class-name>)

(DRIVER-FIND-CONSTRAINTS-ON-CLASS0 <class>)
[SUBR à 1 argument]
Renvoie l'ensemble des contraintes s'appliquant à la classe de nom <class-name>
(de l'objet <class>) (champs et attributs). Une contrainte définie sur le champ d'une
classe masque l'eventuelle contrainte posée sur le même champ dans une classe mère.

Exemple:

? (DRIVER-FIND-CONSTRAINTS-ON-CLASS 'Vendeur)
= (Cstr<Vendeur[qualif]> Cstr<Employe[salaire]> Cstr<Employe emp.empno>)

(DRIVER-CREATE-JOIN <table1-name> <table2-name>
<applied-lambda> . <overwrite>)

(DRIVER-CREATE-JOIN0 <table1> <table2>
<applied-lambda> . <overwrite>)
[SUBR à 3 ou 4 arguments]

Définit un chemin de la table de nom <table1-name> (resp. l'objet <table1>) vers
la table de nom <table2-name> (resp. l'objet <table2>). Ce chemin peut ensuite
être utilisé pour définir la correspondance d'un champ atomique de la classe de
table principale <table1-name> sur un attribut de la table <table2-name>. Il peut
également être utilisé pour définir la correspondance des champs objet, ensemble,
et autres.

Le chemin doit être explicité sous forme d'une lambda où chaque attribut qui y
participe s'exprime sous forme d'une variable passée en argument. Le chemin est
établi entre deux n-uplets des deux relations quand l'application de la lambda renvoie
une valeur différente de nil.

<applied-lambda> est une liste dont le premier élément est une lambda, et dont les
autres représentent, sous forme de listes nom de la relation, nom de l'attribut dans
la relation, l'ensemble des attributs qu'on associe à ses arguments.

Si l'application de la lambda à un n-uplet de valeurs d'attributs renvoie une valeur
vraie (au sens lisp), la jointure est établie pour ce n-uplet. Elle ne l'est pas dans
le cas contraire. L'expression (unique) constituant le corps de la lambda peut faire
appel aux primitives lisp suivantes : and, or, not, =, eq, neq, neqn, null, <>, <, <=
, >, >=, memq et nmemq ((not memq)). Les primitives à deux arguments doivent
être utilisées avec la variable comme premier argument et une constante comme
second. L'usage de l'ensemble des primitives lisp de l'interprète n'est pas autorisé
car DRIVER doit ensuite pouvoir compiler l'expression en SQL pour l'exploiter.

En cas de tentative de redéfinition d'une jointure, l'erreur "jointure déjà existante"
est provoquée, sauf si <overwrite> est précisé à t. Dans ce cas, l'ancienne définition
est perdue, écrasée par la nouvelle. Toutes les structures qui la contenaient pointent
maintenant sur la nouvelle.

Exemple:
? (DRIVER-CREATE-JOIN 'dept 'emp
? ((LAMBDA (a b) (EQ a b)) (dept deptno) (emp deptn)))
= J[dept->emp]

(DRIVER-FIND-JOIN <table1-name> <table2-name>)

(DRIVER-FIND-JOIN0 <table1> <table2>)

[SUBR à 2 arguments]

Retourne la jointure de la table de nom <table1-name> (resp. l'objet <table1>)
vers la table de nom <table2-name> (resp. l'objet <table2> si elle existe.

Exemple:

? (DRIVER-FIND-JOIN 'dept 'emp)
= J[dept->emp]

(DRIVER-JOIN-MATCHING <table1-name> <table2-name> . <joins>)

(DRIVER-JOIN-MATCHING0 <table1> <table2> . <joins>)

[SUBR à 2 ou 3 arguments]

Retourne l'ensemble des jointures de la table de nom <table1-name> (resp. l'objet <table1>) vers la table de nom <table2-name> (resp. l'objet <table2>). L'une des deux tables (ou les deux) peut ne pas être précisée; sa référence doit alors être remplacée par ().

Si une liste de jointures <joins> est précisée, la recherche s'effectuera dedans. Sinon,
l'ensemble des jointures du schéma courant sera considéré.

Exemple:

? (DRIVER-JOIN-MATCHING 'dept())
= (J[dept->emp])

(DRIVER-JOIN-P <join>)

[SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet <join> si ce dernier est une jointure.

Exemple:

? (DRIVER-JOIN-P (DRIVER-FIND-JOIN 'dept 'emp))
= J[dept->emp]

(DRIVER-DELETE-JOIN <table1-name> <table2-name>)

(DRIVER-DELETE-JOIN0 <join>)

[SUBR à 1 et 2 arguments]
Supprime la jointure de la table de nom `<table1-name>` vers la table de nom `<table2-name>` (resp. l'objet jointure `<join>`).

Exemple:

? (DRIVER-DELETE-JOIN 'dept 'emp)

= t

(DRIVER-MAP-FIELD `<class-name>` `<field-name>`
       `<field-map>` `<join-descriptions>` `[<options>] . <overwritep>`
                       [SUBR de 4 à 8 arguments]

(DRIVER-MAP-FIELD0 `<field>` `<field-map>`
       `<joins>` `[<options>] . <overwritep>`
                       [SUBR de 3 à 7 arguments]

Définit la correspondance du champ `<field-name>` (resp. l'objet `<field>`) de la classe `<class-name>` (resp. l'objet `<class>`) dans le monde relationnel.

En fonction du type du champ, sa correspondance peut être un attribut, une expression, un ensemble de jointures, un attribut accessible depuis la table principale par jointure.

`<field-map>` est la correspondance du champ, sauf si cette correspondance est un ensemble de jointures. Si la correspondance est ou comprend un ensemble de jointures, cet ensemble doit être déclaré par `<join-descriptions>` (resp. `<joins>`). `<field-map>` peut donc être une description d'attribut (resp. un objet attribut) ou une expression calculée (voir ci-après). Si la correspondance du champ est uniquement un ensemble de jointures, `<field-map>` vaut nil.

**atom** Les champs atomiques sont associés à un attribut. Si l'attribut fait partie de la relation principale de la classe, aucune jointure ne doit être spécifiée (`<join-descriptions>` (resp. `<joins>`) vaut nil). S'il fait partie d'une table secondaire, un ensemble de jointures reliant la table secondaire à la table principale doit être précisé.

L'option **filter** est disponible pour tous les types de champs. filter permet de définir des filtres par lesquels passeront les données pendant les échanges avec la base. La valeur du champ `lu` dans la base passe dans le filtre avant écriture dans l'objet. La valeur à écrire dans la base et provenant du champ de l'objet transite également par le filtre. La définition et la description des méthodes de filtrage sont présentées au paragraphe B.3.

**atomset** Les champs de type "ensemble d'atomes" sont associés à un attribut d'une table secondaire, relié à la relation principale par un ensemble de jointures. Cet ensemble de jointures doit permettre de sélectionner un ensemble de valeurs de l'attribut en question.
**ordatomset** Même chose que pour les champs de type *atomset*. En plus, l'ordre des éléments de l'ensemble est précisé par la valeur d'attributs de la même table secondaire. Le premier attribut définit l'ordre primaire, le second l'ordre secondaire, et ainsi de suite. L'option **orders** permet de préciser ces attributs et, pour chacun d'entre eux, l'ordre (ascendant ou descendant) dans lequel doit se faire le tri.

La syntaxe de l'option est la suivante :

```
(orders (attr1 ord1) ... (attrN ordN))
```

où chaque *attrI* est un attribut pour la fonction *DRIVER-MAP-FIELD0* et une liste (<table-name> <attr-name>) pour la fonction *DRIVER-MAP-FIELD*, et où chaque *ordI* prend une valeur parmi **asc** et **desc**.

**object** Les champs de type "objet" représentent des liens entre objets dans la représentation objet. Ils ont naturellement comme correspondances un ensemble de jointures reliant leurs relations principales respectives. <field-map> vaut nil.

**object2** Les champs de type "objet 2" retrouvent leurs valeurs en décodant une chaîne de caractères contenue dans un attribut. La correspondance de ce type de champ est donc l'attribut en question, complété de l'ensemble des jointures qui permettent de l'atteindre depuis la relation principale de la classe contenant le champ.

**objectset** Les champs de type "ensemble d'objets" représentent des liens entre un objet et un ensemble d'objets. Ils ont comme correspondances un ensemble de jointures reliant leurs relations principales respectives. A la différence des champs de type objet, ces jointures sont vérifiées par un ensemble de n-uplets au lieu d'un seul. <field-map> vaut nil.

**ordobjset** Même chose que pour les champs de type *objectset*, l'ordre des éléments de l'ensemble étant en plus précisé par la valeur d'attributs de la table secondaire. voir la description du type **ordatomset**.

**object2set** Les champs de type "ensemble d'objets 2" sont associés à un attribut d'une table secondaire, à partir des valeurs duquel seront décodés des pointeurs d'objet. Cet attribut doit être accessible par un ensemble de jointures. A la différence du champ de type *objet2*, ces jointures sont vérifiées par un ensemble de n-uplets au lieu d'un seul.

**ordobj2set** Même chose que pour les champs de type *ordobjset*, l'ordre des éléments de l'ensemble étant en plus précisé par la valeur d'attributs de la table secondaire. voir la description du type **ordatomset**.

**monotexpr** Le type "calcul sur un n-uplet" permet d'associer à un champ l'expression d'un calcul effectué à partir des n-uplets constituant l'objet, celui de la relation principale et ceux des relations secondaires. La correspondance du champ est donc un calcul s'exprimant sous forme d'une lambda appliquée à des attributs, complété de l'ensemble des jointures permettant d'accéder à ses attributs.
Sont autorisées toutes combinaisons des fonctions +, -, * et /.

**multitexpr** Le type "calcul sur un ensemble de n-uplets" permet d'associer à un champ l'expression d'un calcul effectué sur un ensemble de n-uplets. La correspondance de ce type de champ est également une lambda appliquée, complétée de l'ensemble des jointures permettant d'accéder à l'ensemble des n-uplets en relation avec chaque objet.

Sont autorisées, en plus des fonctions de calcul précédentes, les fonctions *avg* (*average* et *sum* permettant de calculer la moyenne et la somme des valeurs d'attributs accessibles par le biais de l'ensemble de jointures indiqué.

En cas de tentative de redéfinition d'une correspondance, l'erreur "correspondance déjà existante" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle.

Exemple:

```sql
? (DRIVER-MAP-FIELD 'Dept 'personnel ()
?         '((dept emp ((LAMBDA (a1 a2) (EQ a1 a2))
?                 (dept deptnum) (emp empno))))))
= t
? (DRIVER-MAP-FIELD 'Dept 'moy-sal
?         '((LAMBDA (a1) (AVG a1)) (emp sal))
?         '((dept emp)))
= t
```

### (DRIVER-FIELD-MAP `<class-name>` `<field-name>`)

### (DRIVER-FIELD-MAP0 `<field>`)

[SUBR à 2 et 1 argument]

Renvoie la correspondance du champ de nom `<field-name>` de la classe de nom `<class-name>` (resp. l'objet `<field>`). Cette correspondance se présente sous la forme d'une liste à deux éléments. Le premier est l'attribut (la lambda appliquée pour les champs calculés) s'il y en a un, le second est la liste des jointures, s'il y en a une.

Exemple:

```sql
? (DRIVER-FIELD-MAP 'Employe 'nom)
= (emp.ename())
? (DRIVER-FIELD-MAP 'Employe 'num-ss)
= (t115@p(person).ssnum (J emp->t115@p(person)]))
? (DRIVER-FIELD-MAP 'Employe 'voiture)
= ((() (J emp->t115@p(person)] J t115@p(person)->t115@vehicle(vehicle)]))
```

### (DRIVER-ATTRIBUTE-MAP-FIELD `<table-name>` `<attr-name>`)

[SUBR à 2 arguments]
(DRIVER-ATTRIBUTE-MAP-FIELD0 <attribute>) [SUBR à 1 argument]

Retourne le champ ayant pour correspondance l'attribut de nom <attr-name> dans
la table de nom <table-name> (resp. à l'objet <table>) s'il existe.

(voir les fonctions DRIVER-ATTRIBUTE-DEF-MAP-FIELDS(0))

Exemple :

? (DRIVER-ATTRIBUTE-MAP-FIELD 'emp 'fname)
= prenom
? (DRIVER-ATTRIBUTE-MAP-FIELD 'person 'position)
= ()
? (DRIVER-ATTRIBUTE-MAP-FIELD 't115@p 'position)
= situ-famille

(DRIVER-DELETE-FIELD-MAP <class-name> <field-name>)

(DRIVER-DELETE-FIELD-MAP0 <field>) [SUBR à 2 ou 1 argument]

Détruit la correspondance établie sur le champ de nom <field-name> de la classe
de nom <class-name> (resp. l'objet <field>).

Exemple :

? (DRIVER-DELETE-FIELD-MAP 'Dept 'personnel)
= t

(DRIVER-MAIN-CLASS-TABLES <class-name> . <allp>)

(DRIVER-MAIN-CLASS-TABLES0 <class> . <allp>)

[SUBR à 1 ou 2 arguments]

Retourne l'ensemble des tables élémentaires de la classe de nom <class-name> (resp. l'objet <class>) si <allp> n'est pas précisé ou vaut (), ou toutes les tables en utilisées dans la correspondance de la classe si <allp> vaut t

Exemple :

? (DRIVER-MAIN-CLASS-TABLES 'Employe)
= (t115@emp1 emp t115@p(person))
? (DRIVER-MAIN-CLASS-TABLES 'Employe t)
= (t115@emp1asu t115@sg(salgrade) t115@dept(dept) t115@address(address)
t115@vehicle(vehicle) emp t115@p(person))

(DRIVER-MAIN-TABLE-P <table>)

(DRIVER-SUB-TABLE-P <table>) [SUBR à 1 argument]
Le prédicat `DRIVER-MAIN-TABLE-P` est vrai et renvoie l'objet `<table>` si la table en question est table principale d'une classe. Le prédicat `DRIVER-SUB-TABLE-P` est vrai et renvoie également l'objet si la table en question est table secondaire d'une classe.

Une table ne peut pas être simultanément principale et secondaire. Elle peut aussi être ni l'une, ni l'autre.

Exemple:

```sql
? (DRIVER-MAIN-TABLE-P (DRIVER-FIND-TABLE 'emp))
= emp
? (DRIVER-SUB-TABLE-P (DRIVER-FIND-TABLE 'person))
= person
```

`(DRIVER-CLASS-LOADING-ORDER <class-names>)`

`(DRIVER-CLASS-LOADING-ORDER0 <classes>)`

[SUBR à 0 ou 1 argument]

Permet de spécifier l'ordre de chargement des classes à utiliser si des objets de différentes classes doivent être chargées au même moment. Cet ordre ne peut être quelconque : on devra forcément charger une classe avant ses filles.

Si cette fonction n'est pas employée, l'ordre de déclaration des classes est utilisé par défaut.

Si seule une partie des classes définies dans le schéma de correspondances est indiquée, ces classes seront chargées d'abord, suivies des autres selon l'ordre dans lequel elles ont été déclarées. Attention à ce que l'ordre de l'ensemble vérifie bien la restriction qui est imposée.

Renvoie l'ensemble des classes (éventuellement complété) dans l'ordre spécifié. Si aucun argument n'est passé, renvoie l'ordre courant de chargement des classes.

Exemple:

```sql
? (DRIVER-CLASS-LOADING-ORDER)
= (Employe Vendeur Dept Adresse)
? (DRIVER-CLASS-LOADING-ORDER '(Employe Dept Vendeur))
= (Employe Dept Vendeur Adresse)
```

`(DRIVER-FIELD-LOADING-ORDER <class-name> . <field-names>)`

`(DRIVER-FIELD-LOADING-ORDER0 <class> . <fields>)`

[SUBR à 1 ou 2 arguments]
Permet de spécifier l'ordre de chargement des champs de la classe indiquée. Si cette fonction n'est pas employée, l'ordre de déclaration des champs est utilisé par défaut.

Si seule une partie des champs définis dans la classe est indiquée, ces champs seront chargés d'abord, suivies des autres selon l'ordre dans lequel ils ont été déclarés.

Renvoie l'ensemble des champs (éventuellement complété) dans l'ordre spécifié. Si seule la classe est spécifiée, renvoie l'ordre courant de chargement de ses champs.

Exemple:

```sql
? (DRIVER-FIELD-LOADING-ORDER 'Employe)
= (nom prenom num-ss qualif grade chef dpt salaire adresse)
? (DRIVER-FIELD-LOADING-ORDER 'Employe
?                      '(nom prenom num-ss adresse))
= (nom prenom num-ss adresse qualif grade chef dpt salaire)
```

### B.1.5 Description relationnelle : fonctions de bas niveau

Les fonctions présentées en B.1.2 permettent de créer simplement des tables et leurs attributs pour décrire le schéma relationnel d'une base de données. Les définitions et variables de tables et d'attributs y sont gérées de manière complètement transparente pour l'utilisateur qui ne manipule en fait que des variables. Ces fonctions sont suffisantes pour l'utilisateur qui ne décrit les correspondances avec le monde objet qu'au moyen de la macro-fonction `DRIVER-DEFCLASSMAP`. Elles sont insuffisantes sans l'utilisation de `DRIVER-DEFCLASSMAP` pour exprimer les auto-jointures ou pour définir plusieurs jointures entre deux mêmes tables.

Les fonctions suivantes, de plus bas niveau, donnent accès aux objets définitions et variables de façon indépendante. Elles permettent la création de variables de tables et d'attributs directement utilisables avec les primitives de description des correspondances, en particulier pour la définition de jointure.

#### (DRIVER-CREATE-TABLE-DEF `<table-def-name>` `<overwrite>`)

[SUBR à 1 ou 2 arguments]

Ajoute la définition de la table de nom `<table-def-name>` dans le schéma courant. Cette définition est initialement vide d'attribut. Les attributs correspondants devront être créés au moyen de la fonction `DRIVER-CREATE-ATTRIBUTE-DEF`.

La création d'une définition de table provoque automatiquement la création de la variable de table de même nom.

En cas de tentative de redéfinition d'une table, l'erreur "table déjà existante" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle, ainsi que toutes les définitions d'attributs, les variables de table et d'attribut qui l'utilisaient. Toutes les structures qui le contenaient pointent maintenant sur la nouvelle.
Cette fonction ne se différencie de la fonction `DRIVER-CREATE-TABLE` que par le résultat qu'elle retourne qui est ici une définition de table plutôt qu'une (variable de) table dans l'autre cas.

Exemple:

```sql
? (DRIVER-CREATE-TABLE-DEF 'project')
= <project>
? (DRIVER-CREATE-TABLE-DEF 'car')
= <car>
```

(DRIVER-FIND-TABLE-DEF `<table-def-name>`) [SUBR à 1 argument]

Retourne la définition de table de nom `<table-def-name>` si elle existe dans le schéma courant.

Exemple:

```sql
? (DRIVER-FIND-TABLE-DEF 'project')
= <project>
```

(DRIVER-TABLE-DEF-P `<table-def>`) [SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet `<table-def>` si ce dernier est une définition de table.

Exemple:

```sql
? (DRIVER-TABLE-DEF-P (DRIVER-FIND-TABLE-DEF 'project'))
= <project>
```

(DRIVER-DELETE-TABLE-DEF `<table-def-name>`)

(DRIVER-DELETE-TABLE-DEF0 `<table-def>`) [SUBR à 1 argument]

Détruit la définition de table de nom `<table-def-name>` (resp. l'objet `<table-def>`)

Dans le schéma courant. Par effet de bord, les attributs définis dans cette table sont également détruits, ainsi que toute variable associée à la table ou à l'un de ses attributs. De même, toutes les références à la table sont retirées du schéma de correspondances.

Exemple:

```sql
? (DRIVER-DELETE-TABLE-DEF 'car')
= t
```
(DRIVER-CREATE-ATTRIBUTE-DEF `<table-def-name>`
  `<attr-def-name>` `<attr-type>` `<typ-len>` `<status>` . `<overwritep>`)

(DRIVER-CREATE-ATTRIBUTE-DEF0 `<table-def>` `<attr-def-name>`
  `<attr-type>` `<typ-len>` `<status>` . `<overwritep>`)
[SUBR à 4 ou 5 arguments]

Ajoute la définition de l'attribut de nom `<attr-def-name>` à la table de nom `<table-def-name>` (resp. à l'objet `<table-def>`) dans le schéma courant. Le type de l'attribut, la longueur de ce type ainsi que le statut de l'attribut doivent être spécifiés. Les différents statuts possibles sont *unique, not-null, keypart, void* ou () (voir la fonction DRIVER-CREATE-ATTRIBUTE).

Les types d'attribut possibles sont par défaut *integer, float et string*. Cette liste peut être complétée en fonction de la base de données utilisée et des types qu'elle reconnaît au moyen de la fonction DRIVER-ADD-ATTRIBUTE-TYPE. Elle est consultée à chaque création d'attribut.

La création d'une définition d'attribut provoque automatiquement la création de la variable d'attribut associée.

En cas de tentative de redéfinition d'un attribut, l'erreur "définition d'attribut déjà existante" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, l'ancienne définition est perdue, écrasée par la nouvelle, ainsi que toutes les variables d'attribut qui l'utilisaient. Toutes les structures qui le contenaient pointent maintenant sur la nouvelle.

Ces fonctions ne se différencient des fonctions DRIVER-CREATE-ATTRIBUTE et DRIVER-CREATE-ATTRIBUTE0 que par le résultat qu'elles retournent qui est ici une définition d'attribut plutôt qu'un (une variable d') attribut dans l'autre cas.

Exemple:

? (DRIVER-CREATE-ATTRIBUTE-DEF 'project 'projno
?                                  'integer 8 'keypart)
= <project.projno>
? (DRIVER-CREATE-ATTRIBUTE-DEF 'project 'pname 'string 20())
= <project.pname>

(DRIVER-FIND-ATTRIBUTE-DEF `<table-def-name>` `<attr-def-name>`)

(DRIVER-FIND-ATTRIBUTE-DEF0 `<table-def>` `<attr-def-name>`)

[SUBR à 2 arguments]

Retourne la définition d'attribut de nom `<attr-def-name>` de la table de nom `<table-def-name>` (de la table `<table-def>`) si elle existe.

Exemple:
? (DRIVER-FIND-ATTRIBUTE-DEF 'project 'pname)
= <project.pname>

(DRIVER-ATTRIBUTE-DEF-P <attr-def>) [SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet <attr-def> si ce dernier est une définition d'attribut.

Exemple:

? (DRIVER-ATTRIBUTE-DEF-P
? (DRIVER-FIND-ATTRIBUTE-DEF 'project 'projno))
= <project.projno>

(DRIVER-DELETE-ATTRIBUTE-DEF <table-def-name> <attr-def-name>)
[SUBR à 2 arguments]

(DRIVER-DELETE-ATTRIBUTE-DEF0 <attr-def>) [SUBR à 1 argument]

Détruit la définition d'attribut de nom <attr-def-name> de la table de nom <table-def-name> (l'objet <attr-def>) dans le schéma courant. Par effet de bord, toute variable associée à l'attribut est également détruite. De même, toutes les références à l'attribut sont retirées du schéma de correspondances.

Exemple:

? (DRIVER-DELETE-ATTRIBUTE-DEF 'project 'pname)
= t

(DRIVER-TABLEDEF-ATTRIBUTEDEFS <table-def-name>)

(DRIVER-TABLEDEF-ATTRIBUTEDEFS0 <table-def>)

[SUBR à 1 argument]

Renvoie dans l'ordre de leurs créations les définitions d'attribut associées à une définition de table. Ce même ordre est utilisé pour une éventuelle création de la relation correspondante dans la base de données relationnelle.

Exemple:

? (DRIVER-TABLEDEF-ATTRIBUTEDEFS 'project)
= (<project.projno>)

(DRIVER-ATTRIBUTE-DEF-MAP-FIELDS <table-def-name> <attr-name>)

[SUBR à 2 arguments]
(DRIVER-ATTRIBUTE-DEF-MAP-FIELDS0 <attribute-def>)

[SUBR à 1 argument]

Renvoie la liste des champs associés à une variable d'attribut dont la définition d'attribut est de nom <attr-def-name> et de table de nom <table-def-name> (resp. la table <table-def>).

Exemple :

? (DRIVER-ATTRIBUTE-DEF-MAP-FIELDS 'person 'position)
= (situ-famille)

Fonctions portant sur les variables de structure

Les variables de table et d'attribut sont utilisées pour construire les correspondances.
Les définitions ne peuvent en effet en aucun cas être utilisées directement.

(DRIVER-CREATE-TABLE-VAR <table-def-name> <var-name>)

(DRIVER-CREATE-TABLE-VAR0 <table-def> <var-name>)

[SUBR à 2 arguments]

Fonctions définissant une variable associée à la définition de table de nom <table-def-name>
 resp. à l'objet <table-def>) dans le schéma courant.

Exemple:

? (DRIVER-CREATE-TABLE-VAR 'project 'project)
** driver-create-table-var : existent table variable : project
? (DRIVER-CREATE-TABLE-VAR 'project 'proj1)
= proj1(project)
? (DRIVER-CREATE-TABLE-VAR 'project 'proj2)
= proj2(project)

(DRIVER-FIND-TABLE-VAR <var-name>)

[SUBR à 1 argument]

Retourne la variable de table de nom <var-name> si elle existe dans le schéma courant.

Exemple :

? (DRIVER-FIND-TABLE-VAR 'project)
= project
? (DRIVER-FIND-TABLE-VAR 'proj1)
= proj1(project)
(DRIVER-DO-FIND-TABLE-VAR `<table-def-name>` `<var-name>`)

(DRIVER-DO-FIND-TABLE-VAR0 `<table-def>` `<var-name>`)

[SUBR à 2 arguments]

Retourne la variable de table de nom `<var-name>` si elle existe dans le schéma courant. Sinon, la crée associée à la définition de table de nom `<table-def-name>` (resp. l'objet `<table-def>`).

Exemple:

? (DRIVER-DO-FIND-TABLE-VAR 'project 'proj1)
= proj1(project)
?
(DRIVER-DO-FIND-TABLE-VAR 'project 'proj2)
= proj2(project)

(DRIVER-TABLE-VAR-P `<table-var>`)

[SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet `<table-var>` si celui-ci est une variable de table.

Exemple:

? (DRIVER-TABLE-VAR-P (DRIVER-FIND-TABLE-VAR 'proj1))
= proj1(project)

(DRIVER-DELETE-TABLE-VAR `<table-var-name>`)

(DRIVER-DELETE-TABLE-VAR0 `<table-var>`)

[SUBR à 1 argument]

Détruit la variable de table de nom `<table-var-name>` (resp. l'objet `<table-var>`)
dans le schéma courant. Par effet de bord, les variables d'attributs associées à cette
variable de table sont également détruites. De même, toutes les références à la table
sont retirées du schéma de correspondances.

ATTENTION: Il n'est pas autorisé de détruire la variable de table automatiquement créée en même temps que la définition de table, celle portant en fait le même nom.

Exemple:

? (DRIVER-DELETE-TABLE-VAR 'project)
** driver-delete-table-var :
    not an erasable table variable : project
?
(DRIVER-DELETE-TABLE-VAR 'proj2)
= t
(DRIVER-TABLEDEF-TABLEVARS `<table-def-name>`)

(DRIVER-TABLEDEF-TABLEVARS0 `<table-def>`) [SUBR à 1 argument]

Renvoie la liste des variables associées à la définition de table de nom `<table-def-name>` (resp. l'objet `<table-def>`).

Exemple:

? (DRIVER-TABLEDEF-TABLEVARS 'project)
= (project proj1(project))

(DRIVER-CREATE-ATTRIBUTE-VAR `<tablevar-name>`

<attrdef-name> . <overwritep>)

(DRIVER-CREATE-ATTRIBUTE-VAR0 `<table-var>`

<attribute-def> . <overwritep>)

[SUBR à 2 ou 3 arguments]

Fonctions créant une variable d'attribut associée à la variable de table de nom `<tablevar-name>` (resp. à l'objet `<table-var>`) et à la définition d'attribut de nom `<attrdef-name>` (resp. et à l'objet `<attribute-def>`).

En cas de tentative de redéfinition d'une variable d'attribut, l'erreur "variable d'attribut déjà existante" est provoquée, sauf si `<overwrite>` est précisé à t. Dans ce cas, il n'y a pas d'erreur. L'objet reste le même puisqu'ayant même variable de table et même définition d'attribut. L'intérêt de ce bouléen est de pouvoir générer automatiquement des créations de variables d'attribut sans se soucier si elles existent déjà.

Exemple:

? (DRIVER-CREATE-ATTRIBUTE-VAR 'proj1 'projno)
= proj1(project).projno
? (DRIVER-CREATE-ATTRIBUTE-VAR 'project 'projno)
** driver-create-attribute-var :
    existent attribute variable : (project . projno)
? (DRIVER-CREATE-ATTRIBUTE-VAR0
? (DRIVER-FIND-TABLE-VAR 'proj1)
? (DRIVER-FIND-ATTRIBUTE-DEF 'Address 'city))
** driver-create-attribute-var :
    not one of the attribute table : (project . city)

(DRIVER-FIND-ATTRIBUTE-VAR `<table-var-name>` `<attr-def-name>`)

(DRIVER-FIND-ATTRIBUTE-VAR0 `<table-var>` `<attribute-def>`)

[SUBR à 2 arguments]
Retourne la variable d'attribut associée à la variable de table de nom `<table-var-name>` (resp. à l'objet `<table-var>`) et à la définition d'attribut de nom `<attr-def-name>` (resp. et à l'objet `<attribute-def>`) si elle existe dans le schéma courant.

Exemple:

```sql
? (DRIVER-FIND-ATTRIBUTE-VAR 'project 'projno)
= project.projno
? (DRIVER-FIND-ATTRIBUTE-VAR 'proj1 'projno)
= proj1(project).empno
```

### (DRIVER-DO-FIND-ATTRIBUTE-VAR `<table-var-name> <attr-def-name>`)

### (DRIVER-DO-FIND-ATTRIBUTE-VAR0 `<table-var> <attribute-def>`)

[SUBR à 2 arguments]

Retourne la variable d'attribut associée à la variable de table de nom `<table-var-name>` (resp. à l'objet `<table-var>`) et à la définition d'attribut de nom `<attr-def-name>` (resp. et à l'objet `<attribute-def>`) si elle existe dans le schéma courant.
Sinon, la crée et la renvoie.

Exemple:

```sql
? (DRIVER-DO-FIND-ATTRIBUTE-VAR 'proj1 'projno)
= proj1(project).projno
? (DRIVER-DO-FIND-ATTRIBUTE-VAR 'proj2 'projno)
= proj2(project).empno
```

### (DRIVER-ATTRIBUTE-VAR-P `<attribute-var>`) [SUBR à 1 argument]

Ce prédicat est vrai et renvoie l'objet `<attribute-var>` si celui-ci est une variable d'attribut.

Exemple:

```sql
? (DRIVER-ATTRIBUTE-VAR-P
? (DRIVER-FIND-ATTRIBUTE-VAR 'proj1 'projno))
= proj1(project).projno
```

### (DRIVER-ATTRDEF-ATTRVARS `<table-def-name> <attribute-def-name>`)

[SUBR à 2 arguments]

### (DRIVER-ATTRDEF-ATTRVARS0 `<attribute-def>`) [SUBR à 1 argument]
Renvoie la liste des variables associées à la définition d'attribut de nom `<attribute-def-name>` de la table de nom `<table-def-name>` (resp. à l'objet `<attribute-def>` pour la seconde fonction).

Exemple:

```sql
? (DRIVER-ATTRDEF-ATTRVARS 'project 'projno)
= (project.projno proj1(project).projno)
```

### (DRIVER-TABLEVAR-ATTRVARS `<table-var-name>`)

### (DRIVER-TABLEVAR-ATTRVARS0 `<table-var>`) [SUBR à 1 argument]

Renvoie la liste des variables d'attribut définies à partir de la variable de table de nom `<table-var-name>` (resp. l'objet `<table-var>`).

Exemple:

```sql
? (DRIVER-TABLEVAR-ATTRVARS 'proj1)
= (proj1(project).projno)
```

### (DRIVER-DELETE-ATTRIBUTE-VAR `<table-var-name>` `<attr-def-name>`)

### (DRIVER-DELETE-ATTRIBUTE-VAR0 `<attribute-var>`)

[SUBR à 1 argument]

Détruit la variable d'attribut associée à la variable de table de nom `<table-var-name>` et à la définition d'attribut de nom `<attr-def-name>` (resp. l'objet `<attribute-var>`). Si elle existe dans le schéma courant. Par effet de bord, toutes les références à l'attribut sont retirées du schéma de correspondances. Par exemple, l'apparition de la variable dans une jointure provoquera la destruction de la jointure.

**ATTENTION:** Il n'est pas autorisé de détruire la variable d'attribut automatiquement créée en même temps que la définition d'attribut, celle dont la variable de table associée porte le même nom que la définition de table correspondante.

Exemple:

```sql
? (DRIVER-DELETE-ATTRIBUTE-VAR 'proj1 'projno)
= t
? (DRIVER-DELETE-ATTRIBUTE-VAR 'project 'projno)
** driver-delete-table-var :
    not an erasable attribute variable : (project projno)
```
### B.1.6 Création des classes et des relations

Ces fonctions permettent de définir les structures objet et relationnelles respectivement dans le langage objet et dans le SGBD connecté si elles n'y existent pas encore.

(DRIVER-MAKE-TABLE `<table-name>`)

(DRIVER-MAKE-TABLE0 `<table>`)

[SUBR à 1 argument]

Définit dans le SGBD associé au schéma de correspondances courant la table de nom `<table-name>` (resp. l'objet `<table>`) précédemment décrite dans ce même schéma.

ATTENTION: Cette fonction ne vérifie pas l'inexistence de la table en question dans le SGBD avant la création demandée.

Exemple:

? (DRIVER-MAKE-TABLE 'emp)

= t

(DRIVER-MAKE-CLASS `<class-name>`)

(DRIVER-MAKE-CLASS0 `<class>`)

[SUBR à 1 argument]

Définit dans le langage objet hôte la classe de nom `<class-name>` précédemment décrite dans le schéma de correspondances courant.

Exemple:

? (DRIVER-MAKE-CLASS 'Employe)

= t

### B.1.7 Génération automatique de classes et de relations

Ces fonctions permettent de générer automatiquement, à partir d'une représentation objet ou relationnelle, celle qui lui correspond dans l'autre modèle. Les rapprochements sont également produits.

(DRIVER-GENERATE-TABLE-MAP `<table-name>`)

[MACRO]

Définit dans le schéma courant une correspondance objet pour la table de nom `<table-name>`. La classe générée comporte un champ atomique par attribut, le type de l'attribut étant repris comme type du champ. Il conviendra donc de définir les méthodes de filtrage en lecture - écriture des champs avec la base pour les attributs ayant un type différent d'integer, float et string.

DRIVER-GENERATE-TABLE-MAP peut être décrit en lisp de la manière suivante :
(driver-create-field0 class 'job 'atom 'string)
(driver-create-field0 class 'mgr 'atom 'integer)
(driver-create-field0 class 'sal 'atom 'float)
(driver-create-field0 class 'com 'atom 'float)
(driver-create-field0 class 'deptn 'atom 'integer)
(if driver-class-make (driver-make-class0 class))
class)
(progn
  (driver-map-class 'emp 'emp t)
  (driver-map-field 'emp 'empno '(emp empno) '())
  (driver-map-field 'emp 'ename '(emp ename) '())
  (driver-map-field 'emp 'fname '(emp fname) '())
  (driver-map-field 'emp 'job '(emp job) '())
  (driver-map-field 'emp 'mgr '(emp mgr) '())
  (driver-map-field 'emp 'sal '(emp sal) '())
  (driver-map-field 'emp 'com '(emp com) '())
  (driver-map-field 'emp 'deptn '(emp deptn) '())
t)))
= ()

(DRIVER-GENERATE-CLASS-MAP <class-name>) [MACRO]

Définit dans le schéma courant une correspondance relationnelle pour la class de nom <class-name>.

DRIVER-GENERATE-CLASS-MAP n'est pas encore implémentée dans cette version de DRIVER.
## B.2 Les primitives utilisateur

### B.2.1 Connexion et communication avec le SGBD

**(DRIVER-CONNECT <dbms-name> <base-name>) [SUBR à 2 arguments]**

Assure la connexion à la base de données de nom <base-name> définie dans le SGBD de nom <dbms-name>. Retourne le curseur résultant de cette connexion.

À la première utilisation de `DRIVER-CONNECT` lors d'une session, le curseur est stocké dans une variable système. Il est utilisé par défaut comme curseur couvrant dans tout schéma de correspondances ultérieurement créé au moyen de la fonction `DRIVER-CREATE-MAPPING` si la variable système `DRIVER-AFFECT-CURSOR-P` vaut t (valeur par défaut).

Après avoir établi la connexion et créé le curseur, `DRIVER-CONNECT` effectue un appel à la fonction `DRIVER-DBMS-CONNECTION` avec les deux arguments `<dbms-name>` et `<base-name>` avant de rendre la main.

Exemple de connexion sur la base `smecidemo` avec le SGBD `ingres` :

```python
? (DRIVER-CONNECT 'ingres 'smecidemo)
= #:tclass:cursor:#[ingres 0 t ()]
```

**(DRIVER-DBMS-CONNECTION <dbms-name> <user-name>) [SUBR à 2 arguments]**

Fonction appelée par `DRIVER-CONNECT` lors de la connexion à une base de données. Par défaut, cette fonction est vide et a comme définition :

```
(de driver-dbms-connection (dbms-name user-name))
```

L'utilisateur a tout loisir de la redéfinir pour ses besoins propres.

**(DRIVER-CREATE-NEW-CURSOR <dbms-name> <base-name>) (DRIVER-CREATE-NEW-CURSOR0 <dbms>) [SUBR à 1 ou 2 arguments]**

Crée et renvoie un nouveau curseur sur la base de données de nom <base-name> définie dans le SGBD de nom <dbms-name>.

Exemple:

```python
? (setq c2 (DRIVER-CREATE-NEW-CURSOR 'ingres 'smecidemo))
= #:tclass:cursor:#[ingres 0 t ()]
```