SQLiteIntrospection.mod 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. MODULE SQLiteIntrospection;
  2. (* Statement metadata and library diagnostics:
  3. sql, expanded_sql, readonly, busy, next_stmt, stmt_status,
  4. version/sourceid, error_offset, autocommit, complete and limits. *)
  5. FROM SYSTEM IMPORT ADDRESS;
  6. FROM CStr IMPORT CString, Copy;
  7. FROM SQLite IMPORT
  8. SQLiteOk, SQLiteRow, SQLiteDone,
  9. SQLiteOpenReadWrite, SQLiteOpenCreate, SQLiteOpenMemory,
  10. SQLiteLimitLikePatternLength, SQLiteStmtStatusVmStep,
  11. sqlite3_open_v2, sqlite3_exec, sqlite3_close_v2,
  12. sqlite3_prepare_v2, sqlite3_step, sqlite3_finalize,
  13. sqlite3_bind_int, sqlite3_sql, sqlite3_expanded_sql,
  14. sqlite3_stmt_readonly, sqlite3_stmt_busy, sqlite3_next_stmt,
  15. sqlite3_stmt_status, sqlite3_libversion,
  16. sqlite3_libversion_number, sqlite3_sourceid, sqlite3_threadsafe,
  17. sqlite3_error_offset, sqlite3_get_autocommit, sqlite3_complete,
  18. sqlite3_limit, sqlite3_free;
  19. VAR
  20. ExitCode : INTEGER;
  21. db, stmt, s1, s2, p, q : ADDRESS;
  22. rc : INTEGER;
  23. ok : BOOLEAN;
  24. PROCEDURE SameText (a, b : ARRAY OF CHAR) : BOOLEAN;
  25. VAR
  26. i : INTEGER;
  27. BEGIN
  28. i := 0;
  29. WHILE (a[i] # CHR(0)) AND (a[i] = b[i]) DO
  30. i := i + 1
  31. END;
  32. RETURN (a[i] = CHR(0)) AND (b[i] = CHR(0))
  33. END SameText;
  34. PROCEDURE TextIs (s : CString; want : ARRAY OF CHAR) : BOOLEAN;
  35. VAR
  36. buf : ARRAY [0..127] OF CHAR;
  37. BEGIN
  38. IF s = NIL THEN RETURN FALSE END;
  39. IF Copy(s, buf) = 0 THEN RETURN FALSE END;
  40. RETURN SameText(buf, want)
  41. END TextIs;
  42. PROCEDURE TextNonEmpty (s : CString) : BOOLEAN;
  43. VAR
  44. buf : ARRAY [0..127] OF CHAR;
  45. BEGIN
  46. IF s = NIL THEN RETURN FALSE END;
  47. RETURN Copy(s, buf) > 0
  48. END TextNonEmpty;
  49. PROCEDURE ExecSQL (sql : ARRAY OF CHAR) : BOOLEAN;
  50. VAR
  51. errmsg : ADDRESS;
  52. good : BOOLEAN;
  53. BEGIN
  54. errmsg := NIL;
  55. good := sqlite3_exec(db, sql, NIL, NIL, errmsg) = SQLiteOk;
  56. IF errmsg # NIL THEN
  57. sqlite3_free(errmsg)
  58. END;
  59. RETURN good
  60. END ExecSQL;
  61. PROCEDURE Finish (VAR s : ADDRESS) : BOOLEAN;
  62. VAR
  63. good : BOOLEAN;
  64. BEGIN
  65. good := TRUE;
  66. IF s # NIL THEN
  67. IF sqlite3_finalize(s) # SQLiteOk THEN good := FALSE END;
  68. s := NIL
  69. END;
  70. RETURN good
  71. END Finish;
  72. BEGIN
  73. ExitCode := 1;
  74. db := NIL; stmt := NIL; s1 := NIL; s2 := NIL;
  75. p := NIL; q := NIL; ok := FALSE;
  76. IF (sqlite3_open_v2(":memory:", db,
  77. SQLiteOpenReadWrite + SQLiteOpenCreate + SQLiteOpenMemory,
  78. NIL) = SQLiteOk) AND (db # NIL) THEN
  79. ok := (sqlite3_libversion_number() > 0)
  80. AND TextNonEmpty(sqlite3_libversion())
  81. AND TextNonEmpty(sqlite3_sourceid())
  82. AND (sqlite3_threadsafe() > 0);
  83. IF ok THEN
  84. ok := (sqlite3_complete("SELECT 1;") = 1)
  85. AND (sqlite3_complete("SELECT 1") = 0)
  86. END;
  87. IF ok THEN
  88. ok := (sqlite3_get_autocommit(db) = 1)
  89. AND ExecSQL("BEGIN;")
  90. AND (sqlite3_get_autocommit(db) = 0)
  91. AND ExecSQL("COMMIT;")
  92. AND (sqlite3_get_autocommit(db) = 1)
  93. END;
  94. IF ok THEN
  95. rc := sqlite3_limit(db, SQLiteLimitLikePatternLength, -1);
  96. ok := (rc > 0)
  97. AND (sqlite3_limit(db, SQLiteLimitLikePatternLength, 1000) = rc)
  98. AND (sqlite3_limit(db, SQLiteLimitLikePatternLength, -1) = 1000)
  99. AND (sqlite3_limit(db, SQLiteLimitLikePatternLength, rc) = 1000)
  100. END;
  101. IF ok THEN ok := ExecSQL("CREATE TABLE t(x INTEGER);") END;
  102. (* Original SQL, expanded SQL, readonly/busy and VM counters. *)
  103. IF ok THEN
  104. stmt := NIL;
  105. rc := sqlite3_prepare_v2(db, "SELECT ?;", -1, stmt, NIL);
  106. ok := (rc = SQLiteOk) AND (stmt # NIL)
  107. AND (sqlite3_stmt_readonly(stmt) = 1)
  108. AND TextIs(sqlite3_sql(stmt), "SELECT ?;")
  109. AND (sqlite3_stmt_busy(stmt) = 0);
  110. IF ok THEN
  111. ok := sqlite3_bind_int(stmt, 1, 42) = SQLiteOk
  112. END;
  113. IF ok THEN
  114. p := sqlite3_expanded_sql(stmt);
  115. ok := (p # NIL) AND TextIs(p, "SELECT 42;");
  116. IF p # NIL THEN
  117. sqlite3_free(p);
  118. p := NIL
  119. END
  120. END;
  121. IF ok THEN ok := sqlite3_step(stmt) = SQLiteRow END;
  122. IF ok THEN ok := sqlite3_stmt_busy(stmt) = 1 END;
  123. IF ok THEN
  124. ok := sqlite3_stmt_status(stmt, SQLiteStmtStatusVmStep, 0) > 0
  125. END;
  126. IF ok THEN ok := sqlite3_step(stmt) = SQLiteDone END;
  127. IF ok THEN ok := sqlite3_stmt_busy(stmt) = 0 END;
  128. IF ok THEN
  129. ok := (sqlite3_stmt_status(stmt, SQLiteStmtStatusVmStep, 1) > 0)
  130. AND (sqlite3_stmt_status(stmt, SQLiteStmtStatusVmStep, 0) = 0)
  131. END;
  132. IF NOT Finish(stmt) THEN ok := FALSE END
  133. END;
  134. (* A write statement is not readonly. *)
  135. IF ok THEN
  136. stmt := NIL;
  137. rc := sqlite3_prepare_v2(db, "INSERT INTO t(x) VALUES(1);",
  138. -1, stmt, NIL);
  139. ok := (rc = SQLiteOk) AND (stmt # NIL)
  140. AND (sqlite3_stmt_readonly(stmt) = 0);
  141. IF NOT Finish(stmt) THEN ok := FALSE END
  142. END;
  143. (* Syntax errors expose a byte offset. *)
  144. IF ok THEN
  145. stmt := NIL;
  146. rc := sqlite3_prepare_v2(db, "SELECT * FROM;", -1, stmt, NIL);
  147. ok := (rc # SQLiteOk) AND (stmt = NIL)
  148. AND (sqlite3_error_offset(db) >= 0);
  149. IF NOT Finish(stmt) THEN ok := FALSE END
  150. END;
  151. (* Statement iteration: exactly the two prepared statements. *)
  152. IF ok THEN
  153. rc := sqlite3_prepare_v2(db, "SELECT 1;", -1, s1, NIL);
  154. ok := (rc = SQLiteOk) AND (s1 # NIL);
  155. IF ok THEN
  156. rc := sqlite3_prepare_v2(db, "SELECT 2;", -1, s2, NIL);
  157. ok := (rc = SQLiteOk) AND (s2 # NIL)
  158. END;
  159. IF ok THEN
  160. p := sqlite3_next_stmt(db, NIL);
  161. q := sqlite3_next_stmt(db, p);
  162. ok := (p # NIL) AND (q # NIL) AND (p # q)
  163. AND (sqlite3_next_stmt(db, q) = NIL)
  164. END;
  165. IF NOT Finish(s1) THEN ok := FALSE END;
  166. IF NOT Finish(s2) THEN ok := FALSE END
  167. END
  168. END;
  169. IF NOT Finish(stmt) THEN ok := FALSE END;
  170. IF NOT Finish(s1) THEN ok := FALSE END;
  171. IF NOT Finish(s2) THEN ok := FALSE END;
  172. IF db # NIL THEN
  173. IF sqlite3_close_v2(db) # SQLiteOk THEN ok := FALSE END
  174. END;
  175. IF ok THEN ExitCode := 42 END
  176. END SQLiteIntrospection.