====== std.db.sqlite ====== SQLite3-Binding via FFI (''libsqlite3.so.0''). Alle Verbindungs- und Statement-Handles werden als ''int64''-Pointer dargestellt. Das API folgt dem Prepared-Statement-Muster: ''SQLiteStmtPrepare'' → Bind → ''SQLiteStmtStep'' → Column-Accessoren → ''SQLiteStmtFinalize''. → [[lyx_-_programmiersprache:units|Standard Library]] · [[lyx_-_programmiersprache:units:db:postgres|std.db.postgres]] · [[lyx_-_programmiersprache:units:db:mysql|std.db.mysql]] ---- ===== Konstanten ===== ==== Rückgabecodes ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''SQLITE_OK'' | 0 | Erfolg | | ''SQLITE_ERROR'' | 1 | Allgemeiner Fehler | | ''SQLITE_BUSY'' | 5 | Datenbank ist gesperrt | | ''SQLITE_NOTFOUND'' | 12 | Nicht gefunden | | ''SQLITE_CONSTRAINT'' | 19 | Constraint-Verletzung (UNIQUE, NOT NULL …) | | ''SQLITE_MISUSE'' | 21 | Falsche Verwendung der API | | ''SQLITE_NOMEM'' | 7 | Kein Speicher verfügbar | | ''SQLITE_ROW'' | 100 | ''SQLiteStmtStep'' liefert eine Zeile | | ''SQLITE_DONE'' | 101 | ''SQLiteStmtStep'' hat alle Zeilen verarbeitet | ==== Spalten-Typkodes ==== ^ Konstante ^ Wert ^ SQLite-Typ ^ | ''SQLITE_INTEGER'' | 1 | Ganzzahl | | ''SQLITE_FLOAT'' | 2 | Gleitkommazahl | | ''SQLITE_TEXT'' | 3 | Text | | ''SQLITE_BLOB'' | 4 | Binärdaten | | ''SQLITE_NULL'' | 5 | NULL | ==== Destruktor-Sentinels ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''SQLITE_STATIC'' | 0 | SQLite kopiert die Daten nicht — Puffer muss bis Step/Reset gültig bleiben | | ''SQLITE_TRANSIENT'' | -1 | SQLite macht eine interne Kopie sofort | ---- ===== Typen ===== ==== SQLiteDB (24 Bytes) ==== Verbindungs-Handle. Immer über ''SQLiteOpen'' erstellen und über ''SQLiteClose'' freigeben. ==== SQLiteStmt (24 Bytes) ==== Prepared-Statement-Handle. Immer über ''SQLiteStmtPrepare'' erstellen und über ''SQLiteStmtFinalize'' freigeben. ---- ===== Funktionen ===== ==== Verbindung ==== Funktionen für Verbindungsaufbau und -verwaltung: ^ Signatur ^ Beschreibung ^ | ''SQLiteOpen(path: pchar): int64'' | Öffnet oder erstellt eine SQLite-Datenbank. ''„:memory:"'' für In-Memory-DB. Gibt SQLiteDB-Pointer zurück; 0 bei Fehler | | ''SQLiteClose(db: int64): void'' | Schließt Verbindung und gibt SQLiteDB-Speicher frei | | ''SQLiteExec(db: int64, sql: pchar): bool'' | Führt SQL ohne Ergebnismenge aus (CREATE TABLE, INSERT ohne Bind, PRAGMA …). Gibt ''true'' bei Erfolg | | ''SQLiteExecParam(db: int64, sql: pchar, params: int64, nparams: int64): bool'' | Führt parametrisiertes SQL mit String-Parametern aus. ''params'': Zeiger auf Array von ''nparams'' pchar-Pointern | | ''SQLiteErrmsg(db: int64): pchar'' | Fehlermeldung der letzten Operation | | ''SQLiteErrno(db: int64): int64'' | Fehlercode der letzten Operation | ==== Prepared Statements ==== Funktionen für Prepared Statements: ^ Signatur ^ Beschreibung ^ | ''SQLiteStmtPrepare(db: int64, sql: pchar): int64'' | Kompiliert SQL zu einem Prepared Statement. Gibt SQLiteStmt-Pointer zurück; 0 bei Fehler | | ''SQLiteStmtStep(stmt: int64): int64'' | Führt einen Schritt aus. Gibt ''SQLITE_ROW'' (Zeile verfügbar), ''SQLITE_DONE'' (fertig) oder Fehlercode zurück | | ''SQLiteStmtReset(stmt: int64): void'' | Setzt Statement zurück — Bindings bleiben erhalten, für Re-Execution mit neuen Werten | | ''SQLiteStmtFinalize(stmt: int64): void'' | Gibt Statement-Speicher frei | | ''SQLiteClearBindings(stmt: int64): void'' | Setzt alle Bindings auf NULL zurück | ==== Parameter-Binding (1-basierter Index) ==== ^ Signatur ^ Beschreibung ^ | ''SQLiteBindInt(stmt: int64, i: int64, v: int64): bool'' | Bindet ''int64'' an Parameter ''i'' | | ''SQLiteBindFloat(stmt: int64, i: int64, v: f64): bool'' | Bindet ''f64'' an Parameter ''i'' | | ''SQLiteBindStr(stmt: int64, i: int64, v: pchar): bool'' | Bindet null-terminierten String an Parameter ''i'' (SQLITE_STATIC — Puffer bis Step/Reset gültig halten) | | ''SQLiteBindNull(stmt: int64, i: int64): bool'' | Bindet NULL an Parameter ''i'' | | ''SQLiteBindBlob(stmt: int64, i: int64, ptr: int64, len: int64): bool'' | Bindet Binärdaten an Parameter ''i'' (SQLITE_STATIC) | ==== Column-Accessoren (0-basierter Index) ==== ^ Signatur ^ Beschreibung ^ | ''SQLiteColumnInt(stmt: int64, i: int64): int64'' | INTEGER-Spalte lesen | | ''SQLiteColumnFloat(stmt: int64, i: int64): f64'' | REAL-Spalte lesen | | ''SQLiteColumnText(stmt: int64, i: int64): pchar'' | TEXT-Spalte lesen — Pointer bis zum nächsten Step/Reset/Finalize gültig | | ''SQLiteColumnBlob(stmt: int64, i: int64): int64'' | BLOB-Spalte — Rohzeiger auf Daten (0 wenn NULL) | | ''SQLiteColumnBytes(stmt: int64, i: int64): int64'' | Länge der BLOB- oder TEXT-Spalte in Bytes | | ''SQLiteColumnType(stmt: int64, i: int64): int64'' | Typ-Code (SQLITE_INTEGER / SQLITE_FLOAT / SQLITE_TEXT / SQLITE_BLOB / SQLITE_NULL) | | ''SQLiteColumnIsNull(stmt: int64, i: int64): bool'' | Gibt ''true'' zurück wenn die Spalte NULL ist | | ''SQLiteColumnCount(stmt: int64): int64'' | Anzahl Spalten im Ergebnis | | ''SQLiteColumnName(stmt: int64, i: int64): pchar'' | Spaltenname (0-basiert) | ==== Transaktionen ==== Transaktionsverwaltung: ^ Signatur ^ Beschreibung ^ | ''SQLiteBegin(db: int64): bool'' | Startet eine Transaktion (BEGIN TRANSACTION) | | ''SQLiteCommit(db: int64): bool'' | Schreibt die Transaktion fest (COMMIT) | | ''SQLiteRollback(db: int64): bool'' | Macht die Transaktion rückgängig (ROLLBACK) | | ''SQLiteBeginImmediate(db: int64): bool'' | Transaktion mit sofortigem Schreib-Lock | | ''SQLiteBeginExclusive(db: int64): bool'' | Exklusive Transaktion (kein anderer Leser/Schreiber) | | ''SQLiteInTransaction(db: int64): bool'' | Gibt ''true'' zurück wenn eine Transaktion aktiv ist | ==== Hilfsfunktionen & Metadaten ==== ^ Signatur ^ Beschreibung ^ | ''SQLiteLastInsertId(db: int64): int64'' | Rowid des letzten erfolgreichen INSERT | | ''SQLiteChanges(db: int64): int64'' | Anzahl betroffener Zeilen des letzten INSERT/UPDATE/DELETE | | ''SQLiteTableExists(db: int64, table: pchar): bool'' | Gibt ''true'' zurück wenn die Tabelle in ''sqlite_master'' existiert | | ''SQLiteDropTable(db: int64, table: pchar): bool'' | Führt ''DROP TABLE IF EXISTS'' aus (mit Identifier-Validierung) | | ''SQLiteVacuum(db: int64): bool'' | Gibt ungenutzten Speicher in der DB-Datei frei | | ''SQLiteSetJournalMode(db: int64, mode: pchar): bool'' | Setzt den Journal-Modus: ''„WAL"'', ''„DELETE"'', ''„TRUNCATE"'', ''„PERSIST"'', ''„MEMORY"'', ''„OFF"'' | | ''SQLiteSetCacheSize(db: int64, pages: int64): bool'' | Setzt Cache-Größe in Seiten (PRAGMA cache_size) | ---- ===== Verwendung ===== ==== Tabelle erstellen und Daten einfügen ==== import std.db.sqlite; import std.io; fn SetupDB(): int64 { var db := SQLiteOpen("/tmp/test.db"); if (db == 0) { return 0; } SQLiteExec(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"); return db; } fn InsertUser(db: int64, name: pchar, age: int64): void { var stmt := SQLiteStmtPrepare(db, "INSERT INTO users (name, age) VALUES (?, ?)"); SQLiteBindStr(stmt, 1, name); SQLiteBindInt(stmt, 2, age); SQLiteStmtStep(stmt); SQLiteStmtFinalize(stmt); } ==== SELECT mit Prepared Statement ==== import std.db.sqlite; import std.io; fn PrintUsers(db: int64): void { var stmt := SQLiteStmtPrepare(db, "SELECT id, name, age FROM users ORDER BY name"); while (SQLiteStmtStep(stmt) == SQLITE_ROW) { PrintLn(IntToStr(SQLiteColumnInt(stmt, 0)) + ": " + SQLiteColumnText(stmt, 1) + " (" + IntToStr(SQLiteColumnInt(stmt, 2)) + ")"); } SQLiteStmtFinalize(stmt); } ==== Transaktion mit Rollback ==== import std.db.sqlite; fn BulkInsert(db: int64, names: int64, count: int64): bool { SQLiteBegin(db); var stmt := SQLiteStmtPrepare(db, "INSERT INTO users (name) VALUES (?)"); var i: int64 := 0; var ok: bool := true; while (i < count) { var name: pchar := peek64(names + i * 8) as pchar; SQLiteBindStr(stmt, 1, name); var rc := SQLiteStmtStep(stmt); if (rc != SQLITE_DONE) { ok := false; break; } SQLiteStmtReset(stmt); i := i + 1; } SQLiteStmtFinalize(stmt); if (ok) { SQLiteCommit(db); } else { SQLiteRollback(db); } return ok; } ==== In-Memory-Datenbank ==== import std.db.sqlite; fn TempDB(): int64 { var db := SQLiteOpen(":memory:"); SQLiteExec(db, "CREATE TABLE tmp (k TEXT, v TEXT)"); SQLiteSetJournalMode(db, "OFF"); // kein Journal für In-Memory nötig return db; } ==== WAL-Modus für Concurrent Reads ==== import std.db.sqlite; fn OpenWAL(path: pchar): int64 { var db := SQLiteOpen(path); SQLiteSetJournalMode(db, "WAL"); SQLiteSetCacheSize(db, 2000); // 2000 Seiten ≈ 8 MB bei 4096 Bytes/Seite return db; } ---- ===== Hinweise ===== * Parameter-Indizes bei Binding sind **1-basiert**, Column-Indizes bei Accessoren sind **0-basiert**. * ''SQLiteBindStr'' verwendet ''SQLITE_STATIC'' — der String-Puffer muss bis zum nächsten ''SQLiteStmtStep'', ''SQLiteStmtReset'' oder ''SQLiteStmtFinalize'' gültig bleiben. * ''SQLiteColumnText'' gibt einen Pointer auf SQLite-internen Speicher zurück — nicht nach ''Step''/''Reset''/''Finalize'' verwenden. * Für schreibintensive Workloads: WAL-Modus aktivieren (''SQLiteSetJournalMode(db, "WAL")'') und mehrere INSERT in Transaktionen bündeln. * ''SQLiteDropTable'' validiert den Tabellennamen auf erlaubte Zeichen (A-Z, a-z, 0-9, _, .) — schützt vor SQL-Injection. ---- ===== Verwandte Units ===== * ''[[lyx_-_programmiersprache:units:db:postgres|std.db.postgres]]'' — PostgreSQL (natives Wire-Protokoll) * ''[[lyx_-_programmiersprache:units:db:mysql|std.db.mysql]]'' — MySQL/MariaDB * ''[[lyx_-_programmiersprache:units:db:redis|std.db.redis]]'' — Redis Key-Value-Store Letzte Aktualisierung: 2026-06-05