MODULE SQLiteBlobErrors; (* BLOB error paths: read-only writes, bounds, invalid opens and expired handles. *) FROM SYSTEM IMPORT ADDRESS, ADR; FROM SQLite IMPORT SQLiteOk, SQLiteError, SQLiteReadOnly, SQLiteAbort, SQLiteBlobReadOnly, SQLiteBlobReadWrite, SQLiteOpenReadWrite, SQLiteOpenCreate, SQLiteOpenMemory, sqlite3_open_v2, sqlite3_exec, sqlite3_close_v2, sqlite3_blob_open, sqlite3_blob_close, sqlite3_blob_read, sqlite3_blob_write, sqlite3_free; VAR ExitCode : INTEGER; db, blob : ADDRESS; rc : INTEGER; ok : BOOLEAN; buf : ARRAY [0..7] OF CHAR; 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 CloseBlob (VAR b : ADDRESS; want : INTEGER) : BOOLEAN; VAR got : INTEGER; BEGIN IF b = NIL THEN RETURN FALSE END; got := sqlite3_blob_close(b); b := NIL; RETURN got = want END CloseBlob; BEGIN ExitCode := 1; db := NIL; blob := NIL; ok := FALSE; buf[0] := 'X'; buf[1] := 'Y'; IF (sqlite3_open_v2(":memory:", db, SQLiteOpenReadWrite + SQLiteOpenCreate + SQLiteOpenMemory, NIL) = SQLiteOk) AND (db # NIL) THEN IF ExecSQL("CREATE TABLE b(id INTEGER PRIMARY KEY, data BLOB);") AND ExecSQL("INSERT INTO b(data) VALUES(zeroblob(4));") AND ExecSQL("INSERT INTO b(data) VALUES(zeroblob(4));") THEN ok := TRUE END END; (* Flags 0 = read-only; a write must fail and remain pending at close. *) IF ok THEN rc := sqlite3_blob_open(db, "main", "b", "data", 1, SQLiteBlobReadOnly, blob); ok := (rc = SQLiteOk) AND (blob # NIL) END; IF ok THEN ok := sqlite3_blob_write(blob, ADR(buf[0]), 1, 0) = SQLiteReadOnly END; IF NOT CloseBlob(blob, SQLiteReadOnly) THEN ok := FALSE END; (* Bounds checks on a read-write handle. *) IF ok THEN rc := sqlite3_blob_open(db, "main", "b", "data", 1, SQLiteBlobReadWrite, blob); ok := (rc = SQLiteOk) AND (blob # NIL) END; IF ok THEN ok := sqlite3_blob_read(blob, ADR(buf[0]), 2, 3) = SQLiteError END; IF ok THEN ok := sqlite3_blob_write(blob, ADR(buf[0]), 2, 3) = SQLiteError END; IF ok THEN ok := sqlite3_blob_read(blob, ADR(buf[0]), 1, -1) = SQLiteError END; IF ok THEN ok := sqlite3_blob_write(blob, ADR(buf[0]), 1, -1) = SQLiteError END; IF NOT CloseBlob(blob, SQLiteOk) THEN ok := FALSE END; (* Invalid row/table/column and a non-BLOB column. *) IF ok THEN rc := sqlite3_blob_open(db, "main", "b", "data", 99, SQLiteBlobReadOnly, blob); ok := (rc # SQLiteOk) AND (blob = NIL) END; IF ok THEN rc := sqlite3_blob_open(db, "main", "b", "nope", 1, SQLiteBlobReadOnly, blob); ok := (rc # SQLiteOk) AND (blob = NIL) END; IF ok THEN rc := sqlite3_blob_open(db, "main", "nope", "data", 1, SQLiteBlobReadOnly, blob); ok := (rc # SQLiteOk) AND (blob = NIL) END; IF ok THEN rc := sqlite3_blob_open(db, "main", "b", "id", 1, SQLiteBlobReadOnly, blob); ok := (rc # SQLiteOk) AND (blob = NIL) END; (* An UPDATE expires an open BLOB handle. *) IF ok THEN rc := sqlite3_blob_open(db, "main", "b", "data", 2, SQLiteBlobReadWrite, blob); ok := (rc = SQLiteOk) AND (blob # NIL) END; IF ok THEN ok := sqlite3_blob_read(blob, ADR(buf[0]), 1, 0) = SQLiteOk END; IF ok THEN ok := ExecSQL("UPDATE b SET data = zeroblob(4) WHERE id = 2;") END; IF ok THEN ok := sqlite3_blob_read(blob, ADR(buf[0]), 1, 0) = SQLiteAbort END; IF NOT CloseBlob(blob, SQLiteOk) THEN ok := FALSE END; IF db # NIL THEN IF sqlite3_close_v2(db) # SQLiteOk THEN ok := FALSE END END; IF ok THEN ExitCode := 42 END END SQLiteBlobErrors.