v0.3: Fase 2A+2B complete - Major feature additions

New features:
- Backup API: Backup struct with step(), progress(), remaining(), pageCount()
- Convenience functions: backupToFile(), loadFromFile(), backupDatabase()
- ATTACH/DETACH: attach(), attachMemory(), detach(), listDatabases()
- User-Defined Functions: createScalarFunction(), FunctionContext, FunctionValue
- Custom Collations: createCollation(), CollationFn, removeCollation()
- Named parameters: bindTextNamed(), bindIntNamed(), etc. (:name, @name, $name)
- Savepoints: savepoint(), release(), rollbackTo()
- Configuration: setBusyTimeout(), setJournalMode(), setSynchronous(), enableWalMode()
- Statement metadata: sql(), isReadOnly(), parameterCount(), parameterIndex()
- Transaction: beginExclusive()
- Utilities: errorCode(), extendedErrorCode(), interrupt(), isReadOnly(), filename()
- Additional bind/column: bindBool(), bindZeroblob(), columnBool(), columnBytes(), columnDeclType()

Documentation:
- Created docs/API.md - Complete API reference
- Created docs/ARCHITECTURE.md - Technical architecture
- Created docs/CGO_PARITY_ANALYSIS.md - Feature parity tracking with go-sqlite3
- Updated CLAUDE.md with all new features

All 20 tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
reugenio 2025-12-08 17:54:50 +01:00
parent a290859182
commit 532cf827f8
5 changed files with 2817 additions and 132 deletions

579
CLAUDE.md
View file

