summaryrefslogtreecommitdiffstats
path: root/doc/src/webkit/guide/chapter_cache.qdoc
blob: bdafe481c3366ed5155dfbe0005e9b2e6772ff09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt WebKit module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/

/*!

\page qtwebkit-guide-cache.html
\title Client Storage
\chapter Client Storage

Traditional mobile web development centered around the limitations of
client handsets,
which had very little storage for applications.
As handsets become more powerful,
however,
this assumption is no longer valid.
HTML5\'s newly introduced Storage features expand application storage
on the client.

HTML 5 standardizes access to an application\'s local data via
\c{LocalStorage} and \c{SessionStorage} APIs.
These APIs boost the amount of client storage available to web
applications.
They also can effectively replace cookies as a means to maintain
application state and track user preferences.

Local storage persists indefinitely,
while session storage lasts only for the duration of a window session.
Local storage is available from any page or window from the same site,
while session storage is local to each window.
Both local and session storage rely on simple key/value pairs,
with keys and values both stored as strings.

Local and session storage are not the only client storage available.
HTML 5 WebSQL serves as a more full-featured,
client-side database.
WebSQL brings SQLite-based structured database functionality,
typically deployed on servers,
to client browser applications.
WebSQL is appropriate for data-intensive applications requiring
complex queries rather than simple key/value access.
WebSQL database transaction calls help avoid interfaces from locking
up,
facilitate rollback and error handling,
and protect against SQL injection.
Database versioning allows you to manage schema changes incrementally.


\section1 Simple Data Storage

The \c{localStorage} and \c{sessionStorage} APIs offer applications
up to 5MB of data storage. They both share the same simple key/value
interface, but have different namespaces and also differ in the extent
to which data is available. Local storage persists indefinitely, while
session storage only lasts for the duration of a window session. Local
storage is available from any page or window from the same site, while
session storage is local to each window.

The following examples demonstrate the API interface.  While these use
\c{localStorage} as an example, the same set of API calls work for
\c{sessionStorage}, which is also available within the \c{window}
object.

The following performs an initial check for support of browser-based
storage and assigns the database to a variable:

\code
if (window.localStorage) {
    var db = window.localStorage;
    // storage functionality here
}
else {
    // store data remotely?
}
\endcode

The \c{getItem()} method retrieves the value of a database field named
\bold{key}:

\code
var value = db.getItem("key");
\endcode

Note that both keys and values are represented as strings.
If you specify any other type of data,
it is converted silently to a string representation.
(See \l{Storing Non-String Data} for ways around this limitation.)
If \c{getItem()} returns \c{null} rather than a string value,
it means the specified key does not exist.

The \c{setItem()} method establishes a new value.
When adding data,
it is a good idea to check to make sure you haven\'t exceeded the
allotted storage space:

\code
try {
    db.setItem("key", "string");
}
catch(err) {
    if (err.QUOTA_EXCEEDED_ERR) {
        // storage space is exceeded
    }
}
\endcode

The \c{removeItem()} method deletes database fields:

\code
db.removeItem("key");
\endcode

The \c{clear()} method deletes all key/value pairs within the
database, either for an entire site in the case of \c{localStorage},
or for an individual window session in the case of \c{sessionStorage}:

\code
db.clear();
\endcode

Databases can be accessed as arrays using index notation, useful in
cases where you may not know all the field names.  The \c{length}
property returns the number of fields in the database, and the
\c{key()} method returns the name of the key corresponding to a given
index. The following reflects the contents of a database in a
JavaScript object:

\code
var obj = {};
for ( var i = 0, l = db.length ; i < l ; i++ ) {
    obj[ db.key(i) ] = db.getItem( db.key(i) );
}
\endcode

Since keys correspond to array indexes, you should not add or remove
keys during any operation that iterates over the full set of key/value
pairs. Newly introduced keys are introduced randomly into the array\'s
sequence.

The following displays simple storage functionality. The application
prompts for a login and password if they are unavailable. This locally
stored data is available the next time users open the browser.
However, the contents of the credit card field is stored only for the
duration of the browing session.

\l{ex_storage}{\inlineimage webkit-guide/scr_storage.png
}

\l{storage_css}{(CSS)}
\l{storage_js}{(JavaScript)}


    \section2 Storing Non-String Data

    Since local and session storage APIs only support string values, you
    need to be careful not to allow errors that result from passive
    conversions from other data types. The following sample shows how
    such an error might come about:

    \code
    var db = window.localStorage;
    var saveCardInfo;
        // user expresses preference NOT to save credit card info:
    saveCardInfo = false;
        // BUG happens here...
    db.setItem("save_card_info", saveCardInfo);
        // variable is now a string, not a boolean:
    saveCardInfo = db.getItem("save_card_info");
        // both "true" and "false" strings evaluate as true...
    if ( saveCardInfo ) {
        // ...so this code always executes...
    }
    else {
        // ...and this code never executes.
    }
    \endcode

    The user\'s preference to retain credit card information is expressed
    within the application as a \c{true} or \c{false} boolean value. When
    each value is passed to storage, however, it is passively converted to
    a string. When reassigned to a JavaScript variable, it no longer
    serves as a valid boolean test. The application falsely assumes users
    want to save credit card information, regardless of their expressed
    preference.

    The following sample fixes the problem. Instead of using \c{true} and
    \c{false} boolean values, it converts \c{1} and \c{0} strings to
    numbers:

    \code
    var db = window.localStorage;
    var saveCardInfo = 0;
    db.setItem("save_card_info", saveCardInfo);
    // multiplying forces numeric output:
    saveCardInfo = db.getItem("save_card_info") * 1;
    \endcode

    For a more reliable alternative, store values as JSON strings and rely
    on automatic type conversion when subsequently parsing them.  The
    following sample shows how parsing JSON preserves both boolean and
    numeric data:

    \code
    var saveCardInfo = true;                    // boolean
    var shipMethod = 2;                        // number
    var db = window.localStorage;

    db.setItem("save_card_info", JSON.stringify(saveCardInfo));
    db.setItem("ship_method", JSON.stringify(shipMethod));

    saveCardInfo = JSON.parse(db.getItem("save_card_info"));    // boolean
    shipMethod = JSON.parse(db.getItem("ship_method"));        // number
    \endcode

    Note that this simple approach may cause problems of its own. For
    example, perhaps the words \bold{true} and \bold{false} really should
    be represented as strings. Encapsulating data within objects accounts
    for such variability:

    \code
    var db = window.localStorage;
    var obj = {
        bool    : true,
        str        : "true",
        num        : 1
    };
    db.setItem("appState", JSON.stringify(obj));    // to database...
    // "appState" is "{'bool':true,'num':1,'str':'true'}"
    obj = JSON.parse(db.getItem("appState"));    // ...and back
    // obj is same as initially defined.
    \endcode

    The ability to save objects as JSON strings means that you can save an
    application\'s state within a single database field.  For example, you
    might use the following approach to save the entire contents of a
    shopping cart in a single field for later use:

    \code
    var db = window.localStorage;
    var cart = { items: [] };

    cart.message = "From your loving uncle";

    cart.items.push({
        description    : "Floor to Ceiling Shoe Rack",
        id        : 203174676,
        price    : 99.95,
        quantity    : 1,
        weight    : 20,
    });

    cart.items.push({
        description    : "Automatic Laser Toy for Cats",
        id        : 203345371,
        price    : 19.95,
        quantity    : 2,
        weight    : 0.5,
    });

    // save all cumulative items:
    db.setItem("cart", JSON.stringify(cart));

    // extract items from storage:
    cart = JSON.parse(db.getItem("cart"));
    \endcode

    JSON allows you to store data types, but functions are ignored.  That
    makes it more difficult to preserve objects representing fully
    functional applications.

    \section2 Storage Events

    The \c{storage} event allows applications to respond indirectly to
    modified data resulting from calls to \c{setItem()}, \c{removeItem()},
    or \c{clear()}. This may be useful in providing users with visual
    feedback notifying them of data that is modified locally, perhaps
    rather than being sent to a remote server:

    \code
    window.addEventListener("storage", function(event){
        var icon = document.querySelector("#indicator");
        if (event.storageArea.length) {
            icon.className = "writing";
        }
        else {
            icon.className = "empty";
        }
    }, false);
    \endcode

    The \c{storage} event\'s \c{storageArea} attribute returns the
    \c{localStorage} or \c{sessionStorage} object being modified. The
    \c{key} is the name of the field being modified, and \c{oldValue} and
    \c{newValue} are its values before and after the event. The \c{url} is
    the page that called the method triggering the change.


\section1 WebSQL Databases

While common local- or session-based databases are capable of storing
complex data structures, QtWebKit-based browsers can also rely upon
the WebSQL standard, which brings SQLite-based structured database
functionality, typically deployed on servers, to client browser
applications. Based on SQLite version 3.6.19, WebSQL is appropriate
for data-intensive applications requring complex queries rather than
simple key/value access.

The following test confirms support for WebSQL:

\code
if (!!window.openDatabase) {
    // supports WebSQL
}
\endcode

Calls to databases made via the WebSQL API are made asynchronously via
transactions to avoid the user interface from locking up, as database
interaction may occur from several windows at a time.

The three core API methods are:

\list

\o \c{openDatabase()}

\o \c{transaction()}

\o \c{executeSql()}

\endlist

    \section2 Creating and Opening a New Database

    To create and open a database, use \c{openDatabase()}on the Window object,
    for example:

    \code
    var db = openDatabase('mydb', '1.0', 'my first database', 2*1024*1024);
    var db = openDatabase('notes', '', 'The Example Notes App!', 1048576);
    \endcode

    The four required arguments are the database name, version, display
    name, and estimated size in bytes.  You can supply a function as an
    optional fifth argument to serve as a callback when a database is
    created.  It may be used to call the \c{changeversion()} method, in
    which case the callback is invoked with an empty string for the
    database version.

    The second example above specifies an empty string for the version. In
    this case the database opens no matter what the database version
    is. (An \c{openDatabase()} call specifying the wrong version for an
    existing database throws an \c{INVALID_STATE_ERR} exception.) You can
    then query the version by examining the database object's version
    property, for example:

    \code
    var version = db.version;
    \endcode

    Note that you don\'t need to close a client-side Web SQL database when
    you\'re done working with it.

    \section2 Transaction Calls and ExecuteSQL Method

    Performing database transactions is superior to running SQL statements
    directly because transactions are not committed if they fail and you
    can undo them if needed. Transactions also allow you to handle errors
    using a callback. To implement a transaction, specify a callback
    function such as the following:

    \code
    db.transaction(function (tx) {
      // SQL details on the tx object go here
    }
    \endcode

    The \c{transaction()} method takes one to three arguments:

    \list

    \o a required transaction callback, in which \c{executeSQL()} calls
    belong

    \o an optional transaction error object

    \o an optional success callback.

    \endlist

    Use the \c{executeSQL()} method to specify SQL statements for read and
    write operations. The method protects against SQL injection and
    provides a callback method to process the results of any SQL queries
    you specify. The \c{executeSQL()} method takes from one to four
    arguments:

    \list

    \o a required SQL statement

    \o an optional object array of arguments

    \o an optional SQL statement callback

    \o an optional SQL statement error callback

    \endlist

    The example below creates the database if it doesn\'t exist, adds a
    two-column table to the database, and adds a row of data to the table:

    \code
    var db = openDatabase('mydb', '1.0', 'my first database', 2 * 1024 * 1024);
    db.transaction(function (tx) {
        tx.executeSql('CREATE TABLE IF NOT EXISTS foo (id unique, text)');
        tx.executeSql('INSERT INTO foo (id, text) VALUES (1, "synergies")');
    });
    \endcode

    To capture data from the user or an external source, use \c{?}
    placeholders to map that data into the SQL query. This ensures the
    data doesn\'t compromise database security, for example from SQL
    injection:

    \code
    tx.executeSql('INSERT INTO foo (id, text) VALUES (?, ?)', [id, value]);
    \endcode

    \c{id} and \c{value} are external variables, and \c{executeSql} maps
    the items in the array to the \c{?}s.

    To select values from the table, use a callback to capture the
    results:

    \code
    tx.executeSql('SELECT * FROM foo', [], function(tx, results) {
        for (var i = 0 , len = results.rows.length; i < len; i++) {
            // do something with results.rows.item(i).text
        }
    });
    \endcode

    No fields are mapped in the above query, but to use the third argument
    you need to pass in an empty array as the second argument.

    The SQL statement callback for \c{executeSQL()} is called with the
    \c{transaction} object and a SQL statement \c{result} object. The
    \c{result} gives access to the ID of the last inserted row, the number
    of rows affected, and an indexed list representing the rows returned,
    in the order returned.

    The \c{result} object contains an array-like \c{rows} object. It has a
    length, but to access individual rows you need to use
    \c{results.rows.item(i)}, where \c{i} is the index of the row.  This
    returns an object representation of each row.  For example, if your
    database has a \c{name} and an \c{age} field, the \c{row} contains a
    \c{name} and an \c{age} property. The value of the \c{age} field can
    be accessed using \c{results.rows.item(i).age}.

    \section2 Changing Database Versions

    Each database has one version at a time and multiple versions cannot
    exist at one time. Versions allow you to manage schema changes
    incrementally.

    You can change the version of a client-side Web SQL database using the
    \c{changeversion()} method:

    \code
    if (db.version == "1.0") {
        try {
            // comment out for crash recovery.
            db.changeVersion("1.0", "2.0", cv_1_0_2_0, oops_1_0_2_0, success_1_0_2_0);
        } catch(e) {
            alert('changeversion 1.0 -> 2.0 failed');
            alert('DB Version: '+db.version);
        }
    }
    \endcode

    \c{changeversion()} takes the following arguments: required old and
    new version numbers, optional SQL transaction callback, optional SQL
    transaction error callback, and optional success callback.

    \section2 Errors

    Asynchronous API errors are reported using callbacks that have a
    \c{SQLError} object as one of their arguments. \c{SQLError} contains a
    code from the table below and a localized message string.

    Error codes are:

    \list

    \o 0 \c{UNKNOWN_ERROR} Transaction failed for reasons unrelated to the DB

    \o 1 \c{DATABASE_ERROR} Statement failed for DB reasons not covered by other
    code

    \o 2 \c{VERSION_ERROR} DB version doesn\'t match expected version

    \o 3 \c{TOO_LARGE_ERROR} Data returned from DB was too large. Try the
    \c{SQL LIMIT} modifier.

    \o 4 \c{QUOTA_ERROR} Insufficient remaining storage

    \o 5 \c{SYNTAX_ERROR} Syntax error, argument mismatch, or unallowed
    statement

    \o 6 \c{CONSTRAINT_ERROR} An \c{INSERT}, \c{UPDATE}, or \c{REPLACE}
    statement failed due to a constraint error

    \o 7 \c{TIMEOUT_ERROR} Timeout waiting for transaction lock

    \endlist

    \bold{See Also:}
    \l{http://html5doctor.com/introducing-web-sql-databases/}{HTML5
    Doctor: Introducing Web SQL Databases}

*/