diff options
Diffstat (limited to 'javascripts/libs/browser_engines/websql_driver.js')
-rw-r--r-- | javascripts/libs/browser_engines/websql_driver.js | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/javascripts/libs/browser_engines/websql_driver.js b/javascripts/libs/browser_engines/websql_driver.js new file mode 100644 index 0000000..2795b6c --- /dev/null +++ b/javascripts/libs/browser_engines/websql_driver.js @@ -0,0 +1,268 @@ +window.WebSQL_driver = function(){ + this.db = null; + this.ddl = []; + this.nativeSQLite = (window.openDatabase !== undefined); + return this; +}; + +$.extend(window.WebSQL_driver.prototype,window.SQLite_driver.prototype); // inherit from parent class + +window.WebSQL_driver.prototype.buildSchema = function (args) { + + var _this = this; // preserve reference to current object through local closures + + try { + + if (_this.nativeSQLite) + { + _this.db = openDatabase(args["short_code"], '1.0', args["short_code"], args["ddl"].length * 1024); + + _this.db.transaction(function(tx){ + + var statements = _this.splitStatement(args["ddl"],args["statement_separator"]); + _this.ddl = statements; + + var currentStatement = 0; + var statement = statements[currentStatement]; + + var sequentiallyExecute = function(tx2, result){ + if (currentStatement < statements.length-1) + { + do { + currentStatement++; + statement = statements[currentStatement]; + } while (currentStatement < statements.length-1 && statement.match(/^\s*$/)); + + if (!statement.match(/^\s*$/)) { + tx.executeSql(statement, [], sequentiallyExecute, handleFailure); + } + else + { + tx.executeSql("intentional failure used to rollback transaction"); + args["success"](); + } + + } + else + { + tx.executeSql("intentional failure used to rollback transaction"); + args["success"](); + } + }; + + var handleFailure = function (tx2, result) { + if (result.message != "not an error") // thank you safari, for this + { + args["error"](result.message); + } + else + { + args["success"](); + } + + return true; // roll back transaction + }; + + if (statement) { + tx.executeSql(statement, [], sequentiallyExecute, handleFailure); + } + else { + args["success"](); + } + }); + + } + else + { + args["error"]("SQLite (WebSQL) not available in your browser. Try either using a webkit-based browser (such as Safari or Chrome) or using the SQLite (SQL.js) database type.") + } + + } + catch (e) + { + args["error"](e); + } + + } + + +window.WebSQL_driver.prototype.executeQuery = function (args) { + + var _this = this; // preserve reference to current object through local closures + + try { + + if (_this.db == null ) { + throw("You need to build the schema before you can run a query."); + } + + var returnSets = []; + + _this.db.transaction(function(tx){ + + var sequentiallyExecute = function(tx2, result) { + + var thisSet = { + "SUCCEEDED": true, + "EXECUTIONTIME": (new Date()) - startTime, + "RESULTS": { + "COLUMNS": [], + "DATA": [] + }, + "EXECUTIONPLAN": { + "COLUMNS": [], + "DATA": [] + } + + }; + + for (var i = 0; i < result.rows.length; i++) { + var rowVals = []; + var item = result.rows.item(i); + + /* We can't be sure about the order of the columns returned, since they are returned as + * a simple unordered structure. So, we'll just take the order returned the from the first + * request, then just use that order for each row. + */ + if (i == 0) { + for (col in item) { + thisSet["RESULTS"]["COLUMNS"].push(col); + } + } + + for (var j = 0; j < thisSet["RESULTS"]["COLUMNS"].length; j++) { + rowVals.push(item[thisSet["RESULTS"]["COLUMNS"][j]]); + } + + thisSet["RESULTS"]["DATA"].push(rowVals); + } + + tx.executeSql("EXPLAIN QUERY PLAN " + statement, [], function (tx3, executionPlanResult) { + + for (var l = 0; l < executionPlanResult.rows.length; l++) { + var rowVals = []; + var item = executionPlanResult.rows.item(l); + + /* We can't be sure about the order of the columns returned, since they are returned as + * a simple unordered structure. So, we'll just take the order returned the from the first + * request, then just use that order for each row. + */ + if (l == 0) { + for (col in item) { + thisSet["EXECUTIONPLAN"]["COLUMNS"].push(col); + } + } + + for (var j = 0; j < thisSet["EXECUTIONPLAN"]["COLUMNS"].length; j++) { + rowVals.push(item[thisSet["EXECUTIONPLAN"]["COLUMNS"][j]]); + } + + thisSet["EXECUTIONPLAN"]["DATA"].push(rowVals); + } + + if (currentStatement > _this.ddl.length-1) + returnSets.push(thisSet); + + // executeSQL runs asynchronously, so we have to make recursive calls to handle subsequent queries in order. + if (currentStatement < (statements.length - 1)) + { + do { + currentStatement++; + statement = statements[currentStatement]; + } while (currentStatement < statements.length-1 && statement.match(/^\s*$/)); + + if (! statement.match(/^\s*$/)) + tx.executeSql(statement, [], sequentiallyExecute, handleFailure); + else + { + tx.executeSql("intentional failure used to rollback transaction"); + args["success"](returnSets); + } + + } + else + { + tx.executeSql("intentional failure used to rollback transaction"); + args["success"](returnSets); + } + + + }, + function(tx3, executionPlanResult){ + // if the explain failed, then just append the base set to the result and move on.... + + if (currentStatement > _this.ddl.length-1) + returnSets.push(thisSet); + + // executeSQL runs asynchronously, so we have to make recursive calls to handle subsequent queries in order. + if (currentStatement < (statements.length - 1)) + { + do { + currentStatement++; + statement = statements[currentStatement]; + } while (currentStatement < statements.length-1 && statement.match(/^\s*$/)); + + if (! statement.match(/^\s*$/)) + tx.executeSql(statement, [], sequentiallyExecute, handleFailure); + else + { + tx.executeSql("intentional failure used to rollback transaction"); + args["success"](returnSets); + } + } + else + { + tx.executeSql("intentional failure used to rollback transaction"); + args["success"](returnSets); + } + + + }); + + } + + var handleFailure = function (tx, result) { + if (result.message != "not an error") // thank you safari, for this + { + var thisSet = { + "SUCCEEDED": false, + "EXECUTIONTIME": (new Date()) - startTime, + "ERRORMESSAGE": result.message + }; + returnSets.push(thisSet); + } + + args["success"](returnSets); // 'success' - slightly confusing here, but in this context a failed query is still a valid result from the database + return true; // roll back transaction + } + + var setArray = [], k, stop = false; + + var statements = _this.ddl.slice(0); + + $.each(_this.splitStatement(args["sql"],args["statement_separator"]), function (i, stmt) { statements.push(stmt); }); + + var currentStatement = 0; + var statement = statements[currentStatement]; + + var startTime = new Date(); + + /* + * executeSql runs asynchronously, so I impose a semblance of synchronous-ness via recusive calls + */ + tx.executeSql(statement, [], sequentiallyExecute, handleFailure); + + + + }); + + } + catch (e) + { + args["error"](e); + } + + + } + + |