Projet

Général

Profil

Anomalie #329 » asgard_5_triggers_v15.sql

Leslie Lemaire, 31/08/2020 13:35

 
1

    
2
-- v0 2020.05.07 AF
3
-- ...
4
-- v7 2020.05.29 LL
5
-- v8 2020.05.29 LL
6
-- v9 2020.05.30 LL
7
-- v10 2020.06.02 LL
8
-- v11 2020.06.11 LL (asgard 0.7.0)
9
-- v12 2020.06.25 LL (asgard 0.7.1)
10
-- v13 2020.08.03 LL (asgard 1.0.0)
11
-- v14 2020.08.27 LL (asgard 1.0.0)
12
-- v15 2020.08.31 LL (asgard 1.0.0)
13
/*
14
trigger AFTER :
15
- meilleure prise en compte des valeurs NULL comme éléments
16
des array de ctrl, qui auraient pu fausser certains tests -
17
"= ANY(array_remove(NEW.ctrl, NULL))"
18
au lieu de "= ANY(NEW.ctrl)" ;
19
- simplification de la structuration des remontées d'erreurs ;
20
- le trigger n'ignore plus les INSERT pour l'application des
21
droits du producteur, ce qui empêchait la mise en cohérence des
22
propriétaires lors du référencement.
23

    
24
trigger BEFORE :
25
- meilleure prise en compte des valeurs NULL comme éléments
26
des array de ctrl, qui auraient pu fausser certains tests -
27
"= ANY(array_remove(NEW.ctrl, NULL))" au lieu de "= ANY(NEW.ctrl)" ;
28
- ajout de contrôles pour les modifications par g_admin sur des
29
schémas dont un super-utilisateur est producteur, y compris référencement ;
30
- amélioration du message d'erreur en cas de tentative de déférencement d'un
31
schéma de la nomenclature ;
32
- quelques HINT remplacés par DETAIL, qui paraissait plus approprié.
33
 */
34

    
35

    
36
-- MOT DE PASSE DE CONTRÔLE : 'x7-A;#rzo'
37
-- peut être modifié sans risque par rechercher/remplacer
38

    
39

    
40
---------------------------------------------
41
------ 5 - TRIGGERS SUR GESTION_SCHEMA ------
42
---------------------------------------------
43
/* 5.1 - TRIGGER BEFORE
44
   5.2 - TRIGGER AFTER */
45
   
46

    
47
------ 5.1 - TRIGGER BEFORE ------
48

    
49
-- FUNCTION: z_asgard_admin.asgard_on_modify_gestion_schema_before()
50

    
51
CREATE OR REPLACE FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_before() RETURNS trigger
52
    LANGUAGE plpgsql
53
    AS $BODY$
54
/* OBJET : Fonction exécutée par le trigger asgard_on_modify_gestion_schema_before,
55
           qui valide les informations saisies dans la table de gestion.
56
CIBLES : z_asgard_admin.gestion_schema.
57
PORTEE : FOR EACH ROW.
58
DECLENCHEMENT : BEFORE INSERT, UPDATE, DELETE.*/
59
DECLARE
60
    n_role text ;
61
BEGIN
62
    
63
    ------ INSERT PAR UN UTILISATEUR NON HABILITE ------
64
    IF TG_OP = 'INSERT' AND NOT has_database_privilege(current_database(), 'CREATE')
65
    -- même si creation vaut faux, seul un rôle habilité à créer des
66
    -- schéma peut ajouter des lignes dans la table de gestion
67
    THEN
68
        RAISE EXCEPTION 'TB1. Vous devez être habilité à créer des schémas pour réaliser cette opération.' ;
69
    END IF ;
70
    
71
    ------ APPLICATION DES VALEURS PAR DEFAUT ------
72
    -- au tout début car de nombreux tests sont faits par la
73
    -- suite sur "NOT NEW.creation"
74
    IF TG_OP IN ('INSERT', 'UPDATE')
75
    THEN
76
        NEW.creation := coalesce(NEW.creation, False) ;
77
        NEW.nomenclature := coalesce(NEW.nomenclature, False) ;
78
    END IF ;
79
    
80
    ------ EFFACEMENT D'UN ENREGISTREMENT ------
81
    IF TG_OP = 'DELETE'
82
    THEN   
83
        -- on n'autorise pas l'effacement si creation vaut True
84
        -- avec une exception pour les commandes envoyées par la fonction
85
        -- de maintenance asgard_sortie_gestion_schema
86
        IF OLD.creation AND (OLD.ctrl[1] IS NULL OR NOT OLD.ctrl[1] = 'EXIT')
87
        THEN
88
            RAISE EXCEPTION 'TB2. Opération interdite (schéma %). L''effacement n''est autorisé que si creation vaut False.', OLD.nom_schema
89
                USING HINT = 'Pour déréférencer un schéma sans le supprimer, vous pouvez utiliser la fonction z_asgard_admin.asgard_sortie_gestion_schema.' ;
90
        END IF;
91
        
92
        -- on n'autorise pas l'effacement pour les schémas de la nomenclature
93
        IF OLD.nomenclature
94
        THEN
95
            IF OLD.ctrl[1] = 'EXIT'
96
            THEN
97
                RAISE EXCEPTION 'TB26. Opération interdite (schéma %). Le déréférencement n''est pas autorisé pour les schémas de la nomenclature nationale.', OLD.nom_schema
98
                    USING HINT = 'Si vous tenez à déréférencer cet enregistrement, basculez préalablement nomenclature sur False.' ;
99
            ELSE
100
                RAISE EXCEPTION 'TB3. Opération interdite (schéma %). L''effacement n''est pas autorisé pour les schémas de la nomenclature nationale.', OLD.nom_schema
101
                    USING HINT = 'Si vous tenez à supprimer définitivement cet enregistrement, basculez préalablement nomenclature sur False.' ;
102
            END IF ;
103
        END IF ;
104
    END IF;
105

    
106
    ------ DE-CREATION D'UN SCHEMA ------
107
    IF TG_OP = 'UPDATE'
108
    THEN
109
        -- si bloc valait déjà d (schéma "mis à la corbeille")
110
        -- on exécute une commande de suppression du schéma. Toute autre modification sur
111
        -- la ligne est ignorée.
112
        IF OLD.bloc = 'd' AND OLD.creation AND NOT NEW.creation AND NEW.ctrl[2] IS NULL
113
                AND OLD.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
114
        THEN
115
            -- on bloque tout de même les tentatives de suppression
116
            -- par un utilisateur qui n'aurait pas des droits suffisants (a priori
117
            -- uniquement dans le cas de g_admin avec un schéma appartenant à un
118
            -- super-utilisateur).
119
            IF NOT pg_has_role(OLD.producteur, 'USAGE')
120
            THEN
121
                RAISE EXCEPTION 'TB23. Opération interdite (schéma %).', OLD.nom_schema
122
                    USING DETAIL = 'Seul les membres du rôle producteur ' || OLD.producteur || ' peuvent supprimer ce schéma.' ;
123
            ELSE
124
                EXECUTE 'DROP SCHEMA ' || quote_ident(OLD.nom_schema) || ' CASCADE' ;
125
                RAISE NOTICE '... Le schéma % a été supprimé.', OLD.nom_schema ;
126
                RETURN NULL ;
127
            END IF ;
128
        -- sinon, on n'autorise creation à passer de true à false que si le schéma
129
        -- n'existe plus (permet notamment à l'event trigger qui gère les
130
        -- suppressions de mettre creation à false)
131
        ELSIF OLD.creation and NOT NEW.creation
132
                AND NEW.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
133
        THEN
134
            RAISE EXCEPTION 'TB4. Opération interdite (schéma %). Le champ creation ne peut passer de True à False si le schéma existe.', NEW.nom_schema
135
                USING HINT =  'Si vous supprimez physiquement le schéma avec la commande DROP SCHEMA, creation basculera sur False automatiquement.' ;
136
        END IF ;
137
    END IF ;
138
    
139
    IF TG_OP <> 'DELETE'
140
    THEN
141
        ------ PROHIBITION DE LA SAISIE MANUELLE DES OID ------
142
        -- vérifié grâce au champ ctrl
143
        IF NEW.ctrl[2] IS NULL
144
            OR NOT array_length(NEW.ctrl, 1) >= 2
145
            OR NEW.ctrl[1] IS NULL
146
            OR NOT NEW.ctrl[1] IN ('CREATE', 'RENAME', 'OWNER', 'DROP', 'SELF', 'EXIT')
147
            OR NOT NEW.ctrl[2] = 'x7-A;#rzo'
148
            -- ctrl NULL ou invalide
149
        THEN
150

    
151
            IF NEW.ctrl[1] = 'EXIT'
152
            THEN
153
                RAISE EXCEPTION 'TB17. Opération interdite (schéma %).', coalesce(NEW.nom_schema, '?')
154
                    USING HINT = 'Pour déréférencer un schéma, veuillez utiliser la fonction z_asgard_admin.asgard_sortie_gestion_schema.' ;
155
            END IF ;
156
            
157
            -- réinitialisation du champ ctrl, qui peut contenir des informations
158
            -- issues de commandes antérieures (dans ctrl[1])
159
            NEW.ctrl := ARRAY['MANUEL', NULL]::text[] ;
160
            
161
            IF TG_OP = 'INSERT' AND (
162
                    NEW.oid_producteur IS NOT NULL
163
                    OR NEW.oid_lecteur IS NOT NULL
164
                    OR NEW.oid_editeur IS NOT NULL
165
                    OR NEW.oid_schema IS NOT NULL
166
                    )
167
            -- cas d'un INSERT manuel pour lequel des OID ont été saisis
