winjs sqlite database is locked

0

I use in a Windows 8 project (js/html) the SQLite3-WinRT library https://github.com/doo/SQLite3-WinRT.
I create a function that is called in a for loop. I have this error:

SQLiteError: 0x800700aa: eachAsync("INSERT INTO home (id, url, cksum)VALUES (16, 'main_page_2.jpg', 'e0d046ca3421a3c2df328b293ad5981a');", ) database is locked

I think the error is because I create a new connection every iteration of loop, but I don't understand another method. Who can help me?

This is the function:

function insertInDB(dbPath, tbName, arrayCol, arrayVal) {
SQLite3JS.openAsync(dbPath).then(function (db) {
var query = "INSERT INTO " + tbName;
var column = " (";
var values = "VALUES (";
for (var i = 0; i < arrayCol.length; i++) {
if (i == arrayCol.length - 1) {
column = column + arrayCol[i] + ")";
} else {
column = column + arrayCol[i] + ", ";
}
}
for (var i = 0; i < arrayVal.length; i++) {
if (i == arrayCol.length - 1) {
values = values + arrayVal[i] + ");";
} else {
values = values + arrayVal[i] + ", ";
}
}
query = query + column + values;
return db.eachAsync(query).done(function () {
console.log("Ok");
db.close();
},
function (error) { console.log(error); },
function (progress) { });
});
}

and this is the loop that call a previous function:

listHome.forEach(function(value, index, array){
var valconfig = new Array(value.id, "'" + value.url + "'", "'" + value.cksum + "'");
console.log("id=" + value.id + " url=" + value.url + " ck=" + value.cksum);

                    insertInDB(sqlPath, "home", colconfig, valconfig);   
                })    
sqlite
windows-runtime
winjs
asked on Stack Overflow Jan 24, 2014 by user3231894 • edited Jan 24, 2014 by Eric Schmidt

1 Answer

0

If I'm reading this correctly, your calling code is iterating over a list of values synchronously. listHome.forEach will call insertInDB for each item in listHome ... but it doesn't wait for insertInDB to return before making the next call to insertInDB.

Inside insertInDB you have call to SQLite3JS.openAsync and db.eachAsync - both asynchronous methods. After perusing SQLite3JS a little bit (which looks pretty cool), both of those methods return promises, where internally they call into a WinRT component. Great design.

So this is what I suspect is happening: one of the asynchronous calls in insertInDB puts a lock on the database. However, insertInDB returns control back to the listHome.forEach loop as soon as it hits the first asynchronous method call. If the lock on the database remains once forEach gets to the next item in listHome, then the operation will attempt to write to a locked database. Hence the error.

I'll think about this a little bit and see if I can come up with a solution.

-- edit --

Okay, I have a solution that might work for you. You might want to create a "DataBaseHelper" class that will queue up the transactions that you need to make in the database.

Here's a rough prototype that I threw together:

[Replaces your foreach loop]

DBHelper.queueUpdates(listHome);

[DBHelper module definition]

(function () {

    var _queue;

    function queueUpdates(array) {        
        _queue = array;
        scheduleUpdates();
    }

    function scheduleUpdates() {
        if (_queue.length > 0) {
            var transaction = _queue.pop();
            insertInDB("path", "table", "column", transaction);
        }
    }

    function insertInDB(dbPath, tbName, arrayCol, arrayVal) {
        return SQLite3JS.openAsync(dbPath).then(function (db) {

            // Construct your SQL query ...

            return db.eachAsync(query).done(function () {
                db.close();
                scheduleUpdates();
            },
            function (error) { console.log(error); },
            function (progress) { });
        });
    }

    WinJS.Namespace.define("DBHelper", {
        queueUpdates: queueUpdates
    })
})();
answered on Stack Overflow Jan 24, 2014 by Eric Schmidt • edited Jan 24, 2014 by Eric Schmidt

User contributions licensed under CC BY-SA 3.0