zcatsql/docs/API.md
reugenio 7229c27c80 Fase 4: Window functions, URI, pragmas y connection pool
- Window functions: createWindowFunction() con 4 callbacks
  (xStep, xFinal, xValue, xInverse)
- URI connection string: openUri() y openUriAlloc()
  (file:path?mode=ro&cache=shared)
- Pragmas adicionales: setAutoVacuum, setCacheSize,
  setCaseSensitiveLike, setDeferForeignKeys, setLockingMode,
  setQueryOnly, setRecursiveTriggers, setSecureDelete,
  setPageSize, setMaxPageCount, setTempStore, setWalAutoCheckpoint
- Maintenance: vacuum, incrementalVacuum, optimize,
  integrityCheck, quickCheck, walCheckpoint
- ConnectionPool: pool thread-safe con acquire/release

Paridad 100% con go-sqlite3 (excepto extensiones dinamicas
que estan deshabilitadas por seguridad)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 19:33:46 +01:00

1133 lines
28 KiB
Markdown

# zsqlite - API Reference
> **Version**: 0.6
> **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
var db = try sqlite.openUri("file:test.db?mode=ro"); // URI
defer db.close();
// Connection pool
var pool = try sqlite.ConnectionPool.init(alloc, "file:db?cache=shared", 10);
defer pool.deinit();
const conn = try pool.acquire();
defer pool.release(conn);
// 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);
try db.createAggregateFunction("sum_squares", 1, stepFn, finalFn);
try db.createWindowFunction("running_sum", 1, stepFn, finalFn, valueFn, inverseFn);
// Custom collations
try db.createCollation("NOCASE2", myCaseInsensitiveCompare);
// Blob I/O
var blob = try sqlite.Blob.open(&db, "main", "table", "column", rowid, true);
defer blob.deinit();
try blob.write(data, 0);
try blob.read(&buffer, 0);
// Hooks
try db.setCommitHook(myCommitHook);
try db.setUpdateHook(myUpdateHook);
try db.setPreUpdateHook(myPreUpdateHook);
try db.setAuthorizer(myAuthorizer);
try db.setProgressHandler(1000, myProgress);
// Timestamp binding
try stmt.bindTimestamp(1, unix_timestamp);
try stmt.bindCurrentTime(1);
// Limits
const old = db.setLimit(.sql_length, 10000);
const current = db.getLimit(.sql_length);
// Pragmas adicionales
try db.setAutoVacuum(alloc, "full");
try db.setCacheSize(alloc, 10000);
try db.setLockingMode(alloc, "exclusive");
// Maintenance
try db.vacuum();
try db.optimize();
const result = try db.integrityCheck(alloc);
```
---
## 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 |
| `openUri(uri)` | Abre con URI (file:path?mode=ro&cache=shared) |
| `openUriAlloc(alloc, uri)` | openUri con string runtime |
| `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 |
| `setAutoVacuum(alloc, mode)` | "none", "full", "incremental" |
| `setCacheSize(alloc, size)` | Tamano de cache en KB |
| `setCaseSensitiveLike(enabled)` | LIKE case-sensitive |
| `setDeferForeignKeys(enabled)` | Diferir FK checks |
| `setLockingMode(alloc, mode)` | "normal", "exclusive" |
| `setQueryOnly(enabled)` | Solo lectura |
| `setRecursiveTriggers(enabled)` | Triggers recursivos |
| `setSecureDelete(enabled)` | Borrado seguro |
| `setPageSize(alloc, size)` | Tamano de pagina |
| `setMaxPageCount(alloc, count)` | Max paginas |
| `setTempStore(alloc, mode)` | "default", "file", "memory" |
| `setWalAutoCheckpoint(alloc, n)` | Checkpoint cada N paginas |
### Maintenance
| Funcion | Descripcion |
|---------|-------------|
| `vacuum()` | Compacta la base de datos |
| `incrementalVacuum(alloc, pages)` | Vacuum incremental |
| `optimize()` | Optimiza indices |
| `integrityCheck(alloc)` | Verifica integridad |
| `quickCheck(alloc)` | Verificacion rapida |
| `walCheckpoint(alloc, mode)` | Checkpoint WAL |
### 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 |
| `getLimit(limit_type)` | Obtener limite actual |
| `setLimit(limit_type, val)` | Establecer limite |
### Hooks y Callbacks
| Funcion | Descripcion |
|---------|-------------|
| `setCommitHook(fn)` | Hook al commit |
| `setRollbackHook(fn)` | Hook al rollback |
| `setUpdateHook(fn)` | Hook a INSERT/UPDATE/DELETE |
| `setPreUpdateHook(fn)` | Hook ANTES de cambios |
| `setAuthorizer(fn)` | Autorizar operaciones SQL |
| `setProgressHandler(n, fn)` | Callback cada N operaciones |
| `setBusyHandler(fn)` | Handler personalizado de busy |
| `clearHooks()` | Eliminar todos los hooks |
---
## 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)` | |
| `bindTimestamp(idx, ts)` | Unix timestamp como ISO8601 |
| `bindTimestampNamed(name, ts)` | |
| `bindCurrentTime(idx)` | Tiempo actual como ISO8601 |
| `bindCurrentTimeNamed(name)` | |
### 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 |
| `columnDatabaseName(idx)` | Nombre de la base de datos |
| `columnTableName(idx)` | Nombre de la tabla |
| `columnOriginName(idx)` | Nombre original de la columna |
### Statement Metadata Extended
| Funcion | Descripcion |
|---------|-------------|
| `expandedSql(allocator)` | SQL con parametros expandidos |
---
## 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
```
### Aggregate Function: Sum of Squares
```zig
const SumState = struct {
total: i64 = 0,
};
fn sumSquaresStep(ctx: sqlite.AggregateContext, args: []const sqlite.FunctionValue) void {
const state = ctx.getAggregateContext(SumState) orelse return;
if (args.len > 0 and !args[0].isNull()) {
const val = args[0].asInt();
state.total += val * val;
}
}
fn sumSquaresFinal(ctx: sqlite.AggregateContext) void {
const state = ctx.getAggregateContext(SumState) orelse {
ctx.setNull();
return;
};
ctx.setInt(state.total);
}
try db.createAggregateFunction("sum_squares", 1, sumSquaresStep, sumSquaresFinal);
// SELECT sum_squares(value) FROM numbers => 1+4+9+16+25 = 55
```
### Blob I/O: Incremental Read/Write
```zig
// Insert placeholder blob
try db.exec("INSERT INTO files (data) VALUES (zeroblob(1024))");
const rowid = db.lastInsertRowId();
// Open for writing
var blob = try sqlite.Blob.open(&db, "main", "files", "data", rowid, true);
defer blob.deinit();
// Write data
try blob.write("Hello, World!", 0);
// Read data
var buffer: [100]u8 = undefined;
try blob.read(&buffer, 0);
```
### Hooks: Monitor Database Changes
```zig
fn onCommit() bool {
std.debug.print("Transaction committed!\n", .{});
return true; // Allow commit
}
fn onUpdate(op: sqlite.UpdateOperation, db_name: []const u8, table: []const u8, rowid: i64) void {
std.debug.print("{s} on {s}.{s} row {d}\n", .{
@tagName(op), db_name, table, rowid
});
}
try db.setCommitHook(onCommit);
try db.setUpdateHook(onUpdate);
// ... operations will trigger hooks ...
db.clearHooks(); // Remove all hooks
```
---
## Blob
```zig
pub const Blob = struct {
pub fn open(db: *Database, schema: [:0]const u8, table: [:0]const u8,
column: [:0]const u8, rowid: i64, writable: bool) Error!Blob
pub fn openAlloc(db: *Database, allocator: Allocator, ...) !Blob
pub fn close(self: *Blob) Error!void
pub fn deinit(self: *Blob) void
pub fn bytes(self: *Blob) i32
pub fn read(self: *Blob, buffer: []u8, offset: i32) Error!void
pub fn write(self: *Blob, data: []const u8, offset: i32) Error!void
pub fn reopen(self: *Blob, rowid: i64) Error!void
pub fn readAll(self: *Blob, allocator: Allocator) ![]u8
};
```
---
## Hooks
### Types
```zig
pub const ZigCommitHookFn = *const fn () bool;
pub const ZigRollbackHookFn = *const fn () void;
pub const ZigUpdateHookFn = *const fn (
operation: UpdateOperation,
db_name: []const u8,
table_name: []const u8,
rowid: i64
) void;
pub const UpdateOperation = enum(i32) {
insert,
update,
delete,
};
```
### Database Methods
| Method | Description |
|--------|-------------|
| `setCommitHook(fn)` | Called when transaction commits |
| `setRollbackHook(fn)` | Called when transaction rolls back |
| `setUpdateHook(fn)` | Called on INSERT/UPDATE/DELETE |
| `clearHooks()` | Remove all hooks |
---
## Aggregate Functions
### Types
```zig
pub const AggregateStepFn = *const fn (ctx: AggregateContext, args: []const FunctionValue) void;
pub const AggregateFinalFn = *const fn (ctx: AggregateContext) void;
```
### AggregateContext
```zig
pub const AggregateContext = struct {
pub fn getAggregateContext(self: Self, comptime T: type) ?*T
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
};
```
### Database Method
```zig
pub fn createAggregateFunction(
self: *Database,
name: [:0]const u8,
num_args: i32,
step_fn: AggregateStepFn,
final_fn: AggregateFinalFn,
) !void
```
---
## Authorizer
Controla que operaciones SQL estan permitidas.
### Types
```zig
pub const AuthAction = enum(i32) {
create_index, create_table, create_temp_index, create_temp_table,
create_temp_trigger, create_temp_view, create_trigger, create_view,
delete, drop_index, drop_table, drop_temp_index, drop_temp_table,
drop_temp_trigger, drop_temp_view, drop_trigger, drop_view,
insert, pragma, read, select, transaction, update,
attach, detach, alter_table, reindex, analyze,
create_vtable, drop_vtable, function, savepoint, recursive,
};
pub const AuthResult = enum(i32) {
ok, // Permitir
deny, // Denegar con error
ignore, // Tratar como NULL
};
pub const ZigAuthorizerFn = *const fn (
action: AuthAction,
arg1: ?[]const u8, // tabla/indice
arg2: ?[]const u8, // columna/trigger
arg3: ?[]const u8, // nombre de database
arg4: ?[]const u8, // trigger/view
) AuthResult;
```
### Ejemplo
```zig
fn myAuthorizer(action: AuthAction, arg1: ?[]const u8, _, _, _) AuthResult {
if (action == .drop_table) {
if (arg1) |table| {
if (std.mem.eql(u8, table, "important")) return .deny;
}
}
return .ok;
}
try db.setAuthorizer(myAuthorizer);
// Ahora DROP TABLE important fallara
try db.setAuthorizer(null); // Remover
```
---
## Pre-Update Hook
Hook que se ejecuta ANTES de cambios, permitiendo acceso a valores antiguos y nuevos.
### Types
```zig
pub const PreUpdateContext = struct {
pub fn columnCount(self: Self) i32
pub fn depth(self: Self) i32 // 0=directo, 1=trigger, etc
pub fn oldValue(self: Self, col: u32) ?FunctionValue // UPDATE/DELETE
pub fn newValue(self: Self, col: u32) ?FunctionValue // UPDATE/INSERT
};
pub const ZigPreUpdateHookFn = *const fn (
ctx: PreUpdateContext,
operation: UpdateOperation,
db_name: []const u8,
table_name: []const u8,
old_rowid: i64,
new_rowid: i64,
) void;
```
### Ejemplo
```zig
fn auditHook(ctx: PreUpdateContext, op: UpdateOperation, _, table: []const u8, _, _) void {
if (op == .update) {
// Acceder a valor antes del cambio
if (ctx.oldValue(0)) |old| {
const old_val = old.asInt();
// Acceder a nuevo valor
if (ctx.newValue(0)) |new| {
const new_val = new.asInt();
std.debug.print("{s}: {d} -> {d}\n", .{table, old_val, new_val});
}
}
}
}
try db.setPreUpdateHook(auditHook);
```
---
## Progress Handler
Callback periodico para queries de larga duracion.
```zig
pub const ZigProgressFn = *const fn () bool; // true=continuar, false=interrumpir
```
### Ejemplo
```zig
var should_cancel = false;
fn checkCancel() bool {
return !should_cancel; // false interrumpe el query
}
try db.setProgressHandler(1000, checkCancel); // Cada 1000 operaciones VM
// Para cancelar un query largo:
// should_cancel = true;
```
---
## Busy Handler
Handler personalizado para cuando la base de datos esta bloqueada.
```zig
pub const ZigBusyHandlerFn = *const fn (count: i32) bool; // true=reintentar
```
### Ejemplo
```zig
fn myBusyHandler(count: i32) bool {
if (count > 10) return false; // Fallar despues de 10 reintentos
std.time.sleep(100_000_000); // Esperar 100ms
return true; // Reintentar
}
try db.setBusyHandler(myBusyHandler);
```
---
## Limits
Control de limites de SQLite.
### Limit Types
```zig
pub const Limit = enum(i32) {
length, // Tamano maximo de string/blob
sql_length, // Longitud maxima de SQL
column, // Columnas por tabla/query
expr_depth, // Profundidad de expresiones
compound_select, // Terminos en SELECT compuesto
vdbe_op, // Operaciones de VM
function_arg, // Argumentos de funcion
attached, // Databases attached
like_pattern_length, // Patron LIKE
variable_number, // Variables SQL
trigger_depth, // Profundidad de triggers
worker_threads, // Threads de trabajo
};
```
### Ejemplo
```zig
// Obtener limite actual
const sql_limit = db.getLimit(.sql_length);
// Establecer nuevo limite (retorna el anterior)
const old_limit = db.setLimit(.sql_length, 10000);
```
---
## Timestamp Binding
Bind de timestamps Unix como texto ISO8601 (YYYY-MM-DD HH:MM:SS).
### Funciones
```zig
pub fn bindTimestamp(self: *Statement, index: u32, ts: i64) Error!void
pub fn bindTimestampNamed(self: *Statement, name: [:0]const u8, ts: i64) Error!void
pub fn bindCurrentTime(self: *Statement, index: u32) Error!void
pub fn bindCurrentTimeNamed(self: *Statement, name: [:0]const u8) Error!void
```
### Ejemplo
```zig
var stmt = try db.prepare("INSERT INTO events (created_at) VALUES (?)");
try stmt.bindTimestamp(1, 1705314645); // 2024-01-15 10:30:45 UTC
// O usar tiempo actual
try stmt.bindCurrentTime(1);
```
---
## Window Functions
Funciones de ventana personalizadas para queries analiticos.
### Types
```zig
pub const WindowValueFn = *const fn (ctx: AggregateContext) void;
pub const WindowInverseFn = *const fn (ctx: AggregateContext, args: []const FunctionValue) void;
```
### Database Method
```zig
pub fn createWindowFunction(
self: *Database,
name: [:0]const u8,
num_args: i32,
step_fn: AggregateStepFn, // Agrega valor a ventana
final_fn: AggregateFinalFn, // Retorna resultado final
value_fn: WindowValueFn, // Retorna valor actual
inverse_fn: WindowInverseFn, // Remueve valor de ventana
) !void
```
### Ejemplo: Running Sum
```zig
const SumState = struct { total: i64 = 0 };
fn runningSumStep(ctx: AggregateContext, args: []const FunctionValue) void {
const state = ctx.getAggregateContext(SumState) orelse return;
if (args.len > 0 and !args[0].isNull()) {
state.total += args[0].asInt();
}
}
fn runningSumFinal(ctx: AggregateContext) void {
const state = ctx.getAggregateContext(SumState) orelse {
ctx.setNull();
return;
};
ctx.setInt(state.total);
}
fn runningSumValue(ctx: AggregateContext) void {
// Igual que final para running sum
runningSumFinal(ctx);
}
fn runningSumInverse(ctx: AggregateContext, args: []const FunctionValue) void {
const state = ctx.getAggregateContext(SumState) orelse return;
if (args.len > 0 and !args[0].isNull()) {
state.total -= args[0].asInt();
}
}
try db.createWindowFunction("running_sum", 1,
runningSumStep, runningSumFinal, runningSumValue, runningSumInverse);
// SELECT running_sum(value) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
// FROM numbers
```
---
## Connection Pool
Pool de conexiones para aplicaciones multi-hilo.
### Struct
```zig
pub const ConnectionPool = struct {
pub fn init(allocator: Allocator, path: [:0]const u8, max_size: usize) !ConnectionPool
pub fn deinit(self: *ConnectionPool) void
pub fn acquire(self: *ConnectionPool) !*Database
pub fn release(self: *ConnectionPool, conn: *Database) void
pub fn inUseCount(self: *ConnectionPool) usize
pub fn openCount(self: *ConnectionPool) usize
pub fn capacity(self: *ConnectionPool) usize
};
```
### Ejemplo
```zig
var pool = try sqlite.ConnectionPool.init(allocator, "file:app.db?cache=shared", 10);
defer pool.deinit();
// En cada thread/request:
const conn = try pool.acquire();
defer pool.release(conn);
try conn.exec("INSERT INTO logs (msg) VALUES ('Hello')");
```
### Notas
- El pool usa mutex para thread-safety
- Las conexiones se crean bajo demanda (lazy)
- Las conexiones liberadas se reutilizan
- Usar URI con `cache=shared` para compartir cache entre conexiones
---
## URI Connection String
Conexion via URI con parametros.
### Funciones
```zig
pub fn openUri(uri: [:0]const u8) Error!Database
pub fn openUriAlloc(allocator: Allocator, uri: []const u8) !Database
```
### Sintaxis URI
```
file:path?param1=value1&param2=value2
```
### Parametros Soportados
| Parametro | Valores | Descripcion |
|-----------|---------|-------------|
| `mode` | ro, rw, rwc, memory | Modo de apertura |
| `cache` | shared, private | Cache compartida |
| `psow` | 0, 1 | Power-safe overwrite |
| `nolock` | 1 | Sin locking |
| `immutable` | 1 | Base inmutable |
### Ejemplos
```zig
// Solo lectura
var db = try sqlite.openUri("file:data.db?mode=ro");
// Memoria compartida (para pools)
var db = try sqlite.openUri("file::memory:?cache=shared");
// Read-write, crear si no existe
var db = try sqlite.openUri("file:app.db?mode=rwc");
// Base inmutable (sin journal)
var db = try sqlite.openUri("file:static.db?immutable=1");
```
---
**© zsqlite v0.6 - API Reference**
*2025-12-08*