michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: importScripts("worker_sqlite_shared.js", michael@0: "resource://gre/modules/workers/require.js"); michael@0: michael@0: self.onmessage = function onmessage(msg) { michael@0: try { michael@0: run_test(); michael@0: } catch (ex) { michael@0: let {message, moduleStack, moduleName, lineNumber} = ex; michael@0: let error = new Error(message, moduleName, lineNumber); michael@0: error.stack = moduleStack; michael@0: dump("Uncaught error: " + error + "\n"); michael@0: dump("Full stack: " + moduleStack + "\n"); michael@0: throw error; michael@0: } michael@0: }; michael@0: michael@0: let Sqlite; michael@0: michael@0: let SQLITE_OK; /* Successful result */ michael@0: let SQLITE_ROW; /* sqlite3_step() has another row ready */ michael@0: let SQLITE_DONE; /* sqlite3_step() has finished executing */ michael@0: michael@0: function test_init() { michael@0: do_print("Starting test_init"); michael@0: // Sqlite should be loaded. michael@0: Sqlite = require("resource://gre/modules/sqlite/sqlite_internal.js"); michael@0: do_check_neq(typeof Sqlite, "undefined"); michael@0: do_check_neq(typeof Sqlite.Constants, "undefined"); michael@0: SQLITE_OK = Sqlite.Constants.SQLITE_OK; michael@0: SQLITE_ROW = Sqlite.Constants.SQLITE_ROW; michael@0: SQLITE_DONE = Sqlite.Constants.SQLITE_DONE; michael@0: } michael@0: michael@0: /** michael@0: * Clean up the database. michael@0: * @param {sqlite3_ptr} db A pointer to the database. michael@0: */ michael@0: function cleanupDB(db) { michael@0: withQuery(db, "DROP TABLE IF EXISTS TEST;", SQLITE_DONE); michael@0: } michael@0: michael@0: /** michael@0: * Open and close sqlite3 database. michael@0: * @param {String} open A name of the sqlite3 open function to be michael@0: * used. michael@0: * @param {Array} openArgs = [] Optional arguments to open function. michael@0: * @param {Function} callback = null An optional callback to be run after the michael@0: * database is opened but before it is michael@0: * closed. michael@0: */ michael@0: function withDB(open, openArgs = [], callback = null) { michael@0: let db = Sqlite.Type.sqlite3_ptr.implementation(); michael@0: let dbPtr = db.address(); michael@0: michael@0: // Open database. michael@0: let result = Sqlite[open].apply(Sqlite, ["data/test.db", dbPtr].concat( michael@0: openArgs)); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: // Drop the test table if it already exists. michael@0: cleanupDB(db); michael@0: michael@0: try { michael@0: if (callback) { michael@0: callback(db); michael@0: } michael@0: } catch (ex) { michael@0: do_check_true(false); michael@0: throw ex; michael@0: } finally { michael@0: // Drop the test table if it still exists. michael@0: cleanupDB(db); michael@0: // Close data base. michael@0: result = Sqlite.close(db); michael@0: do_check_eq(result, SQLITE_OK); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Execute an SQL query using sqlite3 API. michael@0: * @param {sqlite3_ptr} db A pointer to the database. michael@0: * @param {String} sql A SQL query string. michael@0: * @param {Number} stepResult Expected result code after evaluating the michael@0: * SQL statement. michael@0: * @param {Function} bind An optional callback with SQL binding steps. michael@0: * @param {Function} callback An optional callback that runs after the SQL michael@0: * query completes. michael@0: */ michael@0: function withQuery(db, sql, stepResult, bind, callback) { michael@0: // Create an instance of a single SQL statement. michael@0: let sqlStmt = Sqlite.Type.sqlite3_stmt_ptr.implementation(); michael@0: let sqlStmtPtr = sqlStmt.address(); michael@0: michael@0: // Unused portion of an SQL query. michael@0: let unused = Sqlite.Type.cstring.implementation(); michael@0: let unusedPtr = unused.address(); michael@0: michael@0: // Compile an SQL statement. michael@0: let result = Sqlite.prepare_v2(db, sql, sql.length, sqlStmtPtr, unusedPtr); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: try { michael@0: if (bind) { michael@0: bind(sqlStmt); michael@0: } michael@0: michael@0: // Evaluate an SQL statement. michael@0: result = Sqlite.step(sqlStmt); michael@0: do_check_eq(result, stepResult); michael@0: michael@0: if (callback) { michael@0: callback(sqlStmt); michael@0: } michael@0: } catch (ex) { michael@0: do_check_true(false); michael@0: throw ex; michael@0: } finally { michael@0: // Destroy a prepared statement object. michael@0: result = Sqlite.finalize(sqlStmt); michael@0: do_check_eq(result, SQLITE_OK); michael@0: } michael@0: } michael@0: michael@0: function test_open_close() { michael@0: do_print("Starting test_open_close"); michael@0: do_check_eq(typeof Sqlite.open, "function"); michael@0: do_check_eq(typeof Sqlite.close, "function"); michael@0: michael@0: withDB("open"); michael@0: } michael@0: michael@0: function test_open_v2_close() { michael@0: do_print("Starting test_open_v2_close"); michael@0: do_check_eq(typeof Sqlite.open_v2, "function"); michael@0: michael@0: withDB("open_v2", [0x02, null]); michael@0: } michael@0: michael@0: function createTableOnOpen(db) { michael@0: withQuery(db, "CREATE TABLE TEST(" + michael@0: "ID INT PRIMARY KEY NOT NULL," + michael@0: "FIELD1 INT," + michael@0: "FIELD2 REAL," + michael@0: "FIELD3 TEXT," + michael@0: "FIELD4 TEXT," + michael@0: "FIELD5 BLOB" + michael@0: ");", SQLITE_DONE); michael@0: } michael@0: michael@0: function test_create_table() { michael@0: do_print("Starting test_create_table"); michael@0: do_check_eq(typeof Sqlite.prepare_v2, "function"); michael@0: do_check_eq(typeof Sqlite.step, "function"); michael@0: do_check_eq(typeof Sqlite.finalize, "function"); michael@0: michael@0: withDB("open", [], createTableOnOpen); michael@0: } michael@0: michael@0: /** michael@0: * Read column values after evaluating the SQL SELECT statement. michael@0: * @param {sqlite3_stmt_ptr} sqlStmt A pointer to the SQL statement. michael@0: */ michael@0: function onSqlite3Step(sqlStmt) { michael@0: // Get an int value from a query result from the ID (column 0). michael@0: let field = Sqlite.column_int(sqlStmt, 0); michael@0: do_check_eq(field, 3); michael@0: michael@0: // Get an int value from a query result from the column 1. michael@0: field = Sqlite.column_int(sqlStmt, 1); michael@0: do_check_eq(field, 2); michael@0: // Get an int64 value from a query result from the column 1. michael@0: field = Sqlite.column_int64(sqlStmt, 1); michael@0: do_check_eq(field, 2); michael@0: michael@0: // Get a double value from a query result from the column 2. michael@0: field = Sqlite.column_double(sqlStmt, 2); michael@0: do_check_eq(field, 1.2); michael@0: michael@0: // Get a number of bytes of the value in the column 3. michael@0: let bytes = Sqlite.column_bytes(sqlStmt, 3); michael@0: do_check_eq(bytes, 4); michael@0: // Get a text(cstring) value from a query result from the column 3. michael@0: field = Sqlite.column_text(sqlStmt, 3); michael@0: do_check_eq(field.readString(), "DATA"); michael@0: michael@0: // Get a number of bytes of the UTF-16 value in the column 4. michael@0: bytes = Sqlite.column_bytes16(sqlStmt, 4); michael@0: do_check_eq(bytes, 8); michael@0: // Get a text16(wstring) value from a query result from the column 4. michael@0: field = Sqlite.column_text16(sqlStmt, 4); michael@0: do_check_eq(field.readString(), "TADA"); michael@0: michael@0: // Get a blob value from a query result from the column 5. michael@0: field = Sqlite.column_blob(sqlStmt, 5); michael@0: do_check_eq(ctypes.cast(field, michael@0: Sqlite.Type.cstring.implementation).readString(), "BLOB"); michael@0: } michael@0: michael@0: function test_insert_select() { michael@0: do_print("Starting test_insert_select"); michael@0: do_check_eq(typeof Sqlite.column_int, "function"); michael@0: do_check_eq(typeof Sqlite.column_int64, "function"); michael@0: do_check_eq(typeof Sqlite.column_double, "function"); michael@0: do_check_eq(typeof Sqlite.column_bytes, "function"); michael@0: do_check_eq(typeof Sqlite.column_text, "function"); michael@0: do_check_eq(typeof Sqlite.column_text16, "function"); michael@0: do_check_eq(typeof Sqlite.column_blob, "function"); michael@0: michael@0: function onOpen(db) { michael@0: createTableOnOpen(db); michael@0: withQuery(db, michael@0: "INSERT INTO TEST VALUES (3, 2, 1.2, \"DATA\", \"TADA\", \"BLOB\");", michael@0: SQLITE_DONE); michael@0: withQuery(db, "SELECT * FROM TEST;", SQLITE_ROW, null, onSqlite3Step); michael@0: } michael@0: michael@0: withDB("open", [], onOpen); michael@0: } michael@0: michael@0: function test_insert_bind_select() { michael@0: do_print("Starting test_insert_bind_select"); michael@0: do_check_eq(typeof Sqlite.bind_int, "function"); michael@0: do_check_eq(typeof Sqlite.bind_int64, "function"); michael@0: do_check_eq(typeof Sqlite.bind_double, "function"); michael@0: do_check_eq(typeof Sqlite.bind_text, "function"); michael@0: do_check_eq(typeof Sqlite.bind_text16, "function"); michael@0: do_check_eq(typeof Sqlite.bind_blob, "function"); michael@0: michael@0: function onBind(sqlStmt) { michael@0: // Bind an int value to the ID (column 0). michael@0: let result = Sqlite.bind_int(sqlStmt, 1, 3); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: // Bind an int64 value to the FIELD1 (column 1). michael@0: result = Sqlite.bind_int64(sqlStmt, 2, 2); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: // Bind a double value to the FIELD2 (column 2). michael@0: result = Sqlite.bind_double(sqlStmt, 3, 1.2); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: // Destructor. michael@0: let destructor = Sqlite.Constants.SQLITE_TRANSIENT; michael@0: // Bind a text value to the FIELD3 (column 3). michael@0: result = Sqlite.bind_text(sqlStmt, 4, "DATA", 4, destructor); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: // Bind a text16 value to the FIELD4 (column 4). michael@0: result = Sqlite.bind_text16(sqlStmt, 5, "TADA", 8, destructor); michael@0: do_check_eq(result, SQLITE_OK); michael@0: michael@0: // Bind a blob value to the FIELD5 (column 5). michael@0: result = Sqlite.bind_blob(sqlStmt, 6, ctypes.char.array()("BLOB"), 4, michael@0: destructor); michael@0: do_check_eq(result, SQLITE_OK); michael@0: } michael@0: michael@0: function onOpen(db) { michael@0: createTableOnOpen(db); michael@0: withQuery(db, "INSERT INTO TEST VALUES (?, ?, ?, ?, ?, ?);", SQLITE_DONE, michael@0: onBind); michael@0: withQuery(db, "SELECT * FROM TEST;", SQLITE_ROW, null, onSqlite3Step); michael@0: } michael@0: michael@0: withDB("open", [], onOpen); michael@0: } michael@0: michael@0: function run_test() { michael@0: test_init(); michael@0: test_open_close(); michael@0: test_open_v2_close(); michael@0: test_create_table(); michael@0: test_insert_select(); michael@0: test_insert_bind_select(); michael@0: do_test_complete(); michael@0: }