You are on page 1of 6

HTML5 databases and local storage, iPhone and iPad

HTML5 database storage works fairly good on the devices (tested on iPhone 3G and iPad). Default storage limit is 5MB, even if default is set to less it will go over that limit to 5MB, then the user will be prompted if 5MB is reached. Tested on iPhone 3G: maximum limit was 5MB, then a quota exceeded error was received Tested on iPad 1: once 5MB were reached the user was prompted every time more space was needed, up to 50MB. Then a quota exceeded error was received Error cases that are transmitted by the db are easy to handle, also simple cases can be treated from the resultSet (like trying to delete when there are no more items) even if no particular error is sent following the transaction. Operations can become a bit slow on very large data, use the callback methods - error and success - in order to be very particular and react correctly exactly when a transaction ends, not while its still ongoing (database storage is asynchronous). Group as many operations needed to succeed together into one big transaction this way, if anything goes wrong, everything will be reverted to a stable state before the transaction. Pros: SQL Is great for data mining, searching, sorting, and aggregating Cons: Requires quite a bit of code to do simple things May get tricky when trying to nest asynchronous code (be careful with callbacks) Storage space comparison Example [10+1(id autoincrement) columns x 100 rows]: Integer (999999999): Safari5 14KB, iPhone 16KB, iPad 32KB Float (999999999.999999999): Safari5 14KB, iPhone 16KB, iPad 32KB Text (999999999.999999999) : Safari5 58KB, iPhone 52KB, iPad 68KB Example [1+1(id autoincrement) columns x 1 row]: Text of 100KB size on disk: Safari5: 198KB, iPhone: 200KB, iPad: 212KB Text of 1MB size on disk: Safari5: 2MB, iPhone: 2MB, iPad: 2MB Example [1+1(id autoincrement) columns x 10 rows]: Text of 100KB size on disk: Safari5: 1.9MB, iPhone: 1.9MB, iPad: 1.9MB

Key-value local storage is also a good alternative for smaller amounts of data that need persistence (for non-persistent use key-value session storage). JSON can be inserted in the value part using stringify. The limit for local storage is also 5MB. Once this is exceeded a QUOTA_EXCEEDED_ERR exception will be thrown. There are no limits for the size that can be stored in the value part (as much as the quota allows). One can use up the entire space in just one key-value pair. Pros: Very easy to use and memorize the API Synchronous API (no callback needed) Cons: Objects must be serialized, potential performance impact of JSON serialization / deserialization Not nearly as powerful as SQL, which can sort, search and aggregate data much easier Storage space comparison: http://arty.name/localstorage.html Safari5, iPad: 2600k - 2700k characters iPhone 3G: crashed

HTML5 database - basic operations


Initialize database:
var systemDB;
function initDB() { try { if (!window.openDatabase) { alert('Database support not present'); } else { var shortName = 'jsondb'; var version = '1.0'; var displayName = 'JSON Database'; var maxSize = 5*1024*1024; // in bytes var myDB = openDatabase(shortName, version, displayName, maxSize); } } catch(e) { // Error handling code goes here. if (e == INVALID_STATE_ERR) { // Version number mismatch. alert("Invalid database version."); } else { alert("Unknown error "+e+"."); } return; } createTables(myDB); systemDB = myDB; }

Create tables:
function createTables() { var myDB = systemDB; myDB.transaction( function (transaction) { transaction.executeSql( 'CREATE TABLE IF NOT EXISTS table_name (primary_key_name INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, field_name TEXT NOT NULL DEFAULT "", field_name INTEGER NOT NULL DEFAULT 0, field_name BOOLEAN NOT NULL DEFAULT true);', [], nullDataHandler, killTransaction); } ); }

Empty tables:
function emptyTables() { var myDB = systemDB; myDB.transaction( function (transaction) { transaction.executeSql('DROP TABLE appointments;'); } ); createTables(); }

Add data:
function addData(data) { //json data var myDB = systemDB; myDB.transaction( function (transaction) { transaction.executeSql( 'INSERT INTO table_name (field_name, field_name, field_name) VALUES ( ?, ?, ?);', [ data.value1, data.value2, data.value3 ], function (transaction, resultSet) { if (!resultSet.rowsAffected) { // Previous insert failed. Bail. alert('No rows affected!'); return false; } console.log("inserted ID was " + resultSet.insertId); }, myTransactionErrorCallback); }, myTransactionErrorCallback); }

Delete data:
function removeData(searchCrieteria) { var myDB = systemDB; myDB.transaction( function (transaction) { transaction.executeSql( 'DELETE FROM appointments WHERE searched_field = ?;', [searchCrieteria], function (transaction, resultSet) { if (!resultSet.rowsAffected) { alert('No rows affected!'); return false; } }, myTransactionErrorCallback); }, myTransactionErrorCallback); }

Modify data:
function modifyData (oldData, newData) { var myDB = systemDB; myDB.transaction( function (transaction) { transaction.executeSql( 'UPDATE table_name set field_name = ? WHERE field_name = ?;', [newData, oldData], function(transaction, resultSet) {

if (!resultSet.rowsAffected) { alert("No rows to update!");return false; }


}); }, myTransactionErrorCallback, myTransactionSuccessCallback); }

Select data:
function listData () { var myDB = systemDB; myDB.transaction( function (transaction) { transaction.executeSql( 'SELECT * FROM table_name ORDER;', [], function (transaction, resultSet) { for (var i=0; i<resultSet.rows.length; i++) { var row = resultSet.rows.item(i); for (var j in row) { console.log(j + ": " + row[j]); } } }, myTransactionErrorCallback); }, myTransactionErrorCallback); }

Handlers:
/*! When passed as the error handler, this silently causes a transaction to fail. */ function killTransaction(transaction, error) { return true; // fatal transaction error } /*! When passed as the error handler, this causes a transaction to fail with a warning message. */ function myTransactionErrorCallback(error) { // error.message is a human-readable string. // error.code is a numeric error code if (error) { alert('Oops. Error was '+error.message+' (Code '+error.code+')'); } // Handle errors here var we_think_this_error_is_fatal = true; if (we_think_this_error_is_fatal) return true; return false; } /*! This is used as a data handler for a request that should return no data. */ function nullDataHandler(transaction, results) { } /*! On success perform whatever operations are needed */ function myTransactionSuccessCallback() { }

Key-value storage basic operations


Store values:
try { localStorage.setItem("myKey", myValue); } catch (e) { if (e == QUOTA_EXCEEDED_ERR) { alert('Quota exceeded.'); } }

Retrieve values:
var myValue = localStorage.getItem("myKey"); //on fail returns null

or
var myValue = localStorage.myKey; //if the key is a valid JavaScript token

or by index
try { value = localStorage(index); } catch(e) { if (e == INDEX_SIZE_ERR) { alert('There are fewer than '+(index-1)+' keys in the local storage object.'); } }

Delete values:
localStorage.removeItem("myKey"); localStorage.clear(); //to remove all key-value pairs

Handle storage events:


function storage_handler(evt) { alert('The modified key was '+evt.key); alert('The original value was '+evt.oldValue); alert('The new value is '+evt.newValue); alert('The URL of the page that made the change was '+evt.url); alert('The window where the change was made was '+evt.source); }

You might also like