Utilitaires pour modéliser des bases de données en XML PimenTech http://www.pimentech.net 9 septembre 2010 1 Introduction Afin de gagner un peu de temps et d uniformiser les modèles de nos bases de données, nous avons développé 2 utilitaires nous permettant de créer nos bases de données en XML (PGML). Le PGML est grossièrement l équivalent d un modèle EER (Extended Entity Relationship) qui peut d ailleurs être généré en dot et visualisable grâce à Graphviz 1. 2 Syntaxe du pgml Nous présentons ici brièvement la syntaxe utilisée pour construire le pgml notre utilisation du modèle EER (Extended Entity Relationship) 2.1 Entité Dans notre cas, une entité (entity) représente une table dotée d attributs. Par exemple : <table name= book > <attribute name= title type= text /> <attribute name= author type= text /> 2.2 Relation Une relation (relationship) est utilisée pour relier des tables entre elles. Les relations sont dotées de participations, qui définissent la nature du lien entre table et relation la nature de leurs inter-connections la façon dont elles sont connectées On peut voir sur le pgml ci dessous que chaque tag participation est dotée d un type représenté par un triplet : type = (nature_participation, cardinalite, localisation) Nature participation : 0 - Partielle 1 - Totale (obligatoire) Cardinalité : 1 - Une 1 http ://www.research.att.com/sw/tools/graphviz/download.html 1
n - Plus d une Localisation : 1 - La référence sera placée de ce coté 0 - Localisation de la référence indéfinie 3 pgml2dot Afin d illustrer l utilisation de nos outils nous partirons d un petit modèle de gestion de bibliothèques biblio.pgml : <?xml version= 1.0 encoding= ISO-8859-1 standalone="no"?> <!DOCTYPE template SYSTEM "/usr/share/doc/pimentech-dbutils/ pgml_2.0.dtd"> <schema> <table name= people > <attribute name= name type= text /> <table name= author /> <table name= user isa= people > <attribute name= expiration type= date default= now /> <table name= manager isa= people > <attribute name= word type= text /> <table name= book > <attribute name= title type= text /> <attribute name= author type= text /> <relation name= rent > <attribute name= date type= date default= now /> <participation table= book type= 0,1,1 /> <participation table= user type= /> </relation> <relation name= write > <participation table= book type= /> <participation table= author type= /> </relation> </schema> Nous voyons sur le schéma 1 que pgml2dot sans options ne fait que dessiner le modèle EER correspondant, cependant sur le schéma 2 nous voyons le schéma après transformation par notre outil. En effet, la relation write ne peut être réalisé par une simple référence puisqu un seul auteur peut écrire plusieurs livres et de même un livre peut être écrit par plusieurs auteurs. Ainsi notre outil génère la table nécessaire à cet effet. Cette table porte le nom de la relation et un attribut d héritage peut être ajouté comme pour la 2
description des tables (<relation name= write isa= object >...). La relation rent elle est des plus classique et la référence est mise du coté de la table book comme indiqué par le troisième élément du type de participation. Toute relation a, en effet, un type qui correspond pour les deux premiers éléments aux arguments de cardinalité du schéma EER et un troisième qui lui indique si on veut qu une référence soit hébergé par la table désigné dans la participation. Nous voyons également les références calculés par notre outil. 4 pgml2sql Le SQL peut être généré de différentes façon suivant les options ées à pgml2sql. Voici d abord la version la plus simple qui n utilise pas l héritage PostgreSql et génère un identifiant par table : CREATE TABLE people ( id_people SERIAL PRIMARY KEY, name text CREATE TABLE author ( id_author SERIAL PRIMARY KEY, ref_people int4 CREATE TABLE user ( id_user SERIAL PRIMARY KEY, ref_people int4, expiration date DEFAULT now CREATE TABLE book ( id_book SERIAL PRIMARY KEY, title text, author text, ref_user int4, date date DEFAULT now CREATE TABLE manager ( id_manager SERIAL PRIMARY KEY, word text, ref_people int4 CREATE TABLE write ( id_write SERIAL PRIMARY KEY, ref_book int4, ref_author int4 Nous lui préférons cependant celui généré avec : ramon@cumin:~$ pgml2sql.py -f biblio.pgml -o biblio.sql -u -i "uid SERIAL PRIMARY KEY" -r 0 -x ramon@cumin:~$ qui génère également les indexes et utilise l héritage PostgreSql ainsi qu un identifiant commun à toutes les tables. 3
author_isa_people rent date : date 0,1,1 author book title : text author : text user expiration : date write user_isa_people people name : text manager word : text manager_isa_people FIG. 1 Schéma rendu par pgml2dot -f biblio.pgml -o biblio.dot 4
author_write book_write author ref_people : int4 write ref_book : int4 ref_author : int4 user ref_people : int4 expiration : date book title : text author : text ref_user : int4 date : date 0,1,1 author_isa_people user_isa_people rent date : date people name : text manager word : text ref_people : int4 manager_isa_people FIG. 2 Schéma rendu par pgml2dot -s -f biblio.pgml -o sbiblio.dot 5
CREATE TABLE people ( uid SERIAL PRIMARY KEY, name text create index idx_people_uid on people (uid CREATE TABLE author ( ) inherits (people create index idx_author_uid on author (uid CREATE TABLE user ( expiration date DEFAULT now ) inherits (people create index idx_user_uid on user (uid CREATE TABLE book ( uid SERIAL PRIMARY KEY, title text, author text, ref_user int4 DEFAULT 0, date date DEFAULT now create index idx_book_uid on book (uid create index idx_book_ref_user on book (ref_user CREATE TABLE manager ( word text ) inherits (people create index idx_manager_uid on manager (uid CREATE TABLE write ( uid SERIAL PRIMARY KEY, ref_book int4 DEFAULT 0, ref_author int4 DEFAULT 0 create index idx_write_uid on write (uid create index idx_write_ref_book on write (ref_book create index idx_write_ref_author on write (ref_author Il est également à noter qu une option existe pour générer des contraintes. 5 les nouveautées 5.1 les multi indexes : <table name="employe" isa="personne_physique">...... <multi-index names="nom, prenom" constraints="unique"/> qui nous donnera create unique index employe_nom_prenom_key on employe (nom, prenom ou encore : 6
<relation name="travaille_pour" isa="object" constraints="fin is null"> <attribute name="debut" type="date" default="now()"/> <attribute name="fin" type="date"/> <participation type="" table="personne_physique"/> <participation type="" table="societe"/> <participation type="" table="fonction"/> </relation> nous donnera create unique index idx_ne_physique_ref_societe_key on travaille_pour \ (ref_fonction,ref_personne_physique,ref_societe) where fin is null; 5.2 django ramon@host:~$ pgml2django.py -f ~/src/dbutils/src/xml/biblio.pgml from django.db import models class People(models.Model): name = models.textfield() class Author(models.Model): name = models.textfield() class User(models.Model): name = models.textfield() expiration = models.datefield() class Book(models.Model): date = models.datefield() title = models.textfield() user = models.foreignkey(user) class Write(models.Model): author = models.foreignkey(author) book = models.foreignkey(book) class Manager(models.Model): 7
name = models.textfield() word = models.textfield() des options permettent de changer le style du rendu de pgml2sql afin de coller à django : ramon@host:~$ pgml2sql.py -f ~/src/dbutils/src/xml/biblio.pgml -s -n biblio -x -u CREATE TABLE biblio_people ( id SERIAL PRIMARY KEY, name text create unique index idx_biblio_people_id on biblio_people (id CREATE TABLE biblio_manager ( word text ) inherits (biblio_people create unique index idx_biblio_manager_id on biblio_manager (id CREATE TABLE biblio_author ( ) inherits (biblio_people create unique index idx_biblio_author_id on biblio_author (id CREATE TABLE biblio_user ( expiration date DEFAULT now ) inherits (biblio_people create unique index idx_biblio_user_id on biblio_user (id CREATE TABLE biblio_book ( id SERIAL PRIMARY KEY, date date DEFAULT now, title text, user_id int4 create unique index idx_biblio_book_id on biblio_book (id create index idx_biblio_book_user_id on biblio_book (user_id CREATE TABLE biblio_write ( id SERIAL PRIMARY KEY, author_id int4, book_id int4 create unique index idx_biblio_write_id on biblio_write (id create index idx_biblio_write_author_id on biblio_write (author_id create index idx_biblio_write_book_id on biblio_write (book_id create unique index idx_write_author_id_book_id_key on biblio_write \ (author_id,book_id de plus si nous changeons le pgml avec : <schema> <table name= people > <attribute name= name type= text display= true length= 20 />... 8
nous obtenons : class People(models.Model): name = models.charfield(maxlength=20) def str(self): return %s % (self.name) 6 qmlserv Qmlserv est un middleware xml permettant d accéder à une base de données PostgreSQL. Qmlserv peut fonctionner en mode chiffré ou non. Il gère autant de clés que l on veut selon les clients qui se connectent. Qmlserv utilise Pimencrypto.py Qmlclient illustre la façon dont on se connecte à qmlserv. Daemon.py permet de lancer qmlserv en mode daemon et ainsi de le lancer au démarrage de la machine. 6.1 quelques requètes... user mdm word xxx database mdm host localhost <sequence> <transaction> <select table= reseau > <attribute name= code op= equal value= 202 /> </select> <select table= agence default-op= view > <attribute name= date_modification op= greater value= 01/04/2003 /> </select> </transaction> </sequence> getselect <sequence> <transaction> <select table= ville > <attribute name= nom >Paris</attribute> <attribute name= code_postal >75020</attribute> </select> <update-or-insert table= appartement > <attribute name= euid op= equal >2222</attribute> <attribute name= src_modification >john</attribute> </update-or-insert> 9
</transaction> </sequence> 10