168
            -- on les remet à NULL
169
            THEN
170
                NEW.oid_producteur = NULL ;
171
                NEW.oid_editeur = NULL ;
172
                NEW.oid_lecteur = NULL ;
173
                NEW.oid_schema = NULL ;
174
            ELSIF TG_OP = 'UPDATE'
175
            THEN
176
                IF NOT coalesce(NEW.oid_producteur, -1) = coalesce(OLD.oid_producteur, -1)
177
                        OR NOT coalesce(NEW.oid_editeur, -1) = coalesce(OLD.oid_editeur, -1)
178
                        OR NOT coalesce(NEW.oid_lecteur, -1) = coalesce(OLD.oid_lecteur, -1)
179
                        OR NOT coalesce(NEW.oid_schema, -1) = coalesce(OLD.oid_schema, -1)
180
                -- cas d'un UPDATE avec modification des OID
181
                -- on les remet à OLD
182
                THEN
183
                    NEW.oid_producteur = OLD.oid_producteur ;
184
                    NEW.oid_editeur = OLD.oid_editeur ;
185
                    NEW.oid_lecteur = OLD.oid_lecteur ;
186
                    NEW.oid_schema = OLD.oid_schema ;
187
                END IF ;
188
            END IF ;                
189
        ELSE
190
            -- suppression du mot de passe de contrôle.
191
            -- ctrl[1] est par contre conservé - il sera utilisé
192
            -- par le trigger AFTER pour connaître l'opération
193
            -- à l'origine de son déclenchement.
194
            NEW.ctrl[2] := NULL ;
195
        END IF ;
196
        
197
        ------ REQUETES AUTO A IGNORER ------
198
        -- les remontées du trigger AFTER (SELF)
199
        -- sont exclues, car les contraintes ont déjà
200
        -- été validées (et pose problèmes avec les
201
        -- contrôles d'OID sur les UPDATE, car ceux-ci
202
        -- ne seront pas nécessairement déjà remplis) ;
203
        -- les requêtes EXIT de même, car c'est un
204
        -- pré-requis à la suppression qui ne fait
205
        -- que modifier le champ ctrl
206
        IF NEW.ctrl[1] IN ('SELF', 'EXIT')
207
        THEN
208
            -- aucune action
209
            RETURN NEW ;
210
        END IF ;
211
        
212
        ------ VERROUILLAGE DES CHAMPS LIES A LA NOMENCLATURE ------
213
        -- modifiables uniquement par l'ADL
214
        IF TG_OP = 'UPDATE'
215
        THEN
216
            IF (OLD.nomenclature OR NEW.nomenclature) AND NOT pg_has_role('g_admin', 'MEMBER') AND (
217
                    NOT coalesce(OLD.nomenclature, False) = coalesce(NEW.nomenclature, False)
218
                    OR NOT coalesce(OLD.niv1, '') = coalesce(NEW.niv1, '')
219
                    OR NOT coalesce(OLD.niv1_abr, '') = coalesce(NEW.niv1_abr, '')
220
                    OR NOT coalesce(OLD.niv2, '') = coalesce(NEW.niv2, '')
221
                    OR NOT coalesce(OLD.niv2_abr, '') = coalesce(NEW.niv2_abr, '')
222
                    OR NOT coalesce(OLD.nom_schema, '') = coalesce(NEW.nom_schema, '')
223
                    OR NOT coalesce(OLD.bloc, '') = coalesce(NEW.bloc, '')
224
                    )
225
            THEN
226
                RAISE EXCEPTION 'TB18. Opération interdite (schéma %).', NEW.nom_schema
227
                    USING DETAIL = 'Seuls les membres de g_admin sont habilités à modifier les champs nomenclature et - pour les schémas de la nomenclature - bloc, niv1, niv1_abr, niv2, niv2_abr et nom_schema.' ;
228
            END IF ;
229
        ELSIF TG_OP = 'INSERT'
230
        THEN
231
            IF NEW.nomenclature AND NOT pg_has_role('g_admin', 'MEMBER')
232
            THEN
233
                RAISE EXCEPTION 'TB19. Opération interdite (schéma %).', NEW.nom_schema
234
                    USING DETAIL = 'Seuls les membres de g_admin sont autorisés à ajouter des schémas à la nomenclature (nomenclature = True).' ;
235
            END IF ;
236
        END IF ;
237
    
238
        ------ NETTOYAGE DES CHAÎNES VIDES ------
239
        -- si l'utilisateur a entré des chaînes vides on met des NULL
240
        NEW.editeur := nullif(NEW.editeur, '') ;
241
        NEW.lecteur := nullif(NEW.lecteur, '') ;
242
        NEW.bloc := nullif(NEW.bloc, '') ;
243
        NEW.niv1 := nullif(NEW.niv1, '') ;
244
        NEW.niv1_abr := nullif(NEW.niv1_abr, '') ;
245
        NEW.niv2 := nullif(NEW.niv2, '') ;
246
        NEW.niv2_abr := nullif(NEW.niv2_abr, '') ;
247
        NEW.nom_schema := nullif(NEW.nom_schema, '') ;
248
        -- si producteur est vide on met par défaut g_admin
249
        NEW.producteur := coalesce(nullif(NEW.producteur, ''), 'g_admin') ;
250
        
251
        ------ NETTOYAGE DES CHAMPS OID ------
252
        -- pour les rôles de lecteur et éditeur,
253
        -- si le champ de nom est vidé par l'utilisateur,
254
        -- on vide en conséquence l'OID
255
        IF NEW.editeur IS NULL
256
        THEN
257
            NEW.oid_editeur := NULL ;
258
        END IF ;
259
        IF NEW.lecteur IS NULL
260
        THEN
261
            NEW.oid_lecteur := NULL ;
262
        END IF ;
263
        -- si le schéma n'est pas créé, on s'assure que les champs
264
        -- d'OID restent vides
265
        -- à noter que l'event trigger sur DROP SCHEMA vide
266
        -- déjà le champ oid_schema
267
        IF NOT NEW.creation
268
        THEN
269
            NEW.oid_schema := NULL ;
270
            NEW.oid_lecteur := NULL ;
271
            NEW.oid_editeur := NULL ;
272
            NEW.oid_producteur := NULL ;
273
        END IF ;
274
        
275
        ------ VALIDITE DES NOMS DE ROLES ------
276
        -- dans le cas d'un schéma pré-existant, on s'assure que les rôles qui
