Vous êtes sur la page 1sur 16

EXPOSE DE BASE DE DONNEE AVANCEE

39.4, 39.5, 40.1, 40.2 (PostgreSQL Documentation)

Présenté par :
ALI-TAGBA Hamza
EDORH Laurent Gbenouga
KUDITE Jacques
MOHAMED Araphate
NAYO Philippe
OURO-BANG’NA Ridoine

Chargé du cours : Dr APEKE


I- Un exemple complet de trigger sur événement

Voici un exemple très simple d'une fonction trigger sur événement.


La fonction noddl lève une exception à chaque fois qu'elle est appelée. La définition du trigger
événement associe la fonction à l'événement ddl_command_start. Vous trouverai le support
commandes des triggers sur évènement dans la partie ANNEXE.

Création de la fonction trigger et du trigger sur l’évenement ddl_command_start:

Maintenant vous pouvez tester le bon fonctionnement du trigger :

Dans ce cas, pour pouvoir activer l'exécution de certaines commandes DDL, vous pouvez soit
supprimer le trigger sur événement soit le désactiver. Il est généralement plus simple de désactiver
le trigger pendant la durée de la transaction :
II- Un exemple de trigger sur événement de table modifiée

Un exemple de trigger sur événement de table modifiée Grâce à l'événement table_rewrite, il est
possible d'écrire une fonction qui autorise les modifications d'une table seulement pendant les
heures de maintenance.

Ci-dessous un exemple d'implémentation d'une telle règle.


III- Système de règles

Le système de règles (plus précisément, le système de règles de réécriture de requêtes) est


totalement différent des procédures stockées et des déclencheurs. Il modifie les requêtes pour
prendre en considération les règles puis passe la requête modifiée au planificateur de requêtes pour
planification et exécution. Il est très puissant et peut être utilisé pour beaucoup de choses comme
des procédures en langage de requêtes, des vues et des versions. Les fondations théoriques et la
puissance de ce système de règles sont aussi discutées dans ston90b et ong90.

1. Arbre de requêtes

Pour comprendre comment fonctionne le système de règles, il est nécessaire de comprendre quand
il est appelé et quelles sont ses entrées et sorties.

Le système de règles est situé entre l'analyseur et le planificateur. Il prend la sortie de l'analyseur, un
arbre de requête et les règles de réécriture définies par l'utilisateur qui sont aussi des arbres de
requêtes avec quelques informations supplémentaires, et crée zéro ou plusieurs arbres de requêtes
comme résultat. Donc, son entrée et sortie sont toujours des éléments que l'analyseur lui-même
pourrait avoir produit et, du coup, tout ce qu'il voit est représentable basiquement comme une
instruction SQL.

Maintenant, qu'est-ce qu'un arbre de requêtes ? C'est une représentation interne d'une instruction
SQL où les parties qui le forment sont stockées séparément.

Lors de la lecture des représentations SQL des arbres de requêtes dans ce chapitre, il est nécessaire
d'être capable d'identifier les morceaux cassés de l'instruction lorsqu'ils sont dans la structure de
l'arbre de requête.

Les parties d'un arbre de requêtes sont :

 Le type de commande
C'est une simple valeur indiquant quelle commande (SELECT, INSERT, UPDATE,
DELETE) l'arbre de requêtes produira.

 La table d'échelle
La table d'échelle est une liste des relations utilisées dans la requête. Dans une
instruction SELECT, ce sont les relations données après le mot clé FROM.

Chaque entrée de la table d'échelle identifie une table ou une vue et indique par quel nom
elle est désignée dans les autres parties de la requête. Dans l'arbre de requêtes, les entrées de
la table d'échelle sont référencées par des numéros plutôt que par des noms. Il importe donc
peu, ici, de savoir s'il y a des noms dupliqués comme cela peut être le cas avec une
instruction SQL. Cela peut arriver après l'assemblage des tables d'échelle des règles. Les
exemples de ce chapitre ne sont pas
confrontés à cette situation.

 La relation résultat