@ -1,165 +1,406 @@
# zsqlite - SQLite Wrapper para Zig # zsqlite - SQLite Wrapper para Zig
> **Fecha creación**: 2025-12-08 > **Ultima actualizacion**: 2025-12-08
> **Versión Zig**: 0.15.2 > **Lenguaje**: Zig 0.15.2
> **Estado**: En desarrollo inicial > **Estado**: v0.3 - Fase 2B completada
> **Inspiracion**: CGo go-sqlite3, SQLite C API
## Descripción del Proyecto ## Descripcion del Proyecto
Wrapper idiomático de SQLite para Zig. Compila SQLite amalgamation directamente en el binario, resultando en un ejecutable único sin dependencias externas. **zsqlite** es un wrapper idiomatico de SQLite para Zig que compila SQLite amalgamation directamente en el binario, resultando en un ejecutable unico sin dependencias externas.
**Filosofía**: **Filosofia**:
- Zero dependencias runtime - Zero dependencias runtime
- API idiomática Zig (errores, allocators, iteradores) - API idiomatica Zig (errores, allocators, iteradores)
- Binario único y portable - Binario unico y portable
- Compatible con bases de datos SQLite existentes - Compatible con bases de datos SQLite existentes
- Calidad open source (doc comments, codigo claro)
**Objetivo**: Ser el pilar para trabajar con databases en Zig con codigo 100% propio, replicando toda la funcionalidad de wrappers maduros como CGo go-sqlite3.
---
## Estado Actual del Proyecto
### Implementacion v0.3 (Fase 2B Completada)
| Componente | Estado | Archivo |
|------------|--------|---------|
| **Core** | | |
| Database open/close | ✅ | `src/root.zig` |
| Database open with flags | ✅ | `src/root.zig` |
| exec() SQL simple | ✅ | `src/root.zig` |
| execAlloc() runtime strings | ✅ | `src/root.zig` |
| Error mapping completo | ✅ | `src/root.zig` |
| **Prepared Statements** | | |
| prepare/finalize | ✅ | `src/root.zig` |
| prepareAlloc() runtime strings | ✅ | `src/root.zig` |
| reset/clearBindings | ✅ | `src/root.zig` |
| step() iteration | ✅ | `src/root.zig` |
| sql() / isReadOnly() | ✅ | `src/root.zig` |
| parameterCount/Index/Name | ✅ | `src/root.zig` |
| **Bind Parameters** | | |
| bindNull | ✅ | `src/root.zig` |
| bindInt (i64) | ✅ | `src/root.zig` |
| bindFloat (f64) | ✅ | `src/root.zig` |
| bindText | ✅ | `src/root.zig` |
| bindBlob | ✅ | `src/root.zig` |
| bindBool | ✅ | `src/root.zig` |
| bindZeroblob | ✅ | `src/root.zig` |
| **Named Parameters** | | |
| bindNullNamed | ✅ | `src/root.zig` |
| bindIntNamed | ✅ | `src/root.zig` |
| bindFloatNamed | ✅ | `src/root.zig` |
| bindTextNamed | ✅ | `src/root.zig` |
| bindBlobNamed | ✅ | `src/root.zig` |
| bindBoolNamed | ✅ | `src/root.zig` |
| **Column Access** | | |
| columnCount | ✅ | `src/root.zig` |
| columnName | ✅ | `src/root.zig` |
| columnType | ✅ | `src/root.zig` |
| columnInt | ✅ | `src/root.zig` |
| columnFloat | ✅ | `src/root.zig` |
| columnText | ✅ | `src/root.zig` |
| columnBlob | ✅ | `src/root.zig` |
| columnIsNull | ✅ | `src/root.zig` |
| columnBool | ✅ | `src/root.zig` |
| columnBytes | ✅ | `src/root.zig` |
| columnDeclType | ✅ | `src/root.zig` |
| **Transacciones** | | |
| begin/commit/rollback | ✅ | `src/root.zig` |
| beginImmediate | ✅ | `src/root.zig` |
| beginExclusive | ✅ | `src/root.zig` |
| **Savepoints** | | |
| savepoint(name) | ✅ | `src/root.zig` |
| release(name) | ✅ | `src/root.zig` |
| rollbackTo(name) | ✅ | `src/root.zig` |
| **Pragmas/Config** | | |
| setBusyTimeout | ✅ | `src/root.zig` |
| setJournalMode | ✅ | `src/root.zig` |
| setSynchronous | ✅ | `src/root.zig` |
| enableWalMode | ✅ | `src/root.zig` |
| setForeignKeys | ✅ | `src/root.zig` |
| **ATTACH/DETACH** | | |
| attach(file, schema) | ✅ | `src/root.zig` |
| attachMemory(schema) | ✅ | `src/root.zig` |
| detach(schema) | ✅ | `src/root.zig` |
| listDatabases() | ✅ | `src/root.zig` |
| **Backup API** | | |
| Backup.init/initMain | ✅ | `src/root.zig` |
| Backup.step/stepAll | ✅ | `src/root.zig` |
| Backup.finish/deinit | ✅ | `src/root.zig` |
| Backup.remaining/pageCount | ✅ | `src/root.zig` |
| Backup.progress | ✅ | `src/root.zig` |
| backupDatabase() | ✅ | `src/root.zig` |
| backupToFile() | ✅ | `src/root.zig` |
| loadFromFile() | ✅ | `src/root.zig` |
| **User-Defined Functions** | | |
| createScalarFunction() | ✅ | `src/root.zig` |
| removeFunction() | ✅ | `src/root.zig` |
| FunctionContext (setInt/Float/Text/etc) | ✅ | `src/root.zig` |
| FunctionValue (asInt/Float/Text/etc) | ✅ | `src/root.zig` |
| **Custom Collations** | | |
| createCollation() | ✅ | `src/root.zig` |
| removeCollation() | ✅ | `src/root.zig` |
| **Utilidades** | | |
| lastInsertRowId | ✅ | `src/root.zig` |
| changes/totalChanges | ✅ | `src/root.zig` |
| errorMessage | ✅ | `src/root.zig` |
| errorCode/extendedErrorCode | ✅ | `src/root.zig` |
| interrupt | ✅ | `src/root.zig` |
| isReadOnly | ✅ | `src/root.zig` |
| filename | ✅ | `src/root.zig` |
| version/versionNumber | ✅ | `src/root.zig` |
### Tests
| Categoria | Tests | Estado |
|-----------|-------|--------|
| Version | 1 | ✅ |
| Open/Close | 1 | ✅ |
| Create/Insert | 1 | ✅ |
| Prepared Statements | 1 | ✅ |
| Select Query | 1 | ✅ |
| Transaction Commit | 1 | ✅ |
| Transaction Rollback | 1 | ✅ |
| Foreign Keys | 1 | ✅ |
| Null Values | 1 | ✅ |
| Blob Data | 1 | ✅ |
| Named Parameters | 1 | ✅ |
| Savepoints | 1 | ✅ |
| Busy Timeout | 1 | ✅ |
| Statement Metadata | 1 | ✅ |
| Boolean bind/column | 1 | ✅ |
| Backup memory to memory | 1 | ✅ |
| Backup convenience | 1 | ✅ |
| ATTACH/DETACH | 1 | ✅ |
| User-defined functions | 1 | ✅ |
| Custom collations | 1 | ✅ |
| **Total** | **20** | ✅ |
---
## Roadmap
### Fase 1 - Core (COMPLETADO)
- [x] Estructura proyecto
- [x] Compilar SQLite amalgamation
- [x] Abrir/cerrar bases de datos
- [x] Ejecutar SQL simple (exec)
- [x] Prepared statements basicos
- [x] Bind de parametros (int, text, blob, null, float)
- [x] Iterador de resultados
- [x] Transacciones basicas
### Fase 2A - Paridad CGo Core (COMPLETADO)
- [x] SAVEPOINT support
- [x] Named parameters (:name, @name, $name)
- [x] Busy timeout
- [x] WAL mode helpers
- [x] Statement metadata (sql, isReadOnly, parameterCount)
- [x] Boolean bind/column
- [x] Error codes (errorCode, extendedErrorCode)
- [x] Database info (isReadOnly, filename)
- [x] interrupt()
### Fase 2B - Paridad CGo Avanzada (COMPLETADO)
- [x] Backup API completo
- [x] User-defined functions (scalar)
- [x] Collations personalizadas
- [x] ATTACH/DETACH databases
- [ ] Batch bind con tuples/structs
- [ ] Row iterator idiomatico
### Fase 3 - Avanzado (EN PROGRESO)
- [ ] Blob streaming (para archivos grandes)
- [ ] User-defined functions (aggregate)
- [ ] Authorizer callback
- [ ] Progress handler
- [ ] Update/Commit hooks
- [ ] Connection pooling
### Fase 4 - Extras
- [ ] Connection URI parsing
- [ ] Virtual tables
- [ ] FTS5 helpers
- [ ] JSON1 helpers
- [ ] R-Tree helpers
---
## Arquitectura ## Arquitectura
### Estructura de Archivos
``` ```
zsqlite/ zsqlite/
├── CLAUDE.md # Este archivo ├── CLAUDE.md # Este archivo - estado del proyecto
├── build.zig # Sistema de build ├── build.zig # Sistema de build
├── src/ ├── src/
│ ├── root.zig # Exports públicos │ └── root.zig # Wrapper principal (~1000 lineas)
│ ├── sqlite.zig # Wrapper principal
│ ├── statement.zig # Prepared statements
│ ├── row.zig # Iterador de filas
│ └── errors.zig # Mapeo de errores SQLite
├── vendor/ ├── vendor/
│ ├── sqlite3.c # SQLite amalgamation │ ├── sqlite3.c # SQLite 3.47.2 amalgamation
│ └── sqlite3.h # Headers SQLite │ ├── sqlite3.h # Headers SQLite
└── examples/ │ ├── sqlite3ext.h # Extension headers
└── basic.zig # Ejemplo básico │ └── shell.c # SQLite shell (no usado)
├── examples/
│ └── basic.zig # Ejemplo basico funcional
└── docs/
├── ARCHITECTURE.md # Diseno interno
├── API.md # Referencia rapida API
└── CGO_PARITY_ANALYSIS.md # Analisis de paridad con go-sqlite3
``` ```
## API Objetivo ### SQLite Amalgamation
```zig **Version**: SQLite 3.47.2
const std = @import("std");
const sqlite = @import("zsqlite");
pub fn main() !void { **Flags de compilacion**:
var db = try sqlite.open("test.db");
defer db.close();
// Ejecutar SQL directo
try db.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)");
// Prepared statement con parámetros
var stmt = try db.prepare("INSERT INTO users (name) VALUES (?)");
defer stmt.deinit();
try stmt.bind(.{ "Alice" });
try stmt.exec();
stmt.reset();
try stmt.bind(.{ "Bob" });
try stmt.exec();
// Query con iterador
var query = try db.prepare("SELECT id, name FROM users");
defer query.deinit();
while (try query.step()) |row| {
const id = row.int(0);
const name = row.text(1);
std.debug.print("User {}: {s}\n", .{ id, name });
}
}
```
## Funcionalidades Planificadas
### Fase 1 - Core (Actual)
- [x] Estructura proyecto
- [ ] Compilar SQLite amalgamation
- [ ] Abrir/cerrar bases de datos
- [ ] Ejecutar SQL simple (exec)
- [ ] Prepared statements básicos
- [ ] Bind de parámetros (int, text, blob, null)
- [ ] Iterador de resultados
### Fase 2 - Transacciones y Errores
- [ ] BEGIN/COMMIT/ROLLBACK helpers
- [ ] Mapeo completo errores SQLite
- [ ] SAVEPOINT support
### Fase 3 - Avanzado
- [ ] Blob streaming (para archivos grandes)
- [ ] User-defined functions
- [ ] Collations personalizadas
- [ ] Backup API
## SQLite Amalgamation
Usamos SQLite amalgamation (sqlite3.c + sqlite3.h) que es la forma recomendada de embeber SQLite. Es un único archivo .c con todo el código de SQLite.
**Versión objetivo**: SQLite 3.45+ (última estable)
**Flags de compilación recomendados**:
``` ```
-DSQLITE_DQS=0 # Disable double-quoted strings -DSQLITE_DQS=0 # Disable double-quoted strings
-DSQLITE_THREADSAFE=0 # Single-threaded (más rápido) -DSQLITE_THREADSAFE=0 # Single-threaded (mas rapido)
-DSQLITE_DEFAULT_MEMSTATUS=0 # Disable memory tracking -DSQLITE_DEFAULT_MEMSTATUS=0 # Disable memory tracking
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_LIKE_DOESNT_MATCH_BLOBS
-DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_DEPRECATED
-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_SHARED_CACHE
-DSQLITE_USE_ALLOCA
-DSQLITE_ENABLE_FTS5 # Full-text search -DSQLITE_ENABLE_FTS5 # Full-text search
-DSQLITE_ENABLE_JSON1 # JSON functions -DSQLITE_ENABLE_JSON1 # JSON functions
-DSQLITE_ENABLE_RTREE # R-Tree geospatial
-DSQLITE_OMIT_LOAD_EXTENSION # No dynamic extensions
``` ```
## Compilación
```bash
# Descargar SQLite amalgamation (una sola vez)
cd vendor
curl -O https://sqlite.org/2024/sqlite-amalgamation-3450000.zip
unzip sqlite-amalgamation-3450000.zip
mv sqlite-amalgamation-3450000/* .
rm -rf sqlite-amalgamation-3450000*
# Compilar
zig build
# Ejecutar tests
zig build test
# Ejecutar ejemplo
zig build example
```
## Diferencias con otros wrappers
| Característica | zsqlite | zig-sqlite | zqlite.zig |
|----------------|---------|------------|------------|
| Compila SQLite | Sí | No (linkea) | Sí |
| API idiomática | Sí | Parcial | Sí |
| Zero alloc option | Planificado | No | No |
| Zig 0.15 | Sí | ? | ? |
## Uso en simifactu-zig (futuro)
Este wrapper está diseñado para ser drop-in replacement del uso de SQLite en simifactu-fyne, soportando:
- Foreign keys
- Transactions
- Prepared statements
- BLOB storage
- JSON functions
--- ---
## Equipo y Metodología ## API Actual
### Normas de Trabajo ### Abrir Base de Datos
**IMPORTANTE**: Todas las normas de trabajo están en: ```zig
const sqlite = @import("zsqlite");
// In-memory
var db = try sqlite.openMemory();
defer db.close();
// Archivo
var db = try sqlite.open("test.db");
defer db.close();
// Con flags
var db = try sqlite.Database.openWithFlags("test.db", .{
.read_only = true,
.create = false,
});
defer db.close();
```
### Ejecutar SQL Simple
```zig
try db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
try db.exec("INSERT INTO users (name) VALUES ('Alice')");
// Con string runtime
try db.execAlloc(allocator, sql_string);
```
### Prepared Statements
```zig
var stmt = try db.prepare("INSERT INTO users (name, age) VALUES (?, ?)");
defer stmt.finalize();
try stmt.bindText(1, "Bob");
try stmt.bindInt(2, 30);
_ = try stmt.step();
// Reusar
try stmt.reset();
try stmt.clearBindings();
try stmt.bindText(1, "Charlie");
try stmt.bindInt(2, 25);
_ = try stmt.step();
```
### Named Parameters (NUEVO v0.2)
```zig
var stmt = try db.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
defer stmt.finalize();
try stmt.bindTextNamed(":name", "Alice");
try stmt.bindIntNamed(":age", 30);
_ = try stmt.step();
// Tambien soporta @name y $name estilos
```
### Queries
```zig
var stmt = try db.prepare("SELECT id, name FROM users ORDER BY id");
defer stmt.finalize();
while (try stmt.step()) {
const id = stmt.columnInt(0);
const name = stmt.columnText(1) orelse "(null)";
std.debug.print("User {}: {s}\n", .{ id, name });
}
```
### Transacciones
```zig
try db.begin();
errdefer db.rollback() catch {};
try db.exec("INSERT INTO users (name) VALUES ('Alice')");
try db.exec("INSERT INTO users (name) VALUES ('Bob')");
try db.commit();
```
### Savepoints (NUEVO v0.2)
```zig
const allocator = std.heap.page_allocator;
try db.begin();
try db.savepoint(allocator, "sp1");
try db.exec("INSERT INTO test VALUES (1)");
// Revertir al savepoint
try db.rollbackTo(allocator, "sp1");
// O confirmar el savepoint
try db.release(allocator, "sp1");
try db.commit();
```
### WAL Mode (NUEVO v0.2)
```zig
const allocator = std.heap.page_allocator;
// Habilitar WAL mode con settings recomendados
try db.enableWalMode(allocator);
// O configurar individualmente
try db.setJournalMode(allocator, "WAL");
try db.setSynchronous(allocator, "NORMAL");
try db.setBusyTimeout(5000); // 5 segundos
```
### Foreign Keys
```zig
try db.setForeignKeys(true);
```
---
## Comandos
```bash
# Zig path
ZIG=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig
# Compilar
$ZIG build
# Tests
$ZIG build test
# Ejecutar ejemplo
$ZIG build basic && ./zig-out/bin/basic
```
---
## Equipo y Metodologia
### Normas de Trabajo Centralizadas
**IMPORTANTE**: Todas las normas de trabajo estan en:
``` ```
/mnt/cello2/arno/re/recode/TEAM_STANDARDS/ /mnt/cello2/arno/re/recode/TEAM_STANDARDS/
``` ```
**Archivos clave a leer**:
- `LAST_UPDATE.md` - **LEER PRIMERO** - Cambios recientes en normas
- `NORMAS_TRABAJO_CONSENSUADAS.md` - Metodologia fundamental
- `QUICK_REFERENCE.md` - Cheat sheet rapido
### Estandares Zig Open Source (Seccion #24)
- **Claridad**: Codigo autoexplicativo, nombres descriptivos
- **Doc comments**: `///` en todas las funciones publicas
- **Idiomatico**: snake_case, error handling explicito
- **Sin magia**: Preferir codigo explicito sobre abstracciones complejas
### Control de Versiones ### Control de Versiones
```bash ```bash
@ -167,18 +408,92 @@ Este wrapper está diseñado para ser drop-in replacement del uso de SQLite en s
git remote: git@git.reugenio.com:reugenio/zsqlite.git git remote: git@git.reugenio.com:reugenio/zsqlite.git
# Branches # Branches
main # Código estable main # Codigo estable
develop # Desarrollo activo
``` ```
### Zig Path ---
```bash ## Referencias
ZIG=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig
``` ### CGo go-sqlite3 (Referencia principal)
- Repo: https://github.com/mattn/go-sqlite3
- Objetivo: Replicar toda su funcionalidad en Zig
- Analisis: `docs/CGO_PARITY_ANALYSIS.md`
### SQLite C API
- Docs: https://sqlite.org/c3ref/intro.html
- Objetivo: Wrapper completo de funciones relevantes
### Otros Wrappers Zig (Referencia)
- zig-sqlite: https://github.com/vrischmann/zig-sqlite
- zqlite.zig: https://github.com/karlseguin/zqlite.zig
---
## Historial de Desarrollo
### 2025-12-08 - v0.3 (Fase 2B Completada)
- **Backup API completo**:
- Backup struct con init/step/finish/remaining/pageCount/progress
- Funciones de conveniencia: backupDatabase, backupToFile, loadFromFile
- **User-Defined Functions (Scalar)**:
- createScalarFunction() para registrar funciones Zig en SQL
- FunctionContext para retornar resultados
- FunctionValue para acceder a argumentos
- Cleanup automatico con destructores
- **Custom Collations**:
- createCollation() para orden personalizado de strings
- removeCollation() para eliminar collations
- **ATTACH/DETACH Databases**:
- attach(), attachMemory(), detach()
- listDatabases() para enumerar schemas adjuntos
- 20 tests pasando
- ~1700 lineas de codigo en root.zig
### 2025-12-08 - v0.2 (Fase 2A Completada)
- Named parameters (:name, @name, $name)
- Savepoints (savepoint, release, rollbackTo)
- WAL mode helpers (enableWalMode, setJournalMode, setSynchronous)
- Busy timeout (setBusyTimeout)
- Statement metadata (sql, isReadOnly, parameterCount, parameterIndex, parameterName)
- Boolean bind/column (bindBool, columnBool)
- Error codes (errorCode, extendedErrorCode)
- Database info (isReadOnly, filename, interrupt)
- bindZeroblob, columnBytes, columnDeclType
- 15 tests pasando
- Documentacion docs/ creada (ARCHITECTURE.md, API.md, CGO_PARITY_ANALYSIS.md)
### 2025-12-08 - v0.1 (Core Funcional)
- Estructura inicial del proyecto
- SQLite 3.47.2 amalgamation compilando
- Database, Statement, Error types
- Bind parameters completos (null, int, float, text, blob)
- Column access completo
- Transacciones basicas
- 10 tests unitarios pasando
- Ejemplo basic.zig funcional
--- ---
## Notas de Desarrollo ## Notas de Desarrollo
*Se irán añadiendo conforme avance el proyecto* ### Proxima Sesion
1. Blob streaming (para archivos grandes)
2. User-defined aggregate functions
3. Update/Commit hooks
4. Batch bind con comptime structs
### Lecciones Aprendidas
- SQLite amalgamation compila limpiamente con Zig build system
- `@cImport` funciona bien para headers SQLite
- SQLITE_TRANSIENT necesario para strings/blobs que Zig puede mover
- En Zig 0.15 usar `std.fmt.allocPrint` + `\x00` manual en lugar de `allocPrintZ`
- Named parameters funcionan con el prefijo incluido (":name", no "name")
- Callbacks C requieren `callconv(.c)` y estructuras wrapper para pasar estado
- `std.ArrayListUnmanaged` en Zig 0.15 (no `ArrayList.init`)
- UDFs y Collations usan page_allocator interno para simplicidad
---
**© zsqlite - Wrapper SQLite para Zig**
*2025-12-08 - En desarrollo activo*