277
        -- ne changent pas sont toujours valides (qu'ils existent et que le nom
278
        -- n'a pas été modifié entre temps)
279
        -- si tel est le cas, on les met à jour et on le note dans
280
        -- ctrl, pour que le trigger AFTER sache qu'il ne s'agit
281
        -- pas réellement de nouveaux rôles sur lesquels les droits
282
        -- devraient être réappliqués
283
        IF TG_OP = 'UPDATE' AND NEW.creation
284
        THEN
285
            -- producteur
286
            IF OLD.creation AND OLD.producteur = NEW.producteur
287
            THEN
288
                SELECT rolname INTO n_role
289
                    FROM pg_catalog.pg_roles
290
                    WHERE pg_roles.oid = NEW.oid_producteur ;
291
                IF NOT FOUND
292
                -- le rôle producteur n'existe pas
293
                THEN
294
                    -- cas invraisemblable, car un rôle ne peut pas être
295
                    -- supprimé alors qu'il est propriétaire d'un schéma, et la
296
                    -- commande ALTER SCHEMA OWNER TO aurait été interceptée
297
                    -- mais, s'il advient, on repart du propriétaire
298
                    -- renseigné dans pg_namespace
299
                    SELECT replace(nspowner::regrole::text, '"', ''), nspowner
300
                        INTO NEW.producteur, NEW.oid_producteur
301
                        FROM pg_catalog.pg_namespace
302
                        WHERE pg_namespace.oid = NEW.oid_schema ;
303
                    RAISE NOTICE '[table de gestion] ANOMALIE. Schéma %. L''OID actuellement renseigné pour le producteur est invalide. Poursuite avec l''OID du propriétaire courant du schéma.', NEW.nom_schema ;
304
                    NEW.ctrl := array_append(NEW.ctrl, 'CLEAN producteur') ;
305
                ELSIF NOT n_role = NEW.producteur
306
                -- libellé obsolète du producteur
307
                THEN
308
                    NEW.producteur := n_role ;
309
                    RAISE NOTICE '[table de gestion] Schéma %. Mise à jour du libellé du rôle producteur, renommé entre temps.', NEW.nom_schema
310
                        USING DETAIL = 'Ancien nom "' || OLD.producteur || '", nouveau nom "' || NEW.producteur || '".' ;
311
                    NEW.ctrl := array_append(NEW.ctrl, 'CLEAN producteur') ;
312
                END IF ; 
313
            END IF ;
314
            -- éditeur
315
            IF OLD.creation AND OLD.editeur = NEW.editeur
316
                    AND NOT NEW.editeur = 'public'
317
            THEN
318
                SELECT rolname INTO n_role
319
                    FROM pg_catalog.pg_roles
320
                    WHERE pg_roles.oid = NEW.oid_editeur ;
321
                IF NOT FOUND
322
                -- le rôle éditeur n'existe pas
323
                THEN
324
                    NEW.editeur := NULL ;
325
                    NEW.oid_editeur := NULL ;
326
                    RAISE NOTICE '[table de gestion] Schéma %. Le rôle éditeur n''existant plus, il est déréférencé.', NEW.nom_schema
327
                        USING DETAIL = 'Ancien nom "' || OLD.editeur || '".' ;
328
                    NEW.ctrl := array_append(NEW.ctrl, 'CLEAN editeur') ;
329
                ELSIF NOT n_role = NEW.editeur
330
                -- libellé obsolète de l'éditeur
331
                THEN
332
                    NEW.editeur := n_role ;
333
                    RAISE NOTICE '[table de gestion] Schéma %. Mise à jour du libellé du rôle éditeur, renommé entre temps.', NEW.nom_schema
334
                        USING DETAIL = 'Ancien nom "' || OLD.editeur || '", nouveau nom "' || NEW.editeur || '".' ;
335
                    NEW.ctrl := array_append(NEW.ctrl, 'CLEAN editeur') ;
336
                END IF ; 
337
            END IF ;
338
            -- lecteur
339
            IF OLD.creation AND OLD.lecteur = NEW.lecteur
340
                    AND NOT NEW.lecteur = 'public'
341
            THEN
342
                SELECT rolname INTO n_role
343
                    FROM pg_catalog.pg_roles
344
                    WHERE pg_roles.oid = NEW.oid_lecteur ;
345
                IF NOT FOUND
346
                -- le rôle lecteur n'existe pas
347
                THEN
348
                    NEW.lecteur := NULL ;
349
                    NEW.oid_lecteur := NULL ;
350
                    RAISE NOTICE '[table de gestion] Schéma %. Le rôle lecteur n''existant plus, il est déréférencé.', NEW.nom_schema
351
                        USING DETAIL = 'Ancien nom "' || OLD.lecteur || '".' ;
352
                    NEW.ctrl := array_append(NEW.ctrl, 'CLEAN lecteur') ;
353
                ELSIF NOT n_role = NEW.lecteur
354
                -- libellé obsolète du lecteur
355
                THEN
356
                    NEW.lecteur := n_role ;
357
                    RAISE NOTICE '[table de gestion] Schéma %. Mise à jour du libellé du rôle lecteur, renommé entre temps.', NEW.nom_schema
358
                        USING DETAIL = 'Ancien nom "' || OLD.lecteur || '", nouveau nom "' || NEW.lecteur || '".' ;
359
                    NEW.ctrl := array_append(NEW.ctrl, 'CLEAN lecteur') ;
360
                END IF ; 
361
            END IF ;    
362
        END IF ;
363

    
364
        ------ NON RESPECT DES CONTRAINTES ------
365
        -- non nullité de nom_schema
366
        IF NEW.nom_schema IS NULL
367
        THEN
368
            RAISE EXCEPTION 'TB8. Saisie incorrecte. Le nom du schéma doit être renseigné (champ nom_schema).' ;
369
        END IF ;
370
        
371
        -- unicité de nom_schema
372
        -- -> contrôlé après les manipulations sur les blocs de
373
        -- la partie suivante.
374
        
375
        -- unicité de oid_schema
376
        IF TG_OP = 'INSERT' AND NEW.oid_schema IN (SELECT gestion_schema_etr.oid_schema FROM z_asgard.gestion_schema_etr
377
                                                       WHERE gestion_schema_etr.oid_schema IS NOT NULL)
378
        THEN
379
            RAISE EXCEPTION 'TB11. Saisie incorrecte (schéma %). Un schéma de même OID est déjà répertorié dans la table de gestion.', NEW.nom_schema ;
380
        ELSIF TG_OP = 'UPDATE'
381
        THEN
382
            -- cas (très hypothétique) d'une modification d'OID
383
            IF NOT coalesce(NEW.oid_schema, -1) = coalesce(OLD.oid_schema, -1)
384
                    AND NEW.oid_schema IN (SELECT gestion_schema_etr.oid_schema FROM z_asgard.gestion_schema_etr
385
                                                       WHERE gestion_schema_etr.oid_schema IS NOT NULL)
386
            THEN
387
                RAISE EXCEPTION 'TB12. Saisie incorrecte (schéma %). Un schéma de même OID est déjà répertorié dans la table de gestion.', NEW.nom_schema ;
388
            END IF ;
389
        END IF ;
390
        
391
        -- non répétition des rôles
392
        IF NOT ((NEW.oid_lecteur IS NULL OR NOT NEW.oid_lecteur = NEW.oid_producteur)
393
                AND (NEW.oid_editeur IS NULL OR NOT NEW.oid_editeur = NEW.oid_producteur)
394
                AND (NEW.oid_lecteur IS NULL OR NEW.oid_editeur IS NULL OR NOT NEW.oid_lecteur = NEW.oid_editeur))
395
        THEN
396
            RAISE EXCEPTION 'TB13. Saisie incorrecte (schéma %). Les rôles producteur, lecteur et éditeur doivent être distincts.', NEW.nom_schema ;
397
        END IF ;
398
    END IF ;
399
    
400
    ------ COHERENCE BLOC/NOM DU SCHEMA ------
401
    IF TG_OP IN ('INSERT', 'UPDATE')
402
    THEN
403
        IF NEW.bloc IS NULL AND NEW.nom_schema ~ '^[a-z]_'
404
        -- si bloc est NULL, mais que le nom du schéma
405
        -- comporte un préfixe, on met ce préfixe dans bloc
406
        THEN
407
            NEW.bloc := substring(NEW.nom_schema, '^([a-z])_') ;
408
            RAISE NOTICE '[table de gestion] Mise à jour du bloc pour le schéma %.', NEW.nom_schema || ' (' || NEW.bloc || ')' ;
409
        ELSIF NEW.bloc IS NULL
410
        -- si bloc est NULL, et que (sous-entendu) le nom du schéma ne
411
        -- respecte pas la nomenclature, on avertit l'utilisateur
412
        THEN            
413
            RAISE NOTICE '[table de gestion] Le nom du schéma % ne respecte pas la nomenclature.', NEW.nom_schema
414
                USING HINT = 'Si vous saisissez un préfixe dans le champ bloc, il sera automatiquement ajouté au nom du schéma.' ;
415
        ELSIF NOT NEW.nom_schema ~ ('^'|| NEW.bloc || '_') AND NOT NEW.bloc = 'd'
416
        -- le bloc est renseigné mais le nom du schéma ne correspond pas
417
        -- (et il ne s'agit pas d'un schéma mis à la corbeille) :
418
        -- si le nom est de la forme 'a_...', alors :
419
        -- - dans le cas d'un UPDATE avec modification du nom
420
        -- du schéma et pas du bloc, on se fie au nom du schéma
421
        -- et on change le bloc ;
422
        -- - si bloc n'est pas une lettre, on renvoie une erreur ;
423
        -- - dans les autres cas, on se fie au bloc et change le
424
        -- préfixe.
425
        -- Si le nom ne comporte pas de préfixe :
426
        -- - si le bloc est une lettre, on l'ajoute au début du
427
        -- nom (sans doubler l'underscore, si le nom commençait par
428
        -- un underscore) ;
429
        -- - sinon on renvoie une erreur.
430
        THEN
431
            IF NEW.nom_schema ~ '^([a-z])?_'
432
            THEN
433
                IF TG_OP = 'UPDATE'
434
                THEN
435
                    IF NOT NEW.nom_schema = OLD.nom_schema AND NEW.bloc = OLD.bloc
436
                    THEN
437
                        NEW.bloc := substring(NEW.nom_schema, '^([a-z])_') ;
438
                        RAISE NOTICE '[table de gestion] Mise à jour du bloc pour le schéma %.', NEW.nom_schema || ' (' || NEW.bloc || ')' ;
439
                    ELSIF NOT NEW.bloc ~ '^[a-z]$'
440
                    THEN
441
                        RAISE EXCEPTION 'TB14. Saisie invalide (schéma %). Le bloc doit être une lettre minuscule ou rien.', NEW.nom_schema ;
442
                    ELSE
443
                        NEW.nom_schema := regexp_replace(NEW.nom_schema, '^([a-z])?_', NEW.bloc || '_') ;
444
                        RAISE NOTICE '[table de gestion] Mise à jour du préfixe du schéma %.', NEW.nom_schema || ' d''après son bloc (' || NEW.bloc || ')' ;
445
                    END IF ;
446
                ELSIF NOT NEW.bloc ~ '^[a-z]$'
447
                THEN
448
                    RAISE EXCEPTION 'TB15. Saisie invalide (schéma %). Le bloc doit être une lettre minuscule ou rien.', NEW.nom_schema ;
449
                ELSE
450
                    NEW.nom_schema := regexp_replace(NEW.nom_schema, '^([a-z])?_', NEW.bloc || '_') ;
451
                    RAISE NOTICE '[table de gestion] Mise à jour du préfixe du schéma %.', NEW.nom_schema || ' d''après son bloc (' || NEW.bloc || ')' ;
452
                END IF ;
453
            ELSIF NOT NEW.bloc ~ '^[a-z]$'
454
            THEN
455
                RAISE EXCEPTION 'TB16. Saisie invalide (schéma %). Le bloc doit être une lettre minuscule ou rien.', NEW.nom_schema ;
456
            ELSE
457
                NEW.nom_schema := NEW.bloc || '_' || NEW.nom_schema ;
458
                RAISE NOTICE '[table de gestion] Mise à jour du préfixe du schéma %.', NEW.nom_schema || ' d''après son bloc (' || NEW.bloc || ')' ;
459
            END IF ;
460
            -- le trigger AFTER se chargera de renommer physiquement le
461
            -- schéma d'autant que de besoin
462
        END IF ;
463
    END IF ;
464
    
465
    ------ NON RESPECT DES CONTRAINTES (SUITE) ------
466
    -- unicité de nom_schema
467
    IF TG_OP IN ('INSERT', 'UPDATE')
468
    THEN
469
        IF TG_OP = 'INSERT' AND NEW.nom_schema IN (SELECT gestion_schema_etr.nom_schema FROM z_asgard.gestion_schema_etr)
470
        THEN
471
            RAISE EXCEPTION 'TB9. Saisie incorrecte (schéma %). Un schéma de même nom est déjà répertorié dans la table de gestion.', NEW.nom_schema ;
472
        ELSIF TG_OP = 'UPDATE'
473
        THEN
474
            -- cas d'un changement de nom
475
            IF NOT NEW.nom_schema = OLD.nom_schema
476
                   AND NEW.nom_schema IN (SELECT gestion_schema_etr.nom_schema FROM z_asgard.gestion_schema_etr)
477
            THEN 
478
                RAISE EXCEPTION 'TB10. Saisie incorrecte (schéma %). Un schéma de même nom est déjà répertorié dans la table de gestion.', NEW.nom_schema ;
479
            END IF ;
480
        END IF ;
481
    END IF ;
482
    
483
    ------ MISE À LA CORBEILLE ------
484
    -- notification de l'utilisateur
485
    IF TG_OP = 'UPDATE'
486
    THEN
487
        -- schéma existant dont bloc bascule sur 'd'
488
        -- ou schéma créé par bascule de creation sur True dans bloc vaut 'd'
489
        IF NEW.creation AND NEW.bloc = 'd' AND (NOT OLD.bloc = 'd' OR OLD.bloc IS NULL)
490
                OR NEW.creation AND NOT OLD.creation AND NEW.bloc = 'd'
491
        THEN
492
            RAISE NOTICE '[table de gestion] Le schéma % a été mis à la corbeille (bloc = ''d'').', NEW.nom_schema
493
                USING HINT = 'Si vous basculez creation sur False, le schéma et son contenu seront automatiquement supprimés.' ;
494
        -- restauration
495
        ELSIF NEW.creation AND OLD.bloc = 'd' AND (NOT NEW.bloc = 'd' OR NEW.bloc IS NULL)
496
        THEN
497
            RAISE NOTICE '[table de gestion] Le schéma % a été retiré de la corbeille (bloc ne vaut plus ''d'').', NEW.nom_schema ;
498
        END IF ;
499
    ELSIF TG_OP = 'INSERT'
500
    THEN
501
        -- nouveau schéma dont bloc vaut 'd'
502
        IF NEW.creation AND NEW.bloc = 'd'
503
        THEN
504
            RAISE NOTICE '[table de gestion] Le schéma % a été mis à la corbeille (bloc = ''d'').', NEW.nom_schema
505
                USING HINT = 'Si vous basculez creation sur False, le schéma et son contenu seront automatiquement supprimés.' ;  
506
        END IF ;
507
    END IF ;
508
    
509
    ------ SCHEMAS DES SUPER-UTILISATEURS ------
510
    -- concerne uniquement les membres de g_admin, qui voient tous
511
    -- les schémas, y compris ceux des super-utilisateurs dont ils
512
    -- ne sont pas membres. Les contrôles suivants bloquent dans ce
513
    -- cas les tentatives de mise à jour des champs nom_schema,
514
    -- producteur, editeur et lecteur, ainsi que les création de schéma
515
    -- via un INSERT ou un UPDATE.
516
    IF TG_OP = 'UPDATE'
517
    THEN
518
        IF NOT pg_has_role(OLD.producteur, 'USAGE')
519
            AND OLD.producteur IN (SELECT rolname FROM pg_catalog.pg_roles WHERE rolsuper)
520
            AND OLD.creation
521
            AND (
522
                NOT OLD.nom_schema = NEW.nom_schema
523
                OR NOT OLD.producteur = NEW.producteur AND (NEW.ctrl IS NULL OR NOT 'CLEAN producteur' = ANY(array_remove(NEW.ctrl, NULL)))
524
                OR NOT coalesce(OLD.editeur, '') = coalesce(NEW.editeur, '') AND (NEW.ctrl IS NULL OR NOT 'CLEAN editeur' = ANY(array_remove(NEW.ctrl, NULL)))
525
                OR NOT coalesce(OLD.lecteur, '') = coalesce(NEW.lecteur, '') AND (NEW.ctrl IS NULL OR NOT 'CLEAN lecteur' = ANY(array_remove(NEW.ctrl, NULL)))
526
                )
527
        THEN
528
            RAISE EXCEPTION 'TB20. Opération interdite (schéma %).', OLD.nom_schema
529
                USING DETAIL = 'Seul le rôle producteur ' || OLD.producteur || ' (super-utilisateur) peut modifier ce schéma.' ;
530
        ELSIF NOT pg_has_role(NEW.producteur, 'USAGE')
531
            AND NEW.producteur IN (SELECT rolname FROM pg_catalog.pg_roles WHERE rolsuper)
532
            AND NEW.creation AND NOT OLD.creation
533
        THEN
534
            RAISE EXCEPTION 'TB21. Opération interdite (schéma %).', NEW.nom_schema
535
                USING DETAIL = 'Seul le super-utilisateur ' || NEW.producteur || ' peut créer un schéma dont il est identifié comme producteur.' ;
536
        ELSIF NOT pg_has_role(NEW.producteur, 'USAGE')
537
            AND NEW.producteur IN (SELECT rolname FROM pg_catalog.pg_roles WHERE rolsuper)
538
            AND NEW.creation
539
            AND NOT OLD.producteur = NEW.producteur AND (NEW.ctrl IS NULL OR NOT 'CLEAN producteur' = ANY(array_remove(NEW.ctrl, NULL)))
540
        THEN
541
            RAISE EXCEPTION 'TB24. Opération interdite (schéma %).', NEW.nom_schema
542
                USING DETAIL = 'Seul le super-utilisateur ' || NEW.producteur || ' peut se désigner comme producteur d''un schéma.' ;
543
        END IF ;
544
    ELSIF TG_OP = 'INSERT'
545
    THEN
546
        IF NOT pg_has_role(NEW.producteur, 'USAGE')
547
            AND NEW.producteur IN (SELECT rolname FROM pg_catalog.pg_roles WHERE rolsuper)
548
            AND NEW.creation
549
            AND NOT NEW.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
550
            -- on exclut les schémas en cours de référencement, qui sont gérés
551
            -- juste après, avec leur propre message d'erreur
552
        THEN
553
            RAISE EXCEPTION 'TB22. Opération interdite (schéma %).', NEW.nom_schema
554
                USING DETAIL = 'Seul le super-utilisateur ' || NEW.producteur || ' peut créer un schéma dont il est identifié comme producteur.' ;
555
        ELSIF NOT pg_has_role(NEW.producteur, 'USAGE')
556
            AND NEW.producteur IN (SELECT rolname FROM pg_catalog.pg_roles WHERE rolsuper)
557
            AND NEW.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
558
            -- schéma pré-existant en cours de référencement
559
        THEN
560
            RAISE EXCEPTION 'TB25. Opération interdite (schéma %).', NEW.nom_schema
561
                USING DETAIL = 'Seul le super-utilisateur ' || NEW.producteur || ' peut référencer dans ASGARD un schéma dont il est identifié comme producteur.' ;
562
        END IF ;
563
    END IF ;
564
    
565
    ------ RETURN ------
566
	IF TG_OP IN ('UPDATE', 'INSERT')
567
    THEN
568
        RETURN NEW ;
569
    ELSIF TG_OP = 'DELETE'
570
    THEN
571
        RETURN OLD ;
572
    END IF ;
573
    
574
END
575
$BODY$ ;
576

    
577
ALTER FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_before()
578
    OWNER TO g_admin ;
579

    
580
COMMENT ON FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_before() IS 'ASGARD. Fonction appelée par le trigger qui valide les modifications de la table de gestion.';
581

    
582

    
583
-- Trigger: asgard_on_modify_gestion_schema_before
584

    
585
CREATE TRIGGER asgard_on_modify_gestion_schema_before
586
    BEFORE INSERT OR DELETE OR UPDATE
587
    ON z_asgard_admin.gestion_schema
588
    FOR EACH ROW
589
    EXECUTE PROCEDURE z_asgard_admin.asgard_on_modify_gestion_schema_before() ;
590
    
591
COMMENT ON TRIGGER asgard_on_modify_gestion_schema_before ON z_asgard_admin.gestion_schema IS 'ASGARD. Trigger qui valide les modifications de la table de gestion.';
592
    
593

    
594

    
595
------ 5.2 - TRIGGER AFTER ------
596

    
597
-- FUNCTION: z_asgard_admin.asgard_on_modify_gestion_schema_after()
598

    
599
CREATE OR REPLACE FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_after() RETURNS trigger
600
    LANGUAGE plpgsql
601
    AS $BODY$
602
/* OBJET : Fonction exécutée par le trigger asgard_on_modify_gestion_schema_after,
603
           qui répercute physiquement les modifications de la table de gestion.
604
CIBLES : z_asgard_admin.gestion_schema.
605
PORTEE : FOR EACH ROW.
606
DECLENCHEMENT : AFTER INSERT OR UPDATE.*/
607
DECLARE
608
    utilisateur text ;
609
    createur text ;
610
    administrateur text ;
611
    e_mssg text ;
612
    e_hint text ;
613
    e_detl text ;
614
    b_superuser boolean ;
615
    b_test boolean ;
616
    l_commande text[] ;
617
    c text ;
618
    c_reverse text ;
619
    a_producteur text ;
620
    a_editeur text ;
621
    a_lecteur text ;
622
    n int ;
623
BEGIN
624

    
625
    ------ REQUETES AUTO A IGNORER ------
626
    -- les remontées du trigger lui-même (SELF),
627
    -- ainsi que des event triggers sur les
628
    -- suppressions de schémas (DROP), n'appellent
629
    -- aucune action, elles sont donc exclues dès
630
    -- le départ
631
    -- les remontées des changements de noms sont
632
    -- conservées, pour le cas où la mise en
633
    -- cohérence avec "bloc" aurait conduit à une
634
    -- modification du nom par le trigger BEFORE
635
    -- (géré au point suivant)
636
    -- les remontées des créations et changements
637
    -- de propriétaire (CREATE et OWNER) appellent
638
    -- des opérations sur les droits plus lourdes
639
    -- qui ne permettent pas de les exclure en
640
    -- amont
641
    IF NEW.ctrl[1] IN ('SELF', 'DROP')
642
    THEN
643
        -- aucune action
644
        RETURN NULL ;
645
    END IF ;
646

    
647
    ------ MANIPULATIONS PREALABLES ------
648
    utilisateur := current_user ;
649
    
650
    -- si besoin pour les futures opérations sur les rôles,
651
    -- récupération du nom d'un rôle dont current_user est membre
652
    -- et qui a l'attribut CREATEROLE. Autant que possible, la
653
    -- requête renvoie current_user lui-même. On exclut d'office les
654
    -- rôles NOINHERIT qui ne pourront pas avoir simultanément les
655
    -- droits du propriétaire de NEW et OLD.producteur
656
    SELECT rolname INTO createur FROM pg_roles
657
        WHERE pg_has_role(rolname, 'MEMBER') AND rolcreaterole AND rolinherit
658
        ORDER BY rolname = current_user DESC ;
659
    
660
    IF TG_OP = 'UPDATE'
661
    THEN
662
        -- la validité de OLD.producteur n'ayant
663
        -- pas été contrôlée par le trigger BEFORE,
664
        -- on le fait maintenant
665
        SELECT rolname INTO a_producteur
666
            FROM pg_catalog.pg_roles
667
            WHERE pg_roles.oid = OLD.oid_producteur ;
668
        -- pour la suite, on emploira toujours
669
        -- a_producteur à la place de OLD.producteur
670
        -- pour les opérations sur les droits.
671
        -- Il est réputé non NULL pour un schéma
672
        -- pré-existant (OLD.creation vaut True),
673
        -- dans la mesure où un rôle ne peut être
674
        -- supprimé s'il est propriétaire d'un
675
        -- schéma et où tous les changements de
676
        -- propriétaires sont remontés par event
677
        -- triggers (+ contrôles pour assurer la
678
        -- non-modification manuelle des OID).
679
        IF NOT FOUND AND OLD.creation AND (NEW.ctrl IS NULL OR NOT 'CLEAN producteur' = ANY(array_remove(NEW.ctrl, NULL)))
680
        THEN
681
            RAISE NOTICE '[table de gestion] ANOMALIE. Schéma %. L''OID actuellement renseigné pour le producteur dans la table de gestion est invalide. Poursuite avec l''OID du propriétaire courant du schéma.', OLD.nom_schema ;
682
            SELECT replace(nspowner::regrole::text, '"', '') INTO a_producteur
683
                FROM pg_catalog.pg_namespace
684
                WHERE pg_namespace.oid = NEW.oid_schema ;
685
            IF NOT FOUND
686
            THEN
687
                RAISE EXCEPTION 'TA1. Anomalie critique (schéma %). Le propriétaire du schéma est introuvable.', OLD.nom_schema ;
688
            END IF ;
689
        END IF ;
690
    END IF ;
691

    
692
    ------ MISE EN APPLICATION D'UN CHANGEMENT DE NOM DE SCHEMA ------
693
    IF NOT NEW.oid_schema::regnamespace::text = quote_ident(NEW.nom_schema)
694
    -- le schéma existe et ne porte pas déjà le nom NEW.nom_schema
695
    THEN
696
        EXECUTE 'ALTER SCHEMA '|| NEW.oid_schema::regnamespace::text ||
697
                ' RENAME TO ' || quote_ident(NEW.nom_schema) ;
698
        RAISE NOTICE '... Le schéma % a été renommé.', NEW.nom_schema ;
699
    END IF ; 
700
    -- exclusion des remontées d'event trigger correspondant
701
    -- à des changements de noms
702
    IF NEW.ctrl[1] = 'RENAME'
703
    THEN
704
        -- aucune action
705
        RETURN NULL ;
706
    END IF ;
707

    
708
    ------ PREPARATION DU PRODUCTEUR ------
709
    -- on ne s'intéresse pas aux cas :
710
    -- - d'un schéma qui n'a pas/plus vocation à exister
711
    --   (creation vaut False) ;
712
    -- - d'un schéma pré-existant dont les rôles ne changent pas
713
    --   ou dont le libellé a juste été nettoyé par le trigger
714
    --   BEFORE.
715
    -- ils sont donc exclus au préalable
716
    -- si le moindre rôle a changé, il faudra être membre du
717
    -- groupe propriétaire/producteur pour pouvoir modifier
718
    -- les privilèges en conséquence
719
    b_test := False ;
720
    IF NOT NEW.creation
721
    THEN
722
        b_test := True ;
723
    ELSIF TG_OP = 'UPDATE'
724
    THEN
725
        IF OLD.creation
726
                AND (NEW.producteur = OLD.producteur  OR 'CLEAN producteur' = ANY(array_remove(NEW.ctrl, NULL)))
727
                AND (coalesce(NEW.editeur, '') = coalesce(OLD.editeur, '') OR 'CLEAN editeur' = ANY(array_remove(NEW.ctrl, NULL)))
728
                AND (coalesce(NEW.lecteur, '') = coalesce(OLD.lecteur, '') OR 'CLEAN lecteur' = ANY(array_remove(NEW.ctrl, NULL)))
729
        THEN
730
            b_test := True ;
731
        END IF ;
732
    END IF ;
733
    
734
    IF NOT b_test
735
    THEN
736
        IF NOT NEW.producteur IN (SELECT rolname FROM pg_catalog.pg_roles)
737
        -- si le producteur désigné n'existe pas, on le crée
738
        -- ou renvoie une erreur si les privilèges de l'utilisateur
739
        -- sont insuffisants
740
        THEN
741
            IF createur IS NULL
742
            THEN
743
                RAISE EXCEPTION 'TA2. Opération interdite. Vous n''êtes pas habilité à créer le rôle %.', NEW.producteur
744
                    USING HINT = 'Être membre d''un rôle disposant des attributs CREATEROLE et INHERIT est nécessaire pour créer de nouveaux producteurs.' ;
745
            END IF ;
746
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;
747
            EXECUTE 'CREATE ROLE ' || quote_ident(NEW.producteur) ;
748
            RAISE NOTICE '... Le rôle de groupe % a été créé.', NEW.producteur ;
749
            EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;                
750
        ELSE
751
        -- si le rôle producteur existe, on vérifie qu'il n'a pas l'option LOGIN
752
        -- les superusers avec LOGIN (comme postgres) sont tolérés
753
        -- paradoxe ou non, dans l'état actuel des choses, cette erreur se
754
        -- déclenche aussi lorsque la modification ne porte que sur les rôles
755
        -- lecteur/éditeur
756
            SELECT rolsuper INTO b_superuser
757
                FROM pg_roles WHERE rolname = NEW.producteur AND rolcanlogin ;
758
            IF NOT b_superuser
759
            THEN
760
                RAISE EXCEPTION 'TA3. Opération interdite (schéma %). Le producteur/propriétaire du schéma ne doit pas être un rôle de connexion.', NEW.nom_schema ;
761
            END IF ;
762
        END IF ;
763
        b_superuser := coalesce(b_superuser, False) ;
764
        
765
        -- mise à jour du champ d'OID du producteur
766
        IF NEW.ctrl[1] IS NULL OR NOT NEW.ctrl[1] IN ('OWNER', 'CREATE')
767
        -- pas dans le cas d'une remontée de commande directe
768
        -- où l'OID du producteur sera déjà renseigné
769
        -- et uniquement s'il a réellement été modifié (ce
770
        -- qui n'est pas le cas si les changements ne portent
771
        -- que sur les rôles lecteur/éditeur)
