| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- MODULE showcase_all ;
- (*
- m2SQLITE showcase: exercises every procedure of the SQLite
- binding plus all SQLiteUtils helpers end to end.
- 1. library info: version, source id, threadsafe, errstr, complete
- 2. open, autocommit, busy timeout, extended codes, limit, open_v2
- 3. exec with raw errmsg capture, ExecWithErr failure, errcode paths
- 4. prepare_v2 tail capture, prepare_v3 flags, sql text, parameter ids
- 5. all bind kinds, step, changes counters, rowid
- 6. all column kinds, metadata, busy/reset/rebind, transactions
- 7. expanded sql, zeroblob, static destructor, close_v2
- 8. custom functions: scalar tax plus aggregate total
- 9. close
- *)
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM SQLite IMPORT DbHandle, StmtHandle, ContextHandle, ValueHandle,
- SQLiteOk, SQLiteRow, SQLiteDone,
- SQLiteInteger, SQLiteFloat, SQLiteText, SQLiteBlob, SQLiteNull,
- SQLiteOpenReadWrite, SQLiteOpenCreate,
- SQLitePreparePersistent, SQLiteLimitVariableNumber,
- SQLiteUtf8, SQLiteDeterministic,
- sqlite3_libversion, sqlite3_libversion_number, sqlite3_sourceid,
- sqlite3_threadsafe,
- sqlite3_open, sqlite3_open_v2, sqlite3_close, sqlite3_close_v2,
- sqlite3_exec,
- sqlite3_errcode, sqlite3_extended_errcode, sqlite3_errmsg,
- sqlite3_errstr, sqlite3_error_offset, sqlite3_free,
- sqlite3_complete, sqlite3_busy_timeout, sqlite3_get_autocommit,
- sqlite3_changes, sqlite3_total_changes, sqlite3_last_insert_rowid,
- sqlite3_extended_result_codes, sqlite3_limit,
- sqlite3_prepare_v2, sqlite3_prepare_v3,
- sqlite3_step, sqlite3_finalize, sqlite3_reset, sqlite3_clear_bindings,
- sqlite3_data_count, sqlite3_column_count,
- sqlite3_sql, sqlite3_expanded_sql,
- sqlite3_stmt_readonly, sqlite3_stmt_busy,
- sqlite3_bind_blob, sqlite3_bind_zeroblob,
- sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64,
- sqlite3_bind_null, sqlite3_bind_text,
- sqlite3_bind_parameter_count, sqlite3_bind_parameter_name,
- sqlite3_bind_parameter_index,
- sqlite3_column_blob, sqlite3_column_double, sqlite3_column_int,
- sqlite3_column_int64, sqlite3_column_text, sqlite3_column_bytes,
- sqlite3_column_type, sqlite3_column_name, sqlite3_column_decltype,
- sqlite3_create_function,
- sqlite3_value_int64, sqlite3_value_double,
- sqlite3_result_double, sqlite3_result_int64,
- sqlite3_aggregate_context;
- FROM SQLiteUtils IMPORT CStrToM2, ErrMsg, ErrStr, LibVersionStr,
- StaticDestr, TransientDestr,
- BindTextCopy, BindBlobCopy, ExecSimple, ExecWithErr;
- FROM libc IMPORT printf, strncpy;
- TYPE
- ArgVec = POINTER TO ARRAY [0..255] OF ADDRESS;
- TotalPtr = POINTER TO LONGINT;
- VAR
- db, db2: DbHandle;
- stmt: StmtHandle;
- rc, i, ncols, ndata, busy, ro: INTEGER;
- li: LONGINT;
- d: REAL;
- tp: INTEGER;
- tail, msg, p, xsql: ADDRESS;
- buf, buf2: ARRAY [0..127] OF CHAR;
- blobIn: ARRAY [0..3] OF CHAR;
- staticBlob: ARRAY [0..3] OF CHAR;
- out: ARRAY [0..15] OF CHAR;
- showInt, showFloat, showText, showBlob, showNull: INTEGER;
- PROCEDURE fail (what: ARRAY OF CHAR);
- VAR e: ARRAY [0..255] OF CHAR;
- BEGIN
- ErrMsg(db, e);
- printf("FAIL %s: %s\n", what, e);
- HALT(1)
- END fail;
- PROCEDURE check (rc: INTEGER; what: ARRAY OF CHAR);
- BEGIN
- IF rc # SQLiteOk THEN fail(what) END
- END check;
- PROCEDURE section (n: INTEGER; title: ARRAY OF CHAR);
- BEGIN
- printf("--- [%d] %s ---\n", n, title)
- END section;
- PROCEDURE ArgAt (argv: ADDRESS; i: INTEGER) : ValueHandle;
- VAR vec: ArgVec;
- BEGIN
- vec := VAL(ArgVec, argv);
- RETURN vec^[i]
- END ArgAt;
- PROCEDURE tax (ctx: ContextHandle; argc: INTEGER; argv: ADDRESS);
- BEGIN
- sqlite3_result_double(ctx,
- sqlite3_value_double(ArgAt(argv, 0)) * 1.2)
- END tax;
- PROCEDURE totalStep (ctx: ContextHandle; argc: INTEGER; argv: ADDRESS);
- VAR s: TotalPtr;
- BEGIN
- s := VAL(TotalPtr, sqlite3_aggregate_context(ctx, 8));
- s^ := s^ + sqlite3_value_int64(ArgAt(argv, 0))
- END totalStep;
- PROCEDURE totalFinal (ctx: ContextHandle);
- VAR s: TotalPtr;
- BEGIN
- s := VAL(TotalPtr, sqlite3_aggregate_context(ctx, 0));
- sqlite3_result_int64(ctx, s^)
- END totalFinal;
- BEGIN
- staticBlob[0] := 'W'; staticBlob[1] := 'X';
- staticBlob[2] := 'Y'; staticBlob[3] := 'Z';
- blobIn[0] := 'A'; blobIn[1] := 'B';
- blobIn[2] := 'C'; blobIn[3] := 'D';
- (* 1. library info *)
- section(1, "library info");
- LibVersionStr(buf);
- printf("version %s number %d\n", buf, sqlite3_libversion_number());
- IF sqlite3_libversion_number() <= 0 THEN HALT(1) END;
- CStrToM2(sqlite3_libversion(), buf);
- CStrToM2(sqlite3_sourceid(), buf2);
- printf("sourceid %s\n", buf2);
- printf("threadsafe %d\n", sqlite3_threadsafe());
- ErrStr(SQLiteOk, buf);
- printf("errstr ok %s\n", buf);
- CStrToM2(sqlite3_errstr(SQLiteOk), buf);
- printf("raw errstr %s\n", buf);
- IF sqlite3_complete("SELECT 1;") = 0 THEN
- printf("FAIL complete full\n"); HALT(1)
- END;
- IF sqlite3_complete("SELECT") # 0 THEN
- printf("FAIL complete partial\n"); HALT(1)
- END;
- printf("complete ok\n");
- (* 2. open and connection settings *)
- section(2, "open and settings");
- check(sqlite3_open(":memory:", db), "open");
- printf("autocommit %d\n", sqlite3_get_autocommit(db));
- check(sqlite3_busy_timeout(db, 500), "busy timeout");
- check(sqlite3_extended_result_codes(db, 1), "ext codes");
- i := sqlite3_limit(db, SQLiteLimitVariableNumber, -1);
- printf("limit variables %d\n", i);
- IF i <= 0 THEN printf("FAIL limit\n"); HALT(1) END;
- check(sqlite3_open_v2(":memory:", db2,
- SQLiteOpenReadWrite + SQLiteOpenCreate,
- NIL), "open_v2");
- (* 3. exec, including raw errmsg capture and failure paths *)
- section(3, "exec and errors");
- check(ExecSimple(db, "CREATE TABLE demo(id INTEGER PRIMARY KEY,"
- + " small INTEGER, big INTEGER,"
- + " score REAL, label TEXT,"
- + " payload BLOB, code TEXT);"),
- "create");
- check(ExecSimple(db, "INSERT INTO demo(small) VALUES(1);"), "seed");
- printf("changes %d total %d rowid %ld\n",
- sqlite3_changes(db), sqlite3_total_changes(db),
- sqlite3_last_insert_rowid(db));
- msg := NIL;
- rc := sqlite3_exec(db, "INSERT INTO demo(small) VALUES(2);",
- NIL, NIL, ADR(msg));
- IF rc # SQLiteOk THEN fail("raw exec") END;
- IF msg # NIL THEN sqlite3_free(msg) END;
- rc := ExecWithErr(db, "INSERT INTO bogus(x) VALUES(1);", buf);
- printf("expected failure rc %d err %s\n", rc, buf);
- IF rc = SQLiteOk THEN printf("FAIL bad sql ok\n"); HALT(1) END;
- printf("errcode %d ext %d offset %d\n",
- sqlite3_errcode(db), sqlite3_extended_errcode(db),
- sqlite3_error_offset(db));
- CStrToM2(sqlite3_errmsg(db), buf);
- printf("raw errmsg %s\n", buf);
- (* 4. prepare variants, tail, sql text, parameters *)
- section(4, "prepare and parameters");
- tail := NIL;
- check(sqlite3_prepare_v2(db, "SELECT small FROM demo; SELECT 99;",
- -1, stmt, ADR(tail)), "prep tail");
- IF tail = NIL THEN printf("FAIL tail nil\n"); HALT(1) END;
- CStrToM2(tail, buf);
- printf("tail %s\n", buf);
- CStrToM2(sqlite3_sql(stmt), buf);
- printf("sql %s\n", buf);
- check(sqlite3_finalize(stmt), "fin tail");
- check(sqlite3_prepare_v3(db, "SELECT :a, ?, :b;",
- -1, SQLitePreparePersistent,
- stmt, NIL), "prep v3");
- printf("param count %d\n", sqlite3_bind_parameter_count(stmt));
- IF sqlite3_bind_parameter_count(stmt) # 3 THEN HALT(1) END;
- CStrToM2(sqlite3_bind_parameter_name(stmt, 1), buf);
- printf("param1 %s\n", buf);
- IF sqlite3_bind_parameter_name(stmt, 2) # NIL THEN
- printf("FAIL anon param named\n"); HALT(1)
- END;
- i := sqlite3_bind_parameter_index(stmt, ":b");
- printf("param :b index %d\n", i);
- IF i # 3 THEN HALT(1) END;
- ro := sqlite3_stmt_readonly(stmt);
- printf("readonly select %d\n", ro);
- IF ro = 0 THEN HALT(1) END;
- check(sqlite3_finalize(stmt), "fin v3");
- check(sqlite3_prepare_v2(db, "INSERT INTO demo(small) VALUES(1);",
- -1, stmt, NIL), "prep ins");
- IF sqlite3_stmt_readonly(stmt) # 0 THEN
- printf("FAIL readonly insert\n"); HALT(1)
- END;
- check(sqlite3_finalize(stmt), "fin ins");
- (* 5. all bind kinds *)
- section(5, "binds and step");
- check(sqlite3_prepare_v2(db, "DELETE FROM demo;", -1, stmt, NIL),
- "prep delete");
- IF sqlite3_step(stmt) # SQLiteDone THEN HALT(1) END;
- check(sqlite3_finalize(stmt), "fin delete");
- check(sqlite3_prepare_v2(db, "INSERT INTO demo"
- + "(small,big,score,label,payload,code)"
- + " VALUES(?,?,?,?,?,?);",
- -1, stmt, NIL), "prep full insert");
- check(sqlite3_bind_int(stmt, 1, 42), "bind int");
- check(sqlite3_bind_int64(stmt, 2, VAL(LONGINT, 9000000001)),
- "bind int64");
- check(sqlite3_bind_double(stmt, 3, 2.5), "bind double");
- check(BindTextCopy(stmt, 4, "hello"), "bind text copy");
- check(BindBlobCopy(stmt, 5, ADR(blobIn), 4), "bind blob copy");
- check(sqlite3_bind_null(stmt, 6), "bind null");
- IF sqlite3_step(stmt) # SQLiteDone THEN fail("step insert") END;
- printf("insert changes %d rowid %ld\n",
- sqlite3_changes(db), sqlite3_last_insert_rowid(db));
- xsql := sqlite3_expanded_sql(stmt);
- CStrToM2(xsql, buf);
- printf("expanded %s\n", buf);
- IF xsql # NIL THEN sqlite3_free(xsql) END;
- check(sqlite3_finalize(stmt), "fin full insert");
- (* 6. all column kinds, metadata, reuse, transactions *)
- section(6, "columns and reuse");
- check(sqlite3_prepare_v2(db, "SELECT small,big,score,label,"
- + "payload,code FROM demo;",
- -1, stmt, NIL), "prep select");
- rc := sqlite3_step(stmt);
- IF rc # SQLiteRow THEN fail("step row") END;
- ncols := sqlite3_column_count(stmt);
- ndata := sqlite3_data_count(stmt);
- printf("cols %d data %d\n", ncols, ndata);
- IF (ncols # 6) OR (ndata # 6) THEN HALT(1) END;
- busy := sqlite3_stmt_busy(stmt);
- printf("busy %d\n", busy);
- IF busy = 0 THEN HALT(1) END;
- i := sqlite3_column_int(stmt, 0);
- li := sqlite3_column_int64(stmt, 1);
- d := sqlite3_column_double(stmt, 2);
- CStrToM2(sqlite3_column_text(stmt, 3), buf);
- ncols := sqlite3_column_bytes(stmt, 3);
- p := sqlite3_column_blob(stmt, 4);
- tp := sqlite3_column_type(stmt, 4);
- printf("row %d %ld %f %s bytes %d blobtype %d\n",
- i, li, d, buf, ncols, tp);
- IF (i # 42) OR (li # VAL(LONGINT, 9000000001)) THEN HALT(1) END;
- IF ncols # 5 THEN HALT(1) END;
- IF (p = NIL) OR (sqlite3_column_bytes(stmt, 4) # 4) THEN HALT(1) END;
- strncpy(ADR(out), p, 4);
- out[4] := 0C;
- printf("blob %s\n", out);
- IF sqlite3_column_type(stmt, 5) # SQLiteNull THEN HALT(1) END;
- CStrToM2(sqlite3_column_name(stmt, 0), buf);
- CStrToM2(sqlite3_column_decltype(stmt, 0), buf2);
- printf("col0 %s decl %s\n", buf, buf2);
- showInt := SQLiteInteger; showFloat := SQLiteFloat;
- showText := SQLiteText; showBlob := SQLiteBlob; showNull := SQLiteNull;
- printf("type ids int %d float %d text %d blob %d null %d\n",
- showInt, showFloat, showText, showBlob, showNull);
- check(sqlite3_reset(stmt), "reset");
- IF sqlite3_stmt_busy(stmt) # 0 THEN
- printf("FAIL busy after reset\n"); HALT(1)
- END;
- check(sqlite3_clear_bindings(stmt), "clear");
- check(sqlite3_finalize(stmt), "fin select");
- (* statement reuse with raw transient and static destructors *)
- check(sqlite3_prepare_v2(db, "INSERT INTO demo(label,payload)"
- + " VALUES(?,?);",
- -1, stmt, NIL), "prep reuse");
- check(sqlite3_bind_text(stmt, 1, "raw", -1, TransientDestr()),
- "bind raw transient");
- check(sqlite3_bind_blob(stmt, 2, ADR(staticBlob), 4, StaticDestr()),
- "bind static");
- IF sqlite3_step(stmt) # SQLiteDone THEN HALT(1) END;
- check(sqlite3_reset(stmt), "reset reuse");
- check(sqlite3_clear_bindings(stmt), "clear reuse");
- check(BindTextCopy(stmt, 1, "second"), "rebind text");
- check(sqlite3_bind_zeroblob(stmt, 2, 16), "bind zeroblob");
- IF sqlite3_step(stmt) # SQLiteDone THEN HALT(1) END;
- check(sqlite3_finalize(stmt), "fin reuse");
- check(sqlite3_prepare_v2(db, "SELECT COUNT(*),"
- + " SUM(LENGTH(payload)) FROM demo;",
- -1, stmt, NIL), "prep agg");
- IF sqlite3_step(stmt) # SQLiteRow THEN HALT(1) END;
- printf("rows %d blobs %d\n",
- sqlite3_column_int(stmt, 0), sqlite3_column_int(stmt, 1));
- IF sqlite3_column_int(stmt, 0) # 3 THEN HALT(1) END;
- check(sqlite3_finalize(stmt), "fin agg");
- check(ExecSimple(db, "BEGIN;"), "begin");
- IF sqlite3_get_autocommit(db) # 0 THEN HALT(1) END;
- check(ExecSimple(db, "INSERT INTO demo(small) VALUES(7);"), "txn ins");
- check(ExecSimple(db, "COMMIT;"), "commit");
- IF sqlite3_get_autocommit(db) = 0 THEN HALT(1) END;
- printf("total changes %d\n", sqlite3_total_changes(db));
- (* 8. custom functions *)
- section(8, "custom functions");
- check(sqlite3_create_function(db, "m2tax", 1,
- SQLiteUtf8 + SQLiteDeterministic,
- NIL, tax, NIL, NIL), "reg tax");
- check(sqlite3_create_function(db, "m2total", 1, SQLiteUtf8, NIL,
- NIL, totalStep, totalFinal),
- "reg total");
- check(ExecSimple(db, "CREATE TABLE fx(price REAL);"), "fx create");
- check(ExecSimple(db, "INSERT INTO fx VALUES(10.0),(20.0),(30.0);"),
- "fx fill");
- check(sqlite3_prepare_v2(db, "SELECT m2tax(100.0), m2total(price)"
- + " FROM fx;",
- -1, stmt, NIL), "prep fx");
- rc := sqlite3_step(stmt);
- IF rc # SQLiteRow THEN fail("fx step") END;
- d := sqlite3_column_double(stmt, 0);
- li := sqlite3_column_int64(stmt, 1);
- printf("taxed %f totalled %ld\n", d, li);
- IF (d < 119.9) OR (d > 120.1) THEN fail("fx tax") END;
- IF li # 60 THEN fail("fx total") END;
- check(sqlite3_finalize(stmt), "fin fx");
- (* 9. close paths *)
- section(9, "close");
- check(sqlite3_close_v2(db2), "close_v2");
- check(sqlite3_close(db), "close");
- printf("PASS showcase_all\n")
- END showcase_all.
|