C'est un index dans la table d'échelle qui identifie la relation où iront les résultats de la
requête.
Les requêtes SELECT n'ont pas de relation résultat. Le cas spécial d'un SELECT INTO est
pratiquement identique à un CREATE TABEL suivi par un INSERT ... SELECT et n'est
pas discuté séparément ici.
Pour les commandes INSERT, UPDATE et DELTE, la relation de résultat est la table
(ou vue !) où les changements prennent effet.

 La liste cible
La liste cible est une liste d'expressions définissant le résultat d'une requête. Dans le cas d'un
SELECT, ces expressions sont celles qui construisent la sortie finale de la requête. Ils
correspondent aux expressions entre les mots clés SELECT et FROM (* est seulement une
abréviation pour tous les noms de colonnes d'une relation. Il est étendu par l'analyseur en
colonnes individuelles, pour que le système de règles ne le voit jamais).

Les commandes DELETE n'ont pas besoin d'une liste normale de colonnes car elles ne
produisent aucun résultat. En fait, l'optimiseur ajoutera une entrée spéciale ctid pour aller
jusqu'à la liste de cibles vide pour permettre à l'exécuteur de trouver la ligne à supprimer.
(CTID est ajouté quand la relation résultante est une table ordinaire. S'il s'agit d'une vue,
une variable de type ligne est ajoutée à la place, par le système de règles, comme décrit dans
Section 40.2.4, « Mise à jour d'une vue ».)

Pour les commandes INSERT, la liste cible décrit les nouvelles lignes devant aller dans la
relation résultat. Elle consiste en des expressions de la clause VALUES ou en celles de la
clause SELECT dans INSERT ... SELECT. la première étape du processus de réécriture
ajoute les entrées de la liste cible pour les colonnes n'ont affectées par la commande
originale mais ayant des valeurs par défaut. Toute colonne restante (avec soit une valeur
donnée soit une valeur par défaut) sera remplie par le planificateur avec une expression
NULL constante.

Pour les commandes UPDATE, la liste cible décrit les nouvelles lignes remplaçant les
anciennes. Dans le système des règles, elle contient seulement les expressions de la partie
SET colonne = expression de la commande. le planificateur gérera les colonnes
manquantes en insérant des expressions qui copient les valeurs provenant de l'ancienne ligne
dans la nouvelle.

Comme pour DELETE, un CTID ou une variable de type ligne est ajouté pour que
l'exécuteur puisse identifier l'ancienne ligne à mettre à jour.
Chaque entrée de la liste cible contient une expression qui peut être une valeur constante,
une variable pointant vers une colonne d'une des relations de la table d'échelle, un paramètre
ou un arbre d'expressions réalisé à partir d'appels de fonctions, de constantes, de variables,
d'opérateurs, etc.

 la qualification
La qualification de la requête est une expression ressemblant à une de celles contenues dans
les entrées de la liste cible. La valeur résultant de cette expression est un booléen indiquant
si l'opération (INSERT, UPDATE, DELETE ou SELECT) pour la ligne de résultat final
devrait être exécutée ou non. Elle correspond à la clause WHERE d'une instruction SQL.

 l'arbre de jointure
L'arbre de jointure de la requête affiche la structure de la clause FROM. Pour une simple
requête comme SELECT … FROM a, b, c, l'arbre de jointure est une simple liste
d'éléments de FROM parce que nous sommes autorisés à les joindre dans tout ordre. Mais
quand des expressions JOIN, et plus particulièrement les jointures externes, sont utilisées,
nous devons les joindre dans l'ordre affiché par les jointures. Dans ce cas, l'arbre de jointure
affiche la structure des expressions JOIN. Les restrictions associées avec ces clauses JOIN
particulières (à partir d'expressions on ou USING) sont enregistrées comme des expressions
de qualification attachées aux nœuds de l'arbre de jointure. Il s'avère agréable d'enregistrer
l'expression de haut niveau WHERE comme une qualification attachée à l'élément de l'arbre
de jointure de haut niveau. Donc, réellement, l'arbre de jointure représente à la fois les
clauses FROM et WHERE d'un SELECT.

 Le reste
Les autres parties de l'arbre de requête comme la clause ORDER BY n'ont pas d'intérêt ici.
Le système de règles substitue quelques entrées lors de l'application des règles mais ceci n'a
pas grand chose à voir avec les fondamentaux du système de règles.

2. Vues et système de règles


Avec PostgreSQL™, les vues sont implémentées en utilisant le système de règles.
CREATE VIEW ma_vue AS SELECT * FROM ma_table;

2.1. Fonctionnement des règles select

Les règles on SELECT sont appliquées à toutes les requêtes comme la dernière étape, même si la
commande donnée est un INSERT, UPDATE ou DELETE. et ils ont des sémantiques différentes à
partir des règles sur les autres types de commandes dans le fait qu'elles modifient l'arbre de requêtes
en place au lieu d'en créer un nouveau. Donc, les règles select sont décrites avant.

Actuellement, il n'existe qu'une action dans une règle on SELECT et elle doit être une action
SELECT inconditionnelle qui est INSTEAD. cette restriction était requise pour rendre les règles
assez sûres pour les ouvrir aux utilisateurs ordinaires et cela restreint les règles on SELECT à agir
comme des vues.

Pour cette partie, les exemples sont deux vues jointes réalisant quelques calculs et quelques vues
supplémentaires les utilisant à leur tour. Une des deux premières vues est personnalisée plus tard en
ajoutant des règles pour des opérations INSERT, UPDATE et DELETE. de façon à ce que le résultat
final sera une vue qui se comporte comme une vraie table avec quelques fonctionnalités magiques.
Il n'existe pas un tel exemple pour commencer et ceci rend les choses plus difficiles à obtenir. Mais
il est mieux d'avoir un exemple couvrant tous les points discutés étape par étape plutôt que plusieurs
exemples, rendant la compréhension plus difficile.

Les tables réelles dont nous avons besoin dans les deux premières descriptions du système de règles
sont les suivantes :
Comme vous pouvez le constater, elles représentent les données d'un magasin de chaussures.
Les vues sont créées avec :
La commande CREATE VIEW pour la vue lacet (qui est la plus simple que nous avons) écrira une
relation lacet et une entrée dans pg_rewrite indiquant la présence d'une règle de réécriture devant
être appliquée à chaque fois que la relation lacet est référencée dans une table de la requête. La
règle n'a aucune qualification de règle (discuté plus tard, avec les règles autres que select car les
règles select ne le sont pas encore) et qu'il s'agit de INSTEAD. notez que les qualifications de règles
ne sont pas identiques aux qualifications de requêtes. L'action de notre règle a une qualification de
requête. L'action de la règle a un arbre de requête qui est une copie de l'instruction select dans la
commande de création de la vue.

C'est la requête SELECT la plus simple que vous pouvez lancer sur nos vues, donc nous prenons
cette opportunité d'expliquer les bases des règles de vues. SELECT * FROM lacet a été interprété
par l'analyseur et a produit l'arbre de requête :

et ceci est transmis au système de règles. Ce système traverse la table d'échelle et vérifie s'il existe
des règles pour chaque relation.

Pour étendre la vue, la réécriture crée simplement une entrée de la table d'échelle de sous-requête
contenant l'arbre de requête de l'action de la règle et substitue cette entrée avec l'original référencé
dans la vue. L'arbre d'échelle résultant de la réécriture est pratiquement identique à celui que vous
avez saisi :
Maintenant, nous voulons écrire une requête qui trouve les chaussures en magasin dont nous avons
les lacets correspondants (couleur et longueur) et pour lesquels le nombre total de pairs
correspondants exactement est supérieur ou égal à deux.

Cette fois, la sortie de l'analyseur est l'arbre de requête :

La première règle appliquée sera celle de la vue chaussure_prete et cela résultera en cet arbre de
requête :
De façon similaire, les règles pour chaussure et lacet sont substituées dans la table d'échelle de la
sous-requête, amenant à l'arbre de requête final à trois niveaux :

2.2. Règles de vue dans des instructions autres que select

Deux détails de l'arbre de requête n'ont pas été abordés dans la description des règles de vue ci-
dessus. Ce sont le type de commande et le relation résultante. En fait, le type de commande n'est pas
nécessaire pour les règles de la vue mais la relation résultante pourrait affecter la façon dont la
requête sera réécrite car une attention particulière doit être prise si la relation résultante est une vue.

Il existe seulement quelques différences entre un arbre de requête pour un select et un pour une
autre commande. de façon évidente, ils ont un type de commande différent et pour une commande
autre qu'un select, la relation résultante pointe vers l'entrée de table d'échelle où le résultat devrait
arriver. Tout le reste est absolument identique. Donc, avec deux tables t1 et t2 avec les colonnes a et
b, les arbres de requêtes pour les deux commandes :

sont pratiquement identiques. En particulier :


 Les tables d'échelle contiennent des entrées pour les tables t1 et t2.
 Les listes cibles contiennent une variable pointant vers la colonne b de l'entrée de la table
d'échelle pour la table t2.
 Les expressions de qualification comparent les colonnes a des deux entrées de table
d'échelle pour une égalité.
 Les arbres de jointure affichent une jointure simple entre t1 et t2.

La conséquence est que les deux arbres de requête résultent en des plans d'exécution similaires : ce
sont tous les deux des jointures sur les deux tables. Pour l'update, les colonnes manquantes de t1
sont ajoutées à la liste cible par le planificateur et l'arbre de requête final sera lu de cette façon :

et, du coup, l'exécuteur lancé sur la jointure produira exactement le même résultat qu'un :

Mais il existe un petit problème dans UPDATE : la partie du plan d'exécution qui fait la jointure ne
prête pas attention à l'intérêt des résultats de la jointure. Il produit un ensemble de lignes. Le fait
qu'il y a une commande SELECT et une commande UPDATE est géré plus haut dans l'exécuteur où
cette partie sait qu'il s'agit d'une commande UPDATE, et elle sait que ce résultat va aller dans la
table t1. Mais lesquels de ces lignes vont être remplacées par la nouvelle ligne ?

Pour résoudre ce problème, une autre entrée est ajoutée dans la liste cible de l'update (et aussi dans
les instructions delete) : l'identifiant actuel du tuple (ctid, acronyme de current tuple ID). Cette
colonne système contient le numéro de bloc du fichier et la position dans le bloc pour cette ligne.
Connaissant la table, le ctid peut être utilisé pour récupérer la ligne originale de t1 à mettre à jour.
après avoir ajouté le ctid dans la liste cible, la requête ressemble à ceci :

