IMPLEMENTATION MODULE SQLiteUtils; (* Pure V3 helpers over the SQLite binding. *) FROM SYSTEM IMPORT ADDRESS; FROM CStr IMPORT Copy; FROM SQLite IMPORT DbHandle, StmtHandle, ContextHandle, ValueHandle, BackupHandle, SQLiteOk, SQLiteDone, SQLiteBusy, SQLiteLocked, sqlite3_libversion, sqlite3_errmsg, sqlite3_errstr, sqlite3_open, sqlite3_close, sqlite3_errcode, sqlite3_exec, sqlite3_free, sqlite3_bind_text, sqlite3_bind_blob, sqlite3_prepare_v3, sqlite3_value_text, sqlite3_result_text, sqlite3_backup_init, sqlite3_backup_step, sqlite3_backup_finish, SQLiteTransient; PROCEDURE CStrToM2 (src : ADDRESS; VAR dst : ARRAY OF CHAR); VAR n : CARDINAL; BEGIN n := Copy(src, dst) END CStrToM2; PROCEDURE ErrMsg (db : DbHandle; VAR buf : ARRAY OF CHAR); BEGIN CStrToM2(sqlite3_errmsg(db), buf) END ErrMsg; PROCEDURE ErrStr (code : INTEGER; VAR buf : ARRAY OF CHAR); BEGIN CStrToM2(sqlite3_errstr(code), buf) END ErrStr; PROCEDURE LibVersionStr (VAR buf : ARRAY OF CHAR); BEGIN CStrToM2(sqlite3_libversion(), buf) END LibVersionStr; PROCEDURE StaticDestr () : ADDRESS; BEGIN RETURN NIL END StaticDestr; PROCEDURE TransientDestr () : ADDRESS; BEGIN RETURN SQLiteTransient() END TransientDestr; PROCEDURE BindTextCopy (stmt : StmtHandle; idx : INTEGER; value : ARRAY OF CHAR) : INTEGER; BEGIN RETURN sqlite3_bind_text(stmt, idx, value, -1, TransientDestr()) END BindTextCopy; PROCEDURE BindBlobCopy (stmt : StmtHandle; idx : INTEGER; data : ADDRESS; nBytes : INTEGER) : INTEGER; BEGIN RETURN sqlite3_bind_blob(stmt, idx, data, nBytes, TransientDestr()) END BindBlobCopy; PROCEDURE PrepareOne (db : DbHandle; sql : ARRAY OF CHAR; VAR stmt : StmtHandle) : INTEGER; VAR tail : ADDRESS; BEGIN tail := NIL; RETURN sqlite3_prepare_v3(db, sql, -1, 0, stmt, tail) END PrepareOne; PROCEDURE ValueText (value : ValueHandle; VAR buf : ARRAY OF CHAR); BEGIN CStrToM2(sqlite3_value_text(value), buf) END ValueText; PROCEDURE ResultTextCopy (ctx : ContextHandle; value : ARRAY OF CHAR); BEGIN sqlite3_result_text(ctx, value, -1, TransientDestr()) END ResultTextCopy; PROCEDURE BackupToFile (src : DbHandle; filename : ARRAY OF CHAR) : INTEGER; VAR dst : DbHandle; bk : BackupHandle; rc, rc2, tries : INTEGER; BEGIN rc := sqlite3_open(filename, dst); IF rc # SQLiteOk THEN RETURN rc END; bk := sqlite3_backup_init(dst, "main", src, "main"); IF bk = NIL THEN rc := sqlite3_errcode(dst); rc2 := sqlite3_close(dst); RETURN rc END; tries := 0; LOOP rc := sqlite3_backup_step(bk, 50); IF (rc # SQLiteOk) AND (rc # SQLiteBusy) AND (rc # SQLiteLocked) THEN EXIT END; tries := tries + 1; IF tries > 100000 THEN rc := SQLiteBusy; EXIT END END; IF rc = SQLiteDone THEN rc := SQLiteOk END; rc2 := sqlite3_backup_finish(bk); IF rc = SQLiteOk THEN rc := rc2 END; rc2 := sqlite3_close(dst); RETURN rc END BackupToFile; PROCEDURE ExecSimple (db : DbHandle; sql : ARRAY OF CHAR) : INTEGER; VAR msg : ADDRESS; rc : INTEGER; BEGIN msg := NIL; rc := sqlite3_exec(db, sql, NIL, NIL, msg); IF msg # NIL THEN sqlite3_free(msg) END; RETURN rc END ExecSimple; PROCEDURE ExecWithErr (db : DbHandle; sql : ARRAY OF CHAR; VAR errbuf : ARRAY OF CHAR) : INTEGER; VAR msg : ADDRESS; rc : INTEGER; BEGIN msg := NIL; rc := sqlite3_exec(db, sql, NIL, NIL, msg); IF msg # NIL THEN CStrToM2(msg, errbuf); sqlite3_free(msg) ELSE errbuf[0] := CHR(0) END; RETURN rc END ExecWithErr; END SQLiteUtils.