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
|
/*
|
12
|
(ligne 1008) correction d'une coquille qui faisait échouer les créations
|
13
|
via UPDATE creation = True sur les schémas pré-référencés avec des noms
|
14
|
non standard (anomalie #292)
|
15
|
*/
|
16
|
|
17
|
|
18
|
-- MOT DE PASSE DE CONTRÔLE : 'x7-A;#rzo'
|
19
|
-- peut être modifié sans risque par rechercher/remplacer
|
20
|
|
21
|
|
22
|
---------------------------------------------
|
23
|
------ 5 - TRIGGERS SUR GESTION_SCHEMA ------
|
24
|
---------------------------------------------
|
25
|
/* 5.1 - TRIGGER BEFORE
|
26
|
5.2 - TRIGGER AFTER */
|
27
|
|
28
|
|
29
|
------ 5.1 - TRIGGER BEFORE ------
|
30
|
|
31
|
-- FUNCTION: z_asgard_admin.asgard_on_modify_gestion_schema_before()
|
32
|
|
33
|
CREATE OR REPLACE FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_before() RETURNS trigger
|
34
|
LANGUAGE plpgsql
|
35
|
AS $BODY$
|
36
|
/* OBJET : Fonction exécutée par le trigger asgard_on_modify_gestion_schema_before,
|
37
|
qui valide les informations saisies dans la table de gestion.
|
38
|
CIBLES : z_asgard_admin.gestion_schema.
|
39
|
PORTEE : FOR EACH ROW.
|
40
|
DECLENCHEMENT : BEFORE INSERT, UPDATE, DELETE.*/
|
41
|
DECLARE
|
42
|
n_role text ;
|
43
|
BEGIN
|
44
|
|
45
|
------ SAISIE PAR UN UTILISATEUR NON HABILITE ------
|
46
|
IF TG_OP = 'INSERT' AND NOT has_database_privilege(current_database(), 'CREATE')
|
47
|
-- même si creation vaut faux, seul un rôle habilité à créer des
|
48
|
-- schéma peut ajouter des lignes dans la table de gestion
|
49
|
THEN
|
50
|
RAISE EXCEPTION 'TB1. Vous devez être habilité à créer des schémas pour réaliser cette opération.' ;
|
51
|
END IF ;
|
52
|
|
53
|
------ APPLICATION DES VALEURS PAR DEFAUT ------
|
54
|
-- au tout début car de nombreux tests sont faits par la
|
55
|
-- suite sur "NOT NEW.creation"
|
56
|
IF TG_OP IN ('INSERT', 'UPDATE')
|
57
|
THEN
|
58
|
NEW.creation := coalesce(NEW.creation, False) ;
|
59
|
NEW.nomenclature := coalesce(NEW.nomenclature, False) ;
|
60
|
END IF ;
|
61
|
|
62
|
------ EFFACEMENT D'UN ENREGISTREMENT ------
|
63
|
IF TG_OP = 'DELETE'
|
64
|
THEN
|
65
|
-- on n'autorise pas l'effacement si creation vaut True
|
66
|
-- avec une exception pour les commandes envoyées par la fonction
|
67
|
-- de maintenance asgard_sortie_gestion_schema
|
68
|
IF OLD.creation AND (OLD.ctrl[1] IS NULL OR NOT OLD.ctrl[1] = 'EXIT')
|
69
|
THEN
|
70
|
RAISE EXCEPTION 'TB2. Opération interdite (schéma %). L''effacement n''est autorisé que si creation vaut False.', OLD.nom_schema
|
71
|
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.' ;
|
72
|
END IF;
|
73
|
|
74
|
-- on n'autorise pas l'effacement pour les schémas de la nomenclature
|
75
|
IF OLD.nomenclature
|
76
|
THEN
|
77
|
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
|
78
|
USING HINT = 'Si vous tenez à supprimer définitivement cet enregistrement, basculez préalablement nomenclature sur False.' ;
|
79
|
END IF ;
|
80
|
END IF;
|
81
|
|
82
|
------ DE-CREATION D'UN SCHEMA ------
|
83
|
IF TG_OP = 'UPDATE'
|
84
|
THEN
|
85
|
-- si bloc valait déjà d (schéma "mis à la corbeille")
|
86
|
-- on exécute une commande de suppression du schéma. Toute autre modification sur
|
87
|
-- la ligne est ignorée.
|
88
|
IF OLD.bloc = 'd' AND OLD.creation AND NOT NEW.creation AND NEW.ctrl[2] IS NULL
|
89
|
AND OLD.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
|
90
|
THEN
|
91
|
EXECUTE 'DROP SCHEMA ' || quote_ident(OLD.nom_schema) || ' CASCADE' ;
|
92
|
RAISE NOTICE '... Le schéma % a été supprimé.', OLD.nom_schema ;
|
93
|
RETURN NULL ;
|
94
|
-- sinon, on n'autorise creation à passer de true à false que si le schéma
|
95
|
-- n'existe plus (permet notamment à l'event trigger qui gère les
|
96
|
-- suppressions de mettre creation à false)
|
97
|
ELSIF OLD.creation and NOT NEW.creation
|
98
|
AND NEW.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
|
99
|
THEN
|
100
|
RAISE EXCEPTION 'TB4. Opération interdite (schéma %). Le champ creation ne peut passer de Vrai à Faux si le schéma existe.', NEW.nom_schema
|
101
|
USING HINT = 'Si vous supprimez physiquement le schéma avec la commande DROP SCHEMA, creation basculera sur False automatiquement.' ;
|
102
|
END IF ;
|
103
|
END IF ;
|
104
|
|
105
|
IF TG_OP <> 'DELETE'
|
106
|
THEN
|
107
|
------ PROHIBITION DE LA SAISIE MANUELLE DES OID ------
|
108
|
-- vérifié grâce au champ ctrl
|
109
|
IF NEW.ctrl[2] IS NULL
|
110
|
OR NOT array_length(NEW.ctrl, 1) >= 2
|
111
|
OR NEW.ctrl[1] IS NULL
|
112
|
OR NOT NEW.ctrl[1] IN ('CREATE', 'RENAME', 'OWNER', 'DROP', 'SELF', 'EXIT')
|
113
|
OR NOT NEW.ctrl[2] = 'x7-A;#rzo'
|
114
|
-- ctrl NULL ou invalide
|
115
|
THEN
|
116
|
|
117
|
IF NEW.ctrl[1] = 'EXIT'
|
118
|
THEN
|
119
|
RAISE EXCEPTION 'TB17. Opération interdite (schéma %).', coalesce(NEW.nom_schema, '?')
|
120
|
USING HINT = 'Pour déréférencer un schéma, veuillez utiliser la fonction z_asgard_admin.asgard_sortie_gestion_schema.' ;
|
121
|
END IF ;
|
122
|
|
123
|
-- réinitialisation du champ ctrl, qui peut contenir des informations
|
124
|
-- issues de commandes antérieures (dans ctrl[1])
|
125
|
NEW.ctrl := ARRAY['MANUEL', NULL]::text[] ;
|
126
|
|
127
|
IF TG_OP = 'INSERT' AND (
|
128
|
NEW.oid_producteur IS NOT NULL
|
129
|
OR NEW.oid_lecteur IS NOT NULL
|
130
|
OR NEW.oid_editeur IS NOT NULL
|
131
|
OR NEW.oid_schema IS NOT NULL
|
132
|
)
|
133
|
-- cas d'un INSERT manuel pour lequel des OID ont été saisis
|
134
|
-- on les remet à NULL
|
135
|
THEN
|
136
|
NEW.oid_producteur = NULL ;
|
137
|
NEW.oid_editeur = NULL ;
|
138
|
NEW.oid_lecteur = NULL ;
|
139
|
NEW.oid_schema = NULL ;
|
140
|
ELSIF TG_OP = 'UPDATE'
|
141
|
THEN
|
142
|
IF NOT coalesce(NEW.oid_producteur, -1) = coalesce(OLD.oid_producteur, -1)
|
143
|
OR NOT coalesce(NEW.oid_editeur, -1) = coalesce(OLD.oid_editeur, -1)
|
144
|
OR NOT coalesce(NEW.oid_lecteur, -1) = coalesce(OLD.oid_lecteur, -1)
|
145
|
OR NOT coalesce(NEW.oid_schema, -1) = coalesce(OLD.oid_schema, -1)
|
146
|
-- cas d'un UPDATE avec modification des OID
|
147
|
-- on les remet à OLD
|
148
|
THEN
|
149
|
NEW.oid_producteur = OLD.oid_producteur ;
|
150
|
NEW.oid_editeur = OLD.oid_editeur ;
|
151
|
NEW.oid_lecteur = OLD.oid_lecteur ;
|
152
|
NEW.oid_schema = OLD.oid_schema ;
|
153
|
END IF ;
|
154
|
END IF ;
|
155
|
ELSE
|
156
|
-- suppression du mot de passe de contrôle.
|
157
|
-- ctrl[1] est par contre conservé - il sera utilisé
|
158
|
-- par le trigger AFTER pour connaître l'opération
|
159
|
-- à l'origine de son déclenchement.
|
160
|
NEW.ctrl[2] := NULL ;
|
161
|
END IF ;
|
162
|
|
163
|
------ REQUETES AUTO A IGNORER ------
|
164
|
-- les remontées du trigger AFTER (SELF)
|
165
|
-- sont exclues, car les contraintes ont déjà
|
166
|
-- été validées (et pose problèmes avec les
|
167
|
-- contrôles d'OID sur les UPDATE, car ceux-ci
|
168
|
-- ne seront pas nécessairement déjà remplis) ;
|
169
|
-- les requêtes EXIT de même, car c'est un
|
170
|
-- pré-requis à la suppression qui ne fait
|
171
|
-- que modifier le champ ctrl
|
172
|
IF NEW.ctrl[1] IN ('SELF', 'EXIT')
|
173
|
THEN
|
174
|
-- aucune action
|
175
|
RETURN NEW ;
|
176
|
END IF ;
|
177
|
|
178
|
------ VERROUILLAGE DES CHAMPS LIES A LA NOMENCLATURE ------
|
179
|
-- modifiables uniquement par l'ADL
|
180
|
IF TG_OP = 'UPDATE'
|
181
|
THEN
|
182
|
IF (OLD.nomenclature OR NEW.nomenclature) AND NOT pg_has_role('g_admin', 'MEMBER') AND (
|
183
|
NOT coalesce(OLD.nomenclature, False) = coalesce(NEW.nomenclature, False)
|
184
|
OR NOT coalesce(OLD.niv1, '') = coalesce(NEW.niv1, '')
|
185
|
OR NOT coalesce(OLD.niv1_abr, '') = coalesce(NEW.niv1_abr, '')
|
186
|
OR NOT coalesce(OLD.niv2, '') = coalesce(NEW.niv2, '')
|
187
|
OR NOT coalesce(OLD.niv2_abr, '') = coalesce(NEW.niv2_abr, '')
|
188
|
OR NOT coalesce(OLD.nom_schema, '') = coalesce(NEW.nom_schema, '')
|
189
|
OR NOT coalesce(OLD.bloc, '') = coalesce(NEW.bloc, '')
|
190
|
)
|
191
|
THEN
|
192
|
RAISE EXCEPTION 'TB18. Opération interdite (schéma %).', NEW.nom_schema
|
193
|
USING HINT = '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.' ;
|
194
|
END IF ;
|
195
|
ELSIF TG_OP = 'INSERT'
|
196
|
THEN
|
197
|
IF NEW.nomenclature AND NOT pg_has_role('g_admin', 'MEMBER')
|
198
|
THEN
|
199
|
RAISE EXCEPTION 'TB19. Opération interdite (schéma %).', NEW.nom_schema
|
200
|
USING HINT = 'Seuls les membres de g_admin sont autorisés à ajouter des schémas à la nomenclature (nomenclature = True).' ;
|
201
|
END IF ;
|
202
|
END IF ;
|
203
|
|
204
|
------ NETTOYAGE DES CHAÎNES VIDES ------
|
205
|
-- si l'utilisateur a entré des chaînes vides on met des NULL
|
206
|
NEW.editeur := nullif(NEW.editeur, '') ;
|
207
|
NEW.lecteur := nullif(NEW.lecteur, '') ;
|
208
|
NEW.bloc := nullif(NEW.bloc, '') ;
|
209
|
NEW.niv1 := nullif(NEW.niv1, '') ;
|
210
|
NEW.niv1_abr := nullif(NEW.niv1_abr, '') ;
|
211
|
NEW.niv2 := nullif(NEW.niv2, '') ;
|
212
|
NEW.niv2_abr := nullif(NEW.niv2_abr, '') ;
|
213
|
NEW.nom_schema := nullif(NEW.nom_schema, '') ;
|
214
|
-- si producteur est vide on met par défaut g_admin
|
215
|
NEW.producteur := coalesce(nullif(NEW.producteur, ''), 'g_admin') ;
|
216
|
|
217
|
------ NETTOYAGE DES CHAMPS OID ------
|
218
|
-- pour les rôles de lecteur et éditeur,
|
219
|
-- si le champ de nom est vidé par l'utilisateur,
|
220
|
-- on vide en conséquence l'OID
|
221
|
IF NEW.editeur IS NULL
|
222
|
THEN
|
223
|
NEW.oid_editeur := NULL ;
|
224
|
END IF ;
|
225
|
IF NEW.lecteur IS NULL
|
226
|
THEN
|
227
|
NEW.oid_lecteur := NULL ;
|
228
|
END IF ;
|
229
|
-- si le schéma n'est pas créé, on s'assure que les champs
|
230
|
-- d'OID restent vides
|
231
|
-- à noter que l'event trigger sur DROP SCHEMA vide
|
232
|
-- déjà le champ oid_schema
|
233
|
IF NOT NEW.creation
|
234
|
THEN
|
235
|
NEW.oid_schema := NULL ;
|
236
|
NEW.oid_lecteur := NULL ;
|
237
|
NEW.oid_editeur := NULL ;
|
238
|
NEW.oid_producteur := NULL ;
|
239
|
END IF ;
|
240
|
|
241
|
------ VALIDITE DES NOMS DE ROLES ------
|
242
|
-- dans le cas d'un schéma pré-existant, on s'assure que les rôles qui
|
243
|
-- ne changent pas sont toujours valides (qu'ils existent et que le nom
|
244
|
-- n'a pas été modifié entre temps)
|
245
|
-- si tel est le cas, on les met à jour et on le note dans
|
246
|
-- ctrl, pour que le trigger AFTER sache qu'il ne s'agit
|
247
|
-- pas réellement de nouveaux rôles sur lesquels les droits
|
248
|
-- devraient être réappliqués
|
249
|
IF TG_OP = 'UPDATE' AND NEW.creation
|
250
|
THEN
|
251
|
-- producteur
|
252
|
IF OLD.creation AND OLD.producteur = NEW.producteur
|
253
|
THEN
|
254
|
SELECT rolname INTO n_role
|
255
|
FROM pg_catalog.pg_roles
|
256
|
WHERE pg_roles.oid = NEW.oid_producteur ;
|
257
|
IF NOT FOUND
|
258
|
-- le rôle producteur n'existe pas
|
259
|
THEN
|
260
|
-- cas invraisemblable, car un rôle ne peut pas être
|
261
|
-- supprimé alors qu'il est propriétaire d'un schéma, et la
|
262
|
-- commande ALTER SCHEMA OWNER TO aurait été interceptée
|
263
|
-- mais, s'il advient, on repart du propriétaire
|
264
|
-- renseigné dans pg_namespace
|
265
|
SELECT replace(nspowner::regrole::text, '"', ''), nspowner
|
266
|
INTO NEW.producteur, NEW.oid_producteur
|
267
|
FROM pg_catalog.pg_namespace
|
268
|
WHERE pg_namespace.oid = NEW.oid_schema ;
|
269
|
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 ;
|
270
|
NEW.ctrl := array_append(NEW.ctrl, 'CLEAN producteur') ;
|
271
|
ELSIF NOT n_role = NEW.producteur
|
272
|
-- libellé obsolète du producteur
|
273
|
THEN
|
274
|
NEW.producteur := n_role ;
|
275
|
RAISE NOTICE '[table de gestion] Schéma %. Mise à jour du libellé du rôle producteur, renommé entre temps.', NEW.nom_schema
|
276
|
USING DETAIL = 'Ancien nom "' || OLD.producteur || '", nouveau nom "' || NEW.producteur || '".' ;
|
277
|
NEW.ctrl := array_append(NEW.ctrl, 'CLEAN producteur') ;
|
278
|
END IF ;
|
279
|
END IF ;
|
280
|
-- éditeur
|
281
|
IF OLD.creation AND OLD.editeur = NEW.editeur
|
282
|
AND NOT NEW.editeur = 'public'
|
283
|
THEN
|
284
|
SELECT rolname INTO n_role
|
285
|
FROM pg_catalog.pg_roles
|
286
|
WHERE pg_roles.oid = NEW.oid_editeur ;
|
287
|
IF NOT FOUND
|
288
|
-- le rôle éditeur n'existe pas
|
289
|
THEN
|
290
|
NEW.editeur := NULL ;
|
291
|
NEW.oid_editeur := NULL ;
|
292
|
RAISE NOTICE '[table de gestion] Schéma %. Le rôle éditeur n''existant plus, il est déréférencé.', NEW.nom_schema
|
293
|
USING DETAIL = 'Ancien nom "' || OLD.editeur || '".' ;
|
294
|
NEW.ctrl := array_append(NEW.ctrl, 'CLEAN editeur') ;
|
295
|
ELSIF NOT n_role = NEW.editeur
|
296
|
-- libellé obsolète de l'éditeur
|
297
|
THEN
|
298
|
NEW.editeur := n_role ;
|
299
|
RAISE NOTICE '[table de gestion] Schéma %. Mise à jour du libellé du rôle éditeur, renommé entre temps.', NEW.nom_schema
|
300
|
USING DETAIL = 'Ancien nom "' || OLD.editeur || '", nouveau nom "' || NEW.editeur || '".' ;
|
301
|
NEW.ctrl := array_append(NEW.ctrl, 'CLEAN editeur') ;
|
302
|
END IF ;
|
303
|
END IF ;
|
304
|
-- lecteur
|
305
|
IF OLD.creation AND OLD.lecteur = NEW.lecteur
|
306
|
AND NOT NEW.lecteur = 'public'
|
307
|
THEN
|
308
|
SELECT rolname INTO n_role
|
309
|
FROM pg_catalog.pg_roles
|
310
|
WHERE pg_roles.oid = NEW.oid_lecteur ;
|
311
|
IF NOT FOUND
|
312
|
-- le rôle lecteur n'existe pas
|
313
|
THEN
|
314
|
NEW.lecteur := NULL ;
|
315
|
NEW.oid_lecteur := NULL ;
|
316
|
RAISE NOTICE '[table de gestion] Schéma %. Le rôle lecteur n''existant plus, il est déréférencé.', NEW.nom_schema
|
317
|
USING DETAIL = 'Ancien nom "' || OLD.lecteur || '".' ;
|
318
|
NEW.ctrl := array_append(NEW.ctrl, 'CLEAN lecteur') ;
|
319
|
ELSIF NOT n_role = NEW.lecteur
|
320
|
-- libellé obsolète du lecteur
|
321
|
THEN
|
322
|
NEW.lecteur := n_role ;
|
323
|
RAISE NOTICE '[table de gestion] Schéma %. Mise à jour du libellé du rôle lecteur, renommé entre temps.', NEW.nom_schema
|
324
|
USING DETAIL = 'Ancien nom "' || OLD.lecteur || '", nouveau nom "' || NEW.lecteur || '".' ;
|
325
|
NEW.ctrl := array_append(NEW.ctrl, 'CLEAN lecteur') ;
|
326
|
END IF ;
|
327
|
END IF ;
|
328
|
END IF ;
|
329
|
|
330
|
------ NON RESPECT DES CONTRAINTES ------
|
331
|
-- non nullité de nom_schema
|
332
|
IF NEW.nom_schema IS NULL
|
333
|
THEN
|
334
|
RAISE EXCEPTION 'TB8. Saisie incorrecte. Le nom du schéma doit être renseigné (champ nom_schema).' ;
|
335
|
END IF ;
|
336
|
|
337
|
-- unicité de nom_schema
|
338
|
IF TG_OP = 'INSERT' AND NEW.nom_schema IN (SELECT gestion_schema_etr.nom_schema FROM z_asgard.gestion_schema_etr)
|
339
|
THEN
|
340
|
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 ;
|
341
|
ELSIF TG_OP = 'UPDATE'
|
342
|
THEN
|
343
|
-- cas d'un changement de nom
|
344
|
IF NOT NEW.nom_schema = OLD.nom_schema
|
345
|
AND NEW.nom_schema IN (SELECT gestion_schema_etr.nom_schema FROM z_asgard.gestion_schema_etr)
|
346
|
THEN
|
347
|
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 ;
|
348
|
END IF ;
|
349
|
END IF ;
|
350
|
|
351
|
-- unicité de oid_schema
|
352
|
IF TG_OP = 'INSERT' AND NEW.oid_schema IN (SELECT gestion_schema_etr.oid_schema FROM z_asgard.gestion_schema_etr
|
353
|
WHERE gestion_schema_etr.oid_schema IS NOT NULL)
|
354
|
THEN
|
355
|
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 ;
|
356
|
ELSIF TG_OP = 'UPDATE'
|
357
|
THEN
|
358
|
-- cas (très hypothétique) d'une modification d'OID
|
359
|
IF NOT coalesce(NEW.oid_schema, -1) = coalesce(OLD.oid_schema, -1)
|
360
|
AND NEW.oid_schema IN (SELECT gestion_schema_etr.oid_schema FROM z_asgard.gestion_schema_etr
|
361
|
WHERE gestion_schema_etr.oid_schema IS NOT NULL)
|
362
|
THEN
|
363
|
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 ;
|
364
|
END IF ;
|
365
|
END IF ;
|
366
|
|
367
|
-- non répétition des rôles
|
368
|
IF NOT ((NEW.oid_lecteur IS NULL OR NOT NEW.oid_lecteur = NEW.oid_producteur)
|
369
|
AND (NEW.oid_editeur IS NULL OR NOT NEW.oid_editeur = NEW.oid_producteur)
|
370
|
AND (NEW.oid_lecteur IS NULL OR NEW.oid_editeur IS NULL OR NOT NEW.oid_lecteur = NEW.oid_editeur))
|
371
|
THEN
|
372
|
RAISE EXCEPTION 'TB13. Saisie incorrecte (schéma %). Les rôles producteur, lecteur et éditeur doivent être distincts.', NEW.nom_schema ;
|
373
|
END IF ;
|
374
|
END IF ;
|
375
|
|
376
|
------ COHERENCE BLOC/NOM DU SCHEMA ------
|
377
|
IF TG_OP IN ('INSERT', 'UPDATE')
|
378
|
THEN
|
379
|
IF NEW.bloc IS NULL AND NEW.nom_schema ~ '^[a-z]_'
|
380
|
-- si bloc est NULL, mais que le nom du schéma
|
381
|
-- comporte un préfixe, on met ce préfixe dans bloc
|
382
|
THEN
|
383
|
NEW.bloc := substring(NEW.nom_schema, '^([a-z])_') ;
|
384
|
RAISE NOTICE '[table de gestion] Mise à jour du bloc pour le schéma %.', NEW.nom_schema || ' (' || NEW.bloc || ')' ;
|
385
|
ELSIF NEW.bloc IS NULL
|
386
|
-- si bloc est NULL, et que (sous-entendu) le nom du schéma ne
|
387
|
-- respecte pas la nomenclature, on avertit l'utilisateur
|
388
|
THEN
|
389
|
RAISE NOTICE '[table de gestion] Le nom du schéma % ne respecte pas la nomenclature.', NEW.nom_schema
|
390
|
USING HINT = 'Si vous saisissez un préfixe dans le champ bloc, il sera automatiquement ajouté au nom du schéma.' ;
|
391
|
ELSIF NOT NEW.nom_schema ~ ('^'|| NEW.bloc || '_') AND NOT NEW.bloc = 'd'
|
392
|
-- le bloc est renseigné mais le nom du schéma ne correspond pas
|
393
|
-- (et il ne s'agit pas d'un schéma mis à la corbeille) :
|
394
|
-- si le nom est de la forme 'a_...', alors :
|
395
|
-- - dans le cas d'un UPDATE avec modification du nom
|
396
|
-- du schéma et pas du bloc, on se fie au nom du schéma
|
397
|
-- et on change le bloc ;
|
398
|
-- - si bloc n'est pas une lettre, on renvoie une erreur ;
|
399
|
-- - dans les autres cas, on se fie au bloc et change le
|
400
|
-- préfixe.
|
401
|
-- Si le nom ne comporte pas de préfixe :
|
402
|
-- - si le bloc est une lettre, on l'ajoute au début du
|
403
|
-- nom (sans doubler l'underscore, si le nom commençait par
|
404
|
-- un underscore) ;
|
405
|
-- - sinon on renvoie une erreur.
|
406
|
THEN
|
407
|
IF NEW.nom_schema ~ '^([a-z])?_'
|
408
|
THEN
|
409
|
IF TG_OP = 'UPDATE'
|
410
|
THEN
|
411
|
IF NOT NEW.nom_schema = OLD.nom_schema AND NEW.bloc = OLD.bloc
|
412
|
THEN
|
413
|
NEW.bloc := substring(NEW.nom_schema, '^([a-z])_') ;
|
414
|
RAISE NOTICE '[table de gestion] Mise à jour du bloc pour le schéma %.', NEW.nom_schema || ' (' || NEW.bloc || ')' ;
|
415
|
ELSIF NOT NEW.bloc ~ '^[a-z]$'
|
416
|
THEN
|
417
|
RAISE EXCEPTION 'TB14. Saisie invalide (schéma %). Le bloc doit être une lettre minuscule ou rien.', NEW.nom_schema ;
|
418
|
ELSE
|
419
|
NEW.nom_schema := regexp_replace(NEW.nom_schema, '^([a-z])?_', NEW.bloc || '_') ;
|
420
|
RAISE NOTICE '[table de gestion] Mise à jour du préfixe du schéma %.', NEW.nom_schema || ' d''après son bloc (' || NEW.bloc || ')' ;
|
421
|
END IF ;
|
422
|
ELSIF NOT NEW.bloc ~ '^[a-z]$'
|
423
|
THEN
|
424
|
RAISE EXCEPTION 'TB15. Saisie invalide (schéma %). Le bloc doit être une lettre minuscule ou rien.', NEW.nom_schema ;
|
425
|
ELSE
|
426
|
NEW.nom_schema := regexp_replace(NEW.nom_schema, '^([a-z])?_', NEW.bloc || '_') ;
|
427
|
RAISE NOTICE '[table de gestion] Mise à jour du préfixe du schéma %.', NEW.nom_schema || ' d''après son bloc (' || NEW.bloc || ')' ;
|
428
|
END IF ;
|
429
|
ELSIF NOT NEW.bloc ~ '^[a-z]$'
|
430
|
THEN
|
431
|
RAISE EXCEPTION 'TB16. Saisie invalide (schéma %). Le bloc doit être une lettre minuscule ou rien.', NEW.nom_schema ;
|
432
|
ELSE
|
433
|
NEW.nom_schema := NEW.bloc || '_' || NEW.nom_schema ;
|
434
|
RAISE NOTICE '[table de gestion] Mise à jour du préfixe du schéma %.', NEW.nom_schema || ' d''après son bloc (' || NEW.bloc || ')' ;
|
435
|
END IF ;
|
436
|
-- le trigger AFTER se chargera de renommer physiquement le
|
437
|
-- schéma d'autant que de besoin
|
438
|
END IF ;
|
439
|
END IF ;
|
440
|
|
441
|
------ MISE À LA CORBEILLE ------
|
442
|
-- notification de l'utilisateur
|
443
|
IF TG_OP = 'UPDATE'
|
444
|
THEN
|
445
|
-- schéma existant dont bloc bascule sur 'd'
|
446
|
-- ou schéma créé par bascule de creation sur True dans bloc vaut 'd'
|
447
|
IF NEW.creation AND NEW.bloc = 'd' AND (NOT OLD.bloc = 'd' OR OLD.bloc IS NULL)
|
448
|
OR NEW.creation AND NOT OLD.creation AND NEW.bloc = 'd'
|
449
|
THEN
|
450
|
RAISE NOTICE '[table de gestion] Le schéma % a été mis à la corbeille (bloc = ''d'').', NEW.nom_schema
|
451
|
USING HINT = 'Si vous basculez creation sur False, le schéma et son contenu seront automatiquement supprimés.' ;
|
452
|
-- restauration
|
453
|
ELSIF NEW.creation AND OLD.bloc = 'd' AND (NOT NEW.bloc = 'd' OR NEW.bloc IS NULL)
|
454
|
THEN
|
455
|
RAISE NOTICE '[table de gestion] Le schéma % a été retiré de la corbeille (bloc ne vaut plus ''d'').', NEW.nom_schema ;
|
456
|
END IF ;
|
457
|
ELSIF TG_OP = 'INSERT'
|
458
|
THEN
|
459
|
-- nouveau schéma dont bloc vaut 'd'
|
460
|
IF NEW.creation AND NEW.bloc = 'd'
|
461
|
THEN
|
462
|
RAISE NOTICE '[table de gestion] Le schéma % a été mis à la corbeille (bloc = ''d'').', NEW.nom_schema
|
463
|
USING HINT = 'Si vous basculez creation sur False, le schéma et son contenu seront automatiquement supprimés.' ;
|
464
|
END IF ;
|
465
|
END IF ;
|
466
|
|
467
|
------ RETURN ------
|
468
|
IF TG_OP IN ('UPDATE', 'INSERT')
|
469
|
THEN
|
470
|
RETURN NEW ;
|
471
|
ELSIF TG_OP = 'DELETE'
|
472
|
THEN
|
473
|
RETURN OLD ;
|
474
|
END IF ;
|
475
|
|
476
|
END
|
477
|
$BODY$ ;
|
478
|
|
479
|
ALTER FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_before()
|
480
|
OWNER TO g_admin ;
|
481
|
|
482
|
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.';
|
483
|
|
484
|
|
485
|
-- Trigger: asgard_on_modify_gestion_schema_before
|
486
|
|
487
|
CREATE TRIGGER asgard_on_modify_gestion_schema_before
|
488
|
BEFORE INSERT OR DELETE OR UPDATE
|
489
|
ON z_asgard_admin.gestion_schema
|
490
|
FOR EACH ROW
|
491
|
EXECUTE PROCEDURE z_asgard_admin.asgard_on_modify_gestion_schema_before() ;
|
492
|
|
493
|
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.';
|
494
|
|
495
|
|
496
|
|
497
|
------ 5.2 - TRIGGER AFTER ------
|
498
|
|
499
|
-- FUNCTION: z_asgard_admin.asgard_on_modify_gestion_schema_after()
|
500
|
|
501
|
CREATE OR REPLACE FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_after() RETURNS trigger
|
502
|
LANGUAGE plpgsql
|
503
|
AS $BODY$
|
504
|
/* OBJET : Fonction exécutée par le trigger asgard_on_modify_gestion_schema_after,
|
505
|
qui répercute physiquement les modifications de la table de gestion.
|
506
|
CIBLES : z_asgard_admin.gestion_schema.
|
507
|
PORTEE : FOR EACH ROW.
|
508
|
DECLENCHEMENT : AFTER INSERT OR UPDATE.*/
|
509
|
DECLARE
|
510
|
utilisateur text ;
|
511
|
createur text ;
|
512
|
administrateur text ;
|
513
|
e_mssg text ;
|
514
|
e_hint text ;
|
515
|
e_detl text ;
|
516
|
b_superuser boolean ;
|
517
|
b_test boolean ;
|
518
|
l_commande text[] ;
|
519
|
c text ;
|
520
|
c_reverse text ;
|
521
|
a_producteur text ;
|
522
|
a_editeur text ;
|
523
|
a_lecteur text ;
|
524
|
n int ;
|
525
|
BEGIN
|
526
|
|
527
|
------ REQUETES AUTO A IGNORER ------
|
528
|
-- les remontées du trigger lui-même (SELF),
|
529
|
-- ainsi que des event triggers sur les
|
530
|
-- suppressions de schémas (DROP), n'appellent
|
531
|
-- aucune action, elles sont donc exclues dès
|
532
|
-- le départ
|
533
|
-- les remontées des changements de noms sont
|
534
|
-- conservées, pour le cas où la mise en
|
535
|
-- cohérence avec "bloc" aurait conduit à une
|
536
|
-- modification du nom par le trigger BEFORE
|
537
|
-- (géré au point suivant)
|
538
|
-- les remontées des créations et changements
|
539
|
-- de propriétaire (CREATE et OWNER) appellent
|
540
|
-- des opérations sur les droits plus lourdes
|
541
|
-- qui ne permettent pas de les exclure en
|
542
|
-- amont
|
543
|
IF NEW.ctrl[1] IN ('SELF', 'DROP')
|
544
|
THEN
|
545
|
-- aucune action
|
546
|
RETURN NULL ;
|
547
|
END IF ;
|
548
|
|
549
|
------ MANIPULATIONS PREALABLES ------
|
550
|
utilisateur := current_user ;
|
551
|
|
552
|
-- si besoin pour les futures opérations sur les rôles,
|
553
|
-- récupération du nom d'un rôle dont current_user est membre
|
554
|
-- et qui a l'attribut CREATEROLE. Autant que possible, la
|
555
|
-- requête renvoie current_user lui-même. On exclut d'office les
|
556
|
-- rôles NOINHERIT qui ne pourront pas avoir simultanément les
|
557
|
-- droits du propriétaire de NEW et OLD.producteur
|
558
|
SELECT rolname INTO createur FROM pg_roles
|
559
|
WHERE pg_has_role(rolname, 'MEMBER') AND rolcreaterole AND rolinherit
|
560
|
ORDER BY rolname = current_user DESC ;
|
561
|
|
562
|
IF TG_OP = 'UPDATE'
|
563
|
THEN
|
564
|
-- la validité de OLD.producteur n'ayant
|
565
|
-- pas été contrôlée par le trigger BEFORE,
|
566
|
-- on le fait maintenant
|
567
|
SELECT rolname INTO a_producteur
|
568
|
FROM pg_catalog.pg_roles
|
569
|
WHERE pg_roles.oid = OLD.oid_producteur ;
|
570
|
-- pour la suite, on emploira toujours
|
571
|
-- a_producteur à la place de OLD.producteur
|
572
|
-- pour les opérations sur les droits.
|
573
|
-- Il est réputé non NULL pour un schéma
|
574
|
-- pré-existant (OLD.creation vaut True),
|
575
|
-- dans la mesure où un rôle ne peut être
|
576
|
-- supprimé s'il est propriétaire d'un
|
577
|
-- schéma et où tous les changements de
|
578
|
-- propriétaires sont remontés par event
|
579
|
-- triggers (+ contrôles pour assurer la
|
580
|
-- non-modification manuelle des OID).
|
581
|
IF NOT FOUND AND OLD.creation AND NOT 'CLEAN producteur' = ANY(NEW.ctrl)
|
582
|
THEN
|
583
|
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 ;
|
584
|
SELECT replace(nspowner::regrole::text, '"', '') INTO a_producteur
|
585
|
FROM pg_catalog.pg_namespace
|
586
|
WHERE pg_namespace.oid = NEW.oid_schema ;
|
587
|
IF NOT FOUND
|
588
|
THEN
|
589
|
RAISE EXCEPTION 'TA1. Anomalie critique (schéma %). Le propriétaire du schéma est introuvable.', OLD.nom_schema ;
|
590
|
END IF ;
|
591
|
END IF ;
|
592
|
END IF ;
|
593
|
|
594
|
------ MISE EN APPLICATION D'UN CHANGEMENT DE NOM DE SCHEMA ------
|
595
|
IF NOT NEW.oid_schema::regnamespace::text = quote_ident(NEW.nom_schema)
|
596
|
-- le schéma existe et ne porte pas déjà le nom NEW.nom_schema
|
597
|
THEN
|
598
|
EXECUTE 'ALTER SCHEMA '|| NEW.oid_schema::regnamespace::text ||
|
599
|
' RENAME TO ' || quote_ident(NEW.nom_schema) ;
|
600
|
RAISE NOTICE '... Le schéma % a été renommé.', NEW.nom_schema ;
|
601
|
END IF ;
|
602
|
-- exclusion des remontées d'event trigger correspondant
|
603
|
-- à des changements de noms
|
604
|
IF NEW.ctrl[1] = 'RENAME'
|
605
|
THEN
|
606
|
-- aucune action
|
607
|
RETURN NULL ;
|
608
|
END IF ;
|
609
|
|
610
|
------ PREPARATION DU PRODUCTEUR ------
|
611
|
-- on ne s'intéresse pas aux cas :
|
612
|
-- - d'un schéma qui n'a pas/plus vocation à exister
|
613
|
-- (creation vaut False) ;
|
614
|
-- - d'un schéma pré-existant dont les rôles ne changent pas
|
615
|
-- ou dont le libellé a juste été nettoyé par le trigger
|
616
|
-- BEFORE.
|
617
|
-- ils sont donc exclus au préalable
|
618
|
-- si le moindre rôle a changé, il faudra être membre du
|
619
|
-- groupe propriétaire/producteur pour pouvoir modifier
|
620
|
-- les privilèges en conséquence
|
621
|
b_test := False ;
|
622
|
IF NOT NEW.creation
|
623
|
THEN
|
624
|
b_test := True ;
|
625
|
ELSIF TG_OP = 'UPDATE'
|
626
|
THEN
|
627
|
IF OLD.creation
|
628
|
AND (NEW.producteur = OLD.producteur OR 'CLEAN producteur' = ANY(NEW.ctrl))
|
629
|
AND (coalesce(NEW.editeur, '') = coalesce(OLD.editeur, '') OR 'CLEAN editeur' = ANY(NEW.ctrl))
|
630
|
AND (coalesce(NEW.lecteur, '') = coalesce(OLD.lecteur, '') OR 'CLEAN lecteur' = ANY(NEW.ctrl))
|
631
|
THEN
|
632
|
b_test := True ;
|
633
|
END IF ;
|
634
|
END IF ;
|
635
|
|
636
|
IF NOT b_test
|
637
|
THEN
|
638
|
IF NOT NEW.producteur IN (SELECT rolname FROM pg_catalog.pg_roles)
|
639
|
-- si le producteur désigné n'existe pas, on le crée
|
640
|
-- ou renvoie une erreur si les privilèges de l'utilisateur
|
641
|
-- sont insuffisants
|
642
|
THEN
|
643
|
IF createur IS NULL
|
644
|
THEN
|
645
|
RAISE EXCEPTION 'TA2. Opération interdite. Vous n''êtes pas habilité à créer le rôle %.', NEW.producteur
|
646
|
USING HINT = 'Être membre d''un rôle disposant des attributs CREATEROLE et INHERIT est nécessaire pour créer de nouveaux producteurs.' ;
|
647
|
END IF ;
|
648
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
649
|
EXECUTE 'CREATE ROLE ' || quote_ident(NEW.producteur) ;
|
650
|
RAISE NOTICE '... Le rôle de groupe % a été créé.', NEW.producteur ;
|
651
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
652
|
ELSE
|
653
|
-- si le rôle producteur existe, on vérifie qu'il n'a pas l'option LOGIN
|
654
|
-- les superusers avec LOGIN (comme postgres) sont tolérés
|
655
|
-- paradoxe ou non, dans l'état actuel des choses, cette erreur se
|
656
|
-- déclenche aussi lorsque la modification ne porte que sur les rôles
|
657
|
-- lecteur/éditeur
|
658
|
SELECT rolsuper INTO b_superuser
|
659
|
FROM pg_roles WHERE rolname = NEW.producteur AND rolcanlogin ;
|
660
|
IF NOT b_superuser
|
661
|
THEN
|
662
|
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 ;
|
663
|
END IF ;
|
664
|
END IF ;
|
665
|
b_superuser := coalesce(b_superuser, False) ;
|
666
|
|
667
|
-- mise à jour du champ d'OID du producteur
|
668
|
IF NEW.ctrl[1] IS NULL OR NOT NEW.ctrl[1] IN ('OWNER', 'CREATE')
|
669
|
-- pas dans le cas d'une remontée de commande directe
|
670
|
-- où l'OID du producteur sera déjà renseigné
|
671
|
-- et uniquement s'il a réellement été modifié (ce
|
672
|
-- qui n'est pas le cas si les changements ne portent
|
673
|
-- que sur les rôles lecteur/éditeur)
|
674
|
THEN
|
675
|
UPDATE z_asgard.gestion_schema_etr
|
676
|
SET oid_producteur = quote_ident(NEW.producteur)::regrole::oid,
|
677
|
ctrl = ARRAY['SELF', 'x7-A;#rzo']
|
678
|
WHERE nom_schema = NEW.nom_schema AND (
|
679
|
oid_producteur IS NULL
|
680
|
OR NOT oid_producteur = quote_ident(NEW.producteur)::regrole::oid
|
681
|
) ;
|
682
|
END IF ;
|
683
|
|
684
|
-- implémentation des permissions manquantes sur NEW.producteur
|
685
|
IF NOT pg_has_role(utilisateur, NEW.producteur, 'USAGE')
|
686
|
THEN
|
687
|
b_test := True ;
|
688
|
IF createur IS NULL OR b_superuser
|
689
|
THEN
|
690
|
RAISE EXCEPTION 'TA4. Opération interdite. Permissions insuffisantes pour le rôle %.', NEW.producteur
|
691
|
USING HINT = 'Votre rôle doit être membre de ' || NEW.producteur
|
692
|
|| ' ou disposer de l''attribut CREATEROLE pour réaliser cette opération.' ;
|
693
|
END IF ;
|
694
|
END IF ;
|
695
|
IF TG_OP = 'UPDATE'
|
696
|
THEN
|
697
|
IF OLD.creation AND NOT pg_has_role(utilisateur, a_producteur, 'USAGE')
|
698
|
AND NOT (NEW.producteur = OLD.producteur OR 'CLEAN producteur' = ANY(NEW.ctrl))
|
699
|
-- les permissions sur OLD.producteur ne sont contrôlées que si le producteur
|
700
|
-- a effectivement été modifié
|
701
|
THEN
|
702
|
b_test := True ;
|
703
|
IF createur IS NULL OR b_superuser
|
704
|
THEN
|
705
|
RAISE EXCEPTION 'TA5. Opération interdite. Permissions insuffisantes pour le rôle %.', a_producteur
|
706
|
USING HINT = 'Votre rôle doit être membre de ' || a_producteur
|
707
|
|| ' ou disposer de l''attribut CREATEROLE pour réaliser cette opération.' ;
|
708
|
END IF ;
|
709
|
END IF ;
|
710
|
END IF ;
|
711
|
IF b_test
|
712
|
THEN
|
713
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
714
|
-- par commodité, on rend createur membre à la fois de NEW et (si besoin)
|
715
|
-- de OLD.producteur, même si l'utilisateur avait déjà accès à
|
716
|
-- l'un des deux par ailleurs :
|
717
|
IF NOT pg_has_role(createur, NEW.producteur, 'USAGE') AND NOT b_superuser
|
718
|
THEN
|
719
|
EXECUTE 'GRANT ' || quote_ident(NEW.producteur) || ' TO ' || quote_ident(createur) ;
|
720
|
RAISE NOTICE '... Permission accordée à %.', createur || ' sur le rôle ' || NEW.producteur ;
|
721
|
END IF ;
|
722
|
IF TG_OP = 'UPDATE'
|
723
|
THEN
|
724
|
IF NOT pg_has_role(createur, a_producteur, 'USAGE') AND NOT b_superuser
|
725
|
THEN
|
726
|
EXECUTE 'GRANT ' || quote_ident(a_producteur) || ' TO ' || quote_ident(createur) ;
|
727
|
RAISE NOTICE '... Permission accordée à %.', createur || ' sur le rôle ' || a_producteur ;
|
728
|
END IF ;
|
729
|
END IF ;
|
730
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
731
|
END IF ;
|
732
|
|
733
|
-- permission de g_admin sur le producteur, s'il y a encore lieu
|
734
|
-- à noter que, dans le cas où le producteur n'a pas été modifié, g_admin
|
735
|
-- devrait déjà avoir une permission sur NEW.producteur, sauf à ce qu'elle
|
736
|
-- lui ait été retirée manuellement entre temps. Les requêtes suivantes
|
737
|
-- génèreraient alors une erreur même dans le cas où la modification ne
|
738
|
-- porte que sur les rôles lecteur/éditeur - ce qui peut-être perçu comme
|
739
|
-- discutable.
|
740
|
IF NOT pg_has_role('g_admin', NEW.producteur, 'USAGE') AND NOT b_superuser
|
741
|
THEN
|
742
|
IF createur IS NOT NULL
|
743
|
THEN
|
744
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
745
|
EXECUTE 'GRANT ' || quote_ident(NEW.producteur) || ' TO g_admin' ;
|
746
|
RAISE NOTICE '... Permission accordée à g_admin sur le rôle %.', NEW.producteur ;
|
747
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
748
|
ELSE
|
749
|
SELECT grantee INTO administrateur
|
750
|
FROM information_schema.applicable_roles
|
751
|
WHERE is_grantable = 'YES' AND role_name = NEW.producteur ;
|
752
|
IF FOUND
|
753
|
THEN
|
754
|
EXECUTE 'SET ROLE ' || quote_ident(administrateur) ;
|
755
|
EXECUTE 'GRANT ' || quote_ident(NEW.producteur) || ' TO g_admin' ;
|
756
|
RAISE NOTICE '... Permission accordée à g_admin sur le rôle %.', NEW.producteur ;
|
757
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
758
|
ELSE
|
759
|
RAISE EXCEPTION 'TA6. Opération interdite. Permissions insuffisantes pour le rôle %.', NEW.producteur
|
760
|
USING DETAIL = 'GRANT ' || quote_ident(NEW.producteur) || ' TO g_admin',
|
761
|
HINT = 'Votre rôle doit être membre de ' || NEW.producteur
|
762
|
|| ' avec admin option ou disposer de l''attribut CREATEROLE pour réaliser cette opération.' ;
|
763
|
END IF ;
|
764
|
END IF ;
|
765
|
END IF ;
|
766
|
END IF ;
|
767
|
|
768
|
------ PREPARATION DE L'EDITEUR ------
|
769
|
-- limitée ici à la création du rôle et l'implémentation
|
770
|
-- de son OID. On ne s'intéresse donc pas aux cas :
|
771
|
-- - où il y a pas d'éditeur ;
|
772
|
-- - d'un schéma qui n'a pas/plus vocation à exister ;
|
773
|
-- - d'un schéma pré-existant dont l'éditeur ne change pas
|
774
|
-- ou dont le libellé a seulement été nettoyé par le
|
775
|
-- trigger BEFORE.
|
776
|
-- ils sont donc exclus au préalable
|
777
|
b_test := False ;
|
778
|
IF NOT NEW.creation OR NEW.editeur IS NULL
|
779
|
OR 'CLEAN editeur' = ANY(NEW.ctrl)
|
780
|
THEN
|
781
|
b_test := True ;
|
782
|
ELSIF TG_OP = 'UPDATE'
|
783
|
THEN
|
784
|
IF OLD.creation AND NEW.editeur = OLD.editeur
|
785
|
THEN
|
786
|
b_test := True ;
|
787
|
END IF ;
|
788
|
END IF ;
|
789
|
|
790
|
IF NOT b_test
|
791
|
THEN
|
792
|
IF NOT NEW.editeur IN (SELECT rolname FROM pg_catalog.pg_roles)
|
793
|
AND NOT NEW.editeur = 'public'
|
794
|
-- si l'éditeur désigné n'existe pas, on le crée
|
795
|
-- ou renvoie une erreur si les privilèges de l'utilisateur
|
796
|
-- sont insuffisants
|
797
|
THEN
|
798
|
IF createur IS NULL
|
799
|
THEN
|
800
|
RAISE EXCEPTION 'TA7. Opération interdite. Vous n''êtes pas habilité à créer le rôle %.', NEW.editeur
|
801
|
USING HINT = 'Être membre d''un rôle disposant des attributs CREATEROLE et INHERIT est nécessaire pour créer de nouveaux éditeurs.' ;
|
802
|
END IF ;
|
803
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
804
|
EXECUTE 'CREATE ROLE ' || quote_ident(NEW.editeur) ;
|
805
|
RAISE NOTICE '... Le rôle de groupe % a été créé.', NEW.editeur ;
|
806
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
807
|
END IF ;
|
808
|
|
809
|
-- mise à jour du champ d'OID de l'éditeur
|
810
|
IF NEW.editeur = 'public'
|
811
|
THEN
|
812
|
UPDATE z_asgard.gestion_schema_etr
|
813
|
SET oid_editeur = 0,
|
814
|
ctrl = ARRAY['SELF', 'x7-A;#rzo']
|
815
|
WHERE nom_schema = NEW.nom_schema AND (
|
816
|
oid_editeur IS NULL
|
817
|
OR NOT oid_editeur = 0
|
818
|
) ;
|
819
|
ELSE
|
820
|
UPDATE z_asgard.gestion_schema_etr
|
821
|
SET oid_editeur = quote_ident(NEW.editeur)::regrole::oid,
|
822
|
ctrl = ARRAY['SELF', 'x7-A;#rzo']
|
823
|
WHERE nom_schema = NEW.nom_schema AND (
|
824
|
oid_editeur IS NULL
|
825
|
OR NOT oid_editeur = quote_ident(NEW.editeur)::regrole::oid
|
826
|
) ;
|
827
|
END IF ;
|
828
|
END IF ;
|
829
|
|
830
|
------ PREPARATION DU LECTEUR ------
|
831
|
-- limitée ici à la création du rôle et l'implémentation
|
832
|
-- de son OID. On ne s'intéresse donc pas aux cas :
|
833
|
-- - où il y a pas de lecteur ;
|
834
|
-- - d'un schéma qui n'a pas/plus vocation à exister ;
|
835
|
-- - d'un schéma pré-existant dont l'éditeur ne change pas
|
836
|
-- ou dont le libellé a seulement été nettoyé par le
|
837
|
-- trigger BEFORE.
|
838
|
-- ils sont donc exclus au préalable
|
839
|
b_test := False ;
|
840
|
IF NOT NEW.creation OR NEW.lecteur IS NULL
|
841
|
OR 'CLEAN lecteur' = ANY(NEW.ctrl)
|
842
|
THEN
|
843
|
b_test := True ;
|
844
|
ELSIF TG_OP = 'UPDATE'
|
845
|
THEN
|
846
|
IF OLD.creation AND NEW.lecteur = OLD.lecteur
|
847
|
THEN
|
848
|
b_test := True ;
|
849
|
END IF ;
|
850
|
END IF ;
|
851
|
|
852
|
IF NOT b_test
|
853
|
THEN
|
854
|
IF NOT NEW.lecteur IN (SELECT rolname FROM pg_catalog.pg_roles)
|
855
|
AND NOT NEW.lecteur = 'public'
|
856
|
-- si le lecteur désigné n'existe pas, on le crée
|
857
|
-- ou renvoie une erreur si les privilèges de l'utilisateur
|
858
|
-- sont insuffisants
|
859
|
THEN
|
860
|
IF createur IS NULL
|
861
|
THEN
|
862
|
RAISE EXCEPTION 'TA8. Opération interdite. Vous n''êtes pas habilité à créer le rôle %.', NEW.lecteur
|
863
|
USING HINT = 'Être membre d''un rôle disposant des attributs CREATEROLE et INHERIT est nécessaire pour créer de nouveaux éditeurs.' ;
|
864
|
END IF ;
|
865
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
866
|
EXECUTE 'CREATE ROLE ' || quote_ident(NEW.lecteur) ;
|
867
|
RAISE NOTICE '... Le rôle de groupe % a été créé.', NEW.lecteur ;
|
868
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
869
|
END IF ;
|
870
|
|
871
|
-- mise à jour du champ d'OID du lecteur
|
872
|
IF NEW.lecteur = 'public'
|
873
|
THEN
|
874
|
UPDATE z_asgard.gestion_schema_etr
|
875
|
SET oid_lecteur = 0,
|
876
|
ctrl = ARRAY['SELF', 'x7-A;#rzo']
|
877
|
WHERE nom_schema = NEW.nom_schema AND (
|
878
|
oid_lecteur IS NULL
|
879
|
OR NOT oid_lecteur = 0
|
880
|
) ;
|
881
|
ELSE
|
882
|
UPDATE z_asgard.gestion_schema_etr
|
883
|
SET oid_lecteur = quote_ident(NEW.lecteur)::regrole::oid,
|
884
|
ctrl = ARRAY['SELF', 'x7-A;#rzo']
|
885
|
WHERE nom_schema = NEW.nom_schema AND (
|
886
|
oid_lecteur IS NULL
|
887
|
OR NOT oid_lecteur = quote_ident(NEW.lecteur)::regrole::oid
|
888
|
) ;
|
889
|
END IF ;
|
890
|
END IF ;
|
891
|
|
892
|
------ CREATION DU SCHEMA ------
|
893
|
-- on exclut au préalable les cas qui ne
|
894
|
-- correspondent pas à des créations, ainsi que les
|
895
|
-- remontées de l'event trigger sur CREATE SCHEMA,
|
896
|
-- car le schéma existe alors déjà
|
897
|
b_test := False ;
|
898
|
IF NOT NEW.creation OR NEW.ctrl[1] = 'CREATE'
|
899
|
THEN
|
900
|
b_test := True ;
|
901
|
ELSIF TG_OP = 'UPDATE'
|
902
|
THEN
|
903
|
IF OLD.creation
|
904
|
THEN
|
905
|
b_test := True ;
|
906
|
END IF ;
|
907
|
END IF ;
|
908
|
|
909
|
IF NOT b_test
|
910
|
THEN
|
911
|
-- le schéma est créé s'il n'existe pas déjà (cas d'ajout
|
912
|
-- d'un schéma pré-existant qui n'était pas référencé dans
|
913
|
-- gestion_schema jusque-là), sinon on alerte juste
|
914
|
-- l'utilisateur
|
915
|
IF NOT NEW.nom_schema IN (SELECT nspname FROM pg_catalog.pg_namespace)
|
916
|
THEN
|
917
|
IF NOT has_database_privilege(current_database(), 'CREATE')
|
918
|
OR NOT pg_has_role(NEW.producteur, 'USAGE')
|
919
|
THEN
|
920
|
-- si le rôle courant n'a pas les privilèges nécessaires pour
|
921
|
-- créer le schéma, on tente avec le rôle createur [de rôles]
|
922
|
-- pré-identifié, dont on sait au moins qu'il aura les
|
923
|
-- permissions nécessaires sur le rôle producteur - mais pas
|
924
|
-- s'il est habilité à créer des schémas
|
925
|
IF createur IS NOT NULL
|
926
|
THEN
|
927
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
928
|
END IF ;
|
929
|
IF NOT has_database_privilege(current_database(), 'CREATE')
|
930
|
OR NOT pg_has_role(NEW.producteur, 'USAGE')
|
931
|
THEN
|
932
|
RAISE EXCEPTION 'TA9. Opération interdite. Vous n''êtes pas habilité à créer le schéma %.', NEW.nom_schema
|
933
|
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.' ;
|
934
|
END IF ;
|
935
|
END IF ;
|
936
|
EXECUTE 'CREATE SCHEMA ' || quote_ident(NEW.nom_schema) || ' AUTHORIZATION ' || quote_ident(NEW.producteur) ;
|
937
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
938
|
RAISE NOTICE '... Le schéma % a été créé.', NEW.nom_schema ;
|
939
|
ELSE
|
940
|
RAISE NOTICE '(schéma % pré-existant)', NEW.nom_schema ;
|
941
|
END IF ;
|
942
|
-- récupération de l'OID du schéma
|
943
|
UPDATE z_asgard.gestion_schema_etr
|
944
|
SET oid_schema = quote_ident(NEW.nom_schema)::regnamespace::oid,
|
945
|
ctrl = ARRAY['SELF', 'x7-A;#rzo']
|
946
|
WHERE nom_schema = NEW.nom_schema AND (
|
947
|
oid_schema IS NULL
|
948
|
OR NOT oid_schema = quote_ident(NEW.nom_schema)::regnamespace::oid
|
949
|
) ;
|
950
|
END IF ;
|
951
|
|
952
|
------ APPLICATION DES DROITS DU PRODUCTEUR ------
|
953
|
-- comme précédemment pour la préparation du producteur,
|
954
|
-- on ne s'intéresse pas aux cas :
|
955
|
-- - d'un schéma qui n'a pas/plus vocation à exister
|
956
|
-- (creation vaut False) ;
|
957
|
-- - d'un schéma pré-existant dont le producteur ne change pas
|
958
|
-- ou dont le libellé a juste été nettoyé par le trigger
|
959
|
-- BEFORE ;
|
960
|
-- - d'un schéma qui vient d'être créé, car le producteur
|
961
|
-- sera déjà propriétaire du schéma et de son éventuel
|
962
|
-- contenu (INSERT ou remontée de l'event trigger
|
963
|
-- asgard_on_create_schema) ;
|
964
|
-- - de z_asgard_admin (pour permettre sa saisie initiale
|
965
|
-- dans la table de gestion, étant entendu qu'il est
|
966
|
-- impossible au trigger sur gestion_schema de lancer
|
967
|
-- un ALTER TABLE OWNER TO sur cette même table).
|
968
|
-- ils sont donc exclus au préalable
|
969
|
b_test := False ;
|
970
|
IF NOT NEW.creation
|
971
|
OR 'CLEAN producteur' = ANY(NEW.ctrl)
|
972
|
OR TG_OP = 'INSERT'
|
973
|
OR NEW.ctrl[1] = 'CREATE'
|
974
|
OR NEW.nom_schema = 'z_asgard_admin'
|
975
|
THEN
|
976
|
b_test := True ;
|
977
|
ELSIF TG_OP = 'UPDATE'
|
978
|
THEN
|
979
|
IF OLD.creation AND NEW.producteur = OLD.producteur
|
980
|
THEN
|
981
|
b_test := True ;
|
982
|
END IF ;
|
983
|
END IF ;
|
984
|
|
985
|
IF NOT b_test
|
986
|
THEN
|
987
|
-- si besoin, on bascule sur le rôle createur. À ce stade,
|
988
|
-- il est garanti que soit l'utilisateur courant soit
|
989
|
-- createur (pour le cas d'un utilisateur courant
|
990
|
-- NOINHERIT) aura les privilèges nécessaires
|
991
|
IF NOT pg_has_role(NEW.producteur, 'USAGE')
|
992
|
THEN
|
993
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
994
|
ELSIF TG_OP = 'UPDATE'
|
995
|
THEN
|
996
|
IF NOT pg_has_role(a_producteur, 'USAGE')
|
997
|
THEN
|
998
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
999
|
END IF ;
|
1000
|
END IF ;
|
1001
|
|
1002
|
-- changements de propriétaires
|
1003
|
IF (NEW.nom_schema, NEW.producteur)
|
1004
|
IN (SELECT schema_name, schema_owner FROM information_schema.schemata)
|
1005
|
THEN
|
1006
|
-- si producteur est déjà propriétaire du schéma (cas d'une remontée de l'event trigger,
|
1007
|
-- principalement), on ne change que les propriétaires des objets éventuels
|
1008
|
IF quote_ident(NEW.nom_schema)::regnamespace::oid
|
1009
|
IN (SELECT refobjid FROM pg_catalog.pg_depend WHERE deptype = 'n')
|
1010
|
THEN
|
1011
|
-- la commande n'est cependant lancée que s'il existe des dépendances de type
|
1012
|
-- DEPENDENCY_NORMAL sur le schéma, ce qui est une condition nécessaire à
|
1013
|
-- l'existence d'objets dans le schéma
|
1014
|
RAISE NOTICE 'attribution de la propriété des objets au rôle producteur du schéma % :', NEW.nom_schema ;
|
1015
|
SELECT z_asgard.asgard_admin_proprietaire(NEW.nom_schema, NEW.producteur, False)
|
1016
|
INTO n ;
|
1017
|
IF n = 0
|
1018
|
THEN
|
1019
|
RAISE NOTICE '> néant' ;
|
1020
|
END IF ;
|
1021
|
END IF ;
|
1022
|
ELSE
|
1023
|
-- sinon schéma + objets
|
1024
|
RAISE NOTICE 'attribution de la propriété du schéma et des objets au rôle producteur du schéma % :', NEW.nom_schema ;
|
1025
|
PERFORM z_asgard.asgard_admin_proprietaire(NEW.nom_schema, NEW.producteur) ;
|
1026
|
END IF ;
|
1027
|
|
1028
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
1029
|
END IF ;
|
1030
|
|
1031
|
------ APPLICATION DES DROITS DE L'EDITEUR ------
|
1032
|
-- on ne s'intéresse pas aux cas :
|
1033
|
-- - d'un schéma qui n'a pas/plus vocation à exister ;
|
1034
|
-- - d'un schéma pré-existant dont l'éditeur ne change pas
|
1035
|
-- (y compris pour rester vide) ou dont le libellé
|
1036
|
-- a seulement été nettoyé par le trigger BEFORE.
|
1037
|
-- ils sont donc exclus au préalable
|
1038
|
b_test := False ;
|
1039
|
IF NOT NEW.creation OR 'CLEAN editeur' = ANY(NEW.ctrl)
|
1040
|
THEN
|
1041
|
b_test := True ;
|
1042
|
ELSIF TG_OP = 'UPDATE'
|
1043
|
THEN
|
1044
|
IF OLD.creation
|
1045
|
AND coalesce(NEW.editeur, '') = coalesce(OLD.editeur, '')
|
1046
|
THEN
|
1047
|
b_test := True ;
|
1048
|
END IF ;
|
1049
|
END IF ;
|
1050
|
|
1051
|
IF NOT b_test
|
1052
|
THEN
|
1053
|
-- si besoin, on bascule sur le rôle createur. À ce stade,
|
1054
|
-- il est garanti que soit l'utilisateur courant soit
|
1055
|
-- createur (pour le cas d'un utilisateur courant
|
1056
|
-- NOINHERIT) aura les privilèges nécessaires
|
1057
|
IF NOT pg_has_role(NEW.producteur, 'USAGE')
|
1058
|
THEN
|
1059
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
1060
|
END IF ;
|
1061
|
|
1062
|
IF TG_OP = 'UPDATE'
|
1063
|
THEN
|
1064
|
-- la validité de OLD.editeur n'ayant
|
1065
|
-- pas été contrôlée par le trigger BEFORE,
|
1066
|
-- on le fait maintenant
|
1067
|
IF OLD.editeur = 'public'
|
1068
|
THEN
|
1069
|
a_editeur := 'public' ;
|
1070
|
-- récupération des modifications manuelles des
|
1071
|
-- droits de OLD.editeur/public, grâce à la fonction
|
1072
|
-- asgard_synthese_public
|
1073
|
SELECT array_agg(commande) INTO l_commande
|
1074
|
FROM z_asgard.asgard_synthese_public(
|
1075
|
quote_ident(NEW.nom_schema)::regnamespace
|
1076
|
) ;
|
1077
|
ELSE
|
1078
|
SELECT rolname INTO a_editeur
|
1079
|
FROM pg_catalog.pg_roles
|
1080
|
WHERE pg_roles.oid = OLD.oid_editeur ;
|
1081
|
IF FOUND
|
1082
|
THEN
|
1083
|
-- récupération des modifications manuelles des
|
1084
|
-- droits de OLD.editeur, grâce à la fonction
|
1085
|
-- asgard_synthese_role
|
1086
|
SELECT array_agg(commande) INTO l_commande
|
1087
|
FROM z_asgard.asgard_synthese_role(
|
1088
|
quote_ident(NEW.nom_schema)::regnamespace,
|
1089
|
quote_ident(a_editeur)::regrole
|
1090
|
) ;
|
1091
|
END IF ;
|
1092
|
END IF ;
|
1093
|
END IF ;
|
1094
|
|
1095
|
IF l_commande IS NOT NULL
|
1096
|
-- transfert sur NEW.editeur des droits de
|
1097
|
-- OLD.editeur, le cas échéant
|
1098
|
THEN
|
1099
|
IF NEW.editeur IS NOT NULL
|
1100
|
THEN
|
1101
|
RAISE NOTICE 'suppression et transfert vers le nouvel éditeur des privilèges de l''ancien éditeur du schéma % :', NEW.nom_schema ;
|
1102
|
ELSE
|
1103
|
RAISE NOTICE 'suppression des privilèges de l''ancien éditeur du schéma % :', NEW.nom_schema ;
|
1104
|
END IF ;
|
1105
|
FOREACH c IN ARRAY l_commande
|
1106
|
LOOP
|
1107
|
IF NEW.editeur IS NOT NULL
|
1108
|
THEN
|
1109
|
EXECUTE format(c, NEW.editeur) ;
|
1110
|
RAISE NOTICE '> %', format(c, NEW.editeur) ;
|
1111
|
END IF ;
|
1112
|
IF c ~ '^GRANT'
|
1113
|
THEN
|
1114
|
SELECT z_asgard.asgard_grant_to_revoke(c) INTO c_reverse ;
|
1115
|
EXECUTE format(c_reverse, a_editeur) ;
|
1116
|
RAISE NOTICE '> %', format(c_reverse, a_editeur) ;
|
1117
|
END IF ;
|
1118
|
END LOOP ;
|
1119
|
|
1120
|
-- sinon, application des privilèges standards de l'éditeur
|
1121
|
ELSIF NEW.editeur IS NOT NULL
|
1122
|
THEN
|
1123
|
RAISE NOTICE 'application des privilèges standards pour le rôle éditeur du schéma % :', NEW.nom_schema ;
|
1124
|
|
1125
|
EXECUTE 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
|
1126
|
RAISE NOTICE '> %', 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
|
1127
|
|
1128
|
EXECUTE 'GRANT SELECT, UPDATE, DELETE, INSERT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
|
1129
|
RAISE NOTICE '> %', 'GRANT SELECT, UPDATE, DELETE, INSERT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
|
1130
|
|
1131
|
EXECUTE 'GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
|
1132
|
RAISE NOTICE '> %', 'GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.editeur) ;
|
1133
|
|
1134
|
END IF ;
|
1135
|
|
1136
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
1137
|
END IF ;
|
1138
|
|
1139
|
------ APPLICATION DES DROITS DU LECTEUR ------
|
1140
|
-- on ne s'intéresse pas aux cas :
|
1141
|
-- - d'un schéma qui n'a pas/plus vocation à exister ;
|
1142
|
-- - d'un schéma pré-existant dont le lecteur ne change pas
|
1143
|
-- (y compris pour rester vide) ou dont le libellé
|
1144
|
-- a seulement été nettoyé par le trigger BEFORE.
|
1145
|
-- ils sont donc exclus au préalable
|
1146
|
b_test := False ;
|
1147
|
l_commande := NULL ;
|
1148
|
IF NOT NEW.creation OR 'CLEAN lecteur' = ANY(NEW.ctrl)
|
1149
|
THEN
|
1150
|
b_test := True ;
|
1151
|
ELSIF TG_OP = 'UPDATE'
|
1152
|
THEN
|
1153
|
IF OLD.creation
|
1154
|
AND coalesce(NEW.lecteur, '') = coalesce(OLD.lecteur, '')
|
1155
|
THEN
|
1156
|
b_test := True ;
|
1157
|
END IF ;
|
1158
|
END IF ;
|
1159
|
|
1160
|
IF NOT b_test
|
1161
|
THEN
|
1162
|
-- si besoin, on bascule sur le rôle createur. À ce stade,
|
1163
|
-- il est garanti que soit l'utilisateur courant soit
|
1164
|
-- createur (pour le cas d'un utilisateur courant
|
1165
|
-- NOINHERIT) aura les privilèges nécessaires
|
1166
|
IF NOT pg_has_role(NEW.producteur, 'USAGE')
|
1167
|
THEN
|
1168
|
EXECUTE 'SET ROLE ' || quote_ident(createur) ;
|
1169
|
END IF ;
|
1170
|
|
1171
|
IF TG_OP = 'UPDATE'
|
1172
|
THEN
|
1173
|
-- la validité de OLD.lecteur n'ayant
|
1174
|
-- pas été contrôlée par le trigger BEFORE,
|
1175
|
-- on le fait maintenant
|
1176
|
IF OLD.lecteur = 'public'
|
1177
|
THEN
|
1178
|
a_lecteur := 'public' ;
|
1179
|
-- récupération des modifications manuelles des
|
1180
|
-- droits de OLD.lecteur/public, grâce à la fonction
|
1181
|
-- asgard_synthese_public
|
1182
|
SELECT array_agg(commande) INTO l_commande
|
1183
|
FROM z_asgard.asgard_synthese_public(
|
1184
|
quote_ident(NEW.nom_schema)::regnamespace
|
1185
|
) ;
|
1186
|
ELSE
|
1187
|
SELECT rolname INTO a_lecteur
|
1188
|
FROM pg_catalog.pg_roles
|
1189
|
WHERE pg_roles.oid = OLD.oid_lecteur ;
|
1190
|
IF FOUND
|
1191
|
THEN
|
1192
|
-- récupération des modifications manuelles des
|
1193
|
-- droits de OLD.lecteur, grâce à la fonction
|
1194
|
-- asgard_synthese_role
|
1195
|
SELECT array_agg(commande) INTO l_commande
|
1196
|
FROM z_asgard.asgard_synthese_role(
|
1197
|
quote_ident(NEW.nom_schema)::regnamespace,
|
1198
|
quote_ident(a_lecteur)::regrole
|
1199
|
) ;
|
1200
|
END IF ;
|
1201
|
END IF ;
|
1202
|
END IF ;
|
1203
|
|
1204
|
IF l_commande IS NOT NULL
|
1205
|
-- transfert sur NEW.lecteur des droits de
|
1206
|
-- OLD.lecteur, le cas échéant
|
1207
|
THEN
|
1208
|
IF NEW.lecteur IS NOT NULL
|
1209
|
THEN
|
1210
|
RAISE NOTICE 'suppression et transfert vers le nouveau lecteur des privilèges de l''ancien lecteur du schéma % :', NEW.nom_schema ;
|
1211
|
ELSE
|
1212
|
RAISE NOTICE 'suppression des privilèges de l''ancien lecteur du schéma % :', NEW.nom_schema ;
|
1213
|
END IF ;
|
1214
|
FOREACH c IN ARRAY l_commande
|
1215
|
LOOP
|
1216
|
IF NEW.lecteur IS NOT NULL
|
1217
|
THEN
|
1218
|
EXECUTE format(c, NEW.lecteur) ;
|
1219
|
RAISE NOTICE '> %', format(c, NEW.lecteur) ;
|
1220
|
END IF ;
|
1221
|
IF c ~ '^GRANT'
|
1222
|
THEN
|
1223
|
SELECT z_asgard.asgard_grant_to_revoke(c) INTO c_reverse ;
|
1224
|
EXECUTE format(c_reverse, a_lecteur) ;
|
1225
|
RAISE NOTICE '> %', format(c_reverse, a_lecteur) ;
|
1226
|
END IF ;
|
1227
|
END LOOP ;
|
1228
|
|
1229
|
-- sinon, application des privilèges standards du lecteur
|
1230
|
ELSIF NEW.lecteur IS NOT NULL
|
1231
|
THEN
|
1232
|
RAISE NOTICE 'application des privilèges standards pour le rôle lecteur du schéma % :', NEW.nom_schema ;
|
1233
|
|
1234
|
EXECUTE 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
|
1235
|
RAISE NOTICE '> %', 'GRANT USAGE ON SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
|
1236
|
|
1237
|
EXECUTE 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
|
1238
|
RAISE NOTICE '> %', 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
|
1239
|
|
1240
|
EXECUTE 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
|
1241
|
RAISE NOTICE '> %', 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA ' || quote_ident(NEW.nom_schema) || ' TO ' || quote_ident(NEW.lecteur) ;
|
1242
|
|
1243
|
END IF ;
|
1244
|
|
1245
|
EXECUTE 'SET ROLE ' || quote_ident(utilisateur) ;
|
1246
|
END IF ;
|
1247
|
|
1248
|
RETURN NULL ;
|
1249
|
|
1250
|
EXCEPTION WHEN OTHERS THEN
|
1251
|
GET STACKED DIAGNOSTICS e_mssg = MESSAGE_TEXT,
|
1252
|
e_hint = PG_EXCEPTION_HINT,
|
1253
|
e_detl = PG_EXCEPTION_DETAIL ;
|
1254
|
RAISE EXCEPTION 'TA0. Opération annulée. Anomalie lors de la traduction physique des modifications de la table de gestion.'
|
1255
|
USING DETAIL = CASE WHEN e_detl = '' THEN e_mssg ELSE e_mssg || ' / ' || e_detl END,
|
1256
|
HINT = e_hint ;
|
1257
|
END
|
1258
|
$BODY$ ;
|
1259
|
|
1260
|
ALTER FUNCTION z_asgard_admin.asgard_on_modify_gestion_schema_after()
|
1261
|
OWNER TO g_admin ;
|
1262
|
|
1263
|
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.' ;
|
1264
|
|
1265
|
|
1266
|
-- Trigger: asgard_on_modify_gestion_schema_after
|
1267
|
|
1268
|
CREATE TRIGGER asgard_on_modify_gestion_schema_after
|
1269
|
AFTER INSERT OR UPDATE
|
1270
|
ON z_asgard_admin.gestion_schema
|
1271
|
FOR EACH ROW
|
1272
|
EXECUTE PROCEDURE z_asgard_admin.asgard_on_modify_gestion_schema_after();
|
1273
|
|
1274
|
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.' ;
|
1275
|
|