Bug 328532 r=bryner Normalize annotation names in a separate table, migration

code from alpha1.
This commit is contained in:
brettw%gmail.com 2006-04-07 19:50:33 +00:00
parent 17b624959b
commit c945ce38f4
3 changed files with 238 additions and 23 deletions

View File

@ -79,7 +79,7 @@ nsAnnotationService::nsAnnotationService()
nsAnnotationService::~nsAnnotationService()
{
NS_ASSERTION(gAnnotationService == this,
NS_ASSERTION(gAnnotationService == this,
"Deleting a non-singleton annotation service");
if (gAnnotationService == this)
gAnnotationService = nsnull;
@ -102,23 +102,67 @@ nsAnnotationService::Init()
mDBConn = history->GetStorageConnection();
// annotation statements
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_anno SET mime_type = ?4, content = ?5, flags = ?6, expiration = ?7 WHERE anno_id = ?1"),
getter_AddRefs(mDBSetAnnotation));
// mDBSetAnnotation
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_anno "
"SET mime_type = ?4, content = ?5, flags = ?6, expiration = ?7 "
"WHERE anno_id = ?1"),
getter_AddRefs(mDBSetAnnotation));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM moz_anno WHERE page = ?1 AND name = ?2"),
getter_AddRefs(mDBGetAnnotation));
// mDBGetAnnotation
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * "
"FROM moz_anno "
"WHERE page = ?1 AND name_id = "
"(SELECT name_id FROM moz_anno_name WHERE name = ?2)"),
getter_AddRefs(mDBGetAnnotation));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT name FROM moz_anno WHERE page = ?1"),
getter_AddRefs(mDBGetAnnotationNames));
// mDBGetAnnotationNames
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT n.name "
"FROM moz_anno a LEFT JOIN moz_anno_name n ON a.name_id = n.name_id "
"WHERE a.page = ?1"),
getter_AddRefs(mDBGetAnnotationNames));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT a.anno_id, a.page, a.name, a.mime_type, a.content, a.flags, a.expiration FROM moz_history h JOIN moz_anno a ON h.id = a.page WHERE h.url = ?1 AND a.name = ?2"),
getter_AddRefs(mDBGetAnnotationFromURI));
// mDBGetAnnotationFromURI
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT a.anno_id, a.page, ?2, a.mime_type, a.content, a.flags, a.expiration "
"FROM moz_history h JOIN moz_anno a ON h.id = a.page "
"WHERE h.url = ?1 AND a.name_id = "
"(SELECT name_id FROM moz_anno_name WHERE name = ?2)"),
getter_AddRefs(mDBGetAnnotationFromURI));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_anno (page, name, mime_type, content, flags, expiration) VALUES (?2, ?3, ?4, ?5, ?6, ?7)"),
getter_AddRefs(mDBAddAnnotation));
// mDBGetAnnotationNameID
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT name_id FROM moz_anno_name WHERE name = ?1"),
getter_AddRefs(mDBGetAnnotationNameID));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_anno WHERE page = ?1 AND name = ?2"),
getter_AddRefs(mDBRemoveAnnotation));
// mDBAddAnnotationName
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_anno_name (name) VALUES (?1)"),
getter_AddRefs(mDBAddAnnotationName));
NS_ENSURE_SUCCESS(rv, rv);
// mDBAddAnnotation
// Note: kAnnoIndex_Name here is a name ID and not a string like the getters
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_anno "
"(page, name_id, mime_type, content, flags, expiration) "
"VALUES (?2, ?3, ?4, ?5, ?6, ?7)"),
getter_AddRefs(mDBAddAnnotation));
NS_ENSURE_SUCCESS(rv, rv);
// mDBRemoveAnnotation
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"DELETE FROM moz_anno WHERE page = ?1 AND name_id = "
"(SELECT name_id FROM moz_anno_name WHERE name = ?2)"),
getter_AddRefs(mDBRemoveAnnotation));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -139,13 +183,14 @@ nsAnnotationService::InitTables(mozIStorageConnection* aDBConn)
{
nsresult rv;
PRBool exists;
PRBool migrateFromAlpha1 = PR_FALSE;
rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_anno"), &exists);
NS_ENSURE_SUCCESS(rv, rv);
if (! exists) {
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE moz_anno ("
"anno_id INTEGER PRIMARY KEY,"
"page INTEGER NOT NULL,"
"name VARCHAR(32) NOT NULL,"
"name_id INTEGER,"
"mime_type VARCHAR(32) DEFAULT NULL,"
"content LONGVARCHAR, flags INTEGER DEFAULT 0,"
"expiration INTEGER DEFAULT 0)"));
@ -154,7 +199,31 @@ nsAnnotationService::InitTables(mozIStorageConnection* aDBConn)
"CREATE INDEX moz_anno_pageindex ON moz_anno (page)"));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX moz_anno_nameindex ON moz_anno (name)"));
"CREATE INDEX moz_anno_nameindex ON moz_anno (name_id)"));
NS_ENSURE_SUCCESS(rv, rv);
} else {
rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_anno_name"), &exists);
NS_ENSURE_SUCCESS(rv, rv);
if (! exists)
migrateFromAlpha1 = PR_TRUE;
}
rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_anno_name"), &exists);
NS_ENSURE_SUCCESS(rv, rv);
if (! exists) {
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE moz_anno_name ("
"name_id INTEGER PRIMARY KEY,"
"name VARCHAR(32) UNIQUE NOT NULL)"));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX moz_anno_name_nameindex ON moz_anno_name (name)"));
NS_ENSURE_SUCCESS(rv, rv);
}
// this needs to happen after moz_anno_name gets created
if (migrateFromAlpha1) {
rv = MigrateFromAlpha1(aDBConn);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -451,7 +520,10 @@ nsAnnotationService::GetPagesWithAnnotation(const nsACString& aName,
// statement. Perhaps this should change.
nsCOMPtr<mozIStorageStatement> statement;
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT h.url FROM moz_anno a JOIN moz_history h ON a.page = h.id WHERE a.name = ?1"),
"SELECT h.url FROM moz_anno_name n "
"LEFT JOIN moz_anno a ON n.name_id = a.name_id "
"LEFT JOIN moz_history h ON a.page = h.id "
"WHERE n.name = ?1"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
@ -581,6 +653,10 @@ nsAnnotationService::HasAnnotation(nsIURI* aURI,
// nsAnnotationService::RemoveAnnotation
//
// We don't remove anything from the moz_anno_name table. If we delete the
// last item of a given name, that item really should go away. It will get
// cleaned up on the next shutdown.
NS_IMETHODIMP
nsAnnotationService::RemoveAnnotation(nsIURI* aURI,
@ -664,6 +740,10 @@ nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
// XXX: If we use annotations for some standard items like GeckoFlags, it
// might be a good idea to blacklist these standard annotations from this
// copy function.
//
// We operate on strings from GetPageAnnotationNamesTArray. This is less
// efficient than operating on name IDs, which we should consider if this
// is too slow.
NS_IMETHODIMP
nsAnnotationService::CopyAnnotations(nsIURI* aSourceURI, nsIURI* aDestURI,
@ -712,9 +792,10 @@ nsAnnotationService::CopyAnnotations(nsIURI* aSourceURI, nsIURI* aDestURI,
// source with the same values of the annotation on dest.
nsCOMPtr<mozIStorageStatement> statement;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_anno (page, name, mime_type, content, flags, expiration) "
"SELECT ?1, ?3, mime_type, content, flags, expiration "
"FROM moz_anno WHERE page = ?2 AND name = ?3"),
"INSERT INTO moz_anno (page, name_id, mime_type, content, flags, expiration) "
"SELECT ?1, name_id, mime_type, content, flags, expiration "
"FROM moz_anno WHERE page = ?2 AND name_id = "
"(SELECT name_id FROM moz_anno_name WHERE name = ?3)"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
@ -897,9 +978,33 @@ nsAnnotationService::StartSetAnnotation(nsIURI* aURI,
rv = (*aStatement)->BindInt64Parameter(kAnnoIndex_ID, annotationID);
} else {
*aStatement = mDBAddAnnotation;
rv = (*aStatement)->BindInt64Parameter(kAnnoIndex_Page, uriID);
NS_ENSURE_SUCCESS(rv, rv);
rv = (*aStatement)->BindUTF8StringParameter(kAnnoIndex_Name, aName);
// make sure the name exists
{
mozStorageStatementScoper scoper(mDBGetAnnotationNameID);
rv = mDBGetAnnotationNameID->BindUTF8StringParameter(0, aName);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasName;
PRInt64 nameID;
if (NS_FAILED(mDBGetAnnotationNameID->ExecuteStep(&hasName)) || ! hasName) {
// add a new annotation name
mDBGetAnnotationNameID->Reset();
mozStorageStatementScoper addNameScoper(mDBAddAnnotationName);
rv = mDBAddAnnotationName->BindUTF8StringParameter(0, aName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBAddAnnotationName->Execute();
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->GetLastInsertRowID(&nameID);
NS_ENSURE_SUCCESS(rv, rv);
} else {
nameID = mDBGetAnnotationNameID->AsInt64(0);
}
rv = (*aStatement)->BindInt64Parameter(kAnnoIndex_Page, uriID);
NS_ENSURE_SUCCESS(rv, rv);
rv = (*aStatement)->BindInt64Parameter(kAnnoIndex_Name, nameID);
NS_ENSURE_SUCCESS(rv, rv);
}
}
mozStorageStatementScoper statementResetter(*aStatement);
NS_ENSURE_SUCCESS(rv, rv);
@ -923,3 +1028,109 @@ nsAnnotationService::CallSetObservers(nsIURI* aURI, const nsACString& aName)
for (PRInt32 i = 0; i < mObservers.Count(); i ++)
mObservers[i]->OnAnnotationSet(aURI, aName);
}
// nsAnnotationService::MigrateFromAlpha1
//
// The alpha 1 release had a column called "name" with the names of the
// annotations. We need to delete that and move the strings to a
// moz_anno_name table. Since sqlite can not change columns, we rename the
// table, copy the data, and delete the renamed version.
nsresult // static
nsAnnotationService::MigrateFromAlpha1(mozIStorageConnection* aDBConn)
{
// rename current annotation table
nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_anno RENAME TO moz_anno_old"));
NS_ENSURE_SUCCESS(rv, rv);
// create the new annotation table: should be the same as InitTables
// (this migration code is temporary, so we don't worry about maintenance
// too much). Note we create the indices later because we need to delete
// the old ones first.
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE moz_anno ("
"anno_id INTEGER PRIMARY KEY,"
"page INTEGER NOT NULL,"
"name_id INTEGER,"
"mime_type VARCHAR(32) DEFAULT NULL,"
"content LONGVARCHAR, flags INTEGER DEFAULT 0,"
"expiration INTEGER DEFAULT 0)"));
NS_ENSURE_SUCCESS(rv, rv);
// Add an ID column to the old table. We can then set this and copy all
// values to the new table at once.
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_anno_old ADD COLUMN name_id"));
NS_ENSURE_SUCCESS(rv, rv);
// get the unique column names
nsCOMPtr<mozIStorageStatement> statement;
rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT DISTINCT name FROM moz_anno_old"), getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
nsCStringArray uniqueNames;
while (NS_SUCCEEDED(statement->ExecuteStep(&hasMore)) && hasMore) {
nsCAutoString curName;
rv = statement->GetUTF8String(0, curName);
NS_ENSURE_SUCCESS(rv, rv);
uniqueNames.AppendCString(curName);
}
rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_anno_name (name) VALUES (?1)"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
// add the proper name_id values into the old table
nsCOMPtr<mozIStorageStatement> updateAnno;
rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_anno_old SET name_id = ?1 WHERE name = ?2"),
getter_AddRefs(updateAnno));
NS_ENSURE_SUCCESS(rv, rv);
for (PRInt32 i = 0; i < uniqueNames.Count(); i ++) {
// insert the name into the moz_anno_name table
rv = statement->BindUTF8StringParameter(0, *uniqueNames[i]);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 nameID;
rv = aDBConn->GetLastInsertRowID(&nameID);
NS_ENSURE_SUCCESS(rv, rv);
// update the corresponding entries in the moz_anno table to reference it
rv = updateAnno->BindInt64Parameter(0, nameID);
NS_ENSURE_SUCCESS(rv, rv);
rv = updateAnno->BindUTF8StringParameter(1, *uniqueNames[i]);
NS_ENSURE_SUCCESS(rv, rv);
rv = updateAnno->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
// copy values to the new table
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO moz_anno "
"(anno_id, page, name_id, mime_type, content, flags, expiration) "
"SELECT anno_id, page, name_id, mime_type, content, flags, expiration "
"FROM moz_anno_old"));
NS_ENSURE_SUCCESS(rv, rv);
// delete old table & indices (which will be automatically dropped when their
// table is deleted)
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE moz_anno_old"));
NS_ENSURE_SUCCESS(rv, rv);
// create indices on the new table
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX moz_anno_pageindex ON moz_anno (page)"));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX moz_anno_nameindex ON moz_anno (name_id)"));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

View File

@ -91,6 +91,8 @@ protected:
nsCOMPtr<mozIStorageStatement> mDBGetAnnotation;
nsCOMPtr<mozIStorageStatement> mDBGetAnnotationNames;
nsCOMPtr<mozIStorageStatement> mDBGetAnnotationFromURI;
nsCOMPtr<mozIStorageStatement> mDBGetAnnotationNameID;
nsCOMPtr<mozIStorageStatement> mDBAddAnnotationName;
nsCOMPtr<mozIStorageStatement> mDBAddAnnotation;
nsCOMPtr<mozIStorageStatement> mDBRemoveAnnotation;
@ -115,6 +117,8 @@ protected:
PRInt32 aFlags, PRInt32 aExpiration,
mozIStorageStatement** aStatement);
void CallSetObservers(nsIURI* aURI, const nsACString& aName);
static nsresult MigrateFromAlpha1(mozIStorageConnection* aDBConn);
};
#endif /* nsAnnotationService_h___ */

View File

@ -3121,7 +3121,7 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
if (aQuery->AnnotationIsNot())
aClause->AppendLiteral("NOT ");
aClause->AppendLiteral("EXISTS (SELECT anno_id FROM moz_anno anno WHERE anno.page = h.id AND anno.name = ");
aClause->AppendLiteral("EXISTS (SELECT anno_id FROM moz_anno anno JOIN moz_anno_name annoname ON anno.name_id = annoname.name_id WHERE anno.page = h.id AND annoname.name = ");
aClause->Append(paramString);
aClause->AppendLiteral(") ");
// annotation-based queries don't get the common conditions, so you get