toolkit/components/places/nsAnnotationService.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/ArrayUtils.h"
     8 #include "nsAnnotationService.h"
     9 #include "nsNavHistory.h"
    10 #include "nsPlacesTables.h"
    11 #include "nsPlacesIndexes.h"
    12 #include "nsPlacesMacros.h"
    13 #include "Helpers.h"
    15 #include "nsNetUtil.h"
    16 #include "nsIVariant.h"
    17 #include "nsString.h"
    18 #include "nsVariant.h"
    19 #include "mozilla/storage.h"
    21 #include "GeckoProfiler.h"
    23 #include "nsNetCID.h"
    25 using namespace mozilla;
    26 using namespace mozilla::places;
    28 #define ENSURE_ANNO_TYPE(_type, _statement)                                    \
    29   PR_BEGIN_MACRO                                                               \
    30   int32_t type = _statement->AsInt32(kAnnoIndex_Type);                         \
    31   NS_ENSURE_TRUE(type == nsIAnnotationService::_type, NS_ERROR_INVALID_ARG);   \
    32   PR_END_MACRO
    34 #define NOTIFY_ANNOS_OBSERVERS(_notification)                                  \
    35   PR_BEGIN_MACRO                                                               \
    36   for (int32_t i = 0; i < mObservers.Count(); i++)                             \
    37     mObservers[i]->_notification;                                              \
    38   PR_END_MACRO
    40 const int32_t nsAnnotationService::kAnnoIndex_ID = 0;
    41 const int32_t nsAnnotationService::kAnnoIndex_PageOrItem = 1;
    42 const int32_t nsAnnotationService::kAnnoIndex_NameID = 2;
    43 const int32_t nsAnnotationService::kAnnoIndex_Content = 3;
    44 const int32_t nsAnnotationService::kAnnoIndex_Flags = 4;
    45 const int32_t nsAnnotationService::kAnnoIndex_Expiration = 5;
    46 const int32_t nsAnnotationService::kAnnoIndex_Type = 6;
    47 const int32_t nsAnnotationService::kAnnoIndex_DateAdded = 7;
    48 const int32_t nsAnnotationService::kAnnoIndex_LastModified = 8;
    50 namespace mozilla {
    51 namespace places {
    53 ////////////////////////////////////////////////////////////////////////////////
    54 //// AnnotatedResult
    56 AnnotatedResult::AnnotatedResult(const nsCString& aGUID,
    57                                  nsIURI* aURI,
    58                                  int64_t aItemId,
    59                                  const nsACString& aAnnotationName,
    60                                  nsIVariant* aAnnotationValue)
    61 : mGUID(aGUID)
    62 , mURI(aURI)
    63 , mItemId(aItemId)
    64 , mAnnotationName(aAnnotationName)
    65 , mAnnotationValue(aAnnotationValue)
    66 {
    67 }
    69 NS_IMETHODIMP
    70 AnnotatedResult::GetGuid(nsACString& _guid)
    71 {
    72   _guid = mGUID;
    73   return NS_OK;
    74 }
    76 NS_IMETHODIMP
    77 AnnotatedResult::GetUri(nsIURI** _uri)
    78 {
    79   NS_IF_ADDREF(*_uri = mURI);
    80   return NS_OK;
    81 }
    83 NS_IMETHODIMP
    84 AnnotatedResult::GetItemId(int64_t* _itemId)
    85 {
    86   *_itemId = mItemId;
    87   return NS_OK;
    88 }
    90 NS_IMETHODIMP
    91 AnnotatedResult::GetAnnotationName(nsACString& _annotationName)
    92 {
    93   _annotationName = mAnnotationName;
    94   return NS_OK;
    95 }
    97 NS_IMETHODIMP
    98 AnnotatedResult::GetAnnotationValue(nsIVariant** _annotationValue)
    99 {
   100   NS_IF_ADDREF(*_annotationValue = mAnnotationValue);
   101   return NS_OK;
   102 }
   104 NS_IMPL_ISUPPORTS(AnnotatedResult, mozIAnnotatedResult)
   106 } // namespace places
   107 } // namespace mozilla
   109 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsAnnotationService, gAnnotationService)
   111 NS_IMPL_ISUPPORTS(nsAnnotationService
   112 , nsIAnnotationService
   113 , nsIObserver
   114 , nsISupportsWeakReference
   115 )
   118 nsAnnotationService::nsAnnotationService()
   119   : mHasSessionAnnotations(false)
   120 {
   121   NS_ASSERTION(!gAnnotationService,
   122                "Attempting to create two instances of the service!");
   123   gAnnotationService = this;
   124 }
   127 nsAnnotationService::~nsAnnotationService()
   128 {
   129   NS_ASSERTION(gAnnotationService == this,
   130                "Deleting a non-singleton instance of the service");
   131   if (gAnnotationService == this)
   132     gAnnotationService = nullptr;
   133 }
   136 nsresult
   137 nsAnnotationService::Init()
   138 {
   139   mDB = Database::GetDatabase();
   140   NS_ENSURE_STATE(mDB);
   142   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
   143   if (obsSvc) {
   144     (void)obsSvc->AddObserver(this, TOPIC_PLACES_SHUTDOWN, true);
   145   }
   147   return NS_OK;
   148 }
   150 nsresult
   151 nsAnnotationService::SetAnnotationStringInternal(nsIURI* aURI,
   152                                                  int64_t aItemId,
   153                                                  const nsACString& aName,
   154                                                  const nsAString& aValue,
   155                                                  int32_t aFlags,
   156                                                  uint16_t aExpiration)
   157 {
   158   mozStorageTransaction transaction(mDB->MainConn(), false);
   159   nsCOMPtr<mozIStorageStatement> statement;
   160   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
   161                                    nsIAnnotationService::TYPE_STRING,
   162                                    statement);
   163   NS_ENSURE_SUCCESS(rv, rv);
   164   mozStorageStatementScoper scoper(statement);
   166   rv = statement->BindStringByName(NS_LITERAL_CSTRING("content"), aValue);
   167   NS_ENSURE_SUCCESS(rv, rv);
   169   rv = statement->Execute();
   170   NS_ENSURE_SUCCESS(rv, rv);
   172   rv = transaction.Commit();
   173   NS_ENSURE_SUCCESS(rv, rv);
   175   return NS_OK;
   176 }
   179 NS_IMETHODIMP
   180 nsAnnotationService::SetPageAnnotation(nsIURI* aURI,
   181                                        const nsACString& aName,
   182                                        nsIVariant* aValue,
   183                                        int32_t aFlags,
   184                                        uint16_t aExpiration)
   185 {
   186   NS_ENSURE_ARG(aURI);
   187   NS_ENSURE_ARG(aValue);
   189   uint16_t dataType;
   190   nsresult rv = aValue->GetDataType(&dataType);
   191   NS_ENSURE_SUCCESS(rv, rv);
   193   switch (dataType) {
   194     case nsIDataType::VTYPE_INT8:
   195     case nsIDataType::VTYPE_UINT8:
   196     case nsIDataType::VTYPE_INT16:
   197     case nsIDataType::VTYPE_UINT16:
   198     case nsIDataType::VTYPE_INT32:
   199     case nsIDataType::VTYPE_UINT32:
   200     case nsIDataType::VTYPE_BOOL: {
   201       int32_t valueInt;
   202       rv = aValue->GetAsInt32(&valueInt);
   203       if (NS_SUCCEEDED(rv)) {
   204         NS_ENSURE_SUCCESS(rv, rv);
   205         rv = SetPageAnnotationInt32(aURI, aName, valueInt, aFlags, aExpiration);
   206         NS_ENSURE_SUCCESS(rv, rv);
   207         return NS_OK;
   208       }
   209       // Fall through int64_t case otherwise.
   210     }
   211     case nsIDataType::VTYPE_INT64:
   212     case nsIDataType::VTYPE_UINT64: {
   213       int64_t valueLong;
   214       rv = aValue->GetAsInt64(&valueLong);
   215       if (NS_SUCCEEDED(rv)) {
   216         NS_ENSURE_SUCCESS(rv, rv);
   217         rv = SetPageAnnotationInt64(aURI, aName, valueLong, aFlags, aExpiration);
   218         NS_ENSURE_SUCCESS(rv, rv);
   219         return NS_OK;
   220       }
   221       // Fall through double case otherwise.
   222     }
   223     case nsIDataType::VTYPE_FLOAT:
   224     case nsIDataType::VTYPE_DOUBLE: {
   225       double valueDouble;
   226       rv = aValue->GetAsDouble(&valueDouble);
   227       NS_ENSURE_SUCCESS(rv, rv);
   228       rv = SetPageAnnotationDouble(aURI, aName, valueDouble, aFlags, aExpiration);
   229       NS_ENSURE_SUCCESS(rv, rv);
   230       return NS_OK;
   231     }
   232     case nsIDataType::VTYPE_CHAR:
   233     case nsIDataType::VTYPE_WCHAR:
   234     case nsIDataType::VTYPE_DOMSTRING:
   235     case nsIDataType::VTYPE_CHAR_STR:
   236     case nsIDataType::VTYPE_WCHAR_STR:
   237     case nsIDataType::VTYPE_STRING_SIZE_IS:
   238     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
   239     case nsIDataType::VTYPE_UTF8STRING:
   240     case nsIDataType::VTYPE_CSTRING:
   241     case nsIDataType::VTYPE_ASTRING: {
   242       nsAutoString stringValue;
   243       rv = aValue->GetAsAString(stringValue);
   244       NS_ENSURE_SUCCESS(rv, rv);
   245       rv = SetPageAnnotationString(aURI, aName, stringValue, aFlags, aExpiration);
   246       NS_ENSURE_SUCCESS(rv, rv);
   247       return NS_OK;
   248     }
   249   }
   251   return NS_ERROR_NOT_IMPLEMENTED;
   252 }
   255 NS_IMETHODIMP
   256 nsAnnotationService::SetItemAnnotation(int64_t aItemId,
   257                                        const nsACString& aName,
   258                                        nsIVariant* aValue,
   259                                        int32_t aFlags,
   260                                        uint16_t aExpiration)
   261 {
   262   PROFILER_LABEL("AnnotationService", "SetItemAnnotation");
   263   NS_ENSURE_ARG_MIN(aItemId, 1);
   264   NS_ENSURE_ARG(aValue);
   266   if (aExpiration == EXPIRE_WITH_HISTORY)
   267     return NS_ERROR_INVALID_ARG;
   269   uint16_t dataType;
   270   nsresult rv = aValue->GetDataType(&dataType);
   271   NS_ENSURE_SUCCESS(rv, rv);
   273   switch (dataType) {
   274     case nsIDataType::VTYPE_INT8:
   275     case nsIDataType::VTYPE_UINT8:
   276     case nsIDataType::VTYPE_INT16:
   277     case nsIDataType::VTYPE_UINT16:
   278     case nsIDataType::VTYPE_INT32:
   279     case nsIDataType::VTYPE_UINT32:
   280     case nsIDataType::VTYPE_BOOL: {
   281       int32_t valueInt;
   282       rv = aValue->GetAsInt32(&valueInt);
   283       if (NS_SUCCEEDED(rv)) {
   284         NS_ENSURE_SUCCESS(rv, rv);
   285         rv = SetItemAnnotationInt32(aItemId, aName, valueInt, aFlags, aExpiration);
   286         NS_ENSURE_SUCCESS(rv, rv);
   287         return NS_OK;
   288       }
   289       // Fall through int64_t case otherwise.
   290     }
   291     case nsIDataType::VTYPE_INT64:
   292     case nsIDataType::VTYPE_UINT64: {
   293       int64_t valueLong;
   294       rv = aValue->GetAsInt64(&valueLong);
   295       if (NS_SUCCEEDED(rv)) {
   296         NS_ENSURE_SUCCESS(rv, rv);
   297         rv = SetItemAnnotationInt64(aItemId, aName, valueLong, aFlags, aExpiration);
   298         NS_ENSURE_SUCCESS(rv, rv);
   299         return NS_OK;
   300       }
   301       // Fall through double case otherwise.
   302     }
   303     case nsIDataType::VTYPE_FLOAT:
   304     case nsIDataType::VTYPE_DOUBLE: {
   305       double valueDouble;
   306       rv = aValue->GetAsDouble(&valueDouble);
   307       NS_ENSURE_SUCCESS(rv, rv);
   308       rv = SetItemAnnotationDouble(aItemId, aName, valueDouble, aFlags, aExpiration);
   309       NS_ENSURE_SUCCESS(rv, rv);
   310       return NS_OK;
   311     }
   312     case nsIDataType::VTYPE_CHAR:
   313     case nsIDataType::VTYPE_WCHAR:
   314     case nsIDataType::VTYPE_DOMSTRING:
   315     case nsIDataType::VTYPE_CHAR_STR:
   316     case nsIDataType::VTYPE_WCHAR_STR:
   317     case nsIDataType::VTYPE_STRING_SIZE_IS:
   318     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
   319     case nsIDataType::VTYPE_UTF8STRING:
   320     case nsIDataType::VTYPE_CSTRING:
   321     case nsIDataType::VTYPE_ASTRING: {
   322       nsAutoString stringValue;
   323       rv = aValue->GetAsAString(stringValue);
   324       NS_ENSURE_SUCCESS(rv, rv);
   325       rv = SetItemAnnotationString(aItemId, aName, stringValue, aFlags, aExpiration);
   326       NS_ENSURE_SUCCESS(rv, rv);
   327       return NS_OK;
   328     }
   329   }
   331   return NS_ERROR_NOT_IMPLEMENTED;
   332 }
   335 NS_IMETHODIMP
   336 nsAnnotationService::SetPageAnnotationString(nsIURI* aURI,
   337                                              const nsACString& aName,
   338                                              const nsAString& aValue,
   339                                              int32_t aFlags,
   340                                              uint16_t aExpiration)
   341 {
   342   NS_ENSURE_ARG(aURI);
   344   nsresult rv = SetAnnotationStringInternal(aURI, 0, aName, aValue,
   345                                             aFlags, aExpiration);
   346   NS_ENSURE_SUCCESS(rv, rv);
   348   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
   350   return NS_OK;
   351 }
   354 NS_IMETHODIMP
   355 nsAnnotationService::SetItemAnnotationString(int64_t aItemId,
   356                                              const nsACString& aName,
   357                                              const nsAString& aValue,
   358                                              int32_t aFlags,
   359                                              uint16_t aExpiration)
   360 {
   361   NS_ENSURE_ARG_MIN(aItemId, 1);
   363   if (aExpiration == EXPIRE_WITH_HISTORY)
   364     return NS_ERROR_INVALID_ARG;
   366   nsresult rv = SetAnnotationStringInternal(nullptr, aItemId, aName, aValue,
   367                                             aFlags, aExpiration);
   368   NS_ENSURE_SUCCESS(rv, rv);
   370   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
   372   return NS_OK;
   373 }
   376 nsresult
   377 nsAnnotationService::SetAnnotationInt32Internal(nsIURI* aURI,
   378                                                 int64_t aItemId,
   379                                                 const nsACString& aName,
   380                                                 int32_t aValue,
   381                                                 int32_t aFlags,
   382                                                 uint16_t aExpiration)
   383 {
   384   mozStorageTransaction transaction(mDB->MainConn(), false);
   385   nsCOMPtr<mozIStorageStatement> statement;
   386   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
   387                                    nsIAnnotationService::TYPE_INT32,
   388                                    statement);
   389   NS_ENSURE_SUCCESS(rv, rv);
   390   mozStorageStatementScoper scoper(statement);
   392   rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("content"), aValue);
   393   NS_ENSURE_SUCCESS(rv, rv);
   395   rv = statement->Execute();
   396   NS_ENSURE_SUCCESS(rv, rv);
   398   rv = transaction.Commit();
   399   NS_ENSURE_SUCCESS(rv, rv);
   401   return NS_OK;
   402 }
   405 NS_IMETHODIMP
   406 nsAnnotationService::SetPageAnnotationInt32(nsIURI* aURI,
   407                                             const nsACString& aName,
   408                                             int32_t aValue,
   409                                             int32_t aFlags,
   410                                             uint16_t aExpiration)
   411 {
   412   NS_ENSURE_ARG(aURI);
   414   nsresult rv = SetAnnotationInt32Internal(aURI, 0, aName, aValue,
   415                                            aFlags, aExpiration);
   416   NS_ENSURE_SUCCESS(rv, rv);
   418   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
   420   return NS_OK;
   421 }
   424 NS_IMETHODIMP
   425 nsAnnotationService::SetItemAnnotationInt32(int64_t aItemId,
   426                                             const nsACString& aName,
   427                                             int32_t aValue,
   428                                             int32_t aFlags,
   429                                             uint16_t aExpiration)
   430 {
   431   NS_ENSURE_ARG_MIN(aItemId, 1);
   433   if (aExpiration == EXPIRE_WITH_HISTORY)
   434     return NS_ERROR_INVALID_ARG;
   436   nsresult rv = SetAnnotationInt32Internal(nullptr, aItemId, aName, aValue,
   437                                            aFlags, aExpiration);
   438   NS_ENSURE_SUCCESS(rv, rv);
   440   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
   442   return NS_OK;
   443 }
   446 nsresult
   447 nsAnnotationService::SetAnnotationInt64Internal(nsIURI* aURI,
   448                                                 int64_t aItemId,
   449                                                 const nsACString& aName,
   450                                                 int64_t aValue,
   451                                                 int32_t aFlags,
   452                                                 uint16_t aExpiration)
   453 {
   454   mozStorageTransaction transaction(mDB->MainConn(), false);
   455   nsCOMPtr<mozIStorageStatement> statement;
   456   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
   457                                    nsIAnnotationService::TYPE_INT64,
   458                                    statement);
   459   NS_ENSURE_SUCCESS(rv, rv);
   460   mozStorageStatementScoper scoper(statement);
   462   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("content"), aValue);
   463   NS_ENSURE_SUCCESS(rv, rv);
   465   rv = statement->Execute();
   466   NS_ENSURE_SUCCESS(rv, rv);
   468   rv = transaction.Commit();
   469   NS_ENSURE_SUCCESS(rv, rv);
   471   return NS_OK;
   472 }
   475 NS_IMETHODIMP
   476 nsAnnotationService::SetPageAnnotationInt64(nsIURI* aURI,
   477                                             const nsACString& aName,
   478                                             int64_t aValue,
   479                                             int32_t aFlags,
   480                                             uint16_t aExpiration)
   481 {
   482   NS_ENSURE_ARG(aURI);
   484   nsresult rv = SetAnnotationInt64Internal(aURI, 0, aName, aValue,
   485                                            aFlags, aExpiration);
   486   NS_ENSURE_SUCCESS(rv, rv);
   488   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
   490   return NS_OK;
   491 }
   494 NS_IMETHODIMP
   495 nsAnnotationService::SetItemAnnotationInt64(int64_t aItemId,
   496                                             const nsACString& aName,
   497                                             int64_t aValue,
   498                                             int32_t aFlags,
   499                                             uint16_t aExpiration)
   500 {
   501   NS_ENSURE_ARG_MIN(aItemId, 1);
   503   if (aExpiration == EXPIRE_WITH_HISTORY)
   504     return NS_ERROR_INVALID_ARG;
   506   nsresult rv = SetAnnotationInt64Internal(nullptr, aItemId, aName, aValue,
   507                                            aFlags, aExpiration);
   508   NS_ENSURE_SUCCESS(rv, rv);
   510   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
   512   return NS_OK;
   513 }
   516 nsresult
   517 nsAnnotationService::SetAnnotationDoubleInternal(nsIURI* aURI,
   518                                                  int64_t aItemId,
   519                                                  const nsACString& aName,
   520                                                  double aValue,
   521                                                  int32_t aFlags,
   522                                                  uint16_t aExpiration)
   523 {
   524   mozStorageTransaction transaction(mDB->MainConn(), false);
   525   nsCOMPtr<mozIStorageStatement> statement;
   526   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
   527                                    nsIAnnotationService::TYPE_DOUBLE,
   528                                    statement);
   529   NS_ENSURE_SUCCESS(rv, rv);
   530   mozStorageStatementScoper scoper(statement);
   532   rv = statement->BindDoubleByName(NS_LITERAL_CSTRING("content"), aValue);
   533   NS_ENSURE_SUCCESS(rv, rv);
   535   rv = statement->Execute();
   536   NS_ENSURE_SUCCESS(rv, rv);
   538   rv = transaction.Commit();
   539   NS_ENSURE_SUCCESS(rv, rv);
   541   return NS_OK;
   542 }
   545 NS_IMETHODIMP
   546 nsAnnotationService::SetPageAnnotationDouble(nsIURI* aURI,
   547                                              const nsACString& aName,
   548                                              double aValue,
   549                                              int32_t aFlags,
   550                                              uint16_t aExpiration)
   551 {
   552   NS_ENSURE_ARG(aURI);
   554   nsresult rv = SetAnnotationDoubleInternal(aURI, 0, aName, aValue,
   555                                             aFlags, aExpiration);
   556   NS_ENSURE_SUCCESS(rv, rv);
   558   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
   560   return NS_OK;
   561 }
   564 NS_IMETHODIMP
   565 nsAnnotationService::SetItemAnnotationDouble(int64_t aItemId,
   566                                              const nsACString& aName,
   567                                              double aValue,
   568                                              int32_t aFlags,
   569                                              uint16_t aExpiration)
   570 {
   571   NS_ENSURE_ARG_MIN(aItemId, 1);
   573   if (aExpiration == EXPIRE_WITH_HISTORY)
   574     return NS_ERROR_INVALID_ARG;
   576   nsresult rv = SetAnnotationDoubleInternal(nullptr, aItemId, aName, aValue,
   577                                             aFlags, aExpiration);
   578   NS_ENSURE_SUCCESS(rv, rv);
   580   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
   582   return NS_OK;
   583 }
   585 NS_IMETHODIMP
   586 nsAnnotationService::GetPageAnnotationString(nsIURI* aURI,
   587                                              const nsACString& aName,
   588                                              nsAString& _retval)
   589 {
   590   NS_ENSURE_ARG(aURI);
   592   nsCOMPtr<mozIStorageStatement> statement;
   593   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   594   if (NS_FAILED(rv))
   595     return rv;
   597   mozStorageStatementScoper scoper(statement);
   598   ENSURE_ANNO_TYPE(TYPE_STRING, statement);
   599   rv = statement->GetString(kAnnoIndex_Content, _retval);
   600   NS_ENSURE_SUCCESS(rv, rv);
   602   return NS_OK;
   603 }
   606 NS_IMETHODIMP
   607 nsAnnotationService::GetItemAnnotationString(int64_t aItemId,
   608                                              const nsACString& aName,
   609                                              nsAString& _retval)
   610 {
   611   NS_ENSURE_ARG_MIN(aItemId, 1);
   613   nsCOMPtr<mozIStorageStatement> statement;
   614   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   615   if (NS_FAILED(rv))
   616     return rv;
   618   mozStorageStatementScoper scoper(statement);
   619   ENSURE_ANNO_TYPE(TYPE_STRING, statement);
   620   rv = statement->GetString(kAnnoIndex_Content, _retval);
   621   NS_ENSURE_SUCCESS(rv, rv);
   623   return NS_OK;
   624 }
   627 NS_IMETHODIMP
   628 nsAnnotationService::GetPageAnnotation(nsIURI* aURI,
   629                                        const nsACString& aName,
   630                                        nsIVariant** _retval)
   631 {
   632   NS_ENSURE_ARG(aURI);
   633   NS_ENSURE_ARG_POINTER(_retval);
   635   nsCOMPtr<mozIStorageStatement> statement;
   636   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   637   if (NS_FAILED(rv))
   638     return rv;
   640   mozStorageStatementScoper scoper(statement);
   642   nsCOMPtr<nsIWritableVariant> value = new nsVariant();
   643   int32_t type = statement->AsInt32(kAnnoIndex_Type);
   644   switch (type) {
   645     case nsIAnnotationService::TYPE_INT32:
   646     case nsIAnnotationService::TYPE_INT64:
   647     case nsIAnnotationService::TYPE_DOUBLE: {
   648       rv = value->SetAsDouble(statement->AsDouble(kAnnoIndex_Content));
   649       break;
   650     }
   651     case nsIAnnotationService::TYPE_STRING: {
   652       nsAutoString valueString;
   653       rv = statement->GetString(kAnnoIndex_Content, valueString);
   654       if (NS_SUCCEEDED(rv))
   655         rv = value->SetAsAString(valueString);
   656       break;
   657     }
   658     default: {
   659       rv = NS_ERROR_UNEXPECTED;
   660       break;
   661     }
   662   }
   664   if (NS_SUCCEEDED(rv))
   665     NS_ADDREF(*_retval = value);
   667   return rv;
   668 }
   671 NS_IMETHODIMP
   672 nsAnnotationService::GetItemAnnotation(int64_t aItemId,
   673                                        const nsACString& aName,
   674                                        nsIVariant** _retval)
   675 {
   676   NS_ENSURE_ARG_MIN(aItemId, 1);
   677   NS_ENSURE_ARG_POINTER(_retval);
   679   nsCOMPtr<mozIStorageStatement> statement;
   680   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   681   if (NS_FAILED(rv))
   682     return rv;
   684   mozStorageStatementScoper scoper(statement);
   686   nsCOMPtr<nsIWritableVariant> value = new nsVariant();
   687   int32_t type = statement->AsInt32(kAnnoIndex_Type);
   688   switch (type) {
   689     case nsIAnnotationService::TYPE_INT32:
   690     case nsIAnnotationService::TYPE_INT64:
   691     case nsIAnnotationService::TYPE_DOUBLE: {
   692       rv = value->SetAsDouble(statement->AsDouble(kAnnoIndex_Content));
   693       break;
   694     }
   695     case nsIAnnotationService::TYPE_STRING: {
   696       nsAutoString valueString;
   697       rv = statement->GetString(kAnnoIndex_Content, valueString);
   698       if (NS_SUCCEEDED(rv))
   699         rv = value->SetAsAString(valueString);
   700       break;
   701     }
   702     default: {
   703       rv = NS_ERROR_UNEXPECTED;
   704       break;
   705     }
   706   }
   708   if (NS_SUCCEEDED(rv))
   709     NS_ADDREF(*_retval = value);
   711   return rv;
   712 }
   715 NS_IMETHODIMP
   716 nsAnnotationService::GetPageAnnotationInt32(nsIURI* aURI,
   717                                         const nsACString& aName,
   718                                         int32_t* _retval)
   719 {
   720   NS_ENSURE_ARG(aURI);
   721   NS_ENSURE_ARG_POINTER(_retval);
   723   nsCOMPtr<mozIStorageStatement> statement;
   724   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   725   if (NS_FAILED(rv))
   726     return rv;
   728   mozStorageStatementScoper scoper(statement);
   729   ENSURE_ANNO_TYPE(TYPE_INT32, statement);
   730   *_retval = statement->AsInt32(kAnnoIndex_Content);
   731   NS_ENSURE_SUCCESS(rv, rv);
   733   return NS_OK;
   734 }
   737 NS_IMETHODIMP
   738 nsAnnotationService::GetItemAnnotationInt32(int64_t aItemId,
   739                                             const nsACString& aName,
   740                                             int32_t* _retval)
   741 {
   742   NS_ENSURE_ARG_MIN(aItemId, 1);
   743   NS_ENSURE_ARG_POINTER(_retval);
   745   nsCOMPtr<mozIStorageStatement> statement;
   746   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   747   if (NS_FAILED(rv))
   748     return rv;
   750   mozStorageStatementScoper scoper(statement);
   751   ENSURE_ANNO_TYPE(TYPE_INT32, statement);
   752   *_retval = statement->AsInt32(kAnnoIndex_Content);
   754   return NS_OK;
   755 }
   758 NS_IMETHODIMP
   759 nsAnnotationService::GetPageAnnotationInt64(nsIURI* aURI,
   760                                             const nsACString& aName,
   761                                             int64_t* _retval)
   762 {
   763   NS_ENSURE_ARG(aURI);
   764   NS_ENSURE_ARG_POINTER(_retval);
   766   nsCOMPtr<mozIStorageStatement> statement;
   767   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   768   if (NS_FAILED(rv))
   769     return rv;
   771   mozStorageStatementScoper scoper(statement);
   772   ENSURE_ANNO_TYPE(TYPE_INT64, statement);
   773   *_retval = statement->AsInt64(kAnnoIndex_Content);
   775   return NS_OK;
   776 }
   779 NS_IMETHODIMP
   780 nsAnnotationService::GetItemAnnotationInt64(int64_t aItemId,
   781                                             const nsACString& aName,
   782                                             int64_t* _retval)
   783 {
   784   NS_ENSURE_ARG_MIN(aItemId, 1);
   785   NS_ENSURE_ARG_POINTER(_retval);
   787   nsCOMPtr<mozIStorageStatement> statement;
   788   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   789   if (NS_FAILED(rv))
   790     return rv;
   792   mozStorageStatementScoper scoper(statement);
   793   ENSURE_ANNO_TYPE(TYPE_INT64, statement);
   794   *_retval = statement->AsInt64(kAnnoIndex_Content);
   796   return NS_OK;
   797 }
   800 NS_IMETHODIMP
   801 nsAnnotationService::GetPageAnnotationType(nsIURI* aURI,
   802                                            const nsACString& aName,
   803                                            uint16_t* _retval)
   804 {
   805   NS_ENSURE_ARG(aURI);
   806   NS_ENSURE_ARG_POINTER(_retval);
   808   nsCOMPtr<mozIStorageStatement> statement;
   809   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   810   if (NS_FAILED(rv))
   811     return rv;
   813   mozStorageStatementScoper scoper(statement);
   814   *_retval = statement->AsInt32(kAnnoIndex_Type);
   816   return NS_OK;
   817 }
   820 NS_IMETHODIMP
   821 nsAnnotationService::GetItemAnnotationType(int64_t aItemId,
   822                                            const nsACString& aName,
   823                                            uint16_t* _retval)
   824 {
   825   NS_ENSURE_ARG_MIN(aItemId, 1);
   826   NS_ENSURE_ARG_POINTER(_retval);
   828   nsCOMPtr<mozIStorageStatement> statement;
   829   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   830   if (NS_FAILED(rv))
   831     return rv;
   833   mozStorageStatementScoper scoper(statement);
   834   *_retval = statement->AsInt32(kAnnoIndex_Type);
   836   return NS_OK;
   837 }
   840 NS_IMETHODIMP
   841 nsAnnotationService::GetPageAnnotationDouble(nsIURI* aURI,
   842                                              const nsACString& aName,
   843                                              double* _retval)
   844 {
   845   NS_ENSURE_ARG(aURI);
   846   NS_ENSURE_ARG_POINTER(_retval);
   848   nsCOMPtr<mozIStorageStatement> statement;
   849   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   850   if (NS_FAILED(rv))
   851     return rv;
   853   mozStorageStatementScoper scoper(statement);
   854   ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
   855   *_retval = statement->AsDouble(kAnnoIndex_Content);
   857   return NS_OK;
   858 }
   861 NS_IMETHODIMP
   862 nsAnnotationService::GetItemAnnotationDouble(int64_t aItemId,
   863                                              const nsACString& aName,
   864                                              double* _retval)
   865 {
   866   NS_ENSURE_ARG_MIN(aItemId, 1);
   868   nsCOMPtr<mozIStorageStatement> statement;
   869   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   870   if (NS_FAILED(rv))
   871     return rv;
   873   mozStorageStatementScoper scoper(statement);
   874   ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
   875   *_retval = statement->AsDouble(kAnnoIndex_Content);
   877   return NS_OK;
   878 }
   881 NS_IMETHODIMP
   882 nsAnnotationService::GetPageAnnotationInfo(nsIURI* aURI,
   883                                            const nsACString& aName,
   884                                            int32_t* _flags,
   885                                            uint16_t* _expiration,
   886                                            uint16_t* _storageType)
   887 {
   888   NS_ENSURE_ARG(aURI);
   889   NS_ENSURE_ARG_POINTER(_flags);
   890   NS_ENSURE_ARG_POINTER(_expiration);
   891   NS_ENSURE_ARG_POINTER(_storageType);
   893   nsCOMPtr<mozIStorageStatement> statement;
   894   nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   895   if (NS_FAILED(rv))
   896     return rv;
   898   mozStorageStatementScoper scoper(statement);
   899   *_flags = statement->AsInt32(kAnnoIndex_Flags);
   900   *_expiration = (uint16_t)statement->AsInt32(kAnnoIndex_Expiration);
   901   int32_t type = (uint16_t)statement->AsInt32(kAnnoIndex_Type);
   902   if (type == 0) {
   903     // For annotations created before explicit typing,
   904     // we can't determine type, just return as string type.
   905     *_storageType = nsIAnnotationService::TYPE_STRING;
   906   }
   907   else
   908     *_storageType = type;
   910   return NS_OK;
   911 }
   914 NS_IMETHODIMP
   915 nsAnnotationService::GetItemAnnotationInfo(int64_t aItemId,
   916                                            const nsACString& aName,
   917                                            int32_t* _flags,
   918                                            uint16_t* _expiration,
   919                                            uint16_t* _storageType)
   920 {
   921   NS_ENSURE_ARG_MIN(aItemId, 1);
   922   NS_ENSURE_ARG_POINTER(_flags);
   923   NS_ENSURE_ARG_POINTER(_expiration);
   924   NS_ENSURE_ARG_POINTER(_storageType);
   926   nsCOMPtr<mozIStorageStatement> statement;
   927   nsresult rv = StartGetAnnotation(nullptr, aItemId, aName, statement);
   928   if (NS_FAILED(rv))
   929     return rv;
   931   mozStorageStatementScoper scoper(statement);
   932   *_flags = statement->AsInt32(kAnnoIndex_Flags);
   933   *_expiration = (uint16_t)statement->AsInt32(kAnnoIndex_Expiration);
   934   int32_t type = (uint16_t)statement->AsInt32(kAnnoIndex_Type);
   935   if (type == 0) {
   936     // For annotations created before explicit typing,
   937     // we can't determine type, just return as string type.
   938     *_storageType = nsIAnnotationService::TYPE_STRING;
   939   }
   940   else {
   941     *_storageType = type;
   942   }
   944   return NS_OK;
   945 }
   948 NS_IMETHODIMP
   949 nsAnnotationService::GetPagesWithAnnotation(const nsACString& aName,
   950                                             uint32_t* _resultCount,
   951                                             nsIURI*** _results)
   952 {
   953   NS_ENSURE_TRUE(!aName.IsEmpty(), NS_ERROR_INVALID_ARG);
   954   NS_ENSURE_ARG_POINTER(_resultCount);
   955   NS_ENSURE_ARG_POINTER(_results);
   957   *_resultCount = 0;
   958   *_results = nullptr;
   959   nsCOMArray<nsIURI> results;
   961   nsresult rv = GetPagesWithAnnotationCOMArray(aName, &results);
   962   NS_ENSURE_SUCCESS(rv, rv);
   964   // Convert to raw array.
   965   if (results.Count() == 0)
   966     return NS_OK;
   968   *_results = static_cast<nsIURI**>
   969                          (nsMemory::Alloc(results.Count() * sizeof(nsIURI*)));
   970   NS_ENSURE_TRUE(*_results, NS_ERROR_OUT_OF_MEMORY);
   972   *_resultCount = results.Count();
   973   for (uint32_t i = 0; i < *_resultCount; i ++) {
   974     (*_results)[i] = results[i];
   975     NS_ADDREF((*_results)[i]);
   976   }
   978   return NS_OK;
   979 }
   982 nsresult
   983 nsAnnotationService::GetPagesWithAnnotationCOMArray(const nsACString& aName,
   984                                                     nsCOMArray<nsIURI>* _results)
   985 {
   986   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
   987     "SELECT h.url "
   988     "FROM moz_anno_attributes n "
   989     "JOIN moz_annos a ON n.id = a.anno_attribute_id "
   990     "JOIN moz_places h ON h.id = a.place_id "
   991     "WHERE n.name = :anno_name"
   992   );
   993   NS_ENSURE_STATE(stmt);
   994   mozStorageStatementScoper scoper(stmt);
   996   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   997   NS_ENSURE_SUCCESS(rv, rv);
   999   bool hasMore = false;
  1000   while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasMore)) &&
  1001          hasMore) {
  1002     nsAutoCString uristring;
  1003     rv = stmt->GetUTF8String(0, uristring);
  1004     NS_ENSURE_SUCCESS(rv, rv);
  1006     // convert to a URI, in case of some invalid URI, just ignore this row
  1007     // so we can mostly continue.
  1008     nsCOMPtr<nsIURI> uri;
  1009     rv = NS_NewURI(getter_AddRefs(uri), uristring);
  1010     if (NS_FAILED(rv))
  1011       continue;
  1013     bool added = _results->AppendObject(uri);
  1014     NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
  1017   return NS_OK;
  1021 NS_IMETHODIMP
  1022 nsAnnotationService::GetItemsWithAnnotation(const nsACString& aName,
  1023                                             uint32_t* _resultCount,
  1024                                             int64_t** _results)
  1026   NS_ENSURE_TRUE(!aName.IsEmpty(), NS_ERROR_INVALID_ARG);
  1027   NS_ENSURE_ARG_POINTER(_resultCount);
  1028   NS_ENSURE_ARG_POINTER(_results);
  1030   *_resultCount = 0;
  1031   *_results = nullptr;
  1032   nsTArray<int64_t> results;
  1034   nsresult rv = GetItemsWithAnnotationTArray(aName, &results);
  1035   NS_ENSURE_SUCCESS(rv, rv);
  1037   // Convert to raw array.
  1038   if (results.Length() == 0)
  1039     return NS_OK;
  1041   *_results = static_cast<int64_t*>
  1042                          (nsMemory::Alloc(results.Length() * sizeof(int64_t)));
  1043   NS_ENSURE_TRUE(*_results, NS_ERROR_OUT_OF_MEMORY);
  1045   *_resultCount = results.Length();
  1046   for (uint32_t i = 0; i < *_resultCount; i ++) {
  1047     (*_results)[i] = results[i];
  1050   return NS_OK;
  1054 NS_IMETHODIMP
  1055 nsAnnotationService::GetAnnotationsWithName(const nsACString& aName,
  1056                                             uint32_t* _count,
  1057                                             mozIAnnotatedResult*** _annotations)
  1059   NS_ENSURE_ARG(!aName.IsEmpty());
  1060   NS_ENSURE_ARG_POINTER(_annotations);
  1062   *_count = 0;
  1063   *_annotations = nullptr;
  1064   nsCOMArray<mozIAnnotatedResult> annotations;
  1066   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
  1067     "SELECT h.guid, h.url, -1, a.type, a.content "
  1068     "FROM moz_anno_attributes n "
  1069     "JOIN moz_annos a ON n.id = a.anno_attribute_id "
  1070     "JOIN moz_places h ON h.id = a.place_id "
  1071     "WHERE n.name = :anno_name "
  1072     "UNION ALL "
  1073     "SELECT b.guid, h.url, b.id, a.type, a.content "
  1074     "FROM moz_anno_attributes n "
  1075     "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
  1076     "JOIN moz_bookmarks b ON b.id = a.item_id "
  1077     "LEFT JOIN moz_places h ON h.id = b.fk "
  1078     "WHERE n.name = :anno_name "
  1079   );
  1080   NS_ENSURE_STATE(stmt);
  1081   mozStorageStatementScoper scoper(stmt);
  1083   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
  1084                                            aName);
  1085   NS_ENSURE_SUCCESS(rv, rv);
  1087   bool hasMore = false;
  1088   while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasMore)) && hasMore) {
  1089     nsAutoCString guid;
  1090     rv = stmt->GetUTF8String(0, guid);
  1091     NS_ENSURE_SUCCESS(rv, rv);
  1093     nsCOMPtr<nsIURI> uri;
  1094     bool uriIsNull = false;
  1095     rv = stmt->GetIsNull(1, &uriIsNull);
  1096     NS_ENSURE_SUCCESS(rv, rv);
  1097     if (!uriIsNull) {
  1098       nsAutoCString url;
  1099       rv = stmt->GetUTF8String(1, url);
  1100       NS_ENSURE_SUCCESS(rv, rv);
  1101       rv = NS_NewURI(getter_AddRefs(uri), url);
  1102       NS_ENSURE_SUCCESS(rv, rv);
  1105     int64_t itemId = stmt->AsInt64(2);
  1106     int32_t type = stmt->AsInt32(3);
  1108     nsCOMPtr<nsIWritableVariant> variant = new nsVariant();
  1109     switch (type) {
  1110       case nsIAnnotationService::TYPE_INT32: {
  1111         rv = variant->SetAsInt32(stmt->AsInt32(4));
  1112         break;
  1114       case nsIAnnotationService::TYPE_INT64: {
  1115         rv = variant->SetAsInt64(stmt->AsInt64(4));
  1116         break;
  1118       case nsIAnnotationService::TYPE_DOUBLE: {
  1119         rv = variant->SetAsDouble(stmt->AsDouble(4));
  1120         break;
  1122       case nsIAnnotationService::TYPE_STRING: {
  1123         nsAutoString valueString;
  1124         rv = stmt->GetString(4, valueString);
  1125         NS_ENSURE_SUCCESS(rv, rv);
  1127         rv = variant->SetAsAString(valueString);
  1128         break;
  1130       default:
  1131         MOZ_ASSERT(false, "Unsupported annotation type");
  1132         // Move to the next result.
  1133         continue;
  1135     NS_ENSURE_SUCCESS(rv, rv);
  1137     nsCOMPtr<mozIAnnotatedResult> anno = new AnnotatedResult(guid, uri, itemId,
  1138                                                              aName, variant);
  1139     NS_ENSURE_TRUE(annotations.AppendObject(anno), NS_ERROR_OUT_OF_MEMORY);
  1142   // Convert to raw array.
  1143   if (annotations.Count() == 0)
  1144     return NS_OK;
  1146   *_annotations = static_cast<mozIAnnotatedResult**>
  1147     (nsMemory::Alloc(annotations.Count() * sizeof(mozIAnnotatedResult*)));
  1148   NS_ENSURE_TRUE(*_annotations, NS_ERROR_OUT_OF_MEMORY);
  1150   *_count = annotations.Count();
  1151   for (uint32_t i = 0; i < *_count; ++i) {
  1152     NS_ADDREF((*_annotations)[i] = annotations[i]);
  1155   return NS_OK;
  1159 nsresult
  1160 nsAnnotationService::GetItemsWithAnnotationTArray(const nsACString& aName,
  1161                                                   nsTArray<int64_t>* _results)
  1163   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
  1164     "SELECT a.item_id "
  1165     "FROM moz_anno_attributes n "
  1166     "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
  1167     "WHERE n.name = :anno_name"
  1168   );
  1169   NS_ENSURE_STATE(stmt);
  1170   mozStorageStatementScoper scoper(stmt);
  1172   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
  1173   NS_ENSURE_SUCCESS(rv, rv);
  1175   bool hasMore = false;
  1176   while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) &&
  1177          hasMore) {
  1178     if (!_results->AppendElement(stmt->AsInt64(0)))
  1179       return NS_ERROR_OUT_OF_MEMORY;
  1182   return NS_OK;
  1186 NS_IMETHODIMP
  1187 nsAnnotationService::GetPageAnnotationNames(nsIURI* aURI,
  1188                                             uint32_t* _count,
  1189                                             nsIVariant*** _result)
  1191   NS_ENSURE_ARG(aURI);
  1192   NS_ENSURE_ARG_POINTER(_count);
  1193   NS_ENSURE_ARG_POINTER(_result);
  1195   *_count = 0;
  1196   *_result = nullptr;
  1198   nsTArray<nsCString> names;
  1199   nsresult rv = GetAnnotationNamesTArray(aURI, 0, &names);
  1200   NS_ENSURE_SUCCESS(rv, rv);
  1202   if (names.Length() == 0)
  1203     return NS_OK;
  1205   *_result = static_cast<nsIVariant**>
  1206                         (nsMemory::Alloc(sizeof(nsIVariant*) * names.Length()));
  1207   NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
  1209   for (uint32_t i = 0; i < names.Length(); i ++) {
  1210     nsCOMPtr<nsIWritableVariant> var = new nsVariant();
  1211     if (!var) {
  1212       // need to release all the variants we've already created
  1213       for (uint32_t j = 0; j < i; j ++)
  1214         NS_RELEASE((*_result)[j]);
  1215       nsMemory::Free(*_result);
  1216       *_result = nullptr;
  1217       return NS_ERROR_OUT_OF_MEMORY;
  1219     var->SetAsAUTF8String(names[i]);
  1220     NS_ADDREF((*_result)[i] = var);
  1222   *_count = names.Length();
  1224   return NS_OK;
  1228 nsresult
  1229 nsAnnotationService::GetAnnotationNamesTArray(nsIURI* aURI,
  1230                                               int64_t aItemId,
  1231                                               nsTArray<nsCString>* _result)
  1233   _result->Clear();
  1235   bool isItemAnnotation = (aItemId > 0);
  1236   nsCOMPtr<mozIStorageStatement> statement;
  1237   if (isItemAnnotation) {
  1238     statement = mDB->GetStatement(
  1239       "SELECT n.name "
  1240       "FROM moz_anno_attributes n "
  1241       "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
  1242       "WHERE a.item_id = :item_id"
  1243     );
  1245   else {
  1246     statement = mDB->GetStatement(
  1247       "SELECT n.name "
  1248       "FROM moz_anno_attributes n "
  1249       "JOIN moz_annos a ON a.anno_attribute_id = n.id "
  1250       "JOIN moz_places h ON h.id = a.place_id "
  1251       "WHERE h.url = :page_url"
  1252     );
  1254   NS_ENSURE_STATE(statement);
  1255   mozStorageStatementScoper scoper(statement);
  1257   nsresult rv;
  1258   if (isItemAnnotation)
  1259     rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
  1260   else
  1261     rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
  1262   NS_ENSURE_SUCCESS(rv, rv);
  1264   bool hasResult = false;
  1265   while (NS_SUCCEEDED(statement->ExecuteStep(&hasResult)) &&
  1266          hasResult) {
  1267     nsAutoCString name;
  1268     rv = statement->GetUTF8String(0, name);
  1269     NS_ENSURE_SUCCESS(rv, rv);
  1270     if (!_result->AppendElement(name))
  1271       return NS_ERROR_OUT_OF_MEMORY;
  1274   return NS_OK;
  1278 NS_IMETHODIMP
  1279 nsAnnotationService::GetItemAnnotationNames(int64_t aItemId,
  1280                                             uint32_t* _count,
  1281                                             nsIVariant*** _result)
  1283   NS_ENSURE_ARG_MIN(aItemId, 1);
  1284   NS_ENSURE_ARG_POINTER(_count);
  1285   NS_ENSURE_ARG_POINTER(_result);
  1287   *_count = 0;
  1288   *_result = nullptr;
  1290   nsTArray<nsCString> names;
  1291   nsresult rv = GetAnnotationNamesTArray(nullptr, aItemId, &names);
  1292   NS_ENSURE_SUCCESS(rv, rv);
  1294   if (names.Length() == 0)
  1295     return NS_OK;
  1297   *_result = static_cast<nsIVariant**>
  1298                         (nsMemory::Alloc(sizeof(nsIVariant*) * names.Length()));
  1299   NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
  1301   for (uint32_t i = 0; i < names.Length(); i ++) {
  1302     nsCOMPtr<nsIWritableVariant> var = new nsVariant();
  1303     if (!var) {
  1304       // need to release all the variants we've already created
  1305       for (uint32_t j = 0; j < i; j ++)
  1306         NS_RELEASE((*_result)[j]);
  1307       nsMemory::Free(*_result);
  1308       *_result = nullptr;
  1309       return NS_ERROR_OUT_OF_MEMORY;
  1311     var->SetAsAUTF8String(names[i]);
  1312     NS_ADDREF((*_result)[i] = var);
  1314   *_count = names.Length();
  1316   return NS_OK;
  1320 NS_IMETHODIMP
  1321 nsAnnotationService::PageHasAnnotation(nsIURI* aURI,
  1322                                        const nsACString& aName,
  1323                                        bool* _retval)
  1325   NS_ENSURE_ARG(aURI);
  1326   NS_ENSURE_ARG_POINTER(_retval);
  1328   nsresult rv = HasAnnotationInternal(aURI, 0, aName, _retval);
  1329   NS_ENSURE_SUCCESS(rv, rv);
  1331   return NS_OK;
  1335 NS_IMETHODIMP
  1336 nsAnnotationService::ItemHasAnnotation(int64_t aItemId,
  1337                                        const nsACString& aName,
  1338                                        bool* _retval)
  1340   NS_ENSURE_ARG_MIN(aItemId, 1);
  1341   NS_ENSURE_ARG_POINTER(_retval);
  1343   nsresult rv = HasAnnotationInternal(nullptr, aItemId, aName, _retval);
  1344   NS_ENSURE_SUCCESS(rv, rv);
  1346   return NS_OK;
  1350 /**
  1351  * @note We don't remove anything from the moz_anno_attributes table. If we
  1352  *       delete the last item of a given name, that item really should go away.
  1353  *       It will be cleaned up by expiration.
  1354  */
  1355 nsresult
  1356 nsAnnotationService::RemoveAnnotationInternal(nsIURI* aURI,
  1357                                               int64_t aItemId,
  1358                                               const nsACString& aName)
  1360   bool isItemAnnotation = (aItemId > 0);
  1361   nsCOMPtr<mozIStorageStatement> statement;
  1362   if (isItemAnnotation) {
  1363     statement = mDB->GetStatement(
  1364       "DELETE FROM moz_items_annos "
  1365       "WHERE item_id = :item_id "
  1366         "AND anno_attribute_id = "
  1367           "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
  1368     );
  1370   else {
  1371     statement = mDB->GetStatement(
  1372       "DELETE FROM moz_annos "
  1373       "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
  1374         "AND anno_attribute_id = "
  1375           "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
  1376     );
  1378   NS_ENSURE_STATE(statement);
  1379   mozStorageStatementScoper scoper(statement);
  1381   nsresult rv;
  1382   if (isItemAnnotation)
  1383     rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
  1384   else
  1385     rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
  1386   NS_ENSURE_SUCCESS(rv, rv);
  1388   rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
  1389   NS_ENSURE_SUCCESS(rv, rv);
  1391   rv = statement->Execute();
  1392   NS_ENSURE_SUCCESS(rv, rv);
  1394   return NS_OK;
  1398 NS_IMETHODIMP
  1399 nsAnnotationService::RemovePageAnnotation(nsIURI* aURI,
  1400                                           const nsACString& aName)
  1402   NS_ENSURE_ARG(aURI);
  1404   nsresult rv = RemoveAnnotationInternal(aURI, 0, aName);
  1405   NS_ENSURE_SUCCESS(rv, rv);
  1407   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, aName));
  1409   return NS_OK;
  1413 NS_IMETHODIMP
  1414 nsAnnotationService::RemoveItemAnnotation(int64_t aItemId,
  1415                                           const nsACString& aName)
  1417   NS_ENSURE_ARG_MIN(aItemId, 1);
  1419   nsresult rv = RemoveAnnotationInternal(nullptr, aItemId, aName);
  1420   NS_ENSURE_SUCCESS(rv, rv);
  1422   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, aName));
  1424   return NS_OK;
  1428 NS_IMETHODIMP
  1429 nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
  1431   NS_ENSURE_ARG(aURI);
  1433   // Should this be precompiled or a getter?
  1434   nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
  1435     "DELETE FROM moz_annos WHERE place_id = "
  1436       "(SELECT id FROM moz_places WHERE url = :page_url)"
  1437   );
  1438   NS_ENSURE_STATE(statement);
  1439   mozStorageStatementScoper scoper(statement);
  1441   nsresult rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
  1442   NS_ENSURE_SUCCESS(rv, rv);
  1444   rv = statement->Execute();
  1445   NS_ENSURE_SUCCESS(rv, rv);
  1447   // Update observers
  1448   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, EmptyCString()));
  1450   return NS_OK;
  1454 NS_IMETHODIMP
  1455 nsAnnotationService::RemoveItemAnnotations(int64_t aItemId)
  1457   NS_ENSURE_ARG_MIN(aItemId, 1);
  1459   // Should this be precompiled or a getter?
  1460   nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
  1461     "DELETE FROM moz_items_annos WHERE item_id = :item_id"
  1462   );
  1463   NS_ENSURE_STATE(statement);
  1464   mozStorageStatementScoper scoper(statement);
  1466   nsresult rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
  1467   NS_ENSURE_SUCCESS(rv, rv);
  1469   rv = statement->Execute();
  1470   NS_ENSURE_SUCCESS(rv, rv);
  1472   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, EmptyCString()));
  1474   return NS_OK;
  1478 /**
  1479  * @note If we use annotations for some standard items like GeckoFlags, it
  1480  *       might be a good idea to blacklist these standard annotations from this
  1481  *       copy function.
  1482  */
  1483 NS_IMETHODIMP
  1484 nsAnnotationService::CopyPageAnnotations(nsIURI* aSourceURI,
  1485                                          nsIURI* aDestURI,
  1486                                          bool aOverwriteDest)
  1488   NS_ENSURE_ARG(aSourceURI);
  1489   NS_ENSURE_ARG(aDestURI);
  1491   mozStorageTransaction transaction(mDB->MainConn(), false);
  1493   nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
  1494     "SELECT h.id, n.id, n.name, a2.id "
  1495     "FROM moz_places h "
  1496     "JOIN moz_annos a ON a.place_id = h.id "
  1497     "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
  1498     "LEFT JOIN moz_annos a2 ON a2.place_id = "
  1499       "(SELECT id FROM moz_places WHERE url = :dest_url) "
  1500                           "AND a2.anno_attribute_id = n.id "
  1501     "WHERE url = :source_url"
  1502   );
  1503   NS_ENSURE_STATE(sourceStmt);
  1504   mozStorageStatementScoper sourceScoper(sourceStmt);
  1506   nsresult rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("source_url"), aSourceURI);
  1507   NS_ENSURE_SUCCESS(rv, rv);
  1508   rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("dest_url"), aDestURI);
  1509   NS_ENSURE_SUCCESS(rv, rv);
  1511   nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
  1512     "INSERT INTO moz_annos "
  1513     "(place_id, anno_attribute_id, content, flags, expiration, "
  1514      "type, dateAdded, lastModified) "
  1515     "SELECT (SELECT id FROM moz_places WHERE url = :page_url), "
  1516            "anno_attribute_id, content, flags, expiration, type, "
  1517            ":date, :date "
  1518     "FROM moz_annos "
  1519     "WHERE place_id = :page_id "
  1520     "AND anno_attribute_id = :name_id"
  1521   );
  1522   NS_ENSURE_STATE(copyStmt);
  1523   mozStorageStatementScoper copyScoper(copyStmt);
  1525   bool hasResult;
  1526   while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
  1527     int64_t sourcePlaceId = sourceStmt->AsInt64(0);
  1528     int64_t annoNameID = sourceStmt->AsInt64(1);
  1529     nsAutoCString annoName;
  1530     rv = sourceStmt->GetUTF8String(2, annoName);
  1531     NS_ENSURE_SUCCESS(rv, rv);
  1532     int64_t annoExistsOnDest = sourceStmt->AsInt64(3);
  1534     if (annoExistsOnDest) {
  1535       if (!aOverwriteDest)
  1536         continue;
  1537       rv = RemovePageAnnotation(aDestURI, annoName);
  1538       NS_ENSURE_SUCCESS(rv, rv);
  1541     // Copy the annotation.
  1542     mozStorageStatementScoper scoper(copyStmt);
  1543     rv = URIBinder::Bind(copyStmt, NS_LITERAL_CSTRING("page_url"), aDestURI);
  1544     NS_ENSURE_SUCCESS(rv, rv);
  1545     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), sourcePlaceId);
  1546     NS_ENSURE_SUCCESS(rv, rv);
  1547     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), annoNameID);
  1548     NS_ENSURE_SUCCESS(rv, rv);
  1549     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), PR_Now());
  1550     NS_ENSURE_SUCCESS(rv, rv);
  1552     rv = copyStmt->Execute();
  1553     NS_ENSURE_SUCCESS(rv, rv);
  1555     NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aDestURI, annoName));
  1558   rv = transaction.Commit();
  1559   NS_ENSURE_SUCCESS(rv, rv);
  1561   return NS_OK;
  1565 NS_IMETHODIMP
  1566 nsAnnotationService::CopyItemAnnotations(int64_t aSourceItemId,
  1567                                          int64_t aDestItemId,
  1568                                          bool aOverwriteDest)
  1570   NS_ENSURE_ARG_MIN(aSourceItemId, 1);
  1571   NS_ENSURE_ARG_MIN(aDestItemId, 1);
  1573   mozStorageTransaction transaction(mDB->MainConn(), false);
  1575   nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
  1576     "SELECT n.id, n.name, a2.id "
  1577     "FROM moz_bookmarks b "
  1578     "JOIN moz_items_annos a ON a.item_id = b.id "
  1579     "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
  1580     "LEFT JOIN moz_items_annos a2 ON a2.item_id = :dest_item_id "
  1581                                 "AND a2.anno_attribute_id = n.id "
  1582     "WHERE b.id = :source_item_id"
  1583   );
  1584   NS_ENSURE_STATE(sourceStmt);
  1585   mozStorageStatementScoper sourceScoper(sourceStmt);
  1587   nsresult rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
  1588   NS_ENSURE_SUCCESS(rv, rv);
  1589   rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
  1590   NS_ENSURE_SUCCESS(rv, rv);
  1592   nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
  1593       "INSERT OR REPLACE INTO moz_items_annos "
  1594       "(item_id, anno_attribute_id, content, flags, expiration, "
  1595        "type, dateAdded, lastModified) "
  1596       "SELECT :dest_item_id, anno_attribute_id, content, flags, expiration, "
  1597              "type, :date, :date "
  1598       "FROM moz_items_annos "
  1599       "WHERE item_id = :source_item_id "
  1600       "AND anno_attribute_id = :name_id"
  1601   );
  1602   NS_ENSURE_STATE(copyStmt);
  1603   mozStorageStatementScoper copyScoper(copyStmt);
  1605   bool hasResult;
  1606   while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
  1607     int64_t annoNameID = sourceStmt->AsInt64(0);
  1608     nsAutoCString annoName;
  1609     rv = sourceStmt->GetUTF8String(1, annoName);
  1610     NS_ENSURE_SUCCESS(rv, rv);
  1611     int64_t annoExistsOnDest = sourceStmt->AsInt64(2);
  1613     if (annoExistsOnDest) {
  1614       if (!aOverwriteDest)
  1615         continue;
  1616       rv = RemoveItemAnnotation(aDestItemId, annoName);
  1617       NS_ENSURE_SUCCESS(rv, rv);
  1620     // Copy the annotation.
  1621     mozStorageStatementScoper scoper(copyStmt);
  1622     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
  1623     NS_ENSURE_SUCCESS(rv, rv);
  1624     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
  1625     NS_ENSURE_SUCCESS(rv, rv);
  1626     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), annoNameID);
  1627     NS_ENSURE_SUCCESS(rv, rv);
  1628     rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), PR_Now());
  1629     NS_ENSURE_SUCCESS(rv, rv);
  1631     rv = copyStmt->Execute();
  1632     NS_ENSURE_SUCCESS(rv, rv);
  1634     NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aDestItemId, annoName));
  1637   rv = transaction.Commit();
  1638   NS_ENSURE_SUCCESS(rv, rv);
  1640   return NS_OK;
  1644 NS_IMETHODIMP
  1645 nsAnnotationService::AddObserver(nsIAnnotationObserver* aObserver)
  1647   NS_ENSURE_ARG(aObserver);
  1649   if (mObservers.IndexOfObject(aObserver) >= 0)
  1650     return NS_ERROR_INVALID_ARG; // Already registered.
  1651   if (!mObservers.AppendObject(aObserver))
  1652     return NS_ERROR_OUT_OF_MEMORY;
  1653   return NS_OK;
  1657 NS_IMETHODIMP
  1658 nsAnnotationService::RemoveObserver(nsIAnnotationObserver* aObserver)
  1660   NS_ENSURE_ARG(aObserver);
  1662   if (!mObservers.RemoveObject(aObserver))
  1663     return NS_ERROR_INVALID_ARG;
  1664   return NS_OK;
  1667 nsresult
  1668 nsAnnotationService::HasAnnotationInternal(nsIURI* aURI,
  1669                                            int64_t aItemId,
  1670                                            const nsACString& aName,
  1671                                            bool* _hasAnno)
  1673   bool isItemAnnotation = (aItemId > 0);
  1674   nsCOMPtr<mozIStorageStatement> stmt;
  1675   if (isItemAnnotation) {
  1676     stmt = mDB->GetStatement(
  1677       "SELECT b.id, "
  1678              "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
  1679              "a.id, a.dateAdded "
  1680       "FROM moz_bookmarks b "
  1681       "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
  1682                                  "AND a.anno_attribute_id = nameid "
  1683       "WHERE b.id = :item_id"
  1684     );
  1686   else {
  1687     stmt = mDB->GetStatement(
  1688       "SELECT h.id, "
  1689              "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
  1690              "a.id, a.dateAdded "
  1691       "FROM moz_places h "
  1692       "LEFT JOIN moz_annos a ON a.place_id = h.id "
  1693                            "AND a.anno_attribute_id = nameid "
  1694       "WHERE h.url = :page_url"
  1695     );
  1697   NS_ENSURE_STATE(stmt);
  1698   mozStorageStatementScoper checkAnnoScoper(stmt);
  1700   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
  1701   NS_ENSURE_SUCCESS(rv, rv);
  1702   if (isItemAnnotation)
  1703     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
  1704   else
  1705     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
  1706   NS_ENSURE_SUCCESS(rv, rv);
  1708   bool hasResult;
  1709   rv = stmt->ExecuteStep(&hasResult);
  1710   NS_ENSURE_SUCCESS(rv, rv);
  1711   if (!hasResult) {
  1712     // We are trying to get an annotation on an invalid bookmarks or
  1713     // history entry.
  1714     // Here we preserve the old behavior, returning that we don't have the
  1715     // annotation, ignoring the fact itemId is invalid.
  1716     // Otherwise we should return NS_ERROR_INVALID_ARG, but this will somehow
  1717     // break the API.  In future we could want to be pickier.
  1718     *_hasAnno = false;
  1720   else {
  1721     int64_t annotationId = stmt->AsInt64(2);
  1722     *_hasAnno = (annotationId > 0);
  1725   return NS_OK;
  1729 /**
  1730  * This loads the statement and steps it once so you can get data out of it.
  1732  * @note You have to reset the statement when you're done if this succeeds.
  1733  * @throws NS_ERROR_NOT_AVAILABLE if the annotation is not found.
  1734  */
  1736 nsresult
  1737 nsAnnotationService::StartGetAnnotation(nsIURI* aURI,
  1738                                         int64_t aItemId,
  1739                                         const nsACString& aName,
  1740                                         nsCOMPtr<mozIStorageStatement>& aStatement)
  1742   bool isItemAnnotation = (aItemId > 0);
  1744   if (isItemAnnotation) {
  1745     aStatement = mDB->GetStatement(
  1746       "SELECT a.id, a.item_id, :anno_name, a.content, a.flags, "
  1747              "a.expiration, a.type "
  1748       "FROM moz_anno_attributes n "
  1749       "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
  1750       "WHERE a.item_id = :item_id "
  1751       "AND n.name = :anno_name"
  1752     );
  1754   else {
  1755     aStatement = mDB->GetStatement(
  1756       "SELECT a.id, a.place_id, :anno_name, a.content, a.flags, "
  1757              "a.expiration, a.type "
  1758       "FROM moz_anno_attributes n "
  1759       "JOIN moz_annos a ON n.id = a.anno_attribute_id "
  1760       "JOIN moz_places h ON h.id = a.place_id "
  1761       "WHERE h.url = :page_url "
  1762         "AND n.name = :anno_name"
  1763     );
  1765   NS_ENSURE_STATE(aStatement);
  1766   mozStorageStatementScoper getAnnoScoper(aStatement);
  1768   nsresult rv;
  1769   if (isItemAnnotation)
  1770     rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
  1771   else
  1772     rv = URIBinder::Bind(aStatement, NS_LITERAL_CSTRING("page_url"), aURI);
  1773   NS_ENSURE_SUCCESS(rv, rv);
  1775   rv = aStatement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
  1776   NS_ENSURE_SUCCESS(rv, rv);
  1778   bool hasResult = false;
  1779   rv = aStatement->ExecuteStep(&hasResult);
  1780   if (NS_FAILED(rv) || !hasResult)
  1781     return NS_ERROR_NOT_AVAILABLE;
  1783   // on success, DON'T reset the statement, the caller needs to read from it,
  1784   // and it is the caller's job to reset it.
  1785   getAnnoScoper.Abandon();
  1787   return NS_OK;
  1791 /**
  1792  * This does most of the setup work needed to set an annotation, except for
  1793  * binding the the actual value and executing the statement.
  1794  * It will either update an existing annotation or insert a new one.
  1796  * @note The aStatement RESULT IS NOT ADDREFED.  This is just one of the class
  1797  *       vars, which control its scope.  DO NOT RELEASE.
  1798  *       The caller must take care of resetting the statement if this succeeds.
  1799  */
  1800 nsresult
  1801 nsAnnotationService::StartSetAnnotation(nsIURI* aURI,
  1802                                         int64_t aItemId,
  1803                                         const nsACString& aName,
  1804                                         int32_t aFlags,
  1805                                         uint16_t aExpiration,
  1806                                         uint16_t aType,
  1807                                         nsCOMPtr<mozIStorageStatement>& aStatement)
  1809   bool isItemAnnotation = (aItemId > 0);
  1811   if (aExpiration == EXPIRE_SESSION) {
  1812     mHasSessionAnnotations = true;
  1815   // Ensure the annotation name exists.
  1816   nsCOMPtr<mozIStorageStatement> addNameStmt = mDB->GetStatement(
  1817     "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)"
  1818   );
  1819   NS_ENSURE_STATE(addNameStmt);
  1820   mozStorageStatementScoper scoper(addNameStmt);
  1822   nsresult rv = addNameStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
  1823   NS_ENSURE_SUCCESS(rv, rv);
  1824   rv = addNameStmt->Execute();
  1825   NS_ENSURE_SUCCESS(rv, rv);
  1827   // We have to check 2 things:
  1828   // - if the annotation already exists we should update it.
  1829   // - we should not allow setting annotations on invalid URIs or itemIds.
  1830   // This query will tell us:
  1831   // - whether the item or page exists.
  1832   // - whether the annotation already exists.
  1833   // - the nameID associated with the annotation name.
  1834   // - the id and dateAdded of the old annotation, if it exists.
  1835   nsCOMPtr<mozIStorageStatement> stmt;
  1836   if (isItemAnnotation) {
  1837     stmt = mDB->GetStatement(
  1838       "SELECT b.id, "
  1839              "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
  1840              "a.id, a.dateAdded "
  1841       "FROM moz_bookmarks b "
  1842       "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
  1843                                  "AND a.anno_attribute_id = nameid "
  1844       "WHERE b.id = :item_id"
  1845     );
  1847   else {
  1848     stmt = mDB->GetStatement(
  1849       "SELECT h.id, "
  1850              "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
  1851              "a.id, a.dateAdded "
  1852       "FROM moz_places h "
  1853       "LEFT JOIN moz_annos a ON a.place_id = h.id "
  1854                            "AND a.anno_attribute_id = nameid "
  1855       "WHERE h.url = :page_url"
  1856     );
  1858   NS_ENSURE_STATE(stmt);
  1859   mozStorageStatementScoper checkAnnoScoper(stmt);
  1861   rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
  1862   NS_ENSURE_SUCCESS(rv, rv);
  1863   if (isItemAnnotation)
  1864     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
  1865   else
  1866     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
  1867   NS_ENSURE_SUCCESS(rv, rv);
  1869   bool hasResult;
  1870   rv = stmt->ExecuteStep(&hasResult);
  1871   NS_ENSURE_SUCCESS(rv, rv);
  1872   if (!hasResult) {
  1873     // We are trying to create an annotation on an invalid bookmark
  1874     // or history entry.
  1875     return NS_ERROR_INVALID_ARG;
  1878   int64_t fkId = stmt->AsInt64(0);
  1879   int64_t nameID = stmt->AsInt64(1);
  1880   int64_t oldAnnoId = stmt->AsInt64(2);
  1881   int64_t oldAnnoDate = stmt->AsInt64(3);
  1883   if (isItemAnnotation) {
  1884     aStatement = mDB->GetStatement(
  1885       "INSERT OR REPLACE INTO moz_items_annos "
  1886         "(id, item_id, anno_attribute_id, content, flags, "
  1887          "expiration, type, dateAdded, lastModified) "
  1888       "VALUES (:id, :fk, :name_id, :content, :flags, "
  1889       ":expiration, :type, :date_added, :last_modified)"
  1890     );
  1892   else {
  1893     aStatement = mDB->GetStatement(
  1894       "INSERT OR REPLACE INTO moz_annos "
  1895         "(id, place_id, anno_attribute_id, content, flags, "
  1896          "expiration, type, dateAdded, lastModified) "
  1897       "VALUES (:id, :fk, :name_id, :content, :flags, "
  1898       ":expiration, :type, :date_added, :last_modified)"
  1899     );
  1901   NS_ENSURE_STATE(aStatement);
  1902   mozStorageStatementScoper setAnnoScoper(aStatement);
  1904   // Don't replace existing annotations.
  1905   if (oldAnnoId > 0) {
  1906     rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
  1907     NS_ENSURE_SUCCESS(rv, rv);
  1908     rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), oldAnnoDate);
  1909     NS_ENSURE_SUCCESS(rv, rv);
  1911   else {
  1912     rv = aStatement->BindNullByName(NS_LITERAL_CSTRING("id"));
  1913     NS_ENSURE_SUCCESS(rv, rv);
  1914     rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), PR_Now());
  1915     NS_ENSURE_SUCCESS(rv, rv);
  1918   rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
  1919   NS_ENSURE_SUCCESS(rv, rv);
  1920   rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
  1921   NS_ENSURE_SUCCESS(rv, rv);
  1923   rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
  1924   NS_ENSURE_SUCCESS(rv, rv);
  1925   rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
  1926   NS_ENSURE_SUCCESS(rv, rv);
  1927   rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
  1928   NS_ENSURE_SUCCESS(rv, rv);
  1929   rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), PR_Now());
  1930   NS_ENSURE_SUCCESS(rv, rv);
  1932   // On success, leave the statement open, the caller will set the value
  1933   // and execute the statement.
  1934   setAnnoScoper.Abandon();
  1936   return NS_OK;
  1939 ////////////////////////////////////////////////////////////////////////////////
  1940 //// nsIObserver
  1942 NS_IMETHODIMP
  1943 nsAnnotationService::Observe(nsISupports *aSubject,
  1944                              const char *aTopic,
  1945                              const char16_t *aData)
  1947   NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
  1949   if (strcmp(aTopic, TOPIC_PLACES_SHUTDOWN) == 0) {
  1950     // Remove all session annotations, if any.
  1951     if (mHasSessionAnnotations) {
  1952       nsCOMPtr<mozIStorageAsyncStatement> pageAnnoStmt = mDB->GetAsyncStatement(
  1953         "DELETE FROM moz_annos WHERE expiration = :expire_session"
  1954       );
  1955       NS_ENSURE_STATE(pageAnnoStmt);
  1956       nsresult rv = pageAnnoStmt->BindInt32ByName(NS_LITERAL_CSTRING("expire_session"),
  1957                                                   EXPIRE_SESSION);
  1958       NS_ENSURE_SUCCESS(rv, rv);
  1960       nsCOMPtr<mozIStorageAsyncStatement> itemAnnoStmt = mDB->GetAsyncStatement(
  1961         "DELETE FROM moz_items_annos WHERE expiration = :expire_session"
  1962       );
  1963       NS_ENSURE_STATE(itemAnnoStmt);
  1964       rv = itemAnnoStmt->BindInt32ByName(NS_LITERAL_CSTRING("expire_session"),
  1965                                          EXPIRE_SESSION);
  1966       NS_ENSURE_SUCCESS(rv, rv);
  1968       mozIStorageBaseStatement *stmts[] = {
  1969         pageAnnoStmt.get()
  1970       , itemAnnoStmt.get()
  1971       };
  1973       nsCOMPtr<mozIStoragePendingStatement> ps;
  1974       rv = mDB->MainConn()->ExecuteAsync(stmts, ArrayLength(stmts), nullptr,
  1975                                          getter_AddRefs(ps));
  1976       NS_ENSURE_SUCCESS(rv, rv);
  1980   return NS_OK;

mercurial