533
docs/API.md Normal file
View file

@ -0,0 +1,533 @@
# zsqlite - API Reference
> **Version**: 0.3
> **Ultima actualizacion**: 2025-12-08
## Quick Reference
```zig
const sqlite = @import("zsqlite");
// Abrir base de datos
var db = try sqlite.openMemory(); // In-memory
var db = try sqlite.open("file.db"); // Archivo
defer db.close();
// SQL directo
try db.exec("CREATE TABLE ...");
// Prepared statement
var stmt = try db.prepare("SELECT * FROM users WHERE id = ?");
defer stmt.finalize();
try stmt.bindInt(1, 42);
while (try stmt.step()) {
const name = stmt.columnText(1);
}
// Named parameters
var stmt = try db.prepare("INSERT INTO users VALUES (:name, :age)");
try stmt.bindTextNamed(":name", "Alice");
try stmt.bindIntNamed(":age", 30);
// Transacciones
try db.begin();
// ... operaciones ...
try db.commit(); // o db.rollback()
// Savepoints
try db.savepoint(allocator, "sp1");
try db.rollbackTo(allocator, "sp1");
try db.release(allocator, "sp1");
// Backup
try sqlite.backupToFile(&db, "backup.db");
var restored = try sqlite.loadFromFile("backup.db");
// User-defined functions
try db.createScalarFunction("double", 1, myDoubleFunc);
// Custom collations
try db.createCollation("NOCASE2", myCaseInsensitiveCompare);
```
---
## Funciones de Modulo
### open
```zig
pub fn open(path: [:0]const u8) Error!Database
```
Abre una base de datos SQLite.
**Parametros:**
- `path`: Ruta al archivo. Usar `":memory:"` para base de datos en memoria.
**Retorna:** `Database` o error.
---
### openMemory
```zig
pub fn openMemory() Error!Database
```
Abre una base de datos en memoria.
---
### version / versionNumber
```zig
pub fn version() []const u8
pub fn versionNumber() i32
```
Retorna la version de SQLite como string ("3.47.2") o numero (3047002).
---
### backupDatabase
```zig
pub fn backupDatabase(dest_db: *Database, source_db: *Database) Error!void
```
Copia una base de datos completa a otra.
---
### backupToFile
```zig
pub fn backupToFile(source_db: *Database, path: [:0]const u8) Error!void
```
Guarda una base de datos a un archivo.
---
### loadFromFile
```zig
pub fn loadFromFile(path: [:0]const u8) Error!Database
```
Carga una base de datos desde archivo a memoria.
---
## Database
### Apertura y Cierre
| Funcion | Descripcion |
|---------|-------------|
| `open(path)` | Abre conexion (read-write, create) |
| `openWithFlags(path, flags)` | Abre con flags especificos |
| `close()` | Cierra la conexion |
### Ejecucion SQL
| Funcion | Descripcion |
|---------|-------------|
| `exec(sql)` | Ejecuta SQL sin resultados |
| `execAlloc(alloc, sql)` | exec con string runtime |
| `prepare(sql)` | Crea prepared statement |
| `prepareAlloc(alloc, sql)` | prepare con string runtime |
### Transacciones
| Funcion | Descripcion |
|---------|-------------|
| `begin()` | Inicia transaccion (DEFERRED) |
| `beginImmediate()` | Inicia con lock inmediato |
| `beginExclusive()` | Inicia con lock exclusivo |
| `commit()` | Confirma transaccion |
| `rollback()` | Revierte transaccion |
### Savepoints
```zig
pub fn savepoint(self: *Database, allocator: Allocator, name: []const u8) !void
pub fn release(self: *Database, allocator: Allocator, name: []const u8) !void
pub fn rollbackTo(self: *Database, allocator: Allocator, name: []const u8) !void
```
Savepoints permiten transacciones anidadas.
**Ejemplo:**
```zig
try db.begin();
try db.savepoint(alloc, "sp1");
try db.exec("INSERT ...");
try db.rollbackTo(alloc, "sp1"); // Revierte INSERT
try db.release(alloc, "sp1");
try db.commit();
```
### Configuracion
| Funcion | Descripcion |
|---------|-------------|
| `setForeignKeys(enabled)` | Habilita/deshabilita FKs |
| `setBusyTimeout(ms)` | Timeout en ms para locks |
| `setJournalMode(alloc, mode)` | "WAL", "DELETE", etc |
| `setSynchronous(alloc, mode)` | "OFF", "NORMAL", "FULL" |
| `enableWalMode(alloc)` | WAL + NORMAL sync |
### ATTACH/DETACH
```zig
pub fn attach(self: *Database, alloc: Allocator, path: []const u8, schema: []const u8) !void
pub fn attachMemory(self: *Database, alloc: Allocator, schema: []const u8) !void
pub fn detach(self: *Database, alloc: Allocator, schema: []const u8) !void
pub fn listDatabases(self: *Database, alloc: Allocator) ![][]const u8
pub fn freeDatabaseList(alloc: Allocator, list: [][]const u8) void
```
**Ejemplo:**
```zig
try db.attachMemory(alloc, "cache");
try db.exec("CREATE TABLE cache.items (...)");
// SELECT * FROM cache.items
try db.detach(alloc, "cache");
```
### User-Defined Functions
```zig
pub fn createScalarFunction(
self: *Database,
name: [:0]const u8,
num_args: i32,
func: ScalarFn,
) !void
pub fn removeFunction(self: *Database, name: [:0]const u8, num_args: i32) Error!void
```
**Ejemplo:**
```zig
fn myDouble(ctx: FunctionContext, args: []const FunctionValue) void {
if (args[0].isNull()) {
ctx.setNull();
return;
}
ctx.setInt(args[0].asInt() * 2);
}
try db.createScalarFunction("double", 1, myDouble);
// SELECT double(value) FROM table
```
### Custom Collations
```zig
pub fn createCollation(self: *Database, name: [:0]const u8, func: CollationFn) !void
pub fn removeCollation(self: *Database, name: [:0]const u8) Error!void
```
**Ejemplo:**
```zig
fn reverseOrder(a: []const u8, b: []const u8) i32 {
return -std.mem.order(u8, a, b);
}
try db.createCollation("REVERSE", reverseOrder);
// SELECT * FROM table ORDER BY name COLLATE REVERSE
```
### Utilidades
| Funcion | Descripcion |
|---------|-------------|
| `lastInsertRowId()` | Ultimo rowid insertado |
| `changes()` | Filas modificadas (ultimo stmt) |
| `totalChanges()` | Total filas desde conexion |
| `errorMessage()` | Mensaje de error reciente |
| `errorCode()` | Codigo de error |
| `extendedErrorCode()` | Codigo extendido |
| `interrupt()` | Interrumpe operacion |
| `isReadOnly(db_name)` | Si DB es readonly |
| `filename(db_name)` | Ruta del archivo |
---
## Statement
### Ciclo de Vida
| Funcion | Descripcion |
|---------|-------------|
| `finalize()` | Libera el statement |
| `reset()` | Resetea para re-ejecucion |
| `clearBindings()` | Limpia parametros |
| `step()` | Ejecuta un paso (true=hay fila) |
### Metadata
| Funcion | Descripcion |
|---------|-------------|
| `sql()` | Texto SQL del statement |
| `isReadOnly()` | Si es SELECT |
| `parameterCount()` | Numero de parametros |
| `parameterIndex(name)` | Indice de parametro named |
| `parameterName(index)` | Nombre de parametro |
### Bind Parameters (1-indexed)
| Funcion | Descripcion |
|---------|-------------|
| `bindNull(idx)` | NULL |
| `bindInt(idx, val)` | i64 |
| `bindFloat(idx, val)` | f64 |
| `bindText(idx, val)` | []const u8 |
| `bindBlob(idx, val)` | []const u8 |
| `bindBool(idx, val)` | bool (como 0/1) |
| `bindZeroblob(idx, size)` | Blob de ceros |
### Named Parameters
| Funcion | Descripcion |
|---------|-------------|
| `bindNullNamed(name)` | `:name`, `@name`, `$name` |
| `bindIntNamed(name, val)` | |
| `bindFloatNamed(name, val)` | |
| `bindTextNamed(name, val)` | |
| `bindBlobNamed(name, val)` | |
| `bindBoolNamed(name, val)` | |
### Column Access (0-indexed)
| Funcion | Descripcion |
|---------|-------------|
| `columnCount()` | Numero de columnas |
| `columnName(idx)` | Nombre |
| `columnType(idx)` | ColumnType enum |
| `columnInt(idx)` | i64 |
| `columnFloat(idx)` | f64 |
| `columnText(idx)` | ?[]const u8 |
| `columnBlob(idx)` | ?[]const u8 |
| `columnBool(idx)` | bool |
| `columnIsNull(idx)` | bool |
| `columnBytes(idx)` | Tamano en bytes |
| `columnDeclType(idx)` | Tipo declarado |
---
## Backup
```zig
pub const Backup = struct {
pub fn init(dest: *Database, dest_name: [:0]const u8,
source: *Database, source_name: [:0]const u8) Error!Backup
pub fn initMain(dest: *Database, source: *Database) Error!Backup
pub fn step(self: *Backup, n_pages: i32) Error!bool
pub fn stepAll(self: *Backup) Error!void
pub fn remaining(self: *Backup) i32
pub fn pageCount(self: *Backup) i32
pub fn progress(self: *Backup) u8 // 0-100
pub fn finish(self: *Backup) Error!void
pub fn deinit(self: *Backup) void
};
```
**Ejemplo con progreso:**
```zig
var backup = try Backup.initMain(&dest_db, &source_db);
defer backup.deinit();
while (try backup.step(100)) {
std.debug.print("Progress: {}%\n", .{backup.progress()});
}
```
---
## User-Defined Functions
### FunctionContext
```zig
pub const FunctionContext = struct {
pub fn setNull(self: Self) void
pub fn setInt(self: Self, value: i64) void
pub fn setFloat(self: Self, value: f64) void
pub fn setText(self: Self, value: []const u8) void
pub fn setBlob(self: Self, value: []const u8) void
pub fn setError(self: Self, msg: []const u8) void
};
```
### FunctionValue
```zig
pub const FunctionValue = struct {
pub fn getType(self: Self) ColumnType
pub fn isNull(self: Self) bool
pub fn asInt(self: Self) i64
pub fn asFloat(self: Self) f64
pub fn asText(self: Self) ?[]const u8
pub fn asBlob(self: Self) ?[]const u8
};
```
### ScalarFn Type
```zig
pub const ScalarFn = *const fn (ctx: FunctionContext, args: []const FunctionValue) void;
```
---
## Types
### OpenFlags
```zig
pub const OpenFlags = struct {
read_only: bool = false,
read_write: bool = true,
create: bool = true,
uri: bool = false,
memory: bool = false,
no_mutex: bool = false,
full_mutex: bool = false,
};
```
### ColumnType
```zig
pub const ColumnType = enum {
integer,
float,
text,
blob,
null_value,
};
```
### CollationFn
```zig
pub const CollationFn = *const fn (a: []const u8, b: []const u8) i32;
```
Retorna: negativo si a < b, cero si a == b, positivo si a > b.
### Error
Mapeo completo de codigos SQLite:
| Error | Descripcion |
|-------|-------------|
| `SqliteError` | Error generico |
| `Busy` | Database bloqueada |
| `Locked` | Tabla bloqueada |
| `Constraint` | Violacion de constraint |
| `OutOfMemory` | Sin memoria |
| `IoError` | Error de I/O |
| `Corrupt` | DB corrupta |
| `CantOpen` | No se puede abrir |
| `ReadOnly` | DB es readonly |
| `Range` | Parametro fuera de rango |
| ... | (25+ errores mapeados) |
---
## Ejemplos Completos
### CRUD con Named Parameters
```zig
var db = try sqlite.openMemory();
defer db.close();
try db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
// Insert con named params
var insert = try db.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
defer insert.finalize();
try insert.bindTextNamed(":name", "Alice");
try insert.bindIntNamed(":age", 30);
_ = try insert.step();
// Query
var query = try db.prepare("SELECT * FROM users WHERE age > :min_age");
defer query.finalize();
try query.bindIntNamed(":min_age", 25);
while (try query.step()) {
const name = query.columnText(1) orelse "(null)";
std.debug.print("User: {s}\n", .{name});
}
```
### Backup con Progreso
```zig
var source = try sqlite.open("production.db");
defer source.close();
var dest = try sqlite.open("backup.db");
defer dest.close();
var backup = try sqlite.Backup.initMain(&dest, &source);
defer backup.deinit();
while (try backup.step(100)) {
const pct = backup.progress();
std.debug.print("\rBackup: {d}%", .{pct});
}
std.debug.print("\nBackup complete!\n", .{});
```
### UDF: String Length
```zig
fn strLen(ctx: sqlite.FunctionContext, args: []const sqlite.FunctionValue) void {
if (args.len != 1 or args[0].isNull()) {
ctx.setNull();
return;
}
if (args[0].asText()) |text| {
ctx.setInt(@intCast(text.len));
} else {
ctx.setNull();
}
}
try db.createScalarFunction("strlen", 1, strLen);
// SELECT strlen(name) FROM users
```
### Collation: Case-Insensitive
```zig
fn caseInsensitive(a: []const u8, b: []const u8) i32 {
var i: usize = 0;
while (i < a.len and i < b.len) : (i += 1) {
const ca = std.ascii.toLower(a[i]);
const cb = std.ascii.toLower(b[i]);
if (ca < cb) return -1;
if (ca > cb) return 1;
}
if (a.len < b.len) return -1;
if (a.len > b.len) return 1;
return 0;
}
try db.createCollation("ICASE", caseInsensitive);
// SELECT * FROM users ORDER BY name COLLATE ICASE
```
---
**© zsqlite v0.3 - API Reference**
*2025-12-08*

