I am using Sqlite.jsm otherwise (which uses mozIStorageAsyncConnection internally (mostly the same interface as mozIStorageConnection (eg.: it also has a createFunction() method))). This is just to see whether I could create udfs or not, and if yes, then measure their speed versus processing values after they have been fetched from SQLite; but it’s neither here, nor there.
I was using the function constructor, because I couldn’t get it working with function expressions, and then I saw that sqlitemanager uses the constructor version, so I thought maybe there is some quirk at work here, so I tried that as well, but I cannot get it working either way.
I have set up the following basic example (which still does not work with udfs (but works with other statements like ‘SELECT 1’, etc)):
test.xul:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin/"?>
<window id="udf-test" title="UDF test" orient="vertical" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://path/to/test.js"/>
<button label="UDF!" oncommand="udfTest.test();"/>
</window>
test.js:
var udfTest = (function() {
const Cu = Components.utils;
const utils = {};
Cu.import('resource://gre/modules/Services.jsm', utils);
Cu.import('resource://gre/modules/FileUtils.jsm', utils);
var main = {
test: function test() {
var filePath,
dbConn,
stmt;
try {
filePath = '/path/to/test.sqlite';
dbConn = utils.Services.storage.openDatabase(
new utils.FileUtils.File(filePath)
);
dbConn.createFunction('joinValues', -1, function (aValues) {
var valArr = [];
for (var j = 0; j < aValues.numEntries; j++) {
switch (aValues.getTypeOfIndex(j)) {
case 0: //NULL
valArr.push(null);
break;
case 1: //INTEGER
valArr.push(aValues.getInt64(j));
break;
case 2: //REAL
valArr.push(aValues.getDouble(j));
break;
case 3: //TEXT
default:
valArr.push(aValues.getString(j));
}
}
return valArr.join(',');
});
stmt = dbConn.createStatement('SELECT joinValues(1, 2, 3) as result');
stmt.executeAsync({
handleResult: function(aResultSet) {
for (let row = aResultSet.getNextRow();
row;
row = aResultSet.getNextRow()) {
let value = row.getResultByName("result");
console.log('result', value);
}
},
handleError: function(aError) {
console.log("Error: " + aError.message);
dbConn.asyncClose(function() {
console.log('dbConn closed');
});
},
handleCompletion: function(aReason) {
if (aReason != Components.interfaces.mozIStorageStatementCallback.REASON_FINISHED) {
console.log("Query canceled or aborted!");
}
dbConn.asyncClose(function() {
console.log('dbConn closed');
});
}
});
}
catch (ex) {
console.log(ex);
dbConn.asyncClose(function() {
console.log('dbConn closed');
});
}
}
};
return {
test: main.test.bind(main)
}
})();
I have copied the joinValues function from sqlitemanager (where it works as expected). With this setup, as soon as I press the button, firefox crashes. I still don’t understand why it is not working, or how could I get more information about why it is not working. It is just frustrating.
Edit:
The statement gets prepared (if I don’t create the function beforehand, then createStatement throws, otherwise it does not). The crash happens when I try to execute the statement.
Edit 2:
It seems like statements with udfs only work with synchronous execution : (
Both mozIStorageConnection.executeAsync() and mozIStorageStatement.executeAsync() (and mozIStorageConnection.executeSimpleSQL() as well) crashes, when the statement contains udfs; only mozIStorageStatement.executeStep() seems to work with udfs. Should I report it as a bug?