showcase_all.mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. MODULE showcase_all ;
  2. (*
  3. m2SQLITE showcase: exercises every procedure of the SQLite
  4. binding plus all SQLiteUtils helpers end to end.
  5. 1. library info: version, source id, threadsafe, errstr, complete
  6. 2. open, autocommit, busy timeout, extended codes, limit, open_v2
  7. 3. exec with raw errmsg capture, ExecWithErr failure, errcode paths
  8. 4. prepare_v2 tail capture, prepare_v3 flags, sql text, parameter ids
  9. 5. all bind kinds, step, changes counters, rowid
  10. 6. all column kinds, metadata, busy/reset/rebind, transactions
  11. 7. expanded sql, zeroblob, static destructor, close_v2, close
  12. *)
  13. FROM SYSTEM IMPORT ADDRESS, ADR;
  14. FROM SQLite IMPORT DbHandle, StmtHandle,
  15. SQLiteOk, SQLiteRow, SQLiteDone,
  16. SQLiteInteger, SQLiteFloat, SQLiteText, SQLiteBlob, SQLiteNull,
  17. SQLiteOpenReadWrite, SQLiteOpenCreate,
  18. SQLitePreparePersistent, SQLiteLimitVariableNumber,
  19. sqlite3_libversion, sqlite3_libversion_number, sqlite3_sourceid,
  20. sqlite3_threadsafe,
  21. sqlite3_open, sqlite3_open_v2, sqlite3_close, sqlite3_close_v2,
  22. sqlite3_exec,
  23. sqlite3_errcode, sqlite3_extended_errcode, sqlite3_errmsg,
  24. sqlite3_errstr, sqlite3_error_offset, sqlite3_free,
  25. sqlite3_complete, sqlite3_busy_timeout, sqlite3_get_autocommit,
  26. sqlite3_changes, sqlite3_total_changes, sqlite3_last_insert_rowid,
  27. sqlite3_extended_result_codes, sqlite3_limit,
  28. sqlite3_prepare_v2, sqlite3_prepare_v3,
  29. sqlite3_step, sqlite3_finalize, sqlite3_reset, sqlite3_clear_bindings,
  30. sqlite3_data_count, sqlite3_column_count,
  31. sqlite3_sql, sqlite3_expanded_sql,
  32. sqlite3_stmt_readonly, sqlite3_stmt_busy,
  33. sqlite3_bind_blob, sqlite3_bind_zeroblob,
  34. sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64,
  35. sqlite3_bind_null, sqlite3_bind_text,
  36. sqlite3_bind_parameter_count, sqlite3_bind_parameter_name,
  37. sqlite3_bind_parameter_index,
  38. sqlite3_column_blob, sqlite3_column_double, sqlite3_column_int,
  39. sqlite3_column_int64, sqlite3_column_text, sqlite3_column_bytes,
  40. sqlite3_column_type, sqlite3_column_name, sqlite3_column_decltype;
  41. FROM SQLiteUtils IMPORT CStrToM2, ErrMsg, ErrStr, LibVersionStr,
  42. StaticDestr, TransientDestr,
  43. BindTextCopy, BindBlobCopy, ExecSimple, ExecWithErr;
  44. FROM libc IMPORT printf, strncpy;
  45. VAR
  46. db, db2: DbHandle;
  47. stmt: StmtHandle;
  48. rc, i, ncols, ndata, busy, ro: INTEGER;
  49. li: LONGINT;
  50. d: REAL;
  51. tp: INTEGER;
  52. tail, msg, p, xsql: ADDRESS;
  53. buf, buf2: ARRAY [0..127] OF CHAR;
  54. blobIn: ARRAY [0..3] OF CHAR;
  55. staticBlob: ARRAY [0..3] OF CHAR;
  56. out: ARRAY [0..15] OF CHAR;
  57. showInt, showFloat, showText, showBlob, showNull: INTEGER;
  58. PROCEDURE fail (what: ARRAY OF CHAR);
  59. VAR e: ARRAY [0..255] OF CHAR;
  60. BEGIN
  61. ErrMsg(db, e);
  62. printf("FAIL %s: %s\n", what, e);
  63. HALT(1)
  64. END fail;
  65. PROCEDURE check (rc: INTEGER; what: ARRAY OF CHAR);
  66. BEGIN
  67. IF rc # SQLiteOk THEN fail(what) END
  68. END check;
  69. PROCEDURE section (n: INTEGER; title: ARRAY OF CHAR);
  70. BEGIN
  71. printf("--- [%d] %s ---\n", n, title)
  72. END section;
  73. BEGIN
  74. staticBlob[0] := 'W'; staticBlob[1] := 'X';
  75. staticBlob[2] := 'Y'; staticBlob[3] := 'Z';
  76. blobIn[0] := 'A'; blobIn[1] := 'B';
  77. blobIn[2] := 'C'; blobIn[3] := 'D';
  78. (* 1. library info *)
  79. section(1, "library info");
  80. LibVersionStr(buf);
  81. printf("version %s number %d\n", buf, sqlite3_libversion_number());
  82. IF sqlite3_libversion_number() <= 0 THEN HALT(1) END;
  83. CStrToM2(sqlite3_libversion(), buf);
  84. CStrToM2(sqlite3_sourceid(), buf2);
  85. printf("sourceid %s\n", buf2);
  86. printf("threadsafe %d\n", sqlite3_threadsafe());
  87. ErrStr(SQLiteOk, buf);
  88. printf("errstr ok %s\n", buf);
  89. CStrToM2(sqlite3_errstr(SQLiteOk), buf);
  90. printf("raw errstr %s\n", buf);
  91. IF sqlite3_complete("SELECT 1;") = 0 THEN
  92. printf("FAIL complete full\n"); HALT(1)
  93. END;
  94. IF sqlite3_complete("SELECT") # 0 THEN
  95. printf("FAIL complete partial\n"); HALT(1)
  96. END;
  97. printf("complete ok\n");
  98. (* 2. open and connection settings *)
  99. section(2, "open and settings");
  100. check(sqlite3_open(":memory:", db), "open");
  101. printf("autocommit %d\n", sqlite3_get_autocommit(db));
  102. check(sqlite3_busy_timeout(db, 500), "busy timeout");
  103. check(sqlite3_extended_result_codes(db, 1), "ext codes");
  104. i := sqlite3_limit(db, SQLiteLimitVariableNumber, -1);
  105. printf("limit variables %d\n", i);
  106. IF i <= 0 THEN printf("FAIL limit\n"); HALT(1) END;
  107. check(sqlite3_open_v2(":memory:", db2,
  108. SQLiteOpenReadWrite + SQLiteOpenCreate,
  109. NIL), "open_v2");
  110. (* 3. exec, including raw errmsg capture and failure paths *)
  111. section(3, "exec and errors");
  112. check(ExecSimple(db, "CREATE TABLE demo(id INTEGER PRIMARY KEY,"
  113. + " small INTEGER, big INTEGER,"
  114. + " score REAL, label TEXT,"
  115. + " payload BLOB, code TEXT);"),
  116. "create");
  117. check(ExecSimple(db, "INSERT INTO demo(small) VALUES(1);"), "seed");
  118. printf("changes %d total %d rowid %ld\n",
  119. sqlite3_changes(db), sqlite3_total_changes(db),
  120. sqlite3_last_insert_rowid(db));
  121. msg := NIL;
  122. rc := sqlite3_exec(db, "INSERT INTO demo(small) VALUES(2);",
  123. NIL, NIL, ADR(msg));
  124. IF rc # SQLiteOk THEN fail("raw exec") END;
  125. IF msg # NIL THEN sqlite3_free(msg) END;
  126. rc := ExecWithErr(db, "INSERT INTO bogus(x) VALUES(1);", buf);
  127. printf("expected failure rc %d err %s\n", rc, buf);
  128. IF rc = SQLiteOk THEN printf("FAIL bad sql ok\n"); HALT(1) END;
  129. printf("errcode %d ext %d offset %d\n",
  130. sqlite3_errcode(db), sqlite3_extended_errcode(db),
  131. sqlite3_error_offset(db));
  132. CStrToM2(sqlite3_errmsg(db), buf);
  133. printf("raw errmsg %s\n", buf);
  134. (* 4. prepare variants, tail, sql text, parameters *)
  135. section(4, "prepare and parameters");
  136. tail := NIL;
  137. check(sqlite3_prepare_v2(db, "SELECT small FROM demo; SELECT 99;",
  138. -1, stmt, ADR(tail)), "prep tail");
  139. IF tail = NIL THEN printf("FAIL tail nil\n"); HALT(1) END;
  140. CStrToM2(tail, buf);
  141. printf("tail %s\n", buf);
  142. CStrToM2(sqlite3_sql(stmt), buf);
  143. printf("sql %s\n", buf);
  144. check(sqlite3_finalize(stmt), "fin tail");
  145. check(sqlite3_prepare_v3(db, "SELECT :a, ?, :b;",
  146. -1, SQLitePreparePersistent,
  147. stmt, NIL), "prep v3");
  148. printf("param count %d\n", sqlite3_bind_parameter_count(stmt));
  149. IF sqlite3_bind_parameter_count(stmt) # 3 THEN HALT(1) END;
  150. CStrToM2(sqlite3_bind_parameter_name(stmt, 1), buf);
  151. printf("param1 %s\n", buf);
  152. IF sqlite3_bind_parameter_name(stmt, 2) # NIL THEN
  153. printf("FAIL anon param named\n"); HALT(1)
  154. END;
  155. i := sqlite3_bind_parameter_index(stmt, ":b");
  156. printf("param :b index %d\n", i);
  157. IF i # 3 THEN HALT(1) END;
  158. ro := sqlite3_stmt_readonly(stmt);
  159. printf("readonly select %d\n", ro);
  160. IF ro = 0 THEN HALT(1) END;
  161. check(sqlite3_finalize(stmt), "fin v3");
  162. check(sqlite3_prepare_v2(db, "INSERT INTO demo(small) VALUES(1);",
  163. -1, stmt, NIL), "prep ins");
  164. IF sqlite3_stmt_readonly(stmt) # 0 THEN
  165. printf("FAIL readonly insert\n"); HALT(1)
  166. END;
  167. check(sqlite3_finalize(stmt), "fin ins");
  168. (* 5. all bind kinds *)
  169. section(5, "binds and step");
  170. check(sqlite3_prepare_v2(db, "DELETE FROM demo;", -1, stmt, NIL),
  171. "prep delete");
  172. IF sqlite3_step(stmt) # SQLiteDone THEN HALT(1) END;
  173. check(sqlite3_finalize(stmt), "fin delete");
  174. check(sqlite3_prepare_v2(db, "INSERT INTO demo"
  175. + "(small,big,score,label,payload,code)"
  176. + " VALUES(?,?,?,?,?,?);",
  177. -1, stmt, NIL), "prep full insert");
  178. check(sqlite3_bind_int(stmt, 1, 42), "bind int");
  179. check(sqlite3_bind_int64(stmt, 2, VAL(LONGINT, 9000000001)),
  180. "bind int64");
  181. check(sqlite3_bind_double(stmt, 3, 2.5), "bind double");
  182. check(BindTextCopy(stmt, 4, "hello"), "bind text copy");
  183. check(BindBlobCopy(stmt, 5, ADR(blobIn), 4), "bind blob copy");
  184. check(sqlite3_bind_null(stmt, 6), "bind null");
  185. IF sqlite3_step(stmt) # SQLiteDone THEN fail("step insert") END;
  186. printf("insert changes %d rowid %ld\n",
  187. sqlite3_changes(db), sqlite3_last_insert_rowid(db));
  188. xsql := sqlite3_expanded_sql(stmt);
  189. CStrToM2(xsql, buf);
  190. printf("expanded %s\n", buf);
  191. IF xsql # NIL THEN sqlite3_free(xsql) END;
  192. check(sqlite3_finalize(stmt), "fin full insert");
  193. (* 6. all column kinds, metadata, reuse, transactions *)
  194. section(6, "columns and reuse");
  195. check(sqlite3_prepare_v2(db, "SELECT small,big,score,label,"
  196. + "payload,code FROM demo;",
  197. -1, stmt, NIL), "prep select");
  198. rc := sqlite3_step(stmt);
  199. IF rc # SQLiteRow THEN fail("step row") END;
  200. ncols := sqlite3_column_count(stmt);
  201. ndata := sqlite3_data_count(stmt);
  202. printf("cols %d data %d\n", ncols, ndata);
  203. IF (ncols # 6) OR (ndata # 6) THEN HALT(1) END;
  204. busy := sqlite3_stmt_busy(stmt);
  205. printf("busy %d\n", busy);
  206. IF busy = 0 THEN HALT(1) END;
  207. i := sqlite3_column_int(stmt, 0);
  208. li := sqlite3_column_int64(stmt, 1);
  209. d := sqlite3_column_double(stmt, 2);
  210. CStrToM2(sqlite3_column_text(stmt, 3), buf);
  211. ncols := sqlite3_column_bytes(stmt, 3);
  212. p := sqlite3_column_blob(stmt, 4);
  213. tp := sqlite3_column_type(stmt, 4);
  214. printf("row %d %ld %f %s bytes %d blobtype %d\n",
  215. i, li, d, buf, ncols, tp);
  216. IF (i # 42) OR (li # VAL(LONGINT, 9000000001)) THEN HALT(1) END;
  217. IF ncols # 5 THEN HALT(1) END;
  218. IF (p = NIL) OR (sqlite3_column_bytes(stmt, 4) # 4) THEN HALT(1) END;
  219. strncpy(ADR(out), p, 4);
  220. out[4] := 0C;
  221. printf("blob %s\n", out);
  222. IF sqlite3_column_type(stmt, 5) # SQLiteNull THEN HALT(1) END;
  223. CStrToM2(sqlite3_column_name(stmt, 0), buf);
  224. CStrToM2(sqlite3_column_decltype(stmt, 0), buf2);
  225. printf("col0 %s decl %s\n", buf, buf2);
  226. showInt := SQLiteInteger; showFloat := SQLiteFloat;
  227. showText := SQLiteText; showBlob := SQLiteBlob; showNull := SQLiteNull;
  228. printf("type ids int %d float %d text %d blob %d null %d\n",
  229. showInt, showFloat, showText, showBlob, showNull);
  230. check(sqlite3_reset(stmt), "reset");
  231. IF sqlite3_stmt_busy(stmt) # 0 THEN
  232. printf("FAIL busy after reset\n"); HALT(1)
  233. END;
  234. check(sqlite3_clear_bindings(stmt), "clear");
  235. check(sqlite3_finalize(stmt), "fin select");
  236. (* statement reuse with raw transient and static destructors *)
  237. check(sqlite3_prepare_v2(db, "INSERT INTO demo(label,payload)"
  238. + " VALUES(?,?);",
  239. -1, stmt, NIL), "prep reuse");
  240. check(sqlite3_bind_text(stmt, 1, "raw", -1, TransientDestr()),
  241. "bind raw transient");
  242. check(sqlite3_bind_blob(stmt, 2, ADR(staticBlob), 4, StaticDestr()),
  243. "bind static");
  244. IF sqlite3_step(stmt) # SQLiteDone THEN HALT(1) END;
  245. check(sqlite3_reset(stmt), "reset reuse");
  246. check(sqlite3_clear_bindings(stmt), "clear reuse");
  247. check(BindTextCopy(stmt, 1, "second"), "rebind text");
  248. check(sqlite3_bind_zeroblob(stmt, 2, 16), "bind zeroblob");
  249. IF sqlite3_step(stmt) # SQLiteDone THEN HALT(1) END;
  250. check(sqlite3_finalize(stmt), "fin reuse");
  251. check(sqlite3_prepare_v2(db, "SELECT COUNT(*),"
  252. + " SUM(LENGTH(payload)) FROM demo;",
  253. -1, stmt, NIL), "prep agg");
  254. IF sqlite3_step(stmt) # SQLiteRow THEN HALT(1) END;
  255. printf("rows %d blobs %d\n",
  256. sqlite3_column_int(stmt, 0), sqlite3_column_int(stmt, 1));
  257. IF sqlite3_column_int(stmt, 0) # 3 THEN HALT(1) END;
  258. check(sqlite3_finalize(stmt), "fin agg");
  259. check(ExecSimple(db, "BEGIN;"), "begin");
  260. IF sqlite3_get_autocommit(db) # 0 THEN HALT(1) END;
  261. check(ExecSimple(db, "INSERT INTO demo(small) VALUES(7);"), "txn ins");
  262. check(ExecSimple(db, "COMMIT;"), "commit");
  263. IF sqlite3_get_autocommit(db) = 0 THEN HALT(1) END;
  264. printf("total changes %d\n", sqlite3_total_changes(db));
  265. (* 7. close paths *)
  266. section(7, "close");
  267. check(sqlite3_close_v2(db2), "close_v2");
  268. check(sqlite3_close(db), "close");
  269. printf("PASS showcase_all\n")
  270. END showcase_all.