Return to Overview.html CVS log | Up to [Public] / html5 / webdatabase |
1.58 ihickson 1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html lang="en-US-x-Hixie"><title>Web SQL Database</title><style type="text/css"> 1.1 ihickson 2: pre { margin-left: 2em; white-space: pre-wrap; } 3: h2 { margin: 3em 0 1em 0; } 4: h3 { margin: 2.5em 0 1em 0; } 5: h4 { margin: 2.5em 0 0.75em 0; } 6: h5, h6 { margin: 2.5em 0 1em; } 7: h1 + h2, h1 + h2 + h2 { margin: 0.75em 0 0.75em; } 8: h2 + h3, h3 + h4, h4 + h5, h5 + h6 { margin-top: 0.5em; } 9: p { margin: 1em 0; } 10: hr:not(.top) { display: block; background: none; border: none; padding: 0; margin: 2em 0; height: auto; } 11: dl, dd { margin-top: 0; margin-bottom: 0; } 12: dt { margin-top: 0.75em; margin-bottom: 0.25em; clear: left; } 13: dt + dt { margin-top: 0; } 14: dd dt { margin-top: 0.25em; margin-bottom: 0; } 15: dd p { margin-top: 0; } 16: dd dl + p { margin-top: 1em; } 17: dd table + p { margin-top: 1em; } 18: p + * > li, dd li { margin: 1em 0; } 19: dt, dfn { font-weight: bold; font-style: normal; } 20: dt dfn { font-style: italic; } 21: pre, code { font-size: inherit; font-family: monospace; font-variant: normal; } 22: pre strong { color: black; font: inherit; font-weight: bold; background: yellow; } 23: pre em { font-weight: bolder; font-style: normal; } 24: @media screen { code { color: orangered; } code :link, code :visited { color: inherit; } } 25: var sub { vertical-align: bottom; font-size: smaller; position: relative; top: 0.1em; } 26: table { border-collapse: collapse; border-style: hidden hidden none hidden; } 27: table thead { border-bottom: solid; } 28: table tbody th:first-child { border-left: solid; } 1.37 ihickson 29: table tbody th { text-align: left; } 1.1 ihickson 30: table td, table th { border-left: solid; border-right: solid; border-bottom: solid thin; vertical-align: top; padding: 0.2em; } 31: blockquote { margin: 0 0 0 2em; border: 0; padding: 0; font-style: italic; } 32: 33: .bad, .bad *:not(.XXX) { color: gray; border-color: gray; background: transparent; } 34: .matrix, .matrix td { border: none; text-align: right; } 35: .matrix { margin-left: 2em; } 36: .dice-example { border-collapse: collapse; border-style: hidden solid solid hidden; border-width: thin; margin-left: 3em; } 37: .dice-example caption { width: 30em; font-size: smaller; font-style: italic; padding: 0.75em 0; text-align: left; } 38: .dice-example td, .dice-example th { border: solid thin; width: 1.35em; height: 1.05em; text-align: center; padding: 0; } 39: 40: .toc dfn, h1 dfn, h2 dfn, h3 dfn, h4 dfn, h5 dfn, h6 dfn { font: inherit; } 41: img.extra { float: right; } 42: pre.idl { border: solid thin; background: #EEEEEE; color: black; padding: 0.5em 1em; } 43: pre.idl :link, pre.idl :visited { color: inherit; background: transparent; } 44: pre.css { border: solid thin; background: #FFFFEE; color: black; padding: 0.5em 1em; } 45: pre.css:first-line { color: #AAAA50; } 1.72 ihickson 46: dl.domintro { color: green; margin: 2em 0 2em 2em; padding: 0.5em 1em; border: none; background: #DDFFDD; } 1.1 ihickson 47: hr + dl.domintro, div.impl + dl.domintro { margin-top: 2.5em; margin-bottom: 1.5em; } 48: dl.domintro dt, dl.domintro dt * { color: black; text-decoration: none; } 49: dl.domintro dd { margin: 0.5em 0 1em 2em; padding: 0; } 50: dl.domintro dd p { margin: 0.5em 0; } 51: dl.switch { padding-left: 2em; } 52: dl.switch > dt { text-indent: -1.5em; } 53: dl.switch > dt:before { content: '\21AA'; padding: 0 0.5em 0 0; display: inline-block; width: 1em; text-align: right; line-height: 0.5em; } 54: dl.triple { padding: 0 0 0 1em; } 55: dl.triple dt, dl.triple dd { margin: 0; display: inline } 56: dl.triple dt:after { content: ':'; } 57: dl.triple dd:after { content: '\A'; white-space: pre; } 58: .diff-old { text-decoration: line-through; color: silver; background: transparent; } 59: .diff-chg, .diff-new { text-decoration: underline; color: green; background: transparent; } 60: a .diff-new { border-bottom: 1px blue solid; } 61: 62: h2 { page-break-before: always; } 63: h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } 64: h1 + h2, hr + h2.no-toc { page-break-before: auto; } 65: 66: p > span:not([title=""]):not([class="XXX"]):not([class="impl"]), li > span:not([title=""]):not([class="XXX"]):not([class="impl"]) { border-bottom: solid #9999CC; } 67: 68: div.head { margin: 0 0 1em; padding: 1em 0 0 0; } 69: div.head p { margin: 0; } 70: div.head h1 { margin: 0; } 71: div.head .logo { float: right; margin: 0 1em; } 72: div.head .logo img { border: none } /* remove border from top image */ 73: div.head dl { margin: 1em 0; } 1.55 ihickson 74: div.head p.copyright, div.head p.alt { font-size: x-small; font-style: oblique; margin: 0; } 1.1 ihickson 75: 76: body > .toc > li { margin-top: 1em; margin-bottom: 1em; } 77: body > .toc.brief > li { margin-top: 0.35em; margin-bottom: 0.35em; } 78: body > .toc > li > * { margin-bottom: 0.5em; } 79: body > .toc > li > * > li > * { margin-bottom: 0.25em; } 80: .toc, .toc li { list-style: none; } 81: 82: .brief { margin-top: 1em; margin-bottom: 1em; line-height: 1.1; } 83: .brief li { margin: 0; padding: 0; } 84: .brief li p { margin: 0; padding: 0; } 85: 86: .category-list { margin-top: -0.75em; margin-bottom: 1em; line-height: 1.5; } 87: .category-list::before { content: '\21D2\A0'; font-size: 1.2em; font-weight: 900; } 88: .category-list li { display: inline; } 89: .category-list li:not(:last-child)::after { content: ', '; } 90: .category-list li > span, .category-list li > a { text-transform: lowercase; } 91: .category-list li * { text-transform: none; } /* don't affect <code> nested in <a> */ 92: 93: .XXX { color: #E50000; background: white; border: solid red; padding: 0.5em; margin: 1em 0; } 94: .XXX > :first-child { margin-top: 0; } 95: p .XXX { line-height: 3em; } 1.21 ihickson 96: .annotation { border: solid thin black; background: #0C479D; color: white; position: relative; margin: 8px 0 20px 0; } 97: .annotation:before { position: absolute; left: 0; top: 0; width: 100%; height: 100%; margin: 6px -6px -6px 6px; background: #333333; z-index: -1; content: ''; } 98: .annotation :link, .annotation :visited { color: inherit; } 99: .annotation :link:hover, .annotation :visited:hover { background: transparent; } 100: .annotation span { border: none ! important; } 1.1 ihickson 101: .note { color: green; background: transparent; font-family: sans-serif; } 102: .warning { color: red; background: transparent; } 103: .note, .warning { font-weight: bolder; font-style: italic; } 104: p.note, div.note { padding: 0.5em 2em; } 105: span.note { padding: 0 2em; } 106: .note p:first-child, .warning p:first-child { margin-top: 0; } 107: .note p:last-child, .warning p:last-child { margin-bottom: 0; } 108: .warning:before { font-style: normal; } 109: p.note:before { content: 'Note: '; } 110: p.warning:before { content: '\26A0 Warning! '; } 111: 112: .bookkeeping:before { display: block; content: 'Bookkeeping details'; font-weight: bolder; font-style: italic; } 113: .bookkeeping { font-size: 0.8em; margin: 2em 0; } 114: .bookkeeping p { margin: 0.5em 2em; display: list-item; list-style: square; } 115: 116: h4 { position: relative; z-index: 3; } 117: h4 + .element, h4 + div + .element { margin-top: -2.5em; padding-top: 2em; } 118: .element { 119: background: #EEEEFF; 120: color: black; 121: margin: 0 0 1em 0.15em; 122: padding: 0 1em 0.25em 0.75em; 123: border-left: solid #9999FF 0.25em; 124: position: relative; 125: z-index: 1; 126: } 127: .element:before { 128: position: absolute; 129: z-index: 2; 130: top: 0; 131: left: -1.15em; 132: height: 2em; 133: width: 0.9em; 134: background: #EEEEFF; 135: content: ' '; 136: border-style: none none solid solid; 137: border-color: #9999FF; 138: border-width: 0.25em; 139: } 140: 1.12 ihickson 141: .example { display: block; color: #222222; background: #FCFCFC; border-left: double; margin-left: 2em; padding-left: 1em; } 142: td > .example:only-child { margin: 0 0 0 0.1em; } 1.1 ihickson 143: 144: .tall-and-narrow { 145: font-size: 0.6em; 146: column-width: 25em; 147: column-gap: 1em; 148: -moz-column-width: 25em; 149: -moz-column-gap: 1em; 150: -webkit-column-width: 25em; 151: -webkit-column-gap: 1em; 152: } 153: 154: ul.domTree, ul.domTree ul { padding: 0 0 0 1em; margin: 0; } 155: ul.domTree li { padding: 0; margin: 0; list-style: none; position: relative; } 156: ul.domTree li li { list-style: none; } 157: ul.domTree li:first-child::before { position: absolute; top: 0; height: 0.6em; left: -0.75em; width: 0.5em; border-style: none none solid solid; content: ''; border-width: 0.1em; } 158: ul.domTree li:not(:last-child)::after { position: absolute; top: 0; bottom: -0.6em; left: -0.75em; width: 0.5em; border-style: none none solid solid; content: ''; border-width: 0.1em; } 159: ul.domTree span { font-style: italic; font-family: serif; } 160: ul.domTree .t1 code { color: purple; font-weight: bold; } 161: ul.domTree .t2 { font-style: normal; font-family: monospace; } 162: ul.domTree .t2 .name { color: black; font-weight: bold; } 163: ul.domTree .t2 .value { color: blue; font-weight: normal; } 164: ul.domTree .t3 code, .domTree .t4 code, .domTree .t5 code { color: gray; } 165: ul.domTree .t7 code, .domTree .t8 code { color: green; } 166: ul.domTree .t10 code { color: teal; } 167: 1.67 ihickson 168: body.dfnEnabled dfn { cursor: pointer; } 169: .dfnPanel { 170: display: inline; 171: position: absolute; 172: z-index: 10; 173: height: auto; 174: width: auto; 175: padding: 0.5em 0.75em; 176: font: small sans-serif, Droid Sans Fallback; 177: background: #DDDDDD; 178: color: black; 179: border: outset 0.2em; 180: } 181: .dfnPanel * { margin: 0; padding: 0; font: inherit; text-indent: 0; } 182: .dfnPanel :link, .dfnPanel :visited { color: black; } 183: .dfnPanel p { font-weight: bolder; } 184: .dfnPanel * + p { margin-top: 0.25em; } 185: .dfnPanel li { list-style-position: inside; } 186: 1.53 ihickson 187: #configUI { position: absolute; z-index: 20; top: 10em; right: 1em; width: 11em; font-size: small; } 188: #configUI p { margin: 0.5em 0; padding: 0.3em; background: #EEEEEE; color: black; border: inset thin; } 189: #configUI p label { display: block; } 190: #configUI #updateUI, #configUI .loginUI { text-align: center; } 191: #configUI input[type=button] { display: block; margin: auto; } 1.58 ihickson 192: </style><link href="http://www.w3.org/StyleSheets/TR/W3C-ED" rel="stylesheet" type="text/css"><div class="head"> 1.1 ihickson 193: <p><a href="http://www.w3.org/"><img alt="W3C" height="48" src="http://www.w3.org/Icons/w3c_home" width="72"></a></p> 1.50 ihickson 194: <h1>Web SQL Database</h1> 1.29 ihickson 195: 1.74 ! ihickson 196: <h2 class="no-num no-toc" id="editor-s-draft-3-march-2010">Editor's Draft 3 March 2010</h2> 1.58 ihickson 197: <dl><dt>Latest Published Version:</dt> 1.1 ihickson 198: <dd><a href="http://www.w3.org/TR/webdatabase/">http://www.w3.org/TR/webdatabase/</a></dd> 1.29 ihickson 199: <dt>Latest Editor's Draft:</dt> 1.1 ihickson 200: <dd><a href="http://dev.w3.org/html5/webdatabase/">http://dev.w3.org/html5/webdatabase/</a></dd> 1.43 ihickson 201: <!-- ZZZ: add the new version after it has shipped--> 1.1 ihickson 202: <dt>Previous Versions:</dt> 1.43 ihickson 203: <dd><a href="http://www.w3.org/TR/2009/WD-webstorage-20090423/">http://www.w3.org/TR/2009/WD-webstorage-20090423/</a> <!-- yes, storage, not db --> 1.46 ihickson 204: <dd><a href="http://www.w3.org/TR/2009/WD-webdatabase-20091029/">http://www.w3.org/TR/2009/WD-webdatabase-20091029/</a></dd> 1.43 ihickson 205: <!-- :ZZZ --> 1.1 ihickson 206: <dt>Editors:</dt> 207: <dd><a href="mailto:ian@hixie.ch">Ian Hickson</a>, Google, Inc.</dd> 1.10 ihickson 208: </dl><p class="copyright"><a href="http://www.w3.org/Consortium/Legal/ipr-notice#Copyright">Copyright</a> 1.73 ihickson 209: © 2010 <a href="http://www.w3.org/"><abbr title="World Wide 1.10 ihickson 210: Web Consortium">W3C</abbr></a><sup>®</sup> (<a href="http://www.csail.mit.edu/"><abbr title="Massachusetts 1.1 ihickson 211: Institute of Technology">MIT</abbr></a>, <a href="http://www.ercim.org/"><abbr title="European Research 212: Consortium for Informatics and Mathematics">ERCIM</abbr></a>, <a href="http://www.keio.ac.jp/">Keio</a>), All Rights Reserved. W3C 213: <a href="http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer">liability</a>, 214: <a href="http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks">trademark</a> 215: and <a href="http://www.w3.org/Consortium/Legal/copyright-documents">document 216: use</a> rules apply.</p> 1.10 ihickson 217: </div><hr class="top"><h2 class="no-num no-toc" id="abstract">Abstract</h2><p>This specification defines an API for storing data in databases 1.55 ihickson 218: that can be queried using a variant of SQL.<h2 class="no-num no-toc" id="status-of-this-document">Status of This document</h2><!-- intro boilerplate (required) --><p><em>This section describes the status of this document at the 1.1 ihickson 219: time of its publication. Other documents may supersede this 220: document. A list of current W3C publications and the most recently 221: formally published revision of this technical report can be found in 222: the <a href="http://www.w3.org/TR/">W3C technical reports index</a> 1.10 ihickson 223: at http://www.w3.org/TR/.</em></p><!-- where to send feedback (required) --><p>If you wish to make comments regarding this document, please send 1.1 ihickson 224: them to <a href="mailto:public-webapps@w3.org">public-webapps@w3.org</a> 225: (<a href="mailto:public-webapps-request@w3.org?subject=subscribe">subscribe</a>, 226: <a href="http://lists.w3.org/Archives/Public/public-webapps/">archives</a>) 227: 228: <!-- UNDER NO CIRCUMSTANCES IS THE FOLLOWING SENTENCE TO BE REMOVED OR EDITED WITHOUT TALKING TO IAN FIRST --> 229: or <a href="mailto:whatwg@whatwg.org">whatwg@whatwg.org</a> (<a href="http://lists.whatwg.org/listinfo.cgi/whatwg-whatwg.org">subscribe</a>, 230: <a href="http://lists.whatwg.org/pipermail/whatwg-whatwg.org/">archives</a>), 231: <!-- UNDER NO CIRCUMSTANCES IS THE PRECEDING SENTENCE TO BE REMOVED OR EDITED WITHOUT TALKING TO IAN FIRST --> 232: 233: or submit them using <a href="http://www.w3.org/Bugs/Public/enter_bug.cgi?product=WebAppsWG&component=Web%20Storage">our 234: public bug database</a>. 235: 1.10 ihickson 236: All feedback is welcome.</p><!-- stability (required) --><p>Implementors should be aware that this specification is not 1.1 ihickson 237: stable. <strong>Implementors who are not taking part in the 238: discussions are likely to find the specification changing out from 239: under them in incompatible ways.</strong> Vendors interested in 240: implementing this specification before it eventually reaches the 241: Candidate Recommendation stage should join the aforementioned 1.56 ihickson 242: mailing lists and take part in the discussions.<p class="XXX">This specification has reached an impasse: all 243: interested implementors have used the same SQL backend (Sqlite), but 244: we need multiple independent implementations to proceed along a 245: standardisation path. Until another implementor is interested in 246: implementing this spec, the description of the SQL dialect has been 247: left as simply a reference to Sqlite, which isn't acceptable for a 248: standard. Should you be an implementor interested in implementing an 249: independent SQL backend, please contact the editor so that he can 250: write a specification for the dialect, thus allowing this 251: specification to move forward.</p><!-- version history or list of changes (required) --><p>The latest stable version of the editor's draft of this 1.1 ihickson 252: specification is always available on <a href="http://dev.w3.org/html5/webdatabase/Overview.html">the W3C CVS 253: server</a>. Change tracking for this document is available at the 1.10 ihickson 254: following location:<ul><li>CVS log: <a href="http://dev.w3.org/cvsweb/html5/webdatabase/Overview.html">http://dev.w3.org/cvsweb/html5/webdatabase/Overview.html</a></li> 255: </ul><!-- UNDER NO CIRCUMSTANCES IS THE FOLLOWING PARAGRAPH TO BE REMOVED OR EDITED WITHOUT TALKING TO IAN FIRST --><!-- relationship to other work (required) --><p>This specification is automatically generated from the 1.1 ihickson 256: corresponding section in the HTML5 specification's source document, 257: as hosted in the <a href="http://svn.whatwg.org/webapps/">WHATWG 258: Subversion repository</a>. Detailed change history for all of HTML5, 259: including the parts that form this specification, can be found at 1.10 ihickson 260: the following locations:</p><!-- UNDER NO CIRCUMSTANCES IS THE PRECEDING PARAGRAPH TO BE REMOVED OR EDITED WITHOUT TALKING TO IAN FIRST --><!-- UNDER NO CIRCUMSTANCES IS THE FOLLOWING LIST TO BE REMOVED OR EDITED WITHOUT TALKING TO IAN FIRST --><ul><li>Twitter messages (non-editorial changes only): <a href="http://twitter.com/WHATWG">http://twitter.com/WHATWG</a></li> 1.1 ihickson 261: <li>Interactive Web interface: <a href="http://html5.org/tools/web-apps-tracker">http://html5.org/tools/web-apps-tracker</a></li> 262: <li>Commit-Watchers mailing list: <a href="http://lists.whatwg.org/listinfo.cgi/commit-watchers-whatwg.org">http://lists.whatwg.org/listinfo.cgi/commit-watchers-whatwg.org</a></li> 263: <li>Subversion interface: <a href="http://svn.whatwg.org/webapps/">http://svn.whatwg.org/webapps/</a></li> 1.10 ihickson 264: </ul><!-- UNDER NO CIRCUMSTANCES IS THE PRECEDING LIST TO BE REMOVED OR EDITED WITHOUT TALKING TO IAN FIRST --><!-- status of document, group responsible (required) --><p>The W3C <a href="http://www.w3.org/2008/webapps/">Web Apps 1.1 ihickson 265: Working Group</a> is the W3C working group responsible for this 266: specification's progress along the W3C Recommendation track. 1.29 ihickson 267: 1.74 ! ihickson 268: This specification is the 3 March 2010 Editor's Draft. 1.10 ihickson 269: </p><!-- required patent boilerplate --><p>This document was produced by a group operating under the <a href="http://www.w3.org/Consortium/Patent-Policy-20040205/">5 1.1 ihickson 270: February 2004 W3C Patent Policy</a>. W3C maintains a <a href="http://www.w3.org/2004/01/pp-impl/42538/status" rel="disclosure">public list of 271: any patent disclosures</a> made in connection with the deliverables 272: of the group; that page also includes instructions for disclosing a 273: patent. An individual who has actual knowledge of a patent which the 274: individual believes contains <a href="http://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential">Essential 275: Claim(s)</a> must disclose the information in accordance with <a href="http://www.w3.org/Consortium/Patent-Policy-20040205/#sec-Disclosure">section 1.55 ihickson 276: 6 of the W3C Patent Policy</a>.<h2 class="no-num no-toc" id="contents">Table of Contents</h2> 1.1 ihickson 277: <!--begin-toc--> 278: <ol class="toc"> 279: <li><a href="#introduction"><span class="secno">1 </span>Introduction</a></li> 280: <li><a href="#conformance-requirements"><span class="secno">2 </span>Conformance requirements</a> 281: <ol> 282: <li><a href="#dependencies"><span class="secno">2.1 </span>Dependencies</a></ol></li> 283: <li><a href="#terminology"><span class="secno">3 </span>Terminology</a></li> 284: <li><a href="#sql"><span class="secno">4 </span>The API</a> 285: <ol> 286: <li><a href="#databases"><span class="secno">4.1 </span>Databases</a></li> 287: <li><a href="#parsing-and-processing-sql-statements"><span class="secno">4.2 </span>Parsing and processing SQL statements</a></li> 288: <li><a href="#asynchronous-database-api"><span class="secno">4.3 </span>Asynchronous database API</a> 289: <ol> 290: <li><a href="#executing-sql-statements"><span class="secno">4.3.1 </span>Executing SQL statements</a></li> 291: <li><a href="#processing-model"><span class="secno">4.3.2 </span>Processing model</a></ol></li> 292: <li><a href="#synchronous-database-api"><span class="secno">4.4 </span>Synchronous database API</a> 293: <ol> 294: <li><a href="#executing-sql-statements-0"><span class="secno">4.4.1 </span>Executing SQL statements</a></ol></li> 295: <li><a href="#database-query-results"><span class="secno">4.5 </span>Database query results</a></li> 296: <li><a href="#errors-and-exceptions"><span class="secno">4.6 </span>Errors and exceptions</a></ol></li> 1.19 ihickson 297: <li><a href="#web-sql"><span class="secno">5 </span>Web SQL</a></li> 298: <li><a href="#disk-space"><span class="secno">6 </span>Disk space</a></li> 299: <li><a href="#privacy"><span class="secno">7 </span>Privacy</a> 1.1 ihickson 300: <ol> 1.19 ihickson 301: <li><a href="#user-tracking"><span class="secno">7.1 </span>User tracking</a></li> 1.31 ihickson 302: <li><a href="#sensitivity-of-data"><span class="secno">7.2 </span>Sensitivity of data</a></ol></li> 1.19 ihickson 303: <li><a href="#security"><span class="secno">8 </span>Security</a> 1.1 ihickson 304: <ol> 1.19 ihickson 305: <li><a href="#dns-spoofing-attacks"><span class="secno">8.1 </span>DNS spoofing attacks</a></li> 306: <li><a href="#cross-directory-attacks"><span class="secno">8.2 </span>Cross-directory attacks</a></li> 307: <li><a href="#implementation-risks"><span class="secno">8.3 </span>Implementation risks</a></li> 308: <li><a href="#sql-and-user-agents"><span class="secno">8.4 </span>SQL and user agents</a></li> 309: <li><a href="#sql-injection"><span class="secno">8.5 </span>SQL injection</a></ol></li> 1.1 ihickson 310: <li><a class="no-num" href="#references">References</a></ol> 1.10 ihickson 311: <!--end-toc--><hr><!-- Feature requests for future versions (v2): 1.1 ihickson 312: * deleting databases 313: * determining how much storage room is left 314: * handling the database getting corrupted 1.14 ihickson 315: --><h2 id="introduction"><span class="secno">1 </span>Introduction</h2><p><i>This section is non-normative.</i><p>This specification introduces a set of APIs to manipulate 316: client-side databases using SQL.<p>The API is asynchronous, so authors are likely to find anonymous 317: functions (lambdas) very useful in using this API.<p>Here is an example of a script using this API. First, a function 318: <code title="">prepareDatabase()</code> is defined. This function 319: tries to create the database if necessary, giving it one table 320: called "docids" with two columns ("id" and "name"). If it is 321: successful, or if the table doesn't need creating, it calls a 322: section function, <code title="">getDatabase()</code>, which obtains 323: a handle to the database, and then calls the function to do the 324: actual work, in this case <code title="">showDocCount()</code>.<pre>function prepareDatabase(ready, error) { 1.17 ihickson 325: return openDatabase('documents', '1.0', 'Offline document storage', 5*1024*1024, function (db) { 1.14 ihickson 326: db.changeVersion('', '1.0', function (t) { 327: t.executeSql('CREATE TABLE docids (id, name)'); 1.17 ihickson 328: }, error); 329: }); 1.14 ihickson 330: } 331: 332: function showDocCount(db, span) { 333: db.readTransaction(function (t) { 1.18 ihickson 334: t.executeSql('SELECT COUNT(*) AS c FROM docids', [], function (t, r) { 335: span.textContent = r.rows[0].c; 1.14 ihickson 336: }, function (t, e) { 337: // couldn't read database 338: span.textContent = '(unknown: ' + e.message + ')'; 339: }); 340: }); 341: } 342: 343: prepareDatabase(function(db) { 344: // got database 345: var span = document.getElementById('doc-count'); 346: showDocCount(db, span); 347: }, function (e) { 348: // error getting database 349: alert(e.message); 1.18 ihickson 350: });</pre><hr><p>The <code title="dom-sqltransaction-executeSql"><a href="#dom-sqltransaction-executesql">executeSql()</a></code> method has 351: an argument intended to allow variables to be substituted into 352: statements without risking SQL injection vulnerabilities:<pre>db.readTransaction(function (t) { 353: t.executeSql('SELECT title, author FROM docs WHERE id=?', [id], function (t, data) { 354: report(data.rows[0].title, data.rows[0].author); 355: }); 1.19 ihickson 356: });</pre><hr><p>Sometimes, there might be an arbitrary number of variables to 1.18 ihickson 357: substitute in. Even in these case, the right solution is to 358: construct the query using only "?" characters, and then to pass the 1.19 ihickson 359: variables in as the second argument:<pre>function findDocs(db, resultCallback) { 1.18 ihickson 360: var q = ""; 361: for each (var i in labels) 362: q += (q == "" ? "" : ", ") + "?"; 363: db.readTransaction(function (t) { 364: t.executeSql('SELECT id FROM docs WHERE label IN (' + q + ')', labels, function (t, data) { 365: resultCallback(data); 366: }); 367: }); 1.19 ihickson 368: }</pre><h2 id="conformance-requirements"><span class="secno">2 </span>Conformance requirements</h2><p>All diagrams, examples, and notes in this specification are 1.1 ihickson 369: non-normative, as are all sections explicitly marked non-normative. 1.19 ihickson 370: Everything else in this specification is normative.<p>The key words "MUST", "MUST NOT", "REQUIRED", <!--"SHALL", "SHALL 1.1 ihickson 371: NOT",--> "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and 372: "OPTIONAL" in the normative parts of this document are to be 373: interpreted as described in RFC2119. For readability, these words do 1.19 ihickson 374: not appear in all uppercase letters in this specification. <a href="#refsRFC2119">[RFC2119]</a><p>Requirements phrased in the imperative as part of algorithms 1.1 ihickson 375: (such as "strip any leading space characters" or "return false and 376: abort these steps") are to be interpreted with the meaning of the 377: key word ("must", "should", "may", etc) used in introducing the 1.19 ihickson 378: algorithm.<p>Some conformance requirements are phrased as requirements on 1.1 ihickson 379: attributes, methods or objects. Such requirements are to be 1.19 ihickson 380: interpreted as requirements on user agents.<p>Conformance requirements phrased as algorithms or specific steps 1.1 ihickson 381: may be implemented in any manner, so long as the end result is 382: equivalent. (In particular, the algorithms defined in this 383: specification are intended to be easy to follow, and not intended to 1.19 ihickson 384: be performant.)<p>The only conformance class defined by this specification is user 385: agents.<p>User agents may impose implementation-specific limits on 1.1 ihickson 386: otherwise unconstrained inputs, e.g. to prevent denial of service 387: attacks, to guard against running out of memory, or to work around 1.70 ihickson 388: platform-specific limitations.<p>When support for a feature is disabled (e.g. as an emergency 389: measure to mitigate a security problem, or to aid in development, or 390: for performance reasons), user agents must act as if they had no 391: support for the feature whatsoever, and as if the feature was not 392: mentioned in this specification. For example, if a particular 393: feature is accessed via an attribute in a Web IDL interface, the 394: attribute itself would be omitted from the objects that implement 395: that interface — leaving the attribute on the object but 396: making it return null or throw an exception is insufficient.<h3 id="dependencies"><span class="secno">2.1 </span>Dependencies</h3><p>This specification relies on several other underlying 1.68 ihickson 397: specifications.<dl><dt>HTML</dt> 1.1 ihickson 398: 399: <dd> 400: 1.68 ihickson 401: <p>Many fundamental concepts from HTML are used by this 402: specification. <a href="#refsHTML">[HTML]</a></p> 1.1 ihickson 403: 404: </dd> 405: 406: <dt>WebIDL</dt> 407: 408: <dd> 409: 410: <p>The IDL blocks in this specification use the semantics of the 1.7 ihickson 411: WebIDL specification. <a href="#refsWEBIDL">[WEBIDL]</a></p> 1.1 ihickson 412: 413: </dd> 414: 1.10 ihickson 415: </dl><h2 id="terminology"><span class="secno">3 </span>Terminology</h2><p>The construction "a <code title="">Foo</code> object", where 1.1 ihickson 416: <code title="">Foo</code> is actually an interface, is sometimes 417: used instead of the more accurate "an object implementing the 1.10 ihickson 418: interface <code title="">Foo</code>".<p>The term DOM is used to refer to the API set made available to 1.1 ihickson 419: scripts in Web applications, and does not necessarily imply the 420: existence of an actual <code>Document</code> object or of any other 421: <code>Node</code> objects as defined in the DOM Core 1.33 ihickson 422: specifications. <a href="#refsDOMCORE">[DOMCORE]</a><p>An IDL attribute is said to be <em>getting</em> when its value is 1.1 ihickson 423: being retrieved (e.g. by author script), and is said to be 1.10 ihickson 424: <em>setting</em> when a new value is assigned to it.<p>The term "JavaScript" is used to refer to ECMA262, rather than 1.1 ihickson 425: the official term ECMAScript, since the term JavaScript is more 1.10 ihickson 426: widely known. <a href="#refsECMA262">[ECMA262]</a><h2 id="sql"><span class="secno">4 </span>The API</h2><h3 id="databases"><span class="secno">4.1 </span>Databases</h3><p>Each <i>origin</i> has an associated set of databases. Each 1.1 ihickson 427: database has a name and a current version. There is no way to 428: enumerate or delete the databases available for an origin from this 1.10 ihickson 429: API.<p class="note">Each database has one version at a time; a database 1.1 ihickson 430: can't exist in multiple versions at once. Versions are intended to 431: allow authors to manage schema changes incrementally and 432: non-destructively, and without running the risk of old code (e.g. in 433: another browser window) trying to write to a database with incorrect 1.10 ihickson 434: assumptions.<pre class="idl">[Supplemental, NoInterfaceObject] 1.5 ihickson 435: interface <span>WindowDatabase</span> { 1.16 ihickson 436: <a href="#database">Database</a> <a href="#dom-opendatabase" title="dom-opendatabase">openDatabase</a>(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in optional <a href="#databasecallback">DatabaseCallback</a> creationCallback); 1.1 ihickson 437: }; 1.5 ihickson 438: <span>Window</span> implements <span>WindowDatabase</span>; 1.1 ihickson 439: 1.5 ihickson 440: [Supplemental, NoInterfaceObject] 441: interface <span>WorkerUtilsDatabase</span> { 1.16 ihickson 442: <a href="#database">Database</a> <a href="#dom-opendatabase" title="dom-opendatabase">openDatabase</a>(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in optional <a href="#databasecallback">DatabaseCallback</a> creationCallback); 443: <a href="#databasesync">DatabaseSync</a> <a href="#dom-opendatabase-sync" title="dom-opendatabase-sync">openDatabaseSync</a>(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in optional <a href="#databasecallback">DatabaseCallback</a> creationCallback); 1.5 ihickson 444: }; 1.16 ihickson 445: <span>WorkerUtils</span> implements <span>WorkerUtilsDatabase</span>; 446: 447: [Callback=FunctionOnly, NoInterfaceObject] 448: interface <dfn id="databasecallback">DatabaseCallback</dfn> { 449: void <span title="dom-databasecallback-handleEvent">handleEvent</span>(in <a href="#database">Database</a> database); 450: };</pre><p>The <dfn id="dom-opendatabase" title="dom-opendatabase"><code>openDatabase()</code></dfn> method on 451: the <code>Window</code> and <code>WorkerUtils</code> interfaces and 452: the <dfn id="dom-opendatabase-sync" title="dom-opendatabase-sync"><code>openDatabaseSync()</code></dfn> 453: method on the <code>WorkerUtils</code> interface take the following 454: arguments: a database name, a database version, a display name, an 455: estimated size — in bytes — of the data that will be 456: stored in the database, and optionally a callback to be invoked if 1.17 ihickson 457: the database has not yet been created. The callback, if provided, is 458: intended to be used to call <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code>; the 459: callback is invoked with the database having the empty string as its 460: version regardless of the given database version. If the callback is 461: not provided, the database is created with the given database 462: version as its version.<p>When invoked, these methods must run the following steps, with all 463: but the last two steps being run atomically:<ol><li> 1.16 ihickson 464: 465: <p>The user agent may raise a <code>SECURITY_ERR</code> exception 466: instead of returning a <code><a href="#database">Database</a></code> object if the request 467: violates a policy decision (e.g. if the user agent is configured 468: to not allow the page to open databases).</p> 469: 470: </li> 471: 472: <li> 473: 474: <p>For the method on the <code>Window</code> object: let <var title="">origin</var> be the <span>origin</span> of the 475: <span>active document</span> of the <span>browsing context</span> 476: of the <code>Window</code> object on which the method was 477: invoked.</p> 478: 479: <p>For the methods on the <code>WorkerUtils</code> object: let 480: <var title="">origin</var> be the <span>origin</span> of the 481: scripts in the worker.</p> 482: 483: </li> 484: 1.65 ihickson 485: <li><p>If <var title="">origin</var> is not a scheme/host/port 486: tuple, then throw a <code>SECURITY_ERR</code> exception and abort 487: these steps.</li> 488: 1.16 ihickson 489: <li><p>If the database version provided is not the empty string, 490: and there is already a database with the given name from the origin 491: <var title="">origin</var>, but the database has a different 492: version than the version provided, then throw an 493: <code>INVALID_STATE_ERR</code> exception and abort these 494: steps.</li> 495: 496: <li> 497: 1.17 ihickson 498: <p>If no database with the given name from the origin <var title="">origin</var> exists, then create the database and let 1.30 ihickson 499: <var title="">created</var> be true. If a callback was passed to 500: the method, then set the new database's version to the empty 501: string. Otherwise, set the new database's version to the given 502: database version.</p> 1.17 ihickson 503: 1.30 ihickson 504: <p>Otherwise, if a database with the given name already exists, 505: let <var title="">created</var> be false.</p> 1.16 ihickson 506: 507: </li> 508: 509: <li> 510: 511: <p>For the <code title="dom-opendatabase"><a href="#dom-opendatabase">openDatabase()</a></code> 512: methods: let <var title="">result</var> be a newly constructed 513: <code><a href="#database">Database</a></code> object representing the database with the 514: given database name from the origin <var title="">origin</var>.</p> 515: 516: <p>For the <code title="dom-opendatabase-sync"><a href="#dom-opendatabase-sync">openDatabaseSync()</a></code> method: 517: let <var title="">result</var> be a newly constructed 518: <code><a href="#databasesync">DatabaseSync</a></code> object representing the database with 519: the given database name from the origin <var title="">origin</var>.</p> 520: 521: </li> 522: 523: <li> 524: 525: <p>If <var title="">created</var> is false or if no callback was 526: passed to the method, skip this step. Otherwise:</p> 527: 528: <p>For the <code title="dom-opendatabase"><a href="#dom-opendatabase">openDatabase()</a></code> 529: methods: <span>queue a task</span> to to invoke the callback with 530: <var title="">result</var> as its only argument.</p> 531: 532: <p>For the <code title="dom-opendatabase-sync"><a href="#dom-opendatabase-sync">openDatabaseSync()</a></code> method: 533: invoke the callback with <var title="">result</var> as its only 534: argument. If the callback throws an exception, rethrow that 535: exception and abort these steps.</p> 536: 537: </li> 538: 539: <li> 540: 541: <p>Return <var title="">result</var>.</p> 542: 543: </li> 544: 545: </ol><p>All strings including the empty string are valid database 1.1 ihickson 546: names. Database names must be compared in a 1.10 ihickson 547: <span>case-sensitive</span> manner.<p class="note">Implementations can support this even in 1.1 ihickson 548: environments that only support a subset of all strings as database 549: names by mapping database names (e.g. using a hashing algorithm) to 1.16 ihickson 550: the supported set of names.<p>The version that the database was opened with is the <dfn id="concept-database-expected-version" title="concept-database-expected-version">expected version</dfn> of 1.1 ihickson 551: this <code><a href="#database">Database</a></code> or <code><a href="#databasesync">DatabaseSync</a></code> object. It 552: can be the empty string, in which case there is no expected version 1.16 ihickson 553: — any version is fine.<p>User agents are expected to use the display name and the 1.1 ihickson 554: estimated database size to optimize the user experience. For 555: example, a user agent could use the estimated size to suggest an 556: initial quota to the user. This allows a site that is aware that it 557: will try to use hundreds of megabytes to declare this upfront, 558: instead of the user agent prompting the user for permission to 1.10 ihickson 559: increase the quota every five megabytes.<h3 id="parsing-and-processing-sql-statements"><span class="secno">4.2 </span>Parsing and processing SQL statements</h3><p>When the user agent is to <dfn id="preprocess-the-sql-statement" title="preprocess the SQL 560: statement">preprocess a SQL statement</dfn> <var title="">sqlStatement</var> with an array of arguments <var title="">arguments</var>, it must run the following steps:<ol><li><p>Parse <var title="">sqlStatement</var> as a SQL statement, 1.41 ihickson 561: with the exception that U+003F QUESTION MARK characters (?) can be 1.6 ihickson 562: used in place of SQL literals in the statement. <a href="#refsSQL">[SQL]</a></li> 1.1 ihickson 563: 564: <li> 565: 1.49 ihickson 566: <p>Bind each <code title="">?</code> placeholder with the value of 567: the argument in the <var title="">arguments</var> array with the 568: same position. (So the first <code title="">?</code> placeholder 569: gets bound to the first value in the <var title="">arguments</var> 570: array, and generally the <var title="">n</var>th <code title="">?</code> placeholder gets bound to the <var title="">n</var>th value in the <var title="">arguments</var> 571: array.)</p> 572: 573: <p class="note">Binding the <code title="">?</code> placeholders 574: is done at the literal level, not as string concatenations, so 575: this provides a way to dynamically insert parameters into a 576: statement without risk of a SQL injection attack.</p> 1.1 ihickson 577: 578: <p>The result is <var title="">the statement</var>.</p> 579: 580: </li> 581: 582: <li><p>If the <code><a href="#database">Database</a></code> object that the 583: <code><a href="#sqltransaction">SQLTransaction</a></code> or <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> 584: object was created from has an <a href="#concept-database-expected-version" title="concept-database-expected-version">expected version</a> 585: that is neither the empty string nor the actual version of the 586: database, then mark <var title="">the statement</var> as 587: bogus. (<a href="#dom-sqlerror-code-2" title="dom-sqlerror-code-2">Error code 588: 2</a>.)</li> 589: 590: <li> 591: 592: <p>Otherwise, if the syntax of <var title="">sqlStatement</var> is 593: not valid (except for the use of <code title="">?</code> 594: characters in the place of literals), or the statement uses 595: features that are not supported (e.g. due to security reasons), or 596: the number of items in the <var title="">arguments</var> array is 597: not equal to the number of <code title="">?</code> placeholders in 598: the statement, or the statement cannot be parsed for some other 599: reason, then mark <var title="">the statement</var> as 600: bogus. (<a href="#dom-sqlerror-code-5" title="dom-sqlerror-code-5">Error code 601: 5</a>.)</p> 602: 603: <p>User agents must consider statements that use the <code title="">BEGIN</code>, <code title="">COMMIT</code>, and <code title="">ROLLBACK</code> SQL features as being unsupported (and thus 604: will mark them as bogus), so as to not let these statements 605: interfere with the explicit transactions managed by the database API 606: itself.</p> 607: 608: </li> 609: 610: <li id="modifications-fail-if-read-only"> 611: 612: <p>Otherwise, if the <i>mode</i> that was used to create the 613: <code><a href="#sqltransaction">SQLTransaction</a></code> or <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> 614: object is read-only but the statement's main verb can modify the 615: database, mark the statement as bogus. (<a href="#dom-sqlerror-code-5" title="dom-sqlerror-code-5">Error code 5</a>.)</p> 616: 617: <p class="note">Only the statement's main verb (e.g. <code title="">UPDATE</code>, <code title="">SELECT</code>, <code title="">DROP</code>) is considered here. Thus, a statement like 618: "<code title="">UPDATE test SET id=0 WHERE 0=1</code>" would be 619: treated as potentially modifying the database for the purposes 620: of this step, even though it could never in fact have any 621: side-effects.</p> 622: 623: </li> 624: 625: <li><p>Return <var title="">the statement</var>.</li> 626: 1.10 ihickson 627: </ol><p>The user agent must act as if the database was hosted in an 1.1 ihickson 628: otherwise completely empty environment with no resources. For 629: example, attempts to read from or write to the file system will 1.10 ihickson 630: fail.<p class="note">A future version of this specification will probably 631: define the exact SQL subset required in more detail.<h3 id="asynchronous-database-api"><span class="secno">4.3 </span>Asynchronous database API</h3><pre class="idl">interface <dfn id="database">Database</dfn> { 1.34 ihickson 632: void <a href="#dom-database-transaction" title="dom-database-transaction">transaction</a>(in <a href="#sqltransactioncallback">SQLTransactionCallback</a> callback, in optional <a href="#sqltransactionerrorcallback">SQLTransactionErrorCallback</a> errorCallback, in optional <a href="#sqlvoidcallback">SQLVoidCallback</a> successCallback); 633: void <a href="#dom-database-readtransaction" title="dom-database-readTransaction">readTransaction</a>(in <a href="#sqltransactioncallback">SQLTransactionCallback</a> callback, in optional <a href="#sqltransactionerrorcallback">SQLTransactionErrorCallback</a> errorCallback, in optional <a href="#sqlvoidcallback">SQLVoidCallback</a> successCallback); 1.1 ihickson 634: 635: readonly attribute DOMString <a href="#dom-database-version" title="dom-database-version">version</a>; 1.25 ihickson 636: void <a href="#dom-database-changeversion" title="dom-database-changeVersion">changeVersion</a>(in DOMString oldVersion, in DOMString newVersion, in optional <a href="#sqltransactioncallback">SQLTransactionCallback</a> callback, in optional <a href="#sqltransactionerrorcallback">SQLTransactionErrorCallback</a> errorCallback, in optional <a href="#sqlvoidcallback">SQLVoidCallback</a> successCallback); 1.1 ihickson 637: }; 638: 639: [Callback=FunctionOnly, NoInterfaceObject] 640: interface <dfn id="sqlvoidcallback">SQLVoidCallback</dfn> { 641: void <span title="dom-sqlvoidcallback-handleEvent">handleEvent</span>(); 642: }; 643: 644: [Callback=FunctionOnly, NoInterfaceObject] 645: interface <dfn id="sqltransactioncallback">SQLTransactionCallback</dfn> { 646: void <span title="dom-sqltransactioncallback-handleEvent">handleEvent</span>(in <a href="#sqltransaction">SQLTransaction</a> transaction); 647: }; 648: 649: [Callback=FunctionOnly, NoInterfaceObject] 650: interface <dfn id="sqltransactionerrorcallback">SQLTransactionErrorCallback</dfn> { 651: void <span title="dom-sqltransactionerrorcallback-handleEvent">handleEvent</span>(in <a href="#sqlerror">SQLError</a> error); 1.10 ihickson 652: };</pre><p>The <dfn id="dom-database-transaction" title="dom-database-transaction"><code>transaction()</code></dfn> 1.1 ihickson 653: and <dfn id="dom-database-readtransaction" title="dom-database-readTransaction"><code>readTransaction()</code></dfn> 654: methods takes one to three arguments. When called, these methods must 655: immediately return and then asynchronously run the <a href="#transaction-steps">transaction 656: steps</a> with the <i>transaction callback</i> being the first 657: argument, the <i>error callback</i> being the second argument, if 658: any, the <i>success callback</i> being the third argument, if any, 659: and with no <i>preflight operation</i> or <i>postflight 1.10 ihickson 660: operation</i>.<p>For the <code title="dom-database-transaction"><a href="#dom-database-transaction">transaction()</a></code> method, the 1.1 ihickson 661: <i>mode</i> must be read/write. For the <code title="dom-database-readTransaction"><a href="#dom-database-readtransaction">readTransaction()</a></code> 1.10 ihickson 662: method, the <i>mode</i> must be read-only.<p>On getting, the <dfn id="dom-database-version" title="dom-database-version"><code>version</code></dfn> attribute 1.1 ihickson 663: must return the current version of the database (as opposed to the 664: <a href="#concept-database-expected-version" title="concept-database-expected-version">expected 1.10 ihickson 665: version</a> of the <code><a href="#database">Database</a></code> object).<p>The <dfn id="dom-database-changeversion" title="dom-database-changeVersion"><code>changeVersion()</code></dfn> 1.1 ihickson 666: method allows scripts to atomically verify the version number and 667: change it at the same time as doing a schema update. When the method 668: is invoked, it must immediately return, and then asynchronously run 669: the <a href="#transaction-steps">transaction steps</a> with the <i>transaction 670: callback</i> being the third argument, the <i>error callback</i> 671: being the fourth argument, the <i>success callback</i> being the 672: fifth argument, the <i>preflight operation</i> being the 1.10 ihickson 673: following:<ol><li><p>Check that the value of the first argument to the <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code> method 1.1 ihickson 674: exactly matches the database's actual version. If it does not, then 675: the <i>preflight operation</i> fails.</li> 676: 1.10 ihickson 677: </ol><p>...the <i>postflight operation</i> being the following:<ol><li>Change the database's actual version to the value of the second 1.1 ihickson 678: argument to the <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code> 679: method.</li> 680: 681: <li>Change the <code><a href="#database">Database</a></code> object's expected version to 682: the value of the second argument to the <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code> 683: method.</li> 684: 1.25 ihickson 685: </ol><p>...and the <i>mode</i> being read/write.<p>If any of the optional arguments are omitted, then they must be 686: treated as if they were null.<h4 id="executing-sql-statements"><span class="secno">4.3.1 </span>Executing SQL statements</h4><p>The <code title="dom-database-transaction"><a href="#dom-database-transaction">transaction()</a></code>, 1.1 ihickson 687: <code title="dom-database-readTransaction"><a href="#dom-database-readtransaction">readTransaction()</a></code>, 688: and <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code> 689: methods invoke callbacks with <code><a href="#sqltransaction">SQLTransaction</a></code> 1.10 ihickson 690: objects.<pre class="idl">typedef sequence<any> <dfn id="objectarray">ObjectArray</dfn>; 1.1 ihickson 691: 692: interface <dfn id="sqltransaction">SQLTransaction</dfn> { 1.34 ihickson 693: void <a href="#dom-sqltransaction-executesql" title="dom-sqltransaction-executeSql">executeSql</a>(in DOMString sqlStatement, in optional <a href="#objectarray">ObjectArray</a> arguments, in optional <a href="#sqlstatementcallback">SQLStatementCallback</a> callback, in optional <a href="#sqlstatementerrorcallback">SQLStatementErrorCallback</a> errorCallback); 1.1 ihickson 694: }; 695: 696: [Callback=FunctionOnly, NoInterfaceObject] 697: interface <dfn id="sqlstatementcallback">SQLStatementCallback</dfn> { 698: void <span title="dom-sqlstatementcallback-handleEvent">handleEvent</span>(in <a href="#sqltransaction">SQLTransaction</a> transaction, in <a href="#sqlresultset">SQLResultSet</a> resultSet); 699: }; 700: 701: [Callback=FunctionOnly, NoInterfaceObject] 702: interface <dfn id="sqlstatementerrorcallback">SQLStatementErrorCallback</dfn> { 703: boolean <span title="dom-sqlstatementerrorcallback-handleEvent">handleEvent</span>(in <a href="#sqltransaction">SQLTransaction</a> transaction, in <a href="#sqlerror">SQLError</a> error); 1.10 ihickson 704: };</pre><p>When the <dfn id="dom-sqltransaction-executesql" title="dom-sqltransaction-executeSql"><code>executeSql(<var title="">sqlStatement</var>, <var title="">arguments</var>, <var title="">callback</var>, <var title="">errorCallback</var>)</code></dfn> method is invoked, the 1.1 ihickson 705: user agent must run the following algorithm. (This algorithm is 706: relatively simple in that it doesn't actually execute any SQL 1.10 ihickson 707: — the bulk of the work is actually done as part of the 708: <a href="#transaction-steps">transaction steps</a>.)<ol><li><p>If the method was not invoked during the execution of a 1.1 ihickson 709: <code><a href="#sqltransactioncallback">SQLTransactionCallback</a></code>, 710: <code><a href="#sqlstatementcallback">SQLStatementCallback</a></code>, or 711: <code><a href="#sqlstatementerrorcallback">SQLStatementErrorCallback</a></code> then raise an 712: <code>INVALID_STATE_ERR</code> exception. (Calls from inside a 713: <code><a href="#sqltransactionerrorcallback">SQLTransactionErrorCallback</a></code> thus raise an 714: exception. The <code><a href="#sqltransactionerrorcallback">SQLTransactionErrorCallback</a></code> handler is 715: only called once a transaction has failed, and no SQL statements 716: can be added to a failed transaction.)</li> 717: 718: <li> 719: 720: <p><a href="#preprocess-the-sql-statement">Preprocess the SQL statement</a> given as the first 721: argument to the method (<var title="">sqlStatement</var>), using 722: the second argument to the method as the <var title="">arguments</var> array, to obtain <var title="">the 723: statement</var>.</p> 724: 725: <p>If the second argument is omitted or null, then treat the <var title="">arguments</var> array as empty.</p> 726: 727: </li> 728: 729: <li><p>Queue up <var title="">the statement</var> in the 730: transaction, along with the third argument (if any) as the 731: statement's result set callback and the fourth argument (if any) as 732: the error callback.</li> 733: 1.10 ihickson 734: </ol><h4 id="processing-model"><span class="secno">4.3.2 </span>Processing model</h4><p>The <dfn id="transaction-steps">transaction steps</dfn> are as follows. These steps must 1.1 ihickson 735: be run asynchronously. These steps are invoked with a <i>transaction 736: callback</i>, optionally an <i>error callback</i>, optionally a 737: <i>success callback</i>, optionally a <i>preflight operation</i>, 738: optionally a <i>postflight operation</i>, and with a <i>mode</i> 1.10 ihickson 739: that is either read/write or read-only.<ol><li><p>Open a new SQL transaction to the database, and create a 1.1 ihickson 740: <code><a href="#sqltransaction">SQLTransaction</a></code> object that represents that 741: transaction. If the <i>mode</i> is read/write, the transaction must 742: have an exclusive write lock over the entire database. If the 743: <i>mode</i> is read-only, the transaction must have a shared read 744: lock over the entire database. The user agent should wait for an 745: appropriate lock to be available.</li> 746: 747: <li><p>If an error occurred in the opening of the transaction 748: (e.g. if the user agent failed to obtain an appropriate lock after 749: an appropriate delay), jump to the last step.</li> 750: 751: <li><p>If a <i>preflight operation</i> was defined for this 752: instance of the transaction steps, run that. If it fails, then jump 753: to the last step. (This is basically a hook for the <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code> 754: method.)</li> 755: 1.25 ihickson 756: <li><p>If the <i>transaction callback</i> is not null, <span>queue 757: a task</span> to invoke the <i>transaction callback</i> with the 758: aforementioned <code><a href="#sqltransaction">SQLTransaction</a></code> object as its only 759: argument, and wait for that task to be run.</li> 1.1 ihickson 760: 1.25 ihickson 761: <li><p>If the callback raised an exception, jump to the last 1.1 ihickson 762: step.</li> 1.25 ihickson 763: 1.1 ihickson 764: <li><p>While there are any statements queued up in the transaction, 765: perform the following steps for each queued up statement in the 766: transaction, oldest first. Each statement has a statement, 767: optionally a result set callback, and optionally an error 768: callback.</p> 769: 1.10 ihickson 770: <ol><li><p>If the statement is marked as bogus, jump to the "in case 1.1 ihickson 771: of error" steps below.</li> 772: 773: <li><p>Execute the statement in the context of the transaction. 1.6 ihickson 774: <a href="#refsSQL">[SQL]</a></p> 1.1 ihickson 775: 776: <li><p>If the statement failed, jump to the "in case of error" 777: steps below.</li> 778: 779: <li><p>Create a <code><a href="#sqlresultset">SQLResultSet</a></code> object that represents 780: the result of the statement.</li> 781: 1.25 ihickson 782: <li><p>If the statement has a result set callback that is not 783: null, <span>queue a task</span> to invoke it with the 784: <code><a href="#sqltransaction">SQLTransaction</a></code> object as its first argument and the 785: new <code><a href="#sqlresultset">SQLResultSet</a></code> object as its second argument, and 786: wait for that task to be run.</li> 1.1 ihickson 787: 788: <li><p>If the callback was invoked and raised an exception, jump 789: to the last step in the overall steps.</li> 790: 791: <li><p>Move on to the next statement, if any, or onto the next 792: overall step otherwise.</li> 793: 1.10 ihickson 794: </ol><p>In case of error (or more specifically, if the above substeps 1.1 ihickson 795: say to jump to the "in case of error" steps), run the following 796: substeps:</p> 797: 1.25 ihickson 798: <ol><li><p>If the statement had an associated error callback that is 799: not null, then <span>queue a task</span> to invoke that error 800: callback with the <code><a href="#sqltransaction">SQLTransaction</a></code> object and a newly 801: constructed <code><a href="#sqlerror">SQLError</a></code> object that represents the 802: error that caused these substeps to be run as the two arguments, 1.1 ihickson 803: respectively, and wait for the task to be run.</li> 804: 805: <li><p>If the error callback returns false, then move on to the 806: next statement, if any, or onto the next overall step 807: otherwise.</li> 808: 809: <li><p>Otherwise, the error callback did not return false, or 810: there was no error callback. Jump to the last step in the overall 811: steps.</li> 812: 1.10 ihickson 813: </ol></li> 1.1 ihickson 814: 1.15 ihickson 815: <li> 1.1 ihickson 816: 1.15 ihickson 817: <p>If a <i>postflight operation</i> was defined for this instance 818: of the transaction steps, then: as one atomic operation, commit 1.66 ihickson 819: the transaction and, if that succeeds, run the <i>postflight 820: operation</i>. If the commit fails, then instead jump to the last 821: step. (This is basically a hook for the <code title="dom-database-changeVersion"><a href="#dom-database-changeversion">changeVersion()</a></code> 1.15 ihickson 822: method.)</p> 823: 1.66 ihickson 824: <p>Otherwise: commit the transaction. If an error occurred in the 825: committing of the transaction, jump to the last step.</p> 1.1 ihickson 826: 1.15 ihickson 827: </li> 1.1 ihickson 828: 829: <li><p><span>Queue a task</span> to invoke the <i>success 1.25 ihickson 830: callback</i>, if it is not null.</li> 1.1 ihickson 831: 832: <li><p>End these steps. The next step is only used when something 833: goes wrong.</li> 834: 1.48 ihickson 835: <li><p><span>Queue a task</span> to invoke the transaction's 836: <i>error callback</i>, if it is not null, with a newly constructed 1.25 ihickson 837: <code><a href="#sqlerror">SQLError</a></code> object that represents the last error to have 838: occurred in this transaction. Rollback the transaction. Any 839: still-pending statements in the transaction are discarded.</li> 1.1 ihickson 840: 1.35 ihickson 841: </ol><p>The <span>task source</span> for these <span title="concept-task">tasks</span> is the <dfn id="database-access-task-source">database access task 1.28 ihickson 842: source</dfn>.<h3 id="synchronous-database-api"><span class="secno">4.4 </span>Synchronous database API</h3><pre class="idl">interface <dfn id="databasesync">DatabaseSync</dfn> { 1.11 ihickson 843: void <a href="#dom-database-sync-transaction" title="dom-database-sync-transaction">transaction</a>(in <a href="#sqltransactionsynccallback">SQLTransactionSyncCallback</a> callback); 844: void <a href="#dom-database-sync-readtransaction" title="dom-database-sync-readTransaction">readTransaction</a>(in <a href="#sqltransactionsynccallback">SQLTransactionSyncCallback</a> callback); 1.1 ihickson 845: 846: readonly attribute DOMString <a href="#dom-database-sync-version" title="dom-database-sync-version">version</a>; 1.34 ihickson 847: void <a href="#dom-database-sync-changeversion" title="dom-database-sync-changeVersion">changeVersion</a>(in DOMString oldVersion, in DOMString newVersion, in optional <a href="#sqltransactionsynccallback">SQLTransactionSyncCallback</a> callback); 1.11 ihickson 848: }; 849: 850: [Callback=FunctionOnly, NoInterfaceObject] 851: interface <dfn id="sqltransactionsynccallback">SQLTransactionSyncCallback</dfn> { 852: void <span title="dom-sqltransactionsynccallback-handleEvent">handleEvent</span>(in <a href="#sqltransactionsync">SQLTransactionSync</a> transaction); 1.10 ihickson 853: };</pre><p>The <dfn id="dom-database-sync-transaction" title="dom-database-sync-transaction"><code>transaction()</code></dfn> 1.11 ihickson 854: and <dfn id="dom-database-sync-readtransaction" title="dom-database-sync-readTransaction"><code>readTransaction()</code></dfn> 855: methods must run the following steps:<ol><li><p>If the method was the <code title="dom-database-sync-transaction"><a href="#dom-database-sync-transaction">transaction()</a></code> method, 856: <a href="#create-a-sqltransactionsync-object">create a <code>SQLTransactionSync</code> object</a> for a 857: read/write transaction. Otherwise, <a href="#create-a-sqltransactionsync-object">create a 858: <code>SQLTransactionSync</code> object</a> for a read-only 859: transaction. In either case, if this throws an exception, then 860: rethrow it and abort these steps. Otherwise, let <var title="">transaction</var> be the newly created 861: <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object.</li> 862: 863: <li><p>If the first argument is null, rollback the transaction, 864: throw a <code><a href="#sqlexception">SQLException</a></code> exception, and abort these 865: steps. (<a href="#dom-sqlerror-code-0" title="dom-sqlerror-code-0">Error code 866: 0</a>.)</li> 867: 868: <li><p>Invoke the callback given by the first argument, passing it 869: the <var title="">transaction</var> object as its only 870: argument.</li> 871: 872: <li><p>Mark the <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object as <i title="">stale</i>.</p> 873: 874: <li><p>If the callback was terminated by an exception, then 875: rollback the transaction, rethrow that exception, and abort these 876: steps.</li> 877: 878: <li><p>Commit the transaction.</li> 879: 880: <li><p>If an error occurred in the committing of the transaction, 881: rollback the transaction, throw a <code><a href="#sqlexception">SQLException</a></code> 882: exception, and abort these steps.</li> 883: 884: </ol><p>On getting, the <dfn id="dom-database-sync-version" title="dom-database-sync-version"><code>version</code></dfn> 1.1 ihickson 885: attribute must return the current version of the database (as 886: opposed to the <a href="#concept-database-expected-version" title="concept-database-expected-version">expected version</a> of 1.10 ihickson 887: the <code><a href="#databasesync">DatabaseSync</a></code> object).<p>The <dfn id="dom-database-sync-changeversion" title="dom-database-sync-changeVersion"><code>changeVersion()</code></dfn> 1.1 ihickson 888: method allows scripts to atomically verify the version number and 889: change it at the same time as doing a schema update. When the method 1.10 ihickson 890: is invoked, it must run the following steps:<ol><li><p><a href="#create-a-sqltransactionsync-object">Create a <code>SQLTransactionSync</code> object</a> 1.1 ihickson 891: for a read/write transaction. If this throws an exception, then 1.11 ihickson 892: rethrow it and abort these steps. Otherwise, let <var title="">transaction</var> be the newly created 893: <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object.</li> 1.1 ihickson 894: 895: <li><p>Check that the value of the first argument to the <code title="dom-database-sync-changeVersion"><a href="#dom-database-sync-changeversion">changeVersion()</a></code> 896: method exactly matches the database's actual version. If it does 1.11 ihickson 897: not, then throw a <code><a href="#sqlexception">SQLException</a></code> exception and abort 1.1 ihickson 898: these steps. (<a href="#dom-sqlerror-code-2" title="dom-sqlerror-code-2">Error code 899: 2</a>.)</li> 900: 1.25 ihickson 901: <li><p>If the third argument is not null, invoke the callback given 902: by the third argument, passing it the <var title="">transaction</var> object as its only argument.</li> 1.11 ihickson 903: 904: <li><p>Mark the <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object as <i title="">stale</i>.</p> 905: 906: <li><p>If the callback was terminated by an exception, then 907: rollback the transaction, rethrow the exception, and abort these 908: steps.</li> 1.1 ihickson 909: 1.11 ihickson 910: <li><p>Commit the transaction.</li> 911: 912: <li><p>If an error occurred in the committing of the transaction, 913: rollback the transaction, throw a <code><a href="#sqlexception">SQLException</a></code> 914: exception, and abort these steps.</li> 915: 916: <li>Change the database's actual version to the value of the second 1.1 ihickson 917: argument to the <code title="dom-database-sync-changeVersion"><a href="#dom-database-sync-changeversion">changeVersion()</a></code> 918: method.</li> 919: 920: <li>Change the <code><a href="#database">Database</a></code> object's expected version to 921: the value of the second argument to the <code title="dom-database-sync-changeVersion"><a href="#dom-database-sync-changeversion">changeVersion()</a></code> 922: method.</li> 923: 1.10 ihickson 924: </ol><hr><p>When the user agent is to <dfn id="create-a-sqltransactionsync-object">create a 1.1 ihickson 925: <code>SQLTransactionSync</code> object</dfn> for a transaction that 926: is either read/write or read-only, it must run the following 1.10 ihickson 927: steps:<ol><li><p>Open a new SQL transaction to the database, and create a 1.1 ihickson 928: <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object that represents that 929: transaction. If the <i>mode</i> is read/write, the transaction must 930: have an exclusive write lock over the entire database. If the 931: <i>mode</i> is read-only, the transaction must have a shared read 932: lock over the entire database. The user agent should wait for an 933: appropriate lock to be available.</li> 934: 935: <li><p>If an error occurred in the opening of the transaction 936: (e.g. if the user agent failed to obtain an appropriate lock after 937: an appropriate delay), throw a <code><a href="#sqlexception">SQLException</a></code> exception 938: and abort these steps.</li> 939: 940: <li><p>Return the newly created <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> 941: object.</li> 942: 1.10 ihickson 943: </ol><h4 id="executing-sql-statements-0"><span class="secno">4.4.1 </span>Executing SQL statements</h4><p>The <code title="dom-database-sync-transaction"><a href="#dom-database-sync-transaction">transaction()</a></code>, <code title="dom-database-sync-readTransaction"><a href="#dom-database-sync-readtransaction">readTransaction()</a></code>, 1.1 ihickson 944: and <code title="dom-database-sync-changeVersion"><a href="#dom-database-sync-changeversion">changeVersion()</a></code> 1.25 ihickson 945: methods invoke callbacks that are passed 946: <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> objects.<pre class="idl">// typedef sequence<any> <a href="#objectarray">ObjectArray</a>; 1.1 ihickson 947: 948: interface <dfn id="sqltransactionsync">SQLTransactionSync</dfn> { 1.34 ihickson 949: <a href="#sqlresultset">SQLResultSet</a> <a href="#dom-sqltransaction-sync-executesql" title="dom-sqltransaction-sync-executeSql">executeSql</a>(in DOMString sqlStatement, in optional <a href="#objectarray">ObjectArray</a> arguments); 1.10 ihickson 950: };</pre><p>A <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object is initially <i title="">fresh</i>, but it will be marked as <i title="">stale</i> 951: once it has been committed or rolled back.<p>When the <dfn id="dom-sqltransaction-sync-executesql" title="dom-sqltransaction-sync-executeSql"><code>executeSql(<var title="">sqlStatement</var>, <var title="">arguments</var>)</code></dfn> method is invoked, the user 952: agent must run the following algorithm:<ol><li><p>If the <code><a href="#sqltransactionsync">SQLTransactionSync</a></code> object is <i title="">stale</i>, then throw an <code>INVALID_STATE_ERR</code> 1.1 ihickson 953: exception.</li> 954: 955: <li> 956: 957: <p><a href="#preprocess-the-sql-statement">Preprocess the SQL statement</a> given as the first 958: argument to the method (<var title="">sqlStatement</var>), using 959: the second argument to the method as the <var title="">arguments</var> array, to obtain <var title="">the 960: statement</var>.</p> 961: 962: <p>If the second argument is omitted or null, then treat the <var title="">arguments</var> array as empty.</p> 963: 964: </li> 965: 966: <li><p>If the statement is marked as bogus, throw a 967: <code><a href="#sqlexception">SQLException</a></code> exception.</li> 968: 969: <li><p>Execute the statement in the context of the transaction. 1.6 ihickson 970: <a href="#refsSQL">[SQL]</a></p> 1.1 ihickson 971: 972: <li><p>If the statement failed, throw a <code><a href="#sqlexception">SQLException</a></code> 973: exception.</li> 974: 975: <li><p>Create a <code><a href="#sqlresultset">SQLResultSet</a></code> object that represents 976: the result of the statement.</li> 977: 978: <li><p>Return the newly created <code><a href="#sqlresultset">SQLResultSet</a></code> 979: object.</li> 980: 1.11 ihickson 981: </ol><h3 id="database-query-results"><span class="secno">4.5 </span>Database query results</h3><p>The <code title="dom-sqltransaction-executeSql"><a href="#dom-sqltransaction-executesql">executeSql()</a></code> 1.1 ihickson 982: method invokes its callback with a <code><a href="#sqlresultset">SQLResultSet</a></code> object 1.10 ihickson 983: as an argument.<pre class="idl">interface <dfn id="sqlresultset">SQLResultSet</dfn> { 1.1 ihickson 984: readonly attribute long <a href="#dom-sqlresultset-insertid" title="dom-SQLResultSet-insertId">insertId</a>; 985: readonly attribute long <a href="#dom-sqlresultset-rowsaffected" title="dom-SQLResultSet-rowsAffected">rowsAffected</a>; 986: readonly attribute <a href="#sqlresultsetrowlist">SQLResultSetRowList</a> <a href="#dom-sqlresultset-rows" title="dom-SQLResultSet-rows">rows</a>; 1.10 ihickson 987: };</pre><p>The <dfn id="dom-sqlresultset-insertid" title="dom-SQLResultSet-insertId"><code>insertId</code></dfn> 1.1 ihickson 988: attribute must return the row ID of the row that the 989: <code><a href="#sqlresultset">SQLResultSet</a></code> object's SQL statement inserted into the 990: database, if the statement inserted a row. If the statement inserted 991: multiple rows, the ID of the last row must be the one returned. If 992: the statement did not insert a row, then the attribute must instead 1.10 ihickson 993: raise an <code>INVALID_ACCESS_ERR</code> exception.<p>The <dfn id="dom-sqlresultset-rowsaffected" title="dom-SQLResultSet-rowsAffected"><code>rowsAffected</code></dfn> 1.1 ihickson 994: attribute must return the number of rows that were changed by the 995: SQL statement. If the statement did not affected any rows, then the 996: attribute must return zero. For "SELECT" statements, this returns 1.10 ihickson 997: zero (querying the database doesn't affect any rows).<p>The <dfn id="dom-sqlresultset-rows" title="dom-SQLResultSet-rows"><code>rows</code></dfn> 1.1 ihickson 998: attribute must return a <code><a href="#sqlresultsetrowlist">SQLResultSetRowList</a></code> 999: representing the rows returned, in the order returned by the 1.71 ihickson 1000: database. The same object must be returned each time. If no rows 1001: were returned, then the object will be empty (its <code title="dom-SQLResultSetRowList-length"><a href="#dom-sqlresultsetrowlist-length">length</a></code> will be 1002: zero).<pre class="idl">interface <dfn id="sqlresultsetrowlist">SQLResultSetRowList</dfn> { 1.1 ihickson 1003: readonly attribute unsigned long <a href="#dom-sqlresultsetrowlist-length" title="dom-SQLResultSetRowList-length">length</a>; 1.5 ihickson 1004: getter <span>any</span> <a href="#dom-sqlresultsetrowlist-item" title="dom-SQLResultSetRowList-item">item</a>(in unsigned long index); 1.47 ihickson 1005: };</pre><p class="note">For the asynchronous API, implementors are 1006: encouraged to prefetch all the data for 1007: <code><a href="#sqlresultsetrowlist">SQLResultSetRowList</a></code> objects when the object is 1008: constructed (before the result set callback is invoked), rather than 1009: on-demand, for better responsiveness. For the synchronous API, an 1010: on-demand lazy evaluation implementation strategy is encouraged 1011: instead, for better performance.<p><code><a href="#sqlresultsetrowlist">SQLResultSetRowList</a></code> objects have a <dfn id="dom-sqlresultsetrowlist-length" title="dom-SQLResultSetRowList-length"><code>length</code></dfn> 1.1 ihickson 1012: attribute that must return the number of rows it represents (the 1.10 ihickson 1013: number of rows returned by the database). This is the <var title="dom-SQLResultSetRowList-length"><a href="#dom-sqlresultsetrowlist-length">length</a></var>.<p class="note">Fetching the <code title="dom-SQLResultSetRowList-length"><a href="#dom-sqlresultsetrowlist-length">length</a></code> might be 1.1 ihickson 1014: expensive, and authors are thus encouraged to avoid using it (or 1015: enumerating over the object, which implicitly uses it) where 1.10 ihickson 1016: possible.<p>The object's <span>indices of the supported indexed 1.1 ihickson 1017: properties</span> are the numbers in the range zero to <span title=""><var title="dom-SQLResultSetRowList-length"><a href="#dom-sqlresultsetrowlist-length">length</a></var>-1</span>, unless 1018: the <var title="dom-SQLResultSetRowList-length"><a href="#dom-sqlresultsetrowlist-length">length</a></var> is 1019: zero, in which case there are no <span>supported indexed 1.10 ihickson 1020: properties</span>.<p>The <dfn id="dom-sqlresultsetrowlist-item" title="dom-SQLResultSetRowList-item"><code>item(<var title="">index</var>)</code></dfn> attribute must return the row 1.1 ihickson 1021: with the given index <var title="">index</var>. If there is no such 1.10 ihickson 1022: row, then the method must return null.<p>Each row must be represented by a native ordered dictionary data 1.1 ihickson 1023: type. In the JavaScript binding, this must be <code>Object</code>. 1024: Each row object must have one property (or dictionary entry) per 1025: column, with those properties enumerating in the order that these 1026: columns were returned by the database. Each property must have the 1027: name of the column and the value of the cell, as they were returned 1.10 ihickson 1028: by the database.<h3 id="errors-and-exceptions"><span class="secno">4.6 </span>Errors and exceptions</h3><p>Errors in the asynchronous database API are reported using 1.1 ihickson 1029: callbacks that have a <code><a href="#sqlerror">SQLError</a></code> object as one of their 1.10 ihickson 1030: arguments.<pre class="idl">interface <dfn id="sqlerror">SQLError</dfn> { 1.9 ihickson 1031: const unsigned short <a href="#dom-sqlexception-code-unknown" title="dom-SQLException-code-UNKNOWN">UNKNOWN_ERR</a> = 0; 1032: const unsigned short <a href="#dom-sqlexception-code-database" title="dom-SQLException-code-DATABASE">DATABASE_ERR</a> = 1; 1033: const unsigned short <a href="#dom-sqlexception-code-version" title="dom-SQLException-code-VERSION">VERSION_ERR</a> = 2; 1034: const unsigned short <a href="#dom-sqlexception-code-too_large" title="dom-SQLException-code-TOO_LARGE">TOO_LARGE_ERR</a> = 3; 1035: const unsigned short <a href="#dom-sqlexception-code-quota" title="dom-SQLException-code-QUOTA">QUOTA_ERR</a> = 4; 1036: const unsigned short <a href="#dom-sqlexception-code-syntax" title="dom-SQLException-code-SYNTAX">SYNTAX_ERR</a> = 5; 1037: const unsigned short <a href="#dom-sqlexception-code-constraint" title="dom-SQLException-code-CONSTRAINT">CONSTRAINT_ERR</a> = 6; 1038: const unsigned short <a href="#dom-sqlexception-code-timeout" title="dom-SQLException-code-TIMEOUT">TIMEOUT_ERR</a> = 7; 1039: readonly attribute unsigned short <a href="#dom-sqlerror-code" title="dom-SQLError-code">code</a>; 1.1 ihickson 1040: readonly attribute DOMString <a href="#dom-sqlerror-message" title="dom-SQLError-message">message</a>; 1.24 ihickson 1041: };</pre><p>The <dfn id="dom-sqlerror-code" title="dom-SQLError-code"><code>code</code></dfn> IDL 1.1 ihickson 1042: attribute must return the most appropriate code from the table 1.10 ihickson 1043: below.<p>The <dfn id="dom-sqlerror-message" title="dom-SQLError-message"><code>message</code></dfn> 1.24 ihickson 1044: IDL attribute must return an error message describing the error 1.1 ihickson 1045: encountered. The message should be localized to the user's 1.10 ihickson 1046: language.<hr><p>Errors in the synchronous database API are reported using 1047: <code><a href="#sqlexception">SQLException</a></code> exceptions:<pre class="idl">exception <dfn id="sqlexception">SQLException</dfn> { 1.9 ihickson 1048: const unsigned short <a href="#dom-sqlexception-code-unknown" title="dom-SQLException-code-UNKNOWN">UNKNOWN_ERR</a> = 0; 1049: const unsigned short <a href="#dom-sqlexception-code-database" title="dom-SQLException-code-DATABASE">DATABASE_ERR</a> = 1; 1050: const unsigned short <a href="#dom-sqlexception-code-version" title="dom-SQLException-code-VERSION">VERSION_ERR</a> = 2; 1051: const unsigned short <a href="#dom-sqlexception-code-too_large" title="dom-SQLException-code-TOO_LARGE">TOO_LARGE_ERR</a> = 3; 1052: const unsigned short <a href="#dom-sqlexception-code-quota" title="dom-SQLException-code-QUOTA">QUOTA_ERR</a> = 4; 1053: const unsigned short <a href="#dom-sqlexception-code-syntax" title="dom-SQLException-code-SYNTAX">SYNTAX_ERR</a> = 5; 1054: const unsigned short <a href="#dom-sqlexception-code-constraint" title="dom-SQLException-code-CONSTRAINT">CONSTRAINT_ERR</a> = 6; 1055: const unsigned short <a href="#dom-sqlexception-code-timeout" title="dom-SQLException-code-TIMEOUT">TIMEOUT_ERR</a> = 7; 1056: unsigned short <a href="#dom-sqlexception-code" title="dom-SQLException-code">code</a>; 1.1 ihickson 1057: DOMString <a href="#dom-sqlexception-message" title="dom-SQLException-message">message</a>; 1.10 ihickson 1058: };</pre><p>The <dfn id="dom-sqlexception-code" title="dom-SQLException-code"><code>code</code></dfn> 1.24 ihickson 1059: IDL attribute must return the most appropriate code from the table 1060: below.<p>The <dfn id="dom-sqlexception-message" title="dom-SQLException-message"><code>message</code></dfn> IDL 1.1 ihickson 1061: attribute must return an error message describing the error 1062: encountered. The message should be localized to the user's 1.10 ihickson 1063: language.<hr><p>The error codes are as follows:<table><thead><tr><th>Constant 1.6 ihickson 1064: <th>Code 1.1 ihickson 1065: <th>Situation 1.10 ihickson 1066: <tbody><tr><td><dfn id="dom-sqlexception-code-unknown" title="dom-SQLException-code-UNKNOWN"><code>UNKNOWN_ERR</code></dfn> 1.6 ihickson 1067: <td><dfn id="dom-sqlerror-code-0" title="dom-sqlerror-code-0">0</dfn> 1.1 ihickson 1068: <td>The transaction failed for reasons unrelated to the database 1069: itself and not covered by any other error code. 1070: 1.10 ihickson 1071: <tr><td><dfn id="dom-sqlexception-code-database" title="dom-SQLException-code-DATABASE"><code>DATABASE_ERR</code></dfn> 1.6 ihickson 1072: <td><dfn id="dom-sqlerror-code-1" title="dom-sqlerror-code-1">1</dfn> 1.1 ihickson 1073: <td>The statement failed for database reasons not covered by any 1074: other error code. 1075: 1.10 ihickson 1076: <tr><td><dfn id="dom-sqlexception-code-version" title="dom-SQLException-code-VERSION"><code>VERSION_ERR</code></dfn> 1.6 ihickson 1077: <td><dfn id="dom-sqlerror-code-2" title="dom-sqlerror-code-2">2</dfn> 1.1 ihickson 1078: <td>The operation failed because the actual database version was 1079: not what it should be. For example, a statement found that the 1080: actual database version no longer matched the <a href="#concept-database-expected-version" title="concept-database-expected-version">expected version</a> 1081: of the <code><a href="#database">Database</a></code> or <code><a href="#databasesync">DatabaseSync</a></code> object, 1082: or the <code title="dom-database-changeversion"><a href="#dom-database-changeversion">Database.changeVersion()</a></code> 1083: or <code title="dom-database-sync-changeversion"><a href="#dom-database-sync-changeversion">DatabaseSync.changeVersion()</a></code> 1084: methods were passed a version that doesn't match the actual 1085: database version. 1086: 1.10 ihickson 1087: <tr><td><dfn id="dom-sqlexception-code-too_large" title="dom-SQLException-code-TOO_LARGE"><code>TOO_LARGE_ERR</code></dfn> 1.6 ihickson 1088: <td><dfn id="dom-sqlerror-code-3" title="dom-sqlerror-code-3">3</dfn> 1.1 ihickson 1089: <td>The statement failed because the data returned from the 1090: database was too large. The SQL "LIMIT" modifier might be useful 1091: to reduce the size of the result set. 1092: 1.10 ihickson 1093: <tr><td><dfn id="dom-sqlexception-code-quota" title="dom-SQLException-code-QUOTA"><code>QUOTA_ERR</code></dfn> 1.6 ihickson 1094: <td><dfn id="dom-sqlerror-code-4" title="dom-sqlerror-code-4">4</dfn> 1.1 ihickson 1095: <td>The statement failed because there was not enough remaining 1096: storage space, or the storage quota was reached and the user 1097: declined to give more space to the database. 1098: 1.10 ihickson 1099: <tr><td><dfn id="dom-sqlexception-code-syntax" title="dom-SQLException-code-SYNTAX"><code>SYNTAX_ERR</code></dfn> 1.6 ihickson 1100: <td><dfn id="dom-sqlerror-code-5" title="dom-sqlerror-code-5">5</dfn> 1.1 ihickson 1101: <td>The statement failed because of a syntax error, or the number 1102: of arguments did not match the number of <code title="">?</code> 1103: placeholders in the statement, or the statement tried to use a 1104: statement that is not allowed, such as <code title="">BEGIN</code>, <code title="">COMMIT</code>, or <code title="">ROLLBACK</code>, or the statement tried to use a verb 1105: that could modify the database but the transaction was read-only. 1106: 1.10 ihickson 1107: <tr><td><dfn id="dom-sqlexception-code-constraint" title="dom-SQLException-code-CONSTRAINT"><code>CONSTRAINT_ERR</code></dfn> 1.6 ihickson 1108: <td><dfn id="dom-sqlerror-code-6" title="dom-sqlerror-code-6">6</dfn> 1.1 ihickson 1109: <td>An <code title="">INSERT</code>, <code title="">UPDATE</code>, or <code title="">REPLACE</code> 1110: statement failed due to a constraint failure. For example, 1111: because a row was being inserted and the value given for the 1112: primary key column duplicated the value of an existing row. 1113: 1.10 ihickson 1114: <tr><td><dfn id="dom-sqlexception-code-timeout" title="dom-SQLException-code-TIMEOUT"><code>TIMEOUT_ERR</code></dfn> 1.6 ihickson 1115: <td><dfn id="dom-sqlerror-code-7" title="dom-sqlerror-code-7">7</dfn> 1.1 ihickson 1116: <td>A lock for the transaction could not be obtained in a 1117: reasonable time. 1118: 1.51 ihickson 1119: </table><h2 id="web-sql"><span class="secno">5 </span>Web SQL</h2><p>User agents must implement the SQL dialect supported by Sqlite 3.6.19.<p>When converting bound arguments to SQL data types, the JavaScript 1.64 ihickson 1120: ToPrimitive abstract operation must be applied to obtain the raw 1121: value to be processed. <a href="#refsECMA262">[ECMA262]</a>.<h2 id="disk-space"><span class="secno">6 </span>Disk space</h2><p>User agents should limit the total amount of space allowed for 1.1 ihickson 1122: databases. 1123: 1124: <p>User agents should guard against sites storing data under the 1125: origins other affiliated sites, e.g. storing up to the limit in 1126: a1.example.com, a2.example.com, a3.example.com, etc, circumventing 1.10 ihickson 1127: the main example.com storage limit.<p>User agents may prompt the user when quotas are reached, allowing 1.1 ihickson 1128: the user to grant a site more space. This enables sites to store 1129: many user-created documents on the user's computer, for 1.10 ihickson 1130: instance.<p>User agents should allow users to see how much space each domain 1131: is using.<p>A mostly arbitrary limit of five megabytes per 1.1 ihickson 1132: <span>origin</span> is recommended. Implementation feedback is 1133: welcome and will be used to update this suggestion in the 1.19 ihickson 1134: future.<h2 id="privacy"><span class="secno">7 </span>Privacy</h2><h3 id="user-tracking"><span class="secno">7.1 </span>User tracking</h3><p>A third-party advertiser (or any entity capable of getting 1.1 ihickson 1135: content distributed to multiple sites) could use a unique identifier 1136: stored in its 1.39 ihickson 1137: client-side databases 1.1 ihickson 1138: 1.45 ihickson 1139: 1.1 ihickson 1140: to track a user across multiple sessions, building a profile of the 1141: user's interests to allow for highly targeted advertising. In 1142: conjunction with a site that is aware of the user's real identity 1143: (for example an e-commerce site that requires authenticated 1144: credentials), this could allow oppressive groups to target 1145: individuals with greater accuracy than in a world with purely 1.10 ihickson 1146: anonymous Web usage.<p>There are a number of techniques that can be used to mitigate the 1147: risk of user tracking:<dl><dt>Blocking third-party storage</dt> 1.1 ihickson 1148: <dd> 1149: 1150: <p>User agents may restrict access to 1151: the database objects 1152: 1.45 ihickson 1153: 1.1 ihickson 1154: to scripts originating at the domain of the top-level document of 1155: the <span>browsing context</span>, for instance denying access to 1156: the API for pages from other domains running in 1157: <code>iframe</code>s.</p> 1158: 1159: </dd> 1160: 1161: <dt>Expiring stored data</dt> 1162: <dd> 1163: 1.40 ihickson 1164: <p>User agents may, if so configured by the user, automatically 1165: delete stored data after a period of time.</p> 1.1 ihickson 1166: 1167: 1168: <p>This can restrict the ability of a site to track a user, as the 1169: site would then only be able to track the user across multiple 1170: sessions when he authenticates with the site itself (e.g. by 1171: making a purchase or logging in to a service).</p> 1172: 1.40 ihickson 1173: <p>However, this also reduces the usefulness of the API as a 1174: long-term storage mechanism. It can also put the user's data at 1175: risk, if the user does not fully understand the implications of 1176: data expiration.</p> 1.1 ihickson 1177: 1178: 1179: </dd> 1180: 1181: <dt>Treating persistent storage as cookies</dt> 1182: <dd> 1183: 1.31 ihickson 1184: <p>If users attempt to protect their privacy by clearing cookies 1185: without also clearing data stored in the 1.39 ihickson 1186: relevant databases, 1187: 1188: sites can defeat those attempts by using the two features as 1189: redundant backup for each other. User agents should present the 1.31 ihickson 1190: interfaces for clearing these in a way that helps users to 1191: understand this possibility and enables them to delete data in all 1192: persistent storage features simultaneously. <a href="#refsCOOKIES">[COOKIES]</a></p> 1.1 ihickson 1193: 1194: </dd> 1195: 1196: <dt>Site-specific white-listing of access to 1197: databases 1198: 1.45 ihickson 1199: 1.1 ihickson 1200: </dt> 1201: <dd> 1202: 1203: <p>User agents may require the user to authorize access to 1204: databases before a site can use the feature.</p> 1205: 1.45 ihickson 1206: 1.1 ihickson 1207: 1208: </dd> 1209: 1210: <dt>Origin-tracking of stored data</dt> 1211: <dd> 1212: 1213: <p>User agents may record the <span title="origin">origins</span> 1214: of sites that contained content from third-party origins that 1215: caused data to be stored.</p> 1216: 1217: <p>If this information is then used to present the view of data 1218: currently in persistent storage, it would allow the user to make 1219: informed decisions about which parts of the persistent storage to 1220: prune. Combined with a blacklist ("delete this data and prevent 1221: this domain from ever storing data again"), the user can restrict 1222: the use of persistent storage to sites that he trusts.</p> 1223: 1224: </dd> 1225: 1226: <dt>Shared blacklists</dt> 1227: <dd> 1228: 1229: <p>User agents may allow users to share their persistent storage 1230: domain blacklists.</p> 1231: 1232: <p>This would allow communities to act together to protect their 1233: privacy.</p> 1234: 1235: </dd> 1236: 1.10 ihickson 1237: </dl><p>While these suggestions prevent trivial use of this API for user 1.1 ihickson 1238: tracking, they do not block it altogether. Within a single domain, a 1239: site can continue to track the user during a session, and can then 1240: pass all this information to the third party along with any 1241: identifying information (names, credit card numbers, addresses) 1242: obtained by the site. If a third party cooperates with multiple 1243: sites to obtain such information, a profile can still be 1.10 ihickson 1244: created.<p>However, user tracking is to some extent possible even with no 1.1 ihickson 1245: cooperation from the user agent whatsoever, for instance by using 1246: session identifiers in URLs, a technique already commonly used for 1247: innocuous purposes but easily repurposed for user tracking (even 1248: retroactively). This information can then be shared with other 1249: sites, using using visitors' IP addresses and other user-specific 1250: data (e.g. user-agent headers and configuration settings) to combine 1.31 ihickson 1251: separate sessions into coherent user profiles.<h3 id="sensitivity-of-data"><span class="secno">7.2 </span>Sensitivity of data</h3><p>User agents should treat persistently stored data as potentially 1.13 ihickson 1252: sensitive; it's quite possible for e-mails, calendar appointments, 1253: health records, or other confidential documents to be stored in this 1254: mechanism.<p>To this end, user agents should ensure that when deleting data, 1.19 ihickson 1255: it is promptly deleted from the underlying storage.<h2 id="security"><span class="secno">8 </span>Security</h2><h3 id="dns-spoofing-attacks"><span class="secno">8.1 </span>DNS spoofing attacks</h3><p>Because of the potential for DNS spoofing attacks, one cannot 1.1 ihickson 1256: guarantee that a host claiming to be in a certain domain really is 1257: from that domain. To mitigate this, pages can use SSL. Pages using 1258: SSL can be sure that only pages using SSL that have certificates 1259: identifying them as being from the same domain can access their 1260: databases. 1261: 1.19 ihickson 1262: <h3 id="cross-directory-attacks"><span class="secno">8.2 </span>Cross-directory attacks</h3><p>Different authors sharing one host name, for example users 1.1 ihickson 1263: hosting content on <code>geocities.com</code>, all share one 1264: set of databases. 1265: 1266: There is no feature to restrict the access by pathname. Authors on 1267: shared hosts are therefore recommended to avoid using these 1268: features, as it would be trivial for other authors to read the data 1.10 ihickson 1269: and overwrite it.<p class="note">Even if a path-restriction feature was made 1.1 ihickson 1270: available, the usual DOM scripting security model would make it 1271: trivial to bypass this protection and access the data from any 1.19 ihickson 1272: path.<h3 id="implementation-risks"><span class="secno">8.3 </span>Implementation risks</h3><p>The two primary risks when implementing these persistent storage 1.1 ihickson 1273: features are letting hostile sites read information from other 1274: domains, and letting hostile sites write information that is then 1.10 ihickson 1275: read from other domains.<p>Letting third-party sites read data that is not supposed to be 1.1 ihickson 1276: read from their domain causes <em>information leakage</em>, For 1277: example, a user's shopping wishlist on one domain could be used by 1278: another domain for targeted advertising; or a user's 1279: work-in-progress confidential documents stored by a word-processing 1.10 ihickson 1280: site could be examined by the site of a competing company.<p>Letting third-party sites write data to the persistent storage of 1.1 ihickson 1281: other domains can result in <em>information spoofing</em>, which is 1282: equally dangerous. For example, a hostile site could add items to a 1283: user's wishlist; or a hostile site could set a user's session 1284: identifier to a known ID that the hostile site can then use to track 1.10 ihickson 1285: the user's actions on the victim site.<p>Thus, strictly following the <span>origin</span> model described 1.19 ihickson 1286: in this specification is important for user security.<h3 id="sql-and-user-agents"><span class="secno">8.4 </span>SQL and user agents</h3><p>User agent implementors are strongly encouraged to audit all 1.1 ihickson 1287: their supported SQL statements for security implications. For 1288: example, <code title="">LOAD DATA INFILE</code> is likely to pose 1.10 ihickson 1289: security risks and there is little reason to support it.<p>In general, it is recommended that user agents not support 1.1 ihickson 1290: features that control how databases are stored on disk. For example, 1291: there is little reason to allow Web authors to control the character 1292: encoding used in the disk representation of the data, as all data in 1.19 ihickson 1293: JavaScript is implicitly UTF-16.<h3 id="sql-injection"><span class="secno">8.5 </span>SQL injection</h3><p>Authors are strongly recommended to make use of the <code title="">?</code> placeholder feature of the <code title="dom-sqltransaction-executeSql"><a href="#dom-sqltransaction-executesql">executeSql()</a></code> method, 1.68 ihickson 1294: and to never construct SQL statements on the fly.<h2 class="no-num" id="references">References</h2><!--REFS--><p>All references are normative unless marked "Non-normative".</p><!-- Dates are only included for standards older than the Web, 1295: because the newer ones keep changing. --><dl><dt id="refsCOOKIES">[COOKIES]</dt> 1.7 ihickson 1296: <!-- 1.38 ihickson 1297: <dd><cite><a href="http://www.ietf.org/rfc/rfc2109.txt">HTTP State 1.68 ihickson 1298: Management Mechanism</a></cite>, D. Kristol, L. Montulli. IETF.</dd> 1.7 ihickson 1299: <dd><cite><a href="http://www.ietf.org/rfc/rfc2965.txt">HTTP State Management 1.68 ihickson 1300: Mechanism</a></cite>, D. Kristol, L. Montulli. IETF.</dd> 1.7 ihickson 1301: --> 1302: <dd><cite><a href="http://tools.ietf.org/html/draft-abarth-cookie">HTTP State 1.68 ihickson 1303: Management Mechanism</a></cite>, A. Barth. IETF.</dd> 1.7 ihickson 1304: 1305: <dt id="refsDOMCORE">[DOMCORE]</dt> 1306: <dd><cite><a href="http://www.w3.org/TR/DOM-Level-3-Core/">Document 1307: Object Model (DOM) Level 3 Core Specification</a></cite>, A. Le 1308: Hors, P. Le Hegaret, L. Wood, G. Nicol, J. Robie, M. Champion, 1.68 ihickson 1309: S. Byrnes. W3C.</dd> 1.7 ihickson 1310: <!-- 1311: <dd><cite><a href="http://simon.html5.org/specs/web-dom-core">Web 1.68 ihickson 1312: DOM Core</a></cite>, S. Pieters. W3C.</dd> 1.7 ihickson 1313: --> 1314: 1.6 ihickson 1315: <dt id="refsECMA262">[ECMA262]</dt> 1316: <dd><cite><a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript 1.68 ihickson 1317: Language Specification</a></cite>. ECMA.</dd> 1.6 ihickson 1318: 1.68 ihickson 1319: <dt id="refsHTML">[HTML]</dt> 1320: <dd><cite><a href="http://www.whatwg.org/specs/web-apps/current-work/">HTML</a></cite>, 1321: I. Hickson. WHATWG.</dd> 1.8 ihickson 1322: 1323: <dt id="refsRFC2119">[RFC2119]</dt> 1324: <dd><cite><a href="http://www.ietf.org/rfc/rfc2119.txt">Key words for use in 1.68 ihickson 1325: RFCs to Indicate Requirement Levels</a></cite>, S. Bradner. IETF.</dd> 1.8 ihickson 1326: 1.6 ihickson 1327: <dt id="refsSQL">[SQL]</dt> 1328: <dd>The precise dialect has not yet been specified.</dd> 1329: 1.8 ihickson 1330: <dt id="refsWEBIDL">[WEBIDL]</dt> 1331: <!-- 1332: <dd><cite><a href="http://www.w3.org/TR/WebIDL/">Web 1.68 ihickson 1333: IDL</a></cite>, C. McCormack. W3C.</dd> 1.8 ihickson 1334: --> 1335: <dd><cite><a href="http://dev.w3.org/2006/webapi/WebIDL/">Web 1.68 ihickson 1336: IDL</a></cite>, C. McCormack. W3C.</dd> 1.8 ihickson 1337: 1.61 ihickson 1338: </dl>