772
        THEN
773
            UPDATE z_asgard.gestion_schema_etr
774
                SET oid_producteur = quote_ident(NEW.producteur)::regrole::oid,
775
                    ctrl = ARRAY['SELF', 'x7-A;#rzo']
776
                WHERE nom_schema = NEW.nom_schema AND (
777
                    oid_producteur IS NULL
778
                    OR NOT oid_producteur = quote_ident(NEW.producteur)::regrole::oid
779
                    ) ;
780
        END IF ;
781

    
782
        -- implémentation des permissions manquantes sur NEW.producteur
783
        IF NOT pg_has_role(utilisateur, NEW.producteur, 'USAGE')
784
        THEN
785
            b_test := True ;
786
            IF createur IS NULL OR b_superuser
787
            THEN
788
                RAISE EXCEPTION 'TA4. Opération interdite. Permissions insuffisantes pour le rôle %.', NEW.producteur
789
                    USING HINT = 'Votre rôle doit être membre de ' || NEW.producteur
790
                                     || ' ou disposer de l''attribut CREATEROLE pour réaliser cette opération.' ;
791
            END IF ;
792
        END IF ;
793
        IF TG_OP = 'UPDATE'
794
        THEN
795
            IF OLD.creation AND NOT pg_has_role(utilisateur, a_producteur, 'USAGE')
