Dieser Abschnitt erklärt die Erstellung einer
Plug-In-Bibliothek Schritt für Schritt. Er zeigt, wie man
eine Bibliothek entwickelt, die ein Volltext-Parsing-Plug-In
namens simple_parser
enthält. Dieses
Plug-In wendet einfachere Regeln als der eingebaute
Volltext-Parser von MySQL an: Wörter sind nichtleere Folgen
von Whitespace-Zeichen.
Jede Plug-In-Bibliothek enthält Folgendes:
Ein Plug-In-Bibliotheksdeskriptor mit der Versionsnummer der allgemeinen Plug-In-API der Bibliothek und einer allgemeinen Deklaration für jedes Plug-In in der Bibliothek.
Jede allgemeine Plug-In-Deklaration enthält Informationen, die allen Arten von Plug-Ins gemeinsam sind: einen Wert, der den Plug-In-Typ anzeigt, den Namen, den Autor und die Beschreibung des Plug-Ins sowie Zeiger auf die Initialisierungs- und die Deinitialisierungfunktionen, die der Server beim Laden und Entladen des Plug-Ins aufrufen muss.
Außerdem enthält die allgemeine Plug-In-Deklaration einen Zeiger auf einen typspezifischen Plug-In-Deskriptor. Die Struktur dieser Deskriptoren kann je nach Plug-In-Typ unterschiedlich sein, da jede Art von Plug-In ihre eigene API haben kann. Ein Plug-In-Deskriptor enthält eine typspezifische API-Versionsnummer und Zeiger auf die Funktionen, die zur Implementierung dieses Plug-In-Typs erforderlich sind. So hat beispielsweise ein Volltext-Parser-Plug-In Initialisierungs- und Deinitialisierungsfunktionen und eine Parsing-Hauptfunktion. Der Server ruft diese Funktionen auf, wenn er das Plug-In zum Parsen von Text einsetzt.
Die Plug-In-Bibliothek enthält die Schnittstellenfunktionen, auf die der Bibliotheksdeskriptor und die Plug-In-Deskriptoren verweisen.
Eine Plug-In-Bibliothek wird folgendermaßen angelegt:
Zuerst binden Sie die von der Plug-In-Bibliothek
benötigten Header-Dateien ein. Die Datei
plugin.h
ist auf jeden Fall
notwendig, allerdings kann die Bibliothek auch noch andere
Dateien erfordern. Zum Beispiel:
#include <my_global.h> #include <m_string.h> #include <m_ctype.h> #include <plugin.h>
Dann richten Sie den Deskriptor für die Plug-In-Bibliotheksdatei ein.
Jede Plug-In-Bibliothek muss einen Bibliotheksdeskriptor besitzen, der zwei Symbole definiert:
_mysql_plugin_interface_version_
ist die Versionsnummer des allgemeinen
Plug-In-Frameworks. Sie wird durch das Symbol
MYSQL_PLUGIN_INTERFACE_VERSION
angegeben, das in der Datei
plugin.h
definiert ist.
_mysql_plugin_declarations_
definiert ein Array von Plug-In-Deklarationen, wobei
am Ende eine Deklaration steht, in der alle
Bestandteile auf 0 gesetzt sind. Jede Deklaration ist
eine Instanz der Struktur
st_mysql_plugin
(ebenfalls in
plugin.h
definiert). Für jedes
Plug-In in der Bibliothek muss eine solche Deklaration
vorhanden sein.
Wenn der Server diese beiden Symbole nicht in einer Bibliothek vorfindet, akzeptiert er sie nicht als gültige Plug-In-Bibliothek und weist sie mit einer Fehlermeldung zurück. So wird verhindert, dass eine Bibliothek für Plug-In-Zwecke benutzt wird, die nicht speziell als Plug-In-Bibliothek ausgelegt wurde.
Die üblichste (und bequemste) Art, die beiden notwendigen
Symbole zu definieren, bieten die beiden Makros
mysql_declare_plugin
und
mysql_declare_plugin_end
aus der Datei
plugin.h
:
mysql_declare_plugin
... eine oder mehr Plug-In-Deklarationen ...
mysql_declare_plugin_end;
Der Bibliotheksdeskriptor für eine Bibliothek mit einem
einzigen Plug-In namens simple_parser
sähe beispielsweise folgendermaßen aus:
mysql_declare_plugin { MYSQL_FTPARSER_PLUGIN, /* Typ */ &simple_parser_descriptor, /* Deskriptor */ "simple_parser", /* Name */ "MySQL AB", /* Autor */ "Simple Full-Text Parser", /* Beschreibung */ simple_parser_plugin_init, /* Initialisierungsfunktion */ simple_parser_plugin_deinit /* Deinitialisierungsfunktion */ } mysql_declare_plugin_end;
Der Typ eines Volltext-Parser-Plug-Ins müsste
MYSQL_FTPARSER_PLUGIN
sein. Dieser Wert
kennzeichnet das Plug-In als zulässig zur Benutzung in
einer WITH PARSER
-Klausel, wenn ein
FULLTEXT
-Index angelegt werden soll.
(Kein anderer Plug-In-Typ ist für diese Klausel erlaubt.)
Die Makros mysql_declare_plugin
und
mysql_declare_plugin_end
sind in
plugin.h
folgendermaßen definiert:
#define mysql_declare_plugin \ int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ struct st_mysql_plugin _mysql_plugin_declarations_[]= { #define mysql_declare_plugin_end ,{0,0,0,0,0,0,0}}
In der oben gezeigten Verwendung werden die Makros zu
folgendem Code expandiert, der beide erforderlichen
Symbole definiert
(_mysql_plugin_interface_version_
und
_mysql_plugin_declarations_
):
int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; struct st_mysql_plugin _mysql_plugin_declarations_[]= { { MYSQL_FTPARSER_PLUGIN, /* Typ */ &simple_parser_descriptor, /* Deskriptor */ "simple_parser", /* Name */ "MySQL AB", /* Autor */ "Simple Full-Text Parser", /* Beschreibung */ simple_parser_plugin_init, /* Initialisierungsfunktion */ simple_parser_plugin_deinit /* Deinitialisierungsfunktion */ } ,{0,0,0,0,0,0,0} };
Im obigen Beispiel wird nur ein einzelnes Plug-In im
Bibliotheksdeskriptor deklariert, aber es ist ebenso gut
möglich, mehrere Plug-Ins zu deklarieren. Hierzu führen
Sie die Deklarationen – durch Kommata getrennt
– in mysql_declare_plugin
und
mysql_declare_plugin_end
auf.
Nun richten Sie den Plug-In-Deskriptor ein.
Jede Plug-In-Deklaration im Bibliotheksdeskriptor verweist
auf einen typspezifischen Deskriptor für das zugehörige
Plug-In. In der Deklaration von
simple_parser
wird dieser Deskriptor
von &simple_parser_descriptor
angezeigt. Der Deskriptor gibt die Versionsnummer für die
Volltext-Plug-In-Schnittstelle (wie sie in
MYSQL_FTPARSER_INTERFACE_VERSION
steht)
sowie die Parsing-, Initialisierungs- und
Deinitialisierungsfunktionen des Plug-Ins an:
static struct st_mysql_ftparser simple_parser_descriptor= { MYSQL_FTPARSER_INTERFACE_VERSION, /* Schnittstellenversion */ simple_parser_parse, /* Parsing-Funktion */ simple_parser_init, /* Parser-Initialisierungsfunktion */ simple_parser_deinit /* Parser-Deinitialisierungsfunktion */ };
Jetzt richten Sie die Plug-In-Schnittstellenfunktionen ein.
In der allgemeinen Plug-In-Deklaration des
Bibliotheksdeskriptors werden die Initialisierungs- und
Deinitialisierungsfunktionen angegeben, die der Server zum
Laden und Entladen des Plug-Ins aufrufen muss. Für den
simple_parser
geben diese Funktionen
lediglich null zurück, um anzuzeigen, dass sie Erfolg
hatten:
static int simple_parser_plugin_init(void) { return(0); } static int simple_parser_plugin_deinit(void) { return(0); }
Da diese Funktionen eigentlich nichts tun, könnten Sie sie ebenso gut weglassen und in der Plug-In-Deklaration jeweils durch 0 ersetzen.
Der typspezifische Plug-In-Deskriptor für den
simple_parser
gibt die
Initialisierungs-, Deinitialisierungs- und
Parsing-Funktionen an, die der Server bei Benutzung dieses
Plug-Ins aufrufen muss. Beim
simple_parser
tun die Initialisierungs-
und Deinitialisierungsfunktionen gar nichts:
static int simple_parser_init(MYSQL_FTPARSER_PARAM *param) { return(0); } static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param) { return(0); }
Da diese Funktionen nichts tun, könnte man sie hier ebenfalls weglassen und im Plug-In-Deskriptor 0 für sie angeben.
Da die Parsing-Hauptfunktion
simple_parser_parse()
den eingebauten
Volltext-Parser ersetzen soll, muss sie Text in Wörter
zerlegen und diese Wörter an den Server übergeben. Das
erste Argument der Parsing-Funktion ist ein Zeiger auf
eine Struktur, die den Parsing-Kontext enthält. Diese
Struktur besitzt einen doc
-Bestandteil,
der auf den zu parsenden Text verweist, und einen
length
-Bestandteil, der die Länge
dieses Texts anzeigt. Da das Plug-In ganz einfache
Parsing-Regeln verwendet, wonach nichtleere Folgen von
Whitespace-Zeichen als Wörter betrachtet werden, erkennt
es Wörter folgendermaßen:
static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param) { char *end, *start, *docend= param->doc + param->length; for (end= start= param->doc;; end++) { if (end == docend) { if (end > start) add_word(param, start, end - start); break; } else if (isspace(*end)) { if (end > start) add_word(param, start, end - start); start= end + 1; } } return(0); }
Während der Parser ein Wort nach dem anderen erkennt,
ruft er die Funktion add_word()
auf, um
es an den Server zu übergeben.
add_word()
ist nur eine Hilfsfunktion,
die nicht zur Plug-In-Schnittstelle gehört. Der Parser
übergibt den Zeiger auf den Parsing-Kontext, den Zeiger
auf das Wort und einen Längenwert an
add_word()
.
static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len) { MYSQL_FTPARSER_BOOLEAN_INFO bool_info= { FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 }; if (param->mode == MYSQL_FTPARSER_FULL_BOOLEAN_INFO) param->mysql_add_word(param->mysql_ftparam, word, len, &bool_info); else param->mysql_add_word(param->mysql_ftparam, word, len, 0); }
Beim Parsen im booleschen Modus füllt
add_word()
die Bestandteile der
bool_info
-Struktur aus, wie in
Abschnitt 26.2.5.2, „Typspezifische Plug-In-Strukturen und -Funktionen“ beschrieben.
Kompilieren Sie die Plug-In-Bibliothek als Shared Library und installieren Sie sie in das Plug-In-Verzeichnis.
Die Prozedur zum Kompilieren von Shared-Objekten ist von
System zu System unterschiedlich. Wenn Sie Ihre Bibliothek
mithilfe der GNU-Autotools bauen, müsste
libtool in der Lage sein, die richtigen
Kompilierbefehle für Ihr System zu generieren. Wenn die
Bibliothek mypluglib
heißt, müssten
Sie zum Schluss mit einer Shared Object-Datei dastehen,
die so ähnlich wie libmypluglib.so
heißt. (Der Dateiname kann auf Ihrem System eine andere
Erweiterung haben.)
Die Stelle, an der Sie die Bibliothek in Ihrem
Plug-In-Verzeichnis installieren müssen, verrät Ihnen
die Systemvariable plugin_dir
. Zum
Beispiel:
mysql> SHOW VARIABLES LIKE 'plugin_dir';
+---------------+----------------------------+
| Variable_name | Value |
+---------------+----------------------------+
| plugin_dir | /usr/local/mysql/lib/mysql |
+---------------+----------------------------+
Wenn Sie die Plug-In-Bibliothek installieren, achten Sie bitte darauf, dass Ihre Berechtigungen eine Ausführung durch den Server erlauben.
Registrieren Sie das Plug-In beim Server.
Die INSTALL PLUGIN
-Anweisung lässt den
Server das Plug-In in die
plugin
-Tabelle übernehmen und seinen
Code aus der Bibliotheksdatei laden. Registrieren Sie mit
dieser Anweisung den simple_parser
beim
Server und vergewissern Sie sich dann, dass er in die
plugin
-Tabelle aufgenommen wurde:
mysql>INSTALL PLUGIN simple_parser SONAME 'libmypluglib.so';
Query OK, 0 rows affected (0.00 sec) mysql>SELECT * FROM mysql.plugin;
+---------------+-----------------+ | name | dl | +---------------+-----------------+ | simple_parser | libmypluglib.so | +---------------+-----------------+ 1 row in set (0.00 sec)
Nun probieren Sie das Plug-In aus.
Legen Sie eine Tabelle mit einer String-Spalte an und
verbinden Sie das Parser-Plug-In mit einem
FULLTEXT
-Index auf der Spalte:
mysql>CREATE TABLE t (c VARCHAR(255),
->FULLTEXT (c) WITH PARSER simple_parser);
Query OK, 0 rows affected (0.01 sec)
Fügen Sie Text in die Tabelle ein und versuchen Sie einige Suchoperationen. Dabei sollte ausprobiert werden, ob das Parser-Plug-In wirklich alle Nicht-Whitespace-Zeichen als Wortzeichen betrachtet:
mysql>INSERT INTO t VALUES
->('latin1_general_cs is a case-sensitive collation'),
->('I\'d like a case of oranges'),
->('this is sensitive information'),
->('another row'),
->('yet another row');
Query OK, 5 rows affected (0.02 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql>SELECT c FROM t;
+-------------------------------------------------+ | c | +-------------------------------------------------+ | latin1_general_cs is a case-sensitive collation | | I'd like a case of oranges | | this is sensitive information | | another row | | yet another row | +-------------------------------------------------+ 5 rows in set (0.00 sec) mysql>SELECT MATCH(c) AGAINST('case') FROM t;
+--------------------------+ | MATCH(c) AGAINST('case') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | +--------------------------+ 5 rows in set (0.00 sec) mysql>SELECT MATCH(c) AGAINST('sensitive') FROM t;
+-------------------------------+ | MATCH(c) AGAINST('sensitive') | +-------------------------------+ | 0 | | 0 | | 1.3253291845322 | | 0 | | 0 | +-------------------------------+ 5 rows in set (0.01 sec) mysql>SELECT MATCH(c) AGAINST('case-sensitive') FROM t;
+------------------------------------+ | MATCH(c) AGAINST('case-sensitive') | +------------------------------------+ | 1.3109166622162 | | 0 | | 0 | | 0 | | 0 | +------------------------------------+ 5 rows in set (0.01 sec) mysql>SELECT MATCH(c) AGAINST('I\'d') FROM t;
+--------------------------+ | MATCH(c) AGAINST('I\'d') | +--------------------------+ | 0 | | 1.2968142032623 | | 0 | | 0 | | 0 | +--------------------------+ 5 rows in set (0.01 sec)
Beachten Sie, dass weder „case“ noch „insensitive“ auf „case-insensitive“ passen, wie es bei dem eingebauten Parser der Fall wäre.
Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.