author | Wes Johnston <wjohnston@mozilla.com> |
Mon, 27 Feb 2012 10:10:16 -0800 | |
changeset 87850 | 289cd639ff3418020d6adb18153a1b0b4c9de552 |
parent 87849 | 00929ec6099170cb7c22169bf9ea5e7db85630f2 |
child 87851 | 2cd9b8fc084d3a04c819454c10c79c7af10b5258 |
push id | 22160 |
push user | mbrubeck@mozilla.com |
push date | Tue, 28 Feb 2012 17:21:33 +0000 |
treeherder | mozilla-central@dde4e0089a18 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dolske |
bugs | 725881 |
milestone | 13.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/components/satchel/Makefile.in +++ b/toolkit/components/satchel/Makefile.in @@ -62,20 +62,23 @@ LOCAL_INCLUDES = \ $(NULL) CPPSRCS = \ nsFormFillController.cpp \ $(NULL) EXTRA_COMPONENTS = \ nsFormAutoComplete.js \ - nsFormHistory.js \ nsInputListAutoComplete.js \ satchel.manifest \ $(NULL) +EXTRA_PP_COMPONENTS = \ + nsFormHistory.js \ + $(NULL) + EXTRA_JS_MODULES = \ nsFormAutoCompleteResult.jsm \ $(NULL) TEST_DIRS += test include $(topsrcdir)/config/rules.mk
--- a/toolkit/components/satchel/nsFormHistory.js +++ b/toolkit/components/satchel/nsFormHistory.js @@ -38,17 +38,17 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -const DB_VERSION = 3; +const DB_VERSION = 4; const DAY_IN_MS = 86400000; // 1 day in milliseconds function FormHistory() { this.init(); } FormHistory.prototype = { classID : Components.ID("{0c1bb408-71a2-403f-854a-3a0659829ded}"), @@ -69,16 +69,21 @@ FormHistory.prototype = { "id" : "INTEGER PRIMARY KEY", "fieldname" : "TEXT NOT NULL", "value" : "TEXT NOT NULL", "timesUsed" : "INTEGER", "firstUsed" : "INTEGER", "lastUsed" : "INTEGER", "guid" : "TEXT" }, + moz_deleted_formhistory: { + "id" : "INTEGER PRIMARY KEY", + "timeDeleted" : "INTEGER", + "guid" : "TEXT" + } }, indices : { moz_formhistory_index : { table : "moz_formhistory", columns : ["fieldname"] }, moz_formhistory_lastused_index : { table : "moz_formhistory", @@ -240,74 +245,101 @@ FormHistory.prototype = { let [id, guid] = this.getExistingEntryID(name, value); this.sendStringNotification("before-removeEntry", name, value, guid); let stmt; let query = "DELETE FROM moz_formhistory WHERE id = :id"; let params = { id : id }; try { + this.dbConnection.beginTransaction(); + this.moveToDeletedTable("VALUES (:guid, :timeDeleted)", { + guid: guid, + timeDeleted: Date.now() + }); + + // remove from the formhistory database stmt = this.dbCreateStatement(query, params); stmt.execute(); this.sendStringNotification("removeEntry", name, value, guid); } catch (e) { + this.dbConnection.rollbackTransaction(); this.log("removeEntry failed: " + e); throw e; } finally { if (stmt) { stmt.reset(); } } + this.dbConnection.commitTransaction(); }, removeEntriesForName : function (name) { this.log("removeEntriesForName with name=" + name); this.sendStringNotification("before-removeEntriesForName", name); let stmt; let query = "DELETE FROM moz_formhistory WHERE fieldname = :fieldname"; let params = { fieldname : name }; try { + this.dbConnection.beginTransaction(); + this.moveToDeletedTable( + "SELECT guid, :timeDeleted FROM moz_formhistory " + + "WHERE fieldname = :fieldname", { + fieldname: name, + timeDeleted: Date.now() + }); + stmt = this.dbCreateStatement(query, params); stmt.execute(); this.sendStringNotification("removeEntriesForName", name); } catch (e) { + this.dbConnection.rollbackTransaction(); this.log("removeEntriesForName failed: " + e); throw e; } finally { if (stmt) { stmt.reset(); } } + this.dbConnection.commitTransaction(); }, removeAllEntries : function () { this.log("removeAllEntries"); this.sendNotification("before-removeAllEntries", null); let stmt; let query = "DELETE FROM moz_formhistory"; try { + this.dbConnection.beginTransaction(); + this.moveToDeletedTable( + "SELECT guid, :timeDeleted FROM moz_formhistory", { + timeDeleted: Date.now() + }); + stmt = this.dbCreateStatement(query); stmt.execute(); this.sendNotification("removeAllEntries", null); } catch (e) { + this.dbConnection.rollbackTransaction(); this.log("removeEntriesForName failed: " + e); throw e; } finally { if (stmt) { stmt.reset(); } } + this.dbConnection.commitTransaction(); }, nameExists : function (name) { this.log("nameExists for name=" + name); let stmt; let query = "SELECT COUNT(1) AS numEntries FROM moz_formhistory WHERE fieldname = :fieldname"; let params = { fieldname : name }; @@ -339,28 +371,59 @@ FormHistory.prototype = { let stmt; let query = "DELETE FROM moz_formhistory WHERE firstUsed >= :beginTime AND firstUsed <= :endTime"; let params = { beginTime : beginTime, endTime : endTime }; try { + this.dbConnection.beginTransaction(); + this.moveToDeletedTable( + "SELECT guid, :timeDeleted FROM moz_formhistory " + + "WHERE firstUsed >= :beginTime AND firstUsed <= :endTime", { + beginTime: beginTime, + endTime: endTime + }); + stmt = this.dbCreateStatement(query, params); stmt.executeStep(); this.sendIntNotification("removeEntriesByTimeframe", beginTime, endTime); } catch (e) { this.log("removeEntriesByTimeframe failed: " + e); throw e; } finally { if (stmt) { stmt.reset(); } } + this.dbConnection.commitTransaction(); + }, + moveToDeletedTable : function (values, params) { +#ifdef ANDROID + this.log("move entries to deleted"); + + let stmt; + + try { + // move the entry to the deleted items table + let query = "INSERT INTO moz_deleted_formhistory (guid, timeDeleted) "; + if (values) query += values; + stmt = this.dbCreateStatement(query, params); + stmt.execute(); + } catch (e) { + this.log("move entry failed: " + e); + throw e; + } finally { + if (stmt) { + stmt.reset(); + } + } +#endif }, get dbConnection() { // Make sure dbConnection can't be called from now to prevent infinite loops. delete FormHistory.prototype.dbConnection; try { this.dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile).clone(); @@ -642,31 +705,35 @@ FormHistory.prototype = { this.dbMigrate(version); }, dbCreate: function () { this.log("Creating DB -- tables"); for (let name in this.dbSchema.tables) { let table = this.dbSchema.tables[name]; - let tSQL = [[col, table[col]].join(" ") for (col in table)].join(", "); - this.dbConnection.createTable(name, tSQL); + this.dbCreateTable(name, table); } this.log("Creating DB -- indices"); for (let name in this.dbSchema.indices) { let index = this.dbSchema.indices[name]; let statement = "CREATE INDEX IF NOT EXISTS " + name + " ON " + index.table + "(" + index.columns.join(", ") + ")"; this.dbConnection.executeSimpleSQL(statement); } this.dbConnection.schemaVersion = DB_VERSION; }, + dbCreateTable: function(name, table) { + let tSQL = [[col, table[col]].join(" ") for (col in table)].join(", "); + this.log("Creating table " + name + " with " + tSQL); + this.dbConnection.createTable(name, tSQL); + }, dbMigrate : function (oldVersion) { this.log("Attempting to migrate from version " + oldVersion); if (oldVersion > DB_VERSION) { this.log("Downgrading to version " + DB_VERSION); // User's DB is newer. Sanity check that our expected columns are // present, and if so mark the lower version and merrily continue @@ -815,16 +882,21 @@ FormHistory.prototype = { } finally { if (stmt) { stmt.reset(); } } } }, + dbMigrateToVersion4 : function () { + if (!this.dbConnection.tableExists("moz_deleted_formhistory")) { + this.dbCreateTable("moz_deleted_formhistory", this.dbSchema.tables.moz_deleted_formhistory); + } + }, /* * dbAreExpectedColumnsPresent * * Sanity check to ensure that the columns this version of the code expects * are present in the DB we're using. */ dbAreExpectedColumnsPresent : function () {
new file mode 100644 index 0000000000000000000000000000000000000000..e0e8fe2468da9844ef8c1e853271d0408651800f GIT binary patch literal 5120 zc$^Ck^vNtqRY=P(%1ta$FlJz3U}R))P*7lCVBiE|Rt5xM0b)iZK8VfCfFE!&=suF? z1!-p7$-u0`w1deA$QT8bgK`#jaYt>&M*hsal+=pc{Hl0R9A;z|m*f{!#;2ENro>~D zVRa62bqsM;@bq(WjZna?O~Ky}T~<K@B(2%V%*-zC3A9-rtIauy#U-W1sn~62!D~CJ zR;(@nDG3EC(JW$O7dOZ0eQbivc<sh*Wm;xxPD);4ZmMQuAS1iDwl-r^WJzLDPAZy8 zG%gd=x)4VvA6HCMGgE*L32}9I4N?dQ^7M5Kid67+jnq+q+ollW8WE!4=MTi8K0Z1M zWr;bZ7=k64xv9mV@PHWxGN1?&L<k{Rpdmy+5eYU+6O=cZm=`cGp8yi0U=)mkK?T&9 zI2a_Q8QItvK!t*?6Sx@Abz)>-X}-G6X=fyiHe-aU(*>(@gs5|50m;wY_-zM>p2a+w zH6=YIF(|F7I3&;CKgzt^n~MRI|6egMe+3ewU=)mkVG6jIB^e=Q2os#?$Oy^*&ls3L z1Bp>E3P!;&1U$@a@D>9Tj00*8AoBk+=GO!5%26;1Mgc7V3o`>FlL)geBYN|n5dc|h B5=sC7
new file mode 100644 index 0000000000000000000000000000000000000000..8eab177e97f759e9749c58011afed48d111c85f8 GIT binary patch literal 6144 zc%1E+zi!h&7{Kp*j*S}r2norm82ZTrs+DAbN_6OgLo8%9IMldO!x9<UX)W1_6gw2U z86JTNCSHLBwQs-+@B$1SU_nAK<BMx2P3<tDqUe6I&%W=zKj-szr?a2#w7tlM{%{o7 z5o{nHVT>LCAcU&PDWEBp<is;|dQZ?|s;KdG?HV=4RYdCCF?SE2;ObwjE{C{Q5v8py z90!s8+;@ZFQO|LGH*%dG9i9U(jE19EC1T;Bsi~F*mfCD<AeU&#urBK@8Fa(a9%&{# zG4;o)*@bPb3t)6CFm~H*sDr#e_8b{3ZO=+7kr%kF)LCw-9P*;1)^L2o8#wMu8gC{} zkJ|T&S}JG#)Qy(52jynaG3Hxgoi-~mA)=%wk=F_%`*s+OL$^3OzcBiF)50E5mEA-| z8F8YtS^D@zLb5P+dC0!!`p&=(TqWMYqExHl*WElp<`QG3%AHGy3tl~^C<*G2N1MF- zJSXb#!uH1(gfufkIv$xb>R^-((NvTT+EhYc<iwXk=O#x!Ao4jW7!1aL#U1VnTD^@0 z0ntUF(VQ#;jV4C?n=hZ5C*ACNAD`(pCVFbBr}DJ@-N)a@^!lE>tvLIRZT62sYtZRD z+dSM}L3I9qL*!RdFc^#_WreKbbPeJ1TNS7C{}hp*Nx@(+mXNDN$af4}R-xO0>HI$> t-!HqD3<l$0z!QYITcm;KxBr-a|6}q4B?p7SSaPmo9^Dk~Ze;%j{s5eCQKbL?
index f1462cb243c60230b8fafff2b9ca848886d2a799..14279f05ff4e078e38f75e6b35e223bfc5976806 GIT binary patch literal 6144 zc%1E5y>HV%6u%EUfl4h)QB+lkQzWEDNz|ktNl+IY*R)Ynhd3^6$`HB4X$^6sCQiS$ zFu)&BiGcwjbzx#-goTNP0Wp9CLcmZ7W;P@^*We^hQrKEl|KzjZy}RG@@1A^Ty<9e} z87e7Ns=8v3alilw!4*OP00XpnKoe(aLoIy>06qXmV*rFdU+l*<z(NAxEA$gR#P=Zi z3+n`-5oEo-sVUgd4P~XQ>XqF>Q7x;6S}d43ThnSrrMlC@?cpVXlLaDk$+STHJ!bjI zh+ixENlKK389^e~q|`ho<;k3oCq&H1L|jOxNr?DY>*h3BSdwYS&~$a$3T9ISjd|$x z1%vQT)>i9K+0sRA>Kub)L@Rbv6e1-}Ef?1nT_x#^ICGto_*qU0kxivsceqT6wS}5$ z2Qtakn$hkmD^8EO&ckH}3fN;VXRDd}x~}gOx^<b3)wB%uT1}veyuNr4HqL45MRnVe zgF-ha{{5bmI4vwWvt}_!M(j+dowfk|ss<fj8MDQBeOyl+W<t7(VUHBkq;*wf4hQ=2 zdBCE5fFI#C^d9Zw$Z_m47cP1t&YS^57of)zHn&fhKRju|{1^nxje!>*o<I2WOzM^8 ziH)e3-Q?>^m0yVCuEb~uaksXvEiRYD++=2cabi)$Z^3X6F)^0L9JXT$R!jkzp*}sm z%UI9*Uv8`Q{LPe}$mVBO5^`iUhT3>Zi<j(>A{(QrSt+q0jVqbuEH@W}Z9LB6aUHx! zMp-p(ZEfeux%AZ%SEW)%{w2A6w6XXlz~Av#{1LyQrVAG?{x|gDA!r>*tZnj4)5Nx! zM7GJneoBS-2cVY=7cNc_5JdFYIH3RkJ%C^1J^T!R!;g<!l?xZA8iP0touv$8Iy=e~ z)9EZ2km+<*1CWM24B;$GSo8mn@DqUF(VGhwE>184hymfabIV7^#wR9Y@x<jwU(>t< R>C{o@K`<GkGomfiegR?6r>Ot{
--- a/toolkit/components/satchel/test/unit/head_satchel.js +++ b/toolkit/components/satchel/test/unit/head_satchel.js @@ -33,17 +33,17 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ const Ci = Components.interfaces; const Cc = Components.classes; -const CURRENT_SCHEMA = 3; +const CURRENT_SCHEMA = 4; const PR_HOURS = 60 * 60 * 1000000; do_get_profile(); var dirSvc = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties); function getDBVersion(dbfile) {
new file mode 100644 --- /dev/null +++ b/toolkit/components/satchel/test/unit/test_db_update_v4.js @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var testnum = 0; +var fh; + +function run_test() +{ + try { + + // ===== test init ===== + var testfile = do_get_file("formhistory_v3.sqlite"); + var profileDir = dirSvc.get("ProfD", Ci.nsIFile); + + // Cleanup from any previous tests or failures. + var destFile = profileDir.clone(); + destFile.append("formhistory.sqlite"); + if (destFile.exists()) + destFile.remove(false); + + testfile.copyTo(profileDir, "formhistory.sqlite"); + do_check_eq(3, getDBVersion(testfile)); + + fh = Cc["@mozilla.org/satchel/form-history;1"]. + getService(Ci.nsIFormHistory2); + + + // ===== 1 ===== + testnum++; + + // Check that the index was added + do_check_true(fh.DBConnection.tableExists("moz_deleted_formhistory")); + // check for upgraded schema. + do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion); + // check that an entry still exists + do_check_true(fh.entryExists("name-A", "value-A")); + + } catch (e) { + throw "FAILED in test #" + testnum + " -- " + e; + } +}
new file mode 100644 --- /dev/null +++ b/toolkit/components/satchel/test/unit/test_db_update_v4b.js @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var testnum = 0; +var fh; + +function run_test() +{ + try { + + // ===== test init ===== + var testfile = do_get_file("formhistory_v3v4.sqlite"); + var profileDir = dirSvc.get("ProfD", Ci.nsIFile); + + // Cleanup from any previous tests or failures. + var destFile = profileDir.clone(); + destFile.append("formhistory.sqlite"); + if (destFile.exists()) + destFile.remove(false); + + testfile.copyTo(profileDir, "formhistory.sqlite"); + do_check_eq(3, getDBVersion(testfile)); + + fh = Cc["@mozilla.org/satchel/form-history;1"]. + getService(Ci.nsIFormHistory2); + + + // ===== 1 ===== + testnum++; + + // Check that the index was added + do_check_true(fh.DBConnection.tableExists("moz_deleted_formhistory")); + // check for upgraded schema. + do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion); + // check that an entry still exists + do_check_true(fh.entryExists("name-A", "value-A")); + + } catch (e) { + throw "FAILED in test #" + testnum + " -- " + e; + } +}
--- a/toolkit/components/satchel/test/unit/xpcshell.ini +++ b/toolkit/components/satchel/test/unit/xpcshell.ini @@ -8,13 +8,15 @@ tail = skip-if = os == "android" [test_db_corrupt.js] [test_db_update_v1.js] [test_db_update_v1b.js] [test_db_update_v2.js] [test_db_update_v2b.js] [test_db_update_v3.js] [test_db_update_v3b.js] +[test_db_update_v4.js] +[test_db_update_v4b.js] [test_db_update_v999a.js] [test_db_update_v999b.js] [test_expire.js] [test_history_api.js] [test_notify.js]