796
                AND NOT (NEW.producteur = OLD.producteur  OR 'CLEAN producteur' = ANY(array_remove(NEW.ctrl, NULL)))
797
                -- les permissions sur OLD.producteur ne sont contrôlées que si le producteur
798
                -- a effectivement été modifié
799
            THEN
800
                b_test := True ;
801
                IF createur IS NULL OR b_superuser
802
                THEN
803
                    RAISE EXCEPTION 'TA5. Opération interdite. Permissions insuffisantes pour le rôle %.', a_producteur
804
                        USING HINT = 'Votre rôle doit être membre de ' || a_producteur
805
                                         || ' ou disposer de l''attribut CREATEROLE pour réaliser cette opération.' ;
806
                END IF ;            
807
            END IF ;
808
        END IF ;       
809
        IF b_test
810
        THEN
811
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;            
812
            -- par commodité, on rend createur membre à la fois de NEW et (si besoin)
813
            -- de OLD.producteur, même si l'utilisateur avait déjà accès à
814
            -- l'un des deux par ailleurs :
815
            IF NOT pg_has_role(createur, NEW.producteur, 'USAGE') AND NOT b_superuser
816
            THEN
817
                EXECUTE 'GRANT ' || quote_ident(NEW.producteur) || ' TO ' || quote_ident(createur) ;