397
docs/ARCHITECTURE.md Normal file
View file

@ -0,0 +1,397 @@
# zsqlite - Arquitectura Tecnica
> **Version**: 0.3
> **Ultima actualizacion**: 2025-12-08
## Vision General
zsqlite es un wrapper de SQLite para Zig que compila SQLite amalgamation directamente en el binario. El objetivo es proveer una API idiomatica Zig mientras se mantiene acceso completo a las capacidades de SQLite.
```
┌─────────────────────────────────────────────────────────────┐
│ Aplicacion Zig │
├─────────────────────────────────────────────────────────────┤
│ zsqlite API │
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────┐ │
│ │ Database │ │ Statement │ │ Error │ │ Column │ │
│ │ │ │ │ │ Mapping │ │ Type │ │
│ └────┬─────┘ └─────┬─────┘ └────┬─────┘ └─────┬─────┘ │
├───────┼──────────────┼─────────────┼──────────────┼────────┤
│ │ │ │ │ │
│ └──────────────┴─────────────┴──────────────┘ │
@cImport
├─────────────────────────────────────────────────────────────┤
│ SQLite 3.47.2 (C) │
│ (amalgamation) │
└─────────────────────────────────────────────────────────────┘
```
## Componentes Principales
### 1. Database
Representa una conexion a una base de datos SQLite.
```zig
pub const Database = struct {
handle: ?*c.sqlite3,
pub fn open(path: [:0]const u8) Error!Self { ... }
pub fn openWithFlags(path: [:0]const u8, flags: OpenFlags) Error!Self { ... }
pub fn close(self: *Self) void { ... }
pub fn exec(self: *Self, sql: [:0]const u8) Error!void { ... }
pub fn prepare(self: *Self, sql: [:0]const u8) Error!Statement { ... }
// ...
};
```
**Responsabilidades:**
- Gestionar ciclo de vida de conexion SQLite
- Ejecutar SQL directo (exec)
- Crear prepared statements
- Gestionar transacciones
- Configurar pragmas (foreign keys, etc.)
### 2. Statement
Representa un prepared statement de SQLite.
```zig
pub const Statement = struct {
handle: ?*c.sqlite3_stmt,
db: *Database,
pub fn finalize(self: *Self) void { ... }
pub fn reset(self: *Self) Error!void { ... }
pub fn step(self: *Self) Error!bool { ... }
pub fn bindInt(self: *Self, index: u32, value: i64) Error!void { ... }
pub fn bindTextNamed(self: *Self, name: [:0]const u8, value: []const u8) Error!void { ... }
pub fn columnText(self: *Self, index: u32) ?[]const u8 { ... }
// ...
};
```
**Responsabilidades:**
- Bind de parametros posicionales (1-indexed)
- Bind de parametros named (:name, @name, $name)
- Ejecucion paso a paso (step)
- Acceso a columnas de resultados
- Metadata (sql, isReadOnly, parameterCount, etc.)
- Reset para reutilizacion
### 3. Error
Mapeo de codigos de error SQLite a errores Zig.
```zig
pub const Error = error{
SqliteError,
InternalError,
PermissionDenied,
Busy,
Locked,
OutOfMemory,
// ... 25+ errores mapeados
};
fn resultToError(result: c_int) Error { ... }
```
**Diseno:**
- Cada codigo SQLite tiene su propio error Zig
- Permite manejo especifico por tipo de error
- SQLITE_ROW y SQLITE_DONE manejados especialmente en step()
### 4. OpenFlags
Configuracion para apertura de base de datos.
```zig
pub const OpenFlags = struct {
read_only: bool = false,
read_write: bool = true,
create: bool = true,
uri: bool = false,
memory: bool = false,
no_mutex: bool = false,
full_mutex: bool = false,
};
```
### 5. ColumnType
Enum para tipos de columna SQLite.
```zig
pub const ColumnType = enum {
integer,
float,
text,
blob,
null_value,
};
```
### 6. Backup
API para copiar bases de datos con control de progreso.
```zig
pub const Backup = struct {
handle: ?*c.sqlite3_backup,
dest_db: *Database,
source_db: *Database,
pub fn init(dest: *Database, dest_name: [:0]const u8,
source: *Database, source_name: [:0]const u8) Error!Self { ... }
pub fn step(self: *Self, n_pages: i32) Error!bool { ... }
pub fn stepAll(self: *Self) Error!void { ... }
pub fn remaining(self: *Self) i32 { ... }
pub fn pageCount(self: *Self) i32 { ... }
pub fn progress(self: *Self) u8 { ... }
pub fn finish(self: *Self) Error!void { ... }
pub fn deinit(self: *Self) void { ... }
};
```
**Responsabilidades:**
- Copiar base de datos pagina por pagina
- Control granular del progreso
- Permitir backups incrementales
### 7. User-Defined Functions
Soporte para funciones personalizadas en SQL.
```zig
pub const FunctionContext = struct {
ctx: *c.sqlite3_context,
pub fn setNull(self: Self) void { ... }
pub fn setInt(self: Self, value: i64) void { ... }
pub fn setFloat(self: Self, value: f64) void { ... }
pub fn setText(self: Self, value: []const u8) void { ... }
pub fn setBlob(self: Self, value: []const u8) void { ... }
pub fn setError(self: Self, msg: []const u8) void { ... }
};
pub const FunctionValue = struct {
value: *c.sqlite3_value,
pub fn getType(self: Self) ColumnType { ... }
pub fn isNull(self: Self) bool { ... }
pub fn asInt(self: Self) i64 { ... }
pub fn asFloat(self: Self) f64 { ... }
pub fn asText(self: Self) ?[]const u8 { ... }
pub fn asBlob(self: Self) ?[]const u8 { ... }
};
pub const ScalarFn = *const fn (ctx: FunctionContext, args: []const FunctionValue) void;
```
**Patron de uso:**
```zig
fn myDouble(ctx: FunctionContext, args: []const FunctionValue) void {
if (args[0].isNull()) {
ctx.setNull();
return;
}
ctx.setInt(args[0].asInt() * 2);
}
try db.createScalarFunction("double", 1, myDouble);
// SELECT double(5) => 10
```
### 8. Custom Collations
Soporte para ordenamiento personalizado.
```zig
pub const CollationFn = *const fn (a: []const u8, b: []const u8) i32;
```
**Patron de uso:**
```zig
fn reverseOrder(a: []const u8, b: []const u8) i32 {
return -std.mem.order(u8, a, b);
}
try db.createCollation("REVERSE", reverseOrder);
// SELECT * FROM t ORDER BY col COLLATE REVERSE
```
## Integracion con SQLite C
### @cImport
Usamos `@cImport` para importar los headers de SQLite:
```zig
const c = @cImport({
@cInclude("sqlite3.h");
});
```
Esto nos da acceso directo a:
- `c.sqlite3` - Handle de conexion
- `c.sqlite3_stmt` - Handle de statement
- `c.sqlite3_open()`, `c.sqlite3_close()`, etc.
- Todas las constantes (`c.SQLITE_OK`, `c.SQLITE_ROW`, etc.)
### SQLITE_TRANSIENT
Para strings y blobs, usamos `c.SQLITE_TRANSIENT` que indica a SQLite que debe copiar los datos:
```zig
const result = c.sqlite3_bind_text(
self.handle,
@intCast(index),
value.ptr,
@intCast(value.len),
c.SQLITE_TRANSIENT, // SQLite copia el string
);
```
Esto es necesario porque Zig puede mover/liberar la memoria del slice original.
### Conversion de Indices
SQLite usa diferentes convenciones de indices:
- **Bind parameters**: 1-indexed (SQLite convencion)
- **Column access**: 0-indexed (SQLite convencion)
Mantenemos las mismas convenciones en la API publica para consistencia con documentacion SQLite.
## Build System
### build.zig
```zig
// Compilar SQLite como C source
zsqlite_mod.addCSourceFile(.{
.file = b.path("vendor/sqlite3.c"),
.flags = sqlite_flags,
});
// Flags de optimizacion
const sqlite_flags: []const []const u8 = &.{
"-DSQLITE_DQS=0",
"-DSQLITE_THREADSAFE=0",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
// ...
};
```
### Flags de Compilacion
| Flag | Proposito |
|------|-----------|
| `SQLITE_DQS=0` | Deshabilita double-quoted strings como identificadores |
| `SQLITE_THREADSAFE=0` | Single-threaded (mas rapido) |
| `SQLITE_DEFAULT_MEMSTATUS=0` | Sin tracking de memoria |
| `SQLITE_ENABLE_FTS5` | Full-text search habilitado |
| `SQLITE_ENABLE_JSON1` | Funciones JSON habilitadas |
| `SQLITE_ENABLE_RTREE` | R-Tree para geospatial |
| `SQLITE_OMIT_LOAD_EXTENSION` | Sin extensiones dinamicas (seguridad) |
## Patrones de Uso
### Patron RAII con defer
```zig
var db = try sqlite.openMemory();
defer db.close();
var stmt = try db.prepare("SELECT * FROM users");
defer stmt.finalize();
```
### Patron Transaccion con errdefer
```zig
try db.begin();
errdefer db.rollback() catch {};
try db.exec("INSERT ...");
try db.exec("UPDATE ...");
try db.commit();
```
### Iteracion de Resultados
```zig
while (try stmt.step()) {
const id = stmt.columnInt(0);
const name = stmt.columnText(1) orelse "(null)";
// procesar fila
}
```
## Decisiones de Diseno
### 1. Todo en root.zig (por ahora)
Para v0.1, todo el codigo esta en un solo archivo. Cuando crezca significativamente (>400 lineas core), se fragmentara en:
- `database.zig`
- `statement.zig`
- `errors.zig`
- `types.zig`
### 2. Error Union vs Nullable
- Operaciones que pueden fallar: `Error!T`
- Operaciones de lectura que pueden ser NULL: `?T`
```zig
// Puede fallar (error de SQLite)
pub fn open(path: [:0]const u8) Error!Self
// Puede ser NULL (columna NULL)
pub fn columnText(self: *Self, index: u32) ?[]const u8
```
### 3. Slices vs Null-Terminated
- API publica acepta `[:0]const u8` para strings SQL (null-terminated)
- Variantes `*Alloc` aceptan `[]const u8` y agregan null terminator
### 4. Indices Consistentes con SQLite
Mantenemos las convenciones de SQLite:
- Bind: 1-indexed
- Columns: 0-indexed
Esto facilita traducir ejemplos de documentacion SQLite.
## Roadmap Arquitectural
### Fase 2: Modularizacion
Cuando el codigo crezca, fragmentar en modulos:
```
src/
├── root.zig # Re-exports publicos
├── database.zig # Database struct
├── statement.zig # Statement struct
├── errors.zig # Error types
├── types.zig # OpenFlags, ColumnType
└── c.zig # @cImport centralizado
```
### Fase 3: Features Avanzadas
```
src/
├── ...
├── blob.zig # Blob streaming
├── functions.zig # User-defined functions
├── backup.zig # Backup API
└── hooks.zig # Update/commit hooks
```
---
**© zsqlite - Arquitectura Tecnica**
*2025-12-08*

