summaryrefslogtreecommitdiffstats
path: root/javascripts/libs/browser_engines/websql_driver.js
diff options
context:
space:
mode:
Diffstat (limited to 'javascripts/libs/browser_engines/websql_driver.js')
-rw-r--r--javascripts/libs/browser_engines/websql_driver.js268
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);
+ }
+
+
+ }
+
+