818
                RAISE NOTICE '... Permission accordée à %.', createur || ' sur le rôle ' || NEW.producteur ;
819
            END IF ;
820
            IF TG_OP = 'UPDATE'
821
            THEN
822
                IF NOT pg_has_role(createur, a_producteur, 'USAGE') AND NOT b_superuser
823
                THEN
824
                    EXECUTE 'GRANT ' || quote_ident(a_producteur) || ' TO ' || quote_ident(createur) ;
825
                    RAISE NOTICE '... Permission accordée à %.', createur || ' sur le rôle ' || a_producteur ;
826
                END IF ;
827
            END IF ;
828
            EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
829
        END IF ;
830
           
831
        -- permission de g_admin sur le producteur, s'il y a encore lieu
832
        -- à noter que, dans le cas où le producteur n'a pas été modifié, g_admin
833
        -- devrait déjà avoir une permission sur NEW.producteur, sauf à ce qu'elle
834
        -- lui ait été retirée manuellement entre temps. Les requêtes suivantes
835
        -- génèreraient alors une erreur même dans le cas où la modification ne
836
        -- porte que sur les rôles lecteur/éditeur - ce qui peut-être perçu comme
837
        -- discutable.
838
        IF NOT pg_has_role('g_admin', NEW.producteur, 'USAGE') AND NOT b_superuser
839
        THEN
840
            IF createur IS NOT NULL
841
            THEN
842
                EXECUTE 'SET ROLE ' || quote_ident(createur) ;
843
                EXECUTE 'GRANT ' || quote_ident(NEW.producteur) || ' TO g_admin' ;
844
                RAISE NOTICE '... Permission accordée à g_admin sur le rôle %.', NEW.producteur ;
845
                EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
846
            ELSE
847
                SELECT grantee INTO administrateur
848
                    FROM information_schema.applicable_roles
849
                    WHERE is_grantable = 'YES' AND role_name = NEW.producteur ;
850
                IF FOUND
851
                THEN
852
                    EXECUTE 'SET ROLE ' || quote_ident(administrateur) ;
853
                    EXECUTE 'GRANT ' || quote_ident(NEW.producteur) || ' TO g_admin' ;
854
                    RAISE NOTICE '... Permission accordée à g_admin sur le rôle %.', NEW.producteur ;
855
                    EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
856
                ELSE
857
                    RAISE EXCEPTION 'TA6. Opération interdite. Permissions insuffisantes pour le rôle %.', NEW.producteur
858
                        USING DETAIL = 'GRANT ' || quote_ident(NEW.producteur) || ' TO g_admin',
859
                              HINT = 'Votre rôle doit être membre de ' || NEW.producteur
860
                                         || ' avec admin option ou disposer de l''attribut CREATEROLE pour réaliser cette opération.' ;
861
                END IF ;
862
            END IF ;
863
        END IF ;
864
    END IF ;
865
    
866
    ------ PREPARATION DE L'EDITEUR ------
867
    -- limitée ici à la création du rôle et l'implémentation
868
    -- de son OID. On ne s'intéresse donc pas aux cas :
869
    -- - où il y a pas d'éditeur ;
870
    -- - d'un schéma qui n'a pas/plus vocation à exister ;
871
    -- - d'un schéma pré-existant dont l'éditeur ne change pas
872
    --   ou dont le libellé a seulement été nettoyé par le
873
    --   trigger BEFORE.
874
    -- ils sont donc exclus au préalable
875
    b_test := False ;
876
    IF NOT NEW.creation OR NEW.editeur IS NULL
877
            OR 'CLEAN editeur' = ANY(array_remove(NEW.ctrl, NULL))
878
    THEN
879
        b_test := True ;
880
    ELSIF TG_OP = 'UPDATE'
881
    THEN
882
        IF OLD.creation AND NEW.editeur = OLD.editeur
883
        THEN
884
            b_test := True ;           
885
        END IF ;
886
    END IF ;
887
    
888
    IF NOT b_test
889
    THEN
890
        IF NOT NEW.editeur IN (SELECT rolname FROM pg_catalog.pg_roles)
891
                AND NOT NEW.editeur = 'public'
892
        -- si l'éditeur désigné n'existe pas, on le crée
893
        -- ou renvoie une erreur si les privilèges de l'utilisateur
894
        -- sont insuffisants
895
        THEN
896
            IF createur IS NULL
897
            THEN
898
                RAISE EXCEPTION 'TA7. Opération interdite. Vous n''êtes pas habilité à créer le rôle %.', NEW.editeur
899
                    USING HINT = 'Être membre d''un rôle disposant des attributs CREATEROLE et INHERIT est nécessaire pour créer de nouveaux éditeurs.' ;
900
            END IF ;
901
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;
902
            EXECUTE 'CREATE ROLE ' || quote_ident(NEW.editeur) ;
903
            RAISE NOTICE '... Le rôle de groupe % a été créé.', NEW.editeur ;
904
            EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
905
        END IF ;
906
        
907
        -- mise à jour du champ d'OID de l'éditeur
908
        IF NEW.editeur = 'public'
909
        THEN
910
            UPDATE z_asgard.gestion_schema_etr
911
                SET oid_editeur = 0,
912
                    ctrl = ARRAY['SELF', 'x7-A;#rzo']
913
                WHERE nom_schema = NEW.nom_schema AND (
914
                    oid_editeur IS NULL
915
                    OR NOT oid_editeur = 0
916
                    ) ;
917
        ELSE
918
            UPDATE z_asgard.gestion_schema_etr
919
                SET oid_editeur = quote_ident(NEW.editeur)::regrole::oid,
920
                    ctrl = ARRAY['SELF', 'x7-A;#rzo']
921
                WHERE nom_schema = NEW.nom_schema AND (
922
                    oid_editeur IS NULL
923
                    OR NOT oid_editeur = quote_ident(NEW.editeur)::regrole::oid
924
                    ) ;
925
        END IF ;
926
    END IF ;
927
    
928
    ------ PREPARATION DU LECTEUR ------
929
    -- limitée ici à la création du rôle et l'implémentation
930
    -- de son OID. On ne s'intéresse donc pas aux cas :
931
    -- - où il y a pas de lecteur ;
932
    -- - d'un schéma qui n'a pas/plus vocation à exister ;
933
    -- - d'un schéma pré-existant dont l'éditeur ne change pas
934
    --   ou dont le libellé a seulement été nettoyé par le
935
    --   trigger BEFORE.
936
    -- ils sont donc exclus au préalable
937
    b_test := False ;
938
    IF NOT NEW.creation OR NEW.lecteur IS NULL
939
            OR 'CLEAN lecteur' = ANY(array_remove(NEW.ctrl, NULL))
940
    THEN
941
        b_test := True ;
942
    ELSIF TG_OP = 'UPDATE'
943
    THEN
944
        IF OLD.creation AND NEW.lecteur = OLD.lecteur
945
        THEN
946
            b_test := True ;
947
        END IF ;
948
    END IF ;
949
    
950
    IF NOT b_test
951
    THEN
952
        IF NOT NEW.lecteur IN (SELECT rolname FROM pg_catalog.pg_roles)
953
                AND NOT NEW.lecteur = 'public'
954
        -- si le lecteur désigné n'existe pas, on le crée
955
        -- ou renvoie une erreur si les privilèges de l'utilisateur
956
        -- sont insuffisants
957
        THEN
958
            IF createur IS NULL
959
            THEN
960
                RAISE EXCEPTION 'TA8. Opération interdite. Vous n''êtes pas habilité à créer le rôle %.', NEW.lecteur
961
                    USING HINT = 'Être membre d''un rôle disposant des attributs CREATEROLE et INHERIT est nécessaire pour créer de nouveaux éditeurs.' ;
962
            END IF ;
963
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;
964
            EXECUTE 'CREATE ROLE ' || quote_ident(NEW.lecteur) ;
965
            RAISE NOTICE '... Le rôle de groupe % a été créé.', NEW.lecteur ;
966
            EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
967
        END IF ;
968
        
969
        -- mise à jour du champ d'OID du lecteur
970
        IF NEW.lecteur = 'public'
971
        THEN
972
            UPDATE z_asgard.gestion_schema_etr
973
                SET oid_lecteur = 0,
974
                    ctrl = ARRAY['SELF', 'x7-A;#rzo']
975
                WHERE nom_schema = NEW.nom_schema AND (
976
                    oid_lecteur IS NULL
977
                    OR NOT oid_lecteur = 0
978
                    ) ;
979
        ELSE
980
            UPDATE z_asgard.gestion_schema_etr
981
                SET oid_lecteur = quote_ident(NEW.lecteur)::regrole::oid,
