Nach der Tabelleninitialisierung ruft der MySQL Server die
Handler-Funktion
rnd_next()
für jede zu untersuchende Zeile einmal auf, bis seine
Suchbedingung erfüllt oder das Ende der Datei erreicht ist. Im
letzteren Fall gibt er HA_ERR_END_OF_FILE
zurück.
Die Funktion rnd_next()
nimmt einen
Byte-Array-Parameter namens *buf
entgegen.
Dieser *buf
-Parameter muss mit dem Inhalt der
Tabellenzeile im internen Format von MySQL gefüllt sein.
Der Server verwendet drei Datenformate: Zeilen mit fester
Länge, Zeilen mit variabler Länge und variabel lange Zeilen
mit BLOB-Zeigern. In jedem der Formate erscheinen die Spalten in
derselben Reihenfolge wie in der CREATE TABLE-Anweisung. (Die
Tabellendefinition wird in der .frm
-Datei
gespeichert und Optimierer und Handler können beide die
Metadaten der Tabelle aus derselben Quelle holen, nämlich aus
ihrer TABLE
-Struktur.)
Jedes Format beginnt mit einer „NULL-Bitmap“, die für jede nullfähige Spalte ein Bit enthält. Eine Tabelle mit 8 nullfähigen Spalten hat somit eine 1 Byte große Bitmap, während eine Tabelle mit 9 bis 16 nullfähigen Spalten eine 2 Byte große Bitmap besitzt, und so weiter. Eine Ausnahme bilden die Tabellen mit fester Breite: Da sie ein zusätzliches Startbit haben, würde eine solche Tabelle mit 8 nullfähigen Spalten dennoch eine 2 Byte große Bitmap aufweisen.
Hinter der NULL-Bitmap kommen nacheinander die Spalten an die
Reihe. Jede Spalte hat die in Kapitel 11, Datentypen,
angegebene Größe. Im Server sind die Spaltendatentypen in der
Datei sql/field.cc
definiert. In einem
Format mit fester Zeilenbreite werden die Spalten einfach
nacheinander angeordnet. In einem Format mit variabler
Zeilenlänge werden die VARCHAR
-Spalten mit
einer Länge von 1 oder 2 Byte, gefolgt von einem
Zeichen-String, kodiert. In einer variabel langen Zeile mit
BLOB
-Spalten wird jeder BLOB in zwei Teilen
dargestellt: Zuerst kommt ein Integer, der die tatsächliche
Länge des BLOB
darstellt, und dann ein
Zeiger auf den Speicherplatz des BLOB
.
Beispiele für die Konvertierung (oder das
„Packen“) von Zeilen finden Sie ab der Funktion
rnd_next()
in jedem Tabellen-Handler. So
zeigt beispielsweise in ha_tina.cc
der Code
von find_current_row()
, wie die
TABLE
-Struktur (auf welche die Tabelle
verweist) und ein String-Objekt namens Buffer genutzt werden
können, um Zeichendaten aus einer CSV-Datei zu packen. Um eine
Zeile auf die Platte zurückzuspeichern, ist die umgekehrte
Konvertierung erforderlich: Die Zeilen müssen dann aus dem
internen Format wieder zurückkonvertiert werden.
Das folgende Beispiel stammt wieder aus der Speicher-Engine
CSV
:
int ha_tina::rnd_next(byte *buf) { DBUG_ENTER("ha_tina::rnd_next"); statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status); current_position= next_position; if (!share->mapped_file) DBUG_RETURN(HA_ERR_END_OF_FILE); if (HA_ERR_END_OF_FILE == find_current_row(buf) ) DBUG_RETURN(HA_ERR_END_OF_FILE); records++; DBUG_RETURN(0); }
Die Funktion find_current_row()
übernimmt
die Konvertierung aus dem internen Zeilenformat in ein
CSV-Zeilenformat:
int ha_tina::find_current_row(byte *buf) { byte *mapped_ptr= (byte *)share->mapped_file + current_position; byte *end_ptr; DBUG_ENTER("ha_tina::find_current_row"); /* EOF soll als Newline gelten*/ if ((end_ptr= find_eoln(share->mapped_file, current_position, share->file_stat.st_size)) == 0) DBUG_RETURN(HA_ERR_END_OF_FILE); for (Field **field=table->field ; *field ; field++) { buffer.length(0); mapped_ptr++; // Inkrementiere hinter dem ersten Anführungszeichen for(;mapped_ptr != end_ptr; mapped_ptr++) { // Ist notwendig, um Zeilenvorschübe zu konvertieren! if (*mapped_ptr == '"' && (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || (mapped_ptr == end_ptr -1 ))) { mapped_ptr += 2; // Gehe hinter das , und das " break; } if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1)) { mapped_ptr++; if (*mapped_ptr == 'r') buffer.append('\r'); else if (*mapped_ptr == 'n' ) buffer.append('\n'); else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"')) buffer.append(*mapped_ptr); else /* Dies kann nur bei einer extern erzeugten Datei passieren */ { buffer.append('\\'); buffer.append(*mapped_ptr); } } else buffer.append(*mapped_ptr); } (*field)->store(buffer.ptr(), buffer.length(), system_charset_info); } next_position= (end_ptr - share->mapped_file)+1; /* Vielleicht \N für null verwenden? */ memset(buf, 0, table->s->null_bytes); /* Nullen werden nicht implementiert! */ DBUG_RETURN(0); }
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.