[Postfixbuch-users] DB-Strukturen

Stefan Förster cite+postfix-buch at incertum.net
Do Nov 6 16:54:38 CET 2008


Hallo Christian,

ich habe etwas über Deine Anmerkungen nachgedacht und ein paar kleine
Änderungen durchgeführt.

* Christian Boltz <postfixbuch at cboltz.de> wrote:
>> mailsystem=> \d virtual_mailbox_domains
> 
> Passt.

Die neue Version enthält für jede Domain ein boolean-Feld "alias", so
daß virtual_alias_domains und virtual_mailbox_domains jetzt aus einer
Tabelle kommen können.

> [Extra Tabelle mit Logindaten, Quota usw.]
> 
> Was ist der Grund, das nicht in der virtual_mailbox_maps-Tabelle zu
> haben? Üblicherweise wirst Du sowieso eine 1:1-Zuordnung von Logindaten
> und Mailboxen haben.

Ja - ich habe das jetzt jedoch trotzdem beibehalten, erstens sind die
Queries nicht wirklich kompliziert und zweitens weiß man nie, wofür
man es einmal brauchen kann - und sei es nur, damit zwei Nutzer mit
unterschiedlichen Zugangsdaten auf die selbe Mailbox zugreifen können.

> Oder man nutzt ein *zusätzliches* Feld, das die komplette Mailadresse
> enthält - mit Triggern kann man sowas bequem aktuell halten.

Wie gesagt, sowas braucht's eigentlich nicht. Ich habe mal EXPLAIN und
EXPLAIN (ANALYZE) über diverse Beispieldaten laufen lassen, das nimmt
sich nicht viel. Die Idee mit Triggern ist aber gut, s.u.

> Und wie willst Du Weiterleitungen an externe Adressen umsetzen?
> Der Einfachheit halber sollte die Zieladresse ein varchar-Feld sein, in
> dem schlicht eine Mailadresse steht.

Für den Fall würde ich eine eigene, neue Alias-Tabelle einbauen -
wobei ich sowieso kein Fan von derartigen Weiterleitungen bin, es gibt
zuviele Schrumpfköpfe da draußen, die dann - hallo SPF! - Mails hart
droppen.

>> Arbeitet man mit virtual_alias_domains, wird es eklig.
> 
> Oh ja. Haben wir bei Postfixadmin auch schon gemerkt ;-)

Meine derzeitige Lösung sieht folgendermaßen aus:

                                  Table "public.aliases"
  Column   |         Type          |                      Modifiers
-----------+-----------------------+------------------------------------------------------
 id        | integer               | not null default nextval('aliases_id_seq'::regclass)
 domain    | integer               | not null
 localpart | character varying(64) | not null
 target    | integer               | not null
 final     | boolean               | not null
 active    | boolean               | not null
Indexes:
    "aliases_pkey" PRIMARY KEY, btree (id)
    "aliases_domain_key" UNIQUE, btree (domain, localpart, target, final)
    "aliases_active_idx" btree (active)
    "aliases_domain_idx" btree (domain)
    "aliases_final_idx" btree (final)
    "aliases_localpart_idx" btree (localpart)
    "aliases_target_idx" btree (target)
Foreign-key constraints:
    "aliases_domain_fkey" FOREIGN KEY (domain) REFERENCES domains(id)
Triggers:
    check_aliases_new_changed BEFORE INSERT OR UPDATE ON aliases FOR EACH ROW EXECUTE PROCEDURE check_aliases()
    check_aliases_delete AFTER DELETE ON aliases FOR EACH ROW EXECUTE PROCEDURE check_aliases_delete()

Wie man sieht, kann ein Alias entweder (final = true) auf eine Mailbox
oder aber (final = false) auf einen anderen Alias zeigen. Die
strukturelle Integrität der Daten stelle ich dabei mit zwei kleinen
Triggern sicher. Bei einem Update/Einfügen:

CREATE FUNCTION check_aliases_new_changed () RETURNS trigger AS '
  DECLARE
    target            INTEGER;
    mailbox_localpart CHARACTER VARYING(64);

  BEGIN

  -- check whether this is a final alias
  IF NEW.final = TRUE THEN
    -- check where the alias points
    SELECT INTO target id FROM mailboxes WHERE id = NEW.target;
    IF NOT FOUND THEN
      RAISE EXCEPTION ''Target mailbox for final alias undefined'';
    END IF;

    -- check whether alias is already taken
    SELECT INTO mailbox_localpart localpart FROM mailboxes WHERE localpart = NEW.localpart AND id = NEW.target;
    IF FOUND THEN
      RAISE EXCEPTION ''Duplicate localpart for mailbox'';
    END IF;
  ELSE
    -- check where alias points to
    SELECT INTO  target id FROM aliases WHERE id = NEW.target;
    IF NOT FOUND THEN
      RAISE EXCEPTION ''Target alias not found'';
    END IF;
  END IF;

  RETURN NEW;

  END;
' LANGUAGE 'plpgsql';

und beim Löschen:

REATE FUNCTION check_aliases_delete() RETURNS trigger AS '
  DECLARE

  BEGIN

  DELETE FROM aliases a WHERE NOT EXISTS (SELECT 1 FROM aliases WHERE id = a.target);

  RETURN OLD;

  END;
' LANGUAGE 'plpgsql';

Die Queries dazu sind trivial - um den Preis der Tatsache, daß aus
einer Alias-Abfrage nicht sofort die Mailbox, sondern nur eine Liste
von Adressen rausfälllt - was aber auch gewünscht sein kann.

Komme ich Deinen Vorstellungen für eine gute Struktur damit näher?

Zu Postfixadmin - ich habe mir die DB-Strukturen da _noch nicht_
angesehen. Ich habe in der Vergangenheit festgestellt, daß ich
aufhöre, Lösungen zu suchen, wenn mir eine präsentiert wird, und das
will ich bei einem Spielprojekt, bei dem es vordringlich um's lernen
geht, so eigentlich nicht haben.


Ciao
Stefan
-- 
Stefan Förster     http://www.incertum.net/     Public Key: 0xBBE2A9E9
The real problem is not whether machines think but whether men do.
B. F. Skinner



Mehr Informationen über die Mailingliste Postfixbuch-users