SQL ohne Schleifen

Manche Aufgaben schreien geradezu danach, mit Schleifen gelöst zu werden. In SQL ist dies selten nötig. In meinem Beispiel wollten wir für jeden Monat des letzten Jahres die Häufigkeit eines bestimmten Ereignisses errechnen um es graphisch darzustellen. Mein Kollege, der an dieser Stelle besser anonym bleiben möchte, schlug schon vor, die Abfrage 12× mit unterschiedlichen Bedingungen abzuschießen.

Mir fiel ein, daß PostgreSQL über Funktionen verfügt, mit denen man aus einem Datum Jahr/Monat/Tag (und einiges Mehr) extrahieren kann. Die Funktion heißt sinnvollerweise extract. Damit kann man das Problem mit einer einzigen Abfrage erschlagen. Dies sieht dann so aus:

SELECT EXTRACT(month FROM created_on) AS month, COUNT(*) AS occurences
FROM my_event_log
WHERE EXTRACT(year FROM created_on)=2006
GROUP BY EXTRACT(month FROM created_on)
ORDER BY EXTRACT(month FROM created_on)

Dies läßt sich auch prima in Rails verwenden.

events = MyEventLog.count(:conditions => [ "EXTRACT(year FROM created_on)=?", 2006],
                          :group => "EXTRACT(month FROM created_on)",
                          :order => "EXTRACT(month FROM created_on)")

Es sollte an dieser Stelle jedoch nicht unerwähnt bleiben, daß durch die Verwendung von Funktionen wie extract in Verbindung mit ActiveRecord, der datenbankagnostische Aspekt von ActiveRecord verloren geht, da nicht alle Datenbanken die gleichen Funktionen unterstützen. Aber vermutlich ist datenbankagnostische Programmierung eh eine utopische Vision.

MS Access, pgsqlODBC und Booleans

pgsqlODBC macht in den Standardeinstellungen einige sehr sonderbare Sachen. Eine Spalte mit Booleans erscheint in MS Access als Textfeld. Das führt dann natürlich zu einigen Problemen mit Checkboxen. Access meint dann, das Feld wäre zu klein, um den Wert zu speichern. Dabei beherrscht MS Access Booleans. Man muß nur den pgsqlODBC-Treiber überzeugen, das ganze für MS Access verständlich zu präsentieren. Hierzu müssen nur 2 Optionen in der ODBC-Verbindung geändert werden. Die Optionen finden sich unter Datasource

  1. Bools as Char muß ausgeschaltet werden
  2. True is -1muß eingeschaltet werden

Verknüpft man die Tabellen nun (erneut), werden sie in MS Access auch korrekt als Ja/Nein angezeigt und können auch von Checkboxen verwendet werden.

Spielereien mit Rules und Check Constraints in PostgreSQL

Ich hatte heute das Problem, daß ich in der Datenbank Zeiträume (Start- und Enddatum) speichern mußte, in denen bestimmte Resourcen in Benutzung sind/sein werden. Eine Resource darf dabei zu einem bestimmten Zeitpunkt nicht mehrfach belegt werden. Ich mußte also sicherstellen, daß sich die Zeitbereiche einer Resource nicht überlappen.

Check Constrainst von PostgreSQL alleine hilft da leider nicht. Der kann nur auf Konsistenz innerhalb eines Datensatzen prüfen, z.B. ob das Startdatum vor dem Enddatum liegt. Soll geprüft werden, ob die neu einzufügenden Daten in irgendeiner Beziehung zu bereits vorhanden Daten stehen, so müssen Regeln (RULE) definiert werden. Dies sieht in meinem Beispiel so aus.

CREATE TABLE sometable (
	id				serial,
	start_date			date		NOT NULL,
	end_date			date		NOT NULL,
	resource			integer	NOT NULL,
	CHECK (start_date<=end_date)
);
CREATE RULE no_overlap_insert AS ON INSERT TO sometable
WHERE EXISTS (
	SELECT * FROM sometable
	WHERE ((( new.start_date>=start_date AND new.start_date<=end_date )
		OR ( new.end_date>=start_date AND new.end_date<=end_date ))
	  AND new.resource=resource)
)
DO INSTEAD NOTHING;