Maintenant, un autre détail de PostgreSQL™ entre en jeu. Les anciennes lignes de la table ne sont
pas surchargées et cela explique pourquoi rollback est rapide. avec un update, la nouvelle ligne
résultat est insérée dans la table (après avoir enlevé le ctid) et, dans le nouvel en-tête de ligne de
l'ancienne ligne, vers où pointe le ctid, les entrées cmax et xmax sont configurées par le compteur
de commande actuel et par l'identifiant de transaction actuel. Du coup, l'ancienne ligne est cachée
et, après validation de la transaction, le nettoyeur (vacuum) peut éventuellement la supprimer.

Connaissant tout ceci, nous pouvons simplement appliquer les règles de vues de la même façon que
toute autre commande. Il n'y a pas de différence.

2.3. Puissance des vues dans PostgreSQL

L'exemple ci-dessus démontre l'incorporation des définitions de vues par le système de règles dans
l'arbre de requête original. Dans le deuxième exemple, un simple select d'une vue a créé un arbre de
requête final qui est une jointure de quatre tables (unit a été utilisé deux fois avec des noms
différents).

Le bénéfice de l'implémentation des vues avec le système de règles est que le planificateur a toute
l'information sur les tables à parcourir et sur les relations entre ces tables et les qualifications
restrictives à partir des vues et les qualifications à partir de la requête originale dans un seule arbre
de requête. Et c'est toujours la situation quand la requête originale est déjà une jointure sur des vues.
Le planificateur doit décider du meilleur chemin pour exécuter la requête et plus le planificateur a
d'informations, meilleure sera la décision. Le système de règles implémenté dans PostgreSQL™
s'en assure, c'est toute l'information disponible sur la requête à ce moment.

2.4. Mise à jour d'une vue


Qu'arrive-t'il si une vue est nommée comme la relation cible d'un INSERT, l'UPDATE ou le
DELETE ? Faire simplement les substitutions décrites ci-dessus donnerait un arbre de requêtes dont
le résultat pointerait vers une entrée de la table en sous-requête. Cela ne fonctionnera pas.
Néanmoins, il existe différents moyens permettant à PostgreSQL™ de supporter la mise à jour
d'une vue.

Si la sous-requête fait une sélection à partir d'une relation simple et qu'elle est suffisamment simple,
le processus de réécriture peut automatiquement remplacé la sous-requête avec la relation sous-
jacente pour que l'INSERT, l'UPDATE ou le DELETE soit appliqué correctement sur la relation de
base. Les vues qui sont « suffisamment simples » pour cela sont appelées des vues automatiquement
modifiables.

Sinon, l'opération peut être gérée par un trigger INSTEAD OF, créé par l'utilisateur, sur la vue. La
réécriture fonctionne légèrement différemment dans ce cas. Pour INSERT, la réécriture ne fait rien
du tout avec la vue, la laissant comme relation résultante de la requête. Pour UPDATE et DELETE,
il est toujours nécessaire d'étendre la requête de la vue pour récupérer les « anciennes » lignes que
la commande va essayer de mettre à jour ou supprimer. Donc la vue est étendue comme d'habitude
mais une autre entrée de table non étendue est ajoutée à la requête pour représenter la vue en tant
que relation résultante.

Le problème qui survient maintenant est d'identifier les lignes à mettre à jour dans la vue. Rappelez-
vous que, quand la relation résultante est une table, une entrée CTID spéciale est ajoutée à la liste
cible pour identifier les emplacements physiques des lignes à mettre à jour. Ceci ne fonctionne pas
si la relation résultante est une vue car une vue n'a pas de CTID, car ses lignes n'ont pas
d'emplacements physiques réels. À la place, pour une opération UPDATE ou DELETE, une entrée
wholerow (ligne complète) spéciale est ajoutée à la liste cible, qui s'étend pour inclure toutes les
colonnes d'une vue. L'exécuteur utilise cette valeur pour fournir l'« ancienne » ligne au trigger
INSTEAD OF. C'est au trigger de savoir ce que la mise à jour est supposée faire sur les valeurs des
anciennes et nouvelles lignes.

Une autre possibilité est que l'utilisateur définisse des vues INSTEAD qui indiquent les actions à
substituer pour les commandes INSERT, UPDATE et DELETE sur une vue. Ces règles vont réécrire
la commande, typiquement en une commande qui met à jour une ou plusieurs tables, plutôt que des
vues.

Notez que les règles sont évaluées en premier, réécrivant la requête originale avant qu'elle ne soit
optimisée et exécutée. Du coup, si une vue a des triggers INSTEAD OF en plus de règles sur
INSERT, UPDATE ou DELETE, alors les règles seront évaluées en premier et, suivant le résultat,
les triggers pourraient être utilisés.

La réécriture automatique d'une requête INSERT, UPDATE ou DELETE sur une vue simple est
toujours essayée en dernier. Du coup, si une vue a des règles ou des triggers, ces derniers
surchargeront le comportement par défaut des vues automatiquement modifiables.

S'il n'y a pas de règles INSTEAD ou de triggers INSTEAD OF sur la vue et que le processus de
réécriture ne peut pas réécrire automatiquement la requête sous la forme d'une mise à jour de la
relation sous-jacente, une erreur sera renvoyée car l'exécuteur ne peut pas modifier une vue.
ANNEXE :

Support des triggers sur évènement par commande

Vous aimerez peut-être aussi