showcase_all.mod 14 KB

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