]> granicus.if.org Git - postgresql/blob - src/test/regress/expected/plpgsql.out
Quick-and-dirty fix for recursive plpgsql functions, per bug report from
[postgresql] / src / test / regress / expected / plpgsql.out
1 --
2 -- PLPGSQL
3 --
4 create table Room (
5     roomno      char(8),
6     comment     text
7 );
8 create unique index Room_rno on Room using btree (roomno bpchar_ops);
9 create table WSlot (
10     slotname    char(20),
11     roomno      char(8),
12     slotlink    char(20),
13     backlink    char(20)
14 );
15 create unique index WSlot_name on WSlot using btree (slotname bpchar_ops);
16 create table PField (
17     name        text,
18     comment     text
19 );
20 create unique index PField_name on PField using btree (name text_ops);
21 create table PSlot (
22     slotname    char(20),
23     pfname      text,
24     slotlink    char(20),
25     backlink    char(20)
26 );
27 create unique index PSlot_name on PSlot using btree (slotname bpchar_ops);
28 create table PLine (
29     slotname    char(20),
30     phonenumber char(20),
31     comment     text,
32     backlink    char(20)
33 );
34 create unique index PLine_name on PLine using btree (slotname bpchar_ops);
35 create table Hub (
36     name        char(14),
37     comment     text,
38     nslots      integer
39 );
40 create unique index Hub_name on Hub using btree (name bpchar_ops);
41 create table HSlot (
42     slotname    char(20),
43     hubname     char(14),
44     slotno      integer,
45     slotlink    char(20)
46 );
47 create unique index HSlot_name on HSlot using btree (slotname bpchar_ops);
48 create index HSlot_hubname on HSlot using btree (hubname bpchar_ops);
49 create table System (
50     name        text,
51     comment     text
52 );
53 create unique index System_name on System using btree (name text_ops);
54 create table IFace (
55     slotname    char(20),
56     sysname     text,
57     ifname      text,
58     slotlink    char(20)
59 );
60 create unique index IFace_name on IFace using btree (slotname bpchar_ops);
61 create table PHone (
62     slotname    char(20),
63     comment     text,
64     slotlink    char(20)
65 );
66 create unique index PHone_name on PHone using btree (slotname bpchar_ops);
67 -- ************************************************************
68 -- * 
69 -- * Trigger procedures and functions for the patchfield
70 -- * test of PL/pgSQL
71 -- * 
72 -- ************************************************************
73 -- ************************************************************
74 -- * AFTER UPDATE on Room
75 -- *    - If room no changes let wall slots follow
76 -- ************************************************************
77 create function tg_room_au() returns opaque as '
78 begin
79     if new.roomno != old.roomno then
80         update WSlot set roomno = new.roomno where roomno = old.roomno;
81     end if;
82     return new;
83 end;
84 ' language 'plpgsql';
85 create trigger tg_room_au after update
86     on Room for each row execute procedure tg_room_au();
87 -- ************************************************************
88 -- * AFTER DELETE on Room
89 -- *    - delete wall slots in this room
90 -- ************************************************************
91 create function tg_room_ad() returns opaque as '
92 begin
93     delete from WSlot where roomno = old.roomno;
94     return old;
95 end;
96 ' language 'plpgsql';
97 create trigger tg_room_ad after delete
98     on Room for each row execute procedure tg_room_ad();
99 -- ************************************************************
100 -- * BEFORE INSERT or UPDATE on WSlot
101 -- *    - Check that room exists
102 -- ************************************************************
103 create function tg_wslot_biu() returns opaque as '
104 begin
105     if count(*) = 0 from Room where roomno = new.roomno then
106         raise exception ''Room % does not exist'', new.roomno;
107     end if;
108     return new;
109 end;
110 ' language 'plpgsql';
111 create trigger tg_wslot_biu before insert or update
112     on WSlot for each row execute procedure tg_wslot_biu();
113 -- ************************************************************
114 -- * AFTER UPDATE on PField
115 -- *    - Let PSlots of this field follow
116 -- ************************************************************
117 create function tg_pfield_au() returns opaque as '
118 begin
119     if new.name != old.name then
120         update PSlot set pfname = new.name where pfname = old.name;
121     end if;
122     return new;
123 end;
124 ' language 'plpgsql';
125 create trigger tg_pfield_au after update
126     on PField for each row execute procedure tg_pfield_au();
127 -- ************************************************************
128 -- * AFTER DELETE on PField
129 -- *    - Remove all slots of this patchfield
130 -- ************************************************************
131 create function tg_pfield_ad() returns opaque as '
132 begin
133     delete from PSlot where pfname = old.name;
134     return old;
135 end;
136 ' language 'plpgsql';
137 create trigger tg_pfield_ad after delete
138     on PField for each row execute procedure tg_pfield_ad();
139 -- ************************************************************
140 -- * BEFORE INSERT or UPDATE on PSlot
141 -- *    - Ensure that our patchfield does exist
142 -- ************************************************************
143 create function tg_pslot_biu() returns opaque as '
144 declare
145     pfrec       record;
146     rename new to ps;
147 begin
148     select into pfrec * from PField where name = ps.pfname;
149     if not found then
150         raise exception ''Patchfield "%" does not exist'', ps.pfname;
151     end if;
152     return ps;
153 end;
154 ' language 'plpgsql';
155 create trigger tg_pslot_biu before insert or update
156     on PSlot for each row execute procedure tg_pslot_biu();
157 -- ************************************************************
158 -- * AFTER UPDATE on System
159 -- *    - If system name changes let interfaces follow
160 -- ************************************************************
161 create function tg_system_au() returns opaque as '
162 begin
163     if new.name != old.name then
164         update IFace set sysname = new.name where sysname = old.name;
165     end if;
166     return new;
167 end;
168 ' language 'plpgsql';
169 create trigger tg_system_au after update
170     on System for each row execute procedure tg_system_au();
171 -- ************************************************************
172 -- * BEFORE INSERT or UPDATE on IFace
173 -- *    - set the slotname to IF.sysname.ifname
174 -- ************************************************************
175 create function tg_iface_biu() returns opaque as '
176 declare
177     sname       text;
178     sysrec      record;
179 begin
180     select into sysrec * from system where name = new.sysname;
181     if not found then
182         raise exception ''system "%" does not exist'', new.sysname;
183     end if;
184     sname := ''IF.'' || new.sysname;
185     sname := sname || ''.'';
186     sname := sname || new.ifname;
187     if length(sname) > 20 then
188         raise exception ''IFace slotname "%" too long (20 char max)'', sname;
189     end if;
190     new.slotname := sname;
191     return new;
192 end;
193 ' language 'plpgsql';
194 create trigger tg_iface_biu before insert or update
195     on IFace for each row execute procedure tg_iface_biu();
196 -- ************************************************************
197 -- * AFTER INSERT or UPDATE or DELETE on Hub
198 -- *    - insert/delete/rename slots as required
199 -- ************************************************************
200 create function tg_hub_a() returns opaque as '
201 declare
202     hname       text;
203     dummy       integer;
204 begin
205     if tg_op = ''INSERT'' then
206         dummy := tg_hub_adjustslots(new.name, 0, new.nslots);
207         return new;
208     end if;
209     if tg_op = ''UPDATE'' then
210         if new.name != old.name then
211             update HSlot set hubname = new.name where hubname = old.name;
212         end if;
213         dummy := tg_hub_adjustslots(new.name, old.nslots, new.nslots);
214         return new;
215     end if;
216     if tg_op = ''DELETE'' then
217         dummy := tg_hub_adjustslots(old.name, old.nslots, 0);
218         return old;
219     end if;
220 end;
221 ' language 'plpgsql';
222 create trigger tg_hub_a after insert or update or delete
223     on Hub for each row execute procedure tg_hub_a();
224 -- ************************************************************
225 -- * Support function to add/remove slots of Hub
226 -- ************************************************************
227 create function tg_hub_adjustslots(bpchar, integer, integer)
228 returns integer as '
229 declare
230     hname       alias for $1;
231     oldnslots   alias for $2;
232     newnslots   alias for $3;
233 begin
234     if newnslots = oldnslots then
235         return 0;
236     end if;
237     if newnslots < oldnslots then
238         delete from HSlot where hubname = hname and slotno > newnslots;
239         return 0;
240     end if;
241     for i in oldnslots + 1 .. newnslots loop
242         insert into HSlot (slotname, hubname, slotno, slotlink)
243                 values (''HS.dummy'', hname, i, '''');
244     end loop;
245     return 0;
246 end;
247 ' language 'plpgsql';
248 -- ************************************************************
249 -- * BEFORE INSERT or UPDATE on HSlot
250 -- *    - prevent from manual manipulation
251 -- *    - set the slotname to HS.hubname.slotno
252 -- ************************************************************
253 create function tg_hslot_biu() returns opaque as '
254 declare
255     sname       text;
256     xname       HSlot.slotname%TYPE;
257     hubrec      record;
258 begin
259     select into hubrec * from Hub where name = new.hubname;
260     if not found then
261         raise exception ''no manual manipulation of HSlot'';
262     end if;
263     if new.slotno < 1 or new.slotno > hubrec.nslots then
264         raise exception ''no manual manipulation of HSlot'';
265     end if;
266     if tg_op = ''UPDATE'' then
267         if new.hubname != old.hubname then
268             if count(*) > 0 from Hub where name = old.hubname then
269                 raise exception ''no manual manipulation of HSlot'';
270             end if;
271         end if;
272     end if;
273     sname := ''HS.'' || trim(new.hubname);
274     sname := sname || ''.'';
275     sname := sname || new.slotno::text;
276     if length(sname) > 20 then
277         raise exception ''HSlot slotname "%" too long (20 char max)'', sname;
278     end if;
279     new.slotname := sname;
280     return new;
281 end;
282 ' language 'plpgsql';
283 create trigger tg_hslot_biu before insert or update
284     on HSlot for each row execute procedure tg_hslot_biu();
285 -- ************************************************************
286 -- * BEFORE DELETE on HSlot
287 -- *    - prevent from manual manipulation
288 -- ************************************************************
289 create function tg_hslot_bd() returns opaque as '
290 declare
291     hubrec      record;
292 begin
293     select into hubrec * from Hub where name = old.hubname;
294     if not found then
295         return old;
296     end if;
297     if old.slotno > hubrec.nslots then
298         return old;
299     end if;
300     raise exception ''no manual manipulation of HSlot'';
301 end;
302 ' language 'plpgsql';
303 create trigger tg_hslot_bd before delete
304     on HSlot for each row execute procedure tg_hslot_bd();
305 -- ************************************************************
306 -- * BEFORE INSERT on all slots
307 -- *    - Check name prefix
308 -- ************************************************************
309 create function tg_chkslotname() returns opaque as '
310 begin
311     if substr(new.slotname, 1, 2) != tg_argv[0] then
312         raise exception ''slotname must begin with %'', tg_argv[0];
313     end if;
314     return new;
315 end;
316 ' language 'plpgsql';
317 create trigger tg_chkslotname before insert
318     on PSlot for each row execute procedure tg_chkslotname('PS');
319 create trigger tg_chkslotname before insert
320     on WSlot for each row execute procedure tg_chkslotname('WS');
321 create trigger tg_chkslotname before insert
322     on PLine for each row execute procedure tg_chkslotname('PL');
323 create trigger tg_chkslotname before insert
324     on IFace for each row execute procedure tg_chkslotname('IF');
325 create trigger tg_chkslotname before insert
326     on PHone for each row execute procedure tg_chkslotname('PH');
327 -- ************************************************************
328 -- * BEFORE INSERT or UPDATE on all slots with slotlink
329 -- *    - Set slotlink to empty string if NULL value given
330 -- ************************************************************
331 create function tg_chkslotlink() returns opaque as '
332 begin
333     if new.slotlink isnull then
334         new.slotlink := '''';
335     end if;
336     return new;
337 end;
338 ' language 'plpgsql';
339 create trigger tg_chkslotlink before insert or update
340     on PSlot for each row execute procedure tg_chkslotlink();
341 create trigger tg_chkslotlink before insert or update
342     on WSlot for each row execute procedure tg_chkslotlink();
343 create trigger tg_chkslotlink before insert or update
344     on IFace for each row execute procedure tg_chkslotlink();
345 create trigger tg_chkslotlink before insert or update
346     on HSlot for each row execute procedure tg_chkslotlink();
347 create trigger tg_chkslotlink before insert or update
348     on PHone for each row execute procedure tg_chkslotlink();
349 -- ************************************************************
350 -- * BEFORE INSERT or UPDATE on all slots with backlink
351 -- *    - Set backlink to empty string if NULL value given
352 -- ************************************************************
353 create function tg_chkbacklink() returns opaque as '
354 begin
355     if new.backlink isnull then
356         new.backlink := '''';
357     end if;
358     return new;
359 end;
360 ' language 'plpgsql';
361 create trigger tg_chkbacklink before insert or update
362     on PSlot for each row execute procedure tg_chkbacklink();
363 create trigger tg_chkbacklink before insert or update
364     on WSlot for each row execute procedure tg_chkbacklink();
365 create trigger tg_chkbacklink before insert or update
366     on PLine for each row execute procedure tg_chkbacklink();
367 -- ************************************************************
368 -- * BEFORE UPDATE on PSlot
369 -- *    - do delete/insert instead of update if name changes
370 -- ************************************************************
371 create function tg_pslot_bu() returns opaque as '
372 begin
373     if new.slotname != old.slotname then
374         delete from PSlot where slotname = old.slotname;
375         insert into PSlot (
376                     slotname,
377                     pfname,
378                     slotlink,
379                     backlink
380                 ) values (
381                     new.slotname,
382                     new.pfname,
383                     new.slotlink,
384                     new.backlink
385                 );
386         return null;
387     end if;
388     return new;
389 end;
390 ' language 'plpgsql';
391 create trigger tg_pslot_bu before update
392     on PSlot for each row execute procedure tg_pslot_bu();
393 -- ************************************************************
394 -- * BEFORE UPDATE on WSlot
395 -- *    - do delete/insert instead of update if name changes
396 -- ************************************************************
397 create function tg_wslot_bu() returns opaque as '
398 begin
399     if new.slotname != old.slotname then
400         delete from WSlot where slotname = old.slotname;
401         insert into WSlot (
402                     slotname,
403                     roomno,
404                     slotlink,
405                     backlink
406                 ) values (
407                     new.slotname,
408                     new.roomno,
409                     new.slotlink,
410                     new.backlink
411                 );
412         return null;
413     end if;
414     return new;
415 end;
416 ' language 'plpgsql';
417 create trigger tg_wslot_bu before update
418     on WSlot for each row execute procedure tg_Wslot_bu();
419 -- ************************************************************
420 -- * BEFORE UPDATE on PLine
421 -- *    - do delete/insert instead of update if name changes
422 -- ************************************************************
423 create function tg_pline_bu() returns opaque as '
424 begin
425     if new.slotname != old.slotname then
426         delete from PLine where slotname = old.slotname;
427         insert into PLine (
428                     slotname,
429                     phonenumber,
430                     comment,
431                     backlink
432                 ) values (
433                     new.slotname,
434                     new.phonenumber,
435                     new.comment,
436                     new.backlink
437                 );
438         return null;
439     end if;
440     return new;
441 end;
442 ' language 'plpgsql';
443 create trigger tg_pline_bu before update
444     on PLine for each row execute procedure tg_pline_bu();
445 -- ************************************************************
446 -- * BEFORE UPDATE on IFace
447 -- *    - do delete/insert instead of update if name changes
448 -- ************************************************************
449 create function tg_iface_bu() returns opaque as '
450 begin
451     if new.slotname != old.slotname then
452         delete from IFace where slotname = old.slotname;
453         insert into IFace (
454                     slotname,
455                     sysname,
456                     ifname,
457                     slotlink
458                 ) values (
459                     new.slotname,
460                     new.sysname,
461                     new.ifname,
462                     new.slotlink
463                 );
464         return null;
465     end if;
466     return new;
467 end;
468 ' language 'plpgsql';
469 create trigger tg_iface_bu before update
470     on IFace for each row execute procedure tg_iface_bu();
471 -- ************************************************************
472 -- * BEFORE UPDATE on HSlot
473 -- *    - do delete/insert instead of update if name changes
474 -- ************************************************************
475 create function tg_hslot_bu() returns opaque as '
476 begin
477     if new.slotname != old.slotname or new.hubname != old.hubname then
478         delete from HSlot where slotname = old.slotname;
479         insert into HSlot (
480                     slotname,
481                     hubname,
482                     slotno,
483                     slotlink
484                 ) values (
485                     new.slotname,
486                     new.hubname,
487                     new.slotno,
488                     new.slotlink
489                 );
490         return null;
491     end if;
492     return new;
493 end;
494 ' language 'plpgsql';
495 create trigger tg_hslot_bu before update
496     on HSlot for each row execute procedure tg_hslot_bu();
497 -- ************************************************************
498 -- * BEFORE UPDATE on PHone
499 -- *    - do delete/insert instead of update if name changes
500 -- ************************************************************
501 create function tg_phone_bu() returns opaque as '
502 begin
503     if new.slotname != old.slotname then
504         delete from PHone where slotname = old.slotname;
505         insert into PHone (
506                     slotname,
507                     comment,
508                     slotlink
509                 ) values (
510                     new.slotname,
511                     new.comment,
512                     new.slotlink
513                 );
514         return null;
515     end if;
516     return new;
517 end;
518 ' language 'plpgsql';
519 create trigger tg_phone_bu before update
520     on PHone for each row execute procedure tg_phone_bu();
521 -- ************************************************************
522 -- * AFTER INSERT or UPDATE or DELETE on slot with backlink
523 -- *    - Ensure that the opponent correctly points back to us
524 -- ************************************************************
525 create function tg_backlink_a() returns opaque as '
526 declare
527     dummy       integer;
528 begin
529     if tg_op = ''INSERT'' then
530         if new.backlink != '''' then
531             dummy := tg_backlink_set(new.backlink, new.slotname);
532         end if;
533         return new;
534     end if;
535     if tg_op = ''UPDATE'' then
536         if new.backlink != old.backlink then
537             if old.backlink != '''' then
538                 dummy := tg_backlink_unset(old.backlink, old.slotname);
539             end if;
540             if new.backlink != '''' then
541                 dummy := tg_backlink_set(new.backlink, new.slotname);
542             end if;
543         else
544             if new.slotname != old.slotname and new.backlink != '''' then
545                 dummy := tg_slotlink_set(new.backlink, new.slotname);
546             end if;
547         end if;
548         return new;
549     end if;
550     if tg_op = ''DELETE'' then
551         if old.backlink != '''' then
552             dummy := tg_backlink_unset(old.backlink, old.slotname);
553         end if;
554         return old;
555     end if;
556 end;
557 ' language 'plpgsql';
558 create trigger tg_backlink_a after insert or update or delete
559     on PSlot for each row execute procedure tg_backlink_a('PS');
560 create trigger tg_backlink_a after insert or update or delete
561     on WSlot for each row execute procedure tg_backlink_a('WS');
562 create trigger tg_backlink_a after insert or update or delete
563     on PLine for each row execute procedure tg_backlink_a('PL');
564 -- ************************************************************
565 -- * Support function to set the opponents backlink field
566 -- * if it does not already point to the requested slot
567 -- ************************************************************
568 create function tg_backlink_set(bpchar, bpchar)
569 returns integer as '
570 declare
571     myname      alias for $1;
572     blname      alias for $2;
573     mytype      char(2);
574     link        char(4);
575     rec         record;
576 begin
577     mytype := substr(myname, 1, 2);
578     link := mytype || substr(blname, 1, 2);
579     if link = ''PLPL'' then
580         raise exception 
581                 ''backlink between two phone lines does not make sense'';
582     end if;
583     if link in (''PLWS'', ''WSPL'') then
584         raise exception 
585                 ''direct link of phone line to wall slot not permitted'';
586     end if;
587     if mytype = ''PS'' then
588         select into rec * from PSlot where slotname = myname;
589         if not found then
590             raise exception ''% does not exist'', myname;
591         end if;
592         if rec.backlink != blname then
593             update PSlot set backlink = blname where slotname = myname;
594         end if;
595         return 0;
596     end if;
597     if mytype = ''WS'' then
598         select into rec * from WSlot where slotname = myname;
599         if not found then
600             raise exception ''% does not exist'', myname;
601         end if;
602         if rec.backlink != blname then
603             update WSlot set backlink = blname where slotname = myname;
604         end if;
605         return 0;
606     end if;
607     if mytype = ''PL'' then
608         select into rec * from PLine where slotname = myname;
609         if not found then
610             raise exception ''% does not exist'', myname;
611         end if;
612         if rec.backlink != blname then
613             update PLine set backlink = blname where slotname = myname;
614         end if;
615         return 0;
616     end if;
617     raise exception ''illegal backlink beginning with %'', mytype;
618 end;
619 ' language 'plpgsql';
620 -- ************************************************************
621 -- * Support function to clear out the backlink field if
622 -- * it still points to specific slot
623 -- ************************************************************
624 create function tg_backlink_unset(bpchar, bpchar)
625 returns integer as '
626 declare
627     myname      alias for $1;
628     blname      alias for $2;
629     mytype      char(2);
630     rec         record;
631 begin
632     mytype := substr(myname, 1, 2);
633     if mytype = ''PS'' then
634         select into rec * from PSlot where slotname = myname;
635         if not found then
636             return 0;
637         end if;
638         if rec.backlink = blname then
639             update PSlot set backlink = '''' where slotname = myname;
640         end if;
641         return 0;
642     end if;
643     if mytype = ''WS'' then
644         select into rec * from WSlot where slotname = myname;
645         if not found then
646             return 0;
647         end if;
648         if rec.backlink = blname then
649             update WSlot set backlink = '''' where slotname = myname;
650         end if;
651         return 0;
652     end if;
653     if mytype = ''PL'' then
654         select into rec * from PLine where slotname = myname;
655         if not found then
656             return 0;
657         end if;
658         if rec.backlink = blname then
659             update PLine set backlink = '''' where slotname = myname;
660         end if;
661         return 0;
662     end if;
663 end;
664 ' language 'plpgsql';
665 -- ************************************************************
666 -- * AFTER INSERT or UPDATE or DELETE on slot with slotlink
667 -- *    - Ensure that the opponent correctly points back to us
668 -- ************************************************************
669 create function tg_slotlink_a() returns opaque as '
670 declare
671     dummy       integer;
672 begin
673     if tg_op = ''INSERT'' then
674         if new.slotlink != '''' then
675             dummy := tg_slotlink_set(new.slotlink, new.slotname);
676         end if;
677         return new;
678     end if;
679     if tg_op = ''UPDATE'' then
680         if new.slotlink != old.slotlink then
681             if old.slotlink != '''' then
682                 dummy := tg_slotlink_unset(old.slotlink, old.slotname);
683             end if;
684             if new.slotlink != '''' then
685                 dummy := tg_slotlink_set(new.slotlink, new.slotname);
686             end if;
687         else
688             if new.slotname != old.slotname and new.slotlink != '''' then
689                 dummy := tg_slotlink_set(new.slotlink, new.slotname);
690             end if;
691         end if;
692         return new;
693     end if;
694     if tg_op = ''DELETE'' then
695         if old.slotlink != '''' then
696             dummy := tg_slotlink_unset(old.slotlink, old.slotname);
697         end if;
698         return old;
699     end if;
700 end;
701 ' language 'plpgsql';
702 create trigger tg_slotlink_a after insert or update or delete
703     on PSlot for each row execute procedure tg_slotlink_a('PS');
704 create trigger tg_slotlink_a after insert or update or delete
705     on WSlot for each row execute procedure tg_slotlink_a('WS');
706 create trigger tg_slotlink_a after insert or update or delete
707     on IFace for each row execute procedure tg_slotlink_a('IF');
708 create trigger tg_slotlink_a after insert or update or delete
709     on HSlot for each row execute procedure tg_slotlink_a('HS');
710 create trigger tg_slotlink_a after insert or update or delete
711     on PHone for each row execute procedure tg_slotlink_a('PH');
712 -- ************************************************************
713 -- * Support function to set the opponents slotlink field
714 -- * if it does not already point to the requested slot
715 -- ************************************************************
716 create function tg_slotlink_set(bpchar, bpchar)
717 returns integer as '
718 declare
719     myname      alias for $1;
720     blname      alias for $2;
721     mytype      char(2);
722     link        char(4);
723     rec         record;
724 begin
725     mytype := substr(myname, 1, 2);
726     link := mytype || substr(blname, 1, 2);
727     if link = ''PHPH'' then
728         raise exception 
729                 ''slotlink between two phones does not make sense'';
730     end if;
731     if link in (''PHHS'', ''HSPH'') then
732         raise exception 
733                 ''link of phone to hub does not make sense'';
734     end if;
735     if link in (''PHIF'', ''IFPH'') then
736         raise exception 
737                 ''link of phone to hub does not make sense'';
738     end if;
739     if link in (''PSWS'', ''WSPS'') then
740         raise exception 
741                 ''slotlink from patchslot to wallslot not permitted'';
742     end if;
743     if mytype = ''PS'' then
744         select into rec * from PSlot where slotname = myname;
745         if not found then
746             raise exception ''% does not exist'', myname;
747         end if;
748         if rec.slotlink != blname then
749             update PSlot set slotlink = blname where slotname = myname;
750         end if;
751         return 0;
752     end if;
753     if mytype = ''WS'' then
754         select into rec * from WSlot where slotname = myname;
755         if not found then
756             raise exception ''% does not exist'', myname;
757         end if;
758         if rec.slotlink != blname then
759             update WSlot set slotlink = blname where slotname = myname;
760         end if;
761         return 0;
762     end if;
763     if mytype = ''IF'' then
764         select into rec * from IFace where slotname = myname;
765         if not found then
766             raise exception ''% does not exist'', myname;
767         end if;
768         if rec.slotlink != blname then
769             update IFace set slotlink = blname where slotname = myname;
770         end if;
771         return 0;
772     end if;
773     if mytype = ''HS'' then
774         select into rec * from HSlot where slotname = myname;
775         if not found then
776             raise exception ''% does not exist'', myname;
777         end if;
778         if rec.slotlink != blname then
779             update HSlot set slotlink = blname where slotname = myname;
780         end if;
781         return 0;
782     end if;
783     if mytype = ''PH'' then
784         select into rec * from PHone where slotname = myname;
785         if not found then
786             raise exception ''% does not exist'', myname;
787         end if;
788         if rec.slotlink != blname then
789             update PHone set slotlink = blname where slotname = myname;
790         end if;
791         return 0;
792     end if;
793     raise exception ''illegal slotlink beginning with %'', mytype;
794 end;
795 ' language 'plpgsql';
796 -- ************************************************************
797 -- * Support function to clear out the slotlink field if
798 -- * it still points to specific slot
799 -- ************************************************************
800 create function tg_slotlink_unset(bpchar, bpchar)
801 returns integer as '
802 declare
803     myname      alias for $1;
804     blname      alias for $2;
805     mytype      char(2);
806     rec         record;
807 begin
808     mytype := substr(myname, 1, 2);
809     if mytype = ''PS'' then
810         select into rec * from PSlot where slotname = myname;
811         if not found then
812             return 0;
813         end if;
814         if rec.slotlink = blname then
815             update PSlot set slotlink = '''' where slotname = myname;
816         end if;
817         return 0;
818     end if;
819     if mytype = ''WS'' then
820         select into rec * from WSlot where slotname = myname;
821         if not found then
822             return 0;
823         end if;
824         if rec.slotlink = blname then
825             update WSlot set slotlink = '''' where slotname = myname;
826         end if;
827         return 0;
828     end if;
829     if mytype = ''IF'' then
830         select into rec * from IFace where slotname = myname;
831         if not found then
832             return 0;
833         end if;
834         if rec.slotlink = blname then
835             update IFace set slotlink = '''' where slotname = myname;
836         end if;
837         return 0;
838     end if;
839     if mytype = ''HS'' then
840         select into rec * from HSlot where slotname = myname;
841         if not found then
842             return 0;
843         end if;
844         if rec.slotlink = blname then
845             update HSlot set slotlink = '''' where slotname = myname;
846         end if;
847         return 0;
848     end if;
849     if mytype = ''PH'' then
850         select into rec * from PHone where slotname = myname;
851         if not found then
852             return 0;
853         end if;
854         if rec.slotlink = blname then
855             update PHone set slotlink = '''' where slotname = myname;
856         end if;
857         return 0;
858     end if;
859 end;
860 ' language 'plpgsql';
861 -- ************************************************************
862 -- * Describe the backside of a patchfield slot
863 -- ************************************************************
864 create function pslot_backlink_view(bpchar)
865 returns text as '
866 <<outer>>
867 declare
868     rec         record;
869     bltype      char(2);
870     retval      text;
871 begin
872     select into rec * from PSlot where slotname = $1;
873     if not found then
874         return '''';
875     end if;
876     if rec.backlink = '''' then
877         return ''-'';
878     end if;
879     bltype := substr(rec.backlink, 1, 2);
880     if bltype = ''PL'' then
881         declare
882             rec         record;
883         begin
884             select into rec * from PLine where slotname = outer.rec.backlink;
885             retval := ''Phone line '' || trim(rec.phonenumber);
886             if rec.comment != '''' then
887                 retval := retval || '' ('';
888                 retval := retval || rec.comment;
889                 retval := retval || '')'';
890             end if;
891             return retval;
892         end;
893     end if;
894     if bltype = ''WS'' then
895         select into rec * from WSlot where slotname = rec.backlink;
896         retval := trim(rec.slotname) || '' in room '';
897         retval := retval || trim(rec.roomno);
898         retval := retval || '' -> '';
899         return retval || wslot_slotlink_view(rec.slotname);
900     end if;
901     return rec.backlink;
902 end;
903 ' language 'plpgsql';
904 -- ************************************************************
905 -- * Describe the front of a patchfield slot
906 -- ************************************************************
907 create function pslot_slotlink_view(bpchar)
908 returns text as '
909 declare
910     psrec       record;
911     sltype      char(2);
912     retval      text;
913 begin
914     select into psrec * from PSlot where slotname = $1;
915     if not found then
916         return '''';
917     end if;
918     if psrec.slotlink = '''' then
919         return ''-'';
920     end if;
921     sltype := substr(psrec.slotlink, 1, 2);
922     if sltype = ''PS'' then
923         retval := trim(psrec.slotlink) || '' -> '';
924         return retval || pslot_backlink_view(psrec.slotlink);
925     end if;
926     if sltype = ''HS'' then
927         retval := comment from Hub H, HSlot HS
928                         where HS.slotname = psrec.slotlink
929                           and H.name = HS.hubname;
930         retval := retval || '' slot '';
931         retval := retval || slotno::text from HSlot
932                         where slotname = psrec.slotlink;
933         return retval;
934     end if;
935     return psrec.slotlink;
936 end;
937 ' language 'plpgsql';
938 -- ************************************************************
939 -- * Describe the front of a wall connector slot
940 -- ************************************************************
941 create function wslot_slotlink_view(bpchar)
942 returns text as '
943 declare
944     rec         record;
945     sltype      char(2);
946     retval      text;
947 begin
948     select into rec * from WSlot where slotname = $1;
949     if not found then
950         return '''';
951     end if;
952     if rec.slotlink = '''' then
953         return ''-'';
954     end if;
955     sltype := substr(rec.slotlink, 1, 2);
956     if sltype = ''PH'' then
957         select into rec * from PHone where slotname = rec.slotlink;
958         retval := ''Phone '' || trim(rec.slotname);
959         if rec.comment != '''' then
960             retval := retval || '' ('';
961             retval := retval || rec.comment;
962             retval := retval || '')'';
963         end if;
964         return retval;
965     end if;
966     if sltype = ''IF'' then
967         declare
968             syrow       System%RowType;
969             ifrow       IFace%ROWTYPE;
970         begin
971             select into ifrow * from IFace where slotname = rec.slotlink;
972             select into syrow * from System where name = ifrow.sysname;
973             retval := syrow.name || '' IF '';
974             retval := retval || ifrow.ifname;
975             if syrow.comment != '''' then
976                 retval := retval || '' ('';
977                 retval := retval || syrow.comment;
978                 retval := retval || '')'';
979             end if;
980             return retval;
981         end;
982     end if;
983     return rec.slotlink;
984 end;
985 ' language 'plpgsql';
986 -- ************************************************************
987 -- * View of a patchfield describing backside and patches
988 -- ************************************************************
989 create view Pfield_v1 as select PF.pfname, PF.slotname,
990         pslot_backlink_view(PF.slotname) as backside,
991         pslot_slotlink_view(PF.slotname) as patch
992     from PSlot PF;
993 --
994 -- First we build the house - so we create the rooms
995 --
996 insert into Room values ('001', 'Entrance');
997 insert into Room values ('002', 'Office');
998 insert into Room values ('003', 'Office');
999 insert into Room values ('004', 'Technical');
1000 insert into Room values ('101', 'Office');
1001 insert into Room values ('102', 'Conference');
1002 insert into Room values ('103', 'Restroom');
1003 insert into Room values ('104', 'Technical');
1004 insert into Room values ('105', 'Office');
1005 insert into Room values ('106', 'Office');
1006 --
1007 -- Second we install the wall connectors
1008 --
1009 insert into WSlot values ('WS.001.1a', '001', '', '');
1010 insert into WSlot values ('WS.001.1b', '001', '', '');
1011 insert into WSlot values ('WS.001.2a', '001', '', '');
1012 insert into WSlot values ('WS.001.2b', '001', '', '');
1013 insert into WSlot values ('WS.001.3a', '001', '', '');
1014 insert into WSlot values ('WS.001.3b', '001', '', '');
1015 insert into WSlot values ('WS.002.1a', '002', '', '');
1016 insert into WSlot values ('WS.002.1b', '002', '', '');
1017 insert into WSlot values ('WS.002.2a', '002', '', '');
1018 insert into WSlot values ('WS.002.2b', '002', '', '');
1019 insert into WSlot values ('WS.002.3a', '002', '', '');
1020 insert into WSlot values ('WS.002.3b', '002', '', '');
1021 insert into WSlot values ('WS.003.1a', '003', '', '');
1022 insert into WSlot values ('WS.003.1b', '003', '', '');
1023 insert into WSlot values ('WS.003.2a', '003', '', '');
1024 insert into WSlot values ('WS.003.2b', '003', '', '');
1025 insert into WSlot values ('WS.003.3a', '003', '', '');
1026 insert into WSlot values ('WS.003.3b', '003', '', '');
1027 insert into WSlot values ('WS.101.1a', '101', '', '');
1028 insert into WSlot values ('WS.101.1b', '101', '', '');
1029 insert into WSlot values ('WS.101.2a', '101', '', '');
1030 insert into WSlot values ('WS.101.2b', '101', '', '');
1031 insert into WSlot values ('WS.101.3a', '101', '', '');
1032 insert into WSlot values ('WS.101.3b', '101', '', '');
1033 insert into WSlot values ('WS.102.1a', '102', '', '');
1034 insert into WSlot values ('WS.102.1b', '102', '', '');
1035 insert into WSlot values ('WS.102.2a', '102', '', '');
1036 insert into WSlot values ('WS.102.2b', '102', '', '');
1037 insert into WSlot values ('WS.102.3a', '102', '', '');
1038 insert into WSlot values ('WS.102.3b', '102', '', '');
1039 insert into WSlot values ('WS.105.1a', '105', '', '');
1040 insert into WSlot values ('WS.105.1b', '105', '', '');
1041 insert into WSlot values ('WS.105.2a', '105', '', '');
1042 insert into WSlot values ('WS.105.2b', '105', '', '');
1043 insert into WSlot values ('WS.105.3a', '105', '', '');
1044 insert into WSlot values ('WS.105.3b', '105', '', '');
1045 insert into WSlot values ('WS.106.1a', '106', '', '');
1046 insert into WSlot values ('WS.106.1b', '106', '', '');
1047 insert into WSlot values ('WS.106.2a', '106', '', '');
1048 insert into WSlot values ('WS.106.2b', '106', '', '');
1049 insert into WSlot values ('WS.106.3a', '106', '', '');
1050 insert into WSlot values ('WS.106.3b', '106', '', '');
1051 --
1052 -- Now create the patch fields and their slots
1053 --
1054 insert into PField values ('PF0_1', 'Wallslots basement');
1055 --
1056 -- The cables for these will be made later, so they are unconnected for now
1057 --
1058 insert into PSlot values ('PS.base.a1', 'PF0_1', '', '');
1059 insert into PSlot values ('PS.base.a2', 'PF0_1', '', '');
1060 insert into PSlot values ('PS.base.a3', 'PF0_1', '', '');
1061 insert into PSlot values ('PS.base.a4', 'PF0_1', '', '');
1062 insert into PSlot values ('PS.base.a5', 'PF0_1', '', '');
1063 insert into PSlot values ('PS.base.a6', 'PF0_1', '', '');
1064 --
1065 -- These are already wired to the wall connectors
1066 --
1067 insert into PSlot values ('PS.base.b1', 'PF0_1', '', 'WS.002.1a');
1068 insert into PSlot values ('PS.base.b2', 'PF0_1', '', 'WS.002.1b');
1069 insert into PSlot values ('PS.base.b3', 'PF0_1', '', 'WS.002.2a');
1070 insert into PSlot values ('PS.base.b4', 'PF0_1', '', 'WS.002.2b');
1071 insert into PSlot values ('PS.base.b5', 'PF0_1', '', 'WS.002.3a');
1072 insert into PSlot values ('PS.base.b6', 'PF0_1', '', 'WS.002.3b');
1073 insert into PSlot values ('PS.base.c1', 'PF0_1', '', 'WS.003.1a');
1074 insert into PSlot values ('PS.base.c2', 'PF0_1', '', 'WS.003.1b');
1075 insert into PSlot values ('PS.base.c3', 'PF0_1', '', 'WS.003.2a');
1076 insert into PSlot values ('PS.base.c4', 'PF0_1', '', 'WS.003.2b');
1077 insert into PSlot values ('PS.base.c5', 'PF0_1', '', 'WS.003.3a');
1078 insert into PSlot values ('PS.base.c6', 'PF0_1', '', 'WS.003.3b');
1079 --
1080 -- This patchfield will be renamed later into PF0_2 - so its
1081 -- slots references in pfname should follow
1082 --
1083 insert into PField values ('PF0_X', 'Phonelines basement');
1084 insert into PSlot values ('PS.base.ta1', 'PF0_X', '', '');
1085 insert into PSlot values ('PS.base.ta2', 'PF0_X', '', '');
1086 insert into PSlot values ('PS.base.ta3', 'PF0_X', '', '');
1087 insert into PSlot values ('PS.base.ta4', 'PF0_X', '', '');
1088 insert into PSlot values ('PS.base.ta5', 'PF0_X', '', '');
1089 insert into PSlot values ('PS.base.ta6', 'PF0_X', '', '');
1090 insert into PSlot values ('PS.base.tb1', 'PF0_X', '', '');
1091 insert into PSlot values ('PS.base.tb2', 'PF0_X', '', '');
1092 insert into PSlot values ('PS.base.tb3', 'PF0_X', '', '');
1093 insert into PSlot values ('PS.base.tb4', 'PF0_X', '', '');
1094 insert into PSlot values ('PS.base.tb5', 'PF0_X', '', '');
1095 insert into PSlot values ('PS.base.tb6', 'PF0_X', '', '');
1096 insert into PField values ('PF1_1', 'Wallslots 1st floor');
1097 insert into PSlot values ('PS.1st.a1', 'PF1_1', '', 'WS.101.1a');
1098 insert into PSlot values ('PS.1st.a2', 'PF1_1', '', 'WS.101.1b');
1099 insert into PSlot values ('PS.1st.a3', 'PF1_1', '', 'WS.101.2a');
1100 insert into PSlot values ('PS.1st.a4', 'PF1_1', '', 'WS.101.2b');
1101 insert into PSlot values ('PS.1st.a5', 'PF1_1', '', 'WS.101.3a');
1102 insert into PSlot values ('PS.1st.a6', 'PF1_1', '', 'WS.101.3b');
1103 insert into PSlot values ('PS.1st.b1', 'PF1_1', '', 'WS.102.1a');
1104 insert into PSlot values ('PS.1st.b2', 'PF1_1', '', 'WS.102.1b');
1105 insert into PSlot values ('PS.1st.b3', 'PF1_1', '', 'WS.102.2a');
1106 insert into PSlot values ('PS.1st.b4', 'PF1_1', '', 'WS.102.2b');
1107 insert into PSlot values ('PS.1st.b5', 'PF1_1', '', 'WS.102.3a');
1108 insert into PSlot values ('PS.1st.b6', 'PF1_1', '', 'WS.102.3b');
1109 insert into PSlot values ('PS.1st.c1', 'PF1_1', '', 'WS.105.1a');
1110 insert into PSlot values ('PS.1st.c2', 'PF1_1', '', 'WS.105.1b');
1111 insert into PSlot values ('PS.1st.c3', 'PF1_1', '', 'WS.105.2a');
1112 insert into PSlot values ('PS.1st.c4', 'PF1_1', '', 'WS.105.2b');
1113 insert into PSlot values ('PS.1st.c5', 'PF1_1', '', 'WS.105.3a');
1114 insert into PSlot values ('PS.1st.c6', 'PF1_1', '', 'WS.105.3b');
1115 insert into PSlot values ('PS.1st.d1', 'PF1_1', '', 'WS.106.1a');
1116 insert into PSlot values ('PS.1st.d2', 'PF1_1', '', 'WS.106.1b');
1117 insert into PSlot values ('PS.1st.d3', 'PF1_1', '', 'WS.106.2a');
1118 insert into PSlot values ('PS.1st.d4', 'PF1_1', '', 'WS.106.2b');
1119 insert into PSlot values ('PS.1st.d5', 'PF1_1', '', 'WS.106.3a');
1120 insert into PSlot values ('PS.1st.d6', 'PF1_1', '', 'WS.106.3b');
1121 --
1122 -- Now we wire the wall connectors 1a-2a in room 001 to the
1123 -- patchfield. In the second update we make an error, and
1124 -- correct it after
1125 --
1126 update PSlot set backlink = 'WS.001.1a' where slotname = 'PS.base.a1';
1127 update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a3';
1128 select * from WSlot where roomno = '001' order by slotname;
1129        slotname       |  roomno  |       slotlink       |       backlink       
1130 ----------------------+----------+----------------------+----------------------
1131  WS.001.1a            | 001      |                      | PS.base.a1          
1132  WS.001.1b            | 001      |                      | PS.base.a3          
1133  WS.001.2a            | 001      |                      |                     
1134  WS.001.2b            | 001      |                      |                     
1135  WS.001.3a            | 001      |                      |                     
1136  WS.001.3b            | 001      |                      |                     
1137 (6 rows)
1138
1139 select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
1140        slotname       | pfname |       slotlink       |       backlink       
1141 ----------------------+--------+----------------------+----------------------
1142  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1143  PS.base.a2           | PF0_1  |                      |                     
1144  PS.base.a3           | PF0_1  |                      | WS.001.1b           
1145  PS.base.a4           | PF0_1  |                      |                     
1146  PS.base.a5           | PF0_1  |                      |                     
1147  PS.base.a6           | PF0_1  |                      |                     
1148 (6 rows)
1149
1150 update PSlot set backlink = 'WS.001.2a' where slotname = 'PS.base.a3';
1151 select * from WSlot where roomno = '001' order by slotname;
1152        slotname       |  roomno  |       slotlink       |       backlink       
1153 ----------------------+----------+----------------------+----------------------
1154  WS.001.1a            | 001      |                      | PS.base.a1          
1155  WS.001.1b            | 001      |                      |                     
1156  WS.001.2a            | 001      |                      | PS.base.a3          
1157  WS.001.2b            | 001      |                      |                     
1158  WS.001.3a            | 001      |                      |                     
1159  WS.001.3b            | 001      |                      |                     
1160 (6 rows)
1161
1162 select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
1163        slotname       | pfname |       slotlink       |       backlink       
1164 ----------------------+--------+----------------------+----------------------
1165  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1166  PS.base.a2           | PF0_1  |                      |                     
1167  PS.base.a3           | PF0_1  |                      | WS.001.2a           
1168  PS.base.a4           | PF0_1  |                      |                     
1169  PS.base.a5           | PF0_1  |                      |                     
1170  PS.base.a6           | PF0_1  |                      |                     
1171 (6 rows)
1172
1173 update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a2';
1174 select * from WSlot where roomno = '001' order by slotname;
1175        slotname       |  roomno  |       slotlink       |       backlink       
1176 ----------------------+----------+----------------------+----------------------
1177  WS.001.1a            | 001      |                      | PS.base.a1          
1178  WS.001.1b            | 001      |                      | PS.base.a2          
1179  WS.001.2a            | 001      |                      | PS.base.a3          
1180  WS.001.2b            | 001      |                      |                     
1181  WS.001.3a            | 001      |                      |                     
1182  WS.001.3b            | 001      |                      |                     
1183 (6 rows)
1184
1185 select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
1186        slotname       | pfname |       slotlink       |       backlink       
1187 ----------------------+--------+----------------------+----------------------
1188  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1189  PS.base.a2           | PF0_1  |                      | WS.001.1b           
1190  PS.base.a3           | PF0_1  |                      | WS.001.2a           
1191  PS.base.a4           | PF0_1  |                      |                     
1192  PS.base.a5           | PF0_1  |                      |                     
1193  PS.base.a6           | PF0_1  |                      |                     
1194 (6 rows)
1195
1196 --
1197 -- Same procedure for 2b-3b but this time updating the WSlot instead
1198 -- of the PSlot. Due to the triggers the result is the same:
1199 -- WSlot and corresponding PSlot point to each other.
1200 --
1201 update WSlot set backlink = 'PS.base.a4' where slotname = 'WS.001.2b';
1202 update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3a';
1203 select * from WSlot where roomno = '001' order by slotname;
1204        slotname       |  roomno  |       slotlink       |       backlink       
1205 ----------------------+----------+----------------------+----------------------
1206  WS.001.1a            | 001      |                      | PS.base.a1          
1207  WS.001.1b            | 001      |                      | PS.base.a2          
1208  WS.001.2a            | 001      |                      | PS.base.a3          
1209  WS.001.2b            | 001      |                      | PS.base.a4          
1210  WS.001.3a            | 001      |                      | PS.base.a6          
1211  WS.001.3b            | 001      |                      |                     
1212 (6 rows)
1213
1214 select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
1215        slotname       | pfname |       slotlink       |       backlink       
1216 ----------------------+--------+----------------------+----------------------
1217  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1218  PS.base.a2           | PF0_1  |                      | WS.001.1b           
1219  PS.base.a3           | PF0_1  |                      | WS.001.2a           
1220  PS.base.a4           | PF0_1  |                      | WS.001.2b           
1221  PS.base.a5           | PF0_1  |                      |                     
1222  PS.base.a6           | PF0_1  |                      | WS.001.3a           
1223 (6 rows)
1224
1225 update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3b';
1226 select * from WSlot where roomno = '001' order by slotname;
1227        slotname       |  roomno  |       slotlink       |       backlink       
1228 ----------------------+----------+----------------------+----------------------
1229  WS.001.1a            | 001      |                      | PS.base.a1          
1230  WS.001.1b            | 001      |                      | PS.base.a2          
1231  WS.001.2a            | 001      |                      | PS.base.a3          
1232  WS.001.2b            | 001      |                      | PS.base.a4          
1233  WS.001.3a            | 001      |                      |                     
1234  WS.001.3b            | 001      |                      | PS.base.a6          
1235 (6 rows)
1236
1237 select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
1238        slotname       | pfname |       slotlink       |       backlink       
1239 ----------------------+--------+----------------------+----------------------
1240  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1241  PS.base.a2           | PF0_1  |                      | WS.001.1b           
1242  PS.base.a3           | PF0_1  |                      | WS.001.2a           
1243  PS.base.a4           | PF0_1  |                      | WS.001.2b           
1244  PS.base.a5           | PF0_1  |                      |                     
1245  PS.base.a6           | PF0_1  |                      | WS.001.3b           
1246 (6 rows)
1247
1248 update WSlot set backlink = 'PS.base.a5' where slotname = 'WS.001.3a';
1249 select * from WSlot where roomno = '001' order by slotname;
1250        slotname       |  roomno  |       slotlink       |       backlink       
1251 ----------------------+----------+----------------------+----------------------
1252  WS.001.1a            | 001      |                      | PS.base.a1          
1253  WS.001.1b            | 001      |                      | PS.base.a2          
1254  WS.001.2a            | 001      |                      | PS.base.a3          
1255  WS.001.2b            | 001      |                      | PS.base.a4          
1256  WS.001.3a            | 001      |                      | PS.base.a5          
1257  WS.001.3b            | 001      |                      | PS.base.a6          
1258 (6 rows)
1259
1260 select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
1261        slotname       | pfname |       slotlink       |       backlink       
1262 ----------------------+--------+----------------------+----------------------
1263  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1264  PS.base.a2           | PF0_1  |                      | WS.001.1b           
1265  PS.base.a3           | PF0_1  |                      | WS.001.2a           
1266  PS.base.a4           | PF0_1  |                      | WS.001.2b           
1267  PS.base.a5           | PF0_1  |                      | WS.001.3a           
1268  PS.base.a6           | PF0_1  |                      | WS.001.3b           
1269 (6 rows)
1270
1271 insert into PField values ('PF1_2', 'Phonelines 1st floor');
1272 insert into PSlot values ('PS.1st.ta1', 'PF1_2', '', '');
1273 insert into PSlot values ('PS.1st.ta2', 'PF1_2', '', '');
1274 insert into PSlot values ('PS.1st.ta3', 'PF1_2', '', '');
1275 insert into PSlot values ('PS.1st.ta4', 'PF1_2', '', '');
1276 insert into PSlot values ('PS.1st.ta5', 'PF1_2', '', '');
1277 insert into PSlot values ('PS.1st.ta6', 'PF1_2', '', '');
1278 insert into PSlot values ('PS.1st.tb1', 'PF1_2', '', '');
1279 insert into PSlot values ('PS.1st.tb2', 'PF1_2', '', '');
1280 insert into PSlot values ('PS.1st.tb3', 'PF1_2', '', '');
1281 insert into PSlot values ('PS.1st.tb4', 'PF1_2', '', '');
1282 insert into PSlot values ('PS.1st.tb5', 'PF1_2', '', '');
1283 insert into PSlot values ('PS.1st.tb6', 'PF1_2', '', '');
1284 --
1285 -- Fix the wrong name for patchfield PF0_2
1286 --
1287 update PField set name = 'PF0_2' where name = 'PF0_X';
1288 select * from PSlot order by slotname;
1289        slotname       | pfname |       slotlink       |       backlink       
1290 ----------------------+--------+----------------------+----------------------
1291  PS.1st.a1            | PF1_1  |                      | WS.101.1a           
1292  PS.1st.a2            | PF1_1  |                      | WS.101.1b           
1293  PS.1st.a3            | PF1_1  |                      | WS.101.2a           
1294  PS.1st.a4            | PF1_1  |                      | WS.101.2b           
1295  PS.1st.a5            | PF1_1  |                      | WS.101.3a           
1296  PS.1st.a6            | PF1_1  |                      | WS.101.3b           
1297  PS.1st.b1            | PF1_1  |                      | WS.102.1a           
1298  PS.1st.b2            | PF1_1  |                      | WS.102.1b           
1299  PS.1st.b3            | PF1_1  |                      | WS.102.2a           
1300  PS.1st.b4            | PF1_1  |                      | WS.102.2b           
1301  PS.1st.b5            | PF1_1  |                      | WS.102.3a           
1302  PS.1st.b6            | PF1_1  |                      | WS.102.3b           
1303  PS.1st.c1            | PF1_1  |                      | WS.105.1a           
1304  PS.1st.c2            | PF1_1  |                      | WS.105.1b           
1305  PS.1st.c3            | PF1_1  |                      | WS.105.2a           
1306  PS.1st.c4            | PF1_1  |                      | WS.105.2b           
1307  PS.1st.c5            | PF1_1  |                      | WS.105.3a           
1308  PS.1st.c6            | PF1_1  |                      | WS.105.3b           
1309  PS.1st.d1            | PF1_1  |                      | WS.106.1a           
1310  PS.1st.d2            | PF1_1  |                      | WS.106.1b           
1311  PS.1st.d3            | PF1_1  |                      | WS.106.2a           
1312  PS.1st.d4            | PF1_1  |                      | WS.106.2b           
1313  PS.1st.d5            | PF1_1  |                      | WS.106.3a           
1314  PS.1st.d6            | PF1_1  |                      | WS.106.3b           
1315  PS.1st.ta1           | PF1_2  |                      |                     
1316  PS.1st.ta2           | PF1_2  |                      |                     
1317  PS.1st.ta3           | PF1_2  |                      |                     
1318  PS.1st.ta4           | PF1_2  |                      |                     
1319  PS.1st.ta5           | PF1_2  |                      |                     
1320  PS.1st.ta6           | PF1_2  |                      |                     
1321  PS.1st.tb1           | PF1_2  |                      |                     
1322  PS.1st.tb2           | PF1_2  |                      |                     
1323  PS.1st.tb3           | PF1_2  |                      |                     
1324  PS.1st.tb4           | PF1_2  |                      |                     
1325  PS.1st.tb5           | PF1_2  |                      |                     
1326  PS.1st.tb6           | PF1_2  |                      |                     
1327  PS.base.a1           | PF0_1  |                      | WS.001.1a           
1328  PS.base.a2           | PF0_1  |                      | WS.001.1b           
1329  PS.base.a3           | PF0_1  |                      | WS.001.2a           
1330  PS.base.a4           | PF0_1  |                      | WS.001.2b           
1331  PS.base.a5           | PF0_1  |                      | WS.001.3a           
1332  PS.base.a6           | PF0_1  |                      | WS.001.3b           
1333  PS.base.b1           | PF0_1  |                      | WS.002.1a           
1334  PS.base.b2           | PF0_1  |                      | WS.002.1b           
1335  PS.base.b3           | PF0_1  |                      | WS.002.2a           
1336  PS.base.b4           | PF0_1  |                      | WS.002.2b           
1337  PS.base.b5           | PF0_1  |                      | WS.002.3a           
1338  PS.base.b6           | PF0_1  |                      | WS.002.3b           
1339  PS.base.c1           | PF0_1  |                      | WS.003.1a           
1340  PS.base.c2           | PF0_1  |                      | WS.003.1b           
1341  PS.base.c3           | PF0_1  |                      | WS.003.2a           
1342  PS.base.c4           | PF0_1  |                      | WS.003.2b           
1343  PS.base.c5           | PF0_1  |                      | WS.003.3a           
1344  PS.base.c6           | PF0_1  |                      | WS.003.3b           
1345  PS.base.ta1          | PF0_2  |                      |                     
1346  PS.base.ta2          | PF0_2  |                      |                     
1347  PS.base.ta3          | PF0_2  |                      |                     
1348  PS.base.ta4          | PF0_2  |                      |                     
1349  PS.base.ta5          | PF0_2  |                      |                     
1350  PS.base.ta6          | PF0_2  |                      |                     
1351  PS.base.tb1          | PF0_2  |                      |                     
1352  PS.base.tb2          | PF0_2  |                      |                     
1353  PS.base.tb3          | PF0_2  |                      |                     
1354  PS.base.tb4          | PF0_2  |                      |                     
1355  PS.base.tb5          | PF0_2  |                      |                     
1356  PS.base.tb6          | PF0_2  |                      |                     
1357 (66 rows)
1358
1359 select * from WSlot order by slotname;
1360        slotname       |  roomno  |       slotlink       |       backlink       
1361 ----------------------+----------+----------------------+----------------------
1362  WS.001.1a            | 001      |                      | PS.base.a1          
1363  WS.001.1b            | 001      |                      | PS.base.a2          
1364  WS.001.2a            | 001      |                      | PS.base.a3          
1365  WS.001.2b            | 001      |                      | PS.base.a4          
1366  WS.001.3a            | 001      |                      | PS.base.a5          
1367  WS.001.3b            | 001      |                      | PS.base.a6          
1368  WS.002.1a            | 002      |                      | PS.base.b1          
1369  WS.002.1b            | 002      |                      | PS.base.b2          
1370  WS.002.2a            | 002      |                      | PS.base.b3          
1371  WS.002.2b            | 002      |                      | PS.base.b4          
1372  WS.002.3a            | 002      |                      | PS.base.b5          
1373  WS.002.3b            | 002      |                      | PS.base.b6          
1374  WS.003.1a            | 003      |                      | PS.base.c1          
1375  WS.003.1b            | 003      |                      | PS.base.c2          
1376  WS.003.2a            | 003      |                      | PS.base.c3          
1377  WS.003.2b            | 003      |                      | PS.base.c4          
1378  WS.003.3a            | 003      |                      | PS.base.c5          
1379  WS.003.3b            | 003      |                      | PS.base.c6          
1380  WS.101.1a            | 101      |                      | PS.1st.a1           
1381  WS.101.1b            | 101      |                      | PS.1st.a2           
1382  WS.101.2a            | 101      |                      | PS.1st.a3           
1383  WS.101.2b            | 101      |                      | PS.1st.a4           
1384  WS.101.3a            | 101      |                      | PS.1st.a5           
1385  WS.101.3b            | 101      |                      | PS.1st.a6           
1386  WS.102.1a            | 102      |                      | PS.1st.b1           
1387  WS.102.1b            | 102      |                      | PS.1st.b2           
1388  WS.102.2a            | 102      |                      | PS.1st.b3           
1389  WS.102.2b            | 102      |                      | PS.1st.b4           
1390  WS.102.3a            | 102      |                      | PS.1st.b5           
1391  WS.102.3b            | 102      |                      | PS.1st.b6           
1392  WS.105.1a            | 105      |                      | PS.1st.c1           
1393  WS.105.1b            | 105      |                      | PS.1st.c2           
1394  WS.105.2a            | 105      |                      | PS.1st.c3           
1395  WS.105.2b            | 105      |                      | PS.1st.c4           
1396  WS.105.3a            | 105      |                      | PS.1st.c5           
1397  WS.105.3b            | 105      |                      | PS.1st.c6           
1398  WS.106.1a            | 106      |                      | PS.1st.d1           
1399  WS.106.1b            | 106      |                      | PS.1st.d2           
1400  WS.106.2a            | 106      |                      | PS.1st.d3           
1401  WS.106.2b            | 106      |                      | PS.1st.d4           
1402  WS.106.3a            | 106      |                      | PS.1st.d5           
1403  WS.106.3b            | 106      |                      | PS.1st.d6           
1404 (42 rows)
1405
1406 --
1407 -- Install the central phone system and create the phone numbers.
1408 -- They are weired on insert to the patchfields. Again the
1409 -- triggers automatically tell the PSlots to update their
1410 -- backlink field.
1411 --
1412 insert into PLine values ('PL.001', '-0', 'Central call', 'PS.base.ta1');
1413 insert into PLine values ('PL.002', '-101', '', 'PS.base.ta2');
1414 insert into PLine values ('PL.003', '-102', '', 'PS.base.ta3');
1415 insert into PLine values ('PL.004', '-103', '', 'PS.base.ta5');
1416 insert into PLine values ('PL.005', '-104', '', 'PS.base.ta6');
1417 insert into PLine values ('PL.006', '-106', '', 'PS.base.tb2');
1418 insert into PLine values ('PL.007', '-108', '', 'PS.base.tb3');
1419 insert into PLine values ('PL.008', '-109', '', 'PS.base.tb4');
1420 insert into PLine values ('PL.009', '-121', '', 'PS.base.tb5');
1421 insert into PLine values ('PL.010', '-122', '', 'PS.base.tb6');
1422 insert into PLine values ('PL.015', '-134', '', 'PS.1st.ta1');
1423 insert into PLine values ('PL.016', '-137', '', 'PS.1st.ta3');
1424 insert into PLine values ('PL.017', '-139', '', 'PS.1st.ta4');
1425 insert into PLine values ('PL.018', '-362', '', 'PS.1st.tb1');
1426 insert into PLine values ('PL.019', '-363', '', 'PS.1st.tb2');
1427 insert into PLine values ('PL.020', '-364', '', 'PS.1st.tb3');
1428 insert into PLine values ('PL.021', '-365', '', 'PS.1st.tb5');
1429 insert into PLine values ('PL.022', '-367', '', 'PS.1st.tb6');
1430 insert into PLine values ('PL.028', '-501', 'Fax entrance', 'PS.base.ta2');
1431 insert into PLine values ('PL.029', '-502', 'Fax 1st floor', 'PS.1st.ta1');
1432 --
1433 -- Buy some phones, plug them into the wall and patch the
1434 -- phone lines to the corresponding patchfield slots.
1435 --
1436 insert into PHone values ('PH.hc001', 'Hicom standard', 'WS.001.1a');
1437 update PSlot set slotlink = 'PS.base.ta1' where slotname = 'PS.base.a1';
1438 insert into PHone values ('PH.hc002', 'Hicom standard', 'WS.002.1a');
1439 update PSlot set slotlink = 'PS.base.ta5' where slotname = 'PS.base.b1';
1440 insert into PHone values ('PH.hc003', 'Hicom standard', 'WS.002.2a');
1441 update PSlot set slotlink = 'PS.base.tb2' where slotname = 'PS.base.b3';
1442 insert into PHone values ('PH.fax001', 'Canon fax', 'WS.001.2a');
1443 update PSlot set slotlink = 'PS.base.ta2' where slotname = 'PS.base.a3';
1444 --
1445 -- Install a hub at one of the patchfields, plug a computers
1446 -- ethernet interface into the wall and patch it to the hub.
1447 --
1448 insert into Hub values ('base.hub1', 'Patchfield PF0_1 hub', 16);
1449 insert into System values ('orion', 'PC');
1450 insert into IFace values ('IF', 'orion', 'eth0', 'WS.002.1b');
1451 update PSlot set slotlink = 'HS.base.hub1.1' where slotname = 'PS.base.b2';
1452 --
1453 -- Now we take a look at the patchfield
1454 --
1455 select * from PField_v1 where pfname = 'PF0_1' order by slotname;
1456  pfname |       slotname       |                         backside                         |                     patch                     
1457 --------+----------------------+----------------------------------------------------------+-----------------------------------------------
1458  PF0_1  | PS.base.a1           | WS.001.1a in room 001 -> Phone PH.hc001 (Hicom standard) | PS.base.ta1 -> Phone line -0 (Central call)
1459  PF0_1  | PS.base.a2           | WS.001.1b in room 001 -> -                               | -
1460  PF0_1  | PS.base.a3           | WS.001.2a in room 001 -> Phone PH.fax001 (Canon fax)     | PS.base.ta2 -> Phone line -501 (Fax entrance)
1461  PF0_1  | PS.base.a4           | WS.001.2b in room 001 -> -                               | -
1462  PF0_1  | PS.base.a5           | WS.001.3a in room 001 -> -                               | -
1463  PF0_1  | PS.base.a6           | WS.001.3b in room 001 -> -                               | -
1464  PF0_1  | PS.base.b1           | WS.002.1a in room 002 -> Phone PH.hc002 (Hicom standard) | PS.base.ta5 -> Phone line -103
1465  PF0_1  | PS.base.b2           | WS.002.1b in room 002 -> orion IF eth0 (PC)              | Patchfield PF0_1 hub slot 1
1466  PF0_1  | PS.base.b3           | WS.002.2a in room 002 -> Phone PH.hc003 (Hicom standard) | PS.base.tb2 -> Phone line -106
1467  PF0_1  | PS.base.b4           | WS.002.2b in room 002 -> -                               | -
1468  PF0_1  | PS.base.b5           | WS.002.3a in room 002 -> -                               | -
1469  PF0_1  | PS.base.b6           | WS.002.3b in room 002 -> -                               | -
1470  PF0_1  | PS.base.c1           | WS.003.1a in room 003 -> -                               | -
1471  PF0_1  | PS.base.c2           | WS.003.1b in room 003 -> -                               | -
1472  PF0_1  | PS.base.c3           | WS.003.2a in room 003 -> -                               | -
1473  PF0_1  | PS.base.c4           | WS.003.2b in room 003 -> -                               | -
1474  PF0_1  | PS.base.c5           | WS.003.3a in room 003 -> -                               | -
1475  PF0_1  | PS.base.c6           | WS.003.3b in room 003 -> -                               | -
1476 (18 rows)
1477
1478 select * from PField_v1 where pfname = 'PF0_2' order by slotname;
1479  pfname |       slotname       |            backside            |                                 patch                                  
1480 --------+----------------------+--------------------------------+------------------------------------------------------------------------
1481  PF0_2  | PS.base.ta1          | Phone line -0 (Central call)   | PS.base.a1 -> WS.001.1a in room 001 -> Phone PH.hc001 (Hicom standard)
1482  PF0_2  | PS.base.ta2          | Phone line -501 (Fax entrance) | PS.base.a3 -> WS.001.2a in room 001 -> Phone PH.fax001 (Canon fax)
1483  PF0_2  | PS.base.ta3          | Phone line -102                | -
1484  PF0_2  | PS.base.ta4          | -                              | -
1485  PF0_2  | PS.base.ta5          | Phone line -103                | PS.base.b1 -> WS.002.1a in room 002 -> Phone PH.hc002 (Hicom standard)
1486  PF0_2  | PS.base.ta6          | Phone line -104                | -
1487  PF0_2  | PS.base.tb1          | -                              | -
1488  PF0_2  | PS.base.tb2          | Phone line -106                | PS.base.b3 -> WS.002.2a in room 002 -> Phone PH.hc003 (Hicom standard)
1489  PF0_2  | PS.base.tb3          | Phone line -108                | -
1490  PF0_2  | PS.base.tb4          | Phone line -109                | -
1491  PF0_2  | PS.base.tb5          | Phone line -121                | -
1492  PF0_2  | PS.base.tb6          | Phone line -122                | -
1493 (12 rows)
1494
1495 --
1496 -- Finally we want errors
1497 --
1498 insert into PField values ('PF1_1', 'should fail due to unique index');
1499 ERROR:  Cannot insert a duplicate key into unique index pfield_name
1500 update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
1501 ERROR:  WS.not.there         does not exist
1502 update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
1503 ERROR:  illegal backlink beginning with XX
1504 update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
1505 ERROR:  PS.not.there         does not exist
1506 update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
1507 ERROR:  illegal slotlink beginning with XX
1508 insert into HSlot values ('HS', 'base.hub1', 1, '');
1509 ERROR:  Cannot insert a duplicate key into unique index hslot_name
1510 insert into HSlot values ('HS', 'base.hub1', 20, '');
1511 ERROR:  no manual manipulation of HSlot
1512 delete from HSlot;
1513 ERROR:  no manual manipulation of HSlot
1514 insert into IFace values ('IF', 'notthere', 'eth0', '');
1515 ERROR:  system "notthere" does not exist
1516 insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
1517 ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
1518 --
1519 -- Test recursion, per bug report 7-Sep-01
1520 --
1521 CREATE FUNCTION recursion_test(int,int) RETURNS text AS '
1522 DECLARE rslt text;
1523 BEGIN
1524     IF $1 <= 0 THEN
1525         rslt = CAST($2 AS TEXT);
1526     ELSE
1527         rslt = CAST($1 AS TEXT) || '','' || recursion_test($1 - 1, $2);
1528     END IF;
1529     RETURN rslt;
1530 END;' LANGUAGE 'plpgsql';
1531 SELECT recursion_test(4,3);
1532  recursion_test 
1533 ----------------
1534  4,3,2,1,3
1535 (1 row)
1536