|
@@ -0,0 +1,133 @@
|
|
|
|
|
+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.
|