334
docs/CGO_PARITY_ANALYSIS.md Normal file
View file

@ -0,0 +1,334 @@
# Analisis de Paridad con CGo go-sqlite3
> **Fecha**: 2025-12-08
> **Objetivo**: Identificar todas las funcionalidades de go-sqlite3 para replicarlas en zsqlite
## Resumen
go-sqlite3 (https://github.com/mattn/go-sqlite3) es el wrapper SQLite mas maduro para Go.
Este documento analiza todas sus funcionalidades para asegurar paridad en zsqlite.
---
## Estado de Implementacion
### Leyenda
- ✅ Implementado en zsqlite
- ⏳ Pendiente de implementar
- 🔄 Parcialmente implementado
- ❌ No aplicable a Zig
---
## 1. Conexion a Base de Datos
| Funcionalidad | go-sqlite3 | zsqlite | Notas |
|---------------|------------|---------|-------|
| Open basico | ✅ | ✅ | `sqlite.open()` |
| Open con flags | ✅ | ✅ | `Database.openWithFlags()` |
| Close | ✅ | ✅ | `db.close()` |
| URI connection string | ✅ | ⏳ | Parsear `file:path?mode=ro&cache=shared` |
| DSN parameters | ✅ | ⏳ | Configuracion via string |
| Connection pooling | ✅ (via database/sql) | ⏳ | Pool propio |
---
## 2. Configuracion de Pragmas
| Pragma | go-sqlite3 | zsqlite | Prioridad |
|--------|------------|---------|-----------|
| auto_vacuum | ✅ | ⏳ | Media |
| busy_timeout | ✅ | ✅ | `db.setBusyTimeout()` |
| cache_size | ✅ | ⏳ | Media |
| case_sensitive_like | ✅ | ⏳ | Baja |
| defer_foreign_keys | ✅ | ⏳ | Media |
| foreign_keys | ✅ | ✅ | `db.setForeignKeys()` |
| journal_mode | ✅ | ✅ | `db.setJournalMode()` |
| locking_mode | ✅ | ⏳ | Media |
| query_only | ✅ | ⏳ | Baja |
| recursive_triggers | ✅ | ⏳ | Baja |
| secure_delete | ✅ | ⏳ | Baja |
| synchronous | ✅ | ✅ | `db.setSynchronous()` |
---
## 3. Prepared Statements
| Funcionalidad | go-sqlite3 | zsqlite | Notas |
|---------------|------------|---------|-------|
| Prepare | ✅ | ✅ | `db.prepare()` |
| Exec (sin resultados) | ✅ | ✅ | `db.exec()` |
| Query (con resultados) | ✅ | ✅ | `stmt.step()` loop |
| Bind posicional (?) | ✅ | ✅ | `stmt.bindInt(1, val)` |
| Bind named (:name) | ✅ | ✅ | `stmt.bindIntNamed(":name", val)` |
| Bind named (@name) | ✅ | ✅ | `stmt.bindIntNamed("@name", val)` |
| Bind named ($name) | ✅ | ✅ | `stmt.bindIntNamed("$name", val)` |
| Readonly check | ✅ | ✅ | `stmt.isReadOnly()` |
| SQL text | ✅ | ✅ | `stmt.sql()` |
| Expanded SQL | ✅ | ⏳ | `sqlite3_expanded_sql()` |
---
## 4. Bind de Parametros
| Tipo | go-sqlite3 | zsqlite | Notas |
|------|------------|---------|-------|
| NULL | ✅ | ✅ | `stmt.bindNull()` |
| int64 | ✅ | ✅ | `stmt.bindInt()` |
| float64 | ✅ | ✅ | `stmt.bindFloat()` |
| string/text | ✅ | ✅ | `stmt.bindText()` |
| []byte/blob | ✅ | ✅ | `stmt.bindBlob()` |
| bool | ✅ | ✅ | `stmt.bindBool()` |
| time.Time | ✅ | ⏳ | Formatear como string ISO8601 |
| Zeroblob | ✅ | ✅ | `stmt.bindZeroblob()` |
---
## 5. Lectura de Columnas
| Tipo | go-sqlite3 | zsqlite | Notas |
|------|------------|---------|-------|
| Column count | ✅ | ✅ | `stmt.columnCount()` |
| Column name | ✅ | ✅ | `stmt.columnName()` |
| Column type | ✅ | ✅ | `stmt.columnType()` |
| int64 | ✅ | ✅ | `stmt.columnInt()` |
| float64 | ✅ | ✅ | `stmt.columnFloat()` |
| text | ✅ | ✅ | `stmt.columnText()` |
| blob | ✅ | ✅ | `stmt.columnBlob()` |
| NULL check | ✅ | ✅ | `stmt.columnIsNull()` |
| Column bytes | ✅ | ✅ | `stmt.columnBytes()` |
| Declared type | ✅ | ✅ | `stmt.columnDeclType()` |
| Database name | ✅ | ⏳ | `sqlite3_column_database_name()` |
| Table name | ✅ | ⏳ | `sqlite3_column_table_name()` |
| Origin name | ✅ | ⏳ | `sqlite3_column_origin_name()` |
---
## 6. Transacciones
| Funcionalidad | go-sqlite3 | zsqlite | Notas |
|---------------|------------|---------|-------|
| BEGIN | ✅ | ✅ | `db.begin()` |
| BEGIN IMMEDIATE | ✅ | ✅ | `db.beginImmediate()` |
| BEGIN EXCLUSIVE | ✅ | ✅ | `db.beginExclusive()` |
| BEGIN DEFERRED | ✅ | ✅ | `db.begin()` (default) |
| COMMIT | ✅ | ✅ | `db.commit()` |
| ROLLBACK | ✅ | ✅ | `db.rollback()` |
| SAVEPOINT | ✅ | ✅ | `db.savepoint(alloc, "name")` |
| RELEASE | ✅ | ✅ | `db.release(alloc, "name")` |
| ROLLBACK TO | ✅ | ✅ | `db.rollbackTo(alloc, "name")` |
---
## 7. Metadatos y Utilidades
| Funcionalidad | go-sqlite3 | zsqlite | Notas |
|---------------|------------|---------|-------|
| LastInsertRowId | ✅ | ✅ | `db.lastInsertRowId()` |
| Changes | ✅ | ✅ | `db.changes()` |
| TotalChanges | ✅ | ✅ | `db.totalChanges()` |
| Error message | ✅ | ✅ | `db.errorMessage()` |
| Error code | ✅ | ✅ | `db.errorCode()` |
| Extended error code | ✅ | ✅ | `db.extendedErrorCode()` |
| SQLite version | ✅ | ✅ | `sqlite.version()` |
| Version number | ✅ | ✅ | `sqlite.versionNumber()` |
| Database filename | ✅ | ✅ | `db.filename()` |
| Is readonly | ✅ | ✅ | `db.isReadOnly()` |
---
## 8. Limites y Control
| Funcionalidad | go-sqlite3 | zsqlite | Prioridad |
|---------------|------------|---------|-----------|
| GetLimit | ✅ | ⏳ | Baja |
| SetLimit | ✅ | ⏳ | Baja |
| SetFileControlInt | ✅ | ⏳ | Baja |
| Interrupt | ✅ | ✅ | `db.interrupt()` |
---
## 9. Callbacks y Hooks
| Funcionalidad | go-sqlite3 | zsqlite | Prioridad |
|---------------|------------|---------|-----------|
| Commit hook | ✅ | ⏳ | Media |
| Rollback hook | ✅ | ⏳ | Media |
| Update hook | ✅ | ⏳ | Media |
| Pre-update hook | ✅ | ⏳ | Baja |
| Authorizer | ✅ | ⏳ | Baja |
| Progress handler | ✅ | ⏳ | Baja |
| Busy handler | ✅ | ⏳ | Media |
| Busy timeout | ✅ | ✅ | `db.setBusyTimeout()` |
---
## 10. Funciones Personalizadas
| Funcionalidad | go-sqlite3 | zsqlite | Prioridad |
|---------------|------------|---------|-----------|
| RegisterFunc (scalar) | ✅ | ✅ | `db.createScalarFunction()` |
| RegisterAggregator | ✅ | ⏳ | Media |
| RegisterCollation | ✅ | ✅ | `db.createCollation()` |
| User-defined window func | ✅ | ⏳ | Baja |
---
## 11. Backup API
| Funcionalidad | go-sqlite3 | zsqlite | Prioridad |
|---------------|------------|---------|-----------|
| Backup init | ✅ | ✅ | `Backup.init()` |
| Backup step | ✅ | ✅ | `backup.step()` |
| Backup finish | ✅ | ✅ | `backup.finish()` |
| Backup remaining | ✅ | ✅ | `backup.remaining()` |
| Backup pagecount | ✅ | ✅ | `backup.pageCount()` |
---
## 12. Blob I/O
| Funcionalidad | go-sqlite3 | zsqlite | Prioridad |
|---------------|------------|---------|-----------|
| Blob open | ✅ | ⏳ | Media |
| Blob close | ✅ | ⏳ | Media |
| Blob read | ✅ | ⏳ | Media |
| Blob write | ✅ | ⏳ | Media |
| Blob bytes | ✅ | ⏳ | Media |
| Blob reopen | ✅ | ⏳ | Baja |
---
## 13. Extensiones
| Funcionalidad | go-sqlite3 | zsqlite | Notas |
|---------------|------------|---------|-------|
| Load extension | ✅ | ❌ | Deshabilitado por seguridad |
| Enable load ext | ✅ | ❌ | |
---
## Plan de Implementacion
### Fase 2A - Prioridad Alta ✅ COMPLETADA
1. ✅ Busy timeout/handler - `db.setBusyTimeout()`
2. ✅ WAL mode (journal_mode pragma) - `db.setJournalMode()`, `db.enableWalMode()`
3. ✅ Named parameters - `stmt.bindTextNamed()`, etc.
4. ✅ SAVEPOINT/RELEASE/ROLLBACK TO - `db.savepoint()`, etc.
5. ✅ BEGIN EXCLUSIVE - `db.beginExclusive()`
### Fase 2B - Prioridad Alta ✅ COMPLETADA
1. ✅ Backup API completo - `Backup` struct, `backupToFile()`, `loadFromFile()`
2. ✅ User-defined functions (scalar) - `db.createScalarFunction()`
3. ✅ Collations personalizadas - `db.createCollation()`
4. ✅ ATTACH/DETACH - `db.attach()`, `db.detach()`, `db.listDatabases()`
### Fase 3A - Prioridad Media (Siguiente)
1. ⏳ Blob I/O streaming
2. ⏳ Hooks (commit, rollback, update)
3. ⏳ Aggregator functions
4. ⏳ Mas pragmas
### Fase 3B - Prioridad Baja
1. ⏳ Authorizer
2. ⏳ Progress handler
3. ⏳ Pre-update hook
4. ⏳ Window functions
5. ⏳ Limits API
---
## Funciones SQLite C Relevantes (Referencia)
```c
// Conexion
sqlite3_open_v2()
sqlite3_close_v2()
// Statements
sqlite3_prepare_v2()
sqlite3_finalize()
sqlite3_reset()
sqlite3_clear_bindings()
sqlite3_step()
sqlite3_sql()
sqlite3_expanded_sql()
sqlite3_stmt_readonly()
// Bind
sqlite3_bind_parameter_index()
sqlite3_bind_parameter_name()
sqlite3_bind_null()
sqlite3_bind_int64()
sqlite3_bind_double()
sqlite3_bind_text()
sqlite3_bind_blob()
sqlite3_bind_zeroblob()
// Column
sqlite3_column_count()
sqlite3_column_name()
sqlite3_column_type()
sqlite3_column_int64()
sqlite3_column_double()
sqlite3_column_text()
sqlite3_column_blob()
sqlite3_column_bytes()
sqlite3_column_decltype()
sqlite3_column_database_name()
sqlite3_column_table_name()
sqlite3_column_origin_name()
// Utilidades
sqlite3_last_insert_rowid()
sqlite3_changes()
sqlite3_total_changes()
sqlite3_errmsg()
sqlite3_errcode()
sqlite3_extended_errcode()
sqlite3_libversion()
sqlite3_libversion_number()
sqlite3_db_filename()
sqlite3_db_readonly()
// Busy
sqlite3_busy_timeout()
sqlite3_busy_handler()
// Hooks
sqlite3_commit_hook()
sqlite3_rollback_hook()
sqlite3_update_hook()
sqlite3_preupdate_hook()
// Funciones
sqlite3_create_function_v2()
sqlite3_create_collation_v2()
sqlite3_create_window_function()
// Backup
sqlite3_backup_init()
sqlite3_backup_step()
sqlite3_backup_finish()
sqlite3_backup_remaining()
sqlite3_backup_pagecount()
// Blob
sqlite3_blob_open()
sqlite3_blob_close()
sqlite3_blob_read()
sqlite3_blob_write()
sqlite3_blob_bytes()
sqlite3_blob_reopen()
// Control
sqlite3_interrupt()
sqlite3_limit()
sqlite3_progress_handler()
sqlite3_set_authorizer()
```
---
**© zsqlite - CGo Parity Analysis**
*2025-12-08*

File diff suppressed because it is too large Load diff