//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Annotation Service * * The Initial Developer of the Original Code is * Google Inc. * Portions created by the Initial Developer are Copyright (C) 2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Brett Wilson (original author) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * 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 ***** */ #include "nsAnnotationService.h" #include "mozStorageCID.h" #include "nsNavHistory.h" #include "nsNetUtil.h" #include "mozIStorageValueArray.h" #include "mozIStorageStatement.h" #include "mozIStorageFunction.h" #include "mozStorageHelper.h" #include "nsIServiceManager.h" #include "nsIVariant.h" #include "nsString.h" #include "nsVariant.h" const PRInt32 nsAnnotationService::kAnnoIndex_ID = 0; const PRInt32 nsAnnotationService::kAnnoIndex_Page = 1; const PRInt32 nsAnnotationService::kAnnoIndex_Name = 2; const PRInt32 nsAnnotationService::kAnnoIndex_MimeType = 3; const PRInt32 nsAnnotationService::kAnnoIndex_Content = 4; const PRInt32 nsAnnotationService::kAnnoIndex_Flags = 5; const PRInt32 nsAnnotationService::kAnnoIndex_Expiration = 6; static NS_DEFINE_CID(kmozStorageServiceCID, MOZ_STORAGE_SERVICE_CID); static NS_DEFINE_CID(kmozStorageConnectionCID, MOZ_STORAGE_CONNECTION_CID); NS_IMPL_ISUPPORTS1(nsAnnotationService, nsIAnnotationService) // nsAnnotationService::nsAnnotationService nsAnnotationService::nsAnnotationService() { } // nsAnnotationService::~nsAnnotationService nsAnnotationService::~nsAnnotationService() { } // nsAnnotationService::Init nsresult nsAnnotationService::Init() { nsresult rv; nsNavHistory* history = nsNavHistory::GetHistoryService(); if (! history) return NS_ERROR_FAILURE; mDBConn = history->GetStorageConnection(); // create the database rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE moz_anno (anno_id INTEGER PRIMARY KEY, page INTEGER NOT NULL, name VARCHAR(32) NOT NULL, mime_type VARCHAR(32) DEFAULT NULL, content LONGVARCHAR, flags INTEGER DEFAULT 0, expiration INTEGER DEFAULT 0)")); rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE INDEX moz_anno_pageindex ON moz_anno (page)")); rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE INDEX moz_anno_nameindex ON moz_anno (name)")); // 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)); NS_ENSURE_SUCCESS(rv, rv); rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM moz_anno WHERE page = ?1 AND 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)); 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)); 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)); NS_ENSURE_SUCCESS(rv, rv); rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_anno WHERE page = ?1 AND name = ?2"), getter_AddRefs(mDBRemoveAnnotation)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } // nsAnnotationService::SetAnnotationString NS_IMETHODIMP nsAnnotationService::SetAnnotationString(nsIURI* aURI, const nsACString& aName, const nsAString& aValue, PRInt32 aFlags, PRInt32 aExpiration) { mozStorageTransaction transaction(mDBConn, PR_FALSE); mozIStorageStatement* statement; // class var, not owned by this function nsresult rv = StartSetAnnotation(aURI, aName, aFlags, aExpiration, &statement); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper statementResetter(statement); rv = statement->BindStringParameter(kAnnoIndex_Content, aValue); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindNullParameter(kAnnoIndex_MimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); // should reset the statement; observers may call our service back to get // annotation values! statement->Reset(); statementResetter.Abandon(); CallSetObservers(aURI, aName); return NS_OK; } // nsAnnotationService::SetAnnotationInt32 NS_IMETHODIMP nsAnnotationService::SetAnnotationInt32(nsIURI* aURI, const nsACString& aName, PRInt32 aValue, PRInt32 aFlags, PRInt32 aExpiration) { mozStorageTransaction transaction(mDBConn, PR_FALSE); mozIStorageStatement* statement; // class var, not owned by this function nsresult rv = StartSetAnnotation(aURI, aName, aFlags, aExpiration, &statement); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper statementResetter(statement); rv = statement->BindInt32Parameter(kAnnoIndex_Content, aValue); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindNullParameter(kAnnoIndex_MimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); // should reset the statement; observers may call our service back to get // annotation values! statement->Reset(); statementResetter.Abandon(); CallSetObservers(aURI, aName); return NS_OK; } // nsAnnotationService::SetAnnotationInt64 NS_IMETHODIMP nsAnnotationService::SetAnnotationInt64(nsIURI* aURI, const nsACString& aName, PRInt64 aValue, PRInt32 aFlags, PRInt32 aExpiration) { mozStorageTransaction transaction(mDBConn, PR_FALSE); mozIStorageStatement* statement; // class var, not owned by this function nsresult rv = StartSetAnnotation(aURI, aName, aFlags, aExpiration, &statement); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper statementResetter(statement); rv = statement->BindInt64Parameter(kAnnoIndex_Content, aValue); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindNullParameter(kAnnoIndex_MimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); // should reset the statement; observers may call our service back to get // annotation values! statement->Reset(); statementResetter.Abandon(); CallSetObservers(aURI, aName); return NS_OK; } // nsAnnotationService::SetAnnotationDouble NS_IMETHODIMP nsAnnotationService::SetAnnotationDouble(nsIURI* aURI, const nsACString& aName, double aValue, PRInt32 aFlags, PRInt32 aExpiration) { mozStorageTransaction transaction(mDBConn, PR_FALSE); mozIStorageStatement* statement; // class var, not owned by this function nsresult rv = StartSetAnnotation(aURI, aName, aFlags, aExpiration, &statement); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper statementResetter(statement); rv = statement->BindDoubleParameter(kAnnoIndex_Content, aValue); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindNullParameter(kAnnoIndex_MimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); // should reset the statement; observers may call our service back to get // annotation values! statement->Reset(); statementResetter.Abandon(); CallSetObservers(aURI, aName); return NS_OK; } // nsAnnotationService::SetAnnotationBinary NS_IMETHODIMP nsAnnotationService::SetAnnotationBinary(nsIURI* aURI, const nsACString& aName, const PRUint8 *aData, PRUint32 aDataLen, const nsACString& aMimeType, PRInt32 aFlags, PRInt32 aExpiration) { if (aMimeType.Length() == 0) return NS_ERROR_INVALID_ARG; mozStorageTransaction transaction(mDBConn, PR_FALSE); mozIStorageStatement* statement; // class var, not owned by this function nsresult rv = StartSetAnnotation(aURI, aName, aFlags, aExpiration, &statement); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper statementResetter(statement); rv = statement->BindBlobParameter(kAnnoIndex_Content, aData, aDataLen); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindUTF8StringParameter(kAnnoIndex_MimeType, aMimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); // should reset the statement; observers may call our service back to get // annotation values! statement->Reset(); statementResetter.Abandon(); CallSetObservers(aURI, aName); return NS_OK; } // nsAnnotationService::GetAnnotationString NS_IMETHODIMP nsAnnotationService::GetAnnotationString(nsIURI* aURI, const nsACString& aName, nsAString& _retval) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (NS_FAILED(rv)) return rv; rv = mDBGetAnnotationFromURI->GetString(kAnnoIndex_Content, _retval); mDBGetAnnotationFromURI->Reset(); return rv; } // nsAnnotationService::GetAnnotationInt32 NS_IMETHODIMP nsAnnotationService::GetAnnotationInt32(nsIURI* aURI, const nsACString& aName, PRInt32 *_retval) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (NS_FAILED(rv)) return rv; *_retval = mDBGetAnnotationFromURI->AsInt32(kAnnoIndex_Content); mDBGetAnnotationFromURI->Reset(); return NS_OK; } // nsAnnotationService::GetAnnotationInt64 NS_IMETHODIMP nsAnnotationService::GetAnnotationInt64(nsIURI* aURI, const nsACString& aName, PRInt64 *_retval) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (NS_FAILED(rv)) return rv; *_retval = mDBGetAnnotationFromURI->AsInt64(kAnnoIndex_Content); mDBGetAnnotationFromURI->Reset(); return NS_OK; } // nsAnnotationService::GetAnnotationDouble NS_IMETHODIMP nsAnnotationService::GetAnnotationDouble(nsIURI* aURI, const nsACString& aName, double *_retval) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (NS_FAILED(rv)) return rv; *_retval = mDBGetAnnotationFromURI->AsDouble(kAnnoIndex_Content); mDBGetAnnotationFromURI->Reset(); return NS_OK; } // nsAnnotationService::GetAnnotationBinary NS_IMETHODIMP nsAnnotationService::GetAnnotationBinary(nsIURI* aURI, const nsACString& aName, PRUint8** aData, PRUint32* aDataLen, nsACString& aMimeType) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (NS_FAILED(rv)) return rv; rv = mDBGetAnnotationFromURI->GetBlob(kAnnoIndex_Content, aDataLen, aData); if (NS_FAILED(rv)) { mDBGetAnnotationFromURI->Reset(); return rv; } rv = mDBGetAnnotationFromURI->GetUTF8String(kAnnoIndex_MimeType, aMimeType); mDBGetAnnotationFromURI->Reset(); return rv; } // nsAnnotationService::GetAnnotationInfo NS_IMETHODIMP nsAnnotationService::GetAnnotationInfo(nsIURI* aURI, const nsACString& aName, PRInt32 *aFlags, PRInt32 *aExpiration, nsACString& aMimeType, PRInt32 *aStorageType) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (NS_FAILED(rv)) return rv; mozStorageStatementScoper resetter(mDBGetAnnotationFromURI); *aFlags = mDBGetAnnotationFromURI->AsInt32(kAnnoIndex_Flags); *aExpiration = mDBGetAnnotationFromURI->AsInt32(kAnnoIndex_Expiration); rv = mDBGetAnnotationFromURI->GetUTF8String(kAnnoIndex_MimeType, aMimeType); NS_ENSURE_SUCCESS(rv, rv); rv = mDBGetAnnotationFromURI->GetTypeOfIndex(kAnnoIndex_Content, aStorageType); return rv; } // nsAnnotationService::GetPagesWithAnnotation NS_IMETHODIMP nsAnnotationService::GetPagesWithAnnotation(const nsACString& aName, PRUint32* aResultCount, nsIURI*** aResults) { if (aName.IsEmpty() || ! aResultCount || ! aResults) return NS_ERROR_INVALID_ARG; *aResultCount = 0; *aResults = nsnull; // this probably isn't a common operation, so we don't have a precompiled // statement. Perhaps this should change. nsCOMPtr 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"), getter_AddRefs(statement)); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindUTF8StringParameter(0, aName); NS_ENSURE_SUCCESS(rv, rv); PRBool hasMore = PR_FALSE; nsCOMArray results; while (NS_SUCCEEDED(rv = statement->ExecuteStep(&hasMore)) && hasMore) { nsCAutoString uristring; rv = statement->GetUTF8String(0, uristring); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), uristring); NS_ENSURE_SUCCESS(rv, rv); PRBool added = results.AppendObject(uri); NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY); } // convert to raw array if (results.Count() == 0) return NS_OK; *aResults = NS_STATIC_CAST(nsIURI**, nsMemory::Alloc(results.Count() * sizeof(nsIURI*))); if (! aResults) return NS_ERROR_OUT_OF_MEMORY; *aResultCount = results.Count(); for (PRUint32 i = 0; i < *aResultCount; i ++) { (*aResults)[i] = results[i]; NS_ADDREF((*aResults)[i]); } return NS_OK; } // nsAnnotationService::GetPageAnnotationNames NS_IMETHODIMP nsAnnotationService::GetPageAnnotationNames(nsIURI* aURI, PRUint32* aCount, nsIVariant*** _result) { *aCount = 0; *_result = nsnull; nsTArray names; nsresult rv = GetPageAnnotationNamesTArray(aURI, &names); NS_ENSURE_SUCCESS(rv, rv); if (names.Length() == 0) return NS_OK; *_result = NS_STATIC_CAST(nsIVariant**, nsMemory::Alloc(sizeof(nsIVariant*) * names.Length())); NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY); for (PRUint32 i = 0; i < names.Length(); i ++) { nsCOMPtr var = new nsVariant; if (! var) { // need to release all the variants we've already created for (PRUint32 j = 0; j < i; j ++) NS_RELEASE((*_result)[j]); nsMemory::Free(*_result); *_result = nsnull; return rv; } var->SetAsAUTF8String(names[i]); NS_ADDREF((*_result)[i] = var); } *aCount = names.Length(); return NS_OK; } // nsAnnotationService::GetPageAnnotationNamesTArray NS_IMETHODIMP nsAnnotationService::GetPageAnnotationNamesTArray(nsIURI* aURI, nsTArray* aResult) { aResult->Clear(); nsNavHistory* history = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(history, NS_ERROR_FAILURE); PRInt64 uriID; nsresult rv = history->GetUrlIdFor(aURI, &uriID, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); if (uriID == 0) // Check if URI exists. return NS_OK; mozStorageStatementScoper scoper(mDBGetAnnotationNames); rv = mDBGetAnnotationNames->BindInt64Parameter(0, uriID); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult; nsCAutoString name; while (NS_SUCCEEDED(mDBGetAnnotationNames->ExecuteStep(&hasResult)) && hasResult) { rv = mDBGetAnnotationNames->GetUTF8String(0, name); NS_ENSURE_SUCCESS(rv, rv); if (! aResult->AppendElement(name)) return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } // nsAnnotationService::HasAnnotation NS_IMETHODIMP nsAnnotationService::HasAnnotation(nsIURI* aURI, const nsACString& aName, PRBool *_retval) { nsresult rv = StartGetAnnotationFromURI(aURI, aName); if (rv == NS_ERROR_NOT_AVAILABLE) { *_retval = PR_FALSE; rv = NS_OK; } else if (NS_SUCCEEDED(rv)) { *_retval = PR_TRUE; } mDBGetAnnotationFromURI->Reset(); return rv; } // nsAnnotationService::RemoveAnnotation NS_IMETHODIMP nsAnnotationService::RemoveAnnotation(nsIURI* aURI, const nsACString& aName) { nsresult rv; nsNavHistory* history = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(history, NS_ERROR_FAILURE); PRInt64 uriID; rv = history->GetUrlIdFor(aURI, &uriID, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); if (uriID == 0) // Check if URI exists. return NS_OK; mozStorageStatementScoper resetter(mDBRemoveAnnotation); rv = mDBRemoveAnnotation->BindInt64Parameter(0, uriID); NS_ENSURE_SUCCESS(rv, rv); rv = mDBRemoveAnnotation->BindUTF8StringParameter(1, aName); NS_ENSURE_SUCCESS(rv, rv); rv = mDBRemoveAnnotation->Execute(); NS_ENSURE_SUCCESS(rv, rv); resetter.Abandon(); // Update observers for (PRInt32 i = 0; i < mObservers.Count(); i ++) mObservers[i]->OnAnnotationRemoved(aURI, aName); return NS_OK; } // nsAnnotationSerivce::RemovePageAnnotations // // I don't believe this is a common operation, so am not using a precompiled // statement. If this ends up being used a lot, the statement should be // precompiled and added to the class. NS_IMETHODIMP nsAnnotationService::RemovePageAnnotations(nsIURI* aURI) { nsresult rv; nsNavHistory* history = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(history, NS_ERROR_UNEXPECTED); PRInt64 uriID; rv = history->GetUrlIdFor(aURI, &uriID, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); if (uriID == 0) return NS_OK; // URI doesn't exist, nothing to delete nsCOMPtr statement; rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM moz_anno WHERE page = ?1"), getter_AddRefs(statement)); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindInt64Parameter(0, uriID); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); // Update observers for (PRInt32 i = 0; i < mObservers.Count(); i ++) mObservers[i]->OnAnnotationRemoved(aURI, EmptyCString()); return NS_OK; } // nsAnnotationService::AddObserver NS_IMETHODIMP nsAnnotationService::AddObserver(nsIAnnotationObserver* aObserver) { if (mObservers.IndexOfObject(aObserver) >= 0) return NS_ERROR_INVALID_ARG; // already registered if (!mObservers.AppendObject(aObserver)) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } // nsAnnotationService::RemoveObserver NS_IMETHODIMP nsAnnotationService::RemoveObserver(nsIAnnotationObserver* aObserver) { if (!mObservers.RemoveObject(aObserver)) return NS_ERROR_INVALID_ARG; return NS_OK; } // nsAnnotationService::GetAnnotationURI NS_IMETHODIMP nsAnnotationService::GetAnnotationURI(nsIURI* aURI, const nsACString& aName, nsIURI** _result) { if (aName.IsEmpty()) return NS_ERROR_INVALID_ARG; nsCAutoString annoSpec; nsresult rv = aURI->GetSpec(annoSpec); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString spec; spec.AssignLiteral("moz-anno:"); spec += aName; spec += NS_LITERAL_CSTRING(":"); spec += annoSpec; return NS_NewURI(_result, spec); } // nsAnnotationService::HasAnnotationInternal // // This is just like HasAnnotation but takes a URL ID. It will also give // you the ID of the annotation, if it exists. This value can be NULL and // it won't retrieve the annotation ID. If it doesn't exist, annotationID // is not touched. nsresult nsAnnotationService::HasAnnotationInternal(PRInt64 aURLID, const nsACString& aName, PRBool* hasAnnotation, PRInt64* annotationID) { mozStorageStatementScoper resetter(mDBGetAnnotation); nsresult rv; rv = mDBGetAnnotation->BindInt64Parameter(0, aURLID); NS_ENSURE_SUCCESS(rv, rv); rv = mDBGetAnnotation->BindUTF8StringParameter(1, aName); NS_ENSURE_SUCCESS(rv, rv); rv = mDBGetAnnotation->ExecuteStep(hasAnnotation); NS_ENSURE_SUCCESS(rv, rv); if (! annotationID || ! *hasAnnotation) return NS_OK; return mDBGetAnnotation->GetInt64(0, annotationID); } // nsAnnotationService::StartGetAnnotationFromURI // // This loads the statement GetAnnotationFromURI and steps it once so you // can get data out of it. YOU NEED TO RESET THIS STATEMENT WHEN YOU ARE // DONE! Returns error if the annotation is not found, in which case you // don't need to reset anything. nsresult nsAnnotationService::StartGetAnnotationFromURI(nsIURI* aURI, const nsACString& aName) { mozStorageStatementScoper statementResetter(mDBGetAnnotationFromURI); nsresult rv; rv = BindStatementURI(mDBGetAnnotationFromURI, 0, aURI); NS_ENSURE_SUCCESS(rv, rv); rv = mDBGetAnnotationFromURI->BindUTF8StringParameter(1, aName); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult = PR_FALSE; rv = mDBGetAnnotationFromURI->ExecuteStep(&hasResult); if (NS_FAILED(rv) || ! hasResult) return NS_ERROR_NOT_AVAILABLE; // on success, DON'T reset the statement, the caller needs to read from it, // and it is the caller's job to do the reseting. statementResetter.Abandon(); return NS_OK; } // nsAnnotationService::StartSetAnnotation // // This does most of the work of setting an annotation, except for setting // the actual value and MIME type and executing the statement. It will // create a URL entry if necessary. It will either update an existing // annotation or insert a new one, and aStatement will be set to either // mDBAddAnnotation or mDBSetAnnotation. The aStatement RESULT IS NOT // ADDREFED. This is just one of the class vars, which control its scope. // DO NOT RELEASE. // // The caller must make sure the statement is reset. On error, the // statement will not need reseting. nsresult nsAnnotationService::StartSetAnnotation(nsIURI* aURI, const nsACString& aName, PRInt32 aFlags, PRInt32 aExpiration, mozIStorageStatement** aStatement) { nsresult rv; nsNavHistory* history = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(history, NS_ERROR_FAILURE); PRInt64 uriID; rv = history->GetUrlIdFor(aURI, &uriID, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); PRBool hasAnnotation; PRInt64 annotationID; rv = HasAnnotationInternal(uriID, aName, &hasAnnotation, &annotationID); NS_ENSURE_SUCCESS(rv, rv); // either update the existing annotation (using the old annotation's ID) // or insert a new one tied to the URI. if (hasAnnotation) { *aStatement = mDBSetAnnotation; 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); } mozStorageStatementScoper statementResetter(*aStatement); NS_ENSURE_SUCCESS(rv, rv); rv = (*aStatement)->BindInt32Parameter(kAnnoIndex_Flags, aFlags); NS_ENSURE_SUCCESS(rv, rv); rv = (*aStatement)->BindInt32Parameter(kAnnoIndex_Expiration, aExpiration); NS_ENSURE_SUCCESS(rv, rv); // on success, leave the statement open, the caller will set the value // and MIME type and execute the statement statementResetter.Abandon(); return NS_OK; } // nsAnnotationService::CallSetObservers void nsAnnotationService::CallSetObservers(nsIURI* aURI, const nsACString& aName) { for (PRInt32 i = 0; i < mObservers.Count(); i ++) mObservers[i]->OnAnnotationSet(aURI, aName); }