Hier habe ich also ein Check Constrainst, das prüft, ob das Startdatum auch wirklich vor dem Enddatum liegt sowie eine Regel, die verhindert, daß ich eine Resource zu einer Zeit mehrfach belege.

Unschön an dieser Lösung ist jedoch, daß der Check Constrainst einen Fehler hervorruft, wenn die Bedingung nicht erfüllt wird, während die Regel einfach still die Daten verwirft. Man kann also nur anhand der Anzahl der geänderten Datensätze, die nach jedem INSERT/UPDATE zurückgegeben wird, feststellen, ob die Daten erfolgreich gespeichert wurden. Hier wäre es natürlich angenehmer, wenn auch ein Fehler erzeugt würde.

Nicht im Beispiel enthalten ist eine zweite Regel, die verhindert, daß man bereits vorhandene Datensätze so ändert, daß es doch wieder zu Überlappungen kommt. Hierzu muß einfach eine zweite Regel (mit anderem Namen) erstellt werden, die statt ON INSERT ein ON UPDATE enthält.

PostgreSQL auf Mac OS X selbstgebaut

Dies ist eine Anleitung, um PostgreSQL auf Mac OS X Tiger zu installieren. Diese Anleitung ist größtenteils an diese Anleitung angelehnt, doch an einigen Stellen weiche ich davon ab, wo es mir sinnvoll erschien. Ich habe sie für mich und meinen Arbeitskollegen geschrieben, doch ich hoffe, daß sie sich auch für andere als hilfreich erweist.

Es gibt viele Anleitungen, die beschreiben, wie man PostgreSQL auf einem Unix-System installiert. Mac OS X ist im Grunde ein solches. Doch es bringt ein zusätzliches Verzeichnis-Layout mit sich, was sich hierfür eher anbietet. Nach der Installation befinden sich alle Dateien von PostgreSQL in /Library/PostgreSQL. Zusätzlich werden die Binaries sowie die Man-Pages nach /usr/local symlinked, damit man diese einfach von der Kommandozeile benutzen kann. (/usr/local/bin werden die meisten im $PATH haben). Zum Schluß landen die Datenbanken selbst in /Users/Shared/PostgreSQL. Alle Schritte wurden auf einem Powerbook mit G4-Prozessor durchgeführt, sollten jedoch auf den neuen Intel-Macs genauso funktionieren.

Die folgenden Schritte setzen voraus, daß Xcode auf dem System installiert ist. Ansonsten wird es schwierig, PostgreSQL zu kompilieren.

Installation von PostgreSQL auf Mac OS X

