| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- MODULE SQLiteFeatureShowcase;
- (* Broad V3 SQLite binding showcase:
- diagnostics, prepared statements, parameter metadata, row callbacks,
- scalar types, BLOB I/O, statement metadata, UDFs, hooks, backup,
- constraint errors and authorizer behavior. *)
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM CStr IMPORT CString, Copy;
- FROM SysIO IMPORT Write, WriteLn, WriteInt;
- FROM SQLite IMPORT
- SQLiteOk, SQLiteRow, SQLiteDone, SQLiteBusy, SQLiteAuth, SQLiteBlob,
- SQLiteBlobReadWrite, SQLiteOpenReadWrite, SQLiteOpenCreate,
- SQLiteOpenMemory, SQLiteTraceStmt, SQLiteUtf8, SQLiteDeterministic,
- SQLiteAuthOk, SQLiteAuthDeny, SQLiteAuthDelete,
- SQLiteStmtStatusVmStep,
- sqlite3_open_v2, sqlite3_close, sqlite3_close_v2, sqlite3_exec,
- sqlite3_prepare_v2, sqlite3_step, sqlite3_reset,
- sqlite3_clear_bindings, sqlite3_finalize,
- sqlite3_bind_int, sqlite3_bind_null, sqlite3_bind_blob,
- sqlite3_bind_zeroblob,
- sqlite3_bind_text, sqlite3_bind_parameter_count,
- sqlite3_bind_parameter_name, sqlite3_bind_parameter_index,
- sqlite3_column_type, sqlite3_column_bytes, sqlite3_column_int,
- sqlite3_column_blob,
- sqlite3_changes, sqlite3_total_changes,
- sqlite3_sql, sqlite3_expanded_sql, sqlite3_stmt_readonly,
- sqlite3_stmt_busy, sqlite3_next_stmt, sqlite3_stmt_status,
- sqlite3_libversion, sqlite3_libversion_number, sqlite3_sourceid,
- sqlite3_threadsafe, sqlite3_get_autocommit, sqlite3_complete,
- sqlite3_blob_open, sqlite3_blob_close, sqlite3_blob_read,
- sqlite3_blob_write, sqlite3_blob_bytes,
- sqlite3_backup_init, sqlite3_backup_step, sqlite3_backup_finish,
- sqlite3_backup_remaining, sqlite3_backup_pagecount,
- sqlite3_create_function_v2, sqlite3_value_int,
- sqlite3_result_int, sqlite3_result_error,
- sqlite3_progress_handler, sqlite3_trace_v2,
- sqlite3_update_hook, sqlite3_commit_hook, sqlite3_rollback_hook,
- sqlite3_set_authorizer, sqlite3_extended_result_codes,
- sqlite3_extended_errcode, sqlite3_errmsg, sqlite3_free,
- SQLiteArrayAt, SQLiteTransient;
- VAR
- ExitCode : INTEGER;
- db, dst, stmt, s1, s2, blob, bk, prev : ADDRESS;
- rc, pages, remaining, progressCalls, traceCalls : INTEGER;
- updateCalls, commitCalls, rollbackCalls, authCalls : INTEGER;
- ok : BOOLEAN;
- bin, out : ARRAY [0..7] OF CHAR;
- PROCEDURE Say (s : ARRAY OF CHAR);
- VAR
- buf : ARRAY [0..255] OF CHAR;
- i : INTEGER;
- BEGIN
- i := 0;
- WHILE (i <= HIGH(buf)) AND (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
- buf[i] := s[i];
- i := i + 1
- END;
- IF i <= HIGH(buf) THEN buf[i] := CHR(0) END;
- IF i > 0 THEN Write(buf) END
- END Say;
- PROCEDURE SayLn (s : ARRAY OF CHAR);
- BEGIN
- Say(s); WriteLn
- END SayLn;
- PROCEDURE SayInt (n : INTEGER);
- BEGIN
- WriteInt(n)
- END SayInt;
- PROCEDURE SayCS (s : CString);
- VAR
- buf : ARRAY [0..255] OF CHAR;
- BEGIN
- IF s = NIL THEN
- Say("NULL")
- ELSE
- IF Copy(s, buf) > 0 THEN Say(buf) END
- END
- END SayCS;
- PROCEDURE SameText (a, b : ARRAY OF CHAR) : BOOLEAN;
- VAR
- i : INTEGER;
- BEGIN
- i := 0;
- WHILE (a[i] # CHR(0)) AND (a[i] = b[i]) DO i := i + 1 END;
- RETURN (a[i] = CHR(0)) AND (b[i] = CHR(0))
- END SameText;
- PROCEDURE SameBytes (a, b : ARRAY OF CHAR; n : INTEGER) : BOOLEAN;
- VAR
- i : INTEGER;
- BEGIN
- i := 0;
- WHILE (i < n) AND (a[i] = b[i]) DO i := i + 1 END;
- RETURN i = n
- END SameBytes;
- PROCEDURE OpenMemory (VAR h : ADDRESS) : BOOLEAN;
- BEGIN
- h := NIL;
- RETURN sqlite3_open_v2(":memory:", h,
- SQLiteOpenReadWrite + SQLiteOpenCreate + SQLiteOpenMemory,
- NIL) = SQLiteOk
- END OpenMemory;
- PROCEDURE ExecSQL (sql : ARRAY OF CHAR) : BOOLEAN;
- VAR
- errmsg : ADDRESS;
- good : BOOLEAN;
- BEGIN
- errmsg := NIL;
- good := sqlite3_exec(db, sql, NIL, NIL, errmsg) = SQLiteOk;
- IF errmsg # NIL THEN sqlite3_free(errmsg) END;
- RETURN good
- END ExecSQL;
- PROCEDURE QueryInt (h : ADDRESS; sql : ARRAY OF CHAR; want : INTEGER) : BOOLEAN;
- VAR
- s : ADDRESS;
- code, got : INTEGER;
- good : BOOLEAN;
- BEGIN
- s := NIL; got := -777; good := FALSE;
- code := sqlite3_prepare_v2(h, sql, -1, s, NIL);
- IF (code = SQLiteOk) AND (s # NIL) THEN
- IF sqlite3_step(s) = SQLiteRow THEN
- got := sqlite3_column_int(s, 0);
- IF sqlite3_step(s) = SQLiteDone THEN good := TRUE END
- END;
- IF sqlite3_finalize(s) # SQLiteOk THEN good := FALSE END
- END;
- RETURN good AND (got = want)
- END QueryInt;
- PROCEDURE ExecCallback (sql : ARRAY OF CHAR; cb : ADDRESS) : BOOLEAN;
- VAR
- errmsg : ADDRESS;
- good : BOOLEAN;
- BEGIN
- errmsg := NIL;
- good := sqlite3_exec(db, sql, cb, NIL, errmsg) = SQLiteOk;
- IF errmsg # NIL THEN sqlite3_free(errmsg) END;
- RETURN good
- END ExecCallback;
- PROCEDURE Register (name : ARRAY OF CHAR; n : INTEGER;
- user, fn : ADDRESS) : BOOLEAN;
- BEGIN
- RETURN sqlite3_create_function_v2(db, name, n,
- SQLiteUtf8 + SQLiteDeterministic, user, fn, NIL, NIL, NIL)
- = SQLiteOk
- END Register;
- PROCEDURE RowPrinter (arg : ADDRESS; argc : INTEGER;
- argv, colNames : ADDRESS) : INTEGER;
- VAR
- i : INTEGER;
- s : CString;
- buf : ARRAY [0..127] OF CHAR;
- BEGIN
- FOR i := 0 TO argc - 1 DO
- IF i > 0 THEN Say(" | ") END;
- s := SQLiteArrayAt(argv, i);
- IF s = NIL THEN
- Say("NULL")
- ELSIF Copy(s, buf) > 0 THEN
- Say(buf)
- END
- END;
- WriteLn;
- RETURN 0
- END RowPrinter;
- PROCEDURE AddFn (ctx : ADDRESS; argc : INTEGER; argv : ADDRESS);
- BEGIN
- IF argc = 2 THEN
- sqlite3_result_int(ctx,
- sqlite3_value_int(SQLiteArrayAt(argv, 0))
- + sqlite3_value_int(SQLiteArrayAt(argv, 1)))
- ELSE
- sqlite3_result_error(ctx, "m2_add expects 2 arguments", -1)
- END
- END AddFn;
- PROCEDURE ProgressFn (arg : ADDRESS) : INTEGER;
- BEGIN
- progressCalls := progressCalls + 1;
- RETURN 0
- END ProgressFn;
- PROCEDURE TraceFn (mask : CARDINAL; ctx, sql, expanded : ADDRESS) : INTEGER;
- BEGIN
- traceCalls := traceCalls + 1;
- RETURN 0
- END TraceFn;
- PROCEDURE UpdateFn (arg : ADDRESS; op : INTEGER;
- dbName, tableName : ADDRESS; rowid : LONGINT);
- BEGIN
- updateCalls := updateCalls + 1
- END UpdateFn;
- PROCEDURE CommitFn (arg : ADDRESS) : INTEGER;
- BEGIN
- commitCalls := commitCalls + 1;
- RETURN 0
- END CommitFn;
- PROCEDURE RollbackFn (arg : ADDRESS);
- BEGIN
- rollbackCalls := rollbackCalls + 1
- END RollbackFn;
- PROCEDURE AuthFn (arg : ADDRESS; action : INTEGER;
- dbName, tableName, colName, triggerName : ADDRESS) : INTEGER;
- BEGIN
- authCalls := authCalls + 1;
- IF action = SQLiteAuthDelete THEN
- RETURN SQLiteAuthDeny
- ELSE
- RETURN SQLiteAuthOk
- END
- END AuthFn;
- BEGIN
- ExitCode := 1;
- db := NIL; dst := NIL; stmt := NIL; s1 := NIL; s2 := NIL;
- blob := NIL; bk := NIL; prev := NIL;
- progressCalls := 0; traceCalls := 0; updateCalls := 0;
- commitCalls := 0; rollbackCalls := 0; authCalls := 0;
- bin[0] := CHR(0); bin[1] := CHR(1); bin[2] := CHR(2);
- bin[3] := CHR(0); bin[4] := CHR(255);
- ok := FALSE;
- SayLn("SQLite V3 feature showcase");
- Say("libversion="); SayCS(sqlite3_libversion()); WriteLn;
- Say("version_number="); SayInt(sqlite3_libversion_number()); WriteLn;
- Say("threadsafe="); SayInt(sqlite3_threadsafe()); WriteLn;
- Say("complete="); SayInt(sqlite3_complete("SELECT 1;")); WriteLn;
- IF OpenMemory(db) THEN
- ok := sqlite3_extended_result_codes(db, 1) = SQLiteOk
- END;
- IF ok THEN
- ok := ExecSQL("CREATE TABLE people(id INTEGER, name TEXT, data BLOB);")
- AND ExecSQL("CREATE TABLE hook(id INTEGER PRIMARY KEY, v TEXT);")
- END;
- (* Prepared insert with named/anonymous parameter metadata. *)
- IF ok THEN
- stmt := NIL;
- rc := sqlite3_prepare_v2(db,
- "INSERT INTO people(name,data) VALUES(?,?);", -1, stmt, NIL);
- ok := (rc = SQLiteOk) AND (stmt # NIL)
- AND (sqlite3_bind_parameter_count(stmt) = 2)
- AND (sqlite3_bind_parameter_name(stmt, 1) = NIL)
- AND (sqlite3_bind_parameter_index(stmt, ":name") = 0);
- IF ok THEN
- Say("params="); SayInt(sqlite3_bind_parameter_count(stmt));
- Say(" index(:name)="); SayInt(sqlite3_bind_parameter_index(stmt, ":name"));
- WriteLn
- END;
- IF ok THEN
- ok := (sqlite3_bind_text(stmt, 1, "Ada", -1,
- SQLiteTransient()) = SQLiteOk)
- AND (sqlite3_bind_blob(stmt, 2, ADR(bin[0]), 3,
- SQLiteTransient()) = SQLiteOk)
- END;
- IF ok THEN ok := sqlite3_step(stmt) = SQLiteDone END;
- IF ok THEN ok := sqlite3_reset(stmt) = SQLiteOk END;
- IF ok THEN ok := sqlite3_clear_bindings(stmt) = SQLiteOk END;
- IF ok THEN
- ok := (sqlite3_bind_text(stmt, 1, "Grace", -1,
- SQLiteTransient()) = SQLiteOk)
- AND (sqlite3_bind_null(stmt, 2) = SQLiteOk)
- END;
- IF ok THEN ok := sqlite3_step(stmt) = SQLiteDone END;
- IF ok THEN ok := sqlite3_reset(stmt) = SQLiteOk END;
- IF ok THEN ok := sqlite3_clear_bindings(stmt) = SQLiteOk END;
- IF ok THEN
- ok := (sqlite3_bind_text(stmt, 1, "Blob", -1,
- SQLiteTransient()) = SQLiteOk)
- AND (sqlite3_bind_zeroblob(stmt, 2, 8) = SQLiteOk)
- END;
- IF ok THEN ok := sqlite3_step(stmt) = SQLiteDone END;
- IF ok THEN
- Say("rows inserted, changes="); SayInt(sqlite3_changes(db));
- Say(" total="); SayInt(sqlite3_total_changes(db)); WriteLn
- END;
- IF stmt # NIL THEN
- IF sqlite3_finalize(stmt) # SQLiteOk THEN ok := FALSE END;
- stmt := NIL
- END
- END;
- (* Row callback output. *)
- IF ok THEN
- SayLn("people:");
- ok := ExecCallback("SELECT rowid,name FROM people ORDER BY rowid;",
- ADR(RowPrinter))
- END;
- (* User-defined scalar function. *)
- IF ok THEN
- ok := Register("m2_add", 2, NIL, ADR(AddFn))
- AND QueryInt(db, "SELECT m2_add(20,22);", 42);
- IF ok THEN
- Say("m2_add(20,22)=42"); WriteLn
- END
- END;
- (* Statement metadata and expanded SQL. *)
- IF ok THEN
- stmt := NIL;
- rc := sqlite3_prepare_v2(db, "SELECT ?;", -1, stmt, NIL);
- ok := (rc = SQLiteOk) AND (stmt # NIL)
- AND (sqlite3_bind_int(stmt, 1, 42) = SQLiteOk);
- IF ok THEN
- Say("sql="); SayCS(sqlite3_sql(stmt));
- Say(" readonly="); SayInt(sqlite3_stmt_readonly(stmt));
- WriteLn;
- prev := sqlite3_expanded_sql(stmt);
- Say("expanded="); SayCS(prev); WriteLn;
- IF prev # NIL THEN sqlite3_free(prev); prev := NIL END
- END;
- IF ok THEN ok := sqlite3_step(stmt) = SQLiteRow END;
- IF ok THEN
- Say("busy_after_row="); SayInt(sqlite3_stmt_busy(stmt));
- Say(" vm_steps="); SayInt(sqlite3_stmt_status(stmt,
- SQLiteStmtStatusVmStep, 0)); WriteLn
- END;
- IF ok THEN ok := sqlite3_step(stmt) = SQLiteDone END;
- IF stmt # NIL THEN
- IF sqlite3_finalize(stmt) # SQLiteOk THEN ok := FALSE END;
- stmt := NIL
- END
- END;
- (* Statement iteration. *)
- IF ok THEN
- s1 := NIL; s2 := NIL;
- ok := (sqlite3_prepare_v2(db, "SELECT 1;", -1, s1, NIL) = SQLiteOk)
- AND (sqlite3_prepare_v2(db, "SELECT 2;", -1, s2, NIL) = SQLiteOk);
- IF ok THEN
- rc := 0;
- prev := sqlite3_next_stmt(db, NIL);
- WHILE prev # NIL DO
- rc := rc + 1;
- prev := sqlite3_next_stmt(db, prev)
- END;
- Say("open statements="); SayInt(rc); WriteLn;
- ok := rc = 2
- END;
- IF s1 # NIL THEN
- IF sqlite3_finalize(s1) # SQLiteOk THEN ok := FALSE END;
- s1 := NIL
- END;
- IF s2 # NIL THEN
- IF sqlite3_finalize(s2) # SQLiteOk THEN ok := FALSE END;
- s2 := NIL
- END
- END;
- (* Column BLOB metadata. *)
- IF ok THEN
- stmt := NIL;
- rc := sqlite3_prepare_v2(db,
- "SELECT data FROM people WHERE rowid=1;", -1, stmt, NIL);
- ok := (rc = SQLiteOk) AND (stmt # NIL)
- AND (sqlite3_step(stmt) = SQLiteRow)
- AND (sqlite3_column_type(stmt, 0) = SQLiteBlob)
- AND (sqlite3_column_bytes(stmt, 0) = 3)
- AND (sqlite3_column_blob(stmt, 0) # NIL);
- IF ok THEN
- Say("column BLOB bytes=3"); WriteLn
- END;
- IF stmt # NIL THEN
- IF sqlite3_finalize(stmt) # SQLiteOk THEN ok := FALSE END;
- stmt := NIL
- END
- END;
- (* Incremental BLOB round trip. *)
- IF ok THEN
- blob := NIL;
- rc := sqlite3_blob_open(db, "main", "people", "data", 3,
- SQLiteBlobReadWrite, blob);
- ok := (rc = SQLiteOk) AND (blob # NIL)
- AND (sqlite3_blob_bytes(blob) = 8)
- AND (sqlite3_blob_write(blob, ADR(bin[0]), 3, 0) = SQLiteOk)
- AND (sqlite3_blob_read(blob, ADR(out[0]), 3, 0) = SQLiteOk)
- AND SameBytes(bin, out, 3);
- IF ok THEN
- Say("incremental BLOB bytes=8 roundtrip=OK"); WriteLn
- END;
- IF blob # NIL THEN
- IF sqlite3_blob_close(blob) # SQLiteOk THEN ok := FALSE END;
- blob := NIL
- END
- END;
- (* Autocommit state. *)
- IF ok THEN
- Say("autocommit="); SayInt(sqlite3_get_autocommit(db));
- ok := ExecSQL("BEGIN;");
- IF ok THEN
- Say(" in_txn="); SayInt(sqlite3_get_autocommit(db));
- ok := ExecSQL("COMMIT;")
- END;
- IF ok THEN
- Say(" after_commit="); SayInt(sqlite3_get_autocommit(db)); WriteLn
- END
- END;
- (* Progress and trace hooks. *)
- IF ok THEN
- progressCalls := 0;
- sqlite3_progress_handler(db, 1, ADR(ProgressFn), NIL);
- ok := QueryInt(db, "SELECT count(*) FROM people;", 3)
- AND (progressCalls > 0);
- sqlite3_progress_handler(db, 0, NIL, NIL);
- Say("progress calls="); SayInt(progressCalls); WriteLn
- END;
- IF ok THEN
- traceCalls := 0;
- ok := sqlite3_trace_v2(db, SQLiteTraceStmt,
- ADR(TraceFn), NIL) = SQLiteOk;
- IF ok THEN ok := QueryInt(db, "SELECT 1;", 1) AND (traceCalls > 0) END;
- IF ok THEN ok := sqlite3_trace_v2(db, 0, NIL, NIL) = SQLiteOk END;
- Say("trace calls="); SayInt(traceCalls); WriteLn
- END;
- (* Update / commit / rollback hooks. *)
- IF ok THEN
- updateCalls := 0;
- prev := sqlite3_update_hook(db, ADR(UpdateFn), NIL);
- ok := ExecSQL("INSERT INTO hook(v) VALUES('a');")
- AND ExecSQL("UPDATE hook SET v='b' WHERE id=1;")
- AND ExecSQL("DELETE FROM hook WHERE id=1;")
- AND (updateCalls = 3);
- prev := sqlite3_update_hook(db, NIL, NIL);
- Say("update events="); SayInt(updateCalls); WriteLn
- END;
- IF ok THEN
- commitCalls := 0; rollbackCalls := 0;
- prev := sqlite3_commit_hook(db, ADR(CommitFn), NIL);
- sqlite3_rollback_hook(db, ADR(RollbackFn), NIL);
- ok := ExecSQL("BEGIN; INSERT INTO hook(v) VALUES('c'); COMMIT;")
- AND (commitCalls = 1)
- AND ExecSQL("BEGIN; INSERT INTO hook(v) VALUES('d'); ROLLBACK;")
- AND (rollbackCalls = 1);
- prev := sqlite3_commit_hook(db, NIL, NIL);
- sqlite3_rollback_hook(db, NIL, NIL);
- Say("commit="); SayInt(commitCalls);
- Say(" rollback="); SayInt(rollbackCalls); WriteLn
- END;
- (* Authorizer denies DELETE. *)
- IF ok THEN
- authCalls := 0;
- ok := sqlite3_set_authorizer(db, ADR(AuthFn), NIL) = SQLiteOk;
- IF ok THEN
- prev := NIL;
- rc := sqlite3_exec(db, "DELETE FROM hook;", NIL, NIL, prev);
- IF prev # NIL THEN sqlite3_free(prev); prev := NIL END;
- ok := (rc = SQLiteAuth) AND (authCalls > 0);
- Say("authorizer delete rc="); SayInt(rc); WriteLn
- END;
- IF sqlite3_set_authorizer(db, NIL, NIL) # SQLiteOk THEN ok := FALSE END
- END;
- (* Constraint error and errmsg ownership. *)
- IF ok THEN
- ok := ExecSQL("CREATE TABLE u(v TEXT UNIQUE);")
- AND ExecSQL("INSERT INTO u VALUES('x');");
- IF ok THEN
- prev := NIL;
- rc := sqlite3_exec(db, "INSERT INTO u VALUES('x');", NIL, NIL, prev);
- ok := (rc # SQLiteOk) AND (sqlite3_extended_errcode(db) = 2067);
- Say("constraint rc="); SayInt(rc);
- Say(" msg="); SayCS(prev); WriteLn;
- IF prev # NIL THEN sqlite3_free(prev); prev := NIL END
- END
- END;
- (* Online backup. *)
- IF ok THEN
- ok := OpenMemory(dst);
- IF ok THEN
- bk := sqlite3_backup_init(dst, "main", db, "main");
- ok := bk # NIL;
- IF ok THEN
- ok := sqlite3_backup_step(bk, -1) = SQLiteDone;
- IF ok THEN
- pages := sqlite3_backup_pagecount(bk);
- remaining := sqlite3_backup_remaining(bk);
- ok := (pages > 0) AND (remaining = 0)
- END;
- IF sqlite3_backup_finish(bk) # SQLiteOk THEN ok := FALSE END;
- bk := NIL
- END
- END;
- IF ok THEN
- ok := QueryInt(dst, "SELECT count(*) FROM people;", 3);
- Say("backup pages="); SayInt(pages);
- Say(" remaining="); SayInt(remaining); WriteLn
- END
- END;
- (* Close status and cleanup. *)
- IF ok THEN
- stmt := NIL;
- rc := sqlite3_prepare_v2(db, "SELECT 1;", -1, stmt, NIL);
- ok := (rc = SQLiteOk) AND (stmt # NIL);
- IF ok THEN
- rc := sqlite3_close(db);
- Say("close with statement="); SayInt(rc); WriteLn;
- ok := rc = SQLiteBusy
- END;
- IF stmt # NIL THEN
- IF sqlite3_finalize(stmt) # SQLiteOk THEN ok := FALSE END;
- stmt := NIL
- END
- END;
- IF blob # NIL THEN
- IF sqlite3_blob_close(blob) # SQLiteOk THEN ok := FALSE END
- END;
- IF bk # NIL THEN
- IF sqlite3_backup_finish(bk) # SQLiteOk THEN ok := FALSE END
- END;
- IF dst # NIL THEN
- IF sqlite3_close_v2(dst) # SQLiteOk THEN ok := FALSE END
- END;
- IF db # NIL THEN
- IF sqlite3_close(db) # SQLiteOk THEN ok := FALSE END
- END;
- IF ok THEN
- SayLn("done");
- ExitCode := 42
- ELSE
- SayLn("FAIL")
- END
- END SQLiteFeatureShowcase.
|