# zcatsql - API Reference > **Version**: 0.6 > **Ultima actualizacion**: 2025-12-08 ## Quick Reference ```zig const sqlite = @import("zcatsql"); // 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¶m2=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"); ``` --- **© zcatsql v0.6 - API Reference** *2025-12-08*