Nachdem du die Quelltexte von PostgreSQL (in meinem Fall ist es PostgreSQL 8.1.3) ausgepackt hast, wechsel in das Verzeichnis mit den Quelltexten. Der Anfang ist der übliche GNU-Dreisatz.

  1. ./configure --prefix=/Library/PostgreSQL --enable-thread-safety \
     --with-krb5 --with-bonjour --with-openssl
  2. make

    (nun ist etwas Zeit für einen Kaffee oder ein anderes Getränk)

  3. sudo make install
  4. Ich habe mich entschieden, die uid/gid 73 zu benutzen, da diese frei war. Dies muß bei späteren Mac OS X-Versionen nicht unbedingt der Fall sein, und es tut im Grunde auch jede andere uid/gid, solange diese bislang frei war. Die Gruppe und der Benutzer legst du mit diesen Befehlen an.
    sudo niutil -create . /groups/postgres
    sudo niutil -createprop . /groups/postgres gid 73
    sudo niutil -createprop . /groups/postgres realname "PostgreSQL Users"
    sudo niutil -createprop . /groups/postgres name postgres
    sudo niutil -createprop . /groups/postgres passwd "*"

    An dieser Stelle kannst du noch dich selbst zur Gruppe postgres hinzufügen. z.B:

    sudo niutil -createprop . /groups/postgres users fastjack

    (hier solltest du deinen Login-Namen einsetzen, außer du meldest dich auch als „fastjack“ an)

    sudo niutil -create . /users/postgres
    sudo niutil -createprop . /users/postgres uid 73
    sudo niutil -createprop . /users/postgres gid 73
    sudo niutil -createprop . /users/postgres name postgres
    sudo niutil -createprop . /users/postgres realname "PostgreSQL User"
    sudo niutil -createprop . /users/postgres shell /bin/sh
    sudo niutil -createprop . /users/postgres home /Users/Shared/PostgreSQL
    sudo niutil -createprop . /users/postgres passwd "*"
    sudo niutil -createprop . /users/postgres expire 0
    sudo niutil -createprop . /users/postgres change 0

    Falls du lieber mit einem graphischen Tool arbeitest, kannst du den NetInfo Manager (befindet sich bei den Dienstprogrammen) benutzen.

  5. Mac OS X sollte die Gruppe und den Benutzer direkt erkennen. Ein kurzer Test mit „sudo -u postgres id“ sollte folgende Ausgabe bringen:
    uid=73(postgres) gid=73(postgres) groups=73(postgres)Wir können also diesen Benutzer nun verwenden.
  6. Jetzt sollte das Verzeichnis mit dem frisch installierten PostgreSQL noch der Gruppe der PostgreSQL-Benutzer zugänglich gemacht werden. Dies ist nicht unbedingt nötig, doch ich wollte da ganz sichergehen.
    sudo chgrp -R postgres /Library/PostgreSQL
    sudo chmod -R g+r /Library/PostgreSQL
    sudo chmod -R g+x /Library/PostgreSQL/bin/*
  7. Lege nun die Symlinks für die einzelnen Binaries in /usr/local/bin an, sowie die Man-Pages in /usr/local/man. Falls die Verzeichnisse in /usr/localnoch nicht existieren, lege sie vorher an.
    cd /Library/PostgreSQL/bin
    for FOO in /Library/PostgreSQL/bin/*; do
    sudo ln -s $FOO /usr/local/bin/${FOO#$(pwd)/}
    done
    cd ../man/man1
    for FOO in /Library/PostgreSQL/man/man1/*; do
    sudo ln -s $FOO /usr/local/man/man1/${FOO#$(pwd)/}
    done
    cd ../man7
    for FOO in /Library/PostgreSQL/man/man7/*; do
    sudo ln -s $FOO /usr/local/man/man7/${FOO#$(pwd)/}
    done
  8. Zsh-Benutzer werden sollten an dieser Stelle einmal rehash aufrufen, damit die Shell die Binaries in /usr/local/binfindet.Ergänzung: Sollten es beim erstellen der Symlinks zu Fehlermeldungen kommen, so könnte es sein, daß die Verzeichnisse /usr/local/bin, /usr/local/man/man1 oder /usr/local/man/man7 nicht exisitieren. Lege diese dann an und führe das Skript zum erstellen der Symlinks erneut aus.
  9. Nun wird es an der Zeit, auch eine Datenbank anzulegen, oder einen Cluster, wie es im PostgreSQL-Slang heißt.Wie ich bereits am Anfang erwähnte, soll die Datenbank in /Users/Shared/PostgreSQL liegen. Dazu muß das Verzeichnis erst existieren. Lege das Verzeichnis mit folgendem Befehl an.
    sudo mkdir -p /Users/Shared/PostgreSQL
    sudo chown postgres:postgres /Users/Shared/PostgreSQL

    Und jetzt initialisiere die Datenbank mit initdb.

    sudo -u postgres initdb -U dba -A md5 -E UTF8 -W -D /Users/Shared/PostgreSQL/data

    Nun sollte erstmal ein Haufen Zeilen über den Bildschirm huschen. An einer Stelle wirst du nach dem Passwort für den Admin (in diesem Fall habe ich den Admin „dba“ genannt) gefragt. Gib dort ein Passwort ein, aber vergiß es hinterher nicht!

    The files belonging to this database system will be owned by user "postgres".
    This user must also own the server process.
    
    The database cluster will be initialized with locale C.
    
    creating directory /Users/Shared/PostgreSQL/data ... ok
    creating directory /Users/Shared/PostgreSQL/data/global ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_xlog ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_xlog/archive_status ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_clog ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_subtrans ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_twophase ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_multixact/members ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_multixact/offsets ... ok
    creating directory /Users/Shared/PostgreSQL/data/base ... ok
    creating directory /Users/Shared/PostgreSQL/data/base/1 ... ok
    creating directory /Users/Shared/PostgreSQL/data/pg_tblspc ... ok
    selecting default max_connections ... 50
    selecting default shared_buffers ... 300
    creating configuration files ... ok
    creating template1 database in /Users/Shared/PostgreSQL/data/base/1 ... ok
    initializing pg_authid ... ok
    Enter new superuser password: Hier das Passwort eingeben
    Enter it again: und hier nochmal wiederholen
    setting password ... ok
    enabling unlimited row size for system tables ... ok
    initializing dependencies ... ok
    creating system views ... ok
    loading pg_description ... ok
    creating conversions ... ok
    setting privileges on built-in objects ... ok
    creating information schema ... ok
    vacuuming database template1 ... ok
    copying template1 to template0 ... ok
    copying template1 to postgres ... ok
    
    Success. You can now start the database server using:
    
        postmaster -D /Users/Shared/PostgreSQL/data
    or
        pg_ctl -D /Users/Shared/PostgreSQL/data -l logfile start
  10. Damit der Server auch ein Log anlegt, was uns bei Problemen hilfreich sein könnte, mußt du noch ein Verzeichnis in /var/loganlegen. Der postgres-Benutzer muß Schreibrechte für dieses Verzeichnis besitzen. Dies geht am besten mit diesen Befehlen:
    sudo mkdir /var/log/pgsql
    sudo chown postgres /var/log/pgsql

    Damit sollte das Verzeichnis für den PostgreSQL-Server beschreibbar sein, damit dieser uns seine Befindlichkeiten mitteilen kann. Falls du ein anderes Verzeichnis verwenden möchtest, so muß der Pfad entsprechend in der launchd-Konfigurationsdatei aus dem nächsten Schritt auch geändert werden.

  11. Nun könntest du zwar den Server, wie oben beschrieben, starten, doch dies würde nur bis zum nächsten Reboot halten. Da muß was dauerhaftes her. Dazu braucht Mac OS X Tiger eine Konfigurationsdatei für den launchd. Meine sieht so aus. (Im Grunde ist sie unverändert aus der Anfangs erwähnten englischen Anleitung)
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"  "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict>     <key>Label</key>     <string>org.postgresql.postmaster</string>     <key>OnDemand</key>     <false/>     <key>ProgramArguments</key>     <array>         <string>/Library/PostgreSQL/bin/postmaster</string>         <string>-D</string>         <string>/Users/Shared/PostgreSQL/data</string>         <string>-c</string>         <string>redirect_stderr=YES</string>         <string>-c</string>         <string>log_connections=YES</string>         <string>-c</string>         <string>log_directory=/var/log/pgsql</string>         <string>-c</string>         <string>log_filename=postgres_log</string>     </array>     <key>ServiceDescription</key>     <string>PostgreSQL Server</string>     <key>UserName</key>     <string>postgres</string> </dict> </plist> 

    Speichere diese Datei als org.postgresql.postmaster.plist und kopiere sie dann nach /Library/LaunchDaemons. Hier auch direkt zum herunterladen.

    Diese Datei benötigt Mac OS X in /Library/LaunchDaemons, damit der PostgreSQL-Server beim booten mitgestartet wird. Von Hand kann nun der Server mit folgenden Befehlen gestartet werden:

    sudo launchctl load /Library/LaunchDaemons/org.postgresql.postmaster.plist
    sudo launchctl start org.postgresql.postmaster
  12. Der Server sollte nun eigentlich laufen. Ein ps ax | egrep "post(master|gres)"sollte ungefähr folgendes Bild ergeben:
      1825  ??  Ss     0:00.29 /Library/PostgreSQL/bin/postmaster -D /Users/Shared/PostgreSQL/data
    -c redirect_stderr=YES -c log_connections=YES -c log_directory=/var/log/pgsql -c log_filename=postgres_log
      1827  ??  S      0:00.02 postgres: logger process
      1829  ??  R      0:00.08 postgres: writer process
      1830  ??  S      0:00.00 postgres: stats buffer process
      1831  ??  S      0:00.01 postgres: stats collector process

    Der Server läuft also. In /var/log/pgsql sollte sich nun auch ein Logfile wiederfinden. Schau darin nach, ob auch alles reibungslos gelaufen ist. Sollten sich Probleme ergeben, so ist das Logfile die erste Anlaufstelle, um Hinweise zur Lösung zu finden. Mein Logfile sieht so aus:

    LOG:  database system was shut down at 2006-05-03 08:22:15 CEST
    LOG:  checkpoint record is at 0/33E75C
    LOG:  redo record is at 0/33E75C; undo record is at 0/0; shutdown TRUE
    LOG:  next transaction ID: 567; next OID: 10793
    LOG:  next MultiXactId: 1; next MultiXactOffset: 0
    LOG:  database system is ready
    LOG:  transaction ID wrap limit is 2147484148, limited by database "postgres"

    Wir können also eine erste Kontaktaufnahme zum Server wagen. Da wir beim initdb keinen Benutzernamen als Datenbankadministrator angegeben haben, ist der Name des Datenbankadministrators „postgres“. Um also als Datenbankadministrator eine Verbindung zur Datenbank aufzubauen, gib folgenden Befehl ein: psql -U dba template1. PostgreSQL sollte nun nach dem Passwort fragen, was wir beim initdb (s. Punkt 9) festgelegt haben. Nach erfolgreicher Authentifizierung, sollte uns der Prompt des Komandozeilenclients für PostgreSQL begrüßen:

    Welcome to psql 8.1.3, the PostgreSQL interactive terminal.
    
    Type:  \copyright for distribution terms
           \h for help with SQL commands
           \? for help with psql commands
           \g or terminate with semicolon to execute query
           \q to quit
    
    template1=#

    Da wir noch keine eigenen Datenbanken angelegt haben, wird sich die Beispielquery auf eine unspektakuläre Addition beschränken. Gib am Prompt folgendes ein: select 1+1; (Das Semikolon darf hier nicht weggelassen werden). PostgreSQL sollte nun so antworten:

     ?column?
    ----------
            2
    (1 row)

    Damit ist klar, daß 1 + 1 = 2 ist, und daß PostgreSQL rechnen kann.

  13. Die folgenden Schritte sind optional und eher für Anfänger empfohlen, um sich ein wenig mit PostgreSQL vertraut zu machen. Fortgeschrittene können den Rest getrost überspringen.Nun wollen wir erstmal eine neue Datenbank anlegen, in der wir auch arbeiten können. Du solltest nicht versuchen, Datenbanken in der template1-Datenbank anzulegen. Diese Datebank wird als Vorlage bei jedem „create database“ benutzt. Alles was in dieser Datenbank also angelegt wird, wird in jede neu erstellte Datenbank kopiert, was nicht unbedingt gewünscht ist.Eine neue Datebank kann man entweder von der Shell mit „createdb“ oder im PostgreSQL-Client mit „create database“. Da wir noch im PostgreSQL-Client (hoffentlich) drin sind, können wir also schnell eine Datenbank mit create database testdb; anlegen. Der Client sollte dies mit einem „CREATE DATABASE“ bestätigen. Wechsel nun zu dieser Datenbank mit \connect testdb. Der Prompt sollte nun den Namen der neuen Datenbank anzeigen.
  14. Legen wir also nun eine Tabelle in unserer neuen Datebank an.
    create table testtable
    id serial,
    somestring varchar(20),
    primary key(id)
    );

    PostgreSQL wird nun einige Meldungen ausgeben und zum Schluß mit „CREATE TABLE“ bestätigen, daß eine neue Tabelle angelegt wurde. Hier gibt es einige PostgreSQL-Besonderheiten zu beachten (besonders für MySQL-Umsteiger). PostgreSQL wandelt Tabellen- und Spaltennamen standardmäßig in Kleinbuchstaben um, wenn sie nicht nicht explizit in doppelte Anführungszeichen setzt. Hätten wir also „create table TestTable…“ geschrieben, wäre trotzdem nur eine Tabelle mit dem Namen „testtable“ angelegt worden. Wollten wir tatsächlich eine Tabelle „TestTable“ anlegen, so hätten wir „create table "TestTable"…“ schreiben müssen.

  15. Die Tabelle ist im Augenblick noch leer. Fügen wir also ein paar Datensätze ein.
    insert into testtable (somestring) values ('foo');
    insert into testtable (somestring) values ('bar');
    insert into testtable (somestring) values ('baz');
    insert into testtable (somestring) values ('qux');
  16. Um die Daten auch wieder aus der Tabelle herauszuholen, führen wir select * from testtable;aus. PostgreSQL sollte mit dem Inhalt der gesamten Tabelle antworten.
     id | somestring
    ----+------------
      1 | foo
      2 | bar
      3 | baz
      4 | qux
    (4 rows)

Damit läuft PostgreSQL nun auf auf deinem Mac. Jetzt kannst du es mit sinnvollen Daten füllen.

Nachtrag: Folgender Alias für die Shell hat sich als recht nützlich erwiesen: alias pg_ctl='sudo -u postgres pg_ctl'.

Mit Array in PostgreSQL herumhantieren

Ich brauchte bei einer Abfrage einfach nur die beteiligten Mitarbeiter. Eine einfache Auflistung der Namen reichte mir da. Mit PostgreSQL kann man sowas recht einfach erledigen.

SELECT array_to_string(ARRAY['foo', 'bar', 'baz', 'qux'], ', ');
  array_to_string
--------------------
 foo, bar, baz, qux
(1 row)

Das Array wird als String mit jeweils dem zweiten Parameter aus array_to_string() verkettet. Ist viel einfacher als in der Skriptsprache (PHP, Ruby, Perl) die Rows miteinander zu verketten.

Nachtrag: Und bevor jetzt einer fragt, wie das nun mit Rows aus einer Abfrage geht, hier ein Beispiel. Ich habe diese Tabelle

test=# SELECT * from test_table;
 id | some_string
----+-------------
  1 | foo
  2 | bar
  3 | baz
  4 | qux
(4 rows)

Und nun zu einer Row verkettet:

test=# SELECT array_to_string(ARRAY(SELECT some_string FROM test_table WHERE id<4), ', ');
 array_to_string
-----------------
 foo, bar, baz
(1 row)

Notiz an mich selbst: PostgreSQL ACLs

Damit ein Benutzer auf eine Tabelle zugreifen darf, muß ihm dieses privileg erst eingeräumt werden. Soweit nix neues. Allerdings sollte man bei PostgreSQL nicht vergessen dem User auch Rechte auf etwaige Sequenzen zu geben, sonst schlägt ein nextval(footable_id_seq) fehl und damit der ganze Insert. Also immer schön ein GRANT SELECT, UPDATE ON footable_id_seq TO foouser; nachschieben.

(Das UPDATE ist nötig, damit beim nextval die Sequenz auch hochgezählt wird.)

PostgreSQL auf OpenBSD

Für die Installation von Movable Type auf OpenBSD brauchte ich eine Datenbank. Die Wahl fiel auf PostgreSQL. Hier ist was ich tat, um PostgreSQL nach meinen Vorstellungen zu konfigurieren.

Diese Anleitung ist an einigen Stellen OpenBSD-spezifisch. Bei Linux muß logrotate statt newsyslog benutzt werden.

Zuerst muß man den Quelltext herunterladen und an geeigneter Stelle extrahieren. Den Quelltext kompilieren und die fertigen Programme zu installieren funktioniert mit dem üblichen GNU-Dreisatz: (die letzte Zeile sollte man als root aufrufen)

./configure—prefix=/usr/local—with-perl—with-openssl=/usr
make
make install

Damit hat man schon mal alle nötigen Programme installiert. PostgreSQL braucht aber noch einige Vorarbeit, um zu funktionieren. PostgreSQL möchte unter einem eigenen Benutzer laufen. Die folgenden Zeilen legen diesen Benutzer samt passender Gruppe an. (natürlich als root)

groupadd -g 164 pgsql
useradd -c “PostgreSQL Admin User” -d /var/pgsql -g 164 -u 164 -s /bin/sh pgsql

Nun fehlt noch das Datenbankverzeichnis, in dem PostgreSQL seine Daten ablegt. Dieses Verzeichnis sollte dem PostgreSQL-Benutzer gehören.

mkdir /var/pgsql
chown pgsql:pgsql /var/pgsql
chmod 755 /var/pgsql

Jetzt muß die Datenbank initialisiert werden. Da alle Dateien im Datenbankverzeichnis dem PostgreSQL-Benutzer gehören sollten, sollte dies als der PostgreSQL-Benutzer geschehen.

su pgsql
/usr/local/bin/initdb -D /var/pgsql/data

Damit ist die Datenbank im Grunde fertig und kann benutzt werden. Es fehlen aber noch einige Kleinigkeiten, damit das alles rund läuft.

Zuerst soll PostgreSQL beim Booten gestartet werden. Die nächsten Zeilen sollten an passender Stelle in die /etc/rc.local aufgenommen werden: (wieder als root)

if [ -x /usr/local/bin/pg_ctl ]; then
        su -l pgsql -c “/usr/local/bin/pg_ctl start \
                -D /var/pgsql/data -l /var/pgsql/logfile”
        echo -n ‘ postgresql’
fi

Natürlich soll PostgreSQL beim Herunterfahren von OpenBSD sauber beendet werden, um inkonsistenzen in der Datenbank zu verhindern. Dies erledigen diese Zeilen in der /etc/rc.shutdown:

if [ -f /var/pgsql/data/postmaster.pid ]; then
        su -l pgsql -c “/usr/local/bin/pg_ctl stop \
                -D /var/pgsql/data”
        echo -n ‘ postgresql’
fi

PostgreSQL soll über syslogd(8) loggen. Das macht es einfacher, auf einem zentralen Logging-Host zu loggen. Hier müssen in der /var/pgsql/data/postgresql.conf 3 Zeilen angepasst werden. Die Zeilen stehen schon in der Datei drin, sind jedoch auskommentiert.

syslog = 2                      # range 0-2; 0=stdout; 1=both; 2=syslog
syslog_facility = ‘LOCAL0’
syslog_ident = ‘postgres’

Selbverständlich muß der syslogd(8) auch wissen, was er mit den Daten anfangen soll. Darum kümmert sich diese Zeile in der /etc/syslog.conf:

local0.*                                                /var/log/pgsql

Bevor der syslogd(8) nun restarted wird, damit er anfangen kann zu loggen, sollte noch ein leeres Logfile angelegt werden, da der syslogd(8) dies in der Regel nicht tut. Mit touch /var/log/pgsql entsteht ein leeres Logfile an. Schicke ein SIGHUP an syslogd(8) um ihn zu restarten.

Die Logfiles sollten noch in regelmäßigen Abständen rotiert werden, damit das Dateisystem nicht überläuft. Bei OpenBSD kümmert sich newsyslog(8) um das Rotieren von Logfiles. Eine Zeile in der /etc/newsyslog.conf erledigt dies:

/var/log/pgsql                          640  7    *    168   Z

Damit ist PostgreSQL nun bereit zum Einsatz. Um den Server nun endlich zu starten, kann der gleiche Code benutzt werden, wie er auch in der /etc/rc.local steht. Viel Spaß mit PostgreSQL.