Datenbank mit C - Teil 1
-
Inhaltsverzeichnis
1 Vorbemerkung
2 MySQL installieren und starten2.1 Linux
2.2 Windows
2.3 Client starten3 Kurze Einführung in SQL
4 MySQL C-API1 Vorbemerkung
Dieser Artikel handelt von der Datenbank-Programmierung in der Programmiersprache C.
Ziel dieses Artikels ist es, eine Datenbankverbindung zu MySQL herzustellen und die
SQL-Befehle auf die Datenbank anzuwenden. Es geht in erster Linie also nicht um SQL selbst.
Hier wird nur eine kurze Einführung gegeben. Wer sich mehr mit dieser Datenbank-Abfragesprache
beschäftigen will, sei auf die Dokumentation von der MySQL-Webpage verwiesen.
Die Beispiele sollten bei den MySQL-Versionen 4.0, 4.1 und 5.0 funktionieren.2 MySQL installieren und starten
2.1 GNU/Linux
Da MySQL Bestandteil von jeder GNU/Linux-Distribution ist, sollte es mit der Installation
auch kaum Probleme geben. Bitte folgende Pakete installieren:- mysql
- mysql-client
- mysql-devel - die Include-Dateien
- mysql-bench
- mysql-shared
Sie benötigen root-Rechte, um den Server zu starten. Unter Red Hat starten Sie den Server mit
# /etc/rc.d/init.d/mysql start
sollte auch mit SuSE funktionieren, dort geht aber auch
# rcmysql start.
oder wie bei Debian
# /etc/init.d/mysql start
Kommt darauf an, welche Distribution und/oder Versionsnummer vorliegt.
2.2 Windows
Im Gegensatz zu GNU/Linux werden Sie wohl hier die MySQL-Binaries herunterladen müssen. Gehen Sie zu der
MySQL-Webpage und laden Sie dann die Binary-Version herunter.
Ich habe mir die Windows Essential(x86)-Version 4.1.22 heruntergeladen.Jetzt haben Sie eine msi-Datei auf Ihrem Rechner. Um MySQL zu installieren, müssen Sie sich als Administrator anmelden.
Die Datei aufrufen.Hier Custom wählen.
Mit der linken Maustaste auf das Icon bei "C Include Files/Lib Files klicken" und beim Auswahlmenü "alles installieren mit Unterverzeichnisse" anwählen.
Für diejenigen, die den Lcc-win32-Compiler benutzen, bitte das Installationsverzeichnis in einem Wort angeben, also: C:\Programme\MySQL\MySQLServer41.
Könnte sonst evtl. Probleme geben.Diese Einstellung wählen. Im nächsten Fenster "Standard Configuration" wählen.
Mit diesen Einstellungen wird MySQL als Systemdienst gestartet und in den Suchpfad eingetragen.
Sie können am Ende der Installation für root auch ein Passwort vergeben, müssen es aber nicht.
Nach der Installation die libmySQL.dll in ein Systemverzeichnis kopieren, am besten nach C:\Windows\system32Danach starten Sie den Server unter Windows NT und 2000 mit
NET USE MySQL
.
Stoppen mitNET STOP MySQL
Um MySQL als Systemdienst unter Windows NT oder 2000 zu installieren (falls noch nicht geschehen):
C:\Programme\MySQL\MySQL Server 4.1\bin\mysqld-nt --install
oder
C:\Programme\MySQL\MySQL Server 4.1\bin\mysqld-max-nt --install
Starten mit Windows 98
C:\Programme\MySQL\MySQL Server 4.1\bin\mysqld
stoppen
C:\Programme\MySQL\MySQL Server 4.1\bin\mysqladmin -u root -shutdown
Falls bei Ihnen kein mysql-Verzeichnis unter C: angelegt wurde, kann der Pfad auch wie oben bei der Installation gezeigt
C:\Programme\MySQL\MySQL Server <Versionsnummer>
sein. Manchmal wird MySQL auch standardmäßig nach C:\mysql installiert.
2.3 Client starten
Öffnen Sie eine Kommandozeile bzw. ein Terminal und geben Sie folgendes ein:
# mysql -u root -h localhost
Jetzt sollten Sie mit
mysql>
den Eingabecursor vor sich haben. Geben Sie einfach mal
USE mysql;
ein, danach
SELECT user, host, password FROM user;
und schauen sich das Ergebnis an. Das war nur ein erster Test. Alles weitere
über Abfragen usw. im nächsten Abschnitt. Mit \q beenden Sie den Client wieder.3 Kleine Einführung in SQL
MySQL ist eine relationale Datenbank. Dieser Begriff wurde von Edgar F. Codd in den 1970er Jahren geprägt.
1985 hat Codd 12 Grundregeln aufgestellt, die ein relationales Datenbanksystem erfüllen muss. Das Datenmodell
basiert auf den mathematischen Grundlagen der relationalen Algebra und bietet dem Anwender ein Höchstmaß
an Flexibilität, im Vergleich zu anderen Methoden der Datenspeicherung.
z.B.Alle Daten (Anwender- wie auch Systemdaten) in einer relationalen Datenbank werden logisch als
Zeilen in einer Tabelle dargestellt. Somit besteht aus der Benutzersicht jede relationale
Datenbank nur aus Tabellen.Eine Zeile in einer Datenbanktabelle wird als Datensatz bezeichnet.
Eine Spalte als Attribut, z.B. Vorname.Die Daten in den Tabellen stehen in bestimmten Beziehungen zu einander. Ein Schulungsunternehmen hat in
verschiedenen Orten Schulen zur Weiterbildung. Es besteht je eine Tabelle für Schulen, Dozenten,
Teilnehmer und Kurse.1:1-Beziehung: eine Schule hat einen Dozenten als Leiter.
1:n-Beziehung: eine Schule hat mehrere Dozenten, die dort lehren.
n:m-Beziehung: mehrere Teilnehmer nehmen an mehreren Kursen Teil, oder
mehrere Dozenten unterrichten mehrere Kurse.Structured Query Language (SQL) ist eine speziell für relationale Datenbanken entwickelte nonprozedurale
Abfragesprache, deren Anweisungen einer standardisierten Syntax entsprechend als Zeichenkette ausgedrückt
werden kann. SQL-Anweisungen können auch in prozedurale Programmiersprachen - z.B. C - eingebettet werden
(Embedded SQL).Die SQL-Sprachdefinition umfasst drei Anweisungsgruppen:
Datendefinition (Data Definition Language)
Anweisungen zur Verwaltung von Datenbankstrukturen.
Beispiel: Erstellen oder ändern einer TabelleDatenmanipulation (Data Manipulation Language)
Anweisungen zur Bearbeitung der Daten, die vom
Datenbanksystem verwaltet werden.
Beispiel: Neuaufnahme oder Suchen eines DatensatzesDatenkontrolle (Data Control Language)
Anweisungen zur Vergabe bzw. zum Entzug von Zugriffsrechten und zur
Transaktionssicherung
Beispiel: Vergabe des Rechts, Daten in einer Tabelle zu ändern.Auch in MySQL gibt es Datentypen, ähnlich einer Programmiersprache. Hier eine Übersicht aus dem Referenzmanual
von MySQL. Wenn Sie ZEROFILL für eine Spalte angeben, fügt MySQL automatisch der Spalte ein UNSIGNED-Attribut zu.
Folgende Codebuchstaben werden in der Beschreibung benutzt:
* M
Gibt die maximale Anzeigebreite an. Die größte erlaubte Anzagebreite ist 255.
* D
Trifft auf Fließkomma-Typen zu und bezeichnet die Anzahl von Ziffern nach dem
Dezimalpunkt. Der größte mögliche Wert ist 30, sollte aber nicht größer sein als
M-2.Ganzzahlen (Integer)
TINYINT[(M)] 1 Byte
-128 bis 127, UNSIGNED 0 bis 255SMALLINT[(M)] 2 Byte
-32768 bis 32767, UNSIGNED 0 bis 65536MEDIUMINT[(M)] 3 Byte
-83886008 bis 83886007, UNSIGNED 0 bis 16777215INT(M), INTEGER[(M)] 4 Byte
-2147483648 bis 2147483647, UNSIGNED 0 bis 4294967296BIGINT[(M)] 8 Byte
-9223372036854775808 bis 9223372036854775807
UNSIGNED 0 bis 18446744073709551616Gleitpunktzahlen
FLOAT[(M,D)] 4 Byte
-3.402823466E+38 bis 1.175494351E-38 und
1.175494351E-38 bis 3.402823466E+38DOUBLE[(M,D)] 8 Byte
-1.7976931348623157E+308 bis -2.2250738585072014E-308 und
2.2250738585072014E-308 bis 1.7976931348623157E+308DECIMAL[(M[,D])] M Byte(M*8 Bit) Abhägig von M und D, z.B. DECIMAL(8,2)
Zeichen und Strings
CHAR(M) M Anzahl Zeichen, Zeichenkette fester Länge 1 bis max 255 Zeichen
VARCHAR(M) M+1 Anzahl Zeichen, Zeichenkette variabler Länge 1 bis max 255 Zeichen
TINYTEXT, TINYBLOB Zeichenzahl+1 Byte, Zeichenkette variabler Länge bis max 255 Zeichen
TEXT, BLOB Zeichenzahl + 2 Byte, Zeichenkette variabler Länge bis max 65536 Zeichen
MEDIUMTEXT, MEDIUMBLOB Zeichenzahl+3 Byte, Zeichenkette mit variabler Länge bis max 2h24 Zeeichen
LONGTEXT, LONGBLOB Zeichewnzahl+4 Byte, Zeichenkette mit variabler Länge bis max 2h32 Zeichen
Datum und Zeit
DATE 3 Byte, Datum von 1000-01-01 bis 9999-12-31, Format YYYY-MM-DD
DATETIME 8 Byte, Datum und Zeit
von 1000-01-01 00:00:00 bis 9999-12-31 23:59:59, Format YYYY-MM-DD HH:MM:SSTIMESTAMP[(M)] 4 Byte, UNIX-Zeitstempel von Datum und Zeit
von 1970-01-01 00:00:00 bis 2036-12-31 23:59:59
Format YYYY-MM-DD HH:MM:SS Format M = 6 YYMMDD
M = 8 YYYYMMDD
M = 12 YYMMDDHHMMSS
M = 14 YYYYMMDDHHMMSSTIME 3 Byte, Zeit von -838:59:89 bis 838:59:59 Format HH:MM:SS
YEAR[(2|4)] 1 Byte
Jahr in 2- oder 4-Ziffernformat (Vorgabe ist 4-Ziffern)
Die zulässigen Werte reichen von 1901 bis 2155 sowie 0000
im 4-Ziffern-Jahresformat und von 1970 bis 2069 beim
2-Ziffernformat (70 bis 69).MySQL zeigt YEAR-Werte im YYYY-Format an,
gestattet aber YEAR-Spalten Werte als Zeichenketten oder als Zahlen zuzuweisenStarten Sie MySQL wie oben beschrieben - Server und Client. Bei einer Neuinstallation ist das root-Passwort nicht gesetzt.
Die Vergabe eines Passwortes bei GNU/Linux erfolgt über das Programm mysqladmin auf der Konsole.# mysqladmin -u root -h localhost password 'geheim'
Passwort geheim für den user root. Dann anmelden mit
mysql -u root -h localhost -p
Jetzt werden Sie aufgefordert das Passwort einzugeben.
Die Schreibweise der Befehle usw. in der Eingabeaufforderung von MySQL ist eigentlich egal, außer bei GNU/Linux, wo Sie sich an die
exakte Schreibweise für schon angelegte Datenbanken halten müssen. Standardmäßig legt MySQL zwei Datenbanken an: mysql und test.
mysql ist die System-Datenbank, dort werden User, Hosts, Passwörter und Zugriffsrechte verwaltet. Die Datenbank test ist leer.
Eine Befehlszeile wird immer mit einem Semikolon abgeschlossen. MitSHOW DATABASES;
können Sie sich alle vorhandenen Datenbanken anzeigen lassen.
CREATE DATABASE [IF NOT EXISTS] <Name_der_Datenbank>;
legen Sie eine neue Datenbank an. IF NOT EXISTS ist optional. Falls die Datenbank schon existiert wird keine Fehlermeldung ausgeben
und sie wird natürlich auch nicht nochmal angelegt:CREATE DATABASE IF NOT EXISTS weiterbildung;
Um mit der Datenbank weiterbildung zu arbeiten, müssen Sie zu ihr wechseln, das wird mit
USE weiterbildung;
erledigt.
DROP DATABASE [IF EXISTS] <Name_der_Datenbank>;
Löscht eine Datenbank, falls sie existiert:DROP DATABASE IF EXISTS weiterbildung;
Wenn Sie eine neue Datenbank angelegt haben, ist natürlich noch keine Tabelle vorhanden. Mit dem folgenden Befehl erzeugen Sie eine
Tabelle mit ihren Attributen:CREATE TABLE dozent ( d_nr SMALLINT UNSIGNED NOT NULL, d_vorname VARCHAR(20), d_nachname VARCHAR(20), d_gesch VARCHAR(1), d_gebdat DATE, d_besch SMALLINT UNSIGNED);
Mit d_nr haben wir einen Index als vorzeichenlosen Datentyp von SMALLINT definiert. NOT NULL besagt, dass er in jedem Fall
gefüllt werden muss.Die Tabelle wird folgendermaßen mit Werten gefüllt:
INSERT INTO dozent(d_nr, d_vorname, d_nachname, d_geschl, d_gebdat, d_besch) VALUES (1, 'Anna', 'Seger', 'w', '1955-04-13', 1);
Wichtig hierbei ist, dass unten genauso viele Werte im gleichen Format stehen, wie oben Spalten angegeben sind. Strings, die zu lang sind, werden abgeschnitten.
Mit
EXPLAIN dozent;
oder
DESC dozent;
können Sie die Tabellendefinition überprüfen.
Tabellen löschen Sie mit:
DROP TABLE [IF EXISTS] <tabelle_name>;DROP TABLE IF EXISTS dozent;
Tabellendefinition ändern
Nichts im Leben ist so perfekt, als dass man es im Nachhinein nicht noch verbessern könnte ;). Das trifft natürlich
auch auf Datenbanken zu. Weshalb es auch eine Reihe von Befehlen gibt, mit denen Sie im Nachhinein vorhandene Objekte
verändern können. Allerdings ist auch das, wie das Anlegen von Tabellen, eine komplexe Angelegenheit. Der Befehl zum
Bearbeiten der Tabellenstruktur lautet ALTER TABLE, dem der Name der zu verändernden Tabelle folgt. Anschließend
folgen die Schlüsselwörter ADD, MODIFY oder DROP, die zu dieser Tabelle ein neues Element hinzufügen,
eine bestehende Spalte ändern oder ein bereits existierendes Element löschen.ALTER TABLE <name_der_tabelle> { add { <spalten_name> <constraint_definition> } modify <name_der_spalte> <neue_definition> | drop { column | constraint } <name_des_elements> }
Beispiel:
ALTER TABLE dozent ADD d_firma VARCHAR(20);
Legt am Ende der Tabelle dozent eine Spalte d_firma an.
ALTER TABLE dozent ADD d_str VARCHAR(20) AFTER d_nr;
Legt eine Spalte d_str nach d_nr an.
ALTER TABLE dozent DROP d_str;
löscht die Spalte d_str wieder.
ALTER TABLE dozent DROP d_firma;
löscht die Spalte d_firma wieder.
ALTER TABLE dozent MODIFY d_gebdat VARCHAR(8);
ändert den Typ der Spalte von DATE in VARCHAR(8).
ALTER TABLE dozent MODIFY d_gebdat DATE;
und wieder zurück.
Solange eine Tabelle leer ist, kann man eigentlich jede Spalte in jeden beliebigen Datentyp umwandeln. Ansonsten muss
der neue Datentyp natürlich zum alten passen, bzw. die Konvertierung muss im Datenbankstandard enthalten sein, damit
hinterher auch etwas vernünftiges herauskommt.
Die Verlängerung eines Datentyps (z.B. von VARCHAR(10) nach VARCHAR(20)) ist in der Regel immer problemlos möglich.
Das gilt auch, wenn ein Datentyp in einen höherwertigen konvertiert wird (z.B. SMALLINT nach INT oder VARCHAR(200)
nach TEXT).
Verkürzungen eines Datenfeldes ist, sofern überhaupt zulässig, immer mit einem Risiko verbunden. Hierbei können
Daten verloren gehen. Das Verkürzen ist meistens nur erlaubt, wenn die Spalte noch keine Daten enthält.Struktur einer Auswahlabfrage
Im Prinzip besitzt eine Auswahlabfrage eine sehr einfache Struktur und besteht in ihrer Grundform aus zwei bis vier Abschnitten.SELECT <auswahlliste> [FROM <tabellenliste>] [WHERE <auswahl- und verknüpfungsbedingungen>] [ORDER BY <sortierbedingungen>]
Der erste Abschnitt ist zwingend und wird mit Hilfe des Befehls SELECT eingeleitet. Danach folgt eine Liste der gewünschten
Datenfelder und Ausdrücke, d.h., im Rahmen einer solchen Auswahlabfrage können nicht nur Tabellenspalten, sondern auch
komplexe Berechnungen durchgeführt oder ausgegeben werden.SELECT * FROM dozent;
gibt die gesamte Tabelle Dozent aus.
SELECT d_vorname, d_nachname, d_gebdat FROM dozent;
gibt nur d_vorname, d_nachname, d_gebdat der Tabelle Dozent aus.
SELECT * FROM dozent ORDER BY d_vorname ASC
gibt die gesamte Tabelle Dozent aufsteigend(ASC) sortiert nach d_vorname aus.
SELECT * FROM dozent, schule WHERE d_besch=2 AND s_nr=2 ORDER BY d_nachname ASC
Gibt von den Tabellen dozent und schule alles aufsteigend aus, was d_besch=2 und s_nr=2 ist.
Um einen neuen User in MySQL anzulegen, gibt es zwei Möglichkeiten. Sie melden sich als root bei mysql an, wechseln zur
Systemdatenbank mysql (USE mysql;) und fügen einen neuen user mittels dem SQL-Befehl INSERT in die user-Tabelle ein:INSERT INTO user (user, host, password) VALUES('thomas', 'localhost', PASSWORD('streng_geheim'));
Jetzt gibt es einen neuen User der keine Rechte besitzt. Rechte auf Datenbanken und Tabellen werden mit GRANT
vergeben und mit REVOKE wieder genommen.
Rechte für den neu angelegten User thomas mit GRANT:GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP ON weiterbildung TO thomas@localhost;
.
Damit haben Sie die genannten Rechte an der Datenbank weiterbildung an den User thomas vergeben.
Das können wir auch einfacher haben. Die bevorzugte Methode ist es, den Befehl GRANT direkt zur Vergabe der Rechte und
zum Anlegen des Users zu verwenden.GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON weiterbildung TO thomas@localhost IDENTIFIED BY 'streng_geheim';
Hiermit haben Sie dann mehrere Fliegen mit einer Klatsche geschlagen. Es wurde ein neuer User, nämlich thomas angelegt, und
ihm direkt ein Passwort und die Rechte vergeben. Anschließend sollteFLUSH PRIVILEGES;/code] aufgerufen werden. Passwörter können auch mit SET PASSWORD gesetzt werden. [code]SET PASSWORD FOR root=PASSWORD('noch_ein_bisschen_geheimer');
ist eine Alternative zu dem am Anfang vorgestellten mysqladmin-code.
Mit REVOKE können Sie den Benutzern Ihre Rechte entziehen:
REVOKE DROP,DELETE ON weiterbildung FROM thomas;
entzieht dem Benutzer thomas die Rechte DROP und DELETE an der Datenbank weiterbildung.
Sie müssen jetzt nicht unbedingt auf der sehr 'kargen' Eingabeaufforderung von MySQL eine Unmenge von Datenbanken
und/oder Tabellen erzeugen. Starten Sie einfach Ihren Lieblingseditor und erstellen Sie eine Datenbank mit Tabellen und Werten.
Z.B.:CREATE DATABASE IF NOT EXISTS weiterbildung; USE weiterbildung; CREATE TABLE IF NOT EXISTS schule( s_nr TINYINT UNSIGNED NOT NULL, s_plz INT UNSIGNED, s_ort VARCHAR(30), s_str VARCHAR(30)); CREATE TABLE IF NOT EXISTS dozent( d_nr TINYINT UNSIGNED NOT NULL, d_vorname CHAR(20), d_nachname CHAR(20), d_gesch CHAR(1), d_gebdat DATE, d_besch TINYINT UNSIGNED); CREATE TABLE IF NOT EXISTS fach( f_name CHAR(20) NOT NULL, f_dauer TINYINT UNSIGNED, f_maxteilnehmer TINYINT UNSIGNED, f_tagsatz DECIMAL(5,2)); INSERT INTO schule(s_nr, s_plz, s_ort, s_str) VALUES (1, 88123, 'Muenchen', 'Schulweg 99'), (2, 13629, 'Berlin', 'Schulweg 10'); INSERT INTO dozent(d_nr, d_vorname, d_nachname, d_gesch, d_gebdat, d_besch) VALUES (1, 'Anna', 'Seger', 'w', '1955-04-13', 1), (2, 'Peter', 'Hagen', 'm', '1958-10-31', 2), (3, 'Werner', 'Lutz', 'm', '1954-06-05', 2), (4, 'Christoph', 'Schwarz','m', '1955-02-28', 1); INSERT INTO fach(f_name, f_dauer, f_maxteilnehmer, f_tagsatz) VALUES ('Englisch', 10, 10, 300), ('Russisch', 14, 8, 400), ('Japanisch', 20, 12, 500), ('Deutsch', 10, 10, 400), ('Italienisch', 10, 10, 300);
Speichern Sie das ganze unter weiterbildung.sql ab. Danach führen Sie im Terminal-Fenster oder der Console folgendes aus:
# mysql -u root -h localhost -p < weiterbildung.sql
-u root -h localhost -p falls Sie schon ein Passwort vergeben haben.
Natürlich kann auch ein Backup der Datenbank angelegt werden. Dafür gibt es den Befehl mysqldump:
# mysqldump -u root -h localhost -p weiterbidung > bweiterbildung.sql
Oder alles sichern mit:
# mysqldump -u root -h localhost -p -Al --all-databases > bweiterbildung2.sql
Wiederherstellen:
# mysql -u root -h localhost -p < bweiterbildung2.sql
Jetzt können Sie Datenbanken und Tabellen erzeugen und löschen und wissen, wie
Sie Tabellen verändern, Auswahlabfragen usw. stellen. Später werden noch ein paar SQL-Anweisungen dazukommen.MySQL C-API
Die MySQL C-API wurde in C geschrieben. Sie ist Teil der mysqlclient-Bibliothek. Mit ihr können Sie Client-Programme
schreiben, die auf den MySQL-Server zugreifen. Es gibt dazu auch ein paar Beispiele im clients-Verzeichnis des MySQL-Quelltextes.Wenn MySQL wie oben beschrieben unter Windows installiert wird, ist i.d.R. die Bibliothek im Verzeichnis
C:\Programme\MySQL\MySQLServer41\lib\opt und die Headerdateien im Verzeichnis C:\Programme\MySQL\MySQLServer41\include vorhanden. Sie müssen dann noch
die libmysql.dll in ein Systemverzeichnis kopieren. Am besten nach C:\Windows\system32.Bei Linux steht die Bibliothek im Verzeichnis /usr/lib, /usr/lib/mysql oder /usr/local/lib/mysql.
Die Headerdateien im Verzeichnis /usr/include/mysql oder /usr/local/include/mysql. Bei *.rpm's müssen Sie,
wie oben geschrieben, mysql-devel und mysql-shared installieren (Die Distributoren lassen Grüßen ).Unter Windows gibt es ein Problem, was das Kompilieren eines Client-Programm betrifft. Die libmysql.lib wurde mit dem
Visual C++ Compiler erstellt. Dieser Compiler vergibt eine eigene Strukturanordnung für die libmysql.dll. Das heißt,
dass andere Compiler große Probleme bei der Kompilierung haben.Beim Borland Compiler BCC55, den Sie hier herunterladen können,
gibt es das Tool coff2omf. Damit können Sie die im Microsoft-Croff-Format vorliegende libmysql in ein für Borland übliches Format konvertieren:coff2omf C:\Programme\MySQL\MySQLServer41\lib\opt\libmysql.lib C:\borland\bcc55\lib\libmysql.lib
Jetzt haben Sie gleichzeitig auch die Bibliothek in das Bibliotheksverzeichnis des Borland-Kompilers kopiert.
Nutzer anderer Compiler werden wohl mit keinem der beiden Formate zurechtkommen. Entweder Sie steigen auf einen der beiden Compiler um,
oder Sie kompilieren den Sourcecode für diese Bilbliothek selbst.Kommen wir nun zum Lcc-win32 Compiler. Konvertieren der libmysql.lib:
Starten Sie über Start->Programme->Lcc-win32->Lcc-win32 oder auf der Kommandoebene wedit. Klicken Sie auf Utils->import foreign library.
Jetzt klicken Sie auf den Button mit den drei Punkten rechts neben dem Eingabefeld Path of the foreign library(microsoft format) to import und suchen die
libmysql.lib im C:\Programme\MySQL\MySQLServer41\lib\opt-Verzeichnis von MySQL.Das Textfeld Path for the resulting library wird dann automatisch ausgefüllt. Den Rest können Sie so lassen. Jetzt auf ok klicken.
Nachdem Sie auch hier diese beiden Meldungen bestätigt haben, können Sie die Bibliothek benutzen.
Das können Sie auch auf der Kommandoebene machen, indem Sie die Programme pedump und buildlib benutzen. Mit
pedump /exp C:\Programme\MySQL\MySQLServer41\lib\opt\libmysql.lib
erstellt pedump eine Datei libmysql.exp im Verzeichnis C:\lcc\buildlib.
buildlib C:\lcc\buildlib\libmysql.exp C:\lcc\lib\libmysql.lib
Jetzt ist die libmysql.lib im lib-Verzeichnis vom Lcc-Compiler und Sie können sie benutzen.
Hier erst mal ein sehr einfaches Programm, für eine SELECT-Abfrage an den MySQL-Server.
/* select.c - SELECT-Abfrage für VC++ und Lcc-win32 #include "C:\Programme\MySQL\MySQLServer41\include\mysql.h" */ #include <mysql.h> #if defined __WIN32__ #include <windows.h> #endif #include <stdio.h> int main(void) { MYSQL *connection; /* Der MySQL-Handler: Verbindung zum MySQL-Server */ MYSQL_RES *ergebnis; /* Ergebnis einer Abfrage */ char abfrage[1000]; /* beinhaltet die Abfrage */ MYSQL_ROW zeile; /* Ergebniszeile */ int anz; /* Anzahl der Zeilen */ int i; connection = mysql_init(NULL); /* Datenstruktur initalisieren */ /* Die einzelnen Typen von mysql_real_connect() werden weiter unten erklärt */ /* Später werden wir natürlich Variablen für Host, User, Passwort usw benutzen */ if(mysql_real_connect( /* Verbindung aufbauen */ connection, /* MySQL-Handler */ "localhost", /* Host-Name */ "thomas", /* User-Name */ "streng_geheim", /* Passwort */ "weiterbildung", /* Datenbank */ 0, /* Port, standard = 0 */ NULL, /* Socket, standard = NULL */ 0) == NULL) { /* keine Flags */ fprintf(stderr, "Verbindung schlug fehl: %u (%s)\n", mysql_errno(connection), mysql_error(connection)); mysql_close(connection); exit(1); } /* muss hier erst mal genügen */ sprintf(abfrage, "SELECT * FROM dozent"); /* Ich weiss, ziemlich krude */ if((mysql_query(connection, abfrage) != 0)) { /* SQL-Befehl ausführen */ fprintf(stderr, "Abfrage schlug fehl: %u (%s)\n", mysql_errno(connection), mysql_error(connection)); mysql_close(connection); exit(1); } ergebnis = mysql_store_result(connection); /* Ergebnisse speichern */ anz = mysql_num_fields(ergebnis); /* Anzahl der Zeilen ermitteln */ while((zeile = mysql_fetch_row(ergebnis))) { /* Zeilen aus ergebnis abholen */ for(i = 0; i < anz; i++) printf("%s ", zeile[i]); /* Zeilen ausgeben */ printf("\n"); } mysql_free_result(ergebnis); /* Ergebnisspeicher wieder freigeben */ mysql_close(connection); /* verbindung trennen */ return 0; }
Mit VC++ jetzt kompilieren, aber noch nicht linken. Vorher noch den Pfad zur mysql-Bibliothek
dem Linker mitteilen und zwar über:
Projekt->Einstellungen dort im Register Linker ans Ende des Feldes Objekt-/Bibliothek-Module
c:\mysql\lib\opt\libmysql.lib hinzufügen.
Jetzt das Programm linken und ausführen.Mit BCC55 eine Objekt-Datei erstellen:
bcc32 -c -I"C:\Programme\MySQL\MySQLServer41\include" select.c
Jetzt linken:
ilink32 c0x32.obj select.obj , select.exe , , import32.lib cw32.lib libmysql.lib
Naja, vielleicht sollten Sie eine Batch-Datei dafür erstellen ;).
bcc_link.batilink32 c0x32.obj %1 , %2 , , import32.lib cw32.lib libmysql.lib
%1 = OBJ-Datei
%2 = EXE-Datei
Aufruf z. B.:bcc_link select.obj select.exe
Mit dem Lcc-win32:
lcc select.c
die Objekt-Datei erstellen und dann mit
lcclnk select.obj -L"C:\lcc\lib" libmysql.lib
die exe-Datei - nicht vergessen #include "C:\Programme\MySQL\MySQLServer41\lib\opt\mysql.h" einbinden.
Unter Linux erstellen Sie das Programm folgendermaßen mit
# gcc -c -I/usr/include/mysql select.c
erhalten Sie eine Object-Datei namens select.o. Dann mit
# gcc -o select select.o -I/usr/lib/mysql -lmysqlclient
linken und ./select ausführen.
Wenn alles gut gegangen ist, erhalten Sie das Ergebnis der SELECT-Abfrage auf dem Bildschirm.
Die MySQL C-API verwendet auch Funktionen aus der Headerdatei <math.h>. Bei manchen Distributionen dann noch -lm hinzulinken.# gcc -o select select.o -I/usr/lib/mysql -lmysqlclient -lm
Bevor ich jetzt weitermache, noch ein paar Erklärungen für einige Datentypen in der Datei oben:
MYSQL
Der MySQL-Handler wird benutzt, um eine Verbindung mit der Datenbank herzustellen. Er ist in mysql.h definiert.MYSQL_RES
stellt das Ergebnis einer Abfrage, die Zeilen zurückgibt, dar. Also SELECT oder SHOW.
MYSQL_ROW
ist eine typsichere Darstellung einer Zeile von Daten. Sie ist als ein Array von Strings implementiert.
Sie können diese nicht als NULL-begrenzte Zeichenketten behandeln, da sie binäre Daten enthalten können, die
intern NULL-Bytes beinhalten können. Zeilen werden mit dem Aufruf mysql_fetch_row() abgeholt.my_ulonglong
wird für die Anzahl der Zeilen und für mysql_affect_rows(), mysql_num_rows() und mysql_insert_id() verwendet. Der
Bereich ist von 0 bis 1.84e19. Bei manchen Systemen funktioniert es nicht, einen Wert von diesem Typ auszugeben.
Dann sollte man ihn nach unsigned long umwandeln und %lu Format von printf() verwenden.printf("Anzahl der Zeilen: %lu\n", (unsigned long) mysql_num_rows(zeilen));
MYSQL *mysql_init(MYSQL *connection)
hiermit wird die MYSQL-Strukturvariable connection initialisiert, bevor eine Verbindung zum Datenbank-Server hergestellt wird.
Um die Verbindung herzustellen, wird die folgende Funktion benutzt.MYSQL *mysql_real_connect( /* Adresse einer existierenden MYSQL-Struktur */ MYSQL *connect, /* Der Wert von host kann entweder ein Hostname oder eine IP-Adresse sein. Wenn host NULL oder 'localhost' ist, wird eine Verbindung zum lokalen Host angenommen. Wenn das Betriebssystem Sockets (Unix) oder Named Pipes (Windows) unterstützt, werden diese statt TCP/IP benutzt, um sich mit dem Server zu verbinden. */ const char *host, /* user enthält die MySQL-Login-Benutzerkennung. Wenn user NULL ist, wird der aktuelle Benutzer angenommen. Unter Unix ist das der aktuelle Login-Name. Unter Windows-ODBC muss der aktuelle Benutzername explizit angegeben werden. */ const char *user, /* Der passwd-Parameter enthält das Passwort für user. Wenn passwd NULL ist, werden nur Einträge in der user-Tabelle für Benutzer auf Übereinstimmung überprüft, die ein leeres Passwort-Feld haben. Versuchen Sie nicht das Passwort zu verschlüsseln, bevor Sie mysql_real_connect() aufrufen. Die Verschlüsselung wird automatisch durch die Client-API gehandhabt */ const char *passwd, /* db ist der Datenbankname. Wenn db nicht NULL ist, wird die vorgabemäßige Datenbank für die Verbindung auf diesen Wert gesetzt. */ const char *db, /* Wenn port nicht 0 ist, wird dieser Wert als Port-Nummer für die TCP/IP-Verbindung benutzt. Achtung: der host-Parameter legt den Verbindungstyp fest. */ unsigned int port, /* Wenn unix_socket nicht NULL ist, legt die Zeichenkette den Socket oder die Named Pipe fest, die benutzt werden sollen. Auch hier legt der host-Parameter den Vebindungstyp fest. const char *unix_socket, /* Der Wert von client_flag ist üblicherweise 0. Die Flags werden in der MySQL-Referenz beschrieben. Wir werden sie hier nicht benutzen. */ unsigned int client_flag);
*unsigned int mysql_errno(MYSQL connection)
Gibt den Fehler-Code für die zuletzt aufgerufene API-Funktion zurück, die erfolgreich sein
oder fehlschlagen kann. Ein Rückgabewert von 0 bedeutet, dass kein Fehler auftrat.char *mysql_error(MYSQL *connection)
Gibt für die von mysql angegebene Verbindung die Fehlermeldung für die zuletzt aufgerufene API-Funktion zurück,
die erfolgreich sein oder fehlschlagen kann. Eine leere Zeichenkette "" bedeutet, dass kein Fehler auftrat.
Folgende zwei Tests sind demnach äquivalent:if(mysql_errno(connection)) { /* Ein Fehler trat auf } if(mysql_error(connection)[0] != '\0') { /* Ein Fehler trat auf }
Mit char *abfrage (char abfrage[1000]) können wir eine Abfrage machen und alle SQL-Sätze bilden. Eine Abfrage wird mit der folgenden
Funktion durchgeführt:int mysql_query(MYSQL *connection, const char *abfrage);
ausgeführt. mysql_query() kann nicht für Abfragen benutzt werden, die Binärdaten enthalten. Hierfür gibt es
int mysql_real_query(MYSQL *connection, const char *abfrage, unsigned int length);
length ist die Länge des Strings abfrage. mysql_real_query() wird benutzt, wenn eine Abfrage Binärdaten enthält. Binärdaten können das
'\0'-Zeichen enthalten. mysql_real_query() ist schneller als mysql_query(), weil es in der Abfragezeichenkette nicht strlen() aufruft.MYSQL_RES
repränsentiert das Ergebnis einer Abfrage, die Zeilen zurückgibtMYSQL_RES *ergebnis
ergebnis = mysql_use_result(connection)
Diese Funktion wird für jede Abfrage aufgerufen, die erfolgreich Daten zurückgibt(SELECT,SHOW,DESCRIBE,EXPLAIN).
Sie liest die Ergebnismenge nicht tatsächlich in den Client. Stattdessen muss jede Zeile individuell abgerufen werden,
indem Aufrufe von mysql_fetch_row() durchgeführt werden. das liest das Ergebnis einer Anfrage direkt vom Server, ohne
es in einer temporären Tabelle oder einem lokalem Puffer zu speichern.MYSQL_RES *mysql_store_result(MYSQL *connection)
liest das gesamte Ergebnis einer Abfrage zum Client ein, weist eine MYSQL_RES-Struktur zu und platziert des Ergebnis
in diese Struktur.MYSQL_ROW *mysql_fetch_row(MYSQL_RES *ergebnis)
ruft die nächste Zeile der Ergebnismenge ab. Wenn sie nach mysql_use_result() benutzt wird, gibt mysql_fetch_row NULL zurück,
wenn es keine Zeilen mehr zum Abruf gibt oder wenn ein Fehler auftrat.Die Verbindung zur Datenbank wird am Ende mit
mysql_close(connection);
beendet.
Noch ein paar Funktionen:
unsigned int mysql_num_fields(MYSQL *connection)
gibt die Anzahl der Spalten in einer Datenbank zurück.
my_ulonglong mysql_num_rows(MYSQL_RES *ergebnis);
die Anzahl der Zeilen eines Abfrageergebnisses.
my_ulonglong mysql_affect_rows(MYSQL *connection);
gibt die Anzahl der Zeilen zurück, die von einer INSERT, DELETE oder UPDATE Abfrage geändert wurden.
Vielleicht möchten Sie ja auch die Überschriften der einzelnen Spalten der Tabelle auslesen und anzeigen. Das erreichen Sie mit
der Struktur MYSQL_FIELD und der Funktion mysql_fetch_fields().int main(void) { MYSQL *connection; /* Der MySQL-Handler: Verbindung zum MySQL-Server */ MYSQL_RES *ergebnis; /* Ergebnis einer Abfrage */ char abfrage[1000]; /* beinhaltet die Abfrage */ MYSQL_ROW zeile; /* Ergebniszeile */ MYSQL_FIELD *felder; /* Informationen über die Felder einer Tabelle */ int anz; /* Anzahl der Zeilen */ int i; ... ergebnis = mysql_store_result(connection); /* Ergebnisse speichern */ felder = mysql_fetch_fields(ergebnis); /* Informationen über die Felder auslesen*/ anz = mysql_num_fields(ergebnis); /* Anzahl der Zeilen ermitteln */ for(i = 0; i < anz; i++) /* Überschriften ausgeben */ printf("%12s", felder[i].name); printf("\n"); while((zeile = mysql_fetch_row(ergebnis))) { /* Zeilen aus ergebnis abholen */ for(i = 0; i < anz; i++) printf("%12s ", zeile[i]); /* Zeilen ausgeben */ printf("\n"); } ... }
Bei SQL gibt es zwei grundsätzlich verschiedene Arten von Abfragen. Die eine haben Sie oben kennengelernt. Abfragen mit
SELECT, SHOW usw. geben ein Ergebnis zurück, nämlich den Inhalt oder ein Teil des Inhaltes einer Tabelle oder Datenbank
in Form von Zeilen, oder Datensätze auch Tupel genannt.Mit UPDATE, INSERT oder DELETE bekommen Sie keine Daten zurück.
Jetzt werden wir eine solche Abfrage in C programmieren. Der Aufbau ist sehr ähnlich dem ersten./* update.c - UPDATE-Abfrage für VC++ und Lcc-win32 #include "c:\Programme\MySQL\MySQLServer41\include\mysql.h" */ #include <mysql.h> #if defined __WIN32__ #include <windows.h> #endif #include <stdio.h> int main(void) { MYSQL *connection; /* Der Mysql-Handler: Verbindung zum MySQL-Server */ char abfrage[1000]; /* beinhaltet die Abfrage */ int i; unsigned long anzahl; /* Anzahl der veränderten Datensätze */ connection = mysql_init(NULL); /* Datenstruktur initalisieren */ if(mysql_real_connect( /* Verbindung aufbauen */ connection, /* MySQL-Handler */ "localhost", /* Host-Name */ "thomas", /* User-Name */ "streng_geheim", /* Passwort */ "weiterbildung", /* Datenbank */ 0, /* Port, standard = 0 */ NULL, /* Socket, standard = NULL */ 0) == NULL) { /* keine Flags */ fprintf(stderr, "Verbindung schlug fehl\n"); mysql_close(connection); exit(1); } sprintf(abfrage, "UPDATE fach SET f_tagsatz=300 WHERE f_tagsatz=350;"); if((mysql_query(connection, abfrage) != 0)) { /* SQL-Befehl ausführen */ fprintf(stderr, "Abfrage schlug fehl (%s): %s\n", abfrage, mysql_error(connection)); mysql_close(connection); exit(1); } if((anzahl = (unsigned long)mysql_affected_rows(connection)) <= 0) /* Hier wird die Anzahl der geänderten */ printf("Kein Datensatz geändert\n"); /* Datensätze abgeholt und ausgegeben */ else printf("%d %s geändert\n", anzahl, (anzahl==1)?"Datensatz wurde ":"Datensätze wurden "); mysql_close(connection); /* verbindung trennen */ return 0; }
Das Programm sollte die Anzahl der geänderten Datensätze ausgeben.
Das Ganze ist eigentlich gar nicht so schwierig. Grundsätzlich läuft es meistens nach dem gleichen Schema ab:
-
mysql_init() Datenstruktur initialisieren
-
mysql_real_connect() Verbindung aufbauen
-
mysql_query() oder mysql_real_query() Abfrage absetzen
-
gibt es eine Rückgabe?
-
ja
mysql_store_result() das Ergebnis vom Typ MYSQL_RES abholen
mysql_num_fields() Anzahl der Spalten abholen
mysql_fetch_row() Zeilen auslesen
mysql_free_result() Speicher freigeben -
nein
mysql_affected_rows() Anzahl der gefundenen Datensätze angeben -
mysql_close() Verbindung beenden
-
mysql_server_end();
Literatur
Hauptsächlich die MySQL-Documentation
und
-
Sehr schönes Tutorial!
Eine kleine Anmerkung:
Um mit gcc -lmysqlclient unter Linux compilieren zu können, benötigt man die mysql database development files (libmysqlclient-dev).
Mit apt bzw. aptitude lässt sich die momentan neuste Version zum Beispiel so installieren (vorausgesetzt in der sources.list sind die notwendigen Einträge für MySQL):apt
apt-get install libmysqlclient15-dev
aptitude
aptitude install libmysqlclient15-dev
Ich denke es wäre ganz sinnvoll dies hinzuzufügen, damit nicht so lange nach der Lösung gesucht werden muss, wenn libmysqlclient-dev noch nicht installiert sein sollte.
Weiter so!
lg Max