source: trunk/LATMOS-Accounts/bin/la-sql-upgrade.in @ 2038

Last change on this file since 2038 was 2038, checked in by nanardon, 7 years ago

Don't set table owner when upgrading schema

File size: 41.2 KB
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5use LATMOS::Accounts;
6use Getopt::Long;
7use Pod::Usage;
8
9my $DATADIR = '@DATADIR@';
10
11=head1 NAME
12
13    la-sql-upgrade - Update SQL base schema
14
15=head1 SYNOPSIS
16
17    la-sql-upgrade [options] [name]
18
19=cut
20
21GetOptions(
22    'c|config=s'     => \my $config,
23    'b|base=s'       => \my $base,
24    'no-commit'      => \my $nocommit,
25    'v|verbose'      => \my $verbose,
26    'h|help'         => sub { pod2usage(1); },
27) or pod2usage();
28
29=head1 OPTIONS
30
31=over 4
32
33=item -c|--config configdir
34
35Use this configuration directory instead of the default one.
36
37=item -b|--base basename
38
39Query this specific base instead of the default one.
40
41=back
42
43=cut
44
45$| = 1; # autoflush
46
47my $LA = LATMOS::Accounts->new($config, noacl => 1);
48my $labase = $LA->base($base);
49$labase->unexported(1);
50
51my $dbi = $labase->db;
52
53my $rev = $labase->get_global_value('schema_version') || 1;
54
55my @updates = (
56    {
57        ver => 3,
58        sql => [
59            q{ALTER TABLE nethost_attributes_ips DROP CONSTRAINT
60            nethost_is_single_ip},
61            q{DROP TRIGGER IF EXISTS check_zone_name_unity_tg ON nethost},
62            q{DROP TRIGGER IF EXISTS check_zone_name_unity_tg ON netzone},
63            q{DROP FUNCTION IF EXISTS check_zone_name_unity()},
64            q{ALTER TABLE nethost_attributes_ips DROP CONSTRAINT
65            nethost_is_single_ip},
66            q{INSERT INTO settings(varname, val) VALUES ('schema_version', 3)},
67        ],
68    },
69    {
70        ver => 4,
71        sql => [
72            q{
73            CREATE OR REPLACE FUNCTION nethost_sort_fields()
74            RETURNS trigger AS
75            $BODY$BEGIN
76
77            IF (TG_OP='INSERT') then
78            IF (new.attr='ip') THEN
79            insert into nethost_attributes_ips VALUES (new.*);
80            RETURN NULL;
81            END IF;
82
83            IF (new.attr='macaddr') THEN
84            insert into nethost_attributes_macs VALUES (new.*);
85            RETURN NULL;
86            END IF;
87
88            IF (new.attr='owner') THEN
89            insert into nethost_attributes_users VALUES (new.*);
90            RETURN NULL;
91            END IF;
92
93            IF (new.attr='user') THEN
94            insert into nethost_attributes_users VALUES (new.*);
95            RETURN NULL;
96            END IF;
97            end if;
98
99
100            if (TG_OP='DELETE') THEN
101            RETURN old;
102            else
103            RETURN new;
104            end if;
105            END;$BODY$
106            LANGUAGE plpgsql VOLATILE
107            COST 100;
108            },
109        ],
110    },
111    {
112        ver => 5,
113        sql => [
114            q{
115            CREATE OR REPLACE VIEW address_attributes AS
116            ( ( SELECT address."user" AS value, 'user' AS attr, address.rev AS attr_key, address.ikey AS okey
117            FROM address
118            UNION ALL
119            SELECT address.name AS value, 'name' AS attr, address.rev AS attr_key, address.ikey AS okey
120            FROM address )
121            UNION ALL
122            SELECT address_attributes.value, address_attributes.attr, address_attributes.attr_key, address_attributes.okey
123            FROM address_attributes_base address_attributes )
124            UNION ALL
125            SELECT '1' AS value, 'active' AS attr, address.rev AS attr_key, address.ikey AS okey
126            FROM "user" JOIN address ON "user".name = address."user"
127            WHERE "user".exported AND address.exported and
128            ("user".expire IS NULL or "user".expire > now())
129            }
130        ],
131    },
132    {
133        ver => 6,
134        sql => [
135            q{
136            CREATE TABLE request
137            (
138                id serial NOT NULL,
139                "create" timestamp with time zone NOT NULL DEFAULT now(),
140                name text NOT NULL,
141                object text,
142                apply timestamp with time zone NOT NULL DEFAULT now(),
143                done timestamp with time zone,
144                "user" text,
145                CONSTRAINT request_pkey PRIMARY KEY (id ),
146                CONSTRAINT request_name_fkey FOREIGN KEY (name)
147                REFERENCES accreq (name) MATCH SIMPLE
148                ON UPDATE CASCADE ON DELETE CASCADE,
149                CONSTRAINT request_user_fkey FOREIGN KEY ("user")
150                REFERENCES "user" (name) MATCH SIMPLE
151                ON UPDATE CASCADE ON DELETE SET NULL
152            )
153            },
154            q{
155            CREATE INDEX fki_request_name_fkey ON request
156            USING btree (name )
157            },
158            q{
159            CREATE INDEX fki_request_user_fkey ON request
160            USING btree ("user" )
161            },
162            q{
163            CREATE TABLE request_attributes
164            (
165                reqid bigint,
166                attribute text NOT NULL,
167                value text,
168                CONSTRAINT request_id_fkey FOREIGN KEY (reqid)
169                REFERENCES request (id) MATCH SIMPLE
170                ON UPDATE CASCADE ON DELETE CASCADE
171            )
172            },
173            q{
174            CREATE INDEX fki_request_id_fkey ON request_attributes
175            USING btree (reqid )
176            },
177            q{
178            delete from accreq_attributes_list
179            }
180        ],
181    },
182    {
183        ver => 7,
184        sql => [
185            q{
186            ALTER TABLE request ADD COLUMN automated boolean NOT NULL DEFAULT false;
187            },
188            q{
189            ALTER TABLE request ADD COLUMN objrev bigint;
190            },
191            q{
192            ALTER TABLE aliases ADD COLUMN description text;
193            },
194            q{
195            ALTER TABLE revaliases ADD COLUMN description text;
196            },
197            q{
198            CREATE OR REPLACE FUNCTION group_sort_fields()
199              RETURNS trigger AS
200              $BODY$BEGIN
201
202              IF (TG_OP='INSERT') then
203              IF (new.attr='managedBy'
204                  OR  new.attr='managedAlsoBy'
205                  OR  new.attr='member'
206                  OR  new.attr='memberUID') THEN
207              insert into group_attributes_users VALUES (new.*);
208              RETURN NULL;
209              END IF;
210
211              IF (new.attr='sutype') THEN
212              insert into group_attributes_sutypes VALUES (new.*);
213              RETURN NULL;
214              END IF;
215              end if;
216
217
218              IF (TG_OP = 'UPDATE') THEN
219              IF (new.attr='gidNumber') then
220              update "group" set gidnumber = new.value::integer where
221              "group".ikey = new.okey;
222              RETURN NULL;
223              END IF;
224              END IF;
225
226              IF (TG_OP = 'DELETE') THEN
227              IF (old.attr='exported') then
228              update "group" set exported = false where "group".ikey = old.okey;
229              return null;
230              end if;
231              else
232              IF (new.attr='exported') then
233              update "group" set exported = true where "group".ikey = new.okey;
234              RETURN NULL;
235              end if;
236              END IF;
237
238              if (TG_OP='DELETE') THEN
239              RETURN old;
240              else
241              RETURN new;
242              end if;
243              END;$BODY$
244                LANGUAGE plpgsql VOLATILE
245                  COST 100;
246            },
247        ],
248    },
249    {
250        ver => 8,
251        sql => [
252            q{
253            CREATE TABLE objectslogs
254            (
255              logkey SERIAL NOT NULL,
256              ikey bigint NOT NULL,
257              irev bigint,
258              otype text NOT NULL,
259              name text NOT NULL,
260              changetype text NOT NULL,
261              username text NOT NULL,
262              message text NOT NULL,
263              logdate timestamp with time zone NOT NULL DEFAULT now(),
264              CONSTRAINT objectlogs_pkey PRIMARY KEY (logkey)
265            );},
266            q{
267            CREATE INDEX objectlogs_name_idx
268              ON objectslogs
269              USING btree
270              (name);
271            },
272            q{
273            CREATE INDEX objectslogs_ikey_idx
274              ON objectslogs
275              USING btree
276              (ikey);
277            },
278            q{
279            CREATE INDEX objectslogs_otype_idx
280              ON objectslogs
281              USING btree
282              (otype);
283            }
284        ],
285    },
286    {
287        ver => 9,
288        sql => [
289            q{
290            CREATE TABLE nethost_attributes_nethosts
291            (
292            CONSTRAINT nethost_attributes_nethosts_pkey PRIMARY KEY (attr_key),
293            CONSTRAINT nethost_attr_nethosts_fkey FOREIGN KEY (okey)
294            REFERENCES nethost (ikey) MATCH SIMPLE
295            ON UPDATE CASCADE ON DELETE CASCADE,
296            CONSTRAINT nethost_attr_nethosts_nethosts FOREIGN KEY ("value")
297            REFERENCES nethost (name) MATCH SIMPLE
298            ON UPDATE CASCADE ON DELETE CASCADE
299            )
300            INHERITS (nethost_attributes);
301
302            CREATE INDEX fki_nethost_attr_nethosts_fkey
303            ON nethost_attributes_nethosts
304            USING btree
305            (okey);
306
307            CREATE TRIGGER nethost_attr_nethosts_update
308            AFTER INSERT OR UPDATE OR DELETE
309            ON nethost_attributes_nethosts
310            FOR EACH ROW
311            EXECUTE PROCEDURE nethost_attr_update_ref();
312
313
314            CREATE OR REPLACE FUNCTION nethost_sort_fields()
315              RETURNS trigger AS
316              $BODY$BEGIN
317
318              IF (TG_OP='INSERT') then
319              IF (new.attr='ip') THEN
320              insert into nethost_attributes_ips VALUES (new.*);
321              RETURN NULL;
322              END IF;
323
324              IF (new.attr='macaddr') THEN
325              insert into nethost_attributes_macs VALUES (new.*);
326              RETURN NULL;
327              END IF;
328
329              IF (new.attr='owner') THEN
330              insert into nethost_attributes_users VALUES (new.*);
331              RETURN NULL;
332              END IF;
333
334              IF (new.attr='user') THEN
335              insert into nethost_attributes_users VALUES (new.*);
336              RETURN NULL;
337              END IF;
338
339              IF (new.attr='related') THEN
340              insert into nethost_attributes_nethosts VALUES (new.*);
341              RETURN NULL;
342              END IF;
343              end if;
344
345              if (TG_OP='DELETE') THEN
346              RETURN old;
347              else
348              RETURN new;
349              end if;
350              END;$BODY$
351              LANGUAGE plpgsql VOLATILE
352              COST 100;
353
354            }
355        ],
356    },
357    {
358        ver => 10,
359        sql => [
360            q{
361            CREATE OR REPLACE FUNCTION service_attr_update_ref()
362            RETURNS trigger AS
363            $BODY$begin
364
365            IF (TG_OP != 'INSERT') then
366            update "service" set date = now() where "service".ikey = old.okey;
367            end if;
368            IF (TG_OP != 'DELETE') then
369            update "service"  set date = now() where "service".ikey = new.okey;
370            end if;
371
372            IF (TG_OP = 'DELETE') then
373            return old;
374            ELSE
375            return new;
376            END IF;
377
378            END;$BODY$
379            LANGUAGE plpgsql VOLATILE
380            COST 100;
381            },
382            q{
383
384            CREATE TABLE service
385            (
386            "start" date,
387            "end" date,
388            CONSTRAINT service_pkey PRIMARY KEY (name),
389            CONSTRAINT service_ikey_uniq UNIQUE (ikey)
390            )
391            INHERITS (objects);
392            },
393            q{
394            CREATE TABLE service_attributes_list
395            (
396            ikey integer NOT NULL DEFAULT nextval('ikey_seq'::regclass),
397            canonical text NOT NULL,
398            description text,
399            CONSTRAINT service_attributes_list_pkey PRIMARY KEY (ikey),
400            CONSTRAINT g_attr_l_service_uniq UNIQUE (canonical)
401            )
402            INHERITS (revisions, attributes_list)
403            WITH (
404            OIDS=FALSE
405            );
406
407            CREATE TABLE service_attributes
408            (
409            CONSTRAINT service_attributes_pkey PRIMARY KEY (attr_key),
410            CONSTRAINT service_attr_users_okey_fkey FOREIGN KEY (okey)
411            REFERENCES service (ikey) MATCH SIMPLE
412            ON UPDATE CASCADE ON DELETE CASCADE,
413            CONSTRAINT service_attributes_attr_fkey FOREIGN KEY (attr)
414            REFERENCES service_attributes_list (canonical) MATCH SIMPLE
415            ON UPDATE CASCADE ON DELETE NO ACTION
416            )
417            INHERITS (attributes)
418            WITH (
419            OIDS=FALSE
420            );
421
422            CREATE INDEX fki_service_attributes_attr_fkey
423            ON nethost_attributes
424            USING btree
425            (attr);
426
427            CREATE INDEX service_attr_value_idx
428            ON nethost_attributes
429            USING btree
430            (value);
431
432            CREATE TRIGGER serivce_attr_update
433            AFTER INSERT OR UPDATE OR DELETE
434            ON service_attributes
435            FOR EACH ROW
436            EXECUTE PROCEDURE service_attr_update_ref();
437            },
438            q{
439            CREATE TABLE service_attributes_users
440            (
441            CONSTRAINT service_attributes_user_pkey PRIMARY KEY (attr_key),
442            CONSTRAINT service_attr_users_okey_fkey FOREIGN KEY (okey)
443            REFERENCES service (ikey) MATCH SIMPLE
444            ON UPDATE CASCADE ON DELETE CASCADE,
445            CONSTRAINT service_attributes_users_attr_fkey FOREIGN KEY (attr)
446            REFERENCES service_attributes_list (canonical) MATCH SIMPLE
447            ON UPDATE CASCADE ON DELETE NO ACTION,
448            CONSTRAINT service_attributes_users_user_fkey FOREIGN KEY (value)
449            REFERENCES "user" (name) MATCH SIMPLE
450            ON UPDATE CASCADE ON DELETE CASCADE,
451            CONSTRAINT service_attributes_users_uniq UNIQUE (okey, attr, value)
452            )
453            INHERITS (service_attributes);
454
455            CREATE INDEX fki_service_attr_users_okey_fkey
456            ON service_attributes_users
457            USING btree
458            (okey);
459
460            CREATE INDEX fki_service_attributes_users_attr_fkey
461            ON service_attributes_users
462            USING btree
463            (attr);
464
465            CREATE INDEX fki_service_attributes_users_user_fkey
466            ON service_attributes_users
467            USING btree
468            (value);
469
470            CREATE TRIGGER service_attributes_users_update_ref
471            AFTER INSERT OR UPDATE OR DELETE
472            ON service_attributes_users
473            FOR EACH ROW
474            EXECUTE PROCEDURE service_attr_update_ref();
475
476            CREATE OR REPLACE FUNCTION service_sort_fields()
477              RETURNS trigger AS
478              $BODY$BEGIN
479
480              if (TG_OP='INSERT' or TG_OP='UPDATE') THEN
481              IF (new.attr='manager') THEN
482              insert into service_attributes_users VALUES (new.*);
483              RETURN NULL;
484              END IF;
485              END IF;
486
487              if (TG_OP='DELETE') THEN
488              RETURN old;
489              else
490              RETURN new;
491              end if;
492              END;$BODY$
493              LANGUAGE plpgsql VOLATILE
494              COST 100;
495
496              CREATE TRIGGER service_sort_field_tg
497              BEFORE INSERT OR UPDATE OR DELETE
498              ON service_attributes
499              FOR EACH ROW
500              EXECUTE PROCEDURE service_sort_fields();
501
502            CREATE TRIGGER service_rev_tg
503            BEFORE INSERT OR UPDATE OR DELETE
504            ON service
505            FOR EACH ROW
506            EXECUTE PROCEDURE rev_tg_f();
507            },
508        ],
509    },
510    {
511        ver => 11,
512        sql => [
513            q{
514            ALTER TABLE "user" ADD COLUMN endcircuit timestamp with time zone
515            }
516        ],
517    },
518    {
519        ver => 12,
520        sql => [
521            q{
522            CREATE OR REPLACE VIEW user_attributes AS
523            (        (        (        (        (        (        (        (        (        (        (
524            SELECT "user".uidnumber::text AS value, 'uidnumber' AS attr, "user".rev AS attr_key, "user".ikey AS okey FROM "user"
525            UNION ALL
526            SELECT "user".gidnumber::text AS value, 'gidnumber' AS attr, "user".rev AS attr_key, "user".ikey AS okey FROM "user")
527            UNION ALL
528            SELECT "user".name AS value, 'name' AS attr, "user".rev AS attr_key, "user".ikey AS okey FROM "user")
529            UNION ALL
530            SELECT "user".expire::text AS value, 'expire' AS attr, "user".rev AS attr_key, "user".ikey AS okey FROM "user"
531            WHERE "user".expire IS NOT NULL)
532            UNION ALL
533            SELECT '1'::text AS value, 'exported' AS attr, "user".rev AS attr_key, "user".ikey AS okey
534            FROM "user"
535            WHERE "user".exported = true)
536            UNION ALL
537            SELECT address_attributes_site.value, 'allsite' AS attr, "user".rev AS attr_key, "user".ikey AS okey
538            FROM "user"
539            JOIN address ON address."user" = "user".name
540            JOIN address_attributes_site ON address_attributes_site.okey = address.ikey
541            WHERE address_attributes_site.attr = 'site'::text AND address.exported = true)
542            UNION ALL
543            SELECT "group".name AS value, 'memberOf' AS attr, "user".rev AS attr_key, "user".ikey AS okey
544            FROM "user"
545            JOIN group_attributes ON group_attributes.value = "user".name
546            JOIN "group" ON group_attributes.okey = "group".ikey
547            WHERE group_attributes.attr = 'memberUID'::text)
548            UNION ALL
549            SELECT user_attributes.value, user_attributes.attr, user_attributes.attr_key, user_attributes.okey
550            FROM user_attributes_base user_attributes)
551            UNION ALL
552            SELECT "group".name AS value, 'departments' AS attr, "user".rev AS attr_key, "user".ikey AS okey
553            FROM "group"
554            JOIN group_attributes_sutypes ON "group".ikey = group_attributes_sutypes.okey
555            JOIN group_attributes_users ON "group".ikey = group_attributes_users.okey AND group_attributes_users.attr = 'memberUID'::text
556            JOIN "user" ON "user".name = group_attributes_users.value
557            WHERE group_attributes_sutypes.value = 'dpmt'::text AND group_attributes_sutypes.attr = 'sutype'::text)
558            UNION ALL
559            SELECT "group".name AS value, 'cells' AS attr, "user".rev AS attr_key, "user".ikey AS okey
560            FROM "group"
561            JOIN group_attributes_sutypes ON "group".ikey = group_attributes_sutypes.okey
562            JOIN group_attributes_users ON "group".ikey = group_attributes_users.okey AND group_attributes_users.attr = 'memberUID'::text
563            JOIN "user" ON "user".name = group_attributes_users.value
564            WHERE group_attributes_sutypes.value = 'cell'::text AND group_attributes_sutypes.attr = 'sutype'::text)
565            UNION ALL
566            SELECT "group".name AS value, 'managedObjects' AS attr, "user".rev AS attr_key, "user".ikey AS okey
567            FROM "user"
568            JOIN group_attributes ON group_attributes.value = "user".name
569            JOIN "group" ON group_attributes.okey = "group".ikey
570            WHERE group_attributes.attr = 'managedBy'::text)
571            UNION ALL
572            SELECT justify_interval(now() - "user".expire)::text AS value, 'expired' AS attr, "user".rev AS attr_key, "user".ikey AS okey
573            FROM "user"
574            WHERE "user".expire <= now())
575            UNION ALL
576            SELECT 1::text AS value, 'active' AS attr, "user".rev AS attr_key, "user".ikey AS okey
577            FROM "user"
578            WHERE ("user".expire IS NULL OR "user".expire >= now()) AND "user".exported = true
579            UNION ALL
580            SELECT 0::text AS value, 'active' AS attr, "user".rev AS attr_key, "user".ikey AS okey
581            FROM "user"
582            WHERE ("user".expire IS NOT NULL and "user".expire <= now()) or "user".exported = false;
583            },
584            q{
585            CREATE OR REPLACE FUNCTION rev_tg_aliases_f()
586            RETURNS trigger AS
587            $BODY$begin
588
589            IF (TG_OP = 'DELETE') THEN
590            update "user" set rev = nextval('revisions_rev_seq'::regclass), "date" = now() where "name" = ANY (old.forward);
591            return old;
592            ELSE
593                IF (TG_OP = 'UPDATE') THEN
594                update "user" set rev = nextval('revisions_rev_seq'::regclass), "date" = now() where "name" = ANY (old.forward);
595                END IF;
596            update "user" set rev = nextval('revisions_rev_seq'::regclass), "date" = now() where "name" = ANY (new.forward);
597            return new;
598            END IF;
599
600            end;$BODY$
601            LANGUAGE plpgsql VOLATILE
602            COST 100;
603
604            CREATE TRIGGER aliases_user_tg
605            AFTER INSERT OR UPDATE OR DELETE
606            ON aliases
607            FOR EACH ROW
608            EXECUTE PROCEDURE rev_tg_aliases_f();
609            },
610        ],
611    },
612    {
613        ver => 13,
614        sql => [
615            q{
616            CREATE TABLE "stat"
617            (
618            name text NOT NULL,
619            CONSTRAINT stat_pkey PRIMARY KEY (name),
620            CONSTRAINT stat_okey_uniq UNIQUE (ikey)
621            )
622            INHERITS (objects);
623            CREATE INDEX stat_exported_idx
624            ON stat USING btree (exported);
625            CREATE UNIQUE INDEX stat_rev_idx
626            ON stat USING btree (rev);
627
628            CREATE OR REPLACE FUNCTION stat_attr_update_ref()
629            RETURNS trigger AS
630            $BODY$begin
631
632            IF (TG_OP != 'INSERT') then
633            update "stat" set date = now() where "stat".ikey = old.okey;
634            end if;
635            IF (TG_OP != 'DELETE') then
636            update "stat"  set date = now() where "stat".ikey = new.okey;
637            end if;
638
639            IF (TG_OP = 'DELETE') then
640            return old;
641            ELSE
642            return new;
643            END IF;
644
645            END;$BODY$
646            LANGUAGE plpgsql VOLATILE
647            COST 100;
648            },
649            q{
650            CREATE TABLE stat_attributes
651            (
652            CONSTRAINT stat_attributes_pkey PRIMARY KEY (attr_key),
653            CONSTRAINT stat FOREIGN KEY (okey)
654            REFERENCES stat (ikey) MATCH SIMPLE
655            ON UPDATE CASCADE ON DELETE CASCADE
656            )
657            INHERITS (attributes);
658            CREATE INDEX stat_attributes_attr_fkey
659            ON stat_attributes
660            USING btree
661            (attr);
662            CREATE INDEX stat_attr_value_idx
663            ON stat_attributes
664            USING btree
665            (value);
666            CREATE TRIGGER stat_attr_update
667            AFTER INSERT OR UPDATE OR DELETE
668            ON stat_attributes
669            FOR EACH ROW
670            EXECUTE PROCEDURE stat_attr_update_ref();
671            },
672            q{
673            CREATE TABLE stat_attributes_list
674            (
675            CONSTRAINT stat_attr_list_pkey PRIMARY KEY (ikey),
676            CONSTRAINT stat_attr_l_c_uniq UNIQUE (canonical)
677            )
678            INHERITS (revisions, attributes_list);
679            },
680            q{
681            CREATE TABLE statsentry
682            (
683            okey integer NOT NULL,
684            id bigint NOT NULL DEFAULT nextval('revisions_rev_seq'::regclass),
685            tstamp timestamp with time zone NOT NULL DEFAULT now(),
686            CONSTRAINT stat FOREIGN KEY (okey)
687            REFERENCES stat (ikey) MATCH SIMPLE
688            ON UPDATE CASCADE ON DELETE CASCADE,
689            CONSTRAINT statsentry_pkey PRIMARY KEY (id)
690            );
691            CREATE TABLE statvalues
692            (
693            sid bigint NOT NULL,
694            value text NOT NULL,
695            count bigint NOT NULL,
696            CONSTRAINT statvalues_pkey PRIMARY KEY (sid, value),
697            CONSTRAINT statvalues_fkey FOREIGN KEY (sid)
698            REFERENCES statsentry (id) MATCH SIMPLE
699            ON UPDATE CASCADE ON DELETE CASCADE
700            )
701            },
702        ],
703    },
704    {
705        ver => 14,
706        sql => [
707            q{
708            ALTER TABLE objects ADD COLUMN createdby text;
709            },
710            q{
711            ALTER TABLE objects ADD COLUMN modifiedby text;
712            },
713        ],
714    },
715    {
716        ver => 15,
717        sql => [
718            q{
719            CREATE TABLE "employment"
720            (
721            name text NOT NULL,
722            "user" text NOT NULL,
723            firstday date NOT NULL default now(),
724            lastday  date,
725            CONSTRAINT employment_pkey PRIMARY KEY (name),
726            CONSTRAINT employment_okey_uniq UNIQUE (ikey),
727            CONSTRAINT employment_user_fkey FOREIGN KEY ("user")
728                REFERENCES "user" (name) MATCH SIMPLE
729                ON UPDATE CASCADE ON DELETE CASCADE
730            )
731            INHERITS (objects);
732            CREATE INDEX employment_exported_idx
733            ON employment USING btree (exported);
734            CREATE UNIQUE INDEX employment_rev_idx
735            ON employment USING btree (rev);
736
737            CREATE OR REPLACE FUNCTION employment_attr_update_ref()
738            RETURNS trigger AS
739            $BODY$begin
740
741            IF (TG_OP != 'INSERT') then
742            update "employment" set date = now() where "employment".ikey = old.okey;
743            end if;
744            IF (TG_OP != 'DELETE') then
745            update "employment"  set date = now() where "employment".ikey = new.okey;
746            end if;
747
748            IF (TG_OP = 'DELETE') then
749            return old;
750            ELSE
751            return new;
752            END IF;
753
754            END;$BODY$
755            LANGUAGE plpgsql VOLATILE
756            COST 100;
757            },
758            q{
759            CREATE TABLE employment_attributes
760            (
761            CONSTRAINT employment_attributes_pkey PRIMARY KEY (attr_key),
762            CONSTRAINT employment FOREIGN KEY (okey)
763            REFERENCES employment (ikey) MATCH SIMPLE
764            ON UPDATE CASCADE ON DELETE CASCADE
765            )
766            INHERITS (attributes);
767            CREATE INDEX employment_attributes_attr_fkey
768            ON employment_attributes
769            USING btree
770            (attr);
771            CREATE INDEX employment_attr_value_idx
772            ON employment_attributes
773            USING btree
774            (value);
775            CREATE TRIGGER employment_attr_update
776            AFTER INSERT OR UPDATE OR DELETE
777            ON employment_attributes
778            FOR EACH ROW
779            EXECUTE PROCEDURE employment_attr_update_ref();
780            },
781            q{
782            CREATE TABLE employment_attributes_list
783            (
784            CONSTRAINT employment_attr_list_pkey PRIMARY KEY (ikey),
785            CONSTRAINT employment_attr_l_c_uniq UNIQUE (canonical)
786            )
787            INHERITS (revisions, attributes_list);
788            },
789            q{
790            CREATE INDEX employment_firstday_idx
791              ON employment
792                USING btree
793                  (firstday NULLS FIRST);
794            CREATE INDEX employment_lastday_idx
795              ON employment
796                USING btree
797                  (lastday NULLS LAST);
798            },
799        ],
800    },
801    {
802        ver => 16,
803        sql => [
804            q{
805            ALTER TABLE aliases
806              ADD CONSTRAINT aliases_ikey_uniq UNIQUE(ikey);
807            CREATE OR REPLACE FUNCTION aliases_attr_update_ref()
808            RETURNS trigger AS
809            $BODY$begin
810
811            IF (TG_OP != 'INSERT') then
812            update "aliases" set date = now() where "aliases".ikey = old.okey;
813            end if;
814            IF (TG_OP != 'DELETE') then
815            update "aliases"  set date = now() where "aliases".ikey = new.okey;
816            end if;
817
818            IF (TG_OP = 'DELETE') then
819            return old;
820            ELSE
821            return new;
822            END IF;
823
824            END;$BODY$
825            LANGUAGE plpgsql VOLATILE
826            COST 100;
827            },
828            q{
829            CREATE TABLE aliases_attributes_base
830            (
831            CONSTRAINT aliases_attributes_base_pkey PRIMARY KEY (attr_key),
832            CONSTRAINT aliases_fkey FOREIGN KEY (okey)
833            REFERENCES aliases (ikey) MATCH SIMPLE
834            ON UPDATE CASCADE ON DELETE CASCADE
835            )
836            INHERITS (attributes);
837            CREATE INDEX aliases_attributes_base_attr_fkey
838            ON aliases_attributes_base
839            USING btree
840            (attr);
841            CREATE INDEX aliases_attr_value_idx
842            ON aliases_attributes_base
843            USING btree
844            (value);
845            CREATE TRIGGER aliases_attr_update
846            AFTER INSERT OR UPDATE OR DELETE
847            ON aliases_attributes_base
848            FOR EACH ROW
849            EXECUTE PROCEDURE aliases_attr_update_ref();
850            },
851            q{
852            CREATE OR REPLACE VIEW aliases_attributes AS
853            SELECT "user".name AS value,
854            'user'::text AS attr,
855            aliases.rev AS attr_key,
856            aliases.ikey AS okey
857            FROM aliases
858            JOIN "user" ON aliases.name = "user".name OR aliases.forward = ARRAY["user".name]
859            union all
860               select value, attr, attr_key, okey from aliases_attributes_base
861            UNION ALL
862                SELECT "aliases".name AS value,
863                'name'::text AS attr,
864                "aliases".rev AS attr_key,
865                "aliases".ikey AS okey
866                FROM "aliases";
867
868           CREATE OR REPLACE RULE aliases_attributes_insert AS
869           ON INSERT TO aliases_attributes DO INSTEAD  INSERT INTO aliases_attributes_base (value, attr, okey)
870           VALUES (new.value, new.attr, new.okey);
871
872           CREATE OR REPLACE RULE aliases_attributes_update AS
873           ON UPDATE TO aliases_attributes DO INSTEAD  UPDATE aliases_attributes_base SET value = new.value, attr = new.attr, okey = new.okey
874           WHERE aliases_attributes_base.attr_key = old.attr_key AND aliases_attributes_base.attr = old.attr;
875
876           CREATE OR REPLACE RULE aliases_atttributes_delete AS
877           ON DELETE TO aliases_attributes DO INSTEAD  DELETE FROM aliases_attributes_base
878           WHERE aliases_attributes_base.attr_key = old.attr_key AND aliases_attributes_base.attr = old.attr;
879            }
880
881        ],
882    },
883    {
884        ver => 17,
885        sql => [
886            q{
887            CREATE TABLE passwordreset
888            (
889            -- Hérité(e) from table revisions:  rev integer NOT NULL DEFAULT nextval('revisions_rev_seq'::regclass),
890            -- Hérité(e) from table revisions:  date timestamp with time zone NOT NULL DEFAULT now(),
891            -- Hérité(e) from table revisions:  "create" timestamp with time zone NOT NULL DEFAULT now(),
892            -- Hérité(e) from table revisions:  ikey integer NOT NULL DEFAULT nextval('ikey_seq'::regclass),
893            "user" text NOT NULL,
894            id text NOT NULL,
895            CONSTRAINT passwordreset_pkey PRIMARY KEY (id),
896            CONSTRAINT password_reset_user_fkey FOREIGN KEY ("user")
897            REFERENCES "user" (name) MATCH SIMPLE
898            ON UPDATE CASCADE ON DELETE CASCADE
899            )
900            INHERITS (revisions)
901            WITH (
902            OIDS=FALSE
903            );
904            },
905        ],
906    },
907    {
908        ver => 18,
909        sql => [
910            q{
911            ALTER TABLE employment
912            ADD CHECK (lastday is null or firstday <= lastday);
913            }
914        ],
915    },
916    {
917        ver => 19,
918        sql => [
919            q{
920            ALTER TABLE "nethost" ADD COLUMN expire timestamp with time zone;
921            }
922        ],
923    },
924    {
925        ver => 20,
926        sql => [
927            q{
928            CREATE OR REPLACE VIEW user_attributes AS
929                SELECT "user".uidnumber::text AS value, 'uidnumber' AS attr, "user".rev AS attr_key, "user".ikey AS okey
930                FROM "user"
931            UNION ALL
932                SELECT "user".gidnumber::text AS value, 'gidnumber' AS attr, "user".rev AS attr_key, "user".ikey AS okey
933                FROM "user"
934            UNION ALL
935                SELECT "user".name AS value, 'name' AS attr, "user".rev AS attr_key, "user".ikey AS okey
936                FROM "user"
937            UNION ALL
938                SELECT "user".expire::text AS value, 'expire' AS attr, "user".rev AS attr_key, "user".ikey AS okey
939                FROM "user"
940                WHERE "user".expire IS NOT NULL
941            UNION ALL
942                SELECT '1'::text AS value, 'exported' AS attr, "user".rev AS attr_key, "user".ikey AS okey
943                FROM "user"
944                WHERE "user".exported = true
945            UNION ALL
946                SELECT address_attributes_site.value, 'allsite' AS attr, "user".rev AS attr_key, "user".ikey AS okey
947                FROM "user"
948                JOIN address ON address."user" = "user".name
949                JOIN address_attributes_site ON address_attributes_site.okey = address.ikey
950                WHERE address_attributes_site.attr = 'site'::text AND address.exported = true
951            UNION ALL
952                SELECT "group".name AS value, 'memberOf' AS attr, "user".rev AS attr_key, "user".ikey AS okey
953                FROM "user"
954                JOIN group_attributes ON group_attributes.value = "user".name
955                JOIN "group" ON group_attributes.okey = "group".ikey
956                WHERE group_attributes.attr = 'memberUID'::text
957            UNION ALL
958                SELECT user_attributes.value, user_attributes.attr, user_attributes.attr_key, user_attributes.okey
959                FROM user_attributes_base user_attributes
960            UNION ALL
961                SELECT "group".name AS value, 'departments' AS attr, "user".rev AS attr_key, "user".ikey AS okey
962                FROM "group"
963                JOIN group_attributes_sutypes ON "group".ikey = group_attributes_sutypes.okey
964                JOIN group_attributes_users ON "group".ikey = group_attributes_users.okey AND group_attributes_users.attr = 'memberUID'::text
965                JOIN "user" ON "user".name = group_attributes_users.value
966                WHERE group_attributes_sutypes.value = 'dpmt'::text AND group_attributes_sutypes.attr = 'sutype'::text
967            UNION ALL
968                SELECT "group".name AS value, 'cells' AS attr, "user".rev AS attr_key, "user".ikey AS okey
969                FROM "group"
970                JOIN group_attributes_sutypes ON "group".ikey = group_attributes_sutypes.okey
971                JOIN group_attributes_users ON "group".ikey = group_attributes_users.okey AND group_attributes_users.attr = 'memberUID'::text
972                JOIN "user" ON "user".name = group_attributes_users.value
973                WHERE group_attributes_sutypes.value = 'cell'::text AND group_attributes_sutypes.attr = 'sutype'::text
974            UNION ALL
975                SELECT "group".name AS value, 'managedObjects' AS attr, "user".rev AS attr_key, "user".ikey AS okey
976                FROM "user"
977                JOIN group_attributes ON group_attributes.value = "user".name
978                JOIN "group" ON group_attributes.okey = "group".ikey
979                WHERE group_attributes.attr = 'managedBy'::text
980            UNION ALL
981                SELECT justify_interval(now() - "user".expire)::text AS value, 'expired' AS attr, "user".rev AS attr_key, "user".ikey AS okey
982                FROM "user"
983                WHERE "user".expire <= now()
984            UNION ALL
985                SELECT 1::text AS value, 'active' AS attr, "user".rev AS attr_key, "user".ikey AS okey
986                FROM "user"
987                WHERE ("user".expire IS NULL OR "user".expire >= now()) AND "user".exported = true
988            UNION ALL
989                SELECT 0::text AS value, 'active' AS attr, "user".rev AS attr_key, "user".ikey AS okey
990                FROM "user"
991                WHERE "user".expire IS NOT NULL AND "user".expire <= now() OR "user".exported = false
992            UNION ALL
993                SELECT CASE WHEN "user".exported = false THEN 'unexported'
994                WHEN "user".expire IS NOT NULL AND "user".expire <= now() THEN 'expired'
995                ELSE 'active' END AS value, 'status' AS attr, "user".rev AS attr_key, "user".ikey AS okey
996                FROM "user"
997            ;
998
999            }
1000        ],
1001    },
1002    {
1003        ver => 21,
1004        sql => [
1005            'ALTER TABLE objects ADD COLUMN oalias text',
1006            'ALTER TABLE objects
1007               ADD COLUMN nodelete boolean NOT NULL DEFAULT false',
1008            'ALTER TABLE objects
1009               ADD COLUMN internobject boolean NOT NULL DEFAULT false',
1010        ],
1011    },
1012    {
1013        ver => 22,
1014        sql => [
1015            'CREATE INDEX fki_employment
1016            ON employment_attributes
1017            USING btree (okey);'
1018        ],
1019    },
1020    {
1021        ver => 23,
1022        sql => [
1023            'ALTER TABLE address ADD COLUMN expire timestamp with time zone'
1024        ],
1025    },
1026    {
1027        ver => 24,
1028        sql => [
1029            q{
1030            CREATE OR REPLACE FUNCTION user_sort_fields()
1031            RETURNS trigger AS
1032            $BODY$DECLARE
1033            rec RECORD;
1034            BEGIN
1035
1036            IF (TG_OP='UPDATE' or TG_OP='INSERT') THEN
1037
1038            IF (new.attr='locked') THEN
1039            IF (TG_OP = 'INSERT') THEN
1040            new.value = now()::text;
1041            ELSIF (TG_OP='UPDATE') THEN
1042            new.value = old.value;
1043            END IF;
1044            END IF;
1045
1046            IF (new.attr='nickname') THEN
1047            PERFORM 1 from "user" where "user".ikey = new.okey
1048                and new.value = "user".name;
1049            IF NOT FOUND THEN
1050            select aliases.name into rec from aliases join "user"
1051            on array["user".name] = aliases.forward
1052            where "user".ikey = new.okey and aliases.name = new.value;
1053            IF NOT FOUND THEN
1054            insert into aliases ("name", "forward", "description", exported)
1055            select new.value, array["user".name], 'Forward for ' || "user".name || ' nickname', "user".exported from "user" where "user".ikey = new.okey;
1056            END IF;
1057            END IF;
1058            END IF;
1059
1060            IF (new.attr='uidNumber') THEN
1061            update "user" set uidnumber = new.value::integer where ikey = new.okey;
1062            RETURN NULL;
1063            END IF;
1064
1065            IF (new.attr='gidNumber') THEN
1066            update "user" set gidnumber = new.value::integer where ikey = new.okey;
1067            RETURN null;
1068            END IF;
1069
1070            IF (new.attr='expire') THEN
1071            update "user" set expire = new.value::timestamp where ikey = new.okey;
1072            RETURN NULL;
1073            END IF;
1074
1075            IF (new.attr='exported') THEN
1076            update "user" set exported = true where ikey = new.okey;
1077            RETURN NULL;
1078            END IF;
1079
1080            END IF;
1081
1082            IF (TG_OP = 'DELETE') THEN
1083
1084            IF (old.attr='expire') THEN
1085            update "user" set expire = NULL where ikey = old.okey;
1086            RETURN NULL;
1087            END IF;
1088
1089            IF (old.attr='exported') THEN
1090            update "user" set exported = false where ikey = old.okey;
1091            RETURN NULL;
1092            END IF;
1093
1094            END IF;
1095
1096
1097            IF (TG_OP='INSERT') THEN
1098            IF (new.attr='manager') THEN
1099            insert into user_attributes_users VALUES (new.*);
1100            RETURN NULL;
1101            END IF;
1102
1103            IF (new.attr='site') THEN
1104            insert into user_attributes_site VALUES (new.*);
1105            RETURN NULL;
1106            END IF;
1107
1108            IF (new.attr='department') THEN
1109            insert into user_attributes_groups VALUES (new.*);
1110            RETURN NULL;
1111            END IF;
1112
1113            IF (new.attr='contratType') THEN
1114            insert into user_attributes_groups VALUES (new.*);
1115            RETURN NULL;
1116            END IF;
1117
1118            IF (new.attr='jobType') THEN
1119            insert into user_attributes_groups VALUES (new.*);
1120            RETURN NULL;
1121            END IF;
1122
1123            END IF;
1124
1125            IF (TG_OP='DELETE') then
1126            RETURN old;
1127            ELSE
1128            RETURN new;
1129            end if;
1130            END;$BODY$
1131            LANGUAGE plpgsql VOLATILE
1132            COST 100;
1133            },
1134        ],
1135    },
1136    {
1137        ver => 25,
1138        sql => [
1139            'ALTER TABLE objects ADD COLUMN oaliascache text',
1140        ],
1141    },
1142);
1143
1144my @objects = (
1145    {
1146        name => 'dpmt',
1147        otype => 'sutype',
1148        attrs => {
1149            description => 'Department',
1150        },
1151    },
1152    {
1153        name => 'contrattype',
1154        otype => 'sutype',
1155        attrs => {
1156            description => 'Contract',
1157        },
1158    },
1159    {
1160        name => '-useralias',
1161        otype => 'group',
1162        attrs => {
1163            description => 'Internal group for user alias object',
1164            gidnumber => -1,
1165            unexported => 1,
1166        },
1167        intern => 1,
1168    },
1169);
1170
1171$dbi->rollback;
1172
1173foreach my $maj (@updates) {
1174    if ($rev >= $maj->{ver}) {
1175        next;
1176    }
1177    print "\n";
1178    print 'Switching to schema revision: ' . $maj->{ver} . "\n";
1179    foreach my $sql (@{ $maj->{sql} }) {
1180        {
1181            my $sqlv = $sql;
1182            $sqlv =~ s/^/  /mg;
1183            if ($verbose) {
1184                warn '  >' . $sqlv . "\n";
1185            } else {
1186                print 'x';
1187            }
1188        }
1189        my $err = $dbi->do($sql);
1190        defined($err) or die "Erreur :\\" . $dbi->errstr . "\n";
1191    }
1192
1193    print "\n";
1194
1195    print 'Updating schema_version to ' . $maj->{ver} . "\n";
1196
1197    $dbi->do(
1198        'UPDATE settings SET val = ? where varname = ?',
1199        undef,
1200        $maj->{ver}, 'schema_version'
1201    );
1202    print "Done\n\n";
1203
1204}
1205
1206my $setnodel  = $dbi->prepare('UPDATE objects SET nodelete     = true where name = ?');
1207my $setintern = $dbi->prepare('UPDATE objects SET internobject = true where name = ?');
1208
1209foreach (@objects) {
1210    if (!$labase->GetRawObject($_->{otype}, $_->{name})) {
1211        printf("Creating object %s/%s\n", $_->{otype}, $_->{name});
1212        $labase->create_object($_->{otype}, $_->{name}, %{$_->{attrs} || {}})
1213            or die sprintf("cannot create %s/%s\n", $_->{otype}, $_->{name});
1214
1215    }
1216
1217    $setnodel->execute($_->{name});
1218    $setintern->execute($_->{name}) if ($_->{intern});
1219}
1220
1221if ($nocommit) {
1222    $dbi->rollback;
1223} else {
1224    $dbi->commit;
1225}
1226print "Process terminated successfully\n";
Note: See TracBrowser for help on using the repository browser.