Dalitz Datenbanksysteme SS 2017 Praktikumsaufgabe 2 Fassung B (für motivierte Studenten) Lernziele Wiederholung und tieferes Verständnis der in EPR/OOA behandelten C/C++-Programmierung. Vergleich von embedded SQL und eines nativen Call Level Interfaces. Erarbeiten einer Abstraktion des Zugriffs mit Mitteln der modularen Programmierung. Vorbereitung Folgende Informationen müssen Sie zum Antestat bereithalten: • Wie können in einem C++-Programm die Funktionsdefinitionen auf mehrere Sourcedateien verteilt werden? Welche Schritte werden bis zur Erstellung des Executables durchlaufen? (Wiederholung EPR) • Wie funktioniert Compilieren und Linken mit dem gcc? Wie werden Bibliotheken verwendet? ([1] Kap. 12) • Wie kann die Projektverwaltung mit einem Makefile automatisiert werden? ([1] Kap. 12) • Legen Sie ein Konzept zur Kapselung des DB-Zugriffs vor. Dasselbe Hauptprogramm muss funktionieren, unabhängig davon ob der Low-Level Datenbankzugriff über ecpg ([3] p. 296 ff) oder libpq ([2] Kap. 9.1) erfolgt. • Legen Sie für Ihr Konzept ein Makefile vor. Aufgabe Es soll ein C++-Programm “dbimp” geschrieben werden, das Daten aus einer Datei in eine Datenbanktabelle hersteller einspielt. Parallel sollen zwei Programme entwickelt werden: bei dbimp-ecpg erfolgt der DB-Zugriff über embedded SQL (ecpg) und bei dbimp-libpq über libpq. Das Hauptprogramm soll in beiden Fällen dieselben Funktionen aufrufen, deren Prototypen in der bereitgestellten Datei db.h deklariert sind: • db login - Datenbanklogin • db logout - Datenbanklogout • db begin, db commit, db rollback - Transaktionsbefehle • db findhnr - Gibt zurück, ob Herstellernummer schon vorhanden • db insert - Einfügen Datensatz • db delete - Löscht kompletten Tabelleninhalt Diese Funktionen sind dann für jede Programmvariante in getrennten Modulen zu implementieren. 1 Dalitz Datenbanksysteme SS 2017 Kommandozeilenoptionen Die Programme sollen folgendermaßen aufgerufen werden: Usage: dbimp-ecpg [options] <infile> dbimp-libpq [options] <infile> Options: -del delete table contents before import -u database user -p password -h database host -d database name For unset options, the usual PostgreSQL environment (PGUSER, PGPASSWORD, PGHOST, PGDATABASE) takes effect Die Reihenfolge der Optionen ist egal. Bei fehlerhaftem Aufruf (kein infile oder unbekannte, mit ’-’ beginnende Option) wird die obige Meldung ausgegeben und abgebrochen. Zieltabelle und Dateiformat Die Zieltabelle hersteller müssen Sie von Hand per SQL anlegen mit folgenden Feldern: Feld Typ hnr# varchar(3) name varchar(30) plz varchar(5) ort varchar(30) Die Import-Datei enthält pro Zeile einen Datensatz, wobei die einzelnen Felder durch ; getrennt sind. Die Felder stehen in der Reihenfolge hnr, name, plz, ort. Funktionalität dbimp soll sich wie folgt verhalten: • Der ganze Import erfolgt in einer Transaktion: bei Erfolg commit und bei einem Fehler Abbruch und rollback. • Vor dem insert wird anhand des Schlüsselfelds überprüft, ob der Datensatz schon in der Datenbank vorhanden ist. Wenn ja, wird der Satz nicht importiert. • Wenn über die Option -del gewünscht, wird vor dem Import der Tabelleninhalt gelöscht (innerhalb der Transaktion). Am Ende gibt das Programm eine Importstatistik aus mit der Gesamtzahl der gelesenen Datensätze und der Anzahl der davon importierten Sätze. Test Sie können Ihr Programm überprüfen anhand der Testdaten [4]. Hier die Sollergebnisse beginnend mit einer leeren Tabelle hersteller: Kommando dbimp data1 dbimp data2 dbimp -del data2 dbimp data3 Datensätze/ davon importiert 3/3 2/3 3/3 Abbruch wegen Fehler in Zeile 2 von data3 2 Anzahl Tabellensätze nach dem Import 3 5 3 3 Dalitz Datenbanksysteme SS 2017 Hinweise zur C++-Programmierung • Wichtige Kommandozeilenoptionen für den gcc sind -g (enable debugging), -c (Compilieren ohne Linken), -I (weiteres Suchverzeichnis für Include-Dateien), -o (Outputfile beim Linken) und -L (weiteres Suchverzeichnis für Libraries beim Linken). • Um gegen die PostgreSQL-Library libpq zu linken, müssen Sie beim Linken am Ende die Option -lpq angeben. Um gegen die ESQL-Library zu linken, müssen Sie die beim Linken die Option -lecpg angeben. Um gegen die STL zu linken (z.B. nötig für den Datentyp string), müssen Sie die Option -lstdc++ verwenden. • Das Verzeichnis mit den Postgres-Includedateien liefert der Befehl pg config --includedir, das Verzeichnis mit den Link-Libraries der Befehl pg config --libdir. • In embedded SQL können Sie den Login nur über getrennte Übergabe von User und Passwort machen: EXEC SQL CONNECT TO :target USER :user/:password; • Eine Umgebungsvariable können Sie mit der Funktion getenv() aus stdlib.h auslesen. man getenv gibt genauere Informationen dazu. • Komplette Zeilen können Sie einlesen mit der Funktion fgets(). Zum Zerlegen der Inputzeilen können Sie strtok() oder -besser- strsep() verwenden. Alternativ können Sie auch den Tokenizer aus der OOA-Vorlesung verwenden, wobei Sie für die Liste den STL-Container list oder vector verwenden. • Um Buffer-Overflows zu vermeiden, verwenden Sie nach Möglichkeit die STL-Klasse string. Diese kann man auch an die libpq-Funktionen übergeben, die ein const char* als ARgument erwarten (wie?). • Zum Debuggen können Sie den “Data Display Debugger” ddd verwenden. ddd ist ein grafisches Frontend zum gdb. Im unteren Fenster des ddd können Sie auch direkt Kommandos an den gdb absetzen, ohne sich durch unzählige Menüs hangeln zu müssen. Nützliche gdb-Kommandos sind run arg1 arg2 ... (Startet Programm mit angegebenen Argumenten), print var (druckt Inhalt der Variablen var aus) und list file:line (öffnet direkt Datei file und springt an Zeile line). Referenzen [1] Welsh, Kaufmann: Linux - Wegweiser zur Installation&Anwendung. Semesterapparat (TWR Wels) [2] The PostgreSQL Global Development Group: PostgreSQL 9.1.8 Dokumentation. http://www.postgresql.org/docs/ (2013) Kapitel “Client Interfaces, libpq” [3] Geschwinde, Schönig: PostgreSQL Developer’s Handbook. Semesterapparat (TWY Geschw) 3 Dalitz Datenbanksysteme SS 2017 [4] Die Testdaten unter http://informatik.hsnr.de/∼dalitz/data/lehre/DBS/aufg2dat.tar können Sie mit dem Befehl tar xf ... entpacken. Dort liegt auch die Header-Datei db.h und das Makefile Makefile.2b. 4