982
                    ctrl = ARRAY['SELF', 'x7-A;#rzo']
983
                WHERE nom_schema = NEW.nom_schema AND (
984
                    oid_lecteur IS NULL
985
                    OR NOT oid_lecteur = quote_ident(NEW.lecteur)::regrole::oid
986
                    ) ;
987
        END IF ;
988
    END IF ;
989
    
990
    ------ CREATION DU SCHEMA ------
991
    -- on exclut au préalable les cas qui ne
992
    -- correspondent pas à des créations, ainsi que les
993
    -- remontées de l'event trigger sur CREATE SCHEMA,
994
    -- car le schéma existe alors déjà
995
    b_test := False ;
996
    IF NOT NEW.creation OR NEW.ctrl[1] = 'CREATE'
997
    THEN
998
        b_test := True ;
999
    ELSIF TG_OP = 'UPDATE'
1000
    THEN
1001
        IF OLD.creation
1002
        THEN
1003
            b_test := True ;
1004
        END IF ;
1005
    END IF ;
1006
    
1007
    IF NOT b_test
1008
    THEN
1009
        -- le schéma est créé s'il n'existe pas déjà (cas d'ajout
1010
        -- d'un schéma pré-existant qui n'était pas référencé dans
1011
        -- gestion_schema jusque-là), sinon on alerte juste
1012
        -- l'utilisateur
1013
        IF NOT NEW.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
1014
        THEN
1015
            IF NOT has_database_privilege(current_database(), 'CREATE')
1016
                    OR NOT pg_has_role(NEW.producteur, 'USAGE')
1017
            THEN
1018
                -- si le rôle courant n'a pas les privilèges nécessaires pour
1019
                -- créer le schéma, on tente avec le rôle createur [de rôles]
1020
                -- pré-identifié, dont on sait au moins qu'il aura les
1021
                -- permissions nécessaires sur le rôle producteur - mais pas
1022
                -- s'il est habilité à créer des schémas
1023
                IF createur IS NOT NULL
1024
                THEN
1025
                    EXECUTE 'SET ROLE ' || quote_ident(createur) ;
1026
                END IF ;
1027
                IF NOT has_database_privilege(current_database(), 'CREATE')
1028
                        OR NOT pg_has_role(NEW.producteur, 'USAGE')
1029
                THEN
1030
                    RAISE EXCEPTION 'TA9. Opération interdite. Vous n''êtes pas habilité à créer le schéma %.', NEW.nom_schema
1031
                        USING HINT = 'Être membre d''un rôle disposant du privilège CREATE sur la base de données est nécessaire pour créer des schémas.' ;
1032
                END IF ;
1033
            END IF ;
1034
            EXECUTE 'CREATE SCHEMA ' || quote_ident(NEW.nom_schema) || ' AUTHORIZATION ' || quote_ident(NEW.producteur) ;
1035
            EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
1036
            RAISE NOTICE '... Le schéma % a été créé.', NEW.nom_schema ;
1037
        ELSE
1038
            RAISE NOTICE '(schéma % pré-existant)', NEW.nom_schema ;
1039
        END IF ;
1040
        -- récupération de l'OID du schéma
1041
        UPDATE z_asgard.gestion_schema_etr
1042
            SET oid_schema = quote_ident(NEW.nom_schema)::regnamespace::oid,
1043
                ctrl = ARRAY['SELF', 'x7-A;#rzo']
1044
            WHERE nom_schema = NEW.nom_schema AND (
1045
                oid_schema IS NULL
1046
                OR NOT oid_schema = quote_ident(NEW.nom_schema)::regnamespace::oid
1047
                ) ;   
1048
    END IF ;
1049
    
1050
    ------ APPLICATION DES DROITS DU PRODUCTEUR ------
1051
    -- comme précédemment pour la préparation du producteur,
1052
    -- on ne s'intéresse pas aux cas :
1053
    -- - d'un schéma qui n'a pas/plus vocation à exister
1054
    --   (creation vaut False) ;
1055
    -- - d'un schéma pré-existant dont le producteur ne change pas
1056
    --   ou dont le libellé a juste été nettoyé par le trigger
1057
    --   BEFORE ;
1058
    -- - d'une remontée de l'event trigger asgard_on_create_schema,
1059
    --   car le producteur sera déjà propriétaire du schéma
1060
    --   et de son éventuel contenu. Par contre on garde les INSERT,
1061
    --   pour les cas de référencements ;
1062
    -- - de z_asgard_admin (pour permettre sa saisie initiale
1063
    --   dans la table de gestion, étant entendu qu'il est
1064
    --   impossible au trigger sur gestion_schema de lancer
1065
    --   un ALTER TABLE OWNER TO sur cette même table).
1066
    -- ils sont donc exclus au préalable
1067
    b_test := False ;
1068
    IF NOT NEW.creation
1069
            OR 'CLEAN producteur' = ANY(array_remove(NEW.ctrl, NULL))
1070
            OR NEW.ctrl[1] = 'CREATE'
1071
            OR NEW.nom_schema = 'z_asgard_admin'
1072
    THEN
1073
        b_test := True ;
1074
    ELSIF TG_OP = 'UPDATE'
1075
    THEN
1076
        IF OLD.creation AND NEW.producteur = OLD.producteur
1077
        THEN
1078
            b_test := True ;
1079
        END IF ;
1080
    END IF ;
1081
    
1082
    IF NOT b_test
1083
    THEN
1084
        -- si besoin, on bascule sur le rôle createur. À ce stade,
1085
        -- il est garanti que soit l'utilisateur courant soit
1086
        -- createur (pour le cas d'un utilisateur courant
1087
        -- NOINHERIT) aura les privilèges nécessaires
1088
        IF NOT pg_has_role(NEW.producteur, 'USAGE')
1089
        THEN
1090
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;
1091
        ELSIF TG_OP = 'UPDATE'
1092
        THEN
1093
            IF NOT pg_has_role(a_producteur, 'USAGE')
1094
            THEN
1095
                EXECUTE 'SET ROLE ' || quote_ident(createur) ; 
1096
            END IF ;
1097
        END IF ;
1098
        
1099
        -- changements de propriétaires
1100
        IF (NEW.nom_schema, NEW.producteur)
1101
                IN (SELECT schema_name, schema_owner FROM information_schema.schemata)
1102
        THEN
1103
            -- si producteur est déjà propriétaire du schéma (cas d'une remontée de l'event trigger,
1104
            -- principalement), on ne change que les propriétaires des objets éventuels
1105
            IF quote_ident(NEW.nom_schema)::regnamespace::oid
1106
                    IN (SELECT refobjid FROM pg_catalog.pg_depend WHERE deptype = 'n')
1107
            THEN 
1108
                -- la commande n'est cependant lancée que s'il existe des dépendances de type
1109
                -- DEPENDENCY_NORMAL sur le schéma, ce qui est une condition nécessaire à
1110
                -- l'existence d'objets dans le schéma
1111
                RAISE NOTICE 'attribution de la propriété des objets au rôle producteur du schéma % :', NEW.nom_schema ;
1112
                SELECT z_asgard.asgard_admin_proprietaire(NEW.nom_schema, NEW.producteur, False)
1113
                    INTO n ;
1114
                IF n = 0
1115
                THEN
1116
                    RAISE NOTICE '> néant' ;
1117
                END IF ; 
1118
            END IF ;
1119
        ELSE
1120
            -- sinon schéma + objets
1121
            RAISE NOTICE 'attribution de la propriété du schéma et des objets au rôle producteur du schéma % :', NEW.nom_schema ;
1122
            PERFORM z_asgard.asgard_admin_proprietaire(NEW.nom_schema, NEW.producteur) ;
1123
        END IF ;
1124
        
1125
        EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
1126
    END IF ;
1127
    
1128
    ------ APPLICATION DES DROITS DE L'EDITEUR ------
1129
    -- on ne s'intéresse pas aux cas :
1130
    -- - d'un schéma qui n'a pas/plus vocation à exister ;
1131
    -- - d'un schéma pré-existant dont l'éditeur ne change pas
1132
    --   (y compris pour rester vide) ou dont le libellé
1133
    --   a seulement été nettoyé par le trigger BEFORE.
1134
    -- ils sont donc exclus au préalable
1135
    b_test := False ;
1136
    IF NOT NEW.creation OR 'CLEAN editeur' = ANY(array_remove(NEW.ctrl, NULL))
1137
    THEN
1138
        b_test := True ;
1139
    ELSIF TG_OP = 'UPDATE'
1140
    THEN
1141
        IF OLD.creation
1142
            AND coalesce(NEW.editeur, '') = coalesce(OLD.editeur, '')
1143
        THEN
1144
            b_test := True ;           
1145
        END IF ;
1146
    END IF ;
1147
    
1148
    IF NOT b_test
1149
    THEN
1150
        -- si besoin, on bascule sur le rôle createur. À ce stade,
1151
        -- il est garanti que soit l'utilisateur courant soit
1152
        -- createur (pour le cas d'un utilisateur courant
1153
        -- NOINHERIT) aura les privilèges nécessaires
1154
        IF NOT pg_has_role(NEW.producteur, 'USAGE')
1155
        THEN
1156
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;
1157
        END IF ;
1158
        
1159
        IF TG_OP = 'UPDATE'
1160
        THEN
1161
            -- la validité de OLD.editeur n'ayant
1162
            -- pas été contrôlée par le trigger BEFORE,
1163
            -- on le fait maintenant
1164
            IF OLD.editeur = 'public'
1165
            THEN
1166
                a_editeur := 'public' ;
1167
                -- récupération des modifications manuelles des
1168
                -- droits de OLD.editeur/public, grâce à la fonction
1169
                -- asgard_synthese_public
