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.' ;
|