IMPLEMENTATION MODULE SQLiteUtils ; FROM SYSTEM IMPORT ADDRESS, ADR; 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_value_text, sqlite3_result_text, sqlite3_backup_init, sqlite3_backup_step, sqlite3_backup_finish, sqlite3_get_table, sqlite3_free_table; FROM libc IMPORT strlen, strncpy; PROCEDURE CStrToM2 (src: ADDRESS; VAR dst: ARRAY OF CHAR); VAR n: CARDINAL; BEGIN IF HIGH(dst) < 0 THEN RETURN END; IF src = NIL THEN dst[0] := 0C; RETURN END; n := VAL(CARDINAL, strlen(src)); IF n > HIGH(dst) THEN n := HIGH(dst) END; strncpy(ADR(dst), src, n); IF n <= HIGH(dst) THEN dst[n] := 0C END 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 VAL(ADDRESS, 0) END StaticDestr; PROCEDURE TransientDestr () : ADDRESS; BEGIN RETURN VAL(ADDRESS, -1) END TransientDestr; PROCEDURE BindTextCopy (stmt: StmtHandle; idx: INTEGER; v: ARRAY OF CHAR) : INTEGER; BEGIN RETURN sqlite3_bind_text(stmt, idx, v, -1, TransientDestr()) END BindTextCopy; PROCEDURE BindBlobCopy (stmt: StmtHandle; idx: INTEGER; data: ADDRESS; n: INTEGER) : INTEGER; BEGIN RETURN sqlite3_bind_blob(stmt, idx, data, n, TransientDestr()) END BindBlobCopy; PROCEDURE ValueText (v: ValueHandle; VAR buf: ARRAY OF CHAR); BEGIN CStrToM2(sqlite3_value_text(v), buf) END ValueText; PROCEDURE ResultTextCopy (ctx: ContextHandle; str: ARRAY OF CHAR); BEGIN sqlite3_result_text(ctx, str, -1, TransientDestr()) END ResultTextCopy; PROCEDURE BackupToFile (srcDb: 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", srcDb, "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; INC(tries); 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 GetTable (db: DbHandle; sql: ARRAY OF CHAR; VAR tbl: ADDRESS; VAR rows, cols: INTEGER; VAR errbuf: ARRAY OF CHAR) : INTEGER; VAR rc: INTEGER; msg: ADDRESS; BEGIN tbl := NIL; rows := 0; cols := 0; msg := NIL; rc := sqlite3_get_table(db, sql, tbl, rows, cols, ADR(msg)); IF msg # NIL THEN CStrToM2(msg, errbuf); sqlite3_free(msg) ELSIF HIGH(errbuf) >= 0 THEN errbuf[0] := 0C END; IF rc # SQLiteOk THEN IF tbl # NIL THEN sqlite3_free_table(tbl); tbl := NIL END; rows := 0; cols := 0 END; RETURN rc END GetTable; PROCEDURE TableCell (tbl: ADDRESS; cols, row, col: INTEGER; VAR buf: ARRAY OF CHAR); TYPE StrVec = POINTER TO ARRAY [0..65535] OF ADDRESS; VAR vec: StrVec; BEGIN IF (tbl = NIL) OR (cols <= 0) OR (col < 0) OR (col >= cols) OR (row < -1) THEN CStrToM2(NIL, buf); RETURN END; vec := VAL(StrVec, tbl); CStrToM2(vec^[(row + 1) * cols + col], buf) END TableCell; PROCEDURE FreeTable (tbl: ADDRESS); BEGIN IF tbl # NIL THEN sqlite3_free_table(tbl) END END FreeTable; PROCEDURE ExecSimple (db: DbHandle; sql: ARRAY OF CHAR) : INTEGER; BEGIN RETURN sqlite3_exec(db, sql, NIL, NIL, NIL) END ExecSimple; PROCEDURE ExecWithErr (db: DbHandle; sql: ARRAY OF CHAR; VAR buf: ARRAY OF CHAR) : INTEGER; VAR rc: INTEGER; msg: ADDRESS; BEGIN msg := NIL; rc := sqlite3_exec(db, sql, NIL, NIL, ADR(msg)); IF msg # NIL THEN CStrToM2(msg, buf); sqlite3_free(msg) ELSIF HIGH(buf) >= 0 THEN buf[0] := 0C END; RETURN rc END ExecWithErr; END SQLiteUtils.