1170
                SELECT array_agg(commande) INTO l_commande
1171
                    FROM z_asgard.asgard_synthese_public(
1172
                        quote_ident(NEW.nom_schema)::regnamespace
1173
                        ) ;   
1174
            ELSE
1175
                SELECT rolname INTO a_editeur
1176
                    FROM pg_catalog.pg_roles
1177
                    WHERE pg_roles.oid = OLD.oid_editeur ;
1178
                IF FOUND
1179
                THEN
1180
                    -- récupération des modifications manuelles des
1181
                    -- droits de OLD.editeur, grâce à la fonction
1182
                    -- asgard_synthese_role
1183
                    SELECT array_agg(commande) INTO l_commande
1184
                        FROM z_asgard.asgard_synthese_role(
1185
                            quote_ident(NEW.nom_schema)::regnamespace,
1186
                            quote_ident(a_editeur)::regrole
1187
                            ) ;
1188
                END IF ;
1189
            END IF ;
1190
        END IF ;
1191

    
1192
        IF l_commande IS NOT NULL
1193
        -- transfert sur NEW.editeur des droits de
1194
        -- OLD.editeur, le cas échéant
1195
        THEN
1196
            IF NEW.editeur IS NOT NULL
1197
            THEN
1198
                RAISE NOTICE 'suppression et transfert vers le nouvel éditeur des privilèges de l''ancien éditeur du schéma % :', NEW.nom_schema ;
1199
            ELSE
1200
                RAISE NOTICE 'suppression des privilèges de l''ancien éditeur du schéma % :', NEW.nom_schema ;
1201
            END IF ;
1202
            FOREACH c IN ARRAY l_commande
1203
            LOOP
1204
                IF NEW.editeur IS NOT NULL
1205
                THEN
1206
                    EXECUTE format(c, NEW.editeur) ;
1207
                    RAISE NOTICE '> %', format(c, NEW.editeur) ;
1208
                END IF ;
1209
                IF c ~ '^GRANT'
1210
                THEN
1211
                    SELECT z_asgard.asgard_grant_to_revoke(c) INTO c_reverse ;
1212
                    EXECUTE format(c_reverse, a_editeur) ;
1213
                    RAISE NOTICE '> %', format(c_reverse, a_editeur) ;
1214
                END IF ;
1215
            END LOOP ;
1216
            
1217
        -- sinon, application des privilèges standards de l'éditeur
1218
        ELSIF NEW.editeur IS NOT NULL
1219
        THEN
1220
            RAISE NOTICE 'application des privilèges standards pour le rôle éditeur du schéma % :', NEW.nom_schema ;
1221
            
1222
            EXECUTE 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
1223
            RAISE NOTICE '> %', 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
1224
            
1225
            EXECUTE 'GRANT SELECT, UPDATE, DELETE, INSERT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
1226
            RAISE NOTICE '> %', 'GRANT SELECT, UPDATE, DELETE, INSERT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
1227
            
1228
            EXECUTE 'GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
1229
            RAISE NOTICE '> %', 'GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
1230
            
1231
        END IF ;
1232
        
1233
        EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
1234
    END IF ;
1235
    
1236
    ------ APPLICATION DES DROITS DU LECTEUR ------
1237
    -- on ne s'intéresse pas aux cas :
1238
    -- - d'un schéma qui n'a pas/plus vocation à exister ;
1239
    -- - d'un schéma pré-existant dont le lecteur ne change pas
1240
    --   (y compris pour rester vide) ou dont le libellé
1241
    --   a seulement été nettoyé par le trigger BEFORE.
1242
    -- ils sont donc exclus au préalable
1243
    b_test := False ;
1244
    l_commande := NULL ;
1245
    IF NOT NEW.creation OR 'CLEAN lecteur' = ANY(array_remove(NEW.ctrl, NULL))
1246
    THEN
1247
        b_test := True ;
1248
    ELSIF TG_OP = 'UPDATE'
1249
    THEN
1250
        IF OLD.creation
1251
            AND coalesce(NEW.lecteur, '') = coalesce(OLD.lecteur, '')
1252
        THEN
1253
            b_test := True ;           
1254
        END IF ;
1255
    END IF ;
1256
    
1257
    IF NOT b_test
1258
    THEN
1259
        -- si besoin, on bascule sur le rôle createur. À ce stade,
1260
        -- il est garanti que soit l'utilisateur courant soit
1261
        -- createur (pour le cas d'un utilisateur courant
1262
        -- NOINHERIT) aura les privilèges nécessaires
1263
        IF NOT pg_has_role(NEW.producteur, 'USAGE')
1264
        THEN
1265
            EXECUTE 'SET ROLE ' || quote_ident(createur) ;
1266
        END IF ;
1267
        
1268
        IF TG_OP = 'UPDATE'
1269
        THEN
1270
            -- la validité de OLD.lecteur n'ayant
1271
            -- pas été contrôlée par le trigger BEFORE,
1272
            -- on le fait maintenant
1273
            IF OLD.lecteur = 'public'
1274
            THEN
1275
                a_lecteur := 'public' ;
1276
                -- récupération des modifications manuelles des
1277
                -- droits de OLD.lecteur/public, grâce à la fonction
1278
                -- asgard_synthese_public
1279
                SELECT array_agg(commande) INTO l_commande
1280
                    FROM z_asgard.asgard_synthese_public(
1281
                        quote_ident(NEW.nom_schema)::regnamespace
1282
                        ) ;   
1283
            ELSE
1284
                SELECT rolname INTO a_lecteur
1285
                    FROM pg_catalog.pg_roles
1286
                    WHERE pg_roles.oid = OLD.oid_lecteur ;
1287
                IF FOUND
1288
                THEN
1289
                    -- récupération des modifications manuelles des
1290
                    -- droits de OLD.lecteur, grâce à la fonction
1291
                    -- asgard_synthese_role
1292
                    SELECT array_agg(commande) INTO l_commande
1293
                        FROM z_asgard.asgard_synthese_role(
1294
                            quote_ident(NEW.nom_schema)::regnamespace,
1295
                            quote_ident(a_lecteur)::regrole
1296
                            ) ;
1297
                END IF ;
1298
            END IF ;
1299
        END IF ;
1300

    
1301
        IF l_commande IS NOT NULL
1302
        -- transfert sur NEW.lecteur des droits de
1303
        -- OLD.lecteur, le cas échéant
1304
        THEN
1305
            IF NEW.lecteur IS NOT NULL
1306
            THEN
1307
                RAISE NOTICE 'suppression et transfert vers le nouveau lecteur des privilèges de l''ancien lecteur du schéma % :', NEW.nom_schema ;
1308
            ELSE
1309
                RAISE NOTICE 'suppression des privilèges de l''ancien lecteur du schéma % :', NEW.nom_schema ;
1310
            END IF ;
1311
            FOREACH c IN ARRAY l_commande
1312
            LOOP
1313
                IF NEW.lecteur IS NOT NULL
1314
                THEN
1315
                    EXECUTE format(c, NEW.lecteur) ;
1316
                    RAISE NOTICE '> %', format(c, NEW.lecteur) ;
1317
                END IF ;
1318
                IF c ~ '^GRANT'
1319
                THEN
1320
                    SELECT z_asgard.asgard_grant_to_revoke(c) INTO c_reverse ;
1321
                    EXECUTE format(c_reverse, a_lecteur) ;
1322
                    RAISE NOTICE '> %', format(c_reverse, a_lecteur) ;
1323
                END IF ;
1324
            END LOOP ;
1325
            
1326
        -- sinon, application des privilèges standards du lecteur
1327
        ELSIF NEW.lecteur IS NOT NULL
1328
        THEN
1329
            RAISE NOTICE 'application des privilèges standards pour le rôle lecteur du schéma % :', NEW.nom_schema ;
1330
            
1331
            EXECUTE 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
1332
            RAISE NOTICE '> %', 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
1333
            
1334
            EXECUTE 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
1335
            RAISE NOTICE '> %', 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
1336
            
1337
            EXECUTE 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
1338
            RAISE NOTICE '> %', 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
1339
            
1340
        END IF ;
1341
        
1342
        EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
1343
    END IF ;
1344
    
1345
	RETURN NULL ;
1346

    
1347
EXCEPTION WHEN OTHERS THEN
1348
    GET STACKED DIAGNOSTICS e_mssg = MESSAGE_TEXT,
1349
                            e_hint = PG_EXCEPTION_HINT,
1350
                            e_detl = PG_EXCEPTION_DETAIL ;
1351
    RAISE EXCEPTION 'TA0 > %', e_mssg
1352
        USING DETAIL = e_detl,
1353
            HINT = e_hint ;
1354
               
1355
END
1356
$BODY$ ;
1357

    
1358
ALTER FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_after()
1359
    OWNER TO g_admin ;
1360

    
1361
COMMENT ON FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_after() IS 'ASGARD. Fonction appelée par le trigger qui répercute physiquement les modifications de la table de gestion.' ;
1362

    
1363

    
1364
-- Trigger: asgard_on_modify_gestion_schema_after
1365

    
1366
CREATE TRIGGER asgard_on_modify_gestion_schema_after
1367
    AFTER INSERT OR UPDATE
1368
    ON z_asgard_admin.gestion_schema
1369
    FOR EACH ROW
1370
    EXECUTE PROCEDURE z_asgard_admin.asgard_on_modify_gestion_schema_after();
1371

    
1372
COMMENT ON TRIGGER asgard_on_modify_gestion_schema_after ON z_asgard_admin.gestion_schema IS 'ASGARD. Trigger qui répercute physiquement les modifications de la table de gestion.' ;
(2-2/2)