SQLiteUtils.mod 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. IMPLEMENTATION MODULE SQLiteUtils ;
  2. FROM SYSTEM IMPORT ADDRESS, ADR;
  3. FROM SQLite IMPORT DbHandle, StmtHandle, ContextHandle, ValueHandle,
  4. BackupHandle,
  5. SQLiteOk, SQLiteDone, SQLiteBusy, SQLiteLocked,
  6. sqlite3_libversion, sqlite3_errmsg, sqlite3_errstr,
  7. sqlite3_open, sqlite3_close, sqlite3_errcode,
  8. sqlite3_exec, sqlite3_free,
  9. sqlite3_bind_text, sqlite3_bind_blob,
  10. sqlite3_value_text, sqlite3_result_text,
  11. sqlite3_backup_init, sqlite3_backup_step, sqlite3_backup_finish,
  12. sqlite3_get_table, sqlite3_free_table;
  13. FROM libc IMPORT strlen, strncpy;
  14. PROCEDURE CStrToM2 (src: ADDRESS; VAR dst: ARRAY OF CHAR);
  15. VAR n: CARDINAL;
  16. BEGIN
  17. IF HIGH(dst) < 0 THEN RETURN END;
  18. IF src = NIL THEN dst[0] := 0C; RETURN END;
  19. n := VAL(CARDINAL, strlen(src));
  20. IF n > HIGH(dst) THEN n := HIGH(dst) END;
  21. strncpy(ADR(dst), src, n);
  22. IF n <= HIGH(dst) THEN dst[n] := 0C END
  23. END CStrToM2;
  24. PROCEDURE ErrMsg (db: DbHandle; VAR buf: ARRAY OF CHAR);
  25. BEGIN
  26. CStrToM2(sqlite3_errmsg(db), buf)
  27. END ErrMsg;
  28. PROCEDURE ErrStr (code: INTEGER; VAR buf: ARRAY OF CHAR);
  29. BEGIN
  30. CStrToM2(sqlite3_errstr(code), buf)
  31. END ErrStr;
  32. PROCEDURE LibVersionStr (VAR buf: ARRAY OF CHAR);
  33. BEGIN
  34. CStrToM2(sqlite3_libversion(), buf)
  35. END LibVersionStr;
  36. PROCEDURE StaticDestr () : ADDRESS;
  37. BEGIN
  38. RETURN VAL(ADDRESS, 0)
  39. END StaticDestr;
  40. PROCEDURE TransientDestr () : ADDRESS;
  41. BEGIN
  42. RETURN VAL(ADDRESS, -1)
  43. END TransientDestr;
  44. PROCEDURE BindTextCopy (stmt: StmtHandle; idx: INTEGER;
  45. v: ARRAY OF CHAR) : INTEGER;
  46. BEGIN
  47. RETURN sqlite3_bind_text(stmt, idx, v, -1, TransientDestr())
  48. END BindTextCopy;
  49. PROCEDURE BindBlobCopy (stmt: StmtHandle; idx: INTEGER;
  50. data: ADDRESS; n: INTEGER) : INTEGER;
  51. BEGIN
  52. RETURN sqlite3_bind_blob(stmt, idx, data, n, TransientDestr())
  53. END BindBlobCopy;
  54. PROCEDURE ValueText (v: ValueHandle; VAR buf: ARRAY OF CHAR);
  55. BEGIN
  56. CStrToM2(sqlite3_value_text(v), buf)
  57. END ValueText;
  58. PROCEDURE ResultTextCopy (ctx: ContextHandle; str: ARRAY OF CHAR);
  59. BEGIN
  60. sqlite3_result_text(ctx, str, -1, TransientDestr())
  61. END ResultTextCopy;
  62. PROCEDURE BackupToFile (srcDb: DbHandle;
  63. filename: ARRAY OF CHAR) : INTEGER;
  64. VAR dst: DbHandle; bk: BackupHandle; rc, rc2, tries: INTEGER;
  65. BEGIN
  66. rc := sqlite3_open(filename, dst);
  67. IF rc # SQLiteOk THEN RETURN rc END;
  68. bk := sqlite3_backup_init(dst, "main", srcDb, "main");
  69. IF bk = NIL THEN
  70. rc := sqlite3_errcode(dst);
  71. rc2 := sqlite3_close(dst);
  72. RETURN rc
  73. END;
  74. tries := 0;
  75. LOOP
  76. rc := sqlite3_backup_step(bk, 50);
  77. IF (rc # SQLiteOk) AND (rc # SQLiteBusy)
  78. AND (rc # SQLiteLocked) THEN EXIT END;
  79. INC(tries);
  80. IF tries > 100000 THEN rc := SQLiteBusy; EXIT END
  81. END;
  82. IF rc = SQLiteDone THEN rc := SQLiteOk END;
  83. rc2 := sqlite3_backup_finish(bk);
  84. IF rc = SQLiteOk THEN rc := rc2 END;
  85. rc2 := sqlite3_close(dst);
  86. RETURN rc
  87. END BackupToFile;
  88. PROCEDURE GetTable (db: DbHandle; sql: ARRAY OF CHAR;
  89. VAR tbl: ADDRESS; VAR rows, cols: INTEGER;
  90. VAR errbuf: ARRAY OF CHAR) : INTEGER;
  91. VAR rc: INTEGER; msg: ADDRESS;
  92. BEGIN
  93. tbl := NIL; rows := 0; cols := 0;
  94. msg := NIL;
  95. rc := sqlite3_get_table(db, sql, tbl, rows, cols, ADR(msg));
  96. IF msg # NIL THEN
  97. CStrToM2(msg, errbuf);
  98. sqlite3_free(msg)
  99. ELSIF HIGH(errbuf) >= 0 THEN
  100. errbuf[0] := 0C
  101. END;
  102. IF rc # SQLiteOk THEN
  103. IF tbl # NIL THEN sqlite3_free_table(tbl); tbl := NIL END;
  104. rows := 0; cols := 0
  105. END;
  106. RETURN rc
  107. END GetTable;
  108. PROCEDURE TableCell (tbl: ADDRESS; cols, row, col: INTEGER;
  109. VAR buf: ARRAY OF CHAR);
  110. TYPE StrVec = POINTER TO ARRAY [0..65535] OF ADDRESS;
  111. VAR vec: StrVec;
  112. BEGIN
  113. IF (tbl = NIL) OR (cols <= 0) OR (col < 0) OR (col >= cols)
  114. OR (row < -1) THEN
  115. CStrToM2(NIL, buf);
  116. RETURN
  117. END;
  118. vec := VAL(StrVec, tbl);
  119. CStrToM2(vec^[(row + 1) * cols + col], buf)
  120. END TableCell;
  121. PROCEDURE FreeTable (tbl: ADDRESS);
  122. BEGIN
  123. IF tbl # NIL THEN sqlite3_free_table(tbl) END
  124. END FreeTable;
  125. PROCEDURE ExecSimple (db: DbHandle; sql: ARRAY OF CHAR) : INTEGER;
  126. BEGIN
  127. RETURN sqlite3_exec(db, sql, NIL, NIL, NIL)
  128. END ExecSimple;
  129. PROCEDURE ExecWithErr (db: DbHandle; sql: ARRAY OF CHAR;
  130. VAR buf: ARRAY OF CHAR) : INTEGER;
  131. VAR rc: INTEGER; msg: ADDRESS;
  132. BEGIN
  133. msg := NIL;
  134. rc := sqlite3_exec(db, sql, NIL, NIL, ADR(msg));
  135. IF msg # NIL THEN
  136. CStrToM2(msg, buf);
  137. sqlite3_free(msg)
  138. ELSIF HIGH(buf) >= 0 THEN
  139. buf[0] := 0C
  140. END;
  141. RETURN rc
  142. END ExecWithErr;
  143